Bulild case on iron deficiency anemia
"iron deficiency anemia"[MeSH Terms] AND diagnosis AND treatment
iron deficiency anemia peripheral blood smear microcytic hypochromic

Peripheral blood smear from a patient with known chronic lymphocytic leukemia (CLL) showing autoimmune hemolytic anemia (AIHA). Brightfield microscopy of Wright-Giemsa stained smear at 1000x (oil immersion) reveals two dominant cell populations: numerous small mature lymphocytes typical of CLL and red blood cells showing spherocytic deformation. A smudge cell is evident just left of center, a classical clue for CLL. Red cells display reduced central pallor consistent with spherocytes, indicating intravascular or extravascular hemolysis driven by autoantibodies. The background shows mild polychromasia and rare nucleated RBCs, consistent with a robust reticulocyte response; the corrected reticulocyte count in this case is markedly elevated (>7%). Platelets are not significantly abnormal. These features collectively support autoimmune destruction of erythrocytes in the setting of CLL. Diagnostic significance lies in recognizing AIHA as a common autoimmune complication in CLL, with a clinical picture of sudden Hb decline and compensatory erythropoiesis. Differential considerations include drug-induced hemolysis, other causes of hemolytic anemia, or marrow infiltration by CLL. Clinical correlation includes therapy implications (steroids, rituximab) and close monitoring of hemolysis markers. This image is a valuable teaching resource for hematology morphology, AIHA in CLL, and differential diagnosis in anemia.

This composite image consists of clinical photographs and a diagnostic peripheral blood smear. Figure 1a (left) shows a pediatric patient with clinical signs including total alopecia (complete absence of scalp hair) and nail pitting affecting both hands and feet, characterized by small punctate depressions on the nail plates. Figure 1b (right) is a microscopic view of a peripheral blood smear demonstrating microangiopathic hemolytic anemia. Visible are numerous schistocytes—fragmented, irregular red blood cells including helmet cells and triangular forms—alongside some normal erythrocytes showing central pallor. The educational focus is on the multi-systemic manifestations of a medical condition, likely a microangiopathic process such as Hemolytic Uremic Syndrome (HUS) or similar systemic pathology, illustrating the correlation between dermatological signs (hair and nail changes) and hematological abnormalities (hemolysis and schistocytosis).

Peripheral blood smear prepared with Wright-Giemsa stain and examined under brightfield illumination using a 100× oil immersion objective reveals a single large plasma cell among a field of mature erythrocytes. The plasma cell displays features typical of clonal plasma cells: basophilic cytoplasm, an eccentrically placed round nucleus, and a conspicuous perinuclear hof; background shows rouleaux formation of red cells. This image exemplifies hematologic involvement by a plasma cell dyscrasia. In plasma cell leukemia, circulating plasma cells constitute more than 20% of leukocytes, a hallmark distinguishing it from conventional multiple myeloma, although both conditions share monoclonal plasma cell proliferation. The presence of circulating plasma cells is associated with younger patient age, higher incidence of anemia, thrombocytopenia, organomegaly, and possible lymphadenopathy; however lytic bone lesions may be less common. Immunophenotypic patterns often include lack of CD56 expression relative to myeloma. Clinically, this morphological finding warrants confirmation with complete blood count, peripheral smear review, quantitative plasma cell percentage, serum protein electrophoresis, and immunofixation to identify monoclonal immunoglobulin isotype (IgD/IgE or light-chain predominance). Early detection of circulating plasma cells supports prognosis assessment and guides therapy decisions in plasma cell dyscrasia management and monitoring, including risk stratification and treatment response evaluation for practice in clinics.

A comparative medical illustration detailing the effects of iron dysregulation on wound healing and systemic states. The left panel depicts a 'Low Iron' and 'Inflammation' scenario where a cutaneous wound is associated with 'Iron-deficiency anemia'. Key signaling molecules shown include TGF, IL-6, IL-8, and ECM components within a wound bed containing fibroblasts and matrix elements. An arrow indicates the downstream impact on the underlying epithelium and hemoglobin within the bloodstream. The right panel depicts an 'Excessive Iron' and 'Skin damage' scenario characterized by 'Excessive iron deposition'. This state is visually distinguished by an inhibitory symbol (red T-bar) directed at the epithelium, suggesting impaired regenerative capacity. Notably, the epithelium in the high-iron state contains yellow granules labeled as 'Iron-containing haematoxylin' (hemosiderin), which serve as a histological marker of iron overload. Both panels show the anatomical relationship between the cutaneous wound, underlying epithelial cells, and the intravascular space (bloodstream) containing red blood cells and hemoglobin, illustrating how iron homeostasis is critical for normal dermatological repair and systemic oxygen transport.
"iron deficiency anemia"[MeSH Terms] AND treatment
iron deficiency anemia koilonychia spoon nails clinical signs

This is a high-resolution clinical photograph of a human fingernail demonstrating koilonychia, also called spoon nails. Imaging modality is clinical photography with macro/close-up technique to enhance surface and curvature details. The primary subject is the fingernail plate and surrounding nail folds, captured from a dorsal perspective for clear visualization of the nail curvature. The nail plate appears thin and concave, with a pronounced central depression producing a spoon-shaped contour. Lateral edges may be slightly tapered, and the distal third of the plate shows mild translucency. The surface is relatively smooth with minimal ridging, and the lunula is less conspicuous in this view. Surrounding cuticle and perionychial skin show mild erythema, possibly secondary to manipulation or irritation; no frank edema or pitting is evident. Clinically, koilonychia is a classic morphological clue associated with iron deficiency anemia and other nutritional or systemic disorders; in many cases nails become spoon-shaped due to chronic iron depletion. The diagnostic significance lies in recognizing a potentially reversible sign when iron stores are restored. This image is useful for dermatology, medical education, nursing training, and clinical scenario discussions focused on anemia screening, differential diagnosis of nail dystrophies, and patient education about nail changes as a diagnostic cue. Consider correlating with CBC and ferritin, and monitoring response to iron therapy.

This clinical photograph displays the dorsal surface of both hands of a patient against a medical drape. The primary focus is the prominent nail pathology consistent with koilonychia (spoon nails). The fingernails exhibit a characteristic concave, upward-curving shape, appearing flattened or scooped out. Additionally, there is significant chromonychia characterized by brownish discoloration, with some nails showing hyperpigmented, dark areas near the distal and lateral margins. The nails appear thin and brittle in texture. An intravenous (IV) catheter is secured with white adhesive tape on the dorsum of the right hand, indicating an acute clinical setting. These physical findings are classic cutaneous markers of chronic iron deficiency anemia and are relevant to systemic conditions such as Plummer-Vinson syndrome. The image serves as a diagnostic educational resource for identifying dermatological manifestations of systemic hematologic disorders.
iron deficiency anemia microcytic hypochromic red blood cells blood film smear

Educational figure illustrating hematological abnormalities in a murine model of Prkab1 deficiency, serving as a surrogate for studying human hemolytic anemia and microcytosis. Panels A-F present dot plots of hematological indices for wild-type (Prkab1+/+) and deficient (Prkab1tm1b/tm1b) mice, showing significant reductions in hemoglobin (A), hematocrit (B), and mean corpuscular volume (E), with a concomitant increase in red blood cell distribution width (F), indicating microcytic anemia with anisocytosis. Panel G contains high-resolution Scanning Electron Microscopy (SEM) images comparing erythrocyte morphology; wild-type cells show standard biconcave discocyte morphology, whereas Prkab1-deficient cells exhibit poikilocytosis with numerous abnormal forms, including acanthocytes, schistocytes, and echinocytes with irregular surface protrusions. Panel H displays an osmotic resistance curve, where Prkab1-deficient erythrocytes demonstrate a left-ward shift, signifying increased osmotic resistance (delayed hemolysis) compared to wild-type controls. The inset confirms a lower NaCl percentage required for 50% hemolysis in deficient cells, indicating altered membrane stability.

Peripheral blood smear from a patient with known chronic lymphocytic leukemia (CLL) showing autoimmune hemolytic anemia (AIHA). Brightfield microscopy of Wright-Giemsa stained smear at 1000x (oil immersion) reveals two dominant cell populations: numerous small mature lymphocytes typical of CLL and red blood cells showing spherocytic deformation. A smudge cell is evident just left of center, a classical clue for CLL. Red cells display reduced central pallor consistent with spherocytes, indicating intravascular or extravascular hemolysis driven by autoantibodies. The background shows mild polychromasia and rare nucleated RBCs, consistent with a robust reticulocyte response; the corrected reticulocyte count in this case is markedly elevated (>7%). Platelets are not significantly abnormal. These features collectively support autoimmune destruction of erythrocytes in the setting of CLL. Diagnostic significance lies in recognizing AIHA as a common autoimmune complication in CLL, with a clinical picture of sudden Hb decline and compensatory erythropoiesis. Differential considerations include drug-induced hemolysis, other causes of hemolytic anemia, or marrow infiltration by CLL. Clinical correlation includes therapy implications (steroids, rituximab) and close monitoring of hemolysis markers. This image is a valuable teaching resource for hematology morphology, AIHA in CLL, and differential diagnosis in anemia.

A comparative medical illustration detailing the effects of iron dysregulation on wound healing and systemic states. The left panel depicts a 'Low Iron' and 'Inflammation' scenario where a cutaneous wound is associated with 'Iron-deficiency anemia'. Key signaling molecules shown include TGF, IL-6, IL-8, and ECM components within a wound bed containing fibroblasts and matrix elements. An arrow indicates the downstream impact on the underlying epithelium and hemoglobin within the bloodstream. The right panel depicts an 'Excessive Iron' and 'Skin damage' scenario characterized by 'Excessive iron deposition'. This state is visually distinguished by an inhibitory symbol (red T-bar) directed at the epithelium, suggesting impaired regenerative capacity. Notably, the epithelium in the high-iron state contains yellow granules labeled as 'Iron-containing haematoxylin' (hemosiderin), which serve as a histological marker of iron overload. Both panels show the anatomical relationship between the cutaneous wound, underlying epithelial cells, and the intravascular space (bloodstream) containing red blood cells and hemoglobin, illustrating how iron homeostasis is critical for normal dermatological repair and systemic oxygen transport.

| Parameter | Result | Reference Range |
|---|---|---|
| Hemoglobin | 8.4 g/dL | 12-16 g/dL (F) |
| MCV | 68 fL | 80-100 fL |
| MCH | 21 pg | 27-33 pg |
| MCHC | 28 g/dL | 32-36 g/dL |
| RDW | 18% | <14.5% |
| WBC | 7,200/μL | 4,000-11,000 |
| Platelets | 420,000/μL | 150,000-400,000 |
| Reticulocyte count | 1.2% | 0.5-2.5% |
| Parameter | Result | Reference Range | Interpretation |
|---|---|---|---|
| Serum Iron | 38 μg/dL | 60-170 μg/dL | LOW |
| TIBC | 420 μg/dL | 240-360 μg/dL | HIGH |
| Transferrin Saturation | 9% | 20-50% | LOW (<15% = diagnostic) |
| Serum Ferritin | 6 μg/L | 12-150 μg/L | LOW (<12 μg/L = depleted stores) |
Diagnostic clue: Ferritin <12 μg/L confirms depleted iron stores with near 99% specificity. Transferrin saturation <15% is a sensitive indicator of iron-restricted erythropoiesis. - Sleisenger and Fordtran's GI and Liver Disease, p. 332
| Test | Result |
|---|---|
| Peripheral blood smear | Microcytes, hypochromic RBCs, pencil cells, anisocytosis, poikilocytosis |
| HbA2 / HbF (HPLC) | Normal - rules out thalassemia trait |
| Stool for occult blood | Negative |
| Celiac serology (anti-tTG IgA) | Negative |
| Thyroid function (TSH) | Normal |
| Urine routine | Normal |

| Stage | Iron Stores | Erythropoiesis | Hb | Ferritin | TIBC | Transferrin Sat |
|---|---|---|---|---|---|---|
| Stage 1 - Iron depletion | Depleted | Normal | Normal | ↓ | ↑ | Normal |
| Stage 2 - Iron-deficient erythropoiesis | Absent | Impaired | Normal/↓ | ↓↓ | ↑↑ | <20% |
| Stage 3 - Iron deficiency anemia | Absent | Severely impaired | ↓↓ | <12 μg/L | ↑↑↑ | <15% |
| Pool | Males (mg) | Females (mg) |
|---|---|---|
| Total | 3,450 | 2,450 |
| Hemoglobin | 2,100 | 1,750 |
| Myoglobin | 300 | 250 |
| Enzymes (cytochromes, catalase) | 50 | 50 |
| Storage (ferritin + hemosiderin) | 1,000 | 400 |
Normal daily diet in the United States contains 10-20 mg iron; the average daily loss is only 1-2 mg. The mismatch arises when losses exceed the absorptive capacity (~2-3 mg/day maximum). - Robbins, Cotran & Kumar Pathologic Basis of Disease, p. 612
| Sign | Description |
|---|---|
| Koilonychia | Concave (spoon) nails due to nail plate thinning - seen above |
| Angular cheilitis | Painful cracking at the corners of the mouth |
| Glossitis | Smooth, atrophic, painful tongue (loss of papillae) |
| Pica | Craving for non-food substances - ice (pagophagia), dirt (geophagia), paper |
| Plummer-Vinson syndrome | IDA + dysphagia + postcricoid esophageal web (rare, high-risk for esophageal SCC) |
| Restless leg syndrome | Uncomfortable sensations in legs, worse at rest |
| Blue sclerae | Mild, subtle finding |
| Condition | Ferritin | Serum Iron | TIBC | Transferrin Sat | RDW | Key Distinguisher |
|---|---|---|---|---|---|---|
| Iron deficiency anemia | ↓↓ (<15-30) | ↓ | ↑ | ↓ (<15%) | ↑ | Responds to iron |
| Anemia of Inflammation | Normal/↑ (>100) | ↓ | ↓ | ↓ | Normal | Chronic disease present; IL-6 ↑ |
| Thalassemia trait | Normal/↑ | Normal | Normal | Normal | Normal/↑ | HbA2 >3.5% (β-thal); ethnic background; does NOT respond to iron |
| Sideroblastic anemia | ↑ | ↑ | Normal | ↑ | ↑ | Ring sideroblasts on marrow |
| Mixed (IDA + AoI) | Low-normal (<70-100) | ↓ | Normal | ↓ | ↑ | IBD, CKD, aging |
In anemia of chronic disease, both serum iron AND TIBC are low (unlike IDA where TIBC is high), with a normal-to-elevated ferritin. Thalassemia trait shows a low MCV but normal iron studies and elevated HbA2. - Sleisenger and Fordtran's GI and Liver Disease, p. 333
| Group | Key Consideration |
|---|---|
| Pregnant women | Iron requirement rises to 4-5 mg/day in 3rd trimester; routinely supplement all pregnant women; IV iron preferred if Hb <9 g/dL in 3rd trimester |
| Infants/Toddlers | Cow's milk exclusive feeding, premature birth = high risk; introduce iron-fortified cereals at 4-6 months |
| Elderly | Multiple coexisting causes common (malnutrition, chronic disease, GI blood loss); always investigate underlying cause |
| Post-bariatric surgery | Bypass of duodenum leads to severe malabsorption; IV iron often required long-term |
| Chronic kidney disease | Functional iron deficiency due to high hepcidin; IV iron is standard; target ferritin 200-500 μg/L on dialysis |
| IRIDA (hereditary) | TMPRSS6 mutation; low hepcidin fails to rise; refractory to oral iron; requires IV iron exclusively |
Creat this information in a pdf to save and read whenever I need
ls -la /tmp/workspace/ 2>/dev/null || mkdir -p /tmp/workspace && ls -la /tmp/workspace/
~/ida_case/build_pdf.py
"""
Iron Deficiency Anemia - Clinical Case PDF Generator
Uses ReportLab to produce a professional, well-formatted PDF study guide.
"""
import os
import urllib.request
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether, Image, PageBreak
)
from reportlab.platypus.flowables import BalancedColumns
from reportlab.lib.colors import HexColor
from io import BytesIO
# ── Color palette ─────────────────────────────────────────────────────────────
DARK_BLUE = HexColor("#1a3a5c")
MED_BLUE = HexColor("#2563a8")
LIGHT_BLUE = HexColor("#dbeafe")
ACCENT = HexColor("#e74c3c")
GREEN = HexColor("#16a34a")
LIGHT_GREEN = HexColor("#dcfce7")
YELLOW_BG = HexColor("#fefce8")
AMBER = HexColor("#d97706")
GREY_BG = HexColor("#f3f4f6")
GREY_BORDER = HexColor("#d1d5db")
WHITE = colors.white
OUTPUT_DIR = "/tmp/workspace/ida_case"
os.makedirs(OUTPUT_DIR, exist_ok=True)
OUTPUT_PATH = os.path.join(OUTPUT_DIR, "Iron_Deficiency_Anemia_Clinical_Case.pdf")
# ── Download images ────────────────────────────────────────────────────────────
def download_image(url, filename):
path = os.path.join(OUTPUT_DIR, filename)
try:
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
with urllib.request.urlopen(req, timeout=15) as resp:
with open(path, "wb") as f:
f.write(resp.read())
return path
except Exception as e:
print(f" Warning: could not download {url}: {e}")
return None
print("Downloading images...")
img_metabolism = download_image(
"https://cdn.orris.care/cdss_images/c2568c749b4a3e34b649886d8aefef3b6a8be52c4646a90af0bef8692c797d8c.png",
"iron_metabolism.png"
)
img_koilonychia = download_image(
"https://cdn.orris.care/cdss_images/DermNetNZ_1760031665330_70c78a76-fa65-4380-b25d-8485617dd3c9.jpg",
"koilonychia.jpg"
)
img_iron_wound = download_image(
"https://cdn.orris.care/cdss_images/pmc_clinical_VQA_841baaf17ccb33cae0837c316bb44442539e7b948ef3001e5ce4b61d9858d42a.jpg",
"iron_wound.jpg"
)
# ── Document setup ─────────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
OUTPUT_PATH,
pagesize=A4,
rightMargin=2*cm, leftMargin=2*cm,
topMargin=2.5*cm, bottomMargin=2.5*cm,
title="Iron Deficiency Anemia - Clinical Case",
author="Orris Medical AI",
subject="Hematology Clinical Case Study"
)
W = A4[0] - 4*cm # usable width
# ── Styles ─────────────────────────────────────────────────────────────────────
base = getSampleStyleSheet()
def S(name, parent="Normal", **kw):
return ParagraphStyle(name, parent=base[parent], **kw)
styles = {
"title": S("title", fontSize=22, textColor=WHITE,
fontName="Helvetica-Bold", alignment=TA_CENTER,
spaceAfter=4, leading=26),
"subtitle": S("subtitle", fontSize=12, textColor=LIGHT_BLUE,
fontName="Helvetica", alignment=TA_CENTER,
spaceAfter=2, leading=16),
"h1": S("h1", fontSize=13, textColor=WHITE,
fontName="Helvetica-Bold", spaceBefore=6,
spaceAfter=4, leading=16),
"h2": S("h2", fontSize=11, textColor=DARK_BLUE,
fontName="Helvetica-Bold", spaceBefore=6,
spaceAfter=3, leading=14),
"h3": S("h3", fontSize=10, textColor=MED_BLUE,
fontName="Helvetica-Bold", spaceBefore=4,
spaceAfter=2, leading=13),
"body": S("body", fontSize=9.5, textColor=colors.black,
fontName="Helvetica", spaceAfter=3, leading=14,
alignment=TA_JUSTIFY),
"bullet": S("bullet", fontSize=9.5, textColor=colors.black,
fontName="Helvetica", spaceAfter=2, leading=13,
leftIndent=14, bulletIndent=0),
"small": S("small", fontSize=8.5, textColor=HexColor("#555555"),
fontName="Helvetica-Oblique", spaceAfter=2, leading=12,
alignment=TA_CENTER),
"note": S("note", fontSize=9, textColor=HexColor("#374151"),
fontName="Helvetica-Oblique", spaceAfter=3,
leading=13, leftIndent=8),
"keypoint": S("keypoint", fontSize=9.5, textColor=HexColor("#1e3a5f"),
fontName="Helvetica-Bold", spaceAfter=2, leading=13,
leftIndent=12),
"th": S("th", fontSize=8.5, textColor=WHITE,
fontName="Helvetica-Bold", alignment=TA_CENTER, leading=12),
"td": S("td", fontSize=8.5, textColor=colors.black,
fontName="Helvetica", alignment=TA_CENTER, leading=12),
"td_left": S("td_left", fontSize=8.5, textColor=colors.black,
fontName="Helvetica", alignment=TA_LEFT, leading=12),
"td_bold": S("td_bold", fontSize=8.5, textColor=DARK_BLUE,
fontName="Helvetica-Bold", alignment=TA_LEFT, leading=12),
}
# ── Helper builders ────────────────────────────────────────────────────────────
def section_header(text, color=DARK_BLUE):
"""Full-width colored bar with white heading text."""
tbl = Table([[Paragraph(text, styles["h1"])]], colWidths=[W])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), color),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("ROUNDEDCORNERS", [4]),
]))
return tbl
def info_box(text, bg=LIGHT_BLUE, border=MED_BLUE):
tbl = Table([[Paragraph(text, styles["note"])]], colWidths=[W])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("LINEAFTER", (0,0), (0,-1), 3, border),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 12),
("ROUNDEDCORNERS", [3]),
]))
return tbl
def make_table(headers, rows, col_widths, alt_color=GREY_BG):
header_row = [Paragraph(h, styles["th"]) for h in headers]
data = [header_row]
for i, row in enumerate(rows):
styled = []
for j, cell in enumerate(row):
st = styles["td_bold"] if j == 0 else styles["td"]
if cell.startswith(">>"): # left-align special marker
cell = cell[2:]
st = styles["td_left"]
styled.append(Paragraph(cell, st))
data.append(styled)
tbl = Table(data, colWidths=col_widths, repeatRows=1)
ts = [
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("GRID", (0,0), (-1,-1), 0.5, GREY_BORDER),
("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, alt_color]),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("ROUNDEDCORNERS", [2]),
]
tbl.setStyle(TableStyle(ts))
return tbl
def bullet(text):
return Paragraph(f"<bullet>•</bullet> {text}", styles["bullet"])
def sp(h=6):
return Spacer(1, h)
def hr():
return HRFlowable(width=W, thickness=0.5, color=GREY_BORDER, spaceAfter=4)
# ── PAGE HEADER / FOOTER ───────────────────────────────────────────────────────
def on_page(canvas, doc):
canvas.saveState()
# Header bar
canvas.setFillColor(DARK_BLUE)
canvas.rect(doc.leftMargin, A4[1]-1.8*cm, W, 1.1*cm, fill=1, stroke=0)
canvas.setFont("Helvetica-Bold", 9)
canvas.setFillColor(WHITE)
canvas.drawString(doc.leftMargin+0.3*cm, A4[1]-1.3*cm, "IRON DEFICIENCY ANEMIA – Clinical Case Study")
canvas.drawRightString(doc.leftMargin+W, A4[1]-1.3*cm, "Orris Medical AI")
# Footer
canvas.setFillColor(GREY_BORDER)
canvas.rect(doc.leftMargin, 1.5*cm, W, 0.5*cm, fill=1, stroke=0)
canvas.setFont("Helvetica", 7.5)
canvas.setFillColor(HexColor("#374151"))
canvas.drawString(doc.leftMargin+0.2*cm, 1.7*cm,
"Sources: Robbins & Kumar Pathologic Basis of Disease | Harrison's IM 22E | Sleisenger & Fordtran | Goldman-Cecil Medicine")
canvas.drawRightString(doc.leftMargin+W-0.2*cm, 1.7*cm, f"Page {doc.page}")
canvas.restoreState()
# ═══════════════════════════════════════════════════════════════════════════════
# BUILD STORY
# ═══════════════════════════════════════════════════════════════════════════════
story = []
# ── COVER / TITLE BLOCK ────────────────────────────────────────────────────────
cover_data = [[
Paragraph("IRON DEFICIENCY ANEMIA", styles["title"]),
Paragraph("Complete Clinical Case Study | Hematology", styles["subtitle"]),
Paragraph("Orris Medical AI • July 2026", styles["subtitle"]),
]]
cover = Table(cover_data, colWidths=[W])
cover.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), DARK_BLUE),
("TOPPADDING", (0,0), (-1,-1), 18),
("BOTTOMPADDING", (0,0), (-1,-1), 18),
("LEFTPADDING", (0,0), (-1,-1), 14),
("RIGHTPADDING", (0,0), (-1,-1), 14),
("ROUNDEDCORNERS", [6]),
]))
story.append(cover)
story.append(sp(16))
# ── CLINICAL CASE PRESENTATION ─────────────────────────────────────────────────
story.append(section_header("📋 CLINICAL CASE PRESENTATION"))
story.append(sp(6))
story.append(Paragraph("<b>Patient:</b> Mrs. Priya S., 28-year-old female", styles["body"]))
story.append(Paragraph("<b>Chief Complaint:</b> Fatigue, shortness of breath on exertion, and brittle nails — 4 months", styles["body"]))
story.append(sp(4))
story.append(Paragraph(
"A 28-year-old female presents with progressive fatigue, dyspnea on climbing stairs, and difficulty "
"concentrating at work. She reports heavy menstrual periods lasting 7-8 days each cycle. She also "
"complains of craving ice (pagophagia). She is vegetarian and notes poor intake of iron-rich foods. "
"No hematemesis, melena, or hematochezia.", styles["body"]))
story.append(sp(4))
hx_data = [
["Past Medical History", "No chronic illness. No prior surgeries."],
["Medications", "Oral contraceptives stopped 1 year ago; periods became heavier thereafter."],
["Family History", "Mother has hypothyroidism."],
["Social History", "Non-smoker, occasional alcohol. Vegetarian diet."],
]
hx_tbl = Table(hx_data, colWidths=[4*cm, W-4*cm])
hx_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,-1), LIGHT_BLUE),
("FONTNAME", (0,0), (0,-1), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 9),
("GRID", (0,0), (-1,-1), 0.5, GREY_BORDER),
("ROWBACKGROUNDS",(0,0), (-1,-1), [WHITE, GREY_BG]),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
]))
story.append(hx_tbl)
story.append(sp(10))
# ── EXAMINATION ────────────────────────────────────────────────────────────────
story.append(section_header("🩺 PHYSICAL EXAMINATION", MED_BLUE))
story.append(sp(6))
vitals_headers = ["Blood Pressure", "Heart Rate", "RR", "SpO₂", "Temperature"]
vitals_rows = [["110/70 mmHg", "98 bpm", "16/min", "98% (air)", "37.0 °C"]]
story.append(make_table(vitals_headers, vitals_rows,
[W/5]*5, alt_color=LIGHT_BLUE))
story.append(sp(8))
exam_findings = [
("General", "Pale-looking, not in distress"),
("Conjunctivae", "Pale (pallor)"),
("Oral", "Angular cheilitis, smooth/atrophic tongue (glossitis)"),
("Nails", "Koilonychia (spoon nails) bilateral hands — see image below"),
("CVS", "Mild systolic flow murmur (2/6) — hyperdynamic circulation"),
("Abdomen", "Soft, non-tender, no organomegaly"),
]
exam_data = [[Paragraph(f"<b>{k}</b>", styles["td_left"]),
Paragraph(v, styles["td_left"])] for k, v in exam_findings]
exam_tbl = Table(exam_data, colWidths=[3.5*cm, W-3.5*cm])
exam_tbl.setStyle(TableStyle([
("ROWBACKGROUNDS", (0,0), (-1,-1), [WHITE, GREY_BG]),
("GRID", (0,0), (-1,-1), 0.5, GREY_BORDER),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(exam_tbl)
story.append(sp(8))
# Koilonychia image
if img_koilonychia and os.path.exists(img_koilonychia):
img = Image(img_koilonychia, width=7*cm, height=5*cm)
img.hAlign = "CENTER"
caption = Paragraph(
"<i>Koilonychia (spoon nails) — classic sign of chronic iron deficiency anemia. "
"The nail plate is thin and concave with characteristic upward-curving edges. "
"(Image: DermNet NZ)</i>", styles["small"])
img_tbl = Table([[img], [caption]], colWidths=[W])
img_tbl.setStyle(TableStyle([
("ALIGN", (0,0), (-1,-1), "CENTER"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
]))
story.append(img_tbl)
story.append(sp(8))
# ── INVESTIGATIONS ─────────────────────────────────────────────────────────────
story.append(section_header("🔬 INVESTIGATIONS", MED_BLUE))
story.append(sp(6))
story.append(Paragraph("<b>Complete Blood Count (CBC)</b>", styles["h2"]))
cbc_headers = ["Parameter", "Result", "Reference", "Interpretation"]
cbc_rows = [
["Hemoglobin", "8.4 g/dL", "12-16 g/dL (F)", "LOW ↓↓"],
["MCV", "68 fL", "80-100 fL", "LOW — microcytic"],
["MCH", "21 pg", "27-33 pg", "LOW — hypochromic"],
["MCHC", "28 g/dL", "32-36 g/dL", "LOW"],
["RDW", "18%", "<14.5%", "HIGH — anisocytosis"],
["WBC", "7,200/µL", "4,000-11,000", "Normal"],
["Platelets", "420,000/µL", "150,000-400,000", "HIGH — reactive thrombocytosis"],
["Reticulocytes", "1.2%", "0.5-2.5%", "Normal (inadequate for degree of anemia)"],
]
story.append(make_table(cbc_headers, cbc_rows, [4*cm, 2.5*cm, 3.5*cm, W-10*cm]))
story.append(sp(8))
story.append(Paragraph("<b>Iron Studies</b>", styles["h2"]))
fe_headers = ["Parameter", "Result", "Reference", "Status"]
fe_rows = [
["Serum Iron", "38 µg/dL", "60-170 µg/dL", "LOW ↓"],
["TIBC", "420 µg/dL", "240-360 µg/dL", "HIGH ↑"],
["Transferrin Sat.", "9%", "20-50%", "LOW (<15% = diagnostic)"],
["Serum Ferritin", "6 µg/L", "12-150 µg/L (F)","LOW (<12 = depleted stores)"],
]
story.append(make_table(fe_headers, fe_rows, [4.5*cm, 2.5*cm, 3.5*cm, W-10.5*cm]))
story.append(sp(5))
story.append(info_box(
"<b>Key diagnostic thresholds:</b> Ferritin <12 µg/L = depleted iron stores (99% specific). "
"Transferrin saturation <15% = iron-restricted erythropoiesis. TIBC elevated (inverse of iron stores). "
"<i>— Sleisenger & Fordtran's GI and Liver Disease</i>"))
story.append(sp(8))
story.append(Paragraph("<b>Additional Workup</b>", styles["h2"]))
additional = [
["Peripheral blood smear", "Microcytes, hypochromic RBCs, pencil cells, anisocytosis, poikilocytosis"],
["HbA2/HbF (HPLC)", "Normal — thalassemia trait excluded"],
["Stool occult blood", "Negative"],
["Celiac serology (anti-tTG IgA)", "Negative"],
["TSH", "Normal"],
["Urine routine", "Normal"],
]
add_data = [[Paragraph(f"<b>{k}</b>", styles["td_left"]),
Paragraph(v, styles["td_left"])] for k, v in additional]
add_tbl = Table(add_data, colWidths=[5*cm, W-5*cm])
add_tbl.setStyle(TableStyle([
("ROWBACKGROUNDS", (0,0), (-1,-1), [WHITE, GREY_BG]),
("GRID", (0,0), (-1,-1), 0.5, GREY_BORDER),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(add_tbl)
story.append(sp(10))
# ── PATHOPHYSIOLOGY ────────────────────────────────────────────────────────────
story.append(PageBreak())
story.append(section_header("⚙️ PATHOPHYSIOLOGY"))
story.append(sp(6))
story.append(Paragraph(
"Iron deficiency anemia results from a mismatch between iron supply and erythropoietic demand. "
"The body's total iron content is 2.5-6 g; most exists in hemoglobin (~65%), with storage in ferritin "
"and hemosiderin. The duodenum is the sole site of regulated iron absorption; there is no regulated "
"excretion pathway — daily losses are fixed at 1-2 mg via shed epithelial cells and, in women, "
"menstrual blood. — <i>Robbins, Cotran & Kumar Pathologic Basis of Disease, p. 612</i>",
styles["body"]))
story.append(sp(8))
# Iron metabolism diagram
if img_metabolism and os.path.exists(img_metabolism):
img2 = Image(img_metabolism, width=9*cm, height=10.5*cm)
img2.hAlign = "CENTER"
cap2 = Paragraph(
"<i>Fig. Iron metabolism. Iron absorbed from the gut binds plasma transferrin and is transported "
"to the bone marrow, incorporated into hemoglobin, and after 120 days RBCs are phagocytosed by "
"macrophages. Iron is recycled to transferrin. Losses are limited to 1-2 mg/day. "
"(Robbins, Cotran & Kumar Pathologic Basis of Disease)</i>", styles["small"])
img2_tbl = Table([[img2], [cap2]], colWidths=[W])
img2_tbl.setStyle(TableStyle([
("ALIGN", (0,0), (-1,-1), "CENTER"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
]))
story.append(img2_tbl)
story.append(sp(10))
story.append(Paragraph("<b>Three Sequential Stages of Iron Depletion</b>", styles["h2"]))
stages_headers = ["Stage", "Iron Stores", "Hb", "Ferritin", "TIBC", "Transferrin Sat"]
stages_rows = [
["Stage 1 — Iron Depletion", "Depleted", "Normal", "↓", "↑", "Normal"],
["Stage 2 — Iron-Deficient Erythropoiesis", "Absent", "Normal/↓", "↓↓", "↑↑", "<20%"],
["Stage 3 — Iron Deficiency ANEMIA","Absent", "↓↓", "<12 µg/L", "↑↑↑", "<15%"],
]
story.append(make_table(stages_headers, stages_rows,
[5*cm, 2.5*cm, 2*cm, 2.5*cm, 1.8*cm, 3.2*cm]))
story.append(sp(8))
story.append(Paragraph("<b>Hepcidin — The Master Iron Regulator</b>", styles["h2"]))
story.append(Paragraph(
"Hepcidin (produced by the liver) is the principal regulator of iron homeostasis. It binds ferroportin "
"(the only cellular iron exporter) on enterocytes, macrophages, and hepatocytes, promoting its "
"internalisation and degradation — thus blocking iron release into plasma.", styles["body"]))
story.append(sp(3))
hepcidin_items = [
"In <b>iron deficiency</b>: hepcidin is suppressed → ferroportin upregulated → maximal dietary iron absorption",
"In <b>inflammation / anemia of chronic disease</b>: IL-6 drives hepcidin high → ferroportin degraded → iron trapped in macrophages → low serum iron despite normal/high ferritin",
"In <b>IRIDA (hereditary)</b>: TMPRSS6 mutation causes constitutively low hepcidin suppression → iron refractory to oral supplementation — IV iron required",
]
for item in hepcidin_items:
story.append(bullet(item))
story.append(sp(6))
story.append(Paragraph("<b>Iron Distribution in Healthy Adults (mg)</b>", styles["h2"]))
dist_headers = ["Iron Pool", "Males (mg)", "Females (mg)"]
dist_rows = [
["Total body iron", "3,450", "2,450"],
["Hemoglobin", "2,100", "1,750"],
["Myoglobin", "300", "250"],
["Enzymes (cytochromes)", "50", "50"],
["Storage (ferritin/hemosiderin)", "1,000", "400"],
]
story.append(make_table(dist_headers, dist_rows, [7*cm, 3.5*cm, 3.5*cm]))
story.append(sp(5))
story.append(info_box(
"Female storage iron (~400 mg) is far lower than male (~1,000 mg), explaining the much higher "
"vulnerability to IDA from menstrual losses. — <i>Robbins, Cotran & Kumar, p. 612</i>"))
story.append(sp(10))
# ── CAUSES ─────────────────────────────────────────────────────────────────────
story.append(PageBreak())
story.append(section_header("🔍 ETIOLOGY & CAUSES"))
story.append(sp(6))
causes = [
("Blood Loss (Most Common)", [
"Menorrhagia — leading cause in premenopausal women (this patient)",
"GI bleeding — leading cause in men and postmenopausal women (peptic ulcer, colorectal cancer, hookworm, angiodysplasia)",
"Epistaxis, haematuria, pulmonary haemorrhage (rare)",
]),
("Inadequate Dietary Intake", [
"Vegetarian/vegan diet — non-heme iron has only 1-2% bioavailability vs 20% for heme iron",
"Prematurity, exclusive breastfeeding in infants",
"Low-resource settings with high parasite burden (hookworm)",
]),
("Malabsorption", [
"Celiac disease — villous atrophy in duodenum (primary iron absorption site)",
"Atrophic gastritis / H. pylori — reduced gastric acid impairs Fe³⁺ → Fe²⁺ conversion",
"Post-Roux-en-Y gastric bypass — duodenum is bypassed; IV iron often required long-term",
"Inflammatory bowel disease (IBD)",
]),
("Increased Iron Demand", [
"Pregnancy — iron requirements reach 4-5 mg/day in 3rd trimester",
"Rapid growth in infancy and adolescence",
"Erythropoietin therapy (expands erythropoiesis, outpacing iron supply)",
]),
]
for heading, items in causes:
story.append(Paragraph(f"<b>{heading}</b>", styles["h3"]))
for item in items:
story.append(bullet(item))
story.append(sp(4))
# ── CLINICAL FEATURES ──────────────────────────────────────────────────────────
story.append(section_header("🏥 CLINICAL FEATURES", MED_BLUE))
story.append(sp(6))
story.append(Paragraph(
"Anemia develops only in the <b>late stage</b> of iron deficiency. Because of slow progression and "
"efficient compensatory mechanisms, anemia often remains undetected until Hb falls below 8 g/dL. "
"Even before frank anemia, iron deficiency impairs myocytes, cardiomyocytes, and neurons. "
"— <i>Harrison's Principles of Internal Medicine 22E, p. 808</i>", styles["body"]))
story.append(sp(6))
story.append(Paragraph("<b>General Symptoms of Anemia</b>", styles["h2"]))
gen_symptoms = [
"Fatigue, weakness, reduced exercise tolerance",
"Pallor (conjunctival, palmar, nail bed)",
"Dyspnea on exertion, palpitations",
"Headache, poor concentration, irritability",
"Restless legs syndrome",
]
for s in gen_symptoms:
story.append(bullet(s))
story.append(sp(6))
story.append(Paragraph("<b>Signs Specific to Iron Deficiency</b>", styles["h2"]))
signs_headers = ["Sign", "Description"]
signs_rows = [
[">>Koilonychia", "Concave (spoon) nails — nail plate thinning"],
[">>Angular cheilitis", "Painful cracking at corners of the mouth"],
[">>Glossitis", "Smooth, atrophic, painful tongue (loss of papillae)"],
[">>Pica", "Craving non-food substances: ice (pagophagia), dirt (geophagia)"],
[">>Plummer-Vinson syndrome", "IDA + dysphagia + postcricoid esophageal web (risk: esophageal SCC)"],
[">>Blue sclerae", "Mild, subtle finding in chronic IDA"],
]
story.append(make_table(signs_headers, signs_rows, [5*cm, W-5*cm]))
story.append(sp(10))
# ── DIFFERENTIAL DIAGNOSIS ─────────────────────────────────────────────────────
story.append(section_header("⚖️ DIFFERENTIAL DIAGNOSIS"))
story.append(sp(6))
diff_headers = ["Condition", "Ferritin", "Serum Fe", "TIBC", "Sat", "RDW", "Key Clue"]
diff_rows = [
["Iron Deficiency Anemia", "↓↓ (<15)", "↓", "↑", "↓ (<15%)", "↑", "Responds to iron Rx"],
["Anemia of Inflammation", "N/↑ (>100)", "↓", "↓", "↓", "Normal", "Chronic disease; IL-6↑"],
["Thalassemia Trait", "N/↑", "N", "N", "N", "N/↑", "HbA2 >3.5%; ethnic; no Fe Rx"],
["Sideroblastic Anemia", "↑", "↑", "N", "↑", "↑", "Ring sideroblasts; marrow Bx"],
["Mixed IDA + AoI", "Low-N (<100)","↓", "N", "↓", "↑", "IBD, CKD, aging"],
]
story.append(make_table(diff_headers, diff_rows,
[4*cm, 2*cm, 2.2*cm, 1.8*cm, 2*cm, 1.8*cm, W-13.8*cm]))
story.append(sp(5))
story.append(info_box(
"<b>Key distinctions:</b> In anemia of chronic disease, both serum iron AND TIBC are low (in IDA, "
"TIBC is high). Thalassemia trait shows low MCV but NORMAL iron studies and elevated HbA2. "
"Never give iron supplementation empirically to a patient who may have thalassemia. "
"— <i>Sleisenger & Fordtran's GI and Liver Disease</i>"))
story.append(sp(10))
# ── DIAGNOSIS ─────────────────────────────────────────────────────────────────
story.append(PageBreak())
dx_box_data = [[
Paragraph("✅ CONFIRMED DIAGNOSIS", ParagraphStyle("dx_title",
fontSize=13, textColor=WHITE, fontName="Helvetica-Bold",
alignment=TA_CENTER, spaceAfter=4)),
Paragraph(
"Iron Deficiency Anemia secondary to chronic menorrhagia,<br/>"
"with vegetarian diet as contributing factor",
ParagraphStyle("dx_sub", fontSize=11, textColor=LIGHT_GREEN,
fontName="Helvetica-BoldOblique", alignment=TA_CENTER)),
]]
dx_box = Table(dx_box_data, colWidths=[W])
dx_box.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), GREEN),
("TOPPADDING", (0,0), (-1,-1), 12),
("BOTTOMPADDING", (0,0), (-1,-1), 12),
("LEFTPADDING", (0,0), (-1,-1), 12),
("ROUNDEDCORNERS", [6]),
]))
story.append(dx_box)
story.append(sp(8))
story.append(Paragraph("<b>Diagnostic Criteria Met:</b>", styles["h2"]))
dx_criteria = [
"Microcytic hypochromic anemia: MCV 68 fL, MCHC 28 g/dL",
"Serum ferritin 6 µg/L (<12 µg/L = depleted iron stores, ~99% specific)",
"Transferrin saturation 9% (<15% = iron-restricted erythropoiesis)",
"TIBC elevated at 420 µg/dL (compensatory upregulation of transferrin)",
"Clinical signs: koilonychia, glossitis, pagophagia (pica for ice)",
"Clear etiology: heavy menstrual losses + low dietary iron (vegetarian)",
]
for c in dx_criteria:
story.append(bullet(c))
story.append(sp(10))
# ── MANAGEMENT ────────────────────────────────────────────────────────────────
story.append(section_header("💊 MANAGEMENT"))
story.append(sp(6))
story.append(Paragraph("<b>Step 1 — Treat the Underlying Cause</b>", styles["h2"]))
story.append(bullet("Refer to Gynecology for menorrhagia (hormonal therapy, levonorgestrel IUD, or surgical options)"))
story.append(bullet("Dietary counselling: legumes, spinach, tofu, fortified cereals; pair with vitamin C to enhance non-heme iron absorption"))
story.append(bullet("For men / postmenopausal women with IDA: mandatory GI evaluation (upper + lower endoscopy) to exclude colorectal cancer or peptic ulcer"))
story.append(sp(8))
story.append(Paragraph("<b>Step 2 — Iron Replacement Therapy</b>", styles["h2"]))
story.append(Paragraph("<i>Oral Iron (First Line — Mild to Moderate Anemia)</i>", styles["h3"]))
oral_items = [
"<b>Ferrous sulfate 325 mg</b> (65 mg elemental iron) — once daily on <b>alternate days</b>",
"Alternate-day dosing maximises absorption by preventing the reactive hepcidin surge from daily administration — <i>Harrison's IM 22E</i>",
"Take with orange juice (natural vitamin C maximises absorbed fraction)",
"Avoid with calcium, antacids, tea, coffee (inhibit absorption)",
"GI side effects (nausea, constipation, epigastric discomfort) in 30-60% — due to unabsorbed iron toxicity",
"Duration: <b>minimum 3 months</b> — continue 3 months after Hb normalises to replenish stores",
]
for item in oral_items:
story.append(bullet(item))
story.append(sp(6))
story.append(info_box(
"<b>Monitoring response:</b> Reticulocytosis within <b>1 week</b> (early sign of bone marrow response). "
"Hb rise >1 g/dL within <b>2 weeks</b>. Failure = non-compliance, ongoing blood loss, malabsorption, or wrong diagnosis."))
story.append(sp(6))
story.append(Paragraph("<i>Intravenous Iron (When Oral Fails or is Not Feasible)</i>", styles["h3"]))
iv_indic = [
"Intolerance to oral iron or significant GI side effects",
"Malabsorption (celiac disease, post-bariatric surgery, IBD)",
"Hb ≤8 g/dL requiring rapid correction",
"Chronic kidney disease, pregnancy (2nd/3rd trimester with severe IDA)",
"IRIDA (hereditary iron-refractory form)",
]
story.append(Paragraph("<b>Indications:</b>", styles["body"]))
for item in iv_indic:
story.append(bullet(item))
story.append(sp(4))
iv_prep_headers = ["Preparation", "Dose", "Notes"]
iv_prep_rows = [
[">>Ferric carboxymaltose", "Up to 1,000 mg single infusion", "Risk of hypophosphatemia (FGF-23↑)"],
[">>Iron sucrose", "200 mg per infusion", "Well tolerated; multiple sessions"],
[">>Ferric derisomaltose", "Up to 1,500 mg single infusion", "Newer; broad safety profile"],
[">>LMW Iron dextran", "Calculated total dose", "No test dose required (LMW)"],
]
story.append(make_table(iv_prep_headers, iv_prep_rows, [5*cm, 4.5*cm, W-9.5*cm]))
story.append(sp(5))
story.append(info_box(
"Modern IV iron preparations are highly stable, do not require a test dose, and infusion reactions "
"occur in <0.1% (usually mild and self-limited). Severe complement-mediated reactions are "
"extremely rare. — <i>Harrison's Principles of Internal Medicine 22E, p. 810</i>"))
story.append(sp(6))
story.append(Paragraph("<i>Blood Transfusion</i>", styles["h3"]))
story.append(bullet("Reserved for symptomatic severe anemia (Hb <7 g/dL) with haemodynamic instability or cardiovascular compromise"))
story.append(bullet("Not routine for iron deficiency anemia"))
story.append(sp(8))
story.append(Paragraph("<b>Step 3 — Follow-Up</b>", styles["h2"]))
followup = [
"CBC + ferritin at 4 weeks, then at 3 months to confirm iron stores replenished (target ferritin >30 µg/L)",
"Screen female first-degree relatives, especially adolescents",
"If GI cause suspected: upper endoscopy with duodenal biopsy (celiac), lower endoscopy (colorectal lesions); video capsule endoscopy if both negative",
]
for item in followup:
story.append(bullet(item))
story.append(sp(10))
# ── EPIDEMIOLOGY ──────────────────────────────────────────────────────────────
story.append(PageBreak())
story.append(section_header("🌍 EPIDEMIOLOGY"))
story.append(sp(6))
epi_data = [
["Global burden", "~1.2 billion affected — roughly half of the world's anemic population"],
["Preschool children", "Prevalence ~25% globally"],
["Young women", "37-40% affected; most common nutritional disorder in this group"],
["Pregnant women", ">40% with severe forms in low-income countries"],
["USA (females 12-21)", "Iron deficiency 38.6%; overt IDA 6.3% (ferritin <30 µg/L threshold)"],
["GI consultation", "IDA represents 4-13% of all outpatient gastroenterology referrals"],
]
epi_tbl_data = [[Paragraph(f"<b>{k}</b>", styles["td_left"]),
Paragraph(v, styles["td_left"])] for k, v in epi_data]
epi_tbl = Table(epi_tbl_data, colWidths=[4.5*cm, W-4.5*cm])
epi_tbl.setStyle(TableStyle([
("ROWBACKGROUNDS", (0,0), (-1,-1), [WHITE, GREY_BG]),
("GRID", (0,0), (-1,-1), 0.5, GREY_BORDER),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("BACKGROUND", (0,0), (0,-1), LIGHT_BLUE),
("FONTNAME", (0,0), (0,-1), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 9),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(epi_tbl)
story.append(sp(10))
# ── SPECIAL POPULATIONS ────────────────────────────────────────────────────────
story.append(section_header("👥 SPECIAL POPULATIONS", MED_BLUE))
story.append(sp(6))
sp_headers = ["Population", "Key Consideration"]
sp_rows = [
[">>Pregnant women", "Iron req. rises to 4-5 mg/day in 3rd trimester; IV iron if Hb <9 g/dL"],
[">>Infants/Toddlers", "Cow's milk exclusive diet or premature birth = high risk; iron-fortified cereals at 4-6 months"],
[">>Elderly", "Multiple coexisting causes common; always investigate underlying cause"],
[">>Post-bariatric surgery", "Duodenum bypassed; severe malabsorption; IV iron often required long-term"],
[">>Chronic kidney disease", "Functional iron deficiency; high hepcidin; IV iron standard; target ferritin 200-500 µg/L on dialysis"],
[">>IRIDA (hereditary)", "TMPRSS6 mutation; refractory to oral iron; IV iron exclusively required"],
]
story.append(make_table(sp_headers, sp_rows, [4.5*cm, W-4.5*cm]))
story.append(sp(10))
# ── KEY TEACHING POINTS ────────────────────────────────────────────────────────
story.append(section_header("⭐ KEY TEACHING POINTS"))
story.append(sp(6))
kp = [
("Iron deficiency = most common nutritional disorder globally",
"Causes not only anemia but also extra-erythroid effects on muscle, heart, and brain."),
("Ferritin is the single most useful screening test",
"Ferritin <12 µg/L is ~99% specific for depleted stores; <30 µg/L is the more sensitive threshold."),
("Transferrin saturation <15% confirms iron-restricted erythropoiesis",
"Use alongside ferritin for diagnosis. TIBC is elevated (inverse of iron stores)."),
("Always seek the underlying cause",
"IDA in a man or postmenopausal woman demands GI evaluation to exclude colorectal cancer."),
("Alternate-day oral iron is superior to daily dosing",
"Daily iron induces a reactive hepcidin surge that limits next-dose absorption."),
("Monitor response: reticulocytosis at 1 week; Hb rise >1 g/dL at 2 weeks",
"Failure to respond = investigate for non-compliance, blood loss, malabsorption, or wrong diagnosis."),
("Thalassemia trait is the main mimic",
"Normal iron studies + elevated HbA2 distinguish it. Iron supplementation is harmful in thalassemia."),
]
for i, (point, detail) in enumerate(kp):
row_data = [[
Paragraph(f"<b>{i+1}. {point}</b>", styles["keypoint"]),
Paragraph(detail, styles["body"]),
]]
row_tbl = Table(row_data, colWidths=[6.5*cm, W-6.5*cm])
bg = LIGHT_BLUE if i % 2 == 0 else YELLOW_BG
row_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,-1), bg),
("BACKGROUND", (1,0), (1,-1), WHITE),
("GRID", (0,0), (-1,-1), 0.5, GREY_BORDER),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(row_tbl)
story.append(sp(2))
story.append(sp(10))
# ── REFERENCES ─────────────────────────────────────────────────────────────────
story.append(HRFlowable(width=W, thickness=1, color=DARK_BLUE, spaceAfter=6))
story.append(Paragraph("<b>References</b>", styles["h2"]))
refs = [
"Robbins, Cotran & Kumar. <i>Pathologic Basis of Disease, 10th Edition.</i> Elsevier, 2021.",
"Harrison's Principles of Internal Medicine, 22nd Edition. McGraw-Hill, 2025.",
"Sleisenger & Fordtran's Gastrointestinal and Liver Disease. Elsevier, 2021.",
"Goldman-Cecil Medicine, International Edition. Elsevier, 2024.",
"Lippincott Illustrated Reviews: Pharmacology, 8th Edition. Wolters Kluwer, 2022.",
]
for ref in refs:
story.append(bullet(ref))
# ── BUILD ──────────────────────────────────────────────────────────────────────
print("Building PDF...")
doc.build(story, onFirstPage=on_page, onLaterPages=on_page)
print(f"PDF saved to: {OUTPUT_PATH}")
print(f"File size: {os.path.getsize(OUTPUT_PATH) / 1024:.1f} KB")
cd /tmp/workspace/ida_case && python build_pdf.py 2>&1
Iron Deficiency Anemia Clinical Case
PDF Document · PDF
Build a case on Myocardial infarction
STEMI ECG ST elevation myocardial infarction 12 lead electrocardiogram

A 12-lead electrocardiogram (ECG) demonstrating an acute anterolateral ST-elevation myocardial infarction (STEMI). The tracing shows significant, convex-upward ST-segment elevation in the precordial leads (V1–V6), consistent with an anterior wall injury. Leads I and aVL also display ST-elevation, indicating lateral involvement. These changes are accompanied by hyperacute, peaked T-waves most prominent in V2 through V4. There is evidence of reciprocal ST-segment depression in the inferior leads (II, III, and aVF). The QRS complexes appear widened in the leads with maximal ST elevation. The heart rhythm is sinus. This ECG pattern is clinically significant for proximal left anterior descending (LAD) artery occlusion, necessitating urgent reperfusion therapy. The visual presentation focuses on teachable hallmarks of cardiac ischemia, including the relationship between anatomical lead distribution and corresponding vascular territories, as well as the identification of reciprocal changes in opposing leads.

This is a 12-lead electrocardiogram (ECG) demonstrating an acute ST-segment elevation myocardial infarction (STEMI). The diagnostic hallmark is prominent ST-segment elevation across the precordial leads V1 through V6, with the most significant convex elevation appearing in leads V2, V3, and V4. These findings are highly characteristic of an acute anterior wall infarction, typically involving the left anterior descending (LAD) coronary artery. In the limb leads, mild ST-segment elevation is also visible in leads I, II, III, and aVF, accompanied by positive, upright T waves. Lead aVR shows expected global inversion. The tracing displays a sinus rhythm with regular morphology, but the ST-segment deviations from the isoelectric baseline indicate acute myocardial injury. This visual material is a critical educational tool for teaching the ECG localization of coronary occlusions and the identification of STEMI criteria in an emergency clinical context.

A 12-lead electrocardiogram (ECG) demonstrating an acute ST-elevation myocardial infarction (STEMI) with characteristic anterior and anterolateral findings. The tracing displays a normal sinus rhythm with a heart rate of approximately 84 beats per minute and normal P wave morphology. Significant pathology is localized to the precordial leads, specifically V2 through V5, which exhibit pronounced ST-segment elevation. This elevation presents with a convex 'tombstoning' morphology, a high-risk indicator of extensive myocardial injury. Additionally, evolving QS waves are visible in leads V2 and V3, indicating necrotic changes or transmural infarction. These findings are clinically consistent with an acute occlusion of the left anterior descending (LAD) coronary artery. The limb leads (I, II, III, aVR, aVL, aVF) show relatively stable baselines, though mild reciprocal changes or secondary ST-T wave abnormalities may be present in the inferior leads. This diagnostic image serves as a classic educational example of early-stage STEMI progression and the visual identification of localized ischemic injury on electrocardiography.

A standard 12-lead electrocardiogram (ECG) displayed on a red-grid background, illustrating an acute inferolateral ST-elevation myocardial infarction (STEMI). The tracing exhibits significant ST-segment elevations (marked with green circles) in the inferior leads (II, III, and aVF) and the lateral precordial leads (V4, V5, and V6). Concurrent reciprocal ST-segment depressions (marked with yellow arrows) are visible in the high lateral leads (I and aVL) and the anterior precordial leads (V2 and V3). The ECG is organized in a standard layout with limb leads I-III and aVR-aVF on the left and precordial leads V1-V6 on the right, with a continuous rhythm strip at the bottom. This diagnostic image demonstrates the classic electrical patterns of acute myocardial ischemia and infarction, specifically targeting the inferolateral wall of the left ventricle. It serves as a critical educational tool for identifying ST-segment morphology changes and reciprocal electrical deviations in emergency cardiovascular medicine.
myocardial infarction histology necrosis neutrophils coagulative

Imaging modality: Light microscopy of Hematoxylin and Eosin stained myocardial tissue from the left ventricle. This histopathology slide shows acute myocardial infarction with a pronounced inflammatory response at approximately 3-4 days age. Necrotic cardiomyocytes appear with eosinophilic, homogeneous cytoplasm and loss of nuclei, set within a pink, edematous interstitium. Surrounding the necrotic fibers is a dense neutrophilic infiltrate; small dark neutrophils with segmented nuclei are dispersed between intact fibers and around necrotic zones. Early macrophage recruitment may be evident at the infarct border as inflammation persists. Overall architecture shows patchy zones of myocyte loss, with preserved but stressed neighboring myocardium. No organized scar or fibrosis is yet apparent. The staining highlights cellular morphology and tissue organization: striated muscle fibers, cross-striations partially disrupted, and interstitial edema. Clinically, this constellation supports an infarct age of several days, with active inflammation and a high risk of mechanical complications if the infarct is transmural. The image is relevant to teaching, diagnostic pathology, and research on post-infarct healing, inflammation, and ballooning necrosis; it also aids correlation with electrocardiographic changes and serum biomarkers (troponin, CK-MB). This micrograph exemplifies stage-specific histology of myocardial infarction and underscores the importance of timing in diagnosis, prognosis, and therapy planning strategies.

Imaging modality: Light microscopy of hematoxylin-eosin (H&E) stained cardiac tissue. Specimen is paraffin-embedded myocardial section, 5 micron thick, imaged with bright-field optics at high magnification. Anatomic region: left ventricular myocardium with an infarct in the left half of the field. The histology demonstrates pallor of necrotic cardiomyocytes (myocytolysis) produced by sarcolemmal disruption with influx of salt and water and cytoplasmic swelling. In this early post-ischemic stage, fibers lose cross-striations and display increased eosinophilia; nuclei are often absent or pyknotic. The infarct border may show waviness of fibers and mild edema; contraction bands may be present at the margin. Neutrophilic infiltration is typically minimal during the first 24 hours but may begin to appear around this window. The combination of coagulative necrosis, myocytolysis, and pallor indicates an acute myocardial infarction approximately one day old. This histologic pattern correlates with ischemia from coronary occlusion, clinical presentation of acute coronary syndrome, and aligns with diagnostic timelines (0-24 h). Clinically the image supports timing of infarct and helps distinguish acute infarction from myocarditis or chronic scar, serving as an educational reference for pathology, medical education, and research on myocardial injury dynamics. Further confirmed by clinical correlation and education.

Imaging modality: light microscopy of a cardiac tissue section stained with hematoxylin and eosin reveals infarct border-zone myocardium from the left ventricle. The tissue shows parallel, wavy myocardial fibers along the border between viable and necrotic tissue—a hallmark of early coagulative necrosis in myocardial infarction. The fibers appear elongated and noncontractile, with eosinophilic (pink) cytoplasm and loss of distinctive cross-striations; nuclei are scarce or absent in necrotic cells. In the periphery, viable myocytes tug on adjacent fibers during systole, producing the characteristic waviness. The infarct core is hypo-cellular with meshy eosinophilic areas and early inflammatory cells beginning to infiltrate, consistent with the 6–12 hour window after ischemic onset. These histologic changes reflect irreversible injury, rapid necrosis, and initiation of repair processes. Clinically, recognition of wavy fibers and coagulative necrosis supports an acute MI diagnosis and helps estimate timing, guiding anti-ischemic therapy, reperfusion decisions, and prognostic assessment. This image is representative in education and research contexts for teaching infarct evolution, distinguishing acute from subacute tissue changes, and illustrating the border zone pathophysiology in cardiology and pathology education. This micrograph serves as a teaching tool for students, residents, and researchers studying ischemic injury timelines, scar formation, and therapeutic windows in infarcted myocardium.
coronary artery atherosclerosis plaque rupture thrombus occlusion

This is a light microscopic histopathology image of a human left anterior descending (LAD) coronary artery segment from autopsy. The specimen shows an atherosclerotic plaque with rupture of the fibrous cap and overlying luminal thrombosis, resulting in near-complete occlusion of the arterial lumen over approximately 1.0 cm. The arterial wall reveals intimal thickening with a lipid-rich necrotic core, cholesterol clefts, and inflammatory cells. The ruptured plaque exposes subendothelial thrombogenic material, provoking platelet aggregation and formation of an occlusive red thrombus that markedly narrows the lumen. The thrombus appears organized with layered eosinophilic material and fibrin, consistent with thrombotic components seen in acute coronary syndromes. The surrounding media may show early degenerative changes typical of atherosclerosis. This lesion corresponds to a fatal acute myocardial infarction in a patient with a history of ischemic heart disease and prior CAD. Clinically, the finding supports sudden cardiac death due to acute coronary occlusion from plaque rupture. The image emphasizes the pathophysiology of myocardial infarction: plaque instability, thrombosis, rapid flow limitation, and myocardial ischemia. It provides a classic autopsy correlate for education, teaching, and research on coronary atherosclerosis, plaque rupture, thrombosis, and sudden death. This histology image is ideal for autopsy teaching and cardiac pathology research.

Gross pathology photograph from an autopsy showing the heart with acute coronary occlusion. Anatomical site: right coronary artery (RCA) with heavy atherosclerotic disease and a mural thrombus occluding the lumen. Plaque morphology is lipid-rich, irregular, and yellow-brown with possible calcification. The overlying thrombus is dark reddish-brown, adherent to the plaque, and partially fills the arterial lumen, producing abrupt cessation of distal flow. Associated myocardial tissue may show early signs of infarction, such as pallor or edema in the distribution supplied by the RCA. Imaging modality and technique: macroscopic gross pathology image, en-face view of the epicardial artery from autopsy; not a radiologic study and not stained. Pathophysiology: sudden plaque rupture with superimposed mural thrombosis causing acute myocardial infarction (AMI) and death within 72 hours. Clinical correlation: this lesion represents a classic mechanism of fatal coronary artery disease, leading to hemodynamic compromise and ventricular dysfunction. Diagnostic significance: demonstrates the chain of events from atherosclerotic plaque disruption to occlusive thrombosis and myocardial necrosis, illustrating the basis for sudden cardiac death in CAD. Differential considerations include plaque rupture with thrombosis, coronary vasospasm, embolic occlusion, and multivessel atherosclerosis. Educational value: aids understanding of MI pathogenesis, coronary thrombosis, and autopsy-based cardiovascular pathology.

Imaging modality: Histopathology - light microscopy of an intact coronary arterial cross-section, stained with H&E. Specimen location: Left anterior descending coronary artery (LAD), proximal to mid-segment, from an adult male with known ischemic heart disease who died suddenly. Observed features: atherosclerotic plaque rupture with overlying luminal thrombosis; the lumen is nearly occluded over a 1.0 cm segment. The plaque shows a lipid-rich necrotic core and a thin, disrupted fibrous cap; the intima is thickened with yellowish plaque. The thrombus is adherent to the plaque rupture site and extends into the lumen, composed of platelets, fibrin, erythrocytes; the arterial wall demonstrates media degeneration and intimal atherosclerosis. The overall morphology is consistent with acute coronary thrombosis leading to myocardial ischemia and sudden death; histology may reveal early myocardial changes if present elsewhere. Diagnostic significance: this pattern explains sudden cardiac death due to acute myocardial infarction from an occlusive coronary thrombus following plaque rupture; differential considerations include spontaneous coronary dissection, vasospastic occlusion, or embolic events; clinical correlation with ischemic heart disease history supports the infarction mechanism. This image is valuable for education on pathophysiology of plaque rupture, thrombus formation, and fatal acute coronary syndrome; relevant to cardiology, pathology, and medical education.
myocardial infarction complications cardiogenic shock heart failure mechanical

Summary : This figure presents the clinical characteristics and visual depictions of four major mechanical complications that can occur after an acute myocardial infarction: papillary muscle rupture, ventricular septal rupture, contained rupture, and free wall rupture. Each complication is described with its clinical presentation and key diagnostic features. illustration: # Mechanical Complications of Acute Myocardial Infarction : ## 1. Papillary muscle rupture : • Acute pulmonary edema; cardiogenic shock. • Eccentric or broad jet of severe mitral regurgitation (MR). • Mobile mass in left ventricle (LV); prolapsing into left atrium (LA). • Illustration shows a ruptured papillary muscle with regurgitant flow from LV to LA. ## 2. Ventricular septal rupture : • Ranges from asymptomatic to circulatory collapse. • Left to right shunt. • Discontinuity of septum with evidence of color flow. • Illustration depicts a defect in the interventricular septum with abnormal blood flow between ventricles. ## 3. Contained rupture : • May be asymptomatic, or present with chest pain or heart failure (HF). • Small neck communication. • To-and-fro blood flow through rupture. • Illustration shows a localized rupture with a small communication and limited blood leakage. ## 4. Free wall rupture : • Circulatory collapse. • Pericardial effusion or cardiac tamponade. • Electromechanical dissociation. • Illustration depicts a rupture of the ventricular free wall with blood escaping into the pericardial space. # Additional Notes : • Contained rupture is the preferred term for what is sometimes called a pseudoaneurysm. • Abbreviations: HF = heart failure; LA = left atrium; LV = left ventricle; MR = mitral regurgitation. # Analysis : • The figure visually and textually distinguishes the four main mechanical complications post-myocardial infarction, highlighting their clinical presentations and pathophysiological features. • Papillary muscle and septal ruptures primarily affect intracardiac flow, while contained and free wall ruptures involve the cardiac wall and pericardium, with free wall rupture being the most catastrophic. • The illustrations reinforce the anatomical sites and consequences of each complication, aiding in rapid clinical recognition.

This diagnostic image composite features four echocardiographic views (transthoracic ultrasound) illustrating diverse cardiac pathologies associated with cardiogenic shock. The top left and right panels show parasternal long-axis and apical views of a severely dilated left ventricle (LV) with marked wall thinning and impaired contractility, characteristic of dilated cardiomyopathy; an echogenic mass is visible at the LV apex, diagnostic of a ventricular thrombus. The bottom left panel utilizes color Doppler imaging to demonstrate blood flow into a narrow-necked extracardiac pouch, consistent with a left ventricular pseudoaneurysm following myocardial infarction. The bottom right panel displays an apical view of an apical aneurysm or pseudoaneurysm containing extensive intraluminal thrombosis. This comparison chart serves as an educational tool for identifying mechanical complications of myocardial infarction and chronic heart failure, emphasizing the role of echocardiography in diagnosing intracardiac masses and wall motion abnormalities that may contraindicate certain mechanical circulatory supports.
~/mi_case/build_mi_pdf.py
"""
Myocardial Infarction - Clinical Case PDF Generator
Professional, well-formatted clinical case study using ReportLab.
"""
import os
import urllib.request
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, Image, PageBreak
)
from reportlab.lib.colors import HexColor
# ── Color palette ─────────────────────────────────────────────────────────────
DARK_RED = HexColor("#7f1d1d")
MED_RED = HexColor("#b91c1c")
LIGHT_RED = HexColor("#fee2e2")
ACCENT_RED = HexColor("#dc2626")
DARK_BLUE = HexColor("#1e3a5f")
MED_BLUE = HexColor("#2563a8")
LIGHT_BLUE = HexColor("#dbeafe")
GREEN = HexColor("#15803d")
LIGHT_GREEN = HexColor("#dcfce7")
ORANGE = HexColor("#c2410c")
YELLOW_BG = HexColor("#fefce8")
AMBER = HexColor("#d97706")
GREY_BG = HexColor("#f3f4f6")
GREY_BORDER = HexColor("#d1d5db")
DARK_GREY = HexColor("#374151")
WHITE = colors.white
OUTPUT_DIR = "/tmp/workspace/mi_case"
os.makedirs(OUTPUT_DIR, exist_ok=True)
OUTPUT_PATH = os.path.join(OUTPUT_DIR, "Myocardial_Infarction_Clinical_Case.pdf")
# ── Download images ────────────────────────────────────────────────────────────
def download_image(url, filename):
path = os.path.join(OUTPUT_DIR, filename)
try:
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
with urllib.request.urlopen(req, timeout=15) as resp:
with open(path, "wb") as f:
f.write(resp.read())
print(f" Downloaded: {filename}")
return path
except Exception as e:
print(f" Warning: could not download {url}: {e}")
return None
print("Downloading images...")
img_necrosis_prog = download_image(
"https://cdn.orris.care/cdss_images/3b5ba229c882e30d040f5daa03246ee53098c1afeb19665ef8b07d6b879ad0e7.png",
"mi_necrosis_progression.png")
img_ecg_stemi = download_image(
"https://cdn.orris.care/cdss_images/pmc_clinical_VQA_cdfb20f9fc1a8412ffb27a5e6e1ae510547606f1b0c520ad6dc5bda4ec26caeb.jpg",
"stemi_ecg.jpg")
img_ecg_inferior = download_image(
"https://cdn.orris.care/cdss_images/pmc_clinical_VQA_3dee7a4a158b2ae0ff60150e6e2f63ffc7b5cab69ca1b45d2db4b86765c7720e.jpg",
"inferior_stemi_ecg.jpg")
img_plaque_rupture = download_image(
"https://cdn.orris.care/cdss_images/Pathology_1760051680413_dddaac75-2cf3-4ac3-8625-4fd3c9146e4f.jpg",
"plaque_rupture.jpg")
img_histo_acute = download_image(
"https://cdn.orris.care/cdss_images/Pathology_1760051534574_81437af8-b0e7-4175-bc65-2ccf32f62238.jpg",
"mi_histology_acute.jpg")
img_histo_early = download_image(
"https://cdn.orris.care/cdss_images/Pathology_1760051532132_bf19f128-f8d0-466d-92c9-1f1ca3315227.jpg",
"mi_histology_early.jpg")
img_complications = download_image(
"https://cdn.orris.care/cdss_images/GLGCA_4374545_1766840143933_6c3606b4-9f62-4013-8663-6402a6ba89d4_6ded5048-6690-47dd-b099-9d4b52e96e8e.png",
"mi_complications.png")
# ── Document setup ─────────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
OUTPUT_PATH,
pagesize=A4,
rightMargin=2*cm, leftMargin=2*cm,
topMargin=2.5*cm, bottomMargin=2.5*cm,
title="Myocardial Infarction - Clinical Case",
author="Orris Medical AI",
subject="Cardiology Clinical Case Study"
)
W = A4[0] - 4*cm
# ── Styles ─────────────────────────────────────────────────────────────────────
base = getSampleStyleSheet()
def S(name, parent="Normal", **kw):
return ParagraphStyle(name, parent=base[parent], **kw)
styles = {
"title": S("title", fontSize=22, textColor=WHITE,
fontName="Helvetica-Bold", alignment=TA_CENTER,
spaceAfter=4, leading=26),
"subtitle": S("subtitle", fontSize=11, textColor=HexColor("#fca5a5"),
fontName="Helvetica", alignment=TA_CENTER,
spaceAfter=2, leading=16),
"h1": S("h1", fontSize=13, textColor=WHITE,
fontName="Helvetica-Bold", spaceBefore=4,
spaceAfter=4, leading=16),
"h2": S("h2", fontSize=11, textColor=DARK_RED,
fontName="Helvetica-Bold", spaceBefore=6,
spaceAfter=3, leading=14),
"h3": S("h3", fontSize=10, textColor=MED_BLUE,
fontName="Helvetica-Bold", spaceBefore=4,
spaceAfter=2, leading=13),
"body": S("body", fontSize=9.5, textColor=colors.black,
fontName="Helvetica", spaceAfter=3, leading=14,
alignment=TA_JUSTIFY),
"bullet": S("bullet", fontSize=9.5, textColor=colors.black,
fontName="Helvetica", spaceAfter=2, leading=13,
leftIndent=14, bulletIndent=0),
"small": S("small", fontSize=8.5, textColor=HexColor("#555555"),
fontName="Helvetica-Oblique", spaceAfter=2, leading=12,
alignment=TA_CENTER),
"note": S("note", fontSize=9, textColor=DARK_GREY,
fontName="Helvetica-Oblique", spaceAfter=3,
leading=13, leftIndent=8),
"keypoint": S("keypoint", fontSize=9.5, textColor=DARK_RED,
fontName="Helvetica-Bold", spaceAfter=2, leading=13,
leftIndent=12),
"th": S("th", fontSize=8.5, textColor=WHITE,
fontName="Helvetica-Bold", alignment=TA_CENTER, leading=12),
"td": S("td", fontSize=8.5, textColor=colors.black,
fontName="Helvetica", alignment=TA_CENTER, leading=12),
"td_left": S("td_left", fontSize=8.5, textColor=colors.black,
fontName="Helvetica", alignment=TA_LEFT, leading=12),
"td_bold": S("td_bold", fontSize=8.5, textColor=DARK_RED,
fontName="Helvetica-Bold", alignment=TA_LEFT, leading=12),
"alert": S("alert", fontSize=10, textColor=WHITE,
fontName="Helvetica-Bold", alignment=TA_CENTER,
leading=14, spaceAfter=2),
}
# ── Helpers ────────────────────────────────────────────────────────────────────
def section_header(text, color=DARK_RED):
tbl = Table([[Paragraph(text, styles["h1"])]], colWidths=[W])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), color),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("LEFTPADDING", (0,0), (-1,-1), 10),
("ROUNDEDCORNERS", [4]),
]))
return tbl
def info_box(text, bg=LIGHT_BLUE, border=MED_BLUE):
tbl = Table([[Paragraph(text, styles["note"])]], colWidths=[W])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("LINEAFTER", (0,0), (0,-1), 3, border),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING",(0,0),(-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 12),
("ROUNDEDCORNERS", [3]),
]))
return tbl
def alert_box(text, bg=MED_RED):
tbl = Table([[Paragraph(text, styles["alert"])]], colWidths=[W])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 10),
("ROUNDEDCORNERS", [4]),
]))
return tbl
def make_table(headers, rows, col_widths, hdr_color=DARK_RED, alt_color=GREY_BG):
header_row = [Paragraph(h, styles["th"]) for h in headers]
data = [header_row]
for row in rows:
styled = []
for j, cell in enumerate(row):
if cell.startswith(">>"):
styled.append(Paragraph(cell[2:], styles["td_left"]))
elif j == 0:
styled.append(Paragraph(cell, styles["td_bold"]))
else:
styled.append(Paragraph(cell, styles["td"]))
data.append(styled)
tbl = Table(data, colWidths=col_widths, repeatRows=1)
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), hdr_color),
("GRID", (0,0), (-1,-1), 0.5, GREY_BORDER),
("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, alt_color]),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
]))
return tbl
def bullet(text):
return Paragraph(f"<bullet>•</bullet> {text}", styles["bullet"])
def sp(h=6): return Spacer(1, h)
def img_block(path, w, h, caption):
if path and os.path.exists(path):
img = Image(path, width=w, height=h)
img.hAlign = "CENTER"
cap = Paragraph(f"<i>{caption}</i>", styles["small"])
tbl = Table([[img], [cap]], colWidths=[W])
tbl.setStyle(TableStyle([
("ALIGN", (0,0), (-1,-1), "CENTER"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
]))
return tbl
return sp(4)
def two_img_block(p1, w1, h1, cap1, p2, w2, h2, cap2):
"""Side-by-side two images."""
left = []
right = []
if p1 and os.path.exists(p1):
left = [[Image(p1, width=w1, height=h1)],
[Paragraph(f"<i>{cap1}</i>", styles["small"])]]
if p2 and os.path.exists(p2):
right = [[Image(p2, width=w2, height=h2)],
[Paragraph(f"<i>{cap2}</i>", styles["small"])]]
if left and right:
left_t = Table(left, colWidths=[W/2 - 0.5*cm])
right_t = Table(right, colWidths=[W/2 - 0.5*cm])
left_t.setStyle(TableStyle([("ALIGN",(0,0),(-1,-1),"CENTER"),("TOPPADDING",(0,0),(-1,-1),2)]))
right_t.setStyle(TableStyle([("ALIGN",(0,0),(-1,-1),"CENTER"),("TOPPADDING",(0,0),(-1,-1),2)]))
row = Table([[left_t, right_t]], colWidths=[W/2, W/2])
row.setStyle(TableStyle([("ALIGN",(0,0),(-1,-1),"CENTER"),("VALIGN",(0,0),(-1,-1),"TOP")]))
return row
return sp(4)
# ── PAGE HEADER / FOOTER ───────────────────────────────────────────────────────
def on_page(canvas, doc):
canvas.saveState()
canvas.setFillColor(DARK_RED)
canvas.rect(doc.leftMargin, A4[1]-1.8*cm, W, 1.1*cm, fill=1, stroke=0)
canvas.setFont("Helvetica-Bold", 9)
canvas.setFillColor(WHITE)
canvas.drawString(doc.leftMargin+0.3*cm, A4[1]-1.3*cm,
"MYOCARDIAL INFARCTION – Clinical Case Study")
canvas.drawRightString(doc.leftMargin+W, A4[1]-1.3*cm, "Orris Medical AI")
canvas.setFillColor(GREY_BORDER)
canvas.rect(doc.leftMargin, 1.5*cm, W, 0.5*cm, fill=1, stroke=0)
canvas.setFont("Helvetica", 7.5)
canvas.setFillColor(DARK_GREY)
canvas.drawString(doc.leftMargin+0.2*cm, 1.7*cm,
"Sources: Robbins & Kumar Pathologic Basis of Disease | Harrison's IM 22E | Ganong's Review | Goldman-Cecil Medicine")
canvas.drawRightString(doc.leftMargin+W-0.2*cm, 1.7*cm, f"Page {doc.page}")
canvas.restoreState()
# ═══════════════════════════════════════════════════════════════════════════════
# BUILD STORY
# ═══════════════════════════════════════════════════════════════════════════════
story = []
# ── COVER ──────────────────────────────────────────────────────────────────────
cover_data = [[
Paragraph("MYOCARDIAL INFARCTION", styles["title"]),
Paragraph("Complete Clinical Case Study | Cardiology", styles["subtitle"]),
Paragraph("Orris Medical AI • July 2026", styles["subtitle"]),
]]
cover = Table(cover_data, colWidths=[W])
cover.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), DARK_RED),
("TOPPADDING", (0,0), (-1,-1), 18),
("BOTTOMPADDING", (0,0), (-1,-1), 18),
("LEFTPADDING", (0,0), (-1,-1), 14),
("ROUNDEDCORNERS", [6]),
]))
story.append(cover)
story.append(sp(16))
# ── CASE PRESENTATION ─────────────────────────────────────────────────────────
story.append(section_header("📋 CLINICAL CASE PRESENTATION"))
story.append(sp(6))
story.append(Paragraph("<b>Patient:</b> Mr. Rajesh K., 58-year-old male", styles["body"]))
story.append(Paragraph(
"<b>Chief Complaint:</b> Sudden, severe crushing chest pain radiating to the left arm and jaw — 45 minutes",
styles["body"]))
story.append(sp(5))
story.append(Paragraph(
"A 58-year-old male with a 15-year history of hypertension, type 2 diabetes, and active smoking "
"presents to the emergency department by ambulance with sudden onset of severe, crushing, "
"substernal chest pain (8/10) that began while climbing stairs. The pain radiates to the left arm "
"and jaw, is associated with profuse diaphoresis, nausea, and vomiting, and has not been relieved by "
"rest. He took aspirin 325 mg (chewed) en route to hospital. Duration of symptoms: 45 minutes.",
styles["body"]))
story.append(sp(5))
hx = [
["Past Medical History", "Hypertension (15 years), Type 2 diabetes mellitus (10 years), Hyperlipidaemia"],
["Past Cardiac History", "No prior MI; no prior PCI or CABG; stable angina on exertion 2 years ago"],
["Medications", "Metformin 1g BD, Amlodipine 5mg OD, Atorvastatin 20mg OD, no anticoagulants"],
["Family History", "Father: fatal MI at age 55. Brother: coronary artery disease at age 50"],
["Social History", "Active smoker: 30 pack-years. Sedentary lifestyle. High-fat diet."],
["Allergies", "No known drug allergies"],
]
hx_data = [[Paragraph(f"<b>{k}</b>", styles["td_left"]),
Paragraph(v, styles["td_left"])] for k, v in hx]
hx_tbl = Table(hx_data, colWidths=[4.5*cm, W-4.5*cm])
hx_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,-1), LIGHT_RED),
("FONTNAME", (0,0), (0,-1), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 9),
("GRID", (0,0), (-1,-1), 0.5, GREY_BORDER),
("ROWBACKGROUNDS",(0,0), (-1,-1), [WHITE, GREY_BG]),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
]))
story.append(hx_tbl)
story.append(sp(10))
# ── RISK FACTORS ──────────────────────────────────────────────────────────────
story.append(section_header("⚠️ RISK FACTOR ANALYSIS", ORANGE))
story.append(sp(6))
rf_headers = ["Risk Factor", "Status", "Contribution"]
rf_rows = [
["Age (male ≥45 years)", "58 years — HIGH RISK", "Independent major risk factor"],
["Hypertension", "Active — 15 years", "Promotes endothelial injury and atherogenesis"],
["Diabetes Mellitus", "Active — 10 years", "Accelerates atherosclerosis; blunts ischaemic pain"],
["Smoking", "30 pack-years", "Strongest modifiable risk factor for plaque rupture"],
["Hyperlipidaemia", "Present", "LDL-C drives foam cell and atheroma formation"],
["Family History", "Father MI at 55; Brother CAD","Genetic predisposition; premature atherosclerosis"],
["Sedentary Lifestyle", "Present", "Reduces HDL; promotes insulin resistance"],
["Male Sex", "Male", "Males at higher risk until females lose oestrogen protection"],
]
story.append(make_table(rf_headers, rf_rows,
[4*cm, 4*cm, W-8*cm], hdr_color=ORANGE))
story.append(sp(8))
# ── EXAMINATION ───────────────────────────────────────────────────────────────
story.append(section_header("🩺 PHYSICAL EXAMINATION", DARK_BLUE))
story.append(sp(6))
vitals_headers = ["BP", "HR", "RR", "SpO₂", "Temp", "BGL"]
vitals_rows = [["160/100 mmHg", "108 bpm (sinus tachy)", "22/min", "94% (room air)", "37.2 °C", "14 mmol/L"]]
story.append(make_table(vitals_headers, vitals_rows,
[W/6]*6, hdr_color=DARK_RED, alt_color=LIGHT_RED))
story.append(sp(8))
exam = [
("General", "Anxious, diaphoretic, pale; clutching chest; in obvious distress"),
("CVS", "Tachycardia; displaced apex beat; S3 gallop; muffled heart sounds; JVP not raised"),
("Respiratory", "Bilateral basal crackles — early pulmonary oedema"),
("Extremities", "Cool, clammy peripheries; capillary refill 3 seconds"),
("Neurological", "Alert and oriented; GCS 15"),
("Abdomen", "Soft, non-tender; no organomegaly"),
]
exam_data = [[Paragraph(f"<b>{k}</b>", styles["td_left"]),
Paragraph(v, styles["td_left"])] for k, v in exam]
exam_tbl = Table(exam_data, colWidths=[3.5*cm, W-3.5*cm])
exam_tbl.setStyle(TableStyle([
("ROWBACKGROUNDS", (0,0), (-1,-1), [WHITE, GREY_BG]),
("GRID", (0,0), (-1,-1), 0.5, GREY_BORDER),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(exam_tbl)
story.append(sp(10))
# ── INVESTIGATIONS ────────────────────────────────────────────────────────────
story.append(PageBreak())
story.append(section_header("🔬 INVESTIGATIONS"))
story.append(sp(6))
# ECG
story.append(Paragraph("<b>12-Lead ECG — Performed in ED within 10 minutes of arrival</b>", styles["h2"]))
story.append(sp(4))
story.append(img_block(img_ecg_stemi, 14*cm, 8*cm,
"Anterolateral STEMI: ST-segment elevation in V1-V6, I, and aVL with reciprocal depression "
"in inferior leads II, III, aVF. Hyperacute T-waves in V2-V4. Consistent with proximal LAD occlusion."))
story.append(sp(6))
ecg_findings_headers = ["ECG Finding", "Leads", "Interpretation"]
ecg_findings_rows = [
[">>ST-segment elevation ≥1 mm", "V1-V6, I, aVL", "Anterior + lateral STEMI — LAD territory"],
[">>Reciprocal ST depression", "II, III, aVF", "Mirror image of anterior injury current"],
[">>Hyperacute (tall peaked) T-waves","V2-V4", "Earliest ECG sign — minutes after occlusion"],
[">>Loss of R-wave progression", "V1-V4", "Developing Q-waves; transmural necrosis"],
[">>Sinus tachycardia", "All leads", "Sympathetic activation from pain/low output"],
]
story.append(make_table(ecg_findings_headers, ecg_findings_rows,
[5*cm, 3.5*cm, W-8.5*cm]))
story.append(sp(5))
story.append(info_box(
"<b>ECG Localisation of MI:</b> Anterior (V1-V4) = LAD; "
"Lateral (I, aVL, V5-V6) = LCx; Inferior (II, III, aVF) = RCA; "
"Posterior (tall R in V1, ST depression V1-V3) = RCA/LCx. "
"<b>STEMI criteria:</b> ≥2 contiguous leads with ≥1 mm ST elevation (≥2 mm in V2-V3 for males). "
"— <i>Ganong's Review of Medical Physiology 26E; Harrison's IM 22E</i>"))
story.append(sp(8))
# Biomarkers
story.append(Paragraph("<b>Cardiac Biomarkers</b>", styles["h2"]))
bio_headers = ["Marker", "At Presentation", "Peak", "Return to Normal", "Clinical Use"]
bio_rows = [
["High-sensitivity Troponin I", "0.8 ng/L (elevated — >99th %ile)", "12-24 h", "5-7 days", "Most sensitive/specific for MI"],
["Troponin T", "Elevated", "12-24 h", "10-14 days","Confirms myocardial necrosis"],
["CK-MB", "Elevated", "18-24 h", "3-4 days", "Reinfarction detection"],
["Myoglobin", "Elevated (early)", "4-8 h", "24-36 h", "Earliest marker; non-specific"],
["LDH", "Normal at 0-8 h", "3-6 days", "8-14 days", "Late marker; forensic use"],
]
story.append(make_table(bio_headers, bio_rows,
[3.5*cm, 3.5*cm, 2*cm, 2.5*cm, W-11.5*cm]))
story.append(sp(5))
story.append(info_box(
"<b>High-sensitivity troponin (hs-cTn):</b> Detectable within 1-3 hours of symptom onset. "
"A rise AND/OR fall pattern with at least one value above the 99th percentile Upper Reference Limit (URL) "
"is required for diagnosis. Serial measurements at 0h/1h or 0h/2h are standard. "
"— <i>Harrison's Principles of Internal Medicine 22E, p. 2159</i>"))
story.append(sp(8))
# Other labs
story.append(Paragraph("<b>Additional Blood Tests</b>", styles["h2"]))
labs = [
["FBC", "Hb 14.2 g/dL, WBC 14.5 × 10⁹/L (stress leucocytosis), Plt 260 × 10⁹/L"],
["Renal function", "Creatinine 98 µmol/L, eGFR 72 mL/min/1.73m² — note for contrast use"],
["LFTs/LDH", "ALT mildly elevated; LDH within normal range at presentation"],
["Lipid profile", "Total cholesterol 6.8 mmol/L, LDL 4.5 mmol/L, HDL 0.9 mmol/L, TG 2.8 mmol/L"],
["HbA1c", "9.2% — poorly controlled diabetes"],
["BNP", "380 pg/mL — elevated; early heart failure/myocardial stress"],
["Coagulation", "PT/APTT normal; no prior anticoagulation"],
["ABG", "pH 7.38, pO₂ 68 mmHg, pCO₂ 38 mmHg — mild hypoxaemia"],
["CXR", "Cardiomegaly; bilateral perihilar haziness — early pulmonary oedema; no pneumothorax"],
]
lab_data = [[Paragraph(f"<b>{k}</b>", styles["td_left"]),
Paragraph(v, styles["td_left"])] for k, v in labs]
lab_tbl = Table(lab_data, colWidths=[3.5*cm, W-3.5*cm])
lab_tbl.setStyle(TableStyle([
("ROWBACKGROUNDS", (0,0), (-1,-1), [WHITE, GREY_BG]),
("GRID", (0,0), (-1,-1), 0.5, GREY_BORDER),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
]))
story.append(lab_tbl)
story.append(sp(10))
# ── PATHOPHYSIOLOGY ───────────────────────────────────────────────────────────
story.append(PageBreak())
story.append(section_header("⚙️ PATHOPHYSIOLOGY"))
story.append(sp(6))
story.append(Paragraph("<b>Step-by-Step Pathogenesis of MI (Coronary Thrombosis)</b>", styles["h2"]))
steps = [
("<b>Step 1 — Atherosclerotic Plaque Formation:</b>",
"Endothelial injury from hypertension, smoking, hyperlipidaemia, and diabetes triggers LDL oxidation, "
"monocyte recruitment, and foam cell formation within the intima. Over years, a fibrous cap forms "
"overlying a lipid-rich necrotic core."),
("<b>Step 2 — Plaque Rupture or Erosion:</b>",
"Mechanical forces and metalloproteinases degrade the fibrous cap. Plaque rupture exposes "
"subendothelial collagen and the necrotic core to circulating blood. Critically, "
"most MIs occur at plaques with <70% stenosis — these are 'vulnerable plaques.'"),
("<b>Step 3 — Platelet Activation and Aggregation:</b>",
"Exposed collagen triggers platelet adhesion (via vWF-GPIb). Activated platelets release "
"thromboxane A2, ADP, and serotonin — causing further platelet aggregation and coronary vasospasm."),
("<b>Step 4 — Coagulation Cascade Activation:</b>",
"Tissue factor from the plaque activates the extrinsic coagulation pathway → thrombin generation "
"→ fibrin mesh formation. The thrombus rapidly grows."),
("<b>Step 5 — Complete Coronary Occlusion:</b>",
"Within minutes, the thrombus occludes the coronary artery. "
"When angiography is performed within 4 hours of MI onset, thrombotic occlusion is found in ~90% of cases. "
"— <i>Robbins, Cotran & Kumar Pathologic Basis of Disease</i>"),
("<b>Step 6 — Ischaemia → Irreversible Injury:</b>",
"Within seconds: ATP depletion begins. Within 2 minutes: contractility lost. "
"Within 20-40 minutes: irreversible cell death (coagulative necrosis) begins in the subendocardium "
"(most vulnerable zone). Necrosis then propagates as a wavefront toward the epicardium. "
"An infarct achieves its full extent within 6-12 hours without intervention."),
]
for heading, detail in steps:
story.append(Paragraph(heading, styles["h3"]))
story.append(Paragraph(detail, styles["body"]))
story.append(sp(3))
story.append(sp(6))
story.append(img_block(img_necrosis_prog, 12*cm, 14*cm,
"Fig. Progression of myocardial necrosis after coronary artery occlusion. "
"Zone of perfusion (area at risk, yellow outline). Necrosis begins in subendocardium at 2h "
"and extends as a wavefront toward the epicardium at 24h. A thin rim immediately beneath the "
"endocardium is spared (oxygen diffusion from LV cavity). "
"— Robbins, Cotran & Kumar Pathologic Basis of Disease"))
story.append(sp(8))
story.append(Paragraph("<b>Timeline of Ischaemic Events in Cardiomyocytes</b>", styles["h2"]))
timeline_headers = ["Event", "Time After Occlusion"]
timeline_rows = [
[">>Onset of ATP depletion", "Seconds"],
[">>Loss of contractility", "<2 minutes"],
[">>ATP reduced to 50% of normal", "10 minutes"],
[">>ATP reduced to 10% of normal", "40 minutes"],
[">>Irreversible cell death (point of no return)", "20-40 minutes"],
[">>Microvascular injury", ">1 hour"],
[">>Infarct reaches full extent", "6-12 hours (without reperfusion)"],
]
story.append(make_table(timeline_headers, timeline_rows, [10*cm, W-10*cm]))
story.append(sp(5))
story.append(info_box(
"<b>Clinical implication — 'Time is myocardium':</b> Every 30-minute delay in reperfusion costs ~1 million "
"cardiomyocytes. The goal is Door-to-Balloon time <90 minutes. "
"— <i>Robbins, Cotran & Kumar Pathologic Basis of Disease, Table 12.4</i>"))
story.append(sp(8))
# Plaque histology
story.append(Paragraph("<b>Histopathology of Plaque Rupture and Coronary Thrombosis</b>", styles["h2"]))
story.append(sp(4))
story.append(img_block(img_plaque_rupture, 10*cm, 7*cm,
"Histopathology of LAD coronary artery: ruptured fibrous cap with overlying occlusive thrombus. "
"Lipid-rich necrotic core with cholesterol clefts visible. Near-complete luminal occlusion. "
"This pattern explains the pathogenesis of fatal acute MI. "
"(Autopsy specimen, H&E stain)"))
story.append(sp(8))
# ── TEMPORAL MORPHOLOGICAL CHANGES ────────────────────────────────────────────
story.append(PageBreak())
story.append(section_header("🔍 TEMPORAL CHANGES IN MYOCARDIAL INFARCTION"))
story.append(sp(6))
story.append(Paragraph(
"Morphological changes in MI follow a predictable sequence, allowing estimation of infarct age. "
"This is important for forensic pathology, post-mortem diagnosis, and assessing reperfusion timing.",
styles["body"]))
story.append(sp(6))
temporal_headers = ["Time", "Gross Appearance", "Histology", "Key Features"]
temporal_rows = [
["0-4 hours", "Normal / subtle pallor",
">>Near-normal; mild waviness at border; coagulative necrosis starting",
">>'Reversible' window ends at 20-40 min"],
["4-12 hours", "Occasionally dark mottling",
">>Coagulative necrosis; wavy fibers; early oedema; pyknotic nuclei",
">>Wavy fibers = earliest histologic sign"],
["12-24 hours", "Dark mottling",
">>Coagulative necrosis; intense eosinophilia; loss of nuclei; neutrophil infiltration begins",
">>Dense PMN infiltrate"],
["1-3 days", "Mottling with yellow-tan centre",
">>Peak neutrophil infiltration; myocyte 'ghosts' with preserved outlines",
">>Highest risk of free wall rupture"],
["3-7 days", "Hyperaemic border; yellow-tan softening",
">>Macrophage phagocytosis of dead cells; granulation tissue begins at margins",
">>Softening → risk of aneurysm/rupture"],
["1-3 weeks", "Grey-white scar forming",
">>Granulation tissue with neo-vessels and fibroblasts; collagen deposition begins",
">>Organisation / repair phase"],
["Weeks-months", "White, firm scar",
">>Dense collagen scar; loss of nuclei; no inflammation",
">>Complete fibrosis / healed MI"],
]
story.append(make_table(temporal_headers, temporal_rows,
[2.2*cm, 3*cm, 5.5*cm, W-10.7*cm]))
story.append(sp(8))
# Histology images
story.append(Paragraph("<b>Histopathology Images</b>", styles["h2"]))
story.append(sp(4))
story.append(two_img_block(
img_histo_early, 7*cm, 5*cm,
"Early MI (6-12h): Wavy myocardial fibres at the infarct border, eosinophilic cytoplasm, "
"loss of cross-striations. Hallmark of earliest coagulative necrosis. (H&E, LM)",
img_histo_acute, 7*cm, 5*cm,
"Acute MI (3-4 days): Dense neutrophilic infiltrate (dark cells) between necrotic fibres "
"with homogeneous eosinophilic cytoplasm and lost nuclei. Peak inflammatory phase. (H&E, LM)"
))
story.append(sp(8))
# ── CLASSIFICATION ────────────────────────────────────────────────────────────
story.append(section_header("📊 CLASSIFICATION OF MI", DARK_BLUE))
story.append(sp(6))
story.append(Paragraph(
"<b>Fourth Universal Definition of MI (2018)</b> — Five Types:", styles["h2"]))
types_headers = ["Type", "Mechanism", "Example"]
types_rows = [
["Type 1 — Spontaneous MI", ">>Atherothrombosis: plaque rupture/erosion + coronary thrombosis", "This patient"],
["Type 2 — MI due to supply-demand mismatch", ">>Non-thrombotic: vasospasm, tachy/bradyarrhythmia, severe anaemia, hypotension", "Cocaine-induced vasospasm; severe anaemia"],
["Type 3 — MI causing sudden death", ">>Cardiac death before biomarker results available", "Witnessed cardiac arrest with typical ECG"],
["Type 4a — Peri-PCI MI", ">>MI within 48h of PCI procedure (5× troponin rise)", "Post-stenting myonecrosis"],
["Type 4b — Stent thrombosis",">>Angiographic/post-mortem confirmed stent thrombosis", "Acute in-stent thrombosis"],
["Type 5 — Peri-CABG MI", ">>MI within 48h of CABG surgery (10× troponin rise)", "Post-operative myonecrosis"],
]
story.append(make_table(types_headers, types_rows,
[3.5*cm, 6.5*cm, W-10*cm], hdr_color=DARK_BLUE))
story.append(sp(6))
story.append(Paragraph("<b>STEMI vs NSTEMI</b>", styles["h2"]))
sn_headers = ["Feature", "STEMI", "NSTEMI"]
sn_rows = [
["Coronary occlusion", "Complete (100%)", "Partial / intermittent"],
["ECG", "ST elevation ≥1 mm in ≥2 contiguous leads", "ST depression / T-wave changes / normal"],
["Q waves", "Usually develop", "Usually absent"],
["Troponin", "Markedly elevated", "Elevated (lesser extent)"],
["Extent of necrosis", "Transmural (full thickness)","Subendocardial (partial)"],
["Reperfusion strategy", "Emergency PCI ≤90 min (preferred)", "Risk-stratified: early invasive or conservative"],
["Mortality", "Higher acute mortality", "Higher late mortality (unstable, recurrent risk)"],
]
story.append(make_table(sn_headers, sn_rows,
[4.5*cm, 5.5*cm, W-10*cm], hdr_color=DARK_BLUE))
story.append(sp(10))
# ── DIAGNOSIS ─────────────────────────────────────────────────────────────────
dx_box_data = [[
Paragraph("✅ CONFIRMED DIAGNOSIS", ParagraphStyle("dx_title",
fontSize=13, textColor=WHITE, fontName="Helvetica-Bold",
alignment=TA_CENTER, spaceAfter=4)),
Paragraph(
"Acute Anterior STEMI (Type 1 MI) — LAD Territory<br/>"
"Killip Class II (Crackles; no cardiogenic shock)",
ParagraphStyle("dx_sub", fontSize=11, textColor=LIGHT_GREEN,
fontName="Helvetica-BoldOblique", alignment=TA_CENTER)),
]]
dx_box = Table(dx_box_data, colWidths=[W])
dx_box.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), GREEN),
("TOPPADDING", (0,0), (-1,-1), 12),
("BOTTOMPADDING", (0,0), (-1,-1), 12),
("LEFTPADDING", (0,0), (-1,-1), 12),
("ROUNDEDCORNERS", [6]),
]))
story.append(dx_box)
story.append(sp(8))
story.append(Paragraph("<b>Diagnostic Criteria Met:</b>", styles["h2"]))
dx = [
"Acute ischaemic symptoms: crushing chest pain >20 minutes, radiation to arm/jaw, diaphoresis",
"ST elevation in V1-V6, I, aVL (anterior + lateral leads) with reciprocal depression inferiorly",
"High-sensitivity troponin I significantly elevated above 99th percentile URL",
"Risk factors: male, 58 years, hypertension, DM2, smoking, hyperlipidaemia, family history",
"Haemodynamic compromise: tachycardia, cool peripheries, basal crackles (Killip II)",
]
for d in dx:
story.append(bullet(d))
story.append(sp(5))
story.append(Paragraph("<b>Killip Classification (Acute MI Severity)</b>", styles["h2"]))
killip_headers = ["Class", "Clinical Features", "Mortality (historical)"]
killip_rows = [
["Class I", "No heart failure signs", "~6%"],
["Class II", "Mild HF: crackles <50% lung fields, S3 gallop (this patient)", "~17%"],
["Class III", "Severe HF: pulmonary oedema — crackles >50% lung fields", "~38%"],
["Class IV", "Cardiogenic shock: hypotension (<90 mmHg) + peripheral hypoperfusion", "~80%"],
]
story.append(make_table(killip_headers, killip_rows,
[2.5*cm, 8.5*cm, W-11*cm]))
story.append(sp(10))
# ── MANAGEMENT ────────────────────────────────────────────────────────────────
story.append(PageBreak())
story.append(section_header("💊 MANAGEMENT — STEMI"))
story.append(sp(6))
story.append(alert_box("⏱ DOOR-TO-BALLOON TIME TARGET: ≤90 MINUTES — TIME IS MYOCARDIUM", ACCENT_RED))
story.append(sp(8))
story.append(Paragraph("<b>Immediate (ED) Management — 'MONA-B' + Reperfusion</b>", styles["h2"]))
immediate = [
("<b>M — Morphine</b>", "2-4 mg IV for pain relief (use cautiously — may delay P2Y12 inhibitor absorption)"),
("<b>O — Oxygen</b>", "Only if SpO₂ <90%; avoid hyperoxia (harmful in normoxic patients)"),
("<b>N — Nitrates</b>", "Sublingual GTN 0.4 mg (AVOID if SBP <90, RV infarction, or PDE5 inhibitor use)"),
("<b>A — Aspirin</b>", "300 mg chewed stat (already given pre-hospital in this patient)"),
("<b>B — Beta-blocker</b>", "IV metoprolol (only if no contraindications: bradycardia, heart block, severe HF, hypotension)"),
("<b>Anticoagulation</b>", "Unfractionated heparin (UFH) 60 U/kg bolus + infusion; or bivalirudin with primary PCI"),
("<b>P2Y12 inhibitor</b>", "Ticagrelor 180 mg loading dose (preferred) OR clopidogrel 600 mg — dual antiplatelet with aspirin"),
]
for med, desc in immediate:
row_data = [[Paragraph(med, styles["td_bold"]), Paragraph(desc, styles["td_left"])]]
row_tbl = Table(row_data, colWidths=[4*cm, W-4*cm])
row_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,-1), LIGHT_RED),
("BACKGROUND", (1,0), (1,-1), WHITE),
("GRID", (0,0), (-1,-1), 0.5, GREY_BORDER),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("FONTSIZE", (0,0), (-1,-1), 9),
]))
story.append(row_tbl)
story.append(sp(2))
story.append(sp(8))
story.append(Paragraph("<b>Reperfusion Strategy</b>", styles["h2"]))
story.append(Paragraph(
"<b>Primary PCI (Percutaneous Coronary Intervention)</b> is the gold standard reperfusion strategy "
"for STEMI when available within 120 minutes of first medical contact. "
"It involves emergency coronary angiography + stenting of the culprit lesion.",
styles["body"]))
story.append(sp(4))
reperfusion_headers = ["Strategy", "Indication", "Target / Details"]
reperfusion_rows = [
[">>Primary PCI", "STEMI within 12h; PCI centre accessible within 120 min of FMC",
"Door-to-balloon ≤90 min; drug-eluting stent (DES) preferred"],
[">>Fibrinolysis (thrombolysis)", "When primary PCI not available within 120 min of FMC",
"Alteplase, tenecteplase; within 12h of onset; Door-to-needle ≤30 min"],
[">>Rescue PCI", "After failed fibrinolysis (<50% ST resolution at 60-90 min)",
"Emergency transfer to PCI centre"],
[">>CABG", "Left main disease, multivessel disease not amenable to PCI, failed PCI",
"Rarely in acute phase; usually elective post-stabilisation"],
]
story.append(make_table(reperfusion_headers, reperfusion_rows,
[3.5*cm, 5.5*cm, W-9*cm]))
story.append(sp(8))
story.append(Paragraph("<b>Long-Term Post-MI Medications (Secondary Prevention)</b>", styles["h2"]))
ltx_headers = ["Drug Class", "Agent / Dose", "Duration", "Benefit"]
ltx_rows = [
["Antiplatelet (dual)", "Aspirin 75mg OD + Ticagrelor 90mg BD", "Ticagrelor for 12 months", "Prevent stent thrombosis and reinfarction"],
["Antiplatelet (single)", "Aspirin 75mg OD lifelong", "Lifelong", "Prevent recurrent MI/stroke"],
["ACE inhibitor", "Ramipril 2.5→10 mg OD", "Lifelong", "Reduces remodelling, HF, mortality"],
["Beta-blocker", "Metoprolol succinate 25→200 mg OD", "Lifelong", "Reduces reinfarction, SCD risk"],
["Statin (high-intensity)", "Atorvastatin 80 mg OD", "Lifelong", "LDL ↓ ≥50%; stabilises plaques"],
["Aldosterone antagonist","Eplerenone 25-50 mg OD", "≥12 months", "If LVEF ≤40% + HF or DM"],
["SGLT2 inhibitor", "Dapagliflozin 10mg OD", "Lifelong (DM2+HF)", "Reduces CV events/hospitalisations"],
["Nitrate (PRN)", "GTN spray sublingual PRN", "As needed", "Angina relief"],
]
story.append(make_table(ltx_headers, ltx_rows,
[3.5*cm, 4.5*cm, 2.5*cm, W-10.5*cm]))
story.append(sp(8))
story.append(Paragraph("<b>Monitoring & Follow-Up</b>", styles["h2"]))
followup = [
"Continuous cardiac monitoring in CCU for 24-72 hours (arrhythmia detection)",
"Serial ECGs: at 1h, 6h, 24h, discharge — monitor ST resolution, Q-wave evolution",
"Serial troponins: at 0h, 1h, 3h, 6h — confirms necrosis size (peak = infarct size estimate)",
"Echocardiogram within 24-48h: assess LVEF, wall motion abnormalities, pericardial effusion, mechanical complications",
"Target LVEF assessment at 6-12 weeks — determines need for ICD (if LVEF ≤35%)",
"Cardiac rehabilitation referral before discharge",
"Lipid profile, HbA1c, BGL control optimised before discharge",
"Follow-up outpatient appointment at 4-6 weeks; annual thereafter",
]
for f in followup:
story.append(bullet(f))
story.append(sp(10))
# ── COMPLICATIONS ─────────────────────────────────────────────────────────────
story.append(PageBreak())
story.append(section_header("⚡ COMPLICATIONS OF MYOCARDIAL INFARCTION"))
story.append(sp(6))
story.append(Paragraph(
"Complications are the leading cause of MI mortality. They are classified as <b>early</b> (hours to days) "
"and <b>late</b> (weeks to months) and as <b>electrical</b> or <b>mechanical</b>. "
"Early mortality is primarily from arrhythmias; late mortality from pump failure and remodelling. "
"— <i>Harrison's Principles of Internal Medicine 22E</i>", styles["body"]))
story.append(sp(6))
comp_headers = ["Complication", "Timing", "Mechanism", "Clinical Features"]
comp_rows = [
["Ventricular Fibrillation", "Minutes-hours", ">>Reentry in ischaemic zone",
">>Sudden cardiac arrest; most common cause of early out-of-hospital death"],
["Cardiogenic Shock", "Hours-days", ">>Loss of >40% LV myocardium",
">>SBP <90, cool peripheries, oliguria; mortality ~50%"],
["LV Free Wall Rupture", "3-7 days", ">>Softening of necrotic wall",
">>Sudden haemopericardium, tamponade, PEA; usually fatal"],
["VSD (Septal Rupture)", "3-5 days", ">>Necrosis of interventricular septum",
">>New harsh systolic murmur, L→R shunt, rapid deterioration"],
["Papillary Muscle Rupture", "2-7 days", ">>Posteromedial > anterolateral",
">>Acute severe MR, flash pulmonary oedema, new systolic murmur"],
["LV Aneurysm", "Weeks-months", ">>Fibrotic thinning + dyskinesis of necrosed wall",
">>Persistent ST elevation, thrombus, arrhythmias, HF"],
["Pericarditis (Dressler syndrome)", "2-8 weeks",">>Autoimmune pericarditis post-MI",
">>Pleuritic chest pain, fever, friction rub, pericardial effusion"],
["Heart Failure", "Days-months", ">>LV remodelling and dilatation",
">>Dyspnoea, orthopnoea, elevated BNP; chronic complication"],
["RV Infarction", "Acute", ">>RCA occlusion affecting RV",
">>Hypotension + raised JVP + clear lungs; avoid nitrates/diuretics"],
]
story.append(make_table(comp_headers, comp_rows,
[3.5*cm, 2*cm, 4*cm, W-9.5*cm]))
story.append(sp(6))
story.append(img_block(img_complications, 14*cm, 8*cm,
"Mechanical complications of acute MI: (1) Papillary muscle rupture — acute severe MR; "
"(2) Ventricular septal rupture — L→R shunt, systolic murmur; "
"(3) Contained rupture (pseudoaneurysm) — small neck communication; "
"(4) Free wall rupture — pericardial tamponade, circulatory collapse. "
"(Adapted from Fuster and Hurst's The Heart)"))
story.append(sp(10))
# ── DIFFERENTIAL DIAGNOSIS ────────────────────────────────────────────────────
story.append(section_header("⚖️ DIFFERENTIAL DIAGNOSIS OF ACUTE CHEST PAIN", DARK_BLUE))
story.append(sp(6))
ddx_headers = ["Diagnosis", "Key Differentiating Features", "Emergency Test"]
ddx_rows = [
["STEMI (this case)", ">>ST elevation, troponin rise, risk factors, responds to reperfusion",
"12-lead ECG + hs-troponin"],
["NSTEMI/Unstable angina", ">>No ST elevation; troponin rise (NSTEMI) or no rise (UA)",
"Serial troponins + ECG"],
["Aortic Dissection", ">>Tearing pain to back; BP asymmetry; wide mediastinum on CXR; AI present",
"CT aortogram (urgent)"],
["Pulmonary Embolism", ">>Pleuritic pain; dyspnoea; haemoptysis; DVT risk; sinus tachycardia; S1Q3T3",
"CT-PA + D-dimer"],
["Acute Pericarditis", ">>Sharp pleuritic pain; relieved by leaning forward; friction rub; saddle-shaped ST; trapezius pain",
"ECG (diffuse ST); echo"],
["Myocarditis", ">>Younger patient; viral prodrome; diffuse ST changes; echo shows global dysfunction",
"MRI cardiac; troponin"],
["Takotsubo (Stress) CMP", ">>Post-emotional/physical stress; predominantly female; apical ballooning on echo",
"Echo; angiography (no CAD)"],
["Oesophageal Spasm", ">>Burning quality; responds to GTN; no ECG changes; normal troponin",
"Clinical; upper GI contrast"],
["Costochondritis", ">>Reproducible on palpation; no radiation; normal ECG and troponin",
"Clinical diagnosis"],
]
story.append(make_table(ddx_headers, ddx_rows,
[3.5*cm, 6.5*cm, W-10*cm], hdr_color=DARK_BLUE))
story.append(sp(10))
# ── KEY TEACHING POINTS ───────────────────────────────────────────────────────
story.append(PageBreak())
story.append(section_header("⭐ KEY TEACHING POINTS"))
story.append(sp(6))
kp = [
("'Time is myocardium' — Every 30 min delay costs ~1 million cardiomyocytes",
"Door-to-balloon ≤90 min is the target. Begin dual antiplatelet + heparin immediately in the ED."),
("Most MIs occur at <70% stenosis plaques ('vulnerable plaques')",
"High-grade stenosis is not the only danger. Lipid-rich, thin-cap plaques rupture unpredictably."),
("Diabetic patients may present without pain ('silent MI')",
"Autonomic neuropathy blunts ischaemic pain. MI may present as dyspnoea, vomiting, or confusion."),
("First ECG within 10 minutes of arrival — diagnose and act",
"STEMI is a clinical + ECG diagnosis. Do not wait for troponin results to activate the cath lab."),
("Hs-troponin rise AND/OR fall pattern is required — not just a single elevated value",
"A static elevation may indicate chronic myocardial injury. Serial measurements are mandatory."),
("Killip class predicts mortality — assess every STEMI patient",
"Class I = ~6%; Class IV (cardiogenic shock) = ~80%. Guides intensity of monitoring and support."),
("RV infarction: hypotension + raised JVP + clear lungs",
"This triad distinguishes RV infarction from LV failure. Treat with fluids — NOT nitrates/diuretics."),
("Post-MI secondary prevention saves more lives than acute treatment",
"Aspirin + P2Y12 + ACEi + beta-blocker + statin is mandatory. Cardiac rehabilitation reduces mortality by 25-30%."),
]
for i, (point, detail) in enumerate(kp):
row_data = [[
Paragraph(f"<b>{i+1}. {point}</b>", styles["keypoint"]),
Paragraph(detail, styles["body"]),
]]
bg = LIGHT_RED if i % 2 == 0 else YELLOW_BG
row_tbl = Table(row_data, colWidths=[6.5*cm, W-6.5*cm])
row_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,-1), bg),
("BACKGROUND", (1,0), (1,-1), WHITE),
("GRID", (0,0), (-1,-1), 0.5, GREY_BORDER),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(row_tbl)
story.append(sp(2))
story.append(sp(10))
# ── REFERENCES ────────────────────────────────────────────────────────────────
story.append(HRFlowable(width=W, thickness=1, color=DARK_RED, spaceAfter=6))
story.append(Paragraph("<b>References</b>", styles["h2"]))
refs = [
"Robbins, Cotran & Kumar. <i>Pathologic Basis of Disease, 10th Edition.</i> Elsevier, 2021.",
"Harrison's Principles of Internal Medicine, 22nd Edition. McGraw-Hill, 2025.",
"Ganong's Review of Medical Physiology, 26th Edition. McGraw-Hill, 2019.",
"Goldman-Cecil Medicine, International Edition. Elsevier, 2024.",
"Fuster and Hurst's The Heart, 15th Edition. McGraw-Hill, 2022.",
"Braunwald's Heart Disease, 12th Edition. Elsevier, 2022.",
"Fourth Universal Definition of Myocardial Infarction (ESC/ACC/AHA/WHF 2018).",
]
for ref in refs:
story.append(bullet(ref))
# ── BUILD ──────────────────────────────────────────────────────────────────────
print("Building PDF...")
doc.build(story, onFirstPage=on_page, onLaterPages=on_page)
print(f"PDF saved to: {OUTPUT_PATH}")
print(f"File size: {os.path.getsize(OUTPUT_PATH) / 1024:.1f} KB")
cd /tmp/workspace/mi_case && python build_mi_pdf.py 2>&1
Myocardial Infarction Clinical Case
PDF Document · PDF