Interpret
"non-alcoholic fatty liver disease" AND "grade" AND "ultrasound"
Grade II fatty liver ultrasound meaning management NAFLD
| Organ | Finding | Significance |
|---|---|---|
| Liver | 15.2 cm, increased echogenicity, no focal lesions; portal vein (PV) & common bile duct (CBD) normal; no biliary dilatation | Abnormal — Grade II fatty infiltration |
| Gallbladder | Distended, no stones/wall thickening/pericholecystic fluid | Normal |
| Pancreas | Head & body normal; tail obscured by bowel gas | Partially visualized — no concerning finding seen |
| Spleen | 9.1 cm, normal echo, no focal lesions | Normal |
| Right Kidney | 10.1 cm, normal, no calculi/hydronephrosis | Normal |
| Left Kidney | 9.8 cm, normal, no calculi/hydronephrosis | Normal |
| Urinary Bladder | Distended, no wall thickening, no calculi | Normal |
| Prostate | Normal size and echotexture | Normal |
| Free fluid | None | Normal |
| Grade | Sonographic Features | Fat Content (approx.) |
|---|---|---|
| Grade I (Mild) | Slightly increased liver echogenicity; diaphragm and vessels still visible | ~5–33% |
| Grade II (Moderate) | Moderately increased echogenicity; slightly obscured portal vein walls and diaphragm | ~33–66% |
| Grade III (Severe) | Markedly increased echogenicity; diaphragm and posterior liver poorly visualized | >66% |
How to stop metformin in a 60 year old male taking it from previous 5 years now presents with normal hba1c and fasting blood sugar on 90
"metformin" AND "discontinuation" AND "type 2 diabetes" AND "glycemic control"
when to stop metformin type 2 diabetes normal HbA1c guidelines deprescribing
https://diabetesonthenet.com/wp-content/uploads/3.-Ali_Depre…
| Question | Relevance |
|---|---|
| Has he lost significant weight / changed diet? | T2DM remission is achievable with weight loss ≥10–15% |
| Is his HbA1c truly in the normal range (≤5.6% / ≤38 mmol/mol) or just "well-controlled"? | Different implications |
| Fasting glucose 90 mg/dL (5 mmol/L) — normal and not over-treated | Reassuring |
| Any renal impairment (eGFR)? | May be an independent reason to stop |
| Is metformin the only drug, or are there others? | Deprescribing order matters |
| Any hypoglycaemic episodes? | Unlikely with metformin alone (low hypo risk) but relevant if on combination |
| Step | Action | Duration |
|---|---|---|
| Step 1 | Reduce by 500–1000 mg (e.g., from 1000 mg BD → 500 mg BD or 1000 mg OD) | 3 months |
| Step 2 | Check HbA1c. If still at target → reduce further (e.g., 500 mg OD) | 3 months |
| Step 3 | Check HbA1c. If still normal → stop completely | — |
| Follow-up | Recheck HbA1c 3 months after stopping | Ongoing |
Each dose reduction step should be separated by ~3 months to allow HbA1c to reflect the change (HbA1c lags by 8–12 weeks).
| Factor | Implication |
|---|---|
| Age 60 — not yet "elderly frail" | Standard deprescribing approach appropriate |
| 5 years on metformin | His beta-cell reserve may be partially preserved if lifestyle is good |
| Metformin's pleiotropic benefits | It has cardiovascular-neutral to mildly beneficial effects; also reduces risk of some cancers (colon, breast) — worth discussing |
| Renal function (eGFR) | Must be checked; if eGFR <30 ml/min, stopping is mandatory anyway |
| B12 levels | Long-term metformin (>3–5 years) causes B12 malabsorption in ~30% — check B12 and supplement if low |
55year old female presents with leg swelling which resolves on taking rest and has no pain
55 year old female bilateral leg swelling painless resolves with rest differential diagnosis causes
| Feature | Clinical Significance |
|---|---|
| Painless | Rules out DVT, cellulitis, acute arterial ischaemia, compartment syndrome |
| Resolves with rest / limb elevation | Strongly suggests venous or systemic (hydrostatic) oedema — NOT lymphoedema (lymphoedema does NOT respond to elevation) |
| 55-year-old female | Post-menopausal age → venous insufficiency, cardiac, thyroid, or hormonal causes more common |
| Bilateral assumed | Points to systemic causes; unilateral would push toward local venous/lymphatic pathology |
| Cause | Clue |
|---|---|
| Heart failure (right-sided or biventricular) | Bilateral pitting oedema, JVP raised, breathlessness, orthopnoea |
| Hypothyroidism | Non-pitting/myxoedema, fatigue, cold intolerance, dry skin, constipation — common in women this age |
| Hypoalbuminaemia (nephrotic syndrome, cirrhosis, malnutrition) | Bilateral soft pitting oedema, frothy urine (nephrotic), jaundice (liver) |
| Renal failure / CKD | Periorbital oedema too, hypertension |
| Anaemia | High-output state can cause oedema |
| Cause | Notes |
|---|---|
| Medications | Amlodipine (CCBs), NSAIDs, steroids, hormones (HRT/OCPs), gabapentin, pioglitazone — ask full drug history |
| Lymphoedema (early/Stage I) | Soft pitting at this stage, may mimic venous oedema; but typically does NOT resolve with overnight elevation |
| Lipedema | Bilateral symmetric fatty enlargement of legs, spares feet; NOT pitting, NOT relieved by elevation; common in women; often misdiagnosed as oedema |
| Pelvic mass / compression | Bilateral venous outflow obstruction — gynaecological cause important at this age |
| Pregnancy-related / post-menopausal hormonal | Less relevant unless on HRT |
| Test | Purpose |
|---|---|
| Serum albumin, LFTs | Liver disease, hypoalbuminaemia |
| Urine dipstick + spot urine protein:creatinine | Nephrotic syndrome |
| TSH | Hypothyroidism — high yield in 55F |
| BNP / NT-proBNP | Heart failure screen |
| FBC | Anaemia |
| Renal function (creatinine, eGFR) | CKD |
| Venous duplex ultrasound (lower limbs) | Gold standard for CVI; rules out DVT |
| ECG + Echo | If cardiac cause suspected |
| Pelvic ultrasound | If pelvic mass suspected |
Create a quick reference guide for oedema workup
mkdir -p /home/daytona/workspace/oedema-guide && ls /home/daytona/workspace/
~/oedema-guide/build_oedema_guide.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm, mm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import PageBreak
OUTPUT = "/home/daytona/workspace/oedema-guide/Oedema_Workup_Quick_Reference.pdf"
# ── Colours ──────────────────────────────────────────────────────────────────
NAVY = colors.HexColor("#1a3a5c")
TEAL = colors.HexColor("#1a7d8e")
LIGHT_TEAL= colors.HexColor("#d4eef2")
AMBER = colors.HexColor("#e07b1a")
AMBER_LT = colors.HexColor("#fef3e2")
RED = colors.HexColor("#c0392b")
RED_LT = colors.HexColor("#fdecea")
GREEN = colors.HexColor("#1e7d4b")
GREEN_LT = colors.HexColor("#e6f4ed")
GREY_LT = colors.HexColor("#f5f5f5")
GREY_MID = colors.HexColor("#d0d0d0")
WHITE = colors.white
BLACK = colors.black
W, H = A4
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
leftMargin=1.5*cm, rightMargin=1.5*cm,
topMargin=2.0*cm, bottomMargin=1.8*cm,
title="Oedema Workup Quick Reference",
author="Orris Medical"
)
styles = getSampleStyleSheet()
# Custom paragraph styles
def S(name, parent='Normal', **kw):
return ParagraphStyle(name, parent=styles[parent], **kw)
title_style = S("Title2", fontSize=20, textColor=WHITE, alignment=TA_CENTER,
fontName="Helvetica-Bold", spaceAfter=2)
subtitle_style= S("Sub", fontSize=9, textColor=colors.HexColor("#b0d4db"),
alignment=TA_CENTER, fontName="Helvetica")
h1_style = S("H1", fontSize=11, textColor=WHITE, fontName="Helvetica-Bold",
spaceAfter=1, spaceBefore=1)
h2_style = S("H2", fontSize=9, textColor=NAVY, fontName="Helvetica-Bold",
spaceAfter=2, spaceBefore=4)
body_style = S("Body", fontSize=8, textColor=BLACK, fontName="Helvetica",
spaceAfter=2, leading=11)
small_style = S("Small", fontSize=7.5,textColor=colors.HexColor("#444444"),
fontName="Helvetica", leading=10)
bold_style = S("Bold", fontSize=8, textColor=BLACK, fontName="Helvetica-Bold",
spaceAfter=2)
red_bold = S("RedBold",fontSize=8, textColor=RED, fontName="Helvetica-Bold")
green_bold = S("GreenBold",fontSize=8,textColor=GREEN,fontName="Helvetica-Bold")
amber_bold = S("AmberBold",fontSize=8,textColor=AMBER,fontName="Helvetica-Bold")
footer_style = S("Footer", fontSize=7, textColor=colors.grey,
alignment=TA_CENTER)
USABLE_W = W - 3*cm # left+right margins
# ── Helper: section header band ──────────────────────────────────────────────
def section_header(text, bg=NAVY):
data = [[Paragraph(text, h1_style)]]
t = Table(data, colWidths=[USABLE_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
return t
def teal_header(text):
return section_header(text, bg=TEAL)
def hr():
return HRFlowable(width="100%", thickness=0.5, color=GREY_MID, spaceAfter=3)
# ── Title block ───────────────────────────────────────────────────────────────
def build_title():
data = [[
Paragraph("OEDEMA WORKUP", title_style),
Paragraph("Quick Reference Guide for General Practitioners", subtitle_style)
]]
t = Table([[
Paragraph("OEDEMA WORKUP", title_style)
]], colWidths=[USABLE_W])
t.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,-1), NAVY),
("TOPPADDING",(0,0),(-1,-1), 14),
("BOTTOMPADDING",(0,0),(-1,-1), 6),
("LEFTPADDING",(0,0),(-1,-1), 10),
]))
sub = Table([[Paragraph("Quick Reference Guide • General Practitioners", subtitle_style)]],
colWidths=[USABLE_W])
sub.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,-1), TEAL),
("TOPPADDING",(0,0),(-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1), 5),
]))
return [t, sub]
# ── STEP 1: Classify ──────────────────────────────────────────────────────────
def build_step1():
elems = []
elems.append(Spacer(1, 6))
elems.append(section_header("STEP 1 — CLASSIFY THE OEDEMA"))
elems.append(Spacer(1, 4))
data = [
[Paragraph("<b>Feature</b>", bold_style),
Paragraph("<b>Pitting</b>", bold_style),
Paragraph("<b>Non-Pitting</b>", bold_style)],
[Paragraph("Press test (5s)", small_style),
Paragraph("Pit remains >10s", small_style),
Paragraph("Pit disappears rapidly", small_style)],
[Paragraph("Texture", small_style),
Paragraph("Soft, fluctuant", small_style),
Paragraph("Firm, rubbery / doughy", small_style)],
[Paragraph("Causes", small_style),
Paragraph("Cardiac, renal, hepatic,\nvenous, drugs, low albumin", small_style),
Paragraph("Lymphoedema, myxoedema,\nlipedema", small_style)],
[Paragraph("Elevation response", small_style),
Paragraph("✓ Usually resolves", small_style),
Paragraph("✗ Minimal or absent", small_style)],
]
col_w = [USABLE_W*0.28, USABLE_W*0.36, USABLE_W*0.36]
t = Table(data, colWidths=col_w)
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), LIGHT_TEAL),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, GREY_LT]),
("GRID", (0,0), (-1,-1), 0.4, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
elems.append(t)
elems.append(Spacer(1, 3))
# Unilateral vs bilateral banner
side_data = [
[Paragraph("<b>UNILATERAL SWELLING</b>", bold_style),
Paragraph("<b>BILATERAL SWELLING</b>", bold_style)],
[Paragraph("• DVT / thrombophlebitis\n• Cellulitis\n• Baker's cyst rupture\n"
"• Lymphoedema (primary/secondary)\n• Popliteal artery aneurysm\n"
"• Tumour / lymph node compression", small_style),
Paragraph("• Heart failure (most common)\n• Chronic venous insufficiency\n"
"• Hypothyroidism / myxoedema\n• Hypoalbuminaemia (nephrotic, cirrhosis)\n"
"• Medications\n• Dependent / orthostatic\n• Lipedema", small_style)],
]
side_t = Table(side_data, colWidths=[USABLE_W/2, USABLE_W/2])
side_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), RED_LT),
("BACKGROUND", (1,0), (1,0), LIGHT_TEAL),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("GRID", (0,0), (-1,-1), 0.4, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 7),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
elems.append(side_t)
return elems
# ── STEP 2: History red flags ─────────────────────────────────────────────────
def build_step2():
elems = []
elems.append(Spacer(1, 6))
elems.append(section_header("STEP 2 — HISTORY: KEY QUESTIONS & RED FLAGS"))
elems.append(Spacer(1, 4))
hx_data = [
[Paragraph("<b>Question</b>", bold_style),
Paragraph("<b>Positive finding → Think</b>", bold_style)],
[Paragraph("Onset & duration?", small_style),
Paragraph("Acute (<72h) → DVT, cellulitis, heart failure decompensation", small_style)],
[Paragraph("Worse with standing/sitting?", small_style),
Paragraph("Yes → Chronic venous insufficiency or dependent oedema", small_style)],
[Paragraph("Relieves with elevation/rest?", small_style),
Paragraph("Yes → Venous/systemic. No → Lymphoedema", small_style)],
[Paragraph("Painful?", small_style),
Paragraph("Yes → DVT, cellulitis, gout, lipodermatosclerosis", small_style)],
[Paragraph("Breathlessness / orthopnoea / PND?", small_style),
Paragraph("→ Heart failure (biventricular or right-sided)", small_style)],
[Paragraph("Frothy urine / periorbital puffiness?", small_style),
Paragraph("→ Nephrotic syndrome", small_style)],
[Paragraph("Fatigue, weight gain, cold intolerance?", small_style),
Paragraph("→ Hypothyroidism", small_style)],
[Paragraph("Jaundice, alcohol, known liver disease?", small_style),
Paragraph("→ Cirrhosis / hepatic hypoalbuminaemia", small_style)],
[Paragraph("Recent immobility / travel / surgery?", small_style),
Paragraph("→ DVT", small_style)],
[Paragraph("Medications?", small_style),
Paragraph("CCBs (amlodipine), NSAIDs, steroids, HRT,\ngabapentin, pioglitazone, minoxidil", small_style)],
[Paragraph("Pelvic symptoms / history of cancer?", small_style),
Paragraph("→ Pelvic mass obstructing venous/lymphatic return", small_style)],
]
t = Table(hx_data, colWidths=[USABLE_W*0.38, USABLE_W*0.62])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), LIGHT_TEAL),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, GREY_LT]),
("GRID", (0,0), (-1,-1), 0.4, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING",(0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
elems.append(t)
# Red flags box
elems.append(Spacer(1, 5))
rf_data = [[
Paragraph("🚨 RED FLAGS — Urgent referral / same-day assessment", ParagraphStyle(
"rf_hdr", fontSize=8.5, textColor=WHITE, fontName="Helvetica-Bold")),
],[
Paragraph(
"• Acute unilateral painful swollen leg → rule out DVT (Wells score + D-dimer / USS)\n"
"• Breathlessness + bilateral oedema → acute heart failure\n"
"• Fever + warm erythematous leg → cellulitis / necrotising fasciitis\n"
"• Rapid onset + rash + bronchospasm → anaphylaxis\n"
"• Leg oedema + haemoptysis → PE with right heart strain",
small_style)
]]
rf_t = Table(rf_data, colWidths=[USABLE_W])
rf_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), RED),
("BACKGROUND", (0,1), (-1,-1), RED_LT),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
("BOX", (0,0), (-1,-1), 0.8, RED),
]))
elems.append(rf_t)
return elems
# ── STEP 3: Examination ───────────────────────────────────────────────────────
def build_step3():
elems = []
elems.append(Spacer(1, 6))
elems.append(section_header("STEP 3 — FOCUSED EXAMINATION"))
elems.append(Spacer(1, 4))
ex_data = [
[Paragraph("<b>Finding</b>", bold_style),
Paragraph("<b>Diagnosis to consider</b>", bold_style)],
[Paragraph("Pitting oedema — ankles/legs", small_style),
Paragraph("Cardiac, renal, hepatic, venous, drugs", small_style)],
[Paragraph("Non-pitting, rubbery oedema", small_style),
Paragraph("Lymphoedema (Stage II+), myxoedema", small_style)],
[Paragraph("Stemmer sign +ve", small_style),
Paragraph("Lymphoedema (unable to pinch skin at base of 2nd toe)", small_style)],
[Paragraph("Raised JVP + S3 + crackles", small_style),
Paragraph("Heart failure", small_style)],
[Paragraph("Ascites + spider naevi + jaundice", small_style),
Paragraph("Cirrhosis", small_style)],
[Paragraph("Periorbital puffiness", small_style),
Paragraph("Nephrotic syndrome, hypothyroidism", small_style)],
[Paragraph("Thyroid enlargement + bradycardia + dry skin", small_style),
Paragraph("Hypothyroidism", small_style)],
[Paragraph("Varicose veins + skin hyperpigmentation + lipodermatosclerosis", small_style),
Paragraph("Chronic venous insufficiency", small_style)],
[Paragraph("Warm, tender, erythema, tracking", small_style),
Paragraph("Cellulitis / lymphangitis", small_style)],
[Paragraph("Positive Homan's sign (low sensitivity)", small_style),
Paragraph("Consider DVT (use Wells score — do not rely on sign alone)", small_style)],
[Paragraph("Symmetric bilateral leg fat (spares feet)", small_style),
Paragraph("Lipedema — NOT true oedema", small_style)],
]
t = Table(ex_data, colWidths=[USABLE_W*0.44, USABLE_W*0.56])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), LIGHT_TEAL),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, GREY_LT]),
("GRID", (0,0), (-1,-1), 0.4, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING",(0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
elems.append(t)
return elems
# ── STEP 4: Investigations ────────────────────────────────────────────────────
def build_step4():
elems = []
elems.append(Spacer(1, 6))
elems.append(section_header("STEP 4 — INVESTIGATIONS (TIERED APPROACH)"))
elems.append(Spacer(1, 4))
# Tier 1
elems.append(Paragraph("TIER 1 — First-Line (All patients with unexplained oedema)", h2_style))
t1_data = [
[Paragraph("<b>Test</b>", bold_style), Paragraph("<b>Detects</b>", bold_style)],
[Paragraph("FBC", small_style), Paragraph("Anaemia, infection", small_style)],
[Paragraph("Serum albumin + LFTs", small_style),
Paragraph("Hypoalbuminaemia, hepatic disease", small_style)],
[Paragraph("Renal profile (creatinine, urea, eGFR, electrolytes)", small_style),
Paragraph("CKD, nephrotic syndrome", small_style)],
[Paragraph("Urine dipstick + spot urine PCR", small_style),
Paragraph("Proteinuria → nephrotic (PCR >300 mg/mmol)", small_style)],
[Paragraph("TSH", small_style),
Paragraph("Hypothyroidism — very high yield in women >50 y", small_style)],
[Paragraph("BNP / NT-proBNP", small_style),
Paragraph("Heart failure (NT-proBNP >125 pg/mL is abnormal)", small_style)],
[Paragraph("Fasting glucose / HbA1c", small_style),
Paragraph("Diabetic nephropathy context", small_style)],
]
t1 = Table(t1_data, colWidths=[USABLE_W*0.47, USABLE_W*0.53])
t1.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), GREEN_LT),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, GREY_LT]),
("GRID", (0,0), (-1,-1), 0.4, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING",(0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
elems.append(t1)
elems.append(Spacer(1, 5))
elems.append(Paragraph("TIER 2 — Directed by Clinical Suspicion", h2_style))
t2_data = [
[Paragraph("<b>Test</b>", bold_style), Paragraph("<b>When to order</b>", bold_style)],
[Paragraph("Venous duplex USS (lower limbs)", small_style),
Paragraph("Suspected DVT, chronic venous insufficiency", small_style)],
[Paragraph("ECG + Echocardiogram", small_style),
Paragraph("Raised BNP, clinical heart failure", small_style)],
[Paragraph("Chest X-ray", small_style),
Paragraph("Suspected cardiac failure, pleural effusion", small_style)],
[Paragraph("D-dimer", small_style),
Paragraph("Low–moderate Wells score for DVT (do NOT test if high pre-test probability)", small_style)],
[Paragraph("Pelvic / abdominal USS", small_style),
Paragraph("Suspected pelvic mass, liver / renal pathology", small_style)],
[Paragraph("24-hr urine protein / renal biopsy", small_style),
Paragraph("Confirmed nephrotic range proteinuria", small_style)],
[Paragraph("Lymphoscintigraphy", small_style),
Paragraph("Suspected lymphoedema — specialist referral", small_style)],
[Paragraph("Lipid profile", small_style),
Paragraph("Nephrotic syndrome (associated hyperlipidaemia)", small_style)],
]
t2 = Table(t2_data, colWidths=[USABLE_W*0.47, USABLE_W*0.53])
t2.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), AMBER_LT),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, GREY_LT]),
("GRID", (0,0), (-1,-1), 0.4, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING",(0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
elems.append(t2)
return elems
# ── STEP 5: Diagnosis-specific management ────────────────────────────────────
def build_step5():
elems = []
elems.append(Spacer(1, 6))
elems.append(section_header("STEP 5 — DIAGNOSIS-SPECIFIC MANAGEMENT SUMMARY"))
elems.append(Spacer(1, 4))
mgmt = [
[Paragraph("<b>Diagnosis</b>", bold_style),
Paragraph("<b>First-line management</b>", bold_style),
Paragraph("<b>Refer if…</b>", bold_style)],
[Paragraph("Heart failure", small_style),
Paragraph("Loop diuretic (furosemide), ACEI/ARB,\nbeta-blocker, salt restriction", small_style),
Paragraph("EF <40%, refractory, new diagnosis", small_style)],
[Paragraph("Chronic venous insufficiency", small_style),
Paragraph("Compression stockings (class II, 20–30 mmHg),\nelevation, skin care", small_style),
Paragraph("Ulceration, failed conservative Rx", small_style)],
[Paragraph("DVT", small_style),
Paragraph("DOAC (rivaroxaban / apixaban) — start same day;\nconsider LMWH bridge in cancer", small_style),
Paragraph("Proximal DVT, PE signs, cancer, pregnancy", small_style)],
[Paragraph("Hypothyroidism", small_style),
Paragraph("Levothyroxine; recheck TSH in 6–8 weeks", small_style),
Paragraph("Cardiac comorbidity, elderly, resistant", small_style)],
[Paragraph("Nephrotic syndrome", small_style),
Paragraph("Low-salt diet, loop diuretic, ACEi (antiproteinuric)\nstatin, anticoagulation if albumin <20 g/L", small_style),
Paragraph("All new cases → nephrology", small_style)],
[Paragraph("Cirrhosis / hepatic oedema", small_style),
Paragraph("Salt restriction, spironolactone ± furosemide,\navoid NSAIDs, treat underlying cause", small_style),
Paragraph("Refractory ascites, hepatorenal syndrome", small_style)],
[Paragraph("Drug-induced", small_style),
Paragraph("Stop or switch offending drug (e.g. switch\namlodipine to another antihypertensive)", small_style),
Paragraph("Persists after drug stopped >4 weeks", small_style)],
[Paragraph("Lymphoedema", small_style),
Paragraph("Complex decongestive therapy (CDT),\nmulti-layer compression bandaging", small_style),
Paragraph("All cases → lymphoedema specialist", small_style)],
[Paragraph("Dependent oedema / CVI", small_style),
Paragraph("Leg elevation, compression, ambulation,\nweight loss, review medications", small_style),
Paragraph("No improvement after 3 months", small_style)],
]
t = Table(mgmt, colWidths=[USABLE_W*0.24, USABLE_W*0.44, USABLE_W*0.32])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), LIGHT_TEAL),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, GREY_LT]),
("GRID", (0,0), (-1,-1), 0.4, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING",(0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
elems.append(t)
return elems
# ── Wells DVT Score ───────────────────────────────────────────────────────────
def build_wells():
elems = []
elems.append(Spacer(1, 6))
elems.append(teal_header("WELLS SCORE FOR DVT (Quick Reference)"))
elems.append(Spacer(1, 4))
w_data = [
[Paragraph("<b>Clinical feature</b>", bold_style), Paragraph("<b>Score</b>", bold_style)],
[Paragraph("Active cancer (treatment within 6 months or palliative)", small_style), Paragraph("+1", small_style)],
[Paragraph("Paralysis, paresis or recent plaster immobilisation of lower extremity", small_style), Paragraph("+1", small_style)],
[Paragraph("Bedridden ≥3 days or major surgery within 4 weeks", small_style), Paragraph("+1", small_style)],
[Paragraph("Localised tenderness along deep venous system", small_style), Paragraph("+1", small_style)],
[Paragraph("Entire leg swollen", small_style), Paragraph("+1", small_style)],
[Paragraph("Calf swelling >3 cm vs asymptomatic side (measured 10 cm below tibial tuberosity)", small_style), Paragraph("+1", small_style)],
[Paragraph("Pitting oedema confined to symptomatic leg", small_style), Paragraph("+1", small_style)],
[Paragraph("Collateral superficial veins (non-varicose)", small_style), Paragraph("+1", small_style)],
[Paragraph("Alternative diagnosis at least as likely as DVT", small_style), Paragraph("<b>−2</b>", bold_style)],
]
wt = Table(w_data, colWidths=[USABLE_W*0.84, USABLE_W*0.16])
wt.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), LIGHT_TEAL),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, GREY_LT]),
("GRID", (0,0), (-1,-1), 0.4, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING",(0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 6),
("ALIGN", (1,0), (1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
elems.append(wt)
score_data = [[
Paragraph("<b>Score ≤0:</b> Low probability → D-dimer; if negative, DVT excluded", small_style),
Paragraph("<b>Score 1–2:</b> Moderate → D-dimer; if positive, do USS", small_style),
Paragraph("<b>Score ≥3:</b> High probability → USS directly (skip D-dimer)", small_style),
]]
st = Table(score_data, colWidths=[USABLE_W/3]*3)
st.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), GREEN_LT),
("BACKGROUND", (1,0), (1,0), AMBER_LT),
("BACKGROUND", (2,0), (2,0), RED_LT),
("GRID", (0,0), (-1,-1), 0.4, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
elems.append(Spacer(1, 3))
elems.append(st)
return elems
# ── Special populations ───────────────────────────────────────────────────────
def build_special():
elems = []
elems.append(Spacer(1, 6))
elems.append(teal_header("SPECIAL POPULATIONS"))
elems.append(Spacer(1, 4))
sp_data = [
[Paragraph("<b>Population</b>", bold_style),
Paragraph("<b>Key considerations</b>", bold_style)],
[Paragraph("Women >50 y (peri/post-menopausal)", small_style),
Paragraph("Hypothyroidism high yield (check TSH). HRT-related. CVI common. Lipedema often misdiagnosed.", small_style)],
[Paragraph("Elderly / frail", small_style),
Paragraph("Polypharmacy (CCBs, steroids). Cardiac failure. Hypoalbuminaemia from malnutrition. Low diuretic threshold to cause AKI.", small_style)],
[Paragraph("Pregnancy", small_style),
Paragraph("Physiological oedema common in 3rd trimester. DVT risk 5× increased. Pre-eclampsia if hypertension + proteinuria.", small_style)],
[Paragraph("Cancer patients", small_style),
Paragraph("DVT / PE risk (Trousseau syndrome). Lymphoedema post-surgery/radiation. Pelvic mass obstruction. Hypoalbuminaemia.", small_style)],
[Paragraph("Patients with CKD", small_style),
Paragraph("Avoid NSAIDs. Furosemide doses may need to be higher. Refer nephrology if rapid progression.", small_style)],
]
sp_t = Table(sp_data, colWidths=[USABLE_W*0.28, USABLE_W*0.72])
sp_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), LIGHT_TEAL),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, GREY_LT]),
("GRID", (0,0), (-1,-1), 0.4, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING",(0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
elems.append(sp_t)
return elems
# ── Footer note ───────────────────────────────────────────────────────────────
def build_footer():
elems = []
elems.append(Spacer(1, 8))
elems.append(HRFlowable(width="100%", thickness=0.5, color=GREY_MID))
elems.append(Spacer(1, 3))
elems.append(Paragraph(
"Sources: Harrison's Principles of Internal Medicine 22E (2025) · Sabiston Textbook of Surgery 11E · "
"Goldman-Cecil Medicine · NICE Guidelines CG144 (Heart Failure) · ESC Guidelines 2023 (Heart Failure, PE) | "
"For clinical use by qualified practitioners only. Always apply clinical judgement.",
footer_style))
return elems
# ── Assemble document ─────────────────────────────────────────────────────────
story = []
story += build_title()
story += build_step1()
story += build_step2()
story += build_step3()
story += build_step4()
story += build_step5()
story += build_wells()
story += build_special()
story += build_footer()
doc.build(story)
print(f"PDF generated: {OUTPUT}")
cd /home/daytona/workspace/oedema-guide && python build_oedema_guide.py
ls -lh /home/daytona/workspace/oedema-guide/
Oedema Workup Quick Reference
PDF Document · PDF
| Section | Content |
|---|---|
| Step 1 — Classify | Pitting vs non-pitting table; Unilateral vs bilateral differential diagnosis |
| Step 2 — History | 12-question key history table with diagnostic pointers; Red flags box (DVT, acute HF, cellulitis, PE) |
| Step 3 — Examination | 12-sign examination table with diagnoses (Stemmer sign, JVP, S3, varicosities, etc.) |
| Step 4 — Investigations | Tiered approach: Tier 1 (all patients) + Tier 2 (directed by suspicion) |
| Step 5 — Management | 9 diagnoses with first-line treatment and referral criteria |
| Wells DVT Score | Full scoring table + colour-coded interpretation (Low/Moderate/High) |
| Special Populations | Women >50y, elderly, pregnancy, cancer, CKD |