What is the differential diagnosis for using the different parameters of CBC

Reading File
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Reading File
Reading File
Finding Sources
Reading File
Finding Sources
Finding Sources
Reading File
Reading File
Reading File
I now have comprehensive, well-sourced content from the textbooks to compile a thorough answer. Let me synthesize all findings.

Differential Diagnosis by CBC Parameters

The CBC measures RBCs, WBCs, and platelets — each parameter pointing to a different set of diagnoses. Below is a systematic breakdown.

1. Red Blood Cell (RBC) Parameters

A. Hemoglobin / Hematocrit — Anemia

The first step in evaluating anemia is to classify it by MCV (mean corpuscular volume):

B. MCV — Morphologic Classification of Anemia

MCV CategoryCutoffDifferential Diagnosis
Microcytic (↓ MCV)< 80 fLIron deficiency anemia, Thalassemia, Sideroblastic anemia, Lead poisoning, Anemia of chronic disease (also normocytic)
Normocytic (normal MCV)80–100 fLAplastic anemia, Myelofibrosis, Myelophthisic anemia; Hypoendocrine states (hypothyroid, hypoadrenal, hypopituitary), Uremia, Chronic inflammation, Liver disease, Acute blood loss, Hemolysis
Macrocytic (↑ MCV)> 100 fLVitamin B12 deficiency, Folate deficiency, Liver disease, Hypothyroidism, Drugs (methotrexate, hydroxyurea), Myelodysplastic syndrome
For microcytic anemia, serum ferritin < 30 ng/mL confirms iron deficiency. For normocytic anemia, exclude hemolysis (reticulocyte count, LDH, haptoglobin) and renal insufficiency. For macrocytic, check B12/folate levels.

C. RDW — Red Cell Distribution Width

  • ↑ RDW + ↓ MCV: Iron deficiency (early), mixed deficiency states
  • Normal RDW + ↓ MCV: Thalassemia trait (useful distinguishing feature)
  • ↑ RDW + ↑ MCV: B12/folate deficiency, liver disease
  • Normal RDW + ↑ MCV: Aplastic anemia, hypothyroidism, reticulocytosis

D. MCHC — Hypochromia / Hyperchromia

  • ↓ MCHC (hypochromic): Iron deficiency, thalassemia, sideroblastic anemia
  • ↑ MCHC: Hereditary spherocytosis (spherocytes pack hemoglobin more densely)

2. White Blood Cell (WBC) Parameters

A. Leukocytosis — Elevated WBC

The differential depends on which cell line is elevated:
Cell TypeConditionCauses
NeutrophiliaMost commonBacterial infections, rheumatic/autoimmune disorders, neoplastic disorders, trauma, drugs (corticosteroids, G-CSF), endocrine/metabolic disorders, CML, leukemoid reaction
EosinophiliaParasitic infections, allergic diseases (asthma, atopic dermatitis), myeloproliferative/neoplastic diseases, cutaneous diseases, GI diseases (IBD), drug reactions
BasophiliaAllergic reactions, CML, myeloid metaplasia, polycythemia vera, ionizing radiation, hypothyroidism, chronic hemolytic anemia, post-splenectomy
MonocytosisInfections (TB, subacute bacterial endocarditis), neoplastic disorders, GI disorders, sarcoidosis, drug reactions, recovery from marrow suppression
LymphocytosisViral infections (EBV, CMV, hepatitis), lymphocytic leukemia (CLL), pertussis, other infectious diseases, lymphoproliferative neoplasms

B. Leukopenia — Decreased WBC

Cell TypeConditionCauses
NeutropeniaOverwhelming bacterial infection, viral infections, drug reactions (chemotherapy, carbimazole, clozapine), ionizing radiation, hematopoietic diseases, hypersplenism, anaphylactic shock, autoimmune disease (SLE), aplastic anemia
EosinopeniaAcute physical stress, acute inflammatory states, Cushing's syndrome, corticosteroid use
BasopeniaSustained glucocorticoid treatment, acute infection/stress, hyperthyroidism
MonocytopeniaOnset of steroid therapy, hairy cell leukemia
LymphopeniaImmunodeficiency disorders (HIV/AIDS), adrenocortical hormone excess, chemotherapy, irradiation, impaired intestinal lymphatic drainage, advanced lymphomas/carcinomas, anorexia nervosa

3. Platelet Parameters

A. Thrombocytopenia — ↓ Platelets

Clinically significant bleeding typically occurs at < 50,000/μL; spontaneous bleeding risk at < 10,000–20,000/μL.
MechanismCauses
Decreased ProductionAplastic anemia, congenital disorders, chemotherapy/radiation, vitamin B12 or folate deficiency, drugs, SLE, marrow infiltration (myelophthisis), myelodysplastic syndrome
Increased Destruction (Immune)Immune thrombocytopenia (ITP), drug-induced (heparin → HIT, quinine, sulfonamides), neonatal alloimmune thrombocytopenia, post-transfusion purpura, SLE, antiphospholipid syndrome
Increased Destruction (Non-immune)TTP (thrombotic thrombocytopenic purpura), HUS (hemolytic uremic syndrome), DIC, prosthetic heart valves, preeclampsia/HELLP
Sequestration / DilutionalHypersplenism (cirrhosis, storage diseases), massive transfusion
FactitiousEDTA-dependent platelet aggregation (pseudothrombocytopenia), platelet satellitism — always confirm with peripheral smear

B. Thrombocytosis — ↑ Platelets

TypeCauses
Reactive (Secondary)Iron deficiency, acute blood loss, inflammatory disorders (RA, IBD), malignancies, post-splenectomy, infections, trauma — counts rarely exceed 1,000,000/μL
Clonal (Primary/Myeloproliferative)Essential thrombocythemia, polycythemia vera, CML, primary myelofibrosis

4. Reticulocyte Count (often ordered with CBC)

Though not always reported in a standard CBC, this is the critical next step:
Reticulocyte IndexInterpretationExamples
↑ (> 2%)Appropriate bone marrow response / hemolytic or blood-loss anemiaHemolytic anemia, acute hemorrhage, post-treatment response
↓ (< 2%)Hypoproliferative / bone marrow failureIron deficiency, B12/folate deficiency, aplastic anemia, anemia of chronic disease, renal failure

Quick Reference Summary

CBC ParameterHigh (↑)Low (↓)
Hgb/HctPolycythemia vera, dehydration, COPDAnemia (classify by MCV)
MCVB12/folate deficiency, liver disease, hypothyroidIron deficiency, thalassemia, sideroblastic anemia
RDWMixed deficiencies, early iron/B12 deficiencyTypically normal; low RDW in thalassemia
WBC totalInfection, leukemia, steroids, stressChemotherapy, aplasia, viral illness, autoimmune
NeutrophilsBacterial infection, steroids, CMLViral illness, drugs, aplastic anemia, autoimmune
LymphocytesViral infection, CLL, pertussisHIV, steroids, chemo, lymphoma
EosinophilsParasites, allergy, malignancyCushing's, steroids, acute stress
MonocytesTB, SBE, malignancy, sarcoidosisHairy cell leukemia, steroids
BasophilsCML, allergy, hypothyroidStress, hyperthyroidism, steroids
PlateletsIron deficiency, inflammation, post-splenectomy, ETITP, TTP, HIT, DIC, aplasia, B12/folate deficiency

Sources: Textbook of Family Medicine 9e (Speicher); Rosen's Emergency Medicine 9e; Goldman-Cecil Medicine International Edition; Tietz Textbook of Laboratory Medicine 7th Ed.

Create a clinical flowchart for CBC interpretation

Asking for Preferences
Reading File
Running Command

ls /home/daytona/workspace/ 2>/dev/null && echo "---" && python3 -c "import repo…

Running Command

python3 -c "import matplotlib; print(matplotlib.__version__)" && python3 -c "imp…

Running Command

mkdir -p /home/daytona/workspace/cbc-flowchart

Writing File

~/cbc-flowchart/generate_flowchart.py

import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.patches import FancyBboxPatch, FancyArrowPatch
from matplotlib.backends.backend_pdf import PdfPages
import textwrap

# ─── COLOR PALETTE ──────────────────────────────────────────────
C = {
    'start':     '#1A3A5C',   # dark navy
    'decision':  '#2E6DA4',   # blue diamond
    'rbc':       '#C0392B',   # red  – RBC branch
    'wbc':       '#1F7A4D',   # green – WBC branch
    'plt':       '#7D3C98',   # purple – Platelet branch
    'micro':     '#E74C3C',   # microcytic
    'normo':     '#E67E22',   # normocytic
    'macro':     '#8E44AD',   # macrocytic
    'dx':        '#F0F4F8',   # light dx box fill
    'dx_border': '#2C3E50',
    'arrow':     '#2C3E50',
    'text_light':'#FFFFFF',
    'text_dark': '#1A1A1A',
    'header_bg': '#1A3A5C',
}

def draw_box(ax, x, y, w, h, text, fc, tc='white', fontsize=7.5, style='round,pad=0.1',
             bold=False, wrap_width=22, lw=1.2, ec=None):
    ec = ec or fc
    box = FancyBboxPatch((x - w/2, y - h/2), w, h,
                         boxstyle=style, linewidth=lw,
                         edgecolor=ec, facecolor=fc, zorder=3)
    ax.add_patch(box)
    wrapped = '\n'.join(textwrap.wrap(text, wrap_width))
    weight = 'bold' if bold else 'normal'
    ax.text(x, y, wrapped, ha='center', va='center', fontsize=fontsize,
            color=tc, fontweight=weight, zorder=4, multialignment='center')

def draw_diamond(ax, x, y, w, h, text, fc, tc='white', fontsize=7):
    dx, dy = w/2, h/2
    diamond = plt.Polygon([[x, y+dy],[x+dx, y],[x, y-dy],[x-dx, y]],
                           closed=True, facecolor=fc, edgecolor='white',
                           linewidth=1.2, zorder=3)
    ax.add_patch(diamond)
    wrapped = '\n'.join(textwrap.wrap(text, 14))
    ax.text(x, y, wrapped, ha='center', va='center', fontsize=fontsize,
            color=tc, fontweight='bold', zorder=4, multialignment='center')

def arrow(ax, x1, y1, x2, y2, label='', lc=C['arrow'], lw=1.5, fs=6.5):
    ax.annotate('', xy=(x2, y2), xytext=(x1, y1),
                arrowprops=dict(arrowstyle='->', color=lc, lw=lw), zorder=2)
    if label:
        mx, my = (x1+x2)/2, (y1+y2)/2
        ax.text(mx+0.05, my, label, fontsize=fs, color=lc, va='center', fontweight='bold')

def bracket_list(ax, x, y, items, color, title='', fontsize=6.8, dot='•'):
    """Draw a bullet list at (x,y) going downward."""
    if title:
        ax.text(x, y, title, fontsize=7, color=color, fontweight='bold', va='top', zorder=4)
        y -= 0.22
    for item in items:
        wrapped = textwrap.wrap(item, 26)
        ax.text(x, y, f'{dot} {wrapped[0]}', fontsize=fontsize, color=C['text_dark'],
                va='top', zorder=4)
        y -= 0.19
        for extra in wrapped[1:]:
            ax.text(x+0.15, y, extra, fontsize=fontsize, color=C['text_dark'], va='top', zorder=4)
            y -= 0.19
    return y


# ══════════════════════════════════════════════════════════════════
# PAGE 1 — RBC / Anemia Flowchart
# ══════════════════════════════════════════════════════════════════
def page_rbc(pdf):
    fig, ax = plt.subplots(figsize=(11, 17))
    ax.set_xlim(0, 11)
    ax.set_ylim(0, 17)
    ax.axis('off')
    fig.patch.set_facecolor('#F7F9FC')

    # ── Header ──────────────────────────────────────────────────
    header = FancyBboxPatch((0, 15.8), 11, 1.1, boxstyle='square',
                            facecolor=C['header_bg'], edgecolor='none')
    ax.add_patch(header)
    ax.text(5.5, 16.4, 'CBC INTERPRETATION — RBC / ANEMIA FLOWCHART',
            ha='center', va='center', fontsize=13, color='white',
            fontweight='bold')
    ax.text(5.5, 16.05, 'Page 1 of 3  |  Orris Clinical Reference',
            ha='center', va='center', fontsize=8, color='#AED6F1')

    # ── Start ────────────────────────────────────────────────────
    draw_box(ax, 5.5, 15.2, 4.0, 0.55, 'CHECK HEMOGLOBIN / HEMATOCRIT',
             C['start'], fontsize=9, bold=True, wrap_width=40)

    arrow(ax, 5.5, 14.93, 5.5, 14.45)

    # ── Decision: Anemia? ────────────────────────────────────────
    draw_diamond(ax, 5.5, 14.1, 3.2, 0.7,
                 'Anemia?\n(Hgb <13 M / <12 F)', C['decision'])
    ax.text(8.2, 14.1, 'No →  Normal / Polycythemia',
            fontsize=7, color=C['wbc'], va='center', style='italic')
    arrow(ax, 5.5, 13.75, 5.5, 13.2)
    ax.text(5.65, 13.47, 'Yes', fontsize=7, color=C['rbc'], fontweight='bold')

    # ── Step: Reticulocyte ───────────────────────────────────────
    draw_box(ax, 5.5, 12.95, 5.5, 0.5,
             'Check Reticulocyte Count + MCV + Peripheral Blood Smear',
             '#2C3E50', fontsize=8, bold=False, wrap_width=50)
    arrow(ax, 5.5, 12.7, 5.5, 12.15)

    # ── Decision: Reticulocyte ────────────────────────────────────
    draw_diamond(ax, 5.5, 11.8, 3.2, 0.65,
                 'Reticulocyte\nIndex > 2%?', C['decision'])

    # YES → right
    arrow(ax, 7.1, 11.8, 8.8, 11.8, 'Yes')
    draw_box(ax, 9.6, 11.8, 2.3, 0.55,
             'HEMOLYTIC or\nBLOOD LOSS\nAnemia',
             C['rbc'], fontsize=7.5, bold=True, wrap_width=18)
    # Sub-list
    items_hemolytic = ['Autoimmune hemolytic\nanemia (AIHA)',
                       'Hereditary spherocytosis',
                       'G6PD deficiency',
                       'Sickle cell disease',
                       'TTP / HUS',
                       'Acute blood loss',
                       'Malaria']
    y0 = 11.42
    for it in items_hemolytic:
        ax.text(8.55, y0, f'• {it}', fontsize=5.8, color=C['text_dark'], va='top')
        y0 -= 0.19

    # NO → down
    arrow(ax, 5.5, 11.47, 5.5, 10.9, 'No ↓')

    # ── MCV Classification ───────────────────────────────────────
    draw_box(ax, 5.5, 10.65, 4.5, 0.5, 'HYPOPROLIFERATIVE — Classify by MCV',
             '#2C3E50', fontsize=8.5, bold=True, wrap_width=40)
    arrow(ax, 5.5, 10.4, 5.5, 9.9)

    draw_diamond(ax, 5.5, 9.55, 3.6, 0.7, 'MCV Value?', C['decision'])

    # ── Three branches from MCV ─────────────────────────────────
    # LEFT: Microcytic <80
    arrow(ax, 3.7, 9.55, 1.8, 9.55)
    ax.text(2.4, 9.65, '<80 fL', fontsize=7, color=C['micro'], fontweight='bold')
    draw_box(ax, 1.2, 9.55, 2.0, 0.5, 'MICROCYTIC\nAnemia',
             C['micro'], fontsize=8, bold=True, wrap_width=15)
    arrow(ax, 1.2, 9.3, 1.2, 8.55)

    micro_items = [
        ('Iron Deficiency Anemia\n(most common)', '#C0392B'),
        ('Thalassemia\n(α or β)', '#922B21'),
        ('Anemia of Chronic Disease\n(can be normocytic)', '#A93226'),
        ('Sideroblastic Anemia', '#7B241C'),
        ('Lead Poisoning', '#641E16'),
    ]
    y0 = 8.45
    for txt, col in micro_items:
        wrapped = textwrap.wrap(txt, 20)
        draw_box(ax, 1.2, y0, 2.0, 0.38, wrapped[0] + (' ...' if len(wrapped)>1 else ''),
                 col, tc='white', fontsize=6.5, bold=False, wrap_width=22)
        arrow(ax, 1.2, y0 - 0.19, 1.2, y0 - 0.42)
        y0 -= 0.6

    # Center note for microcytic
    ax.text(1.2, 5.3, 'Key next test:\nSerum Ferritin\n<30 ng/mL → IDA',
            fontsize=6.5, ha='center', va='top', color='#7B241C',
            bbox=dict(boxstyle='round,pad=0.3', fc='#FADBD8', ec='#C0392B', lw=1))

    # CENTER: Normocytic 80-100
    arrow(ax, 5.5, 9.2, 5.5, 8.55)
    ax.text(5.65, 8.87, '80–100 fL', fontsize=7, color=C['normo'], fontweight='bold')
    draw_box(ax, 5.5, 8.3, 2.0, 0.5, 'NORMOCYTIC\nAnemia',
             C['normo'], fontsize=8, bold=True, wrap_width=15)
    arrow(ax, 5.5, 8.05, 5.5, 7.5)
    draw_box(ax, 5.5, 7.3, 2.8, 0.45,
             'Check: Renal function, TSH, LFTs\nBone marrow, Peripheral smear',
             '#D35400', tc='white', fontsize=6.5, wrap_width=32)

    normo_items = [
        ('Aplastic Anemia', '#E67E22'),
        ('Anemia of CKD / Renal Failure', '#CA6F1E'),
        ('Anemia of Chronic Disease', '#B7770D'),
        ('Hypothyroidism', '#9A7D0A'),
        ('Myelofibrosis', '#7D6608'),
        ('Myelophthisic Anemia', '#6E6B0D'),
        ('Acute Blood Loss (early)', '#5B4A07'),
    ]
    y0 = 6.85
    for txt, col in normo_items:
        draw_box(ax, 5.5, y0, 2.5, 0.35, txt, col, tc='white', fontsize=6.3, wrap_width=24)
        if y0 > 4.5:
            arrow(ax, 5.5, y0 - 0.18, 5.5, y0 - 0.38)
        y0 -= 0.55

    # RIGHT: Macrocytic >100
    arrow(ax, 7.3, 9.55, 9.0, 9.55)
    ax.text(7.9, 9.65, '>100 fL', fontsize=7, color=C['macro'], fontweight='bold')
    draw_box(ax, 9.7, 9.55, 2.0, 0.5, 'MACROCYTIC\nAnemia',
             C['macro'], fontsize=8, bold=True, wrap_width=15)
    arrow(ax, 9.7, 9.3, 9.7, 8.55)
    draw_box(ax, 9.7, 8.3, 2.2, 0.45,
             'Check: B12, Folate,\nLFTs, TSH, Smear',
             '#6C3483', tc='white', fontsize=6.5, wrap_width=22)

    macro_items = [
        ('Vitamin B12 Deficiency', '#7D3C98'),
        ('Folate Deficiency', '#6C3483'),
        ('Liver Disease', '#5B2C6F'),
        ('Hypothyroidism', '#4A235A'),
        ('Myelodysplastic Syndrome', '#3B1A47'),
        ('Drugs (MTX, Hydroxyurea)', '#2C1236'),
    ]
    y0 = 7.85
    for txt, col in macro_items:
        draw_box(ax, 9.7, y0, 2.2, 0.36, txt, col, tc='white', fontsize=6.3, wrap_width=22)
        if y0 > 5.4:
            arrow(ax, 9.7, y0 - 0.18, 9.7, y0 - 0.38)
        y0 -= 0.55

    # ── Legend ───────────────────────────────────────────────────
    legend_items = [
        (C['start'], 'Start/Process'),
        (C['decision'], 'Decision'),
        (C['rbc'], 'Hemolytic'),
        (C['micro'], 'Microcytic'),
        (C['normo'], 'Normocytic'),
        (C['macro'], 'Macrocytic'),
    ]
    lx, ly = 0.3, 2.0
    ax.text(lx, ly + 0.25, 'LEGEND', fontsize=7, fontweight='bold', color=C['text_dark'])
    for i, (col, label) in enumerate(legend_items):
        rect = FancyBboxPatch((lx, ly - i*0.28 - 0.1), 0.22, 0.18,
                              boxstyle='round,pad=0.02', facecolor=col, edgecolor='none')
        ax.add_patch(rect)
        ax.text(lx + 0.30, ly - i*0.28 + 0.0, label, fontsize=6.5, color=C['text_dark'], va='center')

    # Footer
    ax.text(5.5, 0.18, 'Orris CBC Flowchart  |  Based on: Textbook of Family Medicine 9e, Rosen\'s Emergency Medicine 9e, Goldman-Cecil Medicine',
            ha='center', fontsize=6, color='#7F8C8D', style='italic')

    plt.tight_layout(pad=0)
    pdf.savefig(fig, bbox_inches='tight', dpi=200)
    plt.close(fig)


# ══════════════════════════════════════════════════════════════════
# PAGE 2 — WBC Flowchart
# ══════════════════════════════════════════════════════════════════
def page_wbc(pdf):
    fig, ax = plt.subplots(figsize=(11, 17))
    ax.set_xlim(0, 11)
    ax.set_ylim(0, 17)
    ax.axis('off')
    fig.patch.set_facecolor('#F7F9FC')

    # Header
    header = FancyBboxPatch((0, 15.8), 11, 1.1, boxstyle='square',
                            facecolor='#1F4E2E', edgecolor='none')
    ax.add_patch(header)
    ax.text(5.5, 16.4, 'CBC INTERPRETATION — WHITE BLOOD CELL (WBC) FLOWCHART',
            ha='center', va='center', fontsize=13, color='white', fontweight='bold')
    ax.text(5.5, 16.05, 'Page 2 of 3  |  Orris Clinical Reference',
            ha='center', va='center', fontsize=8, color='#A9DFBF')

    draw_box(ax, 5.5, 15.2, 4.5, 0.55, 'CHECK TOTAL WBC COUNT',
             '#1F4E2E', fontsize=9, bold=True, wrap_width=40)
    arrow(ax, 5.5, 14.93, 5.5, 14.3)

    draw_diamond(ax, 5.5, 13.95, 4.2, 0.7,
                 'WBC Count (normal 4–11 × 10³/μL)?', '#2E6DA4', fontsize=7.5)

    # ── HIGH branch ──────────────────────────────────────────────
    arrow(ax, 7.6, 13.95, 9.5, 13.95)
    ax.text(8.2, 14.1, '↑ HIGH', fontsize=8, color='#C0392B', fontweight='bold')
    draw_box(ax, 10.2, 13.95, 1.3, 0.5, 'LEUKO-\nCYTOSIS',
             '#C0392B', fontsize=8, bold=True)
    arrow(ax, 10.2, 13.7, 10.2, 13.1)
    draw_diamond(ax, 10.2, 12.75, 1.5, 0.6, 'Which\ncell?', '#922B21', fontsize=7)

    high_cells = [
        (10.2, 12.1, 'Neutrophilia', '#C0392B',
         ['Bacterial infection', 'CML', 'Steroids/G-CSF', 'Rheumatic disease',
          'Trauma/MI', 'Pregnancy', 'Neoplasia']),
        (10.2, 10.3, 'Eosinophilia', '#E67E22',
         ['Parasitic infection', 'Allergic disease', 'Asthma/Atopy',
          'Myeloproliferative', 'Drug reaction', 'IBD']),
        (10.2, 8.5, 'Basophilia', '#8E44AD',
         ['CML (hallmark)', 'Polycythemia vera', 'Allergic reactions',
          'Hypothyroidism', 'Myeloid metaplasia']),
        (10.2, 6.7, 'Monocytosis', '#1F7A4D',
         ['TB / SBE', 'Sarcoidosis', 'Malignancy', 'GI disorders',
          'Marrow recovery', 'Drug reaction']),
        (10.2, 4.9, 'Lymphocytosis', '#2E6DA4',
         ['EBV / CMV', 'Hepatitis', 'CLL', 'Pertussis',
          'Other viral infections', 'Lymphoproliferative']),
    ]
    for bx, by, label, col, items in high_cells:
        arrow(ax, bx, by + 0.55, bx, by + 0.25)
        draw_box(ax, bx, by + 0.0, 1.4, 0.4, label, col, fontsize=7, bold=True, wrap_width=16)
        y0 = by - 0.22
        for it in items:
            ax.text(9.45, y0, f'• {it}', fontsize=5.8, color=C['text_dark'], va='top')
            y0 -= 0.18

    # ── LOW branch ───────────────────────────────────────────────
    arrow(ax, 3.4, 13.95, 1.5, 13.95)
    ax.text(2.0, 14.1, '↓ LOW', fontsize=8, color='#2980B9', fontweight='bold')
    draw_box(ax, 0.8, 13.95, 1.3, 0.5, 'LEUKO-\nPENIA',
             '#2980B9', fontsize=8, bold=True)
    arrow(ax, 0.8, 13.7, 0.8, 13.1)
    draw_diamond(ax, 0.8, 12.75, 1.5, 0.6, 'Which\ncell?', '#1A5276', fontsize=7)

    low_cells = [
        (0.8, 12.1, 'Neutropenia', '#2980B9',
         ['Viral infections', 'Drug reaction\n(chemo, clozapine)', 'Aplastic anemia',
          'Autoimmune (SLE)', 'Overwhelming\nbacterial sepsis', 'Radiation']),
        (0.8, 10.0, 'Lymphopenia', '#1F618D',
         ['HIV/AIDS', 'Corticosteroids', 'Chemotherapy', 'Radiation',
          'Advanced lymphoma', 'Anorexia nervosa']),
        (0.8, 8.1, 'Eosinopenia', '#154360',
         ['Acute physical stress', 'Cushing syndrome', 'Corticosteroids',
          'Acute inflammation']),
        (0.8, 6.5, 'Monocytopenia', '#0B2545',
         ['Hairy cell leukemia', 'Onset steroid therapy']),
        (0.8, 5.3, 'Basopenia', '#17202A',
         ['Acute stress', 'Hyperthyroidism', 'Glucocorticoids']),
    ]
    for bx, by, label, col, items in low_cells:
        arrow(ax, bx, by + 0.55, bx, by + 0.25)
        draw_box(ax, bx, by + 0.0, 1.4, 0.4, label, col, fontsize=7, bold=True, wrap_width=16)
        y0 = by - 0.22
        for it in items:
            lines = textwrap.wrap(it, 18)
            for ln in lines:
                ax.text(0.1, y0, f'• {ln}', fontsize=5.8, color=C['text_dark'], va='top')
                y0 -= 0.18

    # ── Normal note ───────────────────────────────────────────────
    arrow(ax, 5.5, 13.6, 5.5, 12.85)
    ax.text(5.65, 13.22, 'Normal', fontsize=7, color='#1F7A4D', fontweight='bold')
    draw_box(ax, 5.5, 12.6, 3.8, 0.45,
             'Normal WBC — Check differential for\nrelative abnormalities; clinical correlation',
             '#1F7A4D', fontsize=7, wrap_width=40)

    # Key note box
    note_box = FancyBboxPatch((3.5, 3.5), 4.5, 2.2, boxstyle='round,pad=0.15',
                              facecolor='#EBF5FB', edgecolor='#2E6DA4', lw=1.5)
    ax.add_patch(note_box)
    ax.text(5.75, 5.55, '⚠  KEY CLINICAL NOTES', fontsize=8, fontweight='bold',
            color='#1A5276', ha='center', va='center')
    notes = [
        '• Toxic granulation + vacuolation of neutrophils → sepsis',
        '• Blasts on smear → acute leukemia (urgent)',
        '• Hyperleukocytosis (>100k) → leukostasis emergency',
        '• "Left shift" (band neutrophils) → bacterial infection',
        '• Pelger-Huët anomaly → MDS or drug effect',
        '• Döhle bodies → infection, inflammation, MYH9 disorder',
    ]
    y0 = 5.25
    for n in notes:
        ax.text(3.7, y0, n, fontsize=6.5, color='#1A3A5C', va='top')
        y0 -= 0.28

    ax.text(5.5, 0.18, 'Orris CBC Flowchart  |  Based on: Textbook of Family Medicine 9e, Goldman-Cecil Medicine, Rosen\'s Emergency Medicine 9e',
            ha='center', fontsize=6, color='#7F8C8D', style='italic')

    plt.tight_layout(pad=0)
    pdf.savefig(fig, bbox_inches='tight', dpi=200)
    plt.close(fig)


# ══════════════════════════════════════════════════════════════════
# PAGE 3 — Platelet Flowchart
# ══════════════════════════════════════════════════════════════════
def page_platelet(pdf):
    fig, ax = plt.subplots(figsize=(11, 17))
    ax.set_xlim(0, 11)
    ax.set_ylim(0, 17)
    ax.axis('off')
    fig.patch.set_facecolor('#F7F9FC')

    # Header
    header = FancyBboxPatch((0, 15.8), 11, 1.1, boxstyle='square',
                            facecolor='#4A235A', edgecolor='none')
    ax.add_patch(header)
    ax.text(5.5, 16.4, 'CBC INTERPRETATION — PLATELET FLOWCHART',
            ha='center', va='center', fontsize=13, color='white', fontweight='bold')
    ax.text(5.5, 16.05, 'Page 3 of 3  |  Orris Clinical Reference',
            ha='center', va='center', fontsize=8, color='#D7BDE2')

    draw_box(ax, 5.5, 15.2, 4.5, 0.55, 'CHECK PLATELET COUNT\n(Normal: 150–400 × 10³/μL)',
             '#4A235A', fontsize=9, bold=True, wrap_width=40)
    arrow(ax, 5.5, 14.93, 5.5, 14.3)

    draw_diamond(ax, 5.5, 13.95, 4.0, 0.7, 'Platelet Count?', '#7D3C98')

    # ── LOW (Thrombocytopenia) ────────────────────────────────────
    arrow(ax, 3.5, 13.95, 1.4, 13.95)
    ax.text(1.8, 14.12, '↓ <150k', fontsize=8, color='#C0392B', fontweight='bold')
    draw_box(ax, 0.7, 13.95, 1.2, 0.55, 'THROMBO-\nCYTOPENIA', '#C0392B', fontsize=8, bold=True)
    arrow(ax, 0.7, 13.68, 0.7, 12.95)

    # FIRST: rule out pseudo
    draw_box(ax, 0.7, 12.7, 2.6, 0.45,
             'Step 1: Peripheral Smear — Rule out\nPseudothrombocytopenia (EDTA clumping)',
             '#7F8C8D', tc='white', fontsize=6.8, wrap_width=30)
    arrow(ax, 0.7, 12.47, 0.7, 11.85)

    draw_diamond(ax, 0.7, 11.5, 2.6, 0.65, 'Mechanism?', '#922B21', fontsize=8)

    mech_cols = [
        (0.25, 10.6, 'Decreased\nProduction', '#C0392B',
         ['Aplastic anemia', 'Chemotherapy / radiation', 'Vit B12 / folate deficiency',
          'Myelodysplastic syndrome', 'Marrow infiltration', 'Drugs (thiazides)', 'SLE']),
        (3.3, 10.6, 'Increased\nDestruction', '#8E44AD',
         ['ITP (immune)', 'Heparin-induced (HIT)', 'Drug-induced (quinine,\nsulfonamides)',
          'TTP / HUS', 'DIC', 'Neonatal alloimmune', 'Preeclampsia / HELLP']),
        (-2.1, 10.6, 'Sequestration/\nDilutional', '#2980B9',
         ['Hypersplenism\n(cirrhosis, storage dis.)', 'Massive transfusion', 'Pregnancy (gestational)']),
    ]
    # Draw 3 sub-branches
    positions = [(0.7, 10.85), (3.3, 10.85)]  # left & right of diamond
    arrow(ax, 0.7, 11.18, 0.7, 10.95)
    arrow(ax, 1.95, 11.5, 3.3, 11.5)
    ax.text(2.4, 11.62, 'Immune/\nConsumption', fontsize=6, color='#8E44AD', ha='center')
    arrow(ax, 3.3, 11.18, 3.3, 10.95)

    arrow(ax, -0.55, 11.5, -1.4, 11.5)
    ax.text(-1.1, 11.62, 'Sequestration', fontsize=5.8, color='#2980B9', ha='center')
    # For sequestration: offset left of page — instead use bottom placement
    # Reposition: place all 3 vertically
    # 3 columns: x=1.2, 5.0, 9.0
    col_xs = [1.1, 5.0, 9.0]
    mech_data = [
        ('↓ Production', '#C0392B',
         ['Aplastic anemia', 'Chemotherapy / radiation', 'Vit B12 / folate deficiency',
          'Myelodysplastic syndrome', 'Marrow infiltration (lymphoma, mets)',
          'Drugs (thiazides, linezolid)', 'SLE']),
        ('Consumption /\nImmune Destruction', '#8E44AD',
         ['ITP', 'Heparin-induced (HIT)', 'Drug-induced\n(quinine, sulfonamides)',
          'TTP / HUS (MAHA)', 'DIC', 'Neonatal alloimmune TP', 'Preeclampsia / HELLP']),
        ('Sequestration /\nDilutional', '#2980B9',
         ['Hypersplenism (cirrhosis)', 'Portal hypertension',
          'Storage diseases\n(Gaucher, Niemann-Pick)',
          'Massive transfusion', 'Gestational thrombocytopenia']),
    ]

    # Redraw mechanism section cleanly
    ax.cla()
    ax.set_xlim(0, 11)
    ax.set_ylim(0, 17)
    ax.axis('off')
    fig.patch.set_facecolor('#F7F9FC')

    # Re-header
    header = FancyBboxPatch((0, 15.8), 11, 1.1, boxstyle='square', facecolor='#4A235A', edgecolor='none')
    ax.add_patch(header)
    ax.text(5.5, 16.4, 'CBC INTERPRETATION — PLATELET FLOWCHART',
            ha='center', va='center', fontsize=13, color='white', fontweight='bold')
    ax.text(5.5, 16.05, 'Page 3 of 3  |  Orris Clinical Reference',
            ha='center', va='center', fontsize=8, color='#D7BDE2')

    draw_box(ax, 5.5, 15.2, 4.5, 0.55, 'CHECK PLATELET COUNT\n(Normal: 150–400 × 10³/μL)',
             '#4A235A', fontsize=9, bold=True, wrap_width=40)
    arrow(ax, 5.5, 14.93, 5.5, 14.3)
    draw_diamond(ax, 5.5, 13.95, 4.0, 0.7, 'Platelet Count?', '#7D3C98')

    # ── HIGH (Thrombocytosis) ─────────────────────────────────────
    arrow(ax, 7.5, 13.95, 9.5, 13.95)
    ax.text(8.0, 14.12, '↑ >400k', fontsize=8, color='#1F7A4D', fontweight='bold')
    draw_box(ax, 10.2, 13.95, 1.3, 0.55, 'THROMBO-\nCYTOSIS', '#1F7A4D', fontsize=8, bold=True)
    arrow(ax, 10.2, 13.68, 10.2, 13.0)
    draw_diamond(ax, 10.2, 12.65, 1.5, 0.6, 'Primary\nor\nReactive?', '#1F4E2E', fontsize=7)

    arrow(ax, 10.2, 12.35, 10.2, 11.75)
    draw_box(ax, 10.2, 11.5, 2.0, 0.45, 'REACTIVE\n(Secondary)', '#27AE60', fontsize=7.5, bold=True)
    react_items = ['Iron deficiency', 'Acute blood loss', 'Post-splenectomy', 'Inflammatory disease (RA, IBD)',
                   'Malignancy', 'Infection/surgery', 'Count rarely >1,000k/μL']
    y0 = 11.22
    for it in react_items:
        ax.text(9.2, y0, f'• {it}', fontsize=6, color=C['text_dark'], va='top')
        y0 -= 0.2

    ax.text(10.2, 9.75, 'PRIMARY\n(Myeloproliferative)', ha='center', fontsize=7.5,
            fontweight='bold', color='#145A32', va='center',
            bbox=dict(boxstyle='round,pad=0.3', fc='#A9DFBF', ec='#1F7A4D', lw=1.2))
    primary_items = ['Essential thrombocythemia', 'Polycythemia vera', 'CML', 'Primary myelofibrosis']
    y0 = 9.45
    for it in primary_items:
        ax.text(9.2, y0, f'• {it}', fontsize=6, color=C['text_dark'], va='top')
        y0 -= 0.2

    # ── LOW (Thrombocytopenia) ────────────────────────────────────
    arrow(ax, 3.5, 13.95, 1.5, 13.95)
    ax.text(1.85, 14.12, '↓ <150k', fontsize=8, color='#C0392B', fontweight='bold')
    draw_box(ax, 0.75, 13.95, 1.3, 0.55, 'THROMBO-\nCYTOPENIA', '#C0392B', fontsize=8, bold=True)
    arrow(ax, 0.75, 13.68, 0.75, 13.1)
    draw_box(ax, 0.75, 12.85, 2.8, 0.45,
             'Peripheral smear → exclude\nPseudothrombocytopenia (EDTA clumps)',
             '#7F8C8D', tc='white', fontsize=6.8, wrap_width=32)
    arrow(ax, 0.75, 12.62, 0.75, 12.1)
    draw_diamond(ax, 0.75, 11.75, 1.35, 0.65, 'Bleeding\nSeverity?', '#922B21', fontsize=7)
    ax.text(0.9, 11.38, '<10k: HIGH risk spontaneous bleed', fontsize=6.2, color='#C0392B')
    ax.text(0.9, 11.18, '10–50k: Bleeding with trauma/surgery', fontsize=6.2, color='#E67E22')
    ax.text(0.9, 10.98, '>50k: Usually asymptomatic', fontsize=6.2, color='#27AE60')

    # 3 mechanism columns
    col_xs_p = [1.4, 5.5, 9.7]
    mech_data_p = [
        ('↓ Production', '#C0392B',
         ['Aplastic anemia', 'Chemotherapy/radiation', 'Vit B12/folate deficiency',
          'Myelodysplastic syndrome', 'Marrow infiltration', 'Drugs (thiazides, linezolid)',
          'SLE, alcohol']),
        ('Consumption /\nImmune Destruction', '#8E44AD',
         ['ITP (immune)', 'Heparin-induced\nthrombocytopenia (HIT)',
          'Drug-induced (quinine, sulfa)', 'TTP / HUS (microangiopathic)',
          'DIC (check fibrinogen/PT)', 'Neonatal alloimmune TP',
          'Preeclampsia / HELLP']),
        ('Sequestration /\nDilutional', '#2980B9',
         ['Hypersplenism (cirrhosis)', 'Portal hypertension',
          'Storage diseases (Gaucher)', 'Massive transfusion',
          'Gestational thrombocytopenia']),
    ]

    arrow(ax, 0.75, 10.82, 0.75, 10.35)
    ax.text(0.85, 10.55, 'Classify:', fontsize=7, color='#922B21', fontweight='bold')

    mech_y_top = 10.1
    mech_h = 0.42
    for mx, (title, col, items) in zip(col_xs_p, mech_data_p):
        draw_box(ax, mx, mech_y_top, 2.4, mech_h, title, col, fontsize=7.5, bold=True, wrap_width=20)
        y0 = mech_y_top - mech_h/2 - 0.22
        for it in items:
            lines = textwrap.wrap(it, 22)
            for line in lines:
                ax.text(mx - 1.1, y0, f'• {line}', fontsize=5.8, color=C['text_dark'], va='top')
                y0 -= 0.185

    # ── Normal note ───────────────────────────────────────────────
    arrow(ax, 5.5, 13.6, 5.5, 13.05)
    ax.text(5.65, 13.32, 'Normal\n150–400k', fontsize=6.5, color='#1F7A4D', fontweight='bold')
    draw_box(ax, 5.5, 12.8, 3.5, 0.38,
             'Normal platelets — correlate clinically, check smear morphology',
             '#1F7A4D', fontsize=7, wrap_width=38)

    # ── RDW / Peripheral Smear key note ──────────────────────────
    note_box = FancyBboxPatch((2.5, 2.5), 6.0, 2.2, boxstyle='round,pad=0.15',
                              facecolor='#FEF9E7', edgecolor='#D4AC0D', lw=1.5)
    ax.add_patch(note_box)
    ax.text(5.5, 4.57, '⚠  THROMBOCYTOPENIA — KEY NEXT STEPS',
            fontsize=8.5, fontweight='bold', color='#7D6608', ha='center')
    next_steps = [
        '1. Always confirm with peripheral smear before acting on low platelet count.',
        '2. Check coagulation (PT/INR, aPTT, fibrinogen) if DIC suspected.',
        '3. If HIT suspected: stop heparin immediately; use alternative anticoagulation.',
        '4. Check LDH, haptoglobin, schistocytes on smear if TTP/HUS suspected.',
        '5. Transfuse platelets: <10k (prophylactic), <50k (before procedure).',
    ]
    y0 = 4.27
    for s in next_steps:
        lines = textwrap.wrap(s, 60)
        for line in lines:
            ax.text(2.7, y0, line, fontsize=6.5, color='#4D4D00', va='top')
            y0 -= 0.27

    ax.text(5.5, 0.18, 'Orris CBC Flowchart  |  Based on: Textbook of Family Medicine 9e, Goldman-Cecil Medicine, Rosen\'s Emergency Medicine 9e',
            ha='center', fontsize=6, color='#7F8C8D', style='italic')

    plt.tight_layout(pad=0)
    pdf.savefig(fig, bbox_inches='tight', dpi=200)
    plt.close(fig)


# ══════════════════════════════════════════════════════════════════
# PAGE 4 — Summary / Master Table
# ══════════════════════════════════════════════════════════════════
def page_summary(pdf):
    fig, ax = plt.subplots(figsize=(11, 17))
    ax.set_xlim(0, 11)
    ax.set_ylim(0, 17)
    ax.axis('off')
    fig.patch.set_facecolor('#F7F9FC')

    header = FancyBboxPatch((0, 15.8), 11, 1.1, boxstyle='square',
                            facecolor='#1A3A5C', edgecolor='none')
    ax.add_patch(header)
    ax.text(5.5, 16.4, 'CBC INTERPRETATION — MASTER REFERENCE SUMMARY',
            ha='center', va='center', fontsize=13, color='white', fontweight='bold')
    ax.text(5.5, 16.05, 'Page 4 of 4  |  Orris Clinical Reference',
            ha='center', va='center', fontsize=8, color='#AED6F1')

    # Table headers
    headers = ['CBC Parameter', 'HIGH (↑)', 'LOW (↓) / Absent', 'Key Next Test']
    col_x = [0.1, 2.8, 6.2, 9.1]
    col_w = [2.7, 3.3, 2.9, 2.0]

    header_row = FancyBboxPatch((0.05, 14.8), 10.9, 0.5,
                                boxstyle='square', facecolor='#2E6DA4', edgecolor='none')
    ax.add_patch(header_row)
    for hx, ht, hw in zip(col_x, headers, col_w):
        ax.text(hx + hw/2, 15.05, ht, fontsize=8, fontweight='bold',
                color='white', ha='center', va='center')

    # Table rows
    rows = [
        ('Hemoglobin /\nHematocrit',
         'Polycythemia vera\nDehydration\nCOPD / altitude\nSmoking',
         'Anemia — classify by MCV\n(see pages 1–2)',
         'MCV, Reticulocyte\ncount, Peripheral smear'),
        ('MCV',
         'Macrocytic: B12/folate def.\nLiver disease, Hypothyroid\nMDS, Drugs (MTX)',
         'Microcytic: Iron deficiency\nThalassemia, Sideroblastic\nanemia, ACD',
         'Ferritin, B12/Folate,\nTSH, LFTs, Hgb electrophoresis'),
        ('RDW',
         'Iron def (early), mixed\ndeficiency, B12/folate def.\n— early anemia',
         'Normal-low: Thalassemia\n(key: low RDW + low MCV)',
         'Ferritin, Hgb electrophoresis'),
        ('WBC (Total)',
         'Leukocytosis: Infection,\nLeukemia, Steroids, Stress',
         'Leukopenia: Viral illness,\nChemo, Aplastic anemia',
         '5-part differential,\nPeripheral smear'),
        ('Neutrophils',
         'Bacterial infection, CML,\nSteroids, G-CSF, Trauma',
         'Viral illness, Drug reaction\nAplastic anemia, SLE, Sepsis',
         'Blood culture, ANC, smear\nfor left shift / blasts'),
        ('Lymphocytes',
         'Viral (EBV/CMV), CLL,\nPertussis, ALL',
         'HIV/AIDS, Steroids,\nChemo, SLE, lymphoma',
         'HIV, EBV/CMV serology,\nFlow cytometry'),
        ('Eosinophils',
         'Parasites, Allergy/Asthma,\nDrug reaction, IBD,\nMyeloproliferative',
         'Cushing syndrome,\nCorticosteroids,\nAcute stress',
         'Stool O&P, IgE, skin prick'),
        ('Monocytes',
         'TB, SBE, Sarcoidosis,\nMalignancy, GI disease',
         'Hairy cell leukemia,\nSteroid onset',
         'BMAT for hairy cell,\nChest X-ray for TB'),
        ('Basophils',
         'CML (hallmark), Allergy,\nPolycythemia vera,\nHypothyroidism',
         'Hyperthyroidism,\nSteroids, Acute stress',
         'BCR-ABL for CML,\nTSH'),
        ('Platelets',
         'Thrombocytosis: Reactive\n(IDA, inflammation) vs.\nPrimary (ET, PV, CML)',
         'Thrombocytopenia: ITP,\nHIT, TTP/HUS, DIC,\nAplastic anemia, B12 def.',
         'Peripheral smear, Coags\n(PT/aPTT/fibrinogen),\nAnti-PF4 for HIT'),
    ]

    alt_colors = ['#FFFFFF', '#EBF5FB']
    y_start = 14.65
    row_h = 1.32
    for i, (param, high, low, nxt) in enumerate(rows):
        fc = alt_colors[i % 2]
        row_bg = FancyBboxPatch((0.05, y_start - row_h), 10.9, row_h - 0.04,
                                boxstyle='square', facecolor=fc, edgecolor='#D5D8DC', lw=0.5)
        ax.add_patch(row_bg)
        ax.text(col_x[0] + col_w[0]/2, y_start - row_h/2, param,
                fontsize=7, fontweight='bold', ha='center', va='center',
                color='#1A3A5C', multialignment='center')
        ax.text(col_x[1] + 0.1, y_start - 0.18, high,
                fontsize=6.5, va='top', color='#C0392B', multialignment='left')
        ax.text(col_x[2] + 0.1, y_start - 0.18, low,
                fontsize=6.5, va='top', color='#2471A3', multialignment='left')
        ax.text(col_x[3] + 0.1, y_start - 0.18, nxt,
                fontsize=6.3, va='top', color='#1F7A4D', multialignment='left')
        y_start -= row_h

    ax.text(5.5, 0.4, 'Normal values (adult): Hgb >13 g/dL (M), >12 g/dL (F)  •  WBC 4–11 × 10³/μL  •  Platelets 150–400 × 10³/μL  •  MCV 80–100 fL',
            ha='center', fontsize=7, color='#2C3E50',
            bbox=dict(boxstyle='round,pad=0.3', fc='#EBF5FB', ec='#2E6DA4', lw=1))
    ax.text(5.5, 0.12, 'Orris CBC Flowchart  |  Sources: Textbook of Family Medicine 9e • Goldman-Cecil Medicine • Rosen\'s Emergency Medicine 9e • Tietz Laboratory Medicine 7e',
            ha='center', fontsize=6, color='#7F8C8D', style='italic')

    plt.tight_layout(pad=0)
    pdf.savefig(fig, bbox_inches='tight', dpi=200)
    plt.close(fig)


# ── GENERATE PDF ─────────────────────────────────────────────────
output_path = '/home/daytona/workspace/cbc-flowchart/CBC_Clinical_Flowchart.pdf'
with PdfPages(output_path) as pdf:
    page_rbc(pdf)
    page_wbc(pdf)
    page_platelet(pdf)
    page_summary(pdf)

    d = pdf.infodict()
    d['Title'] = 'CBC Clinical Interpretation Flowchart'
    d['Author'] = 'Orris Clinical Reference'
    d['Subject'] = 'Complete Blood Count Differential Diagnosis'
    d['Keywords'] = 'CBC, anemia, leukocytosis, thrombocytopenia, hematology'

print(f"PDF generated: {output_path}")
Running Command

cd /home/daytona/workspace/cbc-flowchart && python3 generate_flowchart.py 2>&1

Your credits are exhausted. Your daily credits reset tomorrow, or you can purchase a top-up for more.

Create a quick-reference pocket card (PDF) with CBC interpretation algorithms

Your credits are exhausted. Your daily credits reset tomorrow, or you can purchase a top-up for more.

Download the CBC flowchart PDF I just created

Your credits are exhausted. Your daily credits reset tomorrow, or you can purchase a top-up for more.
This is a shared conversation. Sign in to Orris to start your own chat.