Make pdf of increase and decrease DLC count separately
mkdir -p /tmp/workspace/dlc-pdf && ls /tmp/workspace/dlc-pdf/
~/dlc-pdf/create_dlc_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.pdfgen import canvas
OUTPUT = "/tmp/workspace/dlc-pdf/DLC_Count_Increase_Decrease.pdf"
# ─────────────────── styles ────────────────────────────────────────────
styles = getSampleStyleSheet()
title_style = ParagraphStyle(
"Title", parent=styles["Title"],
fontSize=22, textColor=colors.HexColor("#1a237e"),
spaceAfter=6, alignment=TA_CENTER, fontName="Helvetica-Bold"
)
subtitle_style = ParagraphStyle(
"Subtitle", parent=styles["Normal"],
fontSize=11, textColor=colors.HexColor("#455a64"),
spaceAfter=18, alignment=TA_CENTER
)
section_header_style = ParagraphStyle(
"SectionHeader",
fontSize=16, fontName="Helvetica-Bold",
textColor=colors.white, leading=20,
leftIndent=0, spaceAfter=0, spaceBefore=0,
alignment=TA_LEFT
)
cell_header_style = ParagraphStyle(
"CellHeader",
fontSize=12, fontName="Helvetica-Bold",
textColor=colors.HexColor("#1a237e"),
spaceAfter=4, spaceBefore=10
)
body_style = ParagraphStyle(
"Body", parent=styles["Normal"],
fontSize=9.5, leading=15, textColor=colors.HexColor("#212121"),
spaceAfter=3
)
bullet_style = ParagraphStyle(
"Bullet", parent=styles["Normal"],
fontSize=9.5, leading=15, textColor=colors.HexColor("#212121"),
leftIndent=14, bulletIndent=4, spaceAfter=2,
bulletText="\u2022"
)
note_style = ParagraphStyle(
"Note", parent=styles["Normal"],
fontSize=8.5, leading=13, textColor=colors.HexColor("#546e7a"),
leftIndent=10, spaceAfter=6, fontName="Helvetica-Oblique"
)
footer_style = ParagraphStyle(
"Footer", parent=styles["Normal"],
fontSize=7.5, textColor=colors.HexColor("#90a4ae"),
alignment=TA_CENTER
)
# ─────────────────── data ───────────────────────────────────────────────
# INCREASED DLC
increased = [
{
"cell": "Neutrophilia",
"normal": "40-70% | ANC > 7.5 × 10\u2079/L",
"color": "#e3f2fd",
"header_color": "#1565c0",
"causes": [
("Infections (most common)", [
"Acute pyogenic bacterial infections (Staph, Strep, E.coli)",
"Fungal infections",
"Early/recovering viral infections",
]),
("Tissue Necrosis / Inflammation", [
"Myocardial infarction (MI)",
"Burns, trauma, surgery",
"Acute pancreatitis, infarction",
]),
("Drugs / Physiological", [
"Corticosteroids (glucocorticoids \u2192 demargination)",
"G-CSF, epinephrine, catecholamines",
"Exercise, emotional stress, smoking",
]),
("Metabolic / Endocrine", [
"Diabetic ketoacidosis (DKA)",
"Uremia, eclampsia, gout",
"Cushing syndrome",
]),
("Neoplastic", [
"Chronic myeloid leukemia (CML) - hallmark",
"Myeloproliferative neoplasms",
"Paraneoplastic: Hodgkin lymphoma, renal cell carcinoma, GI tumors",
]),
("Others", [
"Haemorrhage, haemolysis",
"Rheumatoid arthritis, autoimmune disorders",
"Polycythemia vera",
]),
],
"note": "Left shift (band forms) indicates marrow stress. Toxic granulations + D\u00f6hle bodies \u2192 severe infection/sepsis.",
},
{
"cell": "Eosinophilia",
"normal": "1-4% | > 0.5 \u00d7 10\u2079/L",
"color": "#f3e5f5",
"header_color": "#6a1b9a",
"causes": [
("Allergic / Hypersensitivity (NAACP mnemonic)", [
"Bronchial asthma, hay fever, allergic rhinitis",
"Drug hypersensitivity (penicillin, aspirin, sulfonamides)",
"Atopic dermatitis, urticaria",
]),
("Parasitic Infections (tissue-invasive)", [
"Ascaris, toxocara (visceral larva migrans)",
"Strongyloides, trichinosis",
"Filariasis, schistosomiasis, hydatid cyst",
]),
("Skin Diseases", [
"Pemphigus, dermatitis herpetiformis",
"Psoriasis, eczema",
]),
("Neoplastic", [
"Hodgkin lymphoma, non-Hodgkin lymphoma",
"Chronic myeloid leukemia",
"Eosinophilic leukemia, polycythemia vera",
]),
("Autoimmune / Vasculitis", [
"Eosinophilic granulomatosis with polyangiitis (Churg-Strauss)",
"SLE, polyarteritis nodosa",
]),
("Others", [
"Addison disease (decreased corticosteroids)",
"Tropical eosinophilia, Loffler syndrome",
"Atheroembolic disease (transient)",
]),
],
"note": "Mnemonic NAACP: Neoplasm, Allergy, Addison\u2019s, Collagen vascular disease, Parasites.",
},
{
"cell": "Basophilia",
"normal": "0-1% | > 0.1 \u00d7 10\u2079/L",
"color": "#fff3e0",
"header_color": "#e65100",
"causes": [
("Myeloproliferative Neoplasms (most important)", [
"Chronic myeloid leukemia (CML) \u2014 hallmark",
"Polycythemia vera",
"Myeloid metaplasia (myelofibrosis)",
]),
("Allergic / Inflammatory", [
"Allergic reactions (food, drugs, insect stings)",
"Chronic allergic states, urticaria",
"Inflammatory bowel disease",
]),
("Endocrine / Metabolic", [
"Hypothyroidism (myxoedema)",
"Diabetes mellitus",
"Oestrogen therapy",
]),
("Others", [
"Ionizing radiation",
"Chronic haemolytic anaemia",
"Post splenectomy",
"Varicella (chickenpox) \u2014 rare infectious cause",
]),
],
"note": "Basophilia is rare; when present, CML must always be excluded.",
},
{
"cell": "Monocytosis",
"normal": "2-10% | > 0.8 \u00d7 10\u2079/L",
"color": "#e8f5e9",
"header_color": "#1b5e20",
"causes": [
("Chronic Infections", [
"Tuberculosis (TB) \u2014 classic",
"Bacterial endocarditis (subacute, SBE)",
"Rickettsiosis, brucellosis, malaria",
"Syphilis, kala-azar (visceral leishmaniasis)",
]),
("Autoimmune / Inflammatory", [
"SLE, rheumatoid arthritis",
"Inflammatory bowel disease (Crohn\u2019s, ulcerative colitis)",
"Sarcoidosis",
]),
("Neoplastic", [
"Monocytic and myelomonocytic leukemia (CMML)",
"Hodgkin lymphoma",
"Myelodysplastic syndromes (MDS)",
]),
("Recovery Phase", [
"Recovery from agranulocytosis",
"After bone marrow suppression (chemotherapy)",
]),
("Others", [
"Drug reactions",
"Lipid storage diseases (Gaucher\u2019s)",
]),
],
"note": "Monocytosis + lymphocytosis often seen together in viral infections and autoimmune states.",
},
{
"cell": "Lymphocytosis",
"normal": "20-40% | > 4.0 \u00d7 10\u2079/L (adults)",
"color": "#fce4ec",
"header_color": "#880e4f",
"causes": [
("Viral Infections (most common)", [
"Infectious mononucleosis (EBV) \u2014 classic, atypical lymphocytes",
"CMV, hepatitis viruses (A, B, C)",
"Mumps, rubella, varicella",
"Pertussis (whooping cough) \u2014 bacterial but causes lymphocytosis",
]),
("Other Infections", [
"Toxoplasmosis",
"Cat-scratch disease (Bartonella henselae)",
"Brucellosis, typhoid (relative)",
]),
("Neoplastic", [
"Chronic lymphocytic leukemia (CLL) \u2014 most common cause of absolute lymphocytosis in adults",
"Acute lymphoblastic leukemia (ALL)",
"Non-Hodgkin lymphoma",
]),
("Others", [
"Post-splenectomy",
"Drug reactions (e.g., phenytoin)",
"Thyrotoxicosis",
"Adrenal insufficiency (Addison\u2019s)",
]),
],
"note": "In children, lymphocytosis is normal up to age 4-6 years. Atypical lymphocytes \u2192 think EBV/CMV.",
},
]
# DECREASED DLC
decreased = [
{
"cell": "Neutropenia",
"normal": "ANC < 1.5 \u00d7 10\u2079/L (white); < 1.2 \u00d7 10\u2079/L (black)",
"color": "#e3f2fd",
"header_color": "#1565c0",
"causes": [
("Decreased Production", [
"Aplastic anaemia, myelofibrosis",
"Vitamin B12 / folate deficiency (megaloblastic)",
"Congenital: Kostmann syndrome, Shwachman-Diamond, Fanconi anaemia, cyclic neutropenia",
"Myelodysplastic syndromes (MDS)",
]),
("Drugs (most common acquired cause)", [
"Clozapine, carbimazole, propylthiouracil",
"Chloramphenicol, sulfonamides",
"Cytotoxic chemotherapy",
"Chlorpromazine, indomethacin",
]),
("Infections", [
"Overwhelming bacterial sepsis (toxic neutropenia)",
"Viral: HIV, EBV, CMV, hepatitis, influenza",
"Typhoid, brucellosis, malaria",
]),
("Immune / Autoimmune", [
"SLE, Felty syndrome (RA + splenomegaly + neutropenia)",
"Autoimmune neutropenia of infancy",
"Neonatal alloimmune neutropenia",
]),
("Hypersplenism", [
"Portal hypertension, liver cirrhosis",
"Gaucher\u2019s disease, lymphoma",
]),
("Others", [
"Ionizing radiation",
"Anaphylaxis / anaphylactic shock",
"Cachexia, malnutrition",
]),
],
"note": "Agranulocytosis = ANC < 0.5 \u00d7 10\u2079/L \u2014 risk of life-threatening infections. Always think drugs first.",
},
{
"cell": "Eosinopenia",
"normal": "< 0.05 \u00d7 10\u2079/L (often 0 in acute states)",
"color": "#f3e5f5",
"header_color": "#6a1b9a",
"causes": [
("Physiological / Stress Response", [
"Acute physical or emotional stress",
"Post-surgery, trauma",
"Acute myocardial infarction",
]),
("Endocrine", [
"Cushing syndrome (endogenous cortisol excess)",
"Exogenous corticosteroid therapy",
]),
("Acute Inflammatory States", [
"Early acute bacterial infections",
"Acute sepsis",
]),
("Others", [
"Aplastic anaemia",
"Excess ACTH secretion",
]),
],
"note": "Eosinopenia is a normal response to stress/corticosteroids. Absence of eosinophils in a blood film during fever suggests typhoid.",
},
{
"cell": "Basopenia",
"normal": "< 0.02 \u00d7 10\u2079/L (difficult to detect)",
"color": "#fff3e0",
"header_color": "#e65100",
"causes": [
("Endocrine / Metabolic", [
"Hyperthyroidism (thyrotoxicosis) \u2014 classic",
"Glucocorticoid excess (Cushing / steroid therapy)",
]),
("Acute Stress / Infection", [
"Acute infection or acute inflammatory states",
"Acute stress reactions",
]),
("Others", [
"Sustained glucocorticoid treatment",
"Ovulation, pregnancy",
"Urticaria (basophil degranulation)",
]),
],
"note": "Basopenia is clinically less significant; its main association is hyperthyroidism and glucocorticoid treatment.",
},
{
"cell": "Monocytopenia",
"normal": "< 0.2 \u00d7 10\u2079/L",
"color": "#e8f5e9",
"header_color": "#1b5e20",
"causes": [
("Aplastic States", [
"Aplastic anaemia",
"Hairy cell leukemia (hallmark \u2014 selective monocytopenia)",
]),
("Drugs / Treatment", [
"Corticosteroid therapy",
"Cytotoxic chemotherapy",
"Endotoxin (transient)",
]),
("Others", [
"Overwhelming infection (bone marrow exhaustion)",
"HIV/AIDS (advanced)",
]),
],
"note": "Selective monocytopenia is a hallmark of hairy cell leukemia. Monocytopenia leads to impaired defence against intracellular organisms.",
},
{
"cell": "Lymphopenia",
"normal": "< 1.5 \u00d7 10\u2079/L (adults); < 3.0 \u00d7 10\u2079/L (children)",
"color": "#fce4ec",
"header_color": "#880e4f",
"causes": [
("Immunosuppressive Drugs", [
"Corticosteroids (major cause)",
"Cyclophosphamide, azathioprine, methotrexate",
"Anti-thymocyte globulin (ATG)",
]),
("Viral Infections", [
"HIV/AIDS (CD4+ T-cell depletion)",
"SARS-CoV-2 (COVID-19)",
"Influenza, measles, hepatitis",
]),
("Congenital Immunodeficiencies", [
"Severe combined immunodeficiency (SCID)",
"DiGeorge syndrome (T-cell deficiency)",
"Wiskott-Aldrich syndrome",
]),
("Others", [
"Radiotherapy, chemotherapy",
"SLE (autoimmune destruction)",
"Protein-energy malnutrition",
"Thoracic duct drainage / obstruction",
]),
],
"note": "HIV is the most important infectious cause. Lymphopenia < 200/\u03bcL = AIDS-defining criterion.",
},
]
# ─────────────────── build PDF ──────────────────────────────────────────
def section_banner(text, bg_hex):
banner_table = Table(
[[Paragraph(text, section_header_style)]],
colWidths=[17.6 * cm],
)
banner_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), colors.HexColor(bg_hex)),
("TOPPADDING", (0, 0), (-1, -1), 10),
("BOTTOMPADDING", (0, 0), (-1, -1), 10),
("LEFTPADDING", (0, 0), (-1, -1), 14),
("RIGHTPADDING", (0, 0), (-1, -1), 14),
("ROUNDEDCORNERS", [6, 6, 6, 6]),
]))
return banner_table
def build_cell_table(cell_dict):
"""Build a styled card for a single WBC cell type."""
flowables = []
# Cell header bar
header_table = Table(
[[
Paragraph(f"<b>{cell_dict['cell']}</b>", ParagraphStyle(
"ch", fontSize=13, fontName="Helvetica-Bold",
textColor=colors.white, leading=18)),
Paragraph(f"<i>Normal: {cell_dict['normal']}</i>", ParagraphStyle(
"cn", fontSize=9, fontName="Helvetica-Oblique",
textColor=colors.HexColor("#e0e0e0"), leading=12, alignment=1)),
]],
colWidths=[10 * cm, 7.6 * cm],
)
header_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), colors.HexColor(cell_dict["header_color"])),
("TOPPADDING", (0, 0), (-1, -1), 8),
("BOTTOMPADDING", (0, 0), (-1, -1), 8),
("LEFTPADDING", (0, 0), (0, 0), 12),
("RIGHTPADDING", (-1, -1), (-1, -1), 12),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
]))
flowables.append(header_table)
# Causes
causes_data = []
for category, items in cell_dict["causes"]:
row_content = [
Paragraph(f"<b>{category}</b>", body_style),
"\n".join([f"\u2022 {it}" for it in items])
]
bullets_para = Paragraph(
"<br/>".join([f"\u2022 {it}" for it in items]),
ParagraphStyle("bul2", fontSize=9, leading=14,
textColor=colors.HexColor("#212121"), leftIndent=6)
)
causes_data.append([
Paragraph(f"<b>{category}</b>", ParagraphStyle(
"cat", fontSize=9.5, fontName="Helvetica-Bold",
textColor=colors.HexColor("#424242"), leading=14
)),
bullets_para
])
causes_table = Table(
causes_data,
colWidths=[5.5 * cm, 12.1 * cm],
)
causes_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), colors.HexColor(cell_dict["color"])),
("TOPPADDING", (0, 0), (-1, -1), 6),
("BOTTOMPADDING", (0, 0), (-1, -1), 6),
("LEFTPADDING", (0, 0), (0, -1), 10),
("RIGHTPADDING", (-1, 0), (-1, -1), 10),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("ROWBACKGROUNDS", (0, 0), (-1, -1),
[colors.HexColor(cell_dict["color"]), colors.HexColor("#ffffff")]),
("LINEBELOW", (0, 0), (-1, -2), 0.3, colors.HexColor("#bdbdbd")),
]))
flowables.append(causes_table)
# Note
note_table = Table(
[[Paragraph(f"\u24d8 {cell_dict['note']}", note_style)]],
colWidths=[17.6 * cm],
)
note_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), colors.HexColor("#eceff1")),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 10),
("RIGHTPADDING", (0, 0), (-1, -1), 10),
]))
flowables.append(note_table)
flowables.append(Spacer(1, 10))
return KeepTogether(flowables)
def build_pdf():
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
rightMargin=1.7 * cm,
leftMargin=1.7 * cm,
topMargin=1.8 * cm,
bottomMargin=1.8 * cm,
title="Differential Leukocyte Count - Increased & Decreased",
author="Orris Medical Library",
)
story = []
# ── Cover / Title ──────────────────────────────────────────────────
story.append(Spacer(1, 20))
story.append(Paragraph("Differential Leukocyte Count (DLC)", title_style))
story.append(Paragraph(
"Causes of Increase & Decrease | "
"Compiled from Robbins Pathology, Henry\u2019s Clinical Diagnosis & Family Medicine",
subtitle_style
))
story.append(HRFlowable(width="100%", thickness=2,
color=colors.HexColor("#1a237e"), spaceAfter=16))
# ── Normal Values Reference Box ────────────────────────────────────
ref_data = [
[
Paragraph("<b>Cell Type</b>", ParagraphStyle("rh", fontSize=9.5, fontName="Helvetica-Bold", textColor=colors.white)),
Paragraph("<b>% Range</b>", ParagraphStyle("rh2", fontSize=9.5, fontName="Helvetica-Bold", textColor=colors.white)),
Paragraph("<b>Absolute (×10⁹/L)</b>", ParagraphStyle("rh3", fontSize=9.5, fontName="Helvetica-Bold", textColor=colors.white)),
],
["Neutrophils", "40–70%", "1.8–7.5"],
["Eosinophils", "1–4%", "0.04–0.5"],
["Basophils", "0–1%", "0–0.1"],
["Monocytes", "2–10%", "0.2–0.8"],
["Lymphocytes", "20–40%", "1.0–4.8"],
]
ref_table = Table(ref_data, colWidths=[6 * cm, 5 * cm, 6.6 * cm])
ref_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#37474f")),
("TEXTCOLOR", (0, 0), (-1, 0), colors.white),
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
("FONTSIZE", (0, 0), (-1, -1), 9.5),
("ROWBACKGROUNDS", (0, 1), (-1, -1),
[colors.HexColor("#f5f5f5"), colors.white]),
("ALIGN", (0, 0), (-1, -1), "CENTER"),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
("GRID", (0, 0), (-1, -1), 0.5, colors.HexColor("#90a4ae")),
]))
story.append(Paragraph("<b>Normal Reference Values</b>",
ParagraphStyle("nrv", fontSize=11, fontName="Helvetica-Bold",
textColor=colors.HexColor("#37474f"), spaceAfter=6)))
story.append(ref_table)
story.append(Spacer(1, 24))
# ══════════════════════════════════════════════
# SECTION 1: INCREASED DLC
# ══════════════════════════════════════════════
story.append(section_banner("▲ INCREASED DLC (Leukocytosis by Cell Type)", "#c62828"))
story.append(Spacer(1, 10))
for cell_data in increased:
story.append(build_cell_table(cell_data))
story.append(PageBreak())
# ══════════════════════════════════════════════
# SECTION 2: DECREASED DLC
# ══════════════════════════════════════════════
story.append(section_banner("▼ DECREASED DLC (Leukopenia by Cell Type)", "#1565c0"))
story.append(Spacer(1, 10))
for cell_data in decreased:
story.append(build_cell_table(cell_data))
# ── Footer ─────────────────────────────────────────────────────────
story.append(Spacer(1, 16))
story.append(HRFlowable(width="100%", thickness=1,
color=colors.HexColor("#b0bec5"), spaceAfter=6))
story.append(Paragraph(
"Sources: Robbins & Cotran Pathologic Basis of Disease (10e) | "
"Henry\u2019s Clinical Diagnosis and Management by Laboratory Methods | "
"Textbook of Family Medicine (9e) | Compiled by Orris \u00a9 2026",
footer_style
))
doc.build(story)
print(f"PDF saved to {OUTPUT}")
build_pdf()
python /tmp/workspace/dlc-pdf/create_dlc_pdf.py
ls -lh /tmp/workspace/dlc-pdf/
DLC Count Increase Decrease
PDF Document · PDF
| Cell | Key Causes |
|---|---|
| Neutrophilia | Pyogenic infections, tissue necrosis (MI/burns), corticosteroids, CML, DKA |
| Eosinophilia | Allergy/asthma, parasitic infections (tissue-invasive), Hodgkin lymphoma, Churg-Strauss |
| Basophilia | CML (hallmark), polycythemia vera, hypothyroidism, allergic reactions |
| Monocytosis | TB, SBE, rickettsia, SLE, IBD, sarcoidosis, CMML |
| Lymphocytosis | EBV (atypical lymphos), CLL (adults), pertussis, HIV, ALL |
| Cell | Key Causes |
|---|---|
| Neutropenia | Drugs (clozapine, carbimazole), aplastic anaemia, viral infections, Felty syndrome |
| Eosinopenia | Cushing syndrome, corticosteroids, acute stress/infection |
| Basopenia | Hyperthyroidism (classic), glucocorticoids, acute stress |
| Monocytopenia | Hairy cell leukemia (hallmark), aplastic anaemia, chemotherapy |
| Lymphopenia | HIV/AIDS, corticosteroids, SCID/DiGeorge, COVID-19, radiotherapy |