How to evaluate anemia case according to harrison

Reading File
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Reading File
Reading File
Reading File
Reading File
Finding Sources
Searching Content

"66-17" in /textbooks/9781265977061

Reading File
I now have comprehensive content from Harrison's 22nd Edition. Let me compile the full, structured answer:

Evaluation of Anemia - Harrison's Principles of Internal Medicine (22nd Edition, 2025)


1. Definition

Anemia is defined as blood counts below normal for a given population. It is most often detected incidentally on a complete blood count (CBC) showing low hemoglobin and hematocrit. The hemoglobin thresholds vary by age and sex (see Table 66-2 in Harrison's).

2. Signs & Symptoms

Clinical manifestations are largely due to impaired oxygen delivery:
  • Fatigue, shortness of breath
  • Pallor of mucosa/conjunctiva
  • Resting tachycardia
  • Ischemic symptoms if atherosclerosis co-exists (angina, TIA/stroke)
  • Symptoms related to underlying deficiency:
    • Pica in iron deficiency
    • Peripheral neuropathy in B12 deficiency
  • Important caveat: Signs and symptoms are very unreliable in predicting the actual hematocrit level. Patients who develop anemia gradually can tolerate surprisingly low hemoglobin levels due to compensatory mechanisms.

3. Compensatory Mechanisms

Harrison's describes three physiologic compensations (in order of onset):
MechanismTime to ActivationEffect
Increased cardiac outputMinutesMaintains O2 delivery
Increased 2,3-DPGHours to daysShifts O2-Hgb dissociation curve right; more O2 unloading to tissues
Increased plasma volumeWeeksPreserves cardiac output; can cause heart failure if excessive

4. Classification of Anemia (Two Approaches)

Approach 1: By Red Cell Size (MCV-based - Wintrobe's classification)

Microcytic (low MCV)
  • Thalassemia (defect in Hgb protein synthesis)
  • Iron deficiency (inability to make heme)
  • Anemia of chronic disease/inflammation (impaired iron reutilization; can also be normocytic)
  • Sideroblastic anemia (defect in heme synthesis)
Macrocytic (high MCV)
  • Oval macrocytes - defect in DNA synthesis:
    • Vitamin B12 deficiency
    • Folate deficiency
    • Medications (chemotherapy, some antiseizure drugs)
    • Myelodysplasia
  • Round macrocytes - membrane defects:
    • Alcohol use, liver disease
    • Hypothyroidism
    • Dysproteinemia, hypoxia, smoking, reticulocytosis
Normocytic (normal MCV)
  • Aplastic anemia
  • Endocrinopathies
  • Marrow invasion, myeloma
  • Pure red cell aplasia
  • Renal disease

Approach 2: By Mechanism (Reticulocyte-based)

The absolute reticulocyte count is the first indicator of mechanism:
High reticulocytes = Hyperproduction (Increased Loss/Destruction)
  • Bleeding
  • Hemolysis:
    • Acquired: Autoimmune, mechanical
    • Congenital: Hemoglobinopathies (sickle cell), enzyme defects (G6PD), membrane defects
Low/Inappropriately Normal Reticulocytes = Underproduction (at least 75% of all anemia)
  • Nutritional deficiency: Iron, B12, folate, copper, Vitamin C
  • Absence of red cell precursors: Aplastic anemia, pure red cell aplasia
  • Stem cell defects: Myelodysplasia, leukemia
  • Lack of EPO: Renal disease, anemia of inflammation, anemia of aging
  • Marrow replacement: Neoplasm, granulomatous disease, infection

5. Laboratory Testing

Initial Tests (CBC with indices)

IndexFormulaNormalInterpretation
MCVHct/RBC × 1085-95 fLRed cell size
MCHHgb/RBC count28-33 pgHgb per cell
MCHCHgb/Hct × 10033.8-34.2 g/dLLimited value; changes little
RDWSD of RBC size/MCV × 10011-14%Anisocytosis; high in iron deficiency

Peripheral Blood Smear - Mandatory in:

  1. Hypochromic, microcytic anemia unresponsive to iron
  2. Presence of hypersegmented neutrophils
  3. Abnormal red cell morphology on automated count
  4. Circulating nucleated RBCs
  5. Evidence of marrow infiltration (teardrop cells, nucleated RBCs)
  6. Staging of certain malignancies (e.g., lymphoma)
  7. Unexplained severe anemia

Bone Marrow Examination - Indications:

  • Diagnosis of leukemia and myelodysplasia (augmented with molecular testing)

6. Systematic Evaluation Algorithm (Fig. 66-17)

Harrison's recommends a stepwise approach guided by the CBC and reticulocyte count:
CBC + Reticulocyte Count
         |
         ├── HIGH reticulocyte count
         │       |
         │       ├── Rule out BLEEDING first
         │       └── If bleeding excluded → HEMOLYSIS workup:
         │               - LDH (elevated)
         │               - Haptoglobin (low)
         │               - Direct Coombs (DAT) test
         │               - Peripheral smear (schistocytes, spherocytes, sickle cells)
         │
         └── LOW/Normal reticulocyte count → CHECK MCV
                 |
                 ├── LOW MCV (Microcytic)
                 │       |
                 │       ├── Ferritin LOW → Iron deficiency
                 │       ├── Ferritin NORMAL → Thalassemia workup
                 │       │       - RDW: HIGH = iron deficiency, LOW = thalassemia
                 │       └── Anemia of inflammation (diagnosis of exclusion;
                 │               requires active inflammatory process)
                 |
                 ├── HIGH MCV (Macrocytic)
                 │       |
                 │       ├── Peripheral smear:
                 │       │       - Hypersegmented neutrophils + macro-ovalocytes
                 │       │           → B12 and folate levels
                 │       │       - Macro-ovalocytes + normal B12/folate
                 │       │           → Bone marrow (myelodysplasia)
                 │       └── Round macrocytes → History (alcohol, liver disease)
                 │
                 └── NORMAL MCV (Normocytic)
                         |
                         ├── Renal function (BUN/Cr) → Renal anemia
                         ├── EPO levels
                         ├── Other systemic disease evaluation
                         └── Bone marrow exam if no cause found

7. Specific Diagnostic Clues

Iron Deficiency vs. Thalassemia (both microcytic)

  • RDW high (anisocytosis) + low ferritin → Iron deficiency
  • RDW low (homogeneous cells) + normal ferritin → Thalassemia trait
  • Mentzer Index (MCV/RBC): >13 = iron deficiency; <13 = thalassemia

Hemolysis Markers

  • LDH: elevated (released from lysed RBCs)
  • Haptoglobin: low (consumed binding free Hgb)
  • Free hemoglobin in blood/urine
  • Peripheral smear: schistocytes (TMA/microangiopathy), spherocytes (autoimmune/hereditary spherocytosis)

Macrocytic Anemia - Key Smear Finding

  • Hypersegmented neutrophils (>5 lobes) + macro-ovalocytes = megaloblastic anemia → Check B12 and folate

8. Treatment Principles

  • Definitive treatment requires identifying the cause
  • Transfusion is indicated for: hypotension, signs of cardiac compromise (angina)
  • Anemia is often multifactorial (e.g., rheumatoid arthritis patient on NSAIDs may have both anemia of inflammation AND iron deficiency from GI bleeding)
  • Always evaluate iron status before and during treatment of any anemia
  • Modern therapies include: recombinant EPO, TGF-beta inhibitors (myelodysplasia), complement inhibitors (PNH), gene therapy (hemoglobinopathies)

Source: Harrison's Principles of Internal Medicine, 22nd Edition (2025, McGraw-Hill), Chapter 66 - "Anemia and Polycythemia"

Create a quick reference PDF summarizing the anemia workup algorithm

Reading File
Running Command

mkdir -p /home/daytona/workspace/anemia-pdf && ls /home/daytona/workspace/

Writing File

~/anemia-pdf/generate_anemia_pdf.py

from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm, cm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    HRFlowable, KeepTogether
)
from reportlab.platypus.flowables import Flowable
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT
from reportlab.pdfgen import canvas
import os

OUTPUT = "/home/daytona/workspace/anemia-pdf/Anemia_Workup_Quick_Reference.pdf"

# ── Colour palette ────────────────────────────────────────────────────────────
C_DARK_BLUE   = colors.HexColor("#1B3A6B")
C_MID_BLUE    = colors.HexColor("#2563A8")
C_LIGHT_BLUE  = colors.HexColor("#DBEAFE")
C_ACCENT_RED  = colors.HexColor("#B91C1C")
C_ACCENT_TEAL = colors.HexColor("#0F766E")
C_ACCENT_AMB  = colors.HexColor("#92400E")
C_GREEN       = colors.HexColor("#166534")
C_GREEN_LIGHT = colors.HexColor("#DCFCE7")
C_ORANGE_LIGHT= colors.HexColor("#FFF7ED")
C_ORANGE      = colors.HexColor("#C2410C")
C_GRAY_LIGHT  = colors.HexColor("#F1F5F9")
C_GRAY_MED    = colors.HexColor("#CBD5E1")
C_WHITE       = colors.white
C_BLACK       = colors.HexColor("#1E293B")

# ── Page setup ────────────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
    OUTPUT,
    pagesize=A4,
    rightMargin=15*mm, leftMargin=15*mm,
    topMargin=18*mm, bottomMargin=18*mm,
    title="Anemia Workup Quick Reference",
    author="Harrison's 22E – Orris Medical Reference"
)
W, H = A4
content_w = W - 30*mm

styles = getSampleStyleSheet()

# ── Custom paragraph styles ───────────────────────────────────────────────────
def S(name, **kw):
    base = kw.pop("parent", "Normal")
    s = ParagraphStyle(name, parent=styles[base], **kw)
    return s

sTitle    = S("sTitle",    fontSize=20, textColor=C_WHITE,    leading=26,
               alignment=TA_CENTER, fontName="Helvetica-Bold")
sSubtitle = S("sSubtitle", fontSize=9,  textColor=C_LIGHT_BLUE, leading=13,
               alignment=TA_CENTER, fontName="Helvetica")
sSecHdr   = S("sSecHdr",   fontSize=11, textColor=C_WHITE,    leading=15,
               fontName="Helvetica-Bold", leftIndent=4)
sBody     = S("sBody",     fontSize=8.5,textColor=C_BLACK,    leading=12,
               fontName="Helvetica")
sBold     = S("sBold",     fontSize=8.5,textColor=C_BLACK,    leading=12,
               fontName="Helvetica-Bold")
sBullet   = S("sBullet",   fontSize=8,  textColor=C_BLACK,    leading=11,
               fontName="Helvetica", leftIndent=8, bulletIndent=0)
sLabel    = S("sLabel",    fontSize=8,  textColor=C_WHITE,    leading=11,
               fontName="Helvetica-Bold", alignment=TA_CENTER)
sFooter   = S("sFooter",   fontSize=7,  textColor=colors.HexColor("#64748B"),
               leading=9, alignment=TA_CENTER, fontName="Helvetica-Oblique")
sCellHdr  = S("sCellHdr",  fontSize=8,  textColor=C_WHITE, leading=11,
               fontName="Helvetica-Bold", alignment=TA_CENTER)
sCellBody = S("sCellBody", fontSize=7.5,textColor=C_BLACK, leading=10,
               fontName="Helvetica")
sCellBold = S("sCellBold", fontSize=7.5,textColor=C_BLACK, leading=10,
               fontName="Helvetica-Bold")

# ── Helper: coloured section header ──────────────────────────────────────────
def sec_header(text, bg=C_DARK_BLUE):
    tbl = Table([[Paragraph(text, sSecHdr)]], colWidths=[content_w])
    tbl.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), bg),
        ("ROWPADDING", (0,0), (-1,-1), 5),
        ("TOPPADDING",  (0,0), (-1,-1), 5),
        ("BOTTOMPADDING",(0,0),(-1,-1), 4),
        ("ROUNDEDCORNERS", [4]),
    ]))
    return tbl

# ── Helper: two-column layout ─────────────────────────────────────────────────
def two_col(left_content, right_content, ratio=(1,1)):
    total = sum(ratio)
    cw = [content_w * r / total for r in ratio]
    tbl = Table([[left_content, right_content]], colWidths=cw)
    tbl.setStyle(TableStyle([
        ("VALIGN", (0,0), (-1,-1), "TOP"),
        ("LEFTPADDING",  (0,0), (-1,-1), 0),
        ("RIGHTPADDING", (0,0), (-1,-1), 0),
        ("TOPPADDING",   (0,0), (-1,-1), 0),
        ("BOTTOMPADDING",(0,0), (-1,-1), 0),
    ]))
    return tbl

# ── Helper: simple info card ──────────────────────────────────────────────────
def card(rows, col_widths, hdr_bg=C_MID_BLUE, alt_bg=C_GRAY_LIGHT):
    tbl_data = []
    for i, row in enumerate(rows):
        tbl_data.append([Paragraph(str(c), sCellHdr if i == 0 else sCellBody) for c in row])
    tbl = Table(tbl_data, colWidths=col_widths)
    ts = [
        ("BACKGROUND",    (0,0), (-1,0),  hdr_bg),
        ("ROWPADDING",    (0,0), (-1,-1), 4),
        ("TOPPADDING",    (0,0), (-1,-1), 3),
        ("BOTTOMPADDING", (0,0), (-1,-1), 3),
        ("GRID",          (0,0), (-1,-1), 0.4, C_GRAY_MED),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ]
    for i in range(1, len(rows)):
        if i % 2 == 0:
            ts.append(("BACKGROUND", (0,i), (-1,i), alt_bg))
    tbl.setStyle(TableStyle(ts))
    return tbl

# ── Arrow flowable (for algorithm) ───────────────────────────────────────────
class ArrowDown(Flowable):
    def __init__(self, w=20, h=12):
        Flowable.__init__(self)
        self.width = w
        self.height = h
    def draw(self):
        c = self.canv
        c.setFillColor(C_MID_BLUE)
        c.setStrokeColor(C_MID_BLUE)
        mid = self.width / 2
        c.beginPath()
        c.moveTo(mid-5, self.height)
        c.lineTo(mid+5, self.height)
        c.lineTo(mid+5, 4)
        c.lineTo(mid+10, 4)
        c.lineTo(mid, 0)
        c.lineTo(mid-10, 4)
        c.lineTo(mid-5, 4)
        c.lineTo(mid-5, self.height)
        c.closePath()
        c.drawPath(fill=1, stroke=0)

# ── Algorithm box helper ──────────────────────────────────────────────────────
def algo_box(text, bg, fg=C_WHITE, w=None, font="Helvetica-Bold", fsize=8.5):
    w = w or content_w
    sty = ParagraphStyle("ab", fontSize=fsize, textColor=fg, leading=12,
                          fontName=font, alignment=TA_CENTER)
    tbl = Table([[Paragraph(text, sty)]], colWidths=[w])
    tbl.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,-1), bg),
        ("ROWPADDING",    (0,0), (-1,-1), 6),
        ("TOPPADDING",    (0,0), (-1,-1), 6),
        ("BOTTOMPADDING", (0,0), (-1,-1), 6),
        ("BOX",           (0,0), (-1,-1), 0.8, bg),
        ("ROUNDEDCORNERS",[4]),
    ]))
    return tbl

# ─────────────────────────────────────────────────────────────────────────────
# PAGE HEADER CANVAS
# ─────────────────────────────────────────────────────────────────────────────
def header_footer(canv, doc):
    canv.saveState()
    # top banner
    canv.setFillColor(C_DARK_BLUE)
    canv.rect(0, H - 28*mm, W, 28*mm, fill=1, stroke=0)
    # title
    canv.setFillColor(C_WHITE)
    canv.setFont("Helvetica-Bold", 16)
    canv.drawCentredString(W/2, H - 15*mm, "ANEMIA WORKUP  –  QUICK REFERENCE")
    canv.setFont("Helvetica", 8)
    canv.setFillColor(colors.HexColor("#93C5FD"))
    canv.drawCentredString(W/2, H - 22*mm,
        "Based on Harrison's Principles of Internal Medicine, 22nd Edition (2025)")
    # footer
    canv.setFillColor(colors.HexColor("#64748B"))
    canv.setFont("Helvetica-Oblique", 6.5)
    canv.drawCentredString(W/2, 10*mm,
        "For educational use only  |  Always apply clinical judgment  |  Orris Medical Reference")
    canv.drawRightString(W - 15*mm, 10*mm, f"Page {doc.page}")
    canv.restoreState()

# ─────────────────────────────────────────────────────────────────────────────
# BUILD STORY
# ─────────────────────────────────────────────────────────────────────────────
story = []
SP = lambda n=4: Spacer(1, n*mm)

story.append(SP(2))  # space below banner

# ══════════════════════════════════════════════════════════════════════════════
# SECTION 1 – DEFINITION & INITIAL LABS
# ══════════════════════════════════════════════════════════════════════════════
story.append(sec_header("1.  DEFINITION  &  INITIAL LABORATORY TESTS"))
story.append(SP(2))

def_data = [
    [Paragraph("<b>Definition</b>", sCellHdr),
     Paragraph("Hemoglobin/hematocrit below normal for age/sex. Most often detected on routine CBC.", sCellBody)],
    [Paragraph("<b>First-line tests</b>", sCellHdr),
     Paragraph("CBC with red cell indices (MCV, MCH, MCHC, RDW)  +  Reticulocyte count  +  Peripheral blood smear", sCellBody)],
]
def_tbl = Table(def_data, colWidths=[32*mm, content_w - 32*mm])
def_tbl.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (0,-1), C_MID_BLUE),
    ("BACKGROUND",    (1,0), (1,-1), C_GRAY_LIGHT),
    ("GRID",          (0,0), (-1,-1), 0.4, C_GRAY_MED),
    ("TOPPADDING",    (0,0), (-1,-1), 4),
    ("BOTTOMPADDING", (0,0), (-1,-1), 4),
    ("LEFTPADDING",   (0,0), (-1,-1), 5),
    ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
]))
story.append(def_tbl)
story.append(SP(3))

# Red Cell Indices table
indices_data = [
    ["Index", "Formula", "Normal", "Key Use"],
    ["MCV",   "Hct ÷ RBC × 10", "85–95 fL", "Size classification (micro/normo/macro)"],
    ["MCH",   "Hgb ÷ RBC",      "28–33 pg",  "Hgb per cell"],
    ["MCHC",  "Hgb ÷ Hct × 100","33.8–34.2 g/dL","Low only in severe iron def. / HS"],
    ["RDW",   "SD of MCV/MCV × 100","11–14%","High = anisocytosis (iron def.);\nLow = thalassemia (uniform cells)"],
]
cw_idx = [22*mm, 42*mm, 38*mm, content_w - 102*mm]
story.append(card(indices_data, cw_idx))
story.append(SP(4))

# ══════════════════════════════════════════════════════════════════════════════
# SECTION 2 – CLASSIFICATION
# ══════════════════════════════════════════════════════════════════════════════
story.append(sec_header("2.  CLASSIFICATION  (Two Parallel Frameworks)", bg=C_ACCENT_TEAL))
story.append(SP(2))

# --- By MCV ---
mcv_title_tbl = Table(
    [[Paragraph("BY RED CELL SIZE  (MCV)", sLabel)]],
    colWidths=[(content_w/2) - 3*mm]
)
mcv_title_tbl.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,-1), C_MID_BLUE),
    ("TOPPADDING", (0,0), (-1,-1), 4),
    ("BOTTOMPADDING", (0,0), (-1,-1), 4),
]))

mcv_data = [
    [Paragraph("<b>Microcytic</b>\n<font color='#64748B'>(MCV &lt;85 fL)</font>", sCellBold),
     Paragraph("Iron deficiency\nThalassemia (alpha/beta)\nAnemia of inflammation (often normocytic)\nSideroblastic anemia", sCellBody)],
    [Paragraph("<b>Normocytic</b>\n<font color='#64748B'>(MCV 85–95 fL)</font>", sCellBold),
     Paragraph("Aplastic anemia  |  Renal disease\nEndocrinopathy  |  Myeloma\nPure red cell aplasia  |  Early iron/B12 def.", sCellBody)],
    [Paragraph("<b>Macrocytic</b>\n<font color='#64748B'>(MCV &gt;95 fL)</font>", sCellBold),
     Paragraph("<b>Oval macrocytes:</b> B12/folate def., drugs, MDS\n<b>Round macrocytes:</b> Alcohol, liver disease,\nhypothyroidism, reticulocytosis", sCellBody)],
]
half_w = (content_w / 2) - 3*mm
mcv_tbl = Table(mcv_data, colWidths=[28*mm, half_w - 28*mm])
mcv_tbl.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (0,-1), colors.HexColor("#EFF6FF")),
    ("GRID",          (0,0), (-1,-1), 0.4, C_GRAY_MED),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 4),
    ("VALIGN",        (0,0), (-1,-1), "TOP"),
]))

mcv_block = Table(
    [[mcv_title_tbl], [mcv_tbl]],
    colWidths=[half_w]
)
mcv_block.setStyle(TableStyle([
    ("LEFTPADDING",  (0,0), (-1,-1), 0),
    ("RIGHTPADDING", (0,0), (-1,-1), 0),
    ("TOPPADDING",   (0,0), (-1,-1), 0),
    ("BOTTOMPADDING",(0,0), (-1,-1), 0),
]))

# --- By Mechanism ---
mech_title_tbl = Table(
    [[Paragraph("BY MECHANISM  (Reticulocyte Count)", sLabel)]],
    colWidths=[(content_w/2) - 3*mm]
)
mech_title_tbl.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,-1), C_ACCENT_TEAL),
    ("TOPPADDING", (0,0), (-1,-1), 4),
    ("BOTTOMPADDING", (0,0), (-1,-1), 4),
]))

mech_data = [
    [Paragraph("<b>HIGH Retic.</b>\n<font color='#64748B'>(Hyperproduction)</font>", sCellBold),
     Paragraph("Acute bleeding (rule out first!)\n<b>Hemolysis:</b>\n  Acquired: Autoimmune, microangiopathic\n  Congenital: Hgbopathies, G6PD, HS", sCellBody)],
    [Paragraph("<b>LOW Retic.</b>\n<font color='#64748B'>(Underproduction\n~75% of all anemia)</font>", sCellBold),
     Paragraph("Nutritional: Iron, B12, folate, copper\nNo precursors: Aplastic anemia, PRCA\nStem cell defect: MDS, leukemia\nLow EPO: CKD, inflammation, aging\nMarrow replacement: Cancer, granuloma", sCellBody)],
]
mech_tbl = Table(mech_data, colWidths=[30*mm, half_w - 30*mm])
mech_tbl.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (0,-1), colors.HexColor("#F0FDF4")),
    ("GRID",          (0,0), (-1,-1), 0.4, C_GRAY_MED),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 4),
    ("VALIGN",        (0,0), (-1,-1), "TOP"),
]))

mech_block = Table(
    [[mech_title_tbl], [mech_tbl]],
    colWidths=[half_w]
)
mech_block.setStyle(TableStyle([
    ("LEFTPADDING",  (0,0), (-1,-1), 0),
    ("RIGHTPADDING", (0,0), (-1,-1), 0),
    ("TOPPADDING",   (0,0), (-1,-1), 0),
    ("BOTTOMPADDING",(0,0), (-1,-1), 0),
]))

class_row = Table(
    [[mcv_block, Spacer(6*mm, 1), mech_block]],
    colWidths=[half_w, 6*mm, half_w]
)
class_row.setStyle(TableStyle([
    ("VALIGN",        (0,0), (-1,-1), "TOP"),
    ("LEFTPADDING",   (0,0), (-1,-1), 0),
    ("RIGHTPADDING",  (0,0), (-1,-1), 0),
    ("TOPPADDING",    (0,0), (-1,-1), 0),
    ("BOTTOMPADDING", (0,0), (-1,-1), 0),
]))
story.append(class_row)
story.append(SP(4))

# ══════════════════════════════════════════════════════════════════════════════
# SECTION 3 – DIAGNOSTIC ALGORITHM
# ══════════════════════════════════════════════════════════════════════════════
story.append(sec_header("3.  STEPWISE DIAGNOSTIC ALGORITHM  (Harrison's Fig. 66-17)", bg=C_ACCENT_RED))
story.append(SP(3))

# Step 1
story.append(algo_box("STEP 1:  Obtain CBC + Reticulocyte Count  +  Peripheral Smear",
                       bg=C_DARK_BLUE, w=content_w))
story.append(SP(2))
story.append(ArrowDown(w=content_w))
story.append(SP(1))

# Branch header
branch_hdr = Table(
    [[Paragraph("RETICULOCYTE COUNT HIGH?", sLabel),
      Paragraph("RETICULOCYTE COUNT LOW / NORMAL?", sLabel)]],
    colWidths=[content_w/2 - 3*mm, content_w/2 - 3*mm],
    spaceBefore=0
)
branch_hdr.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (0,0), C_ACCENT_RED),
    ("BACKGROUND", (1,0), (1,0), C_MID_BLUE),
    ("TOPPADDING",    (0,0), (-1,-1), 5),
    ("BOTTOMPADDING", (0,0), (-1,-1), 5),
    ("COLPADDING",    (0,0), (-1,-1), 4),
    ("LEFTPADDING",   (0,0), (-1,-1), 6),
]))
story.append(branch_hdr)

# Branch content
left_branch_data = [
    [Paragraph("<b>1. Rule out acute bleeding first</b>", sCellBold)],
    [Paragraph("If bleeding excluded → Hemolysis workup:", sCellBody)],
    [Paragraph("• LDH <font color='#B91C1C'>(elevated)</font>", sCellBody)],
    [Paragraph("• Haptoglobin <font color='#B91C1C'>(low)</font>", sCellBody)],
    [Paragraph("• Direct Antiglobulin Test (DAT/Coombs)", sCellBody)],
    [Paragraph("• Peripheral smear for schistocytes, spherocytes, sickle cells", sCellBody)],
    [Paragraph("• Urine for free Hgb/hemosiderinuria", sCellBody)],
]
left_branch = Table(left_branch_data, colWidths=[content_w/2 - 3*mm])
left_branch.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,-1), colors.HexColor("#FEF2F2")),
    ("TOPPADDING",    (0,0), (-1,-1), 2),
    ("BOTTOMPADDING", (0,0), (-1,-1), 2),
    ("LEFTPADDING",   (0,0), (-1,-1), 6),
    ("GRID",          (0,0), (-1,-1), 0.3, colors.HexColor("#FECACA")),
]))

right_branch_data = [
    [Paragraph("<b>Proceed to MCV-guided workup:</b>", sCellBold)],
    [Paragraph("<font color='#1B3A6B'><b>MCV LOW</b></font>  → Check Ferritin:", sCellBody)],
    [Paragraph("  • Ferritin low → Iron deficiency anemia", sCellBody)],
    [Paragraph("  • Ferritin normal → Thalassemia screen (Hgb electrophoresis, RDW)", sCellBody)],
    [Paragraph("  • Exclusion diagnosis → Anemia of inflammation", sCellBody)],
    [Paragraph("<font color='#0F766E'><b>MCV HIGH</b></font>  → Peripheral smear:", sCellBody)],
    [Paragraph("  • Hyperseg. PMNs + macro-ovalocytes → B12 & folate levels", sCellBody)],
    [Paragraph("  • Oval macrocytes + normal B12/folate → Bone marrow (MDS)", sCellBody)],
    [Paragraph("  • Round macrocytes → History: alcohol, liver, hypothyroid", sCellBody)],
    [Paragraph("<font color='#92400E'><b>MCV NORMAL</b></font>  → Assess:", sCellBody)],
    [Paragraph("  • Renal function + EPO level", sCellBody)],
    [Paragraph("  • Systemic disease screen", sCellBody)],
    [Paragraph("  • Bone marrow if no cause found", sCellBody)],
]
right_branch = Table(right_branch_data, colWidths=[content_w/2 - 3*mm])
right_branch.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,-1), C_LIGHT_BLUE),
    ("TOPPADDING",    (0,0), (-1,-1), 2),
    ("BOTTOMPADDING", (0,0), (-1,-1), 2),
    ("LEFTPADDING",   (0,0), (-1,-1), 6),
    ("GRID",          (0,0), (-1,-1), 0.3, C_GRAY_MED),
]))

branch_content = Table(
    [[left_branch, Spacer(6*mm, 1), right_branch]],
    colWidths=[content_w/2 - 3*mm, 6*mm, content_w/2 - 3*mm]
)
branch_content.setStyle(TableStyle([
    ("VALIGN",        (0,0), (-1,-1), "TOP"),
    ("LEFTPADDING",   (0,0), (-1,-1), 0),
    ("RIGHTPADDING",  (0,0), (-1,-1), 0),
    ("TOPPADDING",    (0,0), (-1,-1), 0),
    ("BOTTOMPADDING", (0,0), (-1,-1), 0),
]))
story.append(branch_content)
story.append(SP(4))

# ══════════════════════════════════════════════════════════════════════════════
# SECTION 4 – KEY DIFFERENTIALS
# ══════════════════════════════════════════════════════════════════════════════
story.append(sec_header("4.  KEY DIFFERENTIALS  &  CONFIRMATORY TESTS", bg=C_ACCENT_AMB))
story.append(SP(2))

diff_data = [
    ["Diagnosis", "Key Lab Findings", "Confirmatory Test"],
    ["Iron Deficiency",
     "Low ferritin, low Fe, high TIBC, high RDW, microcytic hypochromic",
     "Ferritin <30 ng/mL (or <100 if inflammation);\nresponse to iron trial"],
    ["Thalassemia Trait",
     "Low MCV, LOW RDW (uniform cells), normal/high RBC count,\nMentzer index <13",
     "Hgb electrophoresis (↑HbA2 in beta-thal);\nDNA testing"],
    ["Anemia of Inflammation",
     "Low-normal MCV, low serum iron, low TIBC,\nnormal/high ferritin",
     "Diagnosis of exclusion; underlying inflammatory disease"],
    ["B12 / Folate Deficiency",
     "High MCV, macro-ovalocytes, hypersegmented PMNs,\nhigh MMA (B12 def.)",
     "Serum B12 <200 pg/mL; RBC folate;\nserum MMA & homocysteine"],
    ["Autoimmune Hemolysis",
     "High retic., spherocytes, high LDH, low haptoglobin,\n+ DAT (Coombs)",
     "Direct/indirect Coombs; flow cytometry"],
    ["Aplastic Anemia",
     "Pancytopenia, low retic., normal/macrocytic MCV,\nhypocellular smear",
     "Bone marrow biopsy (hypocellular)"],
    ["CKD Anemia",
     "Normocytic, low retic., inappropriately low EPO",
     "eGFR + EPO level"],
    ["MDS",
     "Macro-ovalocytes, dysplastic cells, cytopenias,\nnormal B12/folate",
     "Bone marrow biopsy + cytogenetics + molecular panel"],
]
diff_cw = [35*mm, 68*mm, content_w - 103*mm]
diff_tbl = Table(
    [[Paragraph(c if i == 0 else str(c), sCellHdr if i == 0 else (sCellBold if j==0 else sCellBody))
      for j, c in enumerate(row)]
     for i, row in enumerate(diff_data)],
    colWidths=diff_cw
)
ts_diff = [
    ("BACKGROUND",    (0,0), (-1,0),  C_ACCENT_AMB),
    ("GRID",          (0,0), (-1,-1), 0.4, C_GRAY_MED),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 4),
    ("VALIGN",        (0,0), (-1,-1), "TOP"),
]
for i in range(2, len(diff_data), 2):
    ts_diff.append(("BACKGROUND", (0,i), (-1,i), C_GRAY_LIGHT))
diff_tbl.setStyle(TableStyle(ts_diff))
story.append(diff_tbl)
story.append(SP(4))

# ══════════════════════════════════════════════════════════════════════════════
# SECTION 5 – COMPENSATORY MECHANISMS & SMEAR INDICATIONS
# ══════════════════════════════════════════════════════════════════════════════
story.append(sec_header("5.  COMPENSATION  &  PERIPHERAL SMEAR INDICATIONS", bg=C_GREEN))
story.append(SP(2))

comp_data = [
    ["Mechanism", "Onset", "Effect"],
    ["Increased cardiac output", "Minutes",    "Maintains O₂ delivery; limited by cardiac reserve"],
    ["Increased 2,3-DPG",        "Hours–days", "Shifts O₂-Hgb curve right → more O₂ released to tissues"],
    ["Expanded plasma volume",   "Weeks",      "Preserves preload; risk of heart failure if excessive"],
]
comp_cw = [52*mm, 28*mm, content_w - 80*mm]
comp_tbl = card(comp_data, comp_cw, hdr_bg=C_GREEN, alt_bg=C_GREEN_LIGHT)

smear_items = [
    "Hypochromic microcytic anemia unresponsive to iron",
    "Hypersegmented neutrophils on differential",
    "Abnormal RBC morphology flagged by counter",
    "Circulating nucleated RBCs",
    "Teardrop cells / leukoerythroblastic picture (marrow infiltration)",
    "Staging of lymphoma / haematological malignancy",
    "Unexplained severe or refractory anemia",
]
smear_data = [[Paragraph("PERIPHERAL SMEAR – When to Order", sLabel)]]
smear_tbl_hdr = Table(smear_data, colWidths=[(content_w/2) - 3*mm])
smear_tbl_hdr.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,-1), C_GREEN),
    ("TOPPADDING", (0,0), (-1,-1), 4),
    ("BOTTOMPADDING", (0,0), (-1,-1), 4),
]))

smear_rows = [[Paragraph(f"{'✓'} {item}", sCellBody)] for item in smear_items]
smear_body = Table(smear_rows, colWidths=[(content_w/2) - 3*mm])
smear_body.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,-1), C_GREEN_LIGHT),
    ("GRID",       (0,0), (-1,-1), 0.3, C_GRAY_MED),
    ("TOPPADDING", (0,0), (-1,-1), 2),
    ("BOTTOMPADDING",(0,0), (-1,-1), 2),
    ("LEFTPADDING", (0,0), (-1,-1), 6),
]))
smear_block = Table([[smear_tbl_hdr], [smear_body]], colWidths=[(content_w/2) - 3*mm])
smear_block.setStyle(TableStyle([
    ("LEFTPADDING",  (0,0), (-1,-1), 0),
    ("RIGHTPADDING", (0,0), (-1,-1), 0),
    ("TOPPADDING",   (0,0), (-1,-1), 0),
    ("BOTTOMPADDING",(0,0), (-1,-1), 0),
]))

comp_half = (content_w/2) - 3*mm
comp_block = Table([[comp_tbl]], colWidths=[comp_half])
comp_block.setStyle(TableStyle([
    ("LEFTPADDING",  (0,0), (-1,-1), 0),
    ("RIGHTPADDING", (0,0), (-1,-1), 0),
    ("TOPPADDING",   (0,0), (-1,-1), 0),
    ("BOTTOMPADDING",(0,0), (-1,-1), 0),
]))

sec5_row = Table(
    [[comp_block, Spacer(6*mm, 1), smear_block]],
    colWidths=[comp_half, 6*mm, comp_half]
)
sec5_row.setStyle(TableStyle([
    ("VALIGN",       (0,0), (-1,-1), "TOP"),
    ("LEFTPADDING",  (0,0), (-1,-1), 0),
    ("RIGHTPADDING", (0,0), (-1,-1), 0),
    ("TOPPADDING",   (0,0), (-1,-1), 0),
    ("BOTTOMPADDING",(0,0), (-1,-1), 0),
]))
story.append(sec5_row)
story.append(SP(4))

# ══════════════════════════════════════════════════════════════════════════════
# SECTION 6 – TREATMENT PRINCIPLES
# ══════════════════════════════════════════════════════════════════════════════
story.append(sec_header("6.  TREATMENT PRINCIPLES", bg=C_MID_BLUE))
story.append(SP(2))

tx_data = [
    ["Principle", "Detail"],
    ["Treat the cause",
     "Definitive treatment always requires identifying and correcting the underlying aetiology."],
    ["Transfusion – clear indications",
     "Haemodynamic instability (hypotension) or evidence of cardiac compromise (angina, ACS). NOT based on Hgb number alone."],
    ["Iron stores first",
     "Evaluate iron status BEFORE and DURING treatment of any anemia – even non-iron deficiency cases."],
    ["Multifactorial causes",
     "Anemia is often mixed (e.g., RA on NSAIDs may have ACI + GI-blood-loss IDA simultaneously)."],
    ["Targeted therapies",
     "• Recombinant EPO: CKD on dialysis, chemotherapy-related anemia\n"
     "• TGF-β inhibitors (luspatercept): MDS-related anemia\n"
     "• Complement inhibitors (eculizumab): PNH\n"
     "• Gene therapy: emerging for haemoglobinopathies"],
]
tx_cw = [40*mm, content_w - 40*mm]
tx_tbl = Table(
    [[Paragraph(row[0], sCellHdr if i==0 else sCellBold),
      Paragraph(row[1], sCellHdr if i==0 else sCellBody)] for i, row in enumerate(tx_data)],
    colWidths=tx_cw
)
ts_tx = [
    ("BACKGROUND",    (0,0), (-1,0),  C_MID_BLUE),
    ("GRID",          (0,0), (-1,-1), 0.4, C_GRAY_MED),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 5),
    ("VALIGN",        (0,0), (-1,-1), "TOP"),
]
for i in range(2, len(tx_data), 2):
    ts_tx.append(("BACKGROUND", (0,i), (-1,i), C_GRAY_LIGHT))
tx_tbl.setStyle(TableStyle(ts_tx))
story.append(tx_tbl)
story.append(SP(3))

# ── Final note ─────────────────────────────────────────────────────────────
story.append(HRFlowable(width=content_w, thickness=0.5, color=C_GRAY_MED))
story.append(SP(2))
story.append(Paragraph(
    "<b>Reference:</b> Harrison's Principles of Internal Medicine, 22nd Edition (McGraw-Hill, 2025), "
    "Chapter 66 – <i>Anemia and Polycythemia</i>. "
    "See Chaps. 102–107 for disease-specific management.",
    sFooter
))

# ── BUILD PDF ─────────────────────────────────────────────────────────────────
doc.build(story, onFirstPage=header_footer, onLaterPages=header_footer)
print(f"PDF created: {OUTPUT}")
Running Command

cd /home/daytona/workspace/anemia-pdf && python generate_anemia_pdf.py 2>&1

Editing File

~/anemia-pdf/generate_anemia_pdf.py

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/anemia-pdf/generate_anemia_pdf.py'
Running Command

cd /home/daytona/workspace/anemia-pdf && python generate_anemia_pdf.py 2>&1

Running Command

ls -lh /home/daytona/workspace/anemia-pdf/Anemia_Workup_Quick_Reference.pdf

Running Command

python3 -c " from pypdf import PdfReader r = PdfReader('/home/daytona/workspace/…

Your PDF is ready:

Anemia Workup Quick Reference

PDF Document · PDF


What's inside (2 pages, A4):
SectionContent
1. Definition & Initial LabsCBC indices table (MCV, MCH, MCHC, RDW) with formulas and normal ranges
2. ClassificationSide-by-side: MCV-based (micro/normo/macro) vs. Mechanism-based (high/low reticulocyte)
3. Stepwise AlgorithmVisual flow - CBC → reticulocyte split → MCV-guided branches (iron def., thalassemia, B12/folate, MDS, CKD, etc.)
4. Key Differentials8-row table: each diagnosis with key lab findings + confirmatory test
5. Compensation & Smear3 compensatory mechanisms with timing; peripheral smear indications checklist
6. Treatment PrinciplesTransfusion triggers, iron status rule, targeted biologics (EPO, luspatercept, eculizumab)
All content is sourced directly from Harrison's Principles of Internal Medicine, 22nd Edition (2025), Chapter 66.
This is a shared conversation. Sign in to Orris to start your own chat.