Write short nlte on neurocysticercosis
| Type | Location |
|---|---|
| Parenchymal NCC | Brain parenchyma - most common |
| Extraparenchymal NCC | Ventricles, subarachnoid space, spinal cord, eye |
Make pdf patholfor pathology md student
Yes neurocyatecercosia as a pathology md student
ls /home/daytona/workspace/ 2>/dev/null && mkdir -p /home/daytona/workspace/ncc-…
~/ncc-pdf/make_ncc_pdf.py
#!/usr/bin/env python3
"""
Generate a detailed Pathology MD-level PDF on Neurocysticercosis
using ReportLab.
"""
import urllib.request
import os
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, Image, KeepTogether, PageBreak
)
from reportlab.platypus.flowables import BalancedColumns
from io import BytesIO
# ── colours ──────────────────────────────────────────────────────────────────
DARK_BLUE = colors.HexColor("#1A3A5C")
MID_BLUE = colors.HexColor("#2E6DA4")
LIGHT_BLUE = colors.HexColor("#D6E8F7")
ACCENT_RED = colors.HexColor("#C0392B")
ACCENT_GREEN= colors.HexColor("#1A6B3C")
GOLD = colors.HexColor("#D4A017")
PALE_GREY = colors.HexColor("#F5F5F5")
MED_GREY = colors.HexColor("#CCCCCC")
TEXT_BLACK = colors.HexColor("#1C1C1C")
W, H = A4 # 595 x 842 pt
# ── document ──────────────────────────────────────────────────────────────────
out_path = "/home/daytona/workspace/ncc-pdf/Neurocysticercosis_Pathology_MD.pdf"
doc = SimpleDocTemplate(
out_path,
pagesize=A4,
leftMargin=2*cm, rightMargin=2*cm,
topMargin=2.2*cm, bottomMargin=2*cm,
title="Neurocysticercosis – Pathology MD Notes",
author="Orris Medical AI",
)
# ── styles ────────────────────────────────────────────────────────────────────
base = getSampleStyleSheet()
def ps(name, parent="Normal", **kw):
return ParagraphStyle(name, parent=base[parent], **kw)
styles = {
"cover_title": ps("cover_title", "Title",
fontSize=28, textColor=colors.white, alignment=TA_CENTER,
leading=34, spaceAfter=6),
"cover_sub": ps("cover_sub", "Normal",
fontSize=13, textColor=colors.HexColor("#D6E8F7"), alignment=TA_CENTER,
leading=18, spaceAfter=4),
"cover_tag": ps("cover_tag", "Normal",
fontSize=10, textColor=GOLD, alignment=TA_CENTER, leading=14),
"h1": ps("h1", "Heading1",
fontSize=14, textColor=colors.white, leading=18,
spaceBefore=10, spaceAfter=4, leftIndent=0),
"h2": ps("h2", "Heading2",
fontSize=11.5, textColor=DARK_BLUE, leading=16,
spaceBefore=8, spaceAfter=3, borderPad=2),
"h3": ps("h3", "Heading3",
fontSize=10.5, textColor=MID_BLUE, leading=14,
spaceBefore=5, spaceAfter=2, fontName="Helvetica-BoldOblique"),
"body": ps("body", "Normal",
fontSize=9.5, textColor=TEXT_BLACK, leading=14,
spaceAfter=4, alignment=TA_JUSTIFY),
"bullet": ps("bullet", "Normal",
fontSize=9.5, textColor=TEXT_BLACK, leading=13,
spaceAfter=2, leftIndent=14, firstLineIndent=-10),
"bullet2": ps("bullet2", "Normal",
fontSize=9, textColor=TEXT_BLACK, leading=12,
spaceAfter=1, leftIndent=26, firstLineIndent=-10),
"caption": ps("caption", "Normal",
fontSize=8, textColor=colors.HexColor("#555555"),
alignment=TA_CENTER, leading=11, spaceAfter=4, fontName="Helvetica-Oblique"),
"keybox": ps("keybox", "Normal",
fontSize=9.5, textColor=DARK_BLUE, leading=13,
leftIndent=6, spaceAfter=2),
"warn": ps("warn", "Normal",
fontSize=9.5, textColor=ACCENT_RED, leading=13,
leftIndent=6, spaceAfter=2, fontName="Helvetica-Bold"),
"ref": ps("ref", "Normal",
fontSize=7.5, textColor=colors.HexColor("#666666"),
leading=10, spaceAfter=1, fontName="Helvetica-Oblique"),
"toc_h": ps("toc_h", "Normal",
fontSize=10, textColor=DARK_BLUE, leading=14,
fontName="Helvetica-Bold", spaceAfter=2),
"toc_e": ps("toc_e", "Normal",
fontSize=9.5, textColor=TEXT_BLACK, leading=13,
leftIndent=12, spaceAfter=1),
}
# ── helpers ───────────────────────────────────────────────────────────────────
def section_header(title, level=1):
"""Coloured section header bar."""
bg = DARK_BLUE if level == 1 else MID_BLUE
txt_col = colors.white
fs = 13 if level == 1 else 11
data = [[Paragraph(f"<b>{title}</b>",
ParagraphStyle("sh", fontSize=fs, textColor=txt_col,
leading=fs+4, fontName="Helvetica-Bold"))]]
t = Table(data, colWidths=[W - 4*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("BOX", (0,0), (-1,-1), 0.5, colors.white),
]))
return t
def two_col_table(rows, col_headers=None, col_widths=None):
if col_widths is None:
col_widths = [6.5*cm, 10*cm]
header_style = ParagraphStyle("th", fontSize=9, textColor=colors.white,
fontName="Helvetica-Bold", leading=12)
cell_style = ParagraphStyle("td", fontSize=9, textColor=TEXT_BLACK,
leading=12, spaceAfter=1)
data = []
if col_headers:
data.append([Paragraph(h, header_style) for h in col_headers])
for r in rows:
data.append([Paragraph(str(c), cell_style) for c in r])
t = Table(data, colWidths=col_widths, repeatRows=1 if col_headers else 0)
ts = [
("BACKGROUND", (0,0), (-1,0), DARK_BLUE if col_headers else PALE_GREY),
("BACKGROUND", (0,1), (-1,-1), PALE_GREY),
("ROWBACKGROUNDS", (0,1), (-1,-1), [colors.white, PALE_GREY]),
("GRID", (0,0), (-1,-1), 0.4, MED_GREY),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
]
t.setStyle(TableStyle(ts))
return t
def key_box(items, title="Key Points", border_color=MID_BLUE):
cell_style = ParagraphStyle("kc", fontSize=9.5, textColor=TEXT_BLACK, leading=13)
title_style = ParagraphStyle("kt", fontSize=10, textColor=colors.white,
fontName="Helvetica-Bold", leading=14)
content = [Paragraph(title, title_style)]
for item in items:
content.append(Paragraph(f"• {item}", cell_style))
inner = [[c] for c in content]
t = Table(inner, colWidths=[W - 4*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), border_color),
("BACKGROUND", (0,1), (-1,-1), colors.HexColor("#EEF5FB")),
("BOX", (0,0), (-1,-1), 1, border_color),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
return t
def bullet(text, indent=0):
prefix = "• " if indent == 0 else " - "
ind = 14 + indent*12
return Paragraph(f"{prefix}{text}",
ParagraphStyle("bl", fontSize=9.5, textColor=TEXT_BLACK,
leading=13, spaceAfter=2,
leftIndent=ind, firstLineIndent=-10))
def sp(n=1):
return Spacer(1, n*0.25*cm)
# ── download brain image ──────────────────────────────────────────────────────
img_url = "https://cdn.orris.care/cdss_images/f9784b47b577c0f1846d3f1e4adae98a56d5a5e0c045585bd7c87215715e7b4b.png"
img_path = "/home/daytona/workspace/ncc-pdf/ncc_brain.png"
if not os.path.exists(img_path):
urllib.request.urlretrieve(img_url, img_path)
# ── BUILD STORY ───────────────────────────────────────────────────────────────
story = []
# ============================================================
# COVER PAGE
# ============================================================
cover_bg_data = [[""]]
cover_bg = Table(cover_bg_data, colWidths=[W - 4*cm], rowHeights=[7.5*cm])
cover_bg.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), DARK_BLUE),
("BOX", (0,0), (0,0), 0, DARK_BLUE),
]))
story.append(sp(2))
story.append(cover_bg)
story.append(Spacer(1, -7.5*cm)) # overlay
cover_inner_data = [
[Paragraph("NEUROCYSTICERCOSIS", styles["cover_title"])],
[Paragraph("Comprehensive Pathology Notes", styles["cover_sub"])],
[Paragraph("For MD Pathology Students", styles["cover_sub"])],
[Spacer(1, 0.3*cm)],
[Paragraph("Parasitology · Neuropathology · Clinicopathological Correlation", styles["cover_tag"])],
[Spacer(1, 0.2*cm)],
[Paragraph("Compiled from Harrison's 22E · Goldman-Cecil · Bradley & Daroff · Tintinalli's", styles["cover_tag"])],
]
cover_inner = Table(cover_inner_data, colWidths=[W - 4*cm])
cover_inner.setStyle(TableStyle([
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 20),
("RIGHTPADDING", (0,0), (-1,-1), 20),
]))
story.append(cover_inner)
story.append(Spacer(1, 0.8*cm))
story.append(HRFlowable(width="100%", thickness=2, color=GOLD, spaceAfter=8))
# ============================================================
# 1. OVERVIEW / DEFINITION
# ============================================================
story.append(section_header("1. OVERVIEW AND DEFINITION"))
story.append(sp())
story.append(Paragraph(
"Neurocysticercosis (NCC) is infection of the central nervous system (CNS) by "
"the <b>larval stage (cysticercus)</b> of the pork tapeworm <i>Taenia solium</i>. "
"It is the <b>most common parasitic disease of the human CNS</b> worldwide and the "
"<b>leading cause of symptomatic (acquired) epilepsy</b> globally, contributing an "
"estimated 0.45–1.35 million epilepsy cases in Latin America alone, ~1 million in India, "
"and 0.31–4.6 million in Africa.",
styles["body"]))
story.append(sp())
def_rows = [
["Organism", "<i>Taenia solium</i> (pork tapeworm) – larval (cysticercus) stage"],
["Taxonomic class", "Platyhelminthes → Cestoda"],
["Definitive host", "Humans (adult tapeworm in small intestine)"],
["Intermediate host", "Pigs (normally); humans (aberrant)"],
["Human infection", "Ingestion of T. solium eggs via fecal-oral route (NOT from eating pork)"],
["Endemic regions", "Latin America, Sub-Saharan Africa, South/Southeast Asia, India"],
]
story.append(two_col_table(def_rows, col_headers=["Parameter", "Detail"]))
story.append(sp(2))
# ============================================================
# 2. LIFE CYCLE & PATHOGENESIS
# ============================================================
story.append(section_header("2. LIFE CYCLE AND PATHOGENESIS"))
story.append(sp())
story.append(Paragraph("<b>Life Cycle</b>", styles["h2"]))
lc_steps = [
("<b>Step 1 – Egg ingestion:</b> Humans ingest <i>T. solium</i> eggs from food/water "
"contaminated by feces of a tapeworm carrier (including autoinfection via hand-to-mouth)."),
("<b>Step 2 – Oncosphere release:</b> Eggs hatch in the duodenum; digestive enzymes and bile "
"activate the oncospheres, which penetrate the intestinal wall."),
("<b>Step 3 – Haematogenous dissemination:</b> Oncospheres enter portal circulation and "
"disseminate to muscle, subcutaneous tissue, eye, and CNS."),
("<b>Step 4 – Cyst formation:</b> Oncospheres encyst in tissues over weeks. Each cysticercus "
"consists of a fluid-filled translucent bladder (5–20 mm) containing an invaginated <b>scolex</b> "
"(the future tapeworm head with suckers and hooklets)."),
("<b>Step 5 – Cyst degeneration:</b> Over months to years the larva dies; host immune response "
"triggers inflammation, cyst wall thickening, and eventual calcification."),
]
for s in lc_steps:
story.append(bullet(s))
story.append(sp())
story.append(Paragraph("<b>Why the CNS is preferentially affected</b>", styles["h2"]))
for txt in [
"The blood-brain barrier provides relative immune privilege, allowing cysts to survive longer.",
"Gray-white junction, cortex, basal ganglia, and ventricles are most commonly involved sites.",
"Even vegetarians and non-pork eaters can develop NCC via fecal-oral spread of eggs.",
]:
story.append(bullet(txt))
story.append(sp(2))
# ============================================================
# 3. CLASSIFICATION
# ============================================================
story.append(section_header("3. CLASSIFICATION OF NCC"))
story.append(sp())
class_rows = [
["Parenchymal NCC", "Brain parenchyma – most common form; seizures predominate"],
["Intraventricular NCC", "Ventricles (especially 4th ventricle); obstructive hydrocephalus"],
["Subarachnoid NCC", "Basal cisterns and sulci; meningitis picture, giant cysts possible"],
["Spinal NCC", "Intra- or extramedullary; mimics spinal cord tumour"],
["Ocular NCC", "Vitreous, subretinal space; visual disturbance"],
["Mixed NCC", "Multiple compartments involved simultaneously"],
]
story.append(two_col_table(class_rows, col_headers=["Type", "Location & Key Feature"],
col_widths=[5.5*cm, 11*cm]))
story.append(sp(2))
# ============================================================
# 4. GROSS PATHOLOGY
# ============================================================
story.append(section_header("4. GROSS PATHOLOGY"))
story.append(sp())
# Insert the brain image
try:
img = Image(img_path, width=12*cm, height=9*cm)
img.hAlign = "CENTER"
story.append(img)
story.append(Paragraph(
"Fig. 1. Cerebral Cysticercosis. (A, B) Axial T1-weighted MRI: cystic ring-enhancing lesions at "
"periventricular and subcortical locations; note central hyperintense scolex. "
"(C) CT scan showing subcortical lesions (arrows) and parenchymal calcification (arrowhead). "
"(D) Gross pathology brain section demonstrating multiple translucent cysticercus bladders "
"of varying sizes scattered throughout the cortex and white matter. "
"[Source: Grainger & Allison's Diagnostic Radiology / Bradley & Daroff's Neurology]",
styles["caption"]))
except Exception as e:
story.append(Paragraph(f"[Image could not be loaded: {e}]", styles["caption"]))
story.append(sp())
story.append(Paragraph("<b>Macroscopic features of the cysticercus:</b>", styles["h2"]))
for txt in [
"<b>Size:</b> 5–20 mm (parenchymal); subarachnoid racemose cysts may reach several cm.",
"<b>Appearance:</b> Thin-walled, translucent fluid-filled bladder, pearl-white to yellowish.",
"<b>Contents:</b> Clear slightly turbid fluid resembling CSF; contains an eccentric pearly-white <b>scolex</b> (0.5–1 cm) with 4 suckers and a rostellum bearing 2 rows of hooklets.",
"<b>Scolex</b> appears as a mural nodule or 'dot' within the cyst – the pathognomonic <b>'hole-with-dot' sign</b> on imaging.",
"<b>Distribution:</b> Gray-white junction, cortex, basal ganglia, ventricles, subarachnoid space.",
"<b>Number:</b> Ranges from a single cyst to hundreds (in heavy infections).",
"<b>Calcified lesions (late):</b> Dense white granular foci, 2–10 mm; may be palpable in the brain substance on sectioning.",
"<b>Racemose variant:</b> Multilobulated cluster of cysts WITHOUT a visible scolex; found in basal cisterns and ventricles; highly destructive.",
]:
story.append(bullet(txt))
story.append(sp(2))
# ============================================================
# 5. MICROSCOPIC / HISTOPATHOLOGY
# ============================================================
story.append(section_header("5. HISTOPATHOLOGY (Microscopic Pathology)"))
story.append(sp())
story.append(Paragraph(
"The histological appearance of NCC evolves through <b>four stages</b>, each reflecting the "
"host-parasite interaction and the degree of larval viability. This staging is critical for "
"MD pathology exam purposes.",
styles["body"]))
story.append(sp())
stage_data = [
["Stage", "Name", "Viability", "Histological Features", "Imaging Correlate"],
["1", "Vesicular\n(Viable)", "Live larva",
"• Thin outer laminated membrane (eosinophilic, PAS+)\n"
"• Inner germinative epithelium (tegument)\n"
"• Scolex visible with suckers & hooklets\n"
"• MINIMAL host inflammatory response\n"
"• Surrounding brain parenchyma essentially normal",
"Cystic lesion, clear fluid, visible scolex, NO edema, NO enhancement"],
["2", "Colloidal\n(Degenerating)", "Dying larva",
"• Cyst fluid becomes turbid/colloidal\n"
"• Cyst wall thickens; scolex degenerates\n"
"• Intense host inflammatory infiltrate:\n"
" – Eosinophils, neutrophils, lymphocytes\n"
" – Macrophages, plasma cells\n"
"• Perilesional oedema +++\n"
"• Giant cell reaction begins",
"Ring-enhancing lesion; marked T2/FLAIR oedema"],
["3", "Granulonodular\n(Transitional)", "Dead larva",
"• Cyst shrinks; wall becomes granulomatous\n"
"• Epithelioid macrophages + Langhans/foreign-body giant cells\n"
"• Central caseous-like necrosis may occur\n"
"• Dense mononuclear infiltrate\n"
"• Reactive gliosis (astrocytic proliferation)\n"
"• Early dystrophic calcification",
"Nodular homogeneous enhancement; oedema resolving"],
["4", "Nodular Calcified\n(Inactive)", "Calcified scolex",
"• Dense concentric calcification (dystrophic)\n"
"• Residual ghost outlines of scolex/hooklets\n"
"• Surrounding chronic gliosis (Rosenthal fibres)\n"
"• Haemosiderin-laden macrophages\n"
"• NO active inflammation",
"Hyperdense nodule on CT; no enhancement; SWI blooming on MRI"],
]
cell_s = ParagraphStyle("ts", fontSize=8, textColor=TEXT_BLACK, leading=11)
head_s = ParagraphStyle("th2", fontSize=8.5, textColor=colors.white,
fontName="Helvetica-Bold", leading=12)
fmt_data = []
for i, row in enumerate(stage_data):
if i == 0:
fmt_data.append([Paragraph(c, head_s) for c in row])
else:
fmt_data.append([Paragraph(c.replace("\n", "<br/>"), cell_s) for c in row])
stage_t = Table(fmt_data,
colWidths=[0.8*cm, 2.4*cm, 2*cm, 6.8*cm, 4.5*cm],
repeatRows=1)
stage_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("ROWBACKGROUNDS", (0,1), (-1,-1), [colors.white, PALE_GREY]),
("GRID", (0,0), (-1,-1), 0.4, MED_GREY),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 4),
("BACKGROUND", (0,1), (0,1), colors.HexColor("#D4EFDF")),
("BACKGROUND", (0,2), (0,2), colors.HexColor("#FDEBD0")),
("BACKGROUND", (0,3), (0,3), colors.HexColor("#FADBD8")),
("BACKGROUND", (0,4), (0,4), colors.HexColor("#E8DAEF")),
]))
story.append(stage_t)
story.append(sp())
story.append(Paragraph("<b>Special stains used in histopathological diagnosis:</b>", styles["h2"]))
stain_rows = [
["H&E", "Overall morphology; laminated cyst wall, scolex suckers, hooklets, inflammatory infiltrate"],
["PAS (Periodic Acid Schiff)", "Highlights laminated eosinophilic membrane of cyst wall (PAS-positive)"],
["Von Kossa / Alizarin Red S", "Confirms dystrophic calcification in stage 4"],
["GFAP (IHC)", "Reactive gliosis around cysts"],
["CD68 (IHC)", "Macrophage/microglial activation"],
["Congo Red", "Negative (distinguishes from amyloid in differential)"],
["Masson Trichrome", "Collagen deposition in cyst wall and surrounding fibrosis"],
]
story.append(two_col_table(stain_rows, col_headers=["Stain / Technique", "Purpose / Finding"],
col_widths=[4.5*cm, 12*cm]))
story.append(sp(2))
# ============================================================
# 6. CLINICAL FEATURES
# ============================================================
story.append(section_header("6. CLINICAL FEATURES (Clinicopathological Correlation)"))
story.append(sp())
clinical_rows = [
["Seizures", "Most common (70–90% of parenchymal NCC). Focal (partial) > generalised. "
"Occur as cyst degenerates (stage 2-3) due to perilesional oedema and irritation."],
["Headache / raised ICP", "Intraventricular or subarachnoid cysts obstructing CSF flow. "
"Hydrocephalus, papilloedema."],
["Focal neurological deficits", "Depend on lesion location: hemiparesis, aphasia, visual field defects."],
["Meningitis syndrome", "Subarachnoid/racemose NCC: neck stiffness, fever, CSF pleocytosis (eosinophils)."],
["Dementia / cognitive decline", "Multiple parenchymal cysts; diffuse cerebral involvement."],
["Hydrocephalus", "Intraventricular cysts block foramen of Monro or aqueduct; ependymitis."],
["Spinal cord features", "Radiculopathy, myelopathy; mimics intraspinal tumour."],
["Ocular features", "Floaters, visual loss, retinal detachment (vitreous/subretinal cysts)."],
["Asymptomatic", "Many infections are incidentally found; calcified lesions often silent."],
]
story.append(two_col_table(clinical_rows, col_headers=["Manifestation", "Pathological Basis"],
col_widths=[4.5*cm, 12*cm]))
story.append(sp())
story.append(Paragraph(
"<b>Note for pathologists:</b> The timing of symptoms correlates with cyst stage. "
"Viable cysts (stage 1) are often asymptomatic due to immune evasion. "
"Symptoms peak when the dying larva triggers the host inflammatory cascade (stages 2–3). "
"Stage 4 calcified lesions are the most common autopsy/biopsy finding.",
styles["body"]))
story.append(sp(2))
# ============================================================
# 7. DIAGNOSIS
# ============================================================
story.append(section_header("7. DIAGNOSIS"))
story.append(sp())
story.append(Paragraph("<b>A. Neuroimaging</b>", styles["h2"]))
for txt in [
"<b>CT scan:</b> Preferred for detecting calcified lesions (stage 4). Shows hyperdense nodules without edema or contrast enhancement. Also shows ring-enhancing lesions and hydrocephalus.",
"<b>MRI:</b> Gold standard for active lesions. T1: cystic lesion with hyperintense scolex. T2/FLAIR: perilesional oedema in stages 2-3. Post-contrast: ring enhancement (stage 2), nodular enhancement (stage 3). No signal/enhancement (stage 4).",
"<b>Susceptibility-Weighted Imaging (SWI):</b> Most sensitive MRI sequence for detecting small calcific foci.",
"<b>'Hole-with-dot' sign:</b> Pathognomonic – cystic lesion with eccentric hyperintense scolex on T1 MRI.",
"<b>Racemose NCC:</b> Lobulated cysts in cisterns without scolex; may mimic arachnoid cyst.",
]:
story.append(bullet(txt))
story.append(sp())
story.append(Paragraph("<b>B. Serology</b>", styles["h2"]))
for txt in [
"<b>EITB (Enzyme-linked Immunotransfer Blot):</b> Recommended confirmatory test. Detects IgG antibodies to T. solium glycoprotein antigens. Sensitivity ~94–98% (with ≥2 cysts); lower with single or calcified cysts.",
"<b>ELISA:</b> Widely used but less specific than EITB.",
"<b>CSF antibody detection:</b> More sensitive than serum in subarachnoid NCC.",
"<b>Important:</b> A negative serological test does NOT exclude NCC, especially with a single or calcified lesion.",
]:
story.append(bullet(txt))
story.append(sp())
story.append(Paragraph("<b>C. CSF Analysis</b>", styles["h2"]))
csf_rows = [
["Appearance", "Clear; xanthochromic in severe cases"],
["Cells", "Lymphocytic or eosinophilic pleocytosis (especially in meningeal NCC)"],
["Protein", "Mildly elevated"],
["Glucose", "May be low (subarachnoid NCC)"],
["Specific Ab", "EITB on CSF – high sensitivity in meningeal/subarachnoid disease"],
]
story.append(two_col_table(csf_rows, col_headers=["Parameter", "Finding"],
col_widths=[4*cm, 12.5*cm]))
story.append(sp())
story.append(Paragraph("<b>D. Histopathology / Biopsy</b>", styles["h2"]))
for txt in [
"Rarely required; reserved for atypical or solitary lesions mimicking malignancy.",
"Identifies cysticercus by its pathognomonic laminated tegument and scolex with hooklets on H&E.",
"Stage determines extent of inflammation and appropriate management.",
"Hooklets of T. solium measure ~160 µm and have a characteristic sickle shape – may persist in calcified lesions.",
"Differential includes: tuberculoma, pyogenic abscess, CNS lymphoma, metastasis, primary brain tumour.",
]:
story.append(bullet(txt))
story.append(sp())
story.append(Paragraph("<b>E. Del Brutto Diagnostic Criteria (2017 IDSA/ASTMH revised)</b>", styles["h2"]))
story.append(Paragraph(
"Diagnosis uses a combination of absolute, major, minor, and epidemiological criteria. "
"<b>Absolute criteria</b> (definitive diagnosis) include histopathological demonstration of parasite "
"from CNS biopsy, cystic lesion with scolex on imaging, or direct visualization of subretinal cysticercus. "
"<b>Major criteria</b> include highly suggestive lesions on neuroimaging, positive EITB, resolution of cysts "
"after antiparasitic therapy. <b>Minor criteria</b> include lesions compatible with NCC on neuroimaging, "
"compatible clinical manifestations, positive CSF ELISA.",
styles["body"]))
story.append(sp(2))
# ============================================================
# 8. DIFFERENTIAL DIAGNOSIS
# ============================================================
story.append(section_header("8. DIFFERENTIAL DIAGNOSIS"))
story.append(sp())
dd_rows = [
["Tuberculoma", "Similar ring-enhancing lesion; central caseous necrosis; AFB stain/culture; TB history; PPD/IGRA positive"],
["Pyogenic brain abscess", "Restricted diffusion (ADC map hypointense centre); neutrophilic CSF; fever; source of infection"],
["CNS Toxoplasmosis", "HIV/immunosuppressed; multiple deep white matter lesions; anti-Toxoplasma IgG; responds to empirical therapy"],
["Primary CNS Lymphoma", "Periventricular; EBV+; homogeneous enhancement; ADC low; no parasitic features on biopsy"],
["Metastatic carcinoma", "Known primary; multiple ring-enhancing; no scolex; no improvement with antiparasitics"],
["Arachnoid cyst", "No enhancement; no scolex; no surrounding oedema; stable on imaging"],
["Epidermoid cyst", "Restricted diffusion; DWI bright; no scolex; arises from cisterns"],
["Echinococcosis (Hydatid)", "Single large cyst; 'water-lily sign' on collapse; echinococcal serology; no scolex of T. solium morphology"],
["Rasmussen encephalitis", "Progressive epilepsy; cortical atrophy; no cystic lesion; autoimmune"],
]
story.append(two_col_table(dd_rows, col_headers=["Differential", "Distinguishing Features"],
col_widths=[4.5*cm, 12*cm]))
story.append(sp(2))
# ============================================================
# 9. TREATMENT
# ============================================================
story.append(section_header("9. TREATMENT"))
story.append(sp())
story.append(Paragraph(
"Treatment is <b>stage-dependent</b> and must account for lesion number, location, viability, "
"and presence of hydrocephalus. All treatment decisions should ideally be made with an "
"infectious disease specialist or neurologist.",
styles["body"]))
story.append(sp())
tx_rows = [
["Form", "Sub-group", "Recommendation"],
["Parenchymal – Viable/Enhancing (Stages 1-3)", "1–2 cysts",
"Albendazole monotherapy (15 mg/kg/day ÷ 2 doses × 10–14 days) + Corticosteroids"],
["", ">2 cysts",
"Albendazole + Praziquantel (50 mg/kg/day × 10–14 days) + Corticosteroids"],
["Parenchymal – Calcified (Stage 4)", "Any number",
"NO antiparasitic therapy. Treat seizures with AEDs"],
["NCC Encephalitis (diffuse oedema)", "Any",
"NO antiparasitic. Corticosteroids; treat raised ICP"],
["Intraventricular NCC", "Surgical feasible",
"Neuroendoscopic removal (3rd/4th ventricle); no antiparasitic if removal successful"],
["", "Not feasible",
"VP shunt first, then antiparasitic + corticosteroids"],
["Subarachnoid NCC", "With hydrocephalus",
"VP shunt first, then prolonged albendazole ± praziquantel"],
["Spinal NCC", "Intra/extramedullary",
"Surgical removal or antiparasitic + corticosteroids (individualised)"],
["Ocular NCC", "Any",
"Surgical resection. Antiparasitics CONTRAINDICATED (worsens inflammation in eye)"],
]
head_s2 = ParagraphStyle("th3", fontSize=8.5, textColor=colors.white,
fontName="Helvetica-Bold", leading=12)
cell_s2 = ParagraphStyle("td2", fontSize=8.5, textColor=TEXT_BLACK, leading=12)
tx_fmt = []
for i, row in enumerate(tx_rows):
if i == 0:
tx_fmt.append([Paragraph(c, head_s2) for c in row])
else:
tx_fmt.append([Paragraph(c, cell_s2) for c in row])
tx_t = Table(tx_fmt, colWidths=[4.5*cm, 3*cm, 9*cm], repeatRows=1)
tx_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("ROWBACKGROUNDS", (0,1), (-1,-1), [colors.white, PALE_GREY]),
("GRID", (0,0), (-1,-1), 0.4, MED_GREY),
("VALIGN", (0,0), (-1,-1), "TOP"),
("SPAN", (0,1), (0,2)), ("SPAN", (1,5), (1,6)),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
]))
story.append(tx_t)
story.append(sp())
story.append(Paragraph(
"<b>Adapted from:</b> IDSA/ASTMH Clinical Practice Guidelines 2017 "
"(White AC et al., Clin Infect Dis 2018); Garcia HH et al., Clin Microbiol Rev 2002.",
styles["ref"]))
story.append(sp(2))
# ============================================================
# 10. KEY POINTS / EXAM MNEMONICS
# ============================================================
story.append(section_header("10. KEY POINTS & EXAM MNEMONICS"))
story.append(sp())
story.append(key_box([
"NCC is the MOST COMMON parasitic disease of the CNS worldwide.",
"NCC is the LEADING CAUSE of symptomatic/acquired epilepsy globally.",
"Transmission = EGGS via fecal-oral route (NOT from eating pork — that causes intestinal taeniasis).",
"The pathognomonic morphological feature = SCOLEX inside cyst ('hole-with-dot sign' on MRI T1).",
"Cyst wall = laminated eosinophilic PAS-positive tegument — key histological identification.",
"4 Stages: Vesicular → Colloidal → Granulonodular → Nodular-Calcified.",
"CALCIFIED LESIONS do NOT need antiparasitic therapy.",
"Corticosteroids ALWAYS precede antiparasitic therapy (prevent inflammatory flare).",
"Ocular NCC: antiparasitics are CONTRAINDICATED — only surgical resection.",
"EITB is the recommended confirmatory serological test (not routine ELISA).",
"Susceptibility-weighted MRI (SWI) is the MOST SENSITIVE sequence for calcific foci.",
], title="HIGH-YIELD KEY POINTS", border_color=DARK_BLUE))
story.append(sp())
mnem_data = [
[Paragraph("<b>VESICULAR mnemonic: 'VITAL LARVA, NO FIGHT'</b>",
ParagraphStyle("mn", fontSize=9.5, textColor=ACCENT_GREEN, leading=13))],
[Paragraph("Viable larva → host has not yet mounted immune response → No inflammation, no oedema, no enhancement",
ParagraphStyle("mnd", fontSize=9, textColor=TEXT_BLACK, leading=13))],
[Spacer(1, 0.2*cm)],
[Paragraph("<b>STAGES mnemonic: 'VCal-GN-NC'</b>",
ParagraphStyle("mn2", fontSize=9.5, textColor=ACCENT_GREEN, leading=13))],
[Paragraph("<b>V</b>esicular → <b>C</b>olloidal → <b>G</b>ranulo<b>N</b>odular → <b>N</b>odular-<b>C</b>alcified",
ParagraphStyle("mn2d", fontSize=9, textColor=TEXT_BLACK, leading=13))],
[Spacer(1, 0.2*cm)],
[Paragraph("<b>TREATMENT mnemonic: 'ABC' for viable cysts</b>",
ParagraphStyle("mn3", fontSize=9.5, textColor=ACCENT_GREEN, leading=13))],
[Paragraph("<b>A</b>lbendazole + <b>B</b>etamethasone/dexamethasone (corticosteroid) + "
"<b>C</b>ount cysts (1-2 = monotherapy; >2 = add praziquantel)",
ParagraphStyle("mn3d", fontSize=9, textColor=TEXT_BLACK, leading=13))],
]
mnem_t = Table(mnem_data, colWidths=[W - 4*cm])
mnem_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), colors.HexColor("#F0FFF4")),
("BOX", (0,0), (-1,-1), 1, ACCENT_GREEN),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
story.append(mnem_t)
story.append(sp(2))
# ============================================================
# 11. PREVENTION & EPIDEMIOLOGY
# ============================================================
story.append(section_header("11. PREVENTION AND EPIDEMIOLOGY"))
story.append(sp())
for txt in [
"<b>Global burden:</b> ~2.5–3 million people affected; 50,000 deaths/year attributable to NCC.",
"<b>Endemic areas:</b> Most of sub-Saharan Africa, Latin America, South/Southeast Asia, and the Indian subcontinent.",
"<b>Emerging in developed countries</b> due to immigration from endemic regions and international travel.",
"<b>Food safety:</b> Cook pork to internal temperature ≥56°C for 5 min, or freeze at -20°C for 7–10 days (destroys cysticerci).",
"<b>Water/food hygiene:</b> Proper hand washing, access to clean water, avoidance of raw vegetables fertilised with human waste.",
"<b>Sanitation:</b> Proper disposal of human feces to break the transmission cycle.",
"<b>Animal reservoir control:</b> Mass chemotherapy of pigs + vaccination of pigs with TSOL18 vaccine (recombinant oncosphere antigen).",
"<b>Human carrier treatment:</b> Single-dose niclosamide or praziquantel (5–10 mg/kg) for intestinal taeniasis reduces egg shedding.",
"<b>Screening of food handlers</b> in endemic areas is a public health priority.",
]:
story.append(bullet(txt))
story.append(sp(2))
# ============================================================
# 12. REFERENCES
# ============================================================
story.append(HRFlowable(width="100%", thickness=1, color=MED_GREY, spaceBefore=4, spaceAfter=8))
story.append(Paragraph("<b>References</b>", styles["h2"]))
refs = [
"Harrison's Principles of Internal Medicine, 22nd Edition (2025). McGraw-Hill Medical. Chapter 145.",
"Goldman-Cecil Medicine, International Edition. Elsevier. Chapter 325.",
"Bradley and Daroff's Neurology in Clinical Practice, 8th Edition. Elsevier. Chapters 47 & 79.",
"Tintinalli's Emergency Medicine: A Comprehensive Study Guide, 9th Edition. McGraw-Hill.",
"Grainger & Allison's Diagnostic Radiology: A Textbook of Medical Imaging. Elsevier.",
"Washington Manual of Medical Therapeutics, 36th Edition. Wolters Kluwer.",
"Medical Microbiology, 9th Edition (Murray et al.). Elsevier. Chapter 76.",
"White AC et al. Diagnosis and Treatment of Neurocysticercosis: 2017 Clinical Practice Guidelines "
"by IDSA and ASTMH. Clin Infect Dis. 2018;66(8):e49–e75.",
"Del Brutto OH. Revised diagnostic criteria for neurocysticercosis. J Neurol Sci. 2012;321:25–30.",
"Garcia HH et al. Neurocysticercosis: updated concepts about an old disease. Lancet Neurol. 2005;4:653–661.",
]
for r in refs:
story.append(Paragraph(f"• {r}", styles["ref"]))
story.append(sp(2))
story.append(HRFlowable(width="100%", thickness=1, color=DARK_BLUE, spaceAfter=4))
story.append(Paragraph(
"Compiled by Orris Medical AI • For MD Pathology Academic Use Only • Not for clinical decision-making",
ParagraphStyle("footer", fontSize=7.5, textColor=colors.HexColor("#888888"),
alignment=TA_CENTER, leading=10)))
# ── BUILD ──────────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF created: {out_path}")
cd /home/daytona/workspace/ncc-pdf && python3 make_ncc_pdf.py 2>&1