Learn about Parkinsonism
Parkinson disease pathology Lewy bodies substantia nigra

This composite image presents neuropathological findings from two siblings with Parkinson’s disease. Panel A contains macroscopic brain specimens: images 1 and 2 show the substantia nigra and cerebellum with evidence of depigmentation; images 3 and 4 display coronal sections through the basal ganglia and cortical regions, demonstrating mild ventricular enlargement and cortical atrophy. Panel B presents microscopic immunohistochemistry for alpha-synuclein pathology. Images B1 and B3 illustrate the substantia nigra, highlighting dark-stained Lewy neurites (thread-like processes) and classical Lewy bodies (rounded cytoplasmic inclusions). Images B2 and B4 show cortical sections containing cortical Lewy bodies, which appear as less defined, round inclusions within neuronal soma. The pathology demonstrates the characteristic widespread distribution of alpha-synuclein aggregates in genetic or familial Parkinson’s disease, involving both brainstem and cortical regions. This visual resource is intended for educational use in neurology and pathology to distinguish between macroscopic neurodegeneration and microscopic proteinaceous inclusions.

Educational medical illustration titled 'Neurodegenerative Diseases and Types of Neurons Affected' featuring a sagittal cross-section of the human brain alongside specialized neuronal diagrams. The brain section highlights key anatomical areas susceptible to degeneration: the striatum (green) for Huntington’s Disease (HD), cortical and hippocampal regions (pink neurons) for Alzheimer’s Disease (AD), the substantia nigra and midbrain (red) for Parkinson’s Disease (PD), and the brainstem and spinal pathways (orange) for Amyotrophic Lateral Sclerosis (ALS). The diagram categorizes specific neuronal vulnerabilities: Medium Spiny Neurons in HD, Pyramidal neurons in AD, and Motor neuron degeneration in ALS. For Parkinson's Disease, detailed insets illustrate the pathophysiology of dopaminergic neurons, showing the impairment and loss of melanated cells, alpha-synuclein protein aggregation, and the formation of Lewy bodies. The visual serves as a summary of the neuroanatomical localization and cellular pathology characteristic of major neurodegenerative disorders.

This medical schematic diagram illustrates the Braak staging model of alpha-synuclein pathology progression in Parkinson's disease. The image features a sagittal view of the human brain overlaid with color-coded regions and directional arrows to depict the caudo-rostral spread of Lewy bodies and Lewy neurites. The progression is categorized into six stages starting from a blue arrow representing the peripheral and enteric nervous systems. The pathological ascent is shown sequentially through the medulla oblongata (orange), the pontine tegmentum (green), and into the basal midbrain and forebrain (pink), which includes the substantia nigra. From these subcortical structures, yellow arrows indicate the spread to the temporal mesocortex and allocortex (light yellow), eventually reaching the neocortex (grey) as shown by white arrows. This visual model highlights how neurodegeneration moves from the lower brainstem to higher cortical regions, correlating with the clinical transition from motor symptoms to cognitive dysfunction and dementia.

This composite educational graphic presents multi-modal diagnostic data investigating 18F-AV-1451 (tau PET tracer) retention in neurodegenerative synucleinopathies compared to Alzheimer’s Disease (AD).
Parkinsonism clinical features tremor rigidity bradykinesia posture
Parkinson disease management guidelines
| Category | Examples |
|---|---|
| Parkinson's Disease (PD) | Sporadic (most common), Genetic (SNCA, LRRK2, Parkin, PINK1, DJ-1) |
| Atypical Parkinsonism | Multiple System Atrophy (MSA-c, MSA-p), Progressive Supranuclear Palsy (PSP), Corticobasal Syndrome |
| Secondary Parkinsonism | Drug-induced, Vascular, Tumor, Infection, Normal-pressure hydrocephalus, Trauma, Toxins (MPTP, CO, manganese, cyanide) |
| Other Neurodegenerative | Wilson's disease, Huntington's disease, Alzheimer's with parkinsonism, Prion diseases, SCA3 |


| Gene (PARK locus) | Inheritance | Protein | Notes |
|---|---|---|---|
| SNCA (PARK1) | Autosomal Dominant | Alpha-synuclein | Rare; missense + duplications/triplications |
| Parkin (PARK2) | Autosomal Recessive | Parkin | Up to 50% of early-onset PD |
| PINK1 (PARK6) | Autosomal Recessive | PTEN-induced kinase 1 | Early onset |
| DJ-1 (PARK7) | Autosomal Recessive | DJ-1 | Early onset |
| LRRK2 (PARK8) | Autosomal Dominant | LRRK2 (dardarin) | Common in North Africans, Ashkenazi Jews |

| Condition | Key Features |
|---|---|
| MSA-P (Striatonigral degeneration) | Parkinsonism + autonomic failure + cerebellar features; symmetric onset |
| MSA-C (Olivopontocerebellar atrophy) | Predominantly cerebellar ataxia + parkinsonism |
| PSP (Progressive Supranuclear Palsy) | Vertical gaze palsy, early falls, neck rigidity, symmetric |
| Corticobasal Syndrome | Asymmetric, limb apraxia, cortical sensory loss, alien limb phenomenon |
| DLB (Dementia with Lewy Bodies) | Dementia before/concurrently with parkinsonism, visual hallucinations, fluctuating cognition |
Make a diagnosis flowchart for differentiating PD from atypical parkinsonism syndromes
mkdir -p /tmp/workspace/parkinsonism-flowchart && ls /tmp/workspace/parkinsonism-flowchart/
~/parkinsonism-flowchart/flowchart.py
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.patches import FancyBboxPatch, FancyArrowPatch
import textwrap
fig, ax = plt.subplots(figsize=(26, 34))
ax.set_xlim(0, 26)
ax.set_ylim(0, 34)
ax.axis('off')
fig.patch.set_facecolor('#F7F9FC')
# ── colour palette ──────────────────────────────────────────────────────────
C_START = '#1A3A5C' # dark navy – entry node
C_QUESTION= '#2471A3' # medium blue – decision diamonds
C_SECONDARY='#117A65' # teal – secondary parkinsonism
C_PD = '#1E8449' # green – PD confirmed
C_MSA = '#6C3483' # purple – MSA
C_PSP = '#922B21' # red – PSP
C_CBS = '#B7950B' # gold – CBS
C_DLB = '#1A5276' # dark blue – DLB
C_ARROW = '#555555'
C_REDFLG = '#C0392B'
C_SUPPORT = '#1A6F24'
TEXT_LIGHT= 'white'
TEXT_DARK = '#1A1A1A'
def box(ax, cx, cy, w, h, text, facecolor, textcolor=TEXT_LIGHT,
fontsize=9, bold=False, style='round,pad=0.15', wrap=True,
linespacing=1.4):
rx, ry = cx - w/2, cy - h/2
fancy = FancyBboxPatch((rx, ry), w, h,
boxstyle=style,
facecolor=facecolor,
edgecolor='white', linewidth=1.5,
zorder=3)
ax.add_patch(fancy)
if wrap:
lines = textwrap.wrap(text, width=int(w*8.5))
text_to_show = '\n'.join(lines)
else:
text_to_show = text
ax.text(cx, cy, text_to_show,
ha='center', va='center', fontsize=fontsize,
color=textcolor, fontweight='bold' if bold else 'normal',
linespacing=linespacing, zorder=4,
multialignment='center')
def diamond(ax, cx, cy, w, h, text, facecolor, textcolor=TEXT_LIGHT, fontsize=8.5):
from matplotlib.patches import Polygon
pts = [(cx, cy+h/2), (cx+w/2, cy), (cx, cy-h/2), (cx-w/2, cy)]
poly = Polygon(pts, closed=True, facecolor=facecolor,
edgecolor='white', linewidth=1.5, zorder=3)
ax.add_patch(poly)
lines = textwrap.wrap(text, width=int(w*7))
ax.text(cx, cy, '\n'.join(lines),
ha='center', va='center', fontsize=fontsize,
color=textcolor, fontweight='bold', zorder=4,
multialignment='center', linespacing=1.3)
def arrow(ax, x1, y1, x2, y2, label='', label_side='right', color=C_ARROW):
ax.annotate('', xy=(x2, y2), xytext=(x1, y1),
arrowprops=dict(arrowstyle='->', color=color,
lw=1.8, connectionstyle='arc3,rad=0'),
zorder=2)
if label:
mx, my = (x1+x2)/2, (y1+y2)/2
offset = 0.18 if label_side == 'right' else -0.18
ax.text(mx + offset, my, label, ha='center', va='center',
fontsize=7.5, color=color, fontweight='bold',
bbox=dict(facecolor='white', edgecolor='none', alpha=0.85, pad=1))
def label_on_arrow(ax, x, y, text, color='#333333'):
ax.text(x, y, text, ha='center', va='center', fontsize=7.5,
color=color, fontweight='bold',
bbox=dict(facecolor='white', edgecolor='none', alpha=0.9, pad=1.5))
# ── TITLE ────────────────────────────────────────────────────────────────────
ax.text(13, 33.4,
'Differential Diagnosis: Parkinson\'s Disease vs. Atypical Parkinsonism Syndromes',
ha='center', va='center', fontsize=15, fontweight='bold', color='#1A3A5C')
ax.text(13, 33.0,
'Based on MDS Clinical Diagnostic Criteria | Harrison\'s & Bradley\'s Neurology',
ha='center', va='center', fontsize=8.5, color='#555555', style='italic')
# ── ROW 0: Entry ─────────────────────────────────────────────────────────────
box(ax, 13, 32.2, 9, 0.7,
'PATIENT PRESENTS WITH PARKINSONISM\n(Bradykinesia + Rigidity and/or Rest Tremor)',
C_START, fontsize=10, bold=True)
arrow(ax, 13, 31.85, 13, 31.3)
# ── ROW 1: Exclude secondary ─────────────────────────────────────────────────
diamond(ax, 13, 30.8, 9.5, 1.0,
'Identifiable secondary cause?\n(Drugs · Vascular · Toxins · Tumor · NPH · Infection · Metabolic)',
C_QUESTION, fontsize=8.5)
# YES → left branch
arrow(ax, 8.25, 30.8, 4.5, 30.8, color=C_SECONDARY)
label_on_arrow(ax, 6.3, 30.95, 'YES', color=C_SECONDARY)
box(ax, 3.0, 30.8, 2.8, 0.75,
'SECONDARY\nPARKINSONISM\n(Treat underlying cause)',
C_SECONDARY, fontsize=8)
# NO ↓
arrow(ax, 13, 30.3, 13, 29.65)
label_on_arrow(ax, 13.5, 29.95, 'NO', color='#333')
# ── ROW 2: Levodopa trial ─────────────────────────────────────────────────────
diamond(ax, 13, 29.2, 9.5, 0.9,
'Sustained, marked response to Levodopa trial?',
C_QUESTION)
# YES ↓ (tentative PD direction)
arrow(ax, 13, 28.75, 13, 28.1)
label_on_arrow(ax, 13.5, 28.4, 'YES', color='#333')
# POOR RESPONSE → right
arrow(ax, 17.75, 29.2, 21.5, 29.2, color=C_MSA)
label_on_arrow(ax, 19.6, 29.35, 'POOR / NO', color=C_MSA)
box(ax, 23.0, 29.2, 3.6, 0.75,
'Consider Atypical\nParkinsonism ↓',
C_MSA, fontsize=8)
# ── ROW 3: Red flags check ───────────────────────────────────────────────────
box(ax, 13, 27.55, 11, 1.05,
'Check for RED FLAGS (if present, must be outweighed by supportive features)',
C_REDFLG, fontsize=8.5, bold=True)
# Red flag detail box
redflags_text = (
"• Early severe autonomic failure (within 1st year)\n"
"• Recurrent falls in first year\n"
"• Supranuclear vertical gaze palsy\n"
"• Cerebellar signs\n"
"• Bilateral symmetric onset\n"
"• Rapid progression to wheelchair ≤5 yrs\n"
"• Absence of non-motor features of PD\n"
"• Inspiratory stridor / respiratory disturbance\n"
"• Alien limb phenomenon / apraxia\n"
"• Levodopa-induced severe dyskinesias absent"
)
ax.text(7.8, 25.8, redflags_text,
ha='left', va='top', fontsize=7.8, color='#6B0000',
bbox=dict(facecolor='#FFF5F5', edgecolor='#C0392B',
linewidth=1.2, boxstyle='round,pad=0.5'),
linespacing=1.5, zorder=4)
ax.text(7.5, 26.95, 'RED FLAGS:', ha='left', va='center',
fontsize=8, color=C_REDFLG, fontweight='bold')
# Supportive features box
support_text = (
"• Unilateral onset\n"
"• Clear rest tremor (pill-rolling)\n"
"• Excellent & sustained levodopa response\n"
"• Levodopa-induced dyskinesias\n"
"• Anosmia / hyposmia\n"
"• Cardiac sympathetic denervation (MIBG)\n"
"• Asymmetric striatal DAT loss (DaTscan)\n"
"• REM sleep behaviour disorder (RBD)"
)
ax.text(15.0, 25.8, support_text,
ha='left', va='top', fontsize=7.8, color='#0A4A1A',
bbox=dict(facecolor='#F0FFF4', edgecolor='#1E8449',
linewidth=1.2, boxstyle='round,pad=0.5'),
linespacing=1.5, zorder=4)
ax.text(15.0, 26.95, 'SUPPORTIVE FEATURES:', ha='left', va='center',
fontsize=8, color=C_SUPPORT, fontweight='bold')
arrow(ax, 13, 27.02, 13, 24.5)
# ── ROW 4: Diagnostic decision ───────────────────────────────────────────────
diamond(ax, 13, 24.0, 9.5, 0.9,
'Red flags absent OR outweighed by ≥2 supportive features?',
C_QUESTION)
# YES ↓ → PD
arrow(ax, 13, 23.55, 13, 22.85)
label_on_arrow(ax, 13.5, 23.2, 'YES', color='#333')
box(ax, 13, 22.4, 7.5, 0.8,
'CLINICALLY ESTABLISHED PARKINSON\'S DISEASE',
C_PD, fontsize=10, bold=True)
# PD features sub-box
pd_detail = (
"Imaging: DaTscan – asymmetric posterior putamen ↓ dopamine uptake\n"
"Pathology: Lewy bodies (α-synuclein) in SNc | SNc depigmentation\n"
"Genetics: Consider SNCA, LRRK2, Parkin, PINK1, DJ-1 if onset <50 yrs\n"
"Progression: Usually slow; responds to levodopa for years"
)
ax.text(13, 21.65, pd_detail,
ha='center', va='center', fontsize=8, color='#0A3A1A',
bbox=dict(facecolor='#EAF9ED', edgecolor=C_PD, linewidth=1, boxstyle='round,pad=0.4'),
linespacing=1.5, zorder=4)
# NO → right: Atypical parkinsonism pathway
arrow(ax, 17.75, 24.0, 21.5, 24.0, color=C_MSA)
label_on_arrow(ax, 19.6, 24.15, 'NO / FLAG', color=C_MSA)
# ── ATYPICAL PARKINSONISM COLUMN ──────────────────────────────────────────────
ax.text(23.0, 27.7, 'ATYPICAL PARKINSONISM', ha='center', va='center',
fontsize=9, fontweight='bold', color='white',
bbox=dict(facecolor='#922B21', edgecolor='white', linewidth=1.5,
boxstyle='round,pad=0.4'), zorder=4)
arrow(ax, 23.0, 27.35, 23.0, 26.7, color=C_REDFLG)
# sub-question
diamond(ax, 23.0, 26.2, 5.5, 0.9,
'Key distinguishing features?',
'#7D3C98')
# Arrows downward from diamond to 4 boxes
arrow(ax, 23.0, 25.75, 23.0, 25.15, color='#555')
# ── 4 Atypical boxes ─────────────────────────────────────────────────────────
# PSP
box(ax, 20.2, 24.45, 4.5, 1.1,
'PSP\n(Progressive Supranuclear Palsy)',
C_PSP, fontsize=8, bold=True)
psp_txt = ("↑ Vertical gaze palsy\n"
"↑ Early falls (retropulsion)\n"
"↑ Axial > limb rigidity\n"
"↑ Neck hyperextension\n"
"→ Hummingbird sign (MRI)")
ax.text(20.2, 23.5, psp_txt, ha='center', va='top', fontsize=7.5,
color='#4A0E09',
bbox=dict(facecolor='#FDEDEC', edgecolor=C_PSP, linewidth=0.8,
boxstyle='round,pad=0.3'), linespacing=1.4, zorder=4)
# MSA
box(ax, 25.0, 24.45, 4.5, 1.1,
'MSA\n(Multiple System Atrophy)',
C_MSA, fontsize=8, bold=True)
msa_txt = ("↑ Early autonomic failure\n"
"↑ Cerebellar signs (MSA-C)\n"
"↑ Inspiratory stridor\n"
"↑ Rapid progression\n"
"→ Hot cross bun sign (MRI)")
ax.text(25.0, 23.5, msa_txt, ha='center', va='top', fontsize=7.5,
color='#3B1A5A',
bbox=dict(facecolor='#F5EEF8', edgecolor=C_MSA, linewidth=0.8,
boxstyle='round,pad=0.3'), linespacing=1.4, zorder=4)
# CBS
box(ax, 20.2, 22.1, 4.5, 1.1,
'CBS\n(Corticobasal Syndrome)',
C_CBS, fontsize=8, bold=True)
cbs_txt = ("↑ Alien limb phenomenon\n"
"↑ Cortical sensory loss\n"
"↑ Limb apraxia\n"
"↑ Asymmetric limb dystonia\n"
"→ Asymmetric cortical atrophy")
ax.text(20.2, 21.15, cbs_txt, ha='center', va='top', fontsize=7.5,
color='#4A3B00',
bbox=dict(facecolor='#FDFCE0', edgecolor=C_CBS, linewidth=0.8,
boxstyle='round,pad=0.3'), linespacing=1.4, zorder=4)
# DLB
box(ax, 25.0, 22.1, 4.5, 1.1,
'DLB\n(Dementia with Lewy Bodies)',
C_DLB, fontsize=8, bold=True)
dlb_txt = ("↑ Dementia before/≤1yr motor\n"
"↑ Recurrent visual hallucinations\n"
"↑ Fluctuating cognition\n"
"↑ Neuroleptic sensitivity\n"
"→ Reduced MIBG uptake")
ax.text(25.0, 21.15, dlb_txt, ha='center', va='top', fontsize=7.5,
color='#0A2A40',
bbox=dict(facecolor='#EAF2FF', edgecolor=C_DLB, linewidth=0.8,
boxstyle='round,pad=0.3'), linespacing=1.4, zorder=4)
# Small arrows from diamond to atypical boxes
arrow(ax, 21.0, 25.75, 20.2, 24.95, color='#777')
arrow(ax, 23.0, 25.75, 25.0, 24.95, color='#777')
ax.annotate('', xy=(20.2, 22.6), xytext=(20.2, 23.85),
arrowprops=dict(arrowstyle='->', color='#777', lw=1.5), zorder=2)
ax.annotate('', xy=(25.0, 22.6), xytext=(25.0, 23.85),
arrowprops=dict(arrowstyle='->', color='#777', lw=1.5), zorder=2)
# ── INVESTIGATION BOX ─────────────────────────────────────────────────────────
inv_text = (
"KEY INVESTIGATIONS\n\n"
"• DaTscan / FP-CIT SPECT: Reduced & asymmetric posterior putamen uptake in PD/APS (not in drug-induced or ET)\n"
"• Brain MRI: Normal in PD | Hummingbird sign (PSP) | Hot cross bun sign (MSA) | Asymm. cortical atrophy (CBS)\n"
"• MIBG cardiac scintigraphy: Reduced in PD & DLB; typically preserved in MSA/PSP\n"
"• Autonomic testing: Tilt-table, urodynamics (severe early failure → MSA)\n"
"• Neuropsychology: Profile differs — subcortical (PD) vs. frontal (PSP) vs. cortical (CBS/DLB)\n"
"• Levodopa challenge (≥600 mg/day × 4 wks): ≥30% UPDRS improvement = strong PD support\n"
"• Genetics: SNCA, LRRK2, Parkin, PINK1, GBA1 — consider if age <50 or family history"
)
ax.text(13, 19.5, inv_text,
ha='center', va='center', fontsize=8.5, color='#1A1A1A',
bbox=dict(facecolor='#EEF4FB', edgecolor='#2471A3', linewidth=1.5,
boxstyle='round,pad=0.6'), linespacing=1.6, zorder=4)
arrow(ax, 13, 21.0, 13, 20.55, color='#2471A3')
# ── OUTCOME / TREATMENT GUIDANCE ─────────────────────────────────────────────
tx_text = (
"TREATMENT IMPLICATIONS\n\n"
"PD: Levodopa/carbidopa (gold standard) · Dopamine agonists · MAO-B inhibitors · DBS for advanced motor fluctuations\n"
"PSP / CBS: Poor levodopa response · Supportive care · Physiotherapy · Falls prevention\n"
"MSA: Modest levodopa response (30-40%) · Treat autonomic failure (fludrocortisone, midodrine) · CPAP for stridor\n"
"DLB: Avoid typical antipsychotics (severe sensitivity) · AChEIs for hallucinations/cognition · Low-dose quetiapine if needed"
)
ax.text(13, 17.5, tx_text,
ha='center', va='center', fontsize=8.5, color='#1A1A1A',
bbox=dict(facecolor='#F0FFF4', edgecolor=C_PD, linewidth=1.5,
boxstyle='round,pad=0.6'), linespacing=1.6, zorder=4)
arrow(ax, 13, 18.45, 13, 18.22, color=C_PD)
# ── LEGEND ───────────────────────────────────────────────────────────────────
legend_items = [
(C_START, 'Entry / Syndrome definition'),
(C_QUESTION, 'Decision point'),
(C_SECONDARY, 'Secondary Parkinsonism'),
(C_PD, "Parkinson's Disease"),
(C_PSP, 'PSP'),
(C_MSA, 'MSA'),
(C_CBS, 'Corticobasal Syndrome'),
(C_DLB, 'Dementia with Lewy Bodies'),
(C_REDFLG, 'Red flags'),
]
lx, ly = 0.5, 16.5
ax.text(lx, ly+0.3, 'LEGEND', ha='left', fontsize=8.5, fontweight='bold', color='#333')
for i, (col, lbl) in enumerate(legend_items):
yy = ly - 0.42 * (i+1)
rect = FancyBboxPatch((lx, yy-0.15), 0.55, 0.30,
boxstyle='round,pad=0.05',
facecolor=col, edgecolor='white', linewidth=0.8, zorder=3)
ax.add_patch(rect)
ax.text(lx+0.7, yy, lbl, ha='left', va='center', fontsize=8, color='#333')
# footer
ax.text(13, 0.25,
'Sources: Harrison\'s Principles of Internal Medicine 22E · Bradley & Daroff\'s Neurology in Clinical Practice · '
'MDS Clinical Diagnostic Criteria for PD (Berg et al.) · Katzung Basic & Clinical Pharmacology 16E',
ha='center', va='center', fontsize=7, color='#777', style='italic')
plt.tight_layout(pad=0.5)
plt.savefig('/tmp/workspace/parkinsonism-flowchart/PD_vs_Atypical_Parkinsonism_Flowchart.png',
dpi=180, bbox_inches='tight', facecolor=fig.get_facecolor())
print("Saved PNG")
plt.savefig('/tmp/workspace/parkinsonism-flowchart/PD_vs_Atypical_Parkinsonism_Flowchart.pdf',
bbox_inches='tight', facecolor=fig.get_facecolor())
print("Saved PDF")
cd /tmp/workspace/parkinsonism-flowchart && python flowchart.py 2>&1
ls -lh /tmp/workspace/parkinsonism-flowchart/
PD vs Atypical Parkinsonism Flowchart
Image · PNG
PD vs Atypical Parkinsonism Flowchart
PDF Document · PDF
Make a clinical vignette workbook with case studies
What format should the workbook be in? · What level is this workbook aimed at? · How many case studies would you like?
Make a clinical vignette workbook with case studies
What format should the workbook be in? · What level is this aimed at? · How many case studies?
Make a clinical vignette workbook with case studies
mkdir -p /tmp/workspace/parkinsonism-workbook && ls /tmp/workspace/parkinsonism-workbook/
Make a clinical vignette workbook with case studies
mkdir -p /tmp/workspace/parkinsonism-workbook
Can you make infographic explaining and differentiateing various forms of parkinsonism
A detailed medical infographic titled "Forms of Parkinsonism: Differentiation Guide" showing 6 distinct panels comparing different types of parkinsonism. The infographic should include: 1. PARKINSON'S DISEASE (PD) - green panel: asymmetric onset, rest tremor (pill-rolling), excellent levodopa response, Lewy bodies (alpha-synuclein), slow progression, anosmia/RBD as premotor features, DaTscan shows asymmetric posterior putamen loss 2. PROGRESSIVE SUPRANUCLEAR PALSY (PSP) - red panel: vertical supranuclear gaze palsy (downward gaze palsy), early falls (retropulsion), axial rigidity, neck hyperextension, "hummingbird sign" on MRI, poor levodopa response, tau pathology 3. MULTIPLE SYSTEM ATROPHY (MSA) - purple panel: early severe autonomic failure (orthostatic hypotension, urinary incontinence), cerebellar ataxia (MSA-C) or parkinsonism (MSA-P), inspiratory stridor, "hot cross bun sign" on MRI, alpha-synuclein in oligodendrocytes, poor levodopa response 4. CORTICOBASAL SYNDROME (CBS) - orange panel: markedly asymmetric, alien limb phenomenon, ideomotor apraxia, cortical sensory loss, myoclonus, limb dystonia, asymmetric cortical atrophy on MRI, tau pathology 5. DEMENTIA WITH LEWY BODIES (DLB) - blue panel: dementia onset before or within 1 year of motor symptoms, recurrent vivid visual hallucinations, fluctuating cognition/alertness, REM sleep behavior disorder, severe neuroleptic sensitivity, reduced MIBG uptake 6. DRUG-INDUCED / SECONDARY PARKINSONISM - gray panel: symmetric onset, history of dopamine antagonist (antipsychotics, metoclopramide), resolves on stopping drug, no DaTscan abnormality, also: vascular (lower-body gait disorder, white matter lesions), toxins (MPTP, manganese) Include a small comparison table at bottom showing: Tremor type, Levodopa response, Onset symmetry, Key imaging finding, Pathology for each type. Clean modern medical style, color-coded, professional clinical reference quality.

Generate a differential diagnosis checklist for rapid clinical assessment
~/parkinsonism-workbook/checklist.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.lib.enums import TA_LEFT, TA_CENTER, TA_RIGHT
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether
)
from reportlab.graphics.shapes import Drawing, Rect, String, Circle, Line
from reportlab.graphics import renderPDF
from reportlab.platypus.flowables import Flowable
import os
OUT = "/tmp/workspace/parkinsonism-workbook/Parkinsonism_DDx_Checklist.pdf"
# ── Colours ──────────────────────────────────────────────────────────────────
NAVY = colors.HexColor("#1A3A5C")
TEAL = colors.HexColor("#117A65")
GREEN = colors.HexColor("#1E8449")
RED = colors.HexColor("#922B21")
PURPLE = colors.HexColor("#6C3483")
ORANGE = colors.HexColor("#B7770D")
STEEL = colors.HexColor("#2471A3")
GREY = colors.HexColor("#566573")
LGREY = colors.HexColor("#F2F3F4")
MGREY = colors.HexColor("#D5D8DC")
WHITE = colors.white
BLACK = colors.HexColor("#1A1A1A")
WARN = colors.HexColor("#C0392B")
GOLD = colors.HexColor("#D4AC0D")
# ── Document ─────────────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
OUT, pagesize=A4,
leftMargin=14*mm, rightMargin=14*mm,
topMargin=14*mm, bottomMargin=14*mm,
title="Parkinsonism Differential Diagnosis Checklist",
author="Orris Medical"
)
W = A4[0] - 28*mm # usable width
# ── Styles ───────────────────────────────────────────────────────────────────
base = getSampleStyleSheet()
def S(name, **kw):
return ParagraphStyle(name, **kw)
sTitle = S("sTitle", fontSize=18, textColor=WHITE, alignment=TA_CENTER,
fontName="Helvetica-Bold", leading=22)
sSub = S("sSub", fontSize=9, textColor=WHITE, alignment=TA_CENTER,
fontName="Helvetica", leading=12)
sH1 = S("sH1", fontSize=11, textColor=WHITE, fontName="Helvetica-Bold",
leading=14, leftIndent=4)
sH2 = S("sH2", fontSize=9, textColor=NAVY, fontName="Helvetica-Bold",
leading=12)
sBody = S("sBody", fontSize=8, textColor=BLACK, fontName="Helvetica",
leading=11, leftIndent=4)
sBold = S("sBold", fontSize=8, textColor=BLACK, fontName="Helvetica-Bold",
leading=11)
sWarn = S("sWarn", fontSize=7.5,textColor=WARN, fontName="Helvetica-Bold",
leading=10)
sNote = S("sNote", fontSize=7, textColor=GREY, fontName="Helvetica",
leading=10, alignment=TA_CENTER)
sSmall = S("sSmall", fontSize=7.5,textColor=BLACK, fontName="Helvetica",
leading=10)
sCheck = S("sCheck", fontSize=8, textColor=BLACK, fontName="Helvetica",
leading=12, leftIndent=8)
# ── Helpers ──────────────────────────────────────────────────────────────────
def coloured_header(text, sub, colour, w=W):
data = [[Paragraph(text, sTitle)], [Paragraph(sub, sSub)]]
t = Table(data, colWidths=[w])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), colour),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("ROWBACKGROUNDS",(0,0),(-1,-1),[colour]),
]))
return t
def section_header(text, colour, w=W):
t = Table([[Paragraph(text, sH1)]], colWidths=[w])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), colour),
("TOPPADDING", (0,0),(-1,-1), 4),
("BOTTOMPADDING", (0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 8),
("RIGHTPADDING", (0,0),(-1,-1), 8),
]))
return t
def checkbox(label, indent=0):
return Paragraph(f"□ {label}", sCheck)
def bullet(label, colour=BLACK):
st = ParagraphStyle("bp", fontSize=8, textColor=colour,
fontName="Helvetica", leading=11, leftIndent=12,
bulletText="•", bulletIndent=4)
return Paragraph(label, st)
def two_col_table(left_rows, right_rows, left_head, right_head,
lc=STEEL, rc=STEEL, w=W):
hw = w / 2 - 1*mm
head_style = S("th", fontSize=8.5, textColor=WHITE,
fontName="Helvetica-Bold", leading=11, alignment=TA_CENTER)
header = [
[Paragraph(left_head, head_style),
Paragraph(right_head, head_style)]
]
rows = []
max_r = max(len(left_rows), len(right_rows))
for i in range(max_r):
lv = left_rows[i] if i < len(left_rows) else ""
rv = right_rows[i] if i < len(right_rows) else ""
rows.append([
checkbox(lv) if lv else Paragraph("", sBody),
checkbox(rv) if rv else Paragraph("", sBody),
])
data = header + rows
cmds = [
("BACKGROUND", (0,0),(0,0), lc),
("BACKGROUND", (1,0),(1,0), rc),
("GRID", (0,0),(-1,-1), 0.3, MGREY),
("TOPPADDING", (0,0),(-1,-1), 2),
("BOTTOMPADDING", (0,0),(-1,-1), 2),
("LEFTPADDING", (0,0),(-1,-1), 4),
("RIGHTPADDING", (0,0),(-1,-1), 4),
("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, LGREY]),
("VALIGN", (0,0),(-1,-1), "TOP"),
]
t = Table(data, colWidths=[hw, hw])
t.setStyle(TableStyle(cmds))
return t
def shaded_box(content_rows, bg=LGREY, border=MGREY, w=W):
data = [[r] for r in content_rows]
t = Table(data, colWidths=[w])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), bg),
("BOX", (0,0),(-1,-1), 0.5, border),
("TOPPADDING", (0,0),(-1,-1), 2),
("BOTTOMPADDING", (0,0),(-1,-1), 2),
("LEFTPADDING", (0,0),(-1,-1), 8),
("RIGHTPADDING", (0,0),(-1,-1), 8),
("VALIGN", (0,0),(-1,-1), "TOP"),
]))
return t
def sp(h=4): return Spacer(1, h)
def hr(): return HRFlowable(width=W, thickness=0.5, color=MGREY)
# ── Comparison mega-table ─────────────────────────────────────────────────────
def comparison_table():
cols = ["Feature", "PD", "PSP", "MSA", "CBS", "DLB", "Drug-Induced"]
col_colours = [NAVY, GREEN, RED, PURPLE, ORANGE, STEEL, GREY]
col_w = [28*mm, 26*mm, 26*mm, 26*mm, 26*mm, 26*mm, 24*mm]
rows_data = [
# Feature, PD, PSP, MSA, CBS, DLB, Drug-Induced
["Tremor",
"Rest, pill-rolling, 4-6 Hz, asymm.",
"Rare; postural if present",
"Postural/action; rest tremor uncommon",
"Postural/action; myoclonus common",
"Rest tremor, mild",
"Rest or none; symmetric"],
["Onset symmetry",
"Asymmetric ✓",
"Symmetric (axial dominant)",
"Symmetric or mild asymm.",
"Markedly asymmetric ✓",
"Symmetric",
"Symmetric ✓"],
["Levodopa response",
"Excellent & sustained ✓",
"Poor/absent",
"Partial (30-40%) then fades",
"Poor/absent",
"Partial; can worsen neuropsych.",
"No dopaminergic deficit"],
["Gaze palsy",
"Absent",
"Vertical (downgaze first) ✓✓",
"Absent",
"May develop horiz. + vert.",
"Absent",
"Absent"],
["Early falls",
"Late (>3 yrs)",
"Within 1st year ✓✓",
"Late (autonomic > falls)",
"Variable",
"Early if motor prominent",
"Variable"],
["Autonomic failure",
"Mild-moderate (late)",
"Mild",
"Severe & early ✓✓",
"Urinary (late)",
"Moderate",
"Drug-related hypotension"],
["Cognitive / neuropsych.",
"Late dementia (PDD)",
"Frontal/executive (early)",
"Mild (late)",
"Apraxia, aphasia, alien limb ✓✓",
"Dementia ≤1 yr of motor ✓✓\nVisual hallucinations ✓✓",
"Absent (drug effect)"],
["Cerebellar signs",
"Absent",
"Absent",
"Ataxia (MSA-C) ✓",
"Absent",
"Absent",
"Absent"],
["Key MRI finding",
"Usually normal",
"Hummingbird / penguin sign",
"Hot cross bun sign (pons)",
"Asymm. frontoparietal atrophy",
"Usually normal or gen. atrophy",
"Normal (WM lesions if vascular)"],
["DaTscan",
"Reduced, asymm. post. putamen",
"Reduced (symmetric)",
"Reduced (symmetric)",
"Reduced (asymmetric)",
"Reduced",
"Normal ✓ (key differentiator)"],
["MIBG cardiac",
"Reduced ✓",
"Preserved",
"Preserved",
"Preserved",
"Reduced ✓",
"Preserved"],
["Pathology",
"Lewy bodies\n(α-synuclein)",
"Tau (4R)\nNeurofibrillary tangles",
"GCIs\n(α-synuclein in oligos)",
"Tau (4R)\nCorticobasal inclusions",
"Cortical Lewy bodies\n(α-synuclein)",
"No primary pathology\n(iatrogenic)"],
["Progression",
"Slow (10-20 yrs)",
"Rapid (5-7 yrs)",
"Rapid (6-10 yrs)",
"Rapid (6-8 yrs)",
"Variable",
"Reverses on stopping drug"],
]
style_h = ParagraphStyle("th2", fontSize=7.5, textColor=WHITE,
fontName="Helvetica-Bold", leading=10,
alignment=TA_CENTER)
style_feat = ParagraphStyle("tf", fontSize=7.5, textColor=WHITE,
fontName="Helvetica-Bold", leading=10,
alignment=TA_LEFT)
style_cell = ParagraphStyle("tc", fontSize=7, textColor=BLACK,
fontName="Helvetica", leading=9.5,
alignment=TA_LEFT)
style_pos = ParagraphStyle("tp", fontSize=7, textColor=GREEN,
fontName="Helvetica-Bold", leading=9.5)
header_row = [Paragraph(c, style_h if i > 0 else style_h) for i, c in enumerate(cols)]
table_rows = [header_row]
for row in rows_data:
built = []
for i, cell in enumerate(row):
if i == 0:
built.append(Paragraph(cell, style_feat))
else:
built.append(Paragraph(cell.replace("✓✓","<font color='#1E8449'><b>✓✓</b></font>").replace("✓","<font color='#1E8449'>✓</font>"), style_cell))
table_rows.append(built)
cmds = [
("BACKGROUND", (0,0),(0,0), NAVY),
("BACKGROUND", (1,0),(1,0), GREEN),
("BACKGROUND", (2,0),(2,0), RED),
("BACKGROUND", (3,0),(3,0), PURPLE),
("BACKGROUND", (4,0),(4,0), ORANGE),
("BACKGROUND", (5,0),(5,0), STEEL),
("BACKGROUND", (6,0),(6,0), GREY),
("BACKGROUND", (0,1),( 0,-1), colors.HexColor("#1A3A5C")),
("GRID", (0,0),(-1,-1), 0.3, MGREY),
("TOPPADDING", (0,0),(-1,-1), 3),
("BOTTOMPADDING", (0,0),(-1,-1), 3),
("LEFTPADDING", (0,0),(-1,-1), 3),
("RIGHTPADDING", (0,0),(-1,-1), 3),
("VALIGN", (0,0),(-1,-1), "TOP"),
("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, LGREY]),
("BACKGROUND", (0,1),(0,-1), NAVY),
]
t = Table(table_rows, colWidths=col_w, repeatRows=1)
t.setStyle(TableStyle(cmds))
return t
# ── Red-flag table ────────────────────────────────────────────────────────────
def red_flag_table():
flags = [
("Early severe autonomic failure (yr 1)", "MSA"),
("Recurrent falls within first year", "PSP / MSA"),
("Supranuclear vertical gaze palsy", "PSP"),
("Cerebellar signs (ataxia, nystagmus)", "MSA-C"),
("Bilateral symmetric onset", "Drug-induced / MSA / PSP"),
("Rapid progression to wheelchair ≤5 yrs", "MSA / PSP"),
("Alien limb / ideomotor apraxia", "CBS"),
("Dementia onset ≤1 year of motor symptoms", "DLB"),
("Recurrent vivid visual hallucinations (early)","DLB"),
("Inspiratory stridor / laryngeal dysfunction", "MSA"),
("Antipsychotic / antiemetic use", "Drug-induced"),
("Pyramidal signs (Babinski, hyperreflexia)", "MSA / CBS"),
("History of encephalitis / head trauma", "Secondary"),
("Age <40 yrs at onset", "Genetic PD / Wilson's / DRD"),
("Absence of any non-motor PD features", "Atypical / drug-induced"),
("No response to high-dose levodopa (≥1000 mg)", "Atypical parkinsonism"),
("Normal DaTscan", "Drug-induced / ET"),
("Normal MIBG cardiac uptake", "MSA / PSP / Drug-induced"),
]
hs = ParagraphStyle("fh", fontSize=8, textColor=WHITE,
fontName="Helvetica-Bold", leading=11, alignment=TA_CENTER)
cs = ParagraphStyle("fc", fontSize=7.5, textColor=BLACK,
fontName="Helvetica", leading=11)
ds = ParagraphStyle("fd", fontSize=7.5, textColor=WARN,
fontName="Helvetica-Bold", leading=11)
data = [[Paragraph("RED FLAG / FINDING", hs),
Paragraph("", hs),
Paragraph("SUGGESTS", hs)]]
for flag, dx in flags:
data.append([
Paragraph("⛔", ParagraphStyle("ic", fontSize=10, textColor=WARN,
fontName="Helvetica-Bold", leading=11,
alignment=TA_CENTER)),
Paragraph(flag, cs),
Paragraph(dx, ds),
])
t = Table(data, colWidths=[8*mm, 110*mm, 60*mm])
cmds = [
("BACKGROUND", (0,0),(-1,0), WARN),
("GRID", (0,0),(-1,-1), 0.3, MGREY),
("TOPPADDING", (0,0),(-1,-1), 3),
("BOTTOMPADDING", (0,0),(-1,-1), 3),
("LEFTPADDING", (0,0),(-1,-1), 4),
("RIGHTPADDING", (0,0),(-1,-1), 4),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
("ROWBACKGROUNDS",(0,1),(-1,-1),[WHITE, colors.HexColor("#FEF9F9")]),
("SPAN", (0,0),(0,0)),
]
t.setStyle(TableStyle(cmds))
return t
# ── Supportive-features table ─────────────────────────────────────────────────
def supportive_table():
feats = [
("Clear rest tremor (pill-rolling 4-6 Hz)", "Strong PD"),
("Unilateral onset", "Strong PD"),
("Excellent & sustained levodopa response", "Strong PD"),
("Levodopa-induced dyskinesias", "Strong PD"),
("Anosmia / hyposmia", "PD > others"),
("REM sleep behaviour disorder (RBD)", "PD / DLB / MSA"),
("Cardiac sympathetic denervation (low MIBG)", "PD / DLB"),
("Asymmetric DAT loss on DaTscan", "PD / CBS"),
("Positive family history (1st degree)", "Genetic PD"),
("Age <50 yrs at onset + AR inheritance", "PARK2 / PINK1 / DJ-1"),
("Early constipation / autonomic (premotor yrs)", "PD (Braak stage 1-2)"),
]
hs = ParagraphStyle("sh", fontSize=8, textColor=WHITE,
fontName="Helvetica-Bold", leading=11, alignment=TA_CENTER)
cs = ParagraphStyle("sc", fontSize=7.5, textColor=BLACK,
fontName="Helvetica", leading=11)
ds = ParagraphStyle("sd", fontSize=7.5, textColor=GREEN,
fontName="Helvetica-Bold", leading=11)
data = [[Paragraph("SUPPORTIVE FEATURE", hs),
Paragraph("", hs),
Paragraph("SUGGESTS", hs)]]
for feat, dx in feats:
data.append([
Paragraph("✓", ParagraphStyle("ic2", fontSize=10, textColor=GREEN,
fontName="Helvetica-Bold", leading=11,
alignment=TA_CENTER)),
Paragraph(feat, cs),
Paragraph(dx, ds),
])
t = Table(data, colWidths=[8*mm, 110*mm, 60*mm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), GREEN),
("GRID", (0,0),(-1,-1), 0.3, MGREY),
("TOPPADDING", (0,0),(-1,-1), 3),
("BOTTOMPADDING", (0,0),(-1,-1), 3),
("LEFTPADDING", (0,0),(-1,-1), 4),
("RIGHTPADDING", (0,0),(-1,-1), 4),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, colors.HexColor("#F0FFF4")]),
]))
return t
# ── Investigations checklist ──────────────────────────────────────────────────
def investigations_table():
inv = [
# (test, purpose, interpretation)
("DaTscan / FP-CIT SPECT",
"Confirm nigrostriatal degeneration",
"Reduced = PD/MSA/PSP/CBS. Normal = Drug-induced or ET"),
("Brain MRI (3T preferred)",
"Exclude secondary causes; atypical patterns",
"Hummingbird=PSP; Hot cross bun=MSA; Asymm. atrophy=CBS; WM lesions=Vascular"),
("MIBG cardiac scintigraphy",
"Assess cardiac sympathetic innervation",
"Reduced = PD or DLB. Preserved = MSA/PSP/Drug-induced"),
("Levodopa challenge (carbidopa/levodopa)",
"Confirm dopaminergic response",
"≥30% UPDRS-III improvement supports PD. Poor response → atypical"),
("Autonomic battery (tilt-table, urodynamics, sweat test)",
"Quantify autonomic failure",
"Severe early failure → MSA. Mild-moderate → PD"),
("Neuropsychological testing",
"Characterise cognitive profile",
"Subcortical=PD; Frontal/executive=PSP; Cortical/apraxia=CBS; Global+halluc.=DLB"),
("Serum ceruloplasmin + 24h urine copper",
"Exclude Wilson's disease",
"Mandatory if age <50 yrs"),
("Thyroid function tests (TSH, fT4)",
"Exclude hypothyroid bradykinesia/tremor",
"Hypothyroidism may mimic parkinsonism"),
("Genetic panel (SNCA, LRRK2, Parkin, PINK1, DJ-1, GBA1)",
"Identify monogenic PD",
"Parkin/PINK1: early onset AR. LRRK2: typical PD phenotype. GBA1: risk + severity"),
("EEG",
"DLB workup (if cognitive symptoms)",
"Posterior slow-wave activity with fluctuation supports DLB"),
("CSF alpha-synuclein seed amplification assay (SAA)",
"Biomarker for synucleinopathy",
"High sensitivity/specificity for PD/DLB/MSA (emerging standard)"),
("Full medication review",
"Identify dopamine-blocking agents",
"Antipsychotics, metoclopramide, prochlorperazine, reserpine, valproate"),
]
hs = ParagraphStyle("ih", fontSize=8, textColor=WHITE,
fontName="Helvetica-Bold", leading=11, alignment=TA_CENTER)
cs = ParagraphStyle("ic3", fontSize=7.5, textColor=BLACK,
fontName="Helvetica-Bold", leading=10)
ps = ParagraphStyle("ip", fontSize=7, textColor=GREY,
fontName="Helvetica", leading=10)
rs = ParagraphStyle("ir", fontSize=7, textColor=STEEL,
fontName="Helvetica", leading=10)
data = [[Paragraph("□", hs),
Paragraph("INVESTIGATION", hs),
Paragraph("PURPOSE", hs),
Paragraph("KEY INTERPRETATION", hs)]]
for test, purpose, interp in inv:
data.append([
Paragraph("□", ParagraphStyle("cb", fontSize=11, textColor=NAVY,
fontName="Helvetica-Bold", leading=14,
alignment=TA_CENTER)),
Paragraph(test, cs),
Paragraph(purpose, ps),
Paragraph(interp, rs),
])
t = Table(data, colWidths=[7*mm, 45*mm, 52*mm, 74*mm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), STEEL),
("GRID", (0,0),(-1,-1), 0.3, MGREY),
("TOPPADDING", (0,0),(-1,-1), 3),
("BOTTOMPADDING", (0,0),(-1,-1), 3),
("LEFTPADDING", (0,0),(-1,-1), 4),
("RIGHTPADDING", (0,0),(-1,-1), 4),
("VALIGN", (0,0),(-1,-1), "TOP"),
("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, LGREY]),
]))
return t
# ── Medication checklist table ─────────────────────────────────────────────────
def meds_table():
drugs = [
("Levodopa/Carbidopa\n(Sinemet, Madopar)",
"First-line; gold standard",
"Nausea, dyskinesias, wearing-off, hallucinations, orthostasis",
"PD (all stages); partial MSA"),
("Dopamine agonists\nPramipexole / Ropinirole / Rotigotine",
"Early monotherapy; adjunct to LD",
"ICD (gambling, hypersexuality), somnolence, hallucinations, nausea, oedema",
"Early PD; smooth LD response in advanced PD"),
("MAO-B inhibitors\nSelegiline / Rasagiline / Safinamide",
"Early monotherapy; adjunct; possible neuroprotection",
"Insomnia, headache; serotonin syndrome (avoid SSRIs/SNRIs with selegiline)",
"Early/mild PD; adjunct for wearing-off"),
("COMT inhibitors\nEntacapone / Tolcapone / Opicapone",
"Prolong levodopa effect; reduce wearing-off",
"Diarrhoea, dyskinesias, orange urine; Tolcapone: hepatotoxicity (monitor LFTs)",
"Advanced PD with motor fluctuations"),
("Amantadine\n(immediate / extended release)",
"NMDA antagonist; anti-dyskinetic",
"Livedo reticularis, oedema, confusion, hallucinations; do NOT stop abruptly",
"Mild early PD; dyskinesias in advanced PD (ER formulation)"),
("Istradefylline\n(Adenosine A2A antagonist)",
"Reduce OFF-time",
"Dyskinesias, dizziness, hallucinations, insomnia",
"Advanced PD as adjunct to LD/CD"),
("Anticholinergics\nTrihexyphenidyl / Benztropine",
"Tremor-dominant PD (young patients)",
"Confusion, urinary retention, dry mouth, constipation, cognitive impairment",
"AVOID in elderly; not for atypical syndromes"),
("AChEIs\nRivastigmine / Donepezil",
"Cognitive symptoms in PDD/DLB",
"Nausea, bradycardia, increased tremor (rivastigmine preferred in PDD)",
"PDD (rivastigmine FDA-approved); DLB"),
("Fludrocortisone / Midodrine",
"Orthostatic hypotension (MSA/PD)",
"Supine hypertension, oedema (fludrocortisone); piloerection, urinary retention",
"MSA and PD autonomic failure"),
("Clonazepam / Melatonin",
"REM sleep behaviour disorder",
"Clonazepam: sedation, fall risk, dependency; Melatonin: better tolerated",
"RBD in PD/DLB/MSA"),
("Quetiapine / Clozapine\n(AVOID typicals & risperidone/olanzapine)",
"Psychosis / hallucinations",
"Clozapine requires WBC monitoring (agranulocytosis); quetiapine: sedation",
"PD/DLB psychosis ONLY if AChEIs fail"),
("Pimavanserin\n(5-HT2A inverse agonist)",
"PD psychosis (FDA approved)",
"QT prolongation, falls, oedema",
"PD-related psychosis; NOT approved for DLB"),
]
hs = ParagraphStyle("mh", fontSize=8, textColor=WHITE, fontName="Helvetica-Bold",
leading=11, alignment=TA_CENTER)
ds = ParagraphStyle("md", fontSize=7.5,textColor=NAVY, fontName="Helvetica-Bold", leading=10)
ind = ParagraphStyle("mi", fontSize=7, textColor=GREY, fontName="Helvetica", leading=10)
aes = ParagraphStyle("ma", fontSize=7, textColor=WARN, fontName="Helvetica", leading=10)
ind2= ParagraphStyle("mu", fontSize=7, textColor=GREEN, fontName="Helvetica-Bold", leading=10)
data = [[Paragraph("□", hs),
Paragraph("DRUG", hs),
Paragraph("INDICATION", hs),
Paragraph("ADVERSE EFFECTS", hs),
Paragraph("USE IN", hs)]]
for drug, ind_t, ae, use in drugs:
data.append([
Paragraph("□", ParagraphStyle("cb2", fontSize=11, textColor=NAVY,
fontName="Helvetica-Bold", leading=14,
alignment=TA_CENTER)),
Paragraph(drug, ds),
Paragraph(ind_t, ind),
Paragraph(ae, aes),
Paragraph(use, ind2),
])
t = Table(data, colWidths=[7*mm, 40*mm, 38*mm, 55*mm, 38*mm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), TEAL),
("GRID", (0,0),(-1,-1), 0.3, MGREY),
("TOPPADDING", (0,0),(-1,-1), 3),
("BOTTOMPADDING", (0,0),(-1,-1), 3),
("LEFTPADDING", (0,0),(-1,-1), 4),
("RIGHTPADDING", (0,0),(-1,-1), 4),
("VALIGN", (0,0),(-1,-1), "TOP"),
("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, LGREY]),
]))
return t
# ── Per-diagnosis rapid assessment blocks ─────────────────────────────────────
def dx_block(title, colour, must_haves, against, investigations, management, w=W):
title_s = ParagraphStyle("dxt", fontSize=9.5, textColor=WHITE,
fontName="Helvetica-Bold", leading=13)
cell_s = ParagraphStyle("dxc", fontSize=7.5, textColor=BLACK,
fontName="Helvetica", leading=11)
head_s = ParagraphStyle("dxh", fontSize=7.5, textColor=WHITE,
fontName="Helvetica-Bold", leading=11, alignment=TA_CENTER)
cw = w / 4 - 1*mm
# header row
header = Table([[Paragraph(f"□ {title}", title_s)]],
colWidths=[w])
header.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,-1), colour),
("TOPPADDING",(0,0),(-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING",(0,0),(-1,-1), 8),
]))
def sub_col(heading, items, col_c):
rows = [[Paragraph(heading, head_s)]]
for item in items:
rows.append([checkbox(item)])
t = Table(rows, colWidths=[cw])
t.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0), col_c),
("GRID",(0,0),(-1,-1), 0.3, MGREY),
("TOPPADDING",(0,0),(-1,-1), 2),
("BOTTOMPADDING",(0,0),(-1,-1), 2),
("LEFTPADDING",(0,0),(-1,-1), 4),
("ROWBACKGROUNDS",(0,1),(-1,-1),[WHITE, LGREY]),
("VALIGN",(0,0),(-1,-1),"TOP"),
]))
return t
body = Table([[
sub_col("MUST-HAVES", must_haves, colour),
sub_col("POINTS AGAINST", against, WARN),
sub_col("INVESTIGATIONS", investigations, STEEL),
sub_col("MANAGEMENT", management, TEAL),
]], colWidths=[cw]*4)
body.setStyle(TableStyle([
("TOPPADDING",(0,0),(-1,-1),0),
("BOTTOMPADDING",(0,0),(-1,-1),0),
("LEFTPADDING",(0,0),(-1,-1),1),
("RIGHTPADDING",(0,0),(-1,-1),1),
("VALIGN",(0,0),(-1,-1),"TOP"),
]))
outer = Table([[header],[body]], colWidths=[w])
outer.setStyle(TableStyle([
("BOX",(0,0),(-1,-1), 0.8, colour),
("TOPPADDING",(0,0),(-1,-1),0),
("BOTTOMPADDING",(0,0),(-1,-1),0),
("LEFTPADDING",(0,0),(-1,-1),0),
("RIGHTPADDING",(0,0),(-1,-1),0),
]))
return outer
# ═══════════════════════════════════════════════════════════════════════════════
# BUILD STORY
# ═══════════════════════════════════════════════════════════════════════════════
story = []
# ── COVER HEADER ─────────────────────────────────────────────────────────────
story.append(coloured_header(
"PARKINSONISM · RAPID CLINICAL ASSESSMENT CHECKLIST",
"Differential Diagnosis · Investigations · Management | Specialist Reference | August 2026",
NAVY
))
story.append(sp(6))
# Purpose note
story.append(shaded_box([
Paragraph("<b>Purpose:</b> This checklist supports rapid bedside differentiation of Parkinson's Disease (PD) from "
"Atypical Parkinsonism (PSP, MSA, CBS, DLB) and Secondary Parkinsonism. Work through each section "
"sequentially: confirm parkinsonism → screen for secondary causes → apply red flags → review supportive "
"features → order targeted investigations → initiate appropriate management.",
ParagraphStyle("note", fontSize=8, textColor=BLACK, fontName="Helvetica",
leading=12, leftIndent=4)),
Paragraph("<b>Based on:</b> MDS Clinical Diagnostic Criteria for PD (Berg et al.) · Harrison's Principles of "
"Internal Medicine 22E · Bradley & Daroff's Neurology in Clinical Practice · Katzung Pharmacology 16E",
ParagraphStyle("src", fontSize=7, textColor=GREY, fontName="Helvetica",
leading=10, leftIndent=4)),
], bg=colors.HexColor("#EAF2FF"), border=STEEL))
story.append(sp(8))
# ── STEP 1: Confirm Parkinsonism ──────────────────────────────────────────────
story.append(section_header("STEP 1 · CONFIRM PARKINSONISM (all three criteria must be assessed)", NAVY))
story.append(sp(3))
step1_data = [
[Paragraph("<b>ESSENTIAL (required)</b>", ParagraphStyle("s1h", fontSize=8, textColor=WHITE,
fontName="Helvetica-Bold", leading=11, alignment=TA_CENTER)),
Paragraph("<b>CORE MOTOR FEATURES (TRAP)</b>", ParagraphStyle("s1h2", fontSize=8, textColor=WHITE,
fontName="Helvetica-Bold", leading=11, alignment=TA_CENTER)),
Paragraph("<b>NON-MOTOR CLUES</b>", ParagraphStyle("s1h3", fontSize=8, textColor=WHITE,
fontName="Helvetica-Bold", leading=11, alignment=TA_CENTER))],
["\n".join([
"☐ Bradykinesia",
" PLUS at least one of:",
"☐ Rigidity",
"☐ Rest tremor (4-6 Hz)",
]),
"\n".join([
"☐ T — Tremor at rest (pill-rolling)",
"☐ R — Rigidity (cogwheel / lead-pipe)",
"☐ A — Akinesia / bradykinesia",
"☐ P — Postural instability (pull test +)",
"☐ Flexed posture",
"☐ Freezing of gait",
]),
"\n".join([
"☐ Anosmia / hyposmia",
"☐ Constipation (pre-motor)",
"☐ REM sleep behaviour disorder",
"☐ Depression / anxiety",
"☐ Orthostatic hypotension",
"☐ Micrographia / hypophonia",
])]
]
t1 = Table(step1_data, colWidths=[W/3]*3)
t1.setStyle(TableStyle([
("BACKGROUND", (0,0),(0,0), NAVY),
("BACKGROUND", (1,0),(1,0), STEEL),
("BACKGROUND", (2,0),(2,0), TEAL),
("GRID", (0,0),(-1,-1), 0.3, MGREY),
("TOPPADDING", (0,0),(-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1), 4),
("LEFTPADDING",(0,0),(-1,-1), 6),
("FONTNAME", (0,1),(-1,1), "Helvetica"),
("FONTSIZE", (0,1),(-1,1), 8),
("LEADING", (0,1),(-1,1), 13),
("VALIGN", (0,0),(-1,-1), "TOP"),
("ROWBACKGROUNDS",(0,1),(-1,1),[WHITE]),
]))
story.append(t1)
story.append(sp(8))
# ── STEP 2: Exclude Secondary ─────────────────────────────────────────────────
story.append(section_header("STEP 2 · EXCLUDE SECONDARY (NON-DEGENERATIVE) PARKINSONISM", GREY))
story.append(sp(3))
sec_data = [
["DRUG-INDUCED (most common secondary cause)",
"VASCULAR PARKINSONISM",
"OTHER SECONDARY CAUSES"],
["\n".join([
"☐ Current antipsychotic use",
"☐ Metoclopramide / prochlorperazine",
"☐ Reserpine / tetrabenazine",
"☐ Valproate",
"☐ Calcium channel blockers (flunarizine)",
"",
"Key: Symmetric onset, normal DaTscan",
"Rx: Stop offending drug → observe 3 months",
]),
"\n".join([
"☐ Multiple lacunar infarcts on MRI",
"☐ Periventricular white matter lesions",
"☐ Lower body predominant gait disorder",
"☐ Pyramidal signs",
"☐ History of hypertension / DM / stroke",
"☐ Stepwise progression",
"",
"Rx: Vascular risk factor modification",
]),
"\n".join([
"☐ Normal pressure hydrocephalus (triad)",
"☐ Toxin: MPTP, CO, manganese, cyanide",
"☐ Neoplasm / abscess (MRI)",
"☐ Postencephalitic parkinsonism",
"☐ Wilson's disease (age <50)",
"☐ Metabolic: hypothyroid, hepatic failure",
"",
"→ If any secondary cause found: STOP here",
])]
]
ths = ParagraphStyle("ths", fontSize=8, textColor=WHITE, fontName="Helvetica-Bold",
leading=11, alignment=TA_CENTER)
sec_table_data = [
[Paragraph(sec_data[0][0], ths),
Paragraph(sec_data[0][1], ths),
Paragraph(sec_data[0][2], ths)],
[Paragraph(sec_data[1][0], ParagraphStyle("st", fontSize=7.5, textColor=BLACK,
fontName="Helvetica", leading=12)),
Paragraph(sec_data[1][1], ParagraphStyle("st2", fontSize=7.5, textColor=BLACK,
fontName="Helvetica", leading=12)),
Paragraph(sec_data[1][2], ParagraphStyle("st3", fontSize=7.5, textColor=BLACK,
fontName="Helvetica", leading=12))],
]
t2 = Table(sec_table_data, colWidths=[W/3]*3)
t2.setStyle(TableStyle([
("BACKGROUND",(0,0),(0,0), GREY),
("BACKGROUND",(1,0),(1,0), colors.HexColor("#78909C")),
("BACKGROUND",(2,0),(2,0), colors.HexColor("#546E7A")),
("GRID",(0,0),(-1,-1), 0.3, MGREY),
("TOPPADDING",(0,0),(-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1), 4),
("LEFTPADDING",(0,0),(-1,-1), 6),
("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(t2)
story.append(sp(8))
# ── STEP 3: Red Flags ─────────────────────────────────────────────────────────
story.append(section_header("STEP 3 · SCREEN FOR RED FLAGS (each flags against idiopathic PD)", WARN))
story.append(sp(3))
story.append(red_flag_table())
story.append(sp(8))
# ── STEP 4: Supportive features ───────────────────────────────────────────────
story.append(section_header("STEP 4 · SUPPORTIVE FEATURES FOR IDIOPATHIC PD", GREEN))
story.append(sp(3))
story.append(supportive_table())
story.append(sp(8))
# ── STEP 5: Per-Diagnosis Rapid Assessment ────────────────────────────────────
story.append(section_header("STEP 5 · PER-DIAGNOSIS RAPID ASSESSMENT BLOCKS", NAVY))
story.append(sp(4))
# PD
story.append(KeepTogether([
dx_block(
"PARKINSON'S DISEASE (PD)",
GREEN,
must_haves=[
"Bradykinesia + rigidity and/or rest tremor",
"Asymmetric onset",
"Clear pill-rolling 4-6 Hz rest tremor",
"Anosmia / hyposmia",
"REM sleep behaviour disorder",
"Excellent sustained levodopa response",
"Levodopa-induced dyskinesias",
],
against=[
"Cerebellar signs",
"Vertical supranuclear gaze palsy",
"Early severe autonomic failure",
"Symmetric onset",
"Falls in first year",
"Rapid progression (<5 yrs to chair)",
"Normal DaTscan",
],
investigations=[
"DaTscan (asymm. post. putamen ↓)",
"MIBG scintigraphy (reduced)",
"Brain MRI (usually normal)",
"CSF SAA (alpha-syn seed amplif.)",
"Genetic panel if age <50",
"Levodopa challenge (UPDRS ≥30%↑)",
],
management=[
"Levodopa/carbidopa (gold standard)",
"Dopamine agonist (young/early)",
"MAO-B inhibitor (early/adjunct)",
"COMT inhibitor (wearing-off)",
"Amantadine (dyskinesias)",
"DBS-STN/GPi (advanced, fluct.)",
"Physiotherapy + speech therapy",
]
),
sp(4)
]))
# PSP
story.append(KeepTogether([
dx_block(
"PROGRESSIVE SUPRANUCLEAR PALSY (PSP)",
RED,
must_haves=[
"Vertical supranuclear gaze palsy",
"(esp. downward gaze slowing)",
"Early unexplained falls (yr 1)",
"Axial > limb rigidity",
"Neck hyperextension (retrocollis)",
"Frontal/executive cognitive decline",
"Dysphagia and dysarthria early",
],
against=[
"Unilateral asymmetric onset",
"Good levodopa response",
"Cerebellar signs",
"Alien limb / apraxia",
"Early severe visual hallucinations",
"Preserved vertical gaze",
],
investigations=[
"MRI: hummingbird / penguin sign",
"DaTscan (symmetric reduction)",
"Neuropsych: frontal battery",
"Video oculomotor assessment",
"Tau PET (research setting)",
],
management=[
"Levodopa trial (often poor response)",
"Falls prevention programme",
"Physiotherapy (gait, balance)",
"PEG tube for dysphagia (early)",
"Supportive / palliative care",
"Botox for blepharospasm",
]
),
sp(4)
]))
# MSA
story.append(KeepTogether([
dx_block(
"MULTIPLE SYSTEM ATROPHY (MSA)",
PURPLE,
must_haves=[
"Autonomic failure (OH, incontinence)",
"Parkinsonism (MSA-P) OR",
"Cerebellar ataxia (MSA-C)",
"Onset <60 yrs typically",
"Rapid progression",
"Inspiratory stridor (nocturnal)",
"Emotional incontinence",
],
against=[
"Asymmetric onset",
"Dementia (prominent early)",
"Lewy body pathology",
"Normal autonomic function",
"Good sustained levodopa response",
],
investigations=[
"MRI: hot cross bun sign (pons)",
"Putaminal hypointensity (T2*)",
"Autonomic battery (tilt, QSART)",
"Urodynamics (detrusor failure)",
"DaTscan (symmetric ↓)",
"Sleep study (RBD + stridor)",
],
management=[
"Levodopa trial (partial in 30-40%)",
"Fludrocortisone / midodrine (OH)",
"CPAP / tracheostomy (stridor)",
"Urological referral (incontinence)",
"Physiotherapy (ataxia / falls)",
"PEG tube for dysphagia",
]
),
sp(4)
]))
# CBS
story.append(KeepTogether([
dx_block(
"CORTICOBASAL SYNDROME (CBS)",
ORANGE,
must_haves=[
"Markedly asymmetric parkinsonism",
"Alien limb phenomenon",
"Ideomotor limb apraxia",
"Cortical sensory loss",
"Focal limb dystonia",
"Myoclonus (stimulus-sensitive)",
"Nonfluent aphasia (if frontal)",
],
against=[
"Symmetric onset",
"Good levodopa response",
"Vertical gaze palsy early",
"Cerebellar signs",
"Prominent early autonomic failure",
],
investigations=[
"MRI: asymm. frontoparietal atrophy",
"FDG-PET: asymm. cortical hypometab.",
"DaTscan: asymmetric ↓",
"Neuropsych: apraxia battery",
"Tau PET (4R tauopathy pattern)",
"Genetic: consider MAPT",
],
management=[
"Levodopa trial (usually poor)",
"Clonazepam for myoclonus",
"OT for apraxia / limb dysfunction",
"Speech therapy (aphasia)",
"Physiotherapy",
"Supportive / palliative care",
]
),
sp(4)
]))
# DLB
story.append(KeepTogether([
dx_block(
"DEMENTIA WITH LEWY BODIES (DLB)",
STEEL,
must_haves=[
"Dementia ≤1 yr before motor onset",
"Recurrent vivid visual hallucinations",
"Fluctuating cognition / alertness",
"REM sleep behaviour disorder",
"Neuroleptic hypersensitivity (SEVERE)",
"Parkinsonism (mild, symmetric)",
"Repeated unexplained falls",
],
against=[
"Dementia >1 yr after motor onset → PDD",
"Typical antipsychotic tolerated",
"Early severe autonomic (→ MSA)",
"Vertical gaze palsy (→ PSP)",
"Alien limb / apraxia (→ CBS)",
],
investigations=[
"MIBG scintigraphy: reduced ✓",
"DaTscan: bilateral ↓ (sym.)",
"EEG: posterior slow waves",
"FDG-PET: occipital hypometab.",
"CSF SAA (alpha-syn): positive",
"Neuropsych: visuospatial deficits",
],
management=[
"AChEIs (rivastigmine / donepezil)",
"AVOID typical antipsychotics",
"AVOID risperidone / olanzapine",
"Quetiapine / clozapine (psychosis)",
"Melatonin / clonazepam (RBD)",
"Low-dose levodopa (motor sx)",
]
),
sp(4)
]))
# ── STEP 6: Investigations ────────────────────────────────────────────────────
story.append(section_header("STEP 6 · INVESTIGATIONS CHECKLIST", STEEL))
story.append(sp(3))
story.append(investigations_table())
story.append(sp(8))
# ── STEP 7: Medications ────────────────────────────────────────────────────────
story.append(section_header("STEP 7 · MEDICATION CHECKLIST (with adverse effect profile)", TEAL))
story.append(sp(3))
story.append(meds_table())
story.append(sp(8))
# ── STEP 8: Full comparison table ────────────────────────────────────────────
story.append(section_header("STEP 8 · RAPID COMPARISON TABLE (PD vs. All Atypical Syndromes)", NAVY))
story.append(sp(3))
story.append(comparison_table())
story.append(sp(8))
# ── STEP 9: Diagnostic certainty ─────────────────────────────────────────────
story.append(section_header("STEP 9 · MDS DIAGNOSTIC CERTAINTY LEVELS (for PD)", NAVY))
story.append(sp(3))
cert_data = [
[Paragraph("<b>CLINICALLY ESTABLISHED PD</b>", ParagraphStyle("c1h", fontSize=8.5, textColor=WHITE,
fontName="Helvetica-Bold", leading=12, alignment=TA_CENTER)),
Paragraph("<b>CLINICALLY PROBABLE PD</b>", ParagraphStyle("c2h", fontSize=8.5, textColor=WHITE,
fontName="Helvetica-Bold", leading=12, alignment=TA_CENTER)),
Paragraph("<b>ABSOLUTE EXCLUSION CRITERIA</b>", ParagraphStyle("c3h", fontSize=8.5, textColor=WHITE,
fontName="Helvetica-Bold", leading=12, alignment=TA_CENTER))],
["\n".join([
"☐ Parkinsonism (core feature)",
"☐ No absolute exclusion criteria",
"☐ ≥2 supportive criteria",
"☐ No red flags",
"",
"→ Specificity >90% for PD pathology",
]),
"\n".join([
"☐ Parkinsonism (core feature)",
"☐ No absolute exclusion criteria",
"☐ ≥1 supportive criteria",
"☐ Red flags balanced by equal",
" number of supportive criteria",
"→ Lower certainty; monitor over time",
]),
"\n".join([
"☒ Cerebellar abnormalities",
"☒ Downward vertical gaze palsy",
"☒ FTD / PPA in first 5 yrs",
"☒ Lower limb parkinsonism >3 yrs",
"☒ Dopaminergic drug causing parkin.",
"☒ No response to high-dose levodopa",
"☒ Cortical sensory loss, apraxia",
])]
]
cert_table = Table([
[Paragraph("<b>CLINICALLY ESTABLISHED PD</b>", ParagraphStyle("c1h", fontSize=8.5, textColor=WHITE,
fontName="Helvetica-Bold", leading=12, alignment=TA_CENTER)),
Paragraph("<b>CLINICALLY PROBABLE PD</b>", ParagraphStyle("c2h", fontSize=8.5, textColor=WHITE,
fontName="Helvetica-Bold", leading=12, alignment=TA_CENTER)),
Paragraph("<b>ABSOLUTE EXCLUSION CRITERIA</b>", ParagraphStyle("c3h", fontSize=8.5, textColor=WHITE,
fontName="Helvetica-Bold", leading=12, alignment=TA_CENTER))],
[Paragraph(cert_data[1][0], ParagraphStyle("cv", fontSize=7.5, textColor=BLACK,
fontName="Helvetica", leading=12)),
Paragraph(cert_data[1][1], ParagraphStyle("cv2", fontSize=7.5, textColor=BLACK,
fontName="Helvetica", leading=12)),
Paragraph(cert_data[1][2], ParagraphStyle("cv3", fontSize=7.5, textColor=WARN,
fontName="Helvetica", leading=12))],
], colWidths=[W/3]*3)
cert_table.setStyle(TableStyle([
("BACKGROUND",(0,0),(0,0), GREEN),
("BACKGROUND",(1,0),(1,0), STEEL),
("BACKGROUND",(2,0),(2,0), WARN),
("GRID",(0,0),(-1,-1), 0.3, MGREY),
("TOPPADDING",(0,0),(-1,-1),5),
("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),6),
("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(cert_table)
story.append(sp(8))
# ── FOOTER ───────────────────────────────────────────────────────────────────
story.append(shaded_box([
Paragraph(
"<b>Notes / Clinical observations:</b>",
ParagraphStyle("noteh", fontSize=8, textColor=NAVY, fontName="Helvetica-Bold", leading=12)
),
Paragraph("_" * 140, ParagraphStyle("line", fontSize=8, textColor=MGREY, leading=14)),
Paragraph("_" * 140, ParagraphStyle("line", fontSize=8, textColor=MGREY, leading=14)),
Paragraph("_" * 140, ParagraphStyle("line", fontSize=8, textColor=MGREY, leading=14)),
sp(4),
Paragraph(
"Patient Name: ________________________ DOB: ______________ Clinician: ________________________ Date: ______________",
ParagraphStyle("pid", fontSize=8, textColor=GREY, fontName="Helvetica", leading=12)
),
], bg=colors.HexColor("#F8FBFF"), border=STEEL))
story.append(sp(4))
story.append(Paragraph(
"Sources: Harrison's Principles of Internal Medicine 22E · Bradley & Daroff's Neurology in Clinical Practice · "
"Katzung Basic & Clinical Pharmacology 16E · MDS Clinical Diagnostic Criteria for Parkinson's Disease (Berg et al.) · "
"Adams & Victor's Principles of Neurology 12E · Washington Manual of Medical Therapeutics",
sNote
))
# ── BUILD ─────────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF saved: {OUT}")
print(f"Size: {os.path.getsize(OUT)//1024} KB")
cd /tmp/workspace/parkinsonism-workbook && python checklist.py 2>&1
Parkinsonism DDx Checklist
PDF Document · PDF
Create clinical practice guideline with infographics
A clean professional medical infographic titled "Parkinsonism: Step-by-Step Diagnostic Algorithm" showing a vertical flowchart with 5 decision nodes. Start at top: "Parkinsonism Confirmed (Bradykinesia + Rigidity/Tremor)" in dark navy box. Arrow down to diamond decision: "Secondary cause identified? (Drugs, Vascular, Toxins, NPH, Metabolic)" - YES branch goes right to green box "Treat underlying cause". NO branch continues down to diamond: "Red flags present? (Early falls, Vertical gaze palsy, Cerebellar signs, Symmetric onset, Early autonomic failure)" - YES branch to orange box listing "Atypical Parkinsonism workup: MRI, DaTscan, autonomic testing". NO branch continues down to diamond: "Supportive features present? (Asymmetric onset, Rest tremor, Anosmia, RBD, Levodopa response)". YES leads to green box "Clinically Established Parkinson's Disease". Alongside show two smaller boxes: "MDS Criteria: ≥2 supportive + 0 red flags = Established PD" and "DaTscan + MIBG for confirmation". At bottom a row of 5 colored mini-boxes: PD (green), PSP (red), MSA (purple), CBS (orange), DLB (blue). Professional, clean, white background, modern medical style.
A professional medical infographic titled "Pharmacological Management of Parkinson's Disease" showing a tiered treatment pyramid/ladder. At the base (widest, green): "Levodopa/Carbidopa - Gold Standard - All stages". Second tier (blue): "Dopamine Agonists: Pramipexole, Ropinirole, Rotigotine patch - Early disease or adjunct". Third tier (teal): "MAO-B Inhibitors: Rasagiline, Selegiline, Safinamide - Early monotherapy or adjunct for wearing-off". Fourth tier (orange): "COMT Inhibitors: Entacapone, Opicapone - Advanced disease, reduce wearing-off". Fifth tier (purple): "Amantadine - Anti-dyskinetic, NMDA antagonist". Top tier (red): "Surgical: Deep Brain Stimulation STN/GPi - Advanced motor fluctuations". On the right side show a vertical timeline: "Early PD → Moderate PD → Advanced PD" with corresponding drug layers highlighted. Below show a warning box in red: "AVOID in DLB: Typical antipsychotics, Risperidone, Olanzapine". Professional, clinical, color-coded, white background.
A professional medical infographic titled "Non-Motor Features of Parkinson's Disease: Recognition & Management" with a human body silhouette in the center. Around the body, connect labeled organ/system boxes with arrows pointing to the silhouette: BRAIN (top): "Cognitive decline, Dementia (PDD), Depression, Anxiety, Hallucinations, Impulse control disorders" - treat with AChEIs, SSRIs, quetiapine. NOSE: "Anosmia - earliest pre-motor biomarker". EYES: "Visual hallucinations, REM sleep disorder". HEART: "Cardiac sympathetic denervation - MIBG reduced". GUT (abdomen): "Constipation, Dysphagia, Gastroparesis, Nausea on levodopa - Braak stage 1". BLADDER: "Urinary urgency/frequency/incontinence". LEGS/CIRCULATION: "Orthostatic hypotension - Fludrocortisone/Midodrine". SKIN: "Seborrhoea, Excessive sweating". At bottom a timeline bar showing: "Pre-motor phase (years before diagnosis) → Motor onset → Motor + Non-motor → Advanced". Professional, clean, medical illustration style, color-coded by system.
A professional medical comparison infographic titled "Atypical Parkinsonism: At-a-Glance Comparison" showing 4 condition cards side by side. PSP card (red): brain icon with downward gaze arrow, bullet points: Vertical gaze palsy, Early falls, Retrocollis, Tau pathology, Hummingbird MRI sign, Poor levodopa response. MSA card (purple): autonomic system icon, bullet points: Severe autonomic failure, Cerebellar ataxia, Inspiratory stridor, Hot cross bun MRI sign, Alpha-synuclein oligodendrocytes, Poor levodopa. CBS card (orange): asymmetric limb icon, bullet points: Alien limb phenomenon, Ideomotor apraxia, Cortical sensory loss, Markedly asymmetric, Tau pathology, Levodopa-resistant. DLB card (blue): brain with Lewy body icon, bullet points: Dementia before/with motor, Visual hallucinations, Fluctuating cognition, RBD, Neuroleptic DANGER, Reduced MIBG. Below each card a small MRI brain image label showing the characteristic finding. Bottom row: treatment summary for each. Clean, modern, professional medical design, white background, distinct color coding for each condition.
Error calling model 'gemini-3-pro-image' (RESOURCE_EXHAUSTED): 429 RESOURCE_EXHAUSTED. {'error': {'code': 429, 'message': 'Resource has been exhausted (e.g. check quota).', 'status': 'RESOURCE_EXHAUSTED'}}
We encountered an error while processing your request. Please try again or reach out to us for help.
Create clinical practice guideline with infographics
mkdir -p /tmp/workspace/parkinsonism-cpg/assets && echo "ready"
Create clinical practice guideline with infographics
mkdir -p /tmp/workspace/parkinsonism-cpg/assets && python3 - <<'PYEOF' import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt import matplotlib.patches as mpatches from matplotlib.patches import FancyBboxPatch, FancyArrowPatch from matplotlib.patches import Polygon as MplPolygon import textwrap, os ASSET = "/tmp/workspace/parkinsonism-cpg/assets" # ── palette ────────────────────────────────────────────────────────────────── NAVY = "#1A3A5C"; GREEN = "#1E8449"; RED = "#922B21" PURPLE = "#6C3483"; ORANGE = "#B7770D"; STEEL = "#2471A3" TEAL = "#117A65"; WARN = "#C0392B"; LGREY = "#F2F3F4" MGREY = "#BDC3C7"; WHITE = "white"; BLACK = "#1A1A1A" GOLD = "#D4AC0D" def fbox(ax, cx, cy, w, h, txt, fc, tc="white", fs=9, bold=False, wrap=True, lsp=1.35): rx, ry = cx-w/2, cy-h/2 p = FancyBboxPatch((rx,ry),w,h, boxstyle="round,pad=0.12", fc=fc, ec="white", lw=1.4, zorder=3) ax.add_patch(p) t = textwrap.fill(txt, width=max(8,int(w*9))) if wrap else txt ax.text(cx, cy, t, ha="center", va="center", fontsize=fs, color=tc, fontweight="bold" if bold else "normal", linespacing=lsp, zorder=4, multialignment="center") def diamond(ax, cx, cy, w, h, txt, fc, tc="white", fs=8.5): pts = [(cx,cy+h/2),(cx+w/2,cy),(cx,cy-h/2),(cx-w/2,cy)] poly = MplPolygon(pts, closed=True, fc=fc, ec="white", lw=1.4, zorder=3) ax.add_patch(poly) t = textwrap.fill(txt, width=max(6,int(w*6.5))) ax.text(cx,cy,t,ha="center",va="center",fontsize=fs, color=tc,fontweight="bold",zorder=4,multialignment="center",linespacing=1.25) def arr(ax,x1,y1,x2,y2,lbl="",lc="#444",lbl_off=(0,0)): ax.annotate("",xy=(x2,y2),xytext=(x1,y1), arrowprops=dict(arrowstyle="->",color=lc,lw=1.8),zorder=2) if lbl: mx,my=(x1+x2)/2+lbl_off[0],(y1+y2)/2+lbl_off[1] ax.text(mx,my,lbl,ha="center",va="center",fontsize=8,color=lc, fontweight="bold", bbox=dict(fc="white",ec="none",alpha=0.9,pad=1.5),zorder=5) # ════════════════════════════════════════════════════════════════════════════ # INFOGRAPHIC 1 — Diagnostic Algorithm # ════════════════════════════════════════════════════════════════════════════ fig,ax = plt.subplots(figsize=(14,20)); ax.set_xlim(0,14); ax.set_ylim(0,20); ax.axis("off") fig.patch.set_facecolor("#F7F9FC") ax.text(7,19.5,"PARKINSONISM: STEP-BY-STEP DIAGNOSTIC ALGORITHM", ha="center",va="center",fontsize=14,fontweight="bold",color=NAVY) ax.text(7,19.1,"Based on MDS Clinical Diagnostic Criteria · Harrison's 22E · Bradley & Daroff's Neurology", ha="center",va="center",fontsize=8.5,color="#555",style="italic") # Node 1 — Entry fbox(ax,7,18.3,10,0.85, "PATIENT PRESENTS WITH SUSPECTED PARKINSONISM\nBradykinesia + Rigidity and/or Rest Tremor", NAVY,fs=10,bold=True) arr(ax,7,17.88,7,17.2) # Node 2 — Secondary diamond(ax,7,16.7,10,0.95, "Identifiable secondary cause?\n(Drugs · Vascular · Toxin · NPH · Metabolic · Infection)", STEEL,fs=8.5) fbox(ax,12,16.7,3.2,1.0, "SECONDARY\nPARKINSONISM\n→ Treat cause", TEAL,fs=8.5) arr(ax,12,16.22,12,15.6) fbox(ax,12,15.2,3.2,0.75, "Stop drug (DIP)\nVascular Rx factors\nNPH → shunt eval.", TEAL,tc="white",fs=7.5) ax.text(9.7,16.82,"YES",ha="center",va="center",fontsize=8,color=TEAL,fontweight="bold", bbox=dict(fc="white",ec="none",alpha=0.9)) arr(ax,7,16.22,7,15.5) ax.text(7.3,15.85,"NO",ha="center",va="center",fontsize=8,color="#333",fontweight="bold", bbox=dict(fc="white",ec="none",alpha=0.9)) # Node 3 — Red Flags diamond(ax,7,15.0,10,0.9, "Red Flags present?\n(Vertical gaze palsy · Early falls · Cerebellar · Symmetric · Severe autonomic)", WARN,fs=8.5) fbox(ax,12,15.0,3.2,1.0, "ATYPICAL\nPARKINSONISM\nWorkup ↓", WARN,fs=8.5) ax.text(9.7,15.1,"YES →",ha="center",va="center",fontsize=8,color=WARN,fontweight="bold", bbox=dict(fc="white",ec="none",alpha=0.9)) arr(ax,7,14.55,7,13.8) ax.text(7.3,14.15,"NO",ha="center",va="center",fontsize=8,color="#333",fontweight="bold", bbox=dict(fc="white",ec="none",alpha=0.9)) # Atypical workup box fbox(ax,12,14.0,3.2,1.8, "MRI Brain\nDaTscan / SPECT\nAutonomic battery\nNeuropsych testing\nLevodopa challenge", "#7B241C",fs=7.5) arr(ax,12,15.5,12,14.9) # Node 4 — Supportive diamond(ax,7,13.3,10,0.9, "≥2 Supportive Features? No Red Flags?\n(Asymm. onset · Rest tremor · Anosmia · RBD · Levodopa response)", GREEN,fs=8.5) arr(ax,7,12.85,7,12.1) ax.text(7.3,12.45,"YES",ha="center",va="center",fontsize=8,color=GREEN,fontweight="bold", bbox=dict(fc="white",ec="none",alpha=0.9)) arr(ax,2,13.3,2,12.3) ax.text(3.85,13.3,"NO / 1 FEATURE →",ha="right",va="center",fontsize=8,color=STEEL,fontweight="bold", bbox=dict(fc="white",ec="none",alpha=0.9)) ax.annotate("",xy=(2,13.3),xytext=(2.1,13.3), arrowprops=dict(arrowstyle="<-",color=STEEL,lw=1.5),zorder=2) fbox(ax,2,11.9,3.5,0.8, "Clinically PROBABLE PD\n(Monitor; repeat levodopa trial)", STEEL,fs=8) # Node 5 — PD fbox(ax,7,11.6,10,0.85, "CLINICALLY ESTABLISHED PARKINSON'S DISEASE", GREEN,fs=10.5,bold=True) # PD details pd_box = ( "DaTscan: asymmetric posterior putamen ↓ | MIBG: cardiac sympathetic denervation\n" "Pathology: Lewy bodies (α-synuclein) in SNc | Genetics if age <50: SNCA · LRRK2 · Parkin · PINK1" ) fbox(ax,7,10.85,12,0.7,pd_box, "#EAF9ED",tc=BLACK,fs=8,wrap=False) # Atypical row dxs = [ ("PSP","Vertical gaze palsy\nRetropulsion falls\nHummingbird MRI",RED), ("MSA","Autonomic failure\nCerebellar ataxia\nHot cross bun MRI",PURPLE), ("CBS","Alien limb\nApraxia · Myoclonus\nAsymm. cortical atrophy",ORANGE), ("DLB","Dementia ≤1 yr\nVisual hallucinations\nNeuroleptic DANGER",STEEL), ] ax.text(7,9.95,"ATYPICAL PARKINSONISM — KEY DISTINGUISHING FEATURES", ha="center",fontsize=9.5,fontweight="bold",color=NAVY) for i,(name,txt,col) in enumerate(dxs): cx = 1.8 + i*3.15 fbox(ax,cx,9.5,2.9,0.65,name,col,fs=9,bold=True) fbox(ax,cx,8.85,2.9,1.05,txt,col,fs=7.5,tc="white",lsp=1.4) # Investigations row inv = [ ("DaTscan","Confirms nigrostriatal\ndegeneration\n(not drug-induced/ET)",STEEL), ("Brain MRI","Hummingbird=PSP\nHot cross bun=MSA\nWM lesions=Vascular",NAVY), ("MIBG","Low = PD/DLB\nPreserved = MSA/PSP",TEAL), ("Levodopa\nChallenge","≥30% UPDRS↑\n= strong PD support",GREEN), ("Autonomic\nBattery","Severe early = MSA\nMild = PD autonomic",ORANGE), ] ax.text(7,8.0,"KEY INVESTIGATIONS", ha="center",fontsize=9.5,fontweight="bold",color=NAVY) for i,(name,txt,col) in enumerate(inv): cx = 1.4 + i*2.65 fbox(ax,cx,7.5,2.4,0.65,name,col,fs=8.5,bold=True) fbox(ax,cx,6.8,2.4,0.95,txt,col,fs=7.2,tc="white",lsp=1.35) # Genetic box ax.text(7,5.95,"GENETIC TESTING — CONSIDER IF AGE <50 OR FAMILY HISTORY", ha="center",fontsize=9,fontweight="bold",color=NAVY) genes = [("LRRK2\n(PARK8)","AD, typical PD\nNorth African/\nAshkenazi",STEEL), ("Parkin\n(PARK2)","AR, up to 50%\nearly-onset PD",GREEN), ("PINK1\n(PARK6)","AR, early onset\nmitochondrial",TEAL), ("SNCA\n(PARK1)","AD, rare\nα-synuclein\nmutations",RED), ("GBA1","Risk factor +\nfaster progression\nLysosomal",PURPLE)] for i,(name,txt,col) in enumerate(genes): cx = 1.4 + i*2.65 fbox(ax,cx,5.45,2.4,0.65,name,col,fs=8.5,bold=True) fbox(ax,cx,4.75,2.4,0.95,txt,col,fs=7.2,tc="white",lsp=1.35) ax.text(7,0.3,"Sources: Harrison's Principles of Internal Medicine 22E · MDS Diagnostic Criteria (Berg et al.) · " "Bradley & Daroff's Neurology", ha="center",fontsize=7,color="#777",style="italic") plt.tight_layout(pad=0.3) plt.savefig(f"{ASSET}/infographic_01_diagnosis.png",dpi=150,bbox_inches="tight", facecolor=fig.get_facecolor()) plt.close() print("Saved infographic_01") PYEOF echo "Exit: $?"
python3 - <<'PYEOF' import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt import matplotlib.patches as mpatches from matplotlib.patches import FancyBboxPatch from matplotlib.patches import Polygon as MplPolygon import textwrap ASSET = "/tmp/workspace/parkinsonism-cpg/assets" NAVY="#1A3A5C";GREEN="#1E8449";RED="#922B21";PURPLE="#6C3483" ORANGE="#B7770D";STEEL="#2471A3";TEAL="#117A65";WARN="#C0392B" WHITE="white";BLACK="#1A1A1A";LGREY="#F2F3F4";MGREY="#BDC3C7" def fbox(ax,cx,cy,w,h,txt,fc,tc="white",fs=9,bold=False,lsp=1.35,wrap=True,pad=0.12): p=FancyBboxPatch((cx-w/2,cy-h/2),w,h,boxstyle=f"round,pad={pad}", fc=fc,ec="white",lw=1.3,zorder=3) ax.add_patch(p) t=textwrap.fill(txt,width=max(6,int(w*9))) if wrap else txt ax.text(cx,cy,t,ha="center",va="center",fontsize=fs,color=tc, fontweight="bold" if bold else "normal",linespacing=lsp, zorder=4,multialignment="center") def arr(ax,x1,y1,x2,y2,lc="#444"): ax.annotate("",xy=(x2,y2),xytext=(x1,y1), arrowprops=dict(arrowstyle="->",color=lc,lw=2),zorder=2) # ════════════════════════════════════════════════════════════════════════════ # INFOGRAPHIC 2 — Treatment Algorithm # ════════════════════════════════════════════════════════════════════════════ fig,ax=plt.subplots(figsize=(16,22)); ax.set_xlim(0,16); ax.set_ylim(0,22); ax.axis("off") fig.patch.set_facecolor("#F7F9FC") ax.text(8,21.5,"PARKINSON'S DISEASE: PHARMACOLOGICAL MANAGEMENT ALGORITHM", ha="center",fontsize=14,fontweight="bold",color=NAVY) ax.text(8,21.1,"Clinical Practice Guideline · Specialist Level · Based on MDS/AAN Guidelines & Katzung Pharmacology 16E", ha="center",fontsize=8.5,color="#555",style="italic") # Stage labels for y,lbl,col in [(19.5,"EARLY PD\n(Mild symptoms, functional impairment minor)",GREEN), (15.5,"MODERATE PD\n(Motor fluctuations beginning, wearing-off)",STEEL), (10.5,"ADVANCED PD\n(Dyskinesias, motor fluctuations, non-motor burden)",ORANGE), (5.5,"REFRACTORY / SURGICAL\n(Drug-resistant fluctuations & dyskinesias)",RED)]: fbox(ax,2,y,3.5,0.95,lbl,col,fs=8.5,bold=True) # ── EARLY PD ────────────────────────────────────────────────────────────── fbox(ax,9,20.5,10,0.75, "CONFIRM DIAGNOSIS · Educate patient · Multidisciplinary team referral · Exercise programme", NAVY,fs=9,bold=True) arr(ax,8,20.12,8,19.5) # Decision: Age / cognitive from matplotlib.patches import Polygon as P2 def diam(ax,cx,cy,w,h,txt,fc,fs=8.5): pts=[(cx,cy+h/2),(cx+w/2,cy),(cx,cy-h/2),(cx-w/2,cy)] ax.add_patch(P2(pts,closed=True,fc=fc,ec="white",lw=1.4,zorder=3)) ax.text(cx,cy,textwrap.fill(txt,width=int(w*6)),ha="center",va="center", fontsize=fs,color="white",fontweight="bold",zorder=4,multialignment="center",linespacing=1.2) diam(ax,8,19.0,9,0.9,"Age <70 AND no significant cognitive impairment?",STEEL,fs=8.5) ax.text(12.7,19.1,"YES →",ha="center",fontsize=8,color=GREEN,fontweight="bold") ax.text(3.7,18.45,"NO ↓",ha="center",fontsize=8,color=WARN,fontweight="bold") # YES branch — young / cognitively intact fbox(ax,13.5,18.55,4.5,1.65, "DOPAMINE AGONIST\nPramipexole · Ropinirole · Rotigotine\n\nOR MAO-B INHIBITOR\nRasagiline · Selegiline\n(Delay levodopa, reduce dyskinesia risk)", GREEN,fs=8,lsp=1.5) arr(ax,11.4,18.55,13.5-2.25,18.55,lc=GREEN) # NO branch — older / cognitive fbox(ax,8,17.55,9.5,1.5, "LEVODOPA / CARBIDOPA (Sinemet / Madopar) — GOLD STANDARD\n" "Start: 100/25 mg TID · Titrate by 50-100 mg/wk to symptom control\n" "Target: lowest effective dose · Extended release for nocturnal symptoms", GREEN,fs=8.5,bold=True,lsp=1.5) arr(ax,8,18.55,8,18.32) ax.text(8,16.65,"If symptoms not adequately controlled, or if dopamine agonist used → ADD levodopa", ha="center",fontsize=8,color="#444",style="italic") # ── MODERATE PD ──────────────────────────────────────────────────────────── arr(ax,8,16.4,8,15.85) fbox(ax,8,15.4,13.5,0.8, "ASSESS FOR MOTOR FLUCTUATIONS · Wearing-off? · Dyskinesias? · On-off unpredictability?", STEEL,fs=9,bold=True) arr(ax,8,15.0,8,14.4) # 3-column moderate options cols_mod = [ ("WEARING-OFF\n→ Add COMT inhibitor\nEntacapone 200mg with each LD dose\nOR Opicapone 50mg OD\nOR Extended-release LD\nOR MAO-B inhibitor adjunct",STEEL), ("ADD DOPAMINE AGONIST\n(if not already on one)\nPramipexole ER / Ropinirole XL\nOR Rotigotine patch\n→ Smooth dopaminergic\nstimulation; less wearing-off",GREEN), ("ISTRADEFYLLINE\n(Adenosine A2A antagonist)\n20-40 mg OD\n→ Reduces OFF-time\nas adjunct to LD/carbidopa\nCan add 20-45 min ON-time/day",TEAL), ] for i,(txt,col) in enumerate(cols_mod): cx=4+i*4 fbox(ax,cx,13.6,3.7,1.5,txt,col,fs=7.8,lsp=1.4) # ── ADVANCED PD ──────────────────────────────────────────────────────────── arr(ax,8,12.82,8,12.2) fbox(ax,8,11.75,13.5,0.8, "ADVANCED PD: Dyskinesias · Severe off-periods · Non-motor burden · Cognitive decline", ORANGE,fs=9,bold=True) cols_adv = [ ("DYSKINESIAS\n→ Amantadine\n(NMDA antagonist)\n100mg BD/TID\nOR ER amantadine\n(Gocovri) at bedtime\n→ Reduce LD peak dose",ORANGE), ("PSYCHOSIS /\nHALLUCINATIONS\n→ Stop anticholinergics\n→ AChEI (rivastigmine)\n→ Quetiapine (low dose)\n→ Clozapine (monitoring)\n→ Pimavanserin",PURPLE), ("AUTONOMIC\nFAILURE\n→ OH: fludrocortisone\n midodrine\n→ Constipation: bulk\n→ Bladder: oxybutynin\n→ ED: PDE5 inhibitors",TEAL), ("COGNITIVE\nDECLINE\n→ Rivastigmine\n (FDA-approved PDD)\n→ Donepezil\n→ Memantine (severe)\n→ AVOID anticholinergics",STEEL), ] arr(ax,8,11.35,8,10.85) for i,(txt,col) in enumerate(cols_adv): cx=2.5+i*3.7 fbox(ax,cx,9.9,3.3,1.7,txt,col,fs=7.5,lsp=1.4) # ── SURGICAL ─────────────────────────────────────────────────────────────── arr(ax,8,9.0,8,8.35) fbox(ax,8,7.9,13.5,0.8, "SURGICAL INTERVENTION — Consider when motor fluctuations persist despite optimised pharmacotherapy", RED,fs=9,bold=True) surgical = [ ("DEEP BRAIN STIMULATION\n(DBS)\nSTN or GPi target\nBest: Good levodopa\nresponder, <70 yrs,\nno dementia, no psychosis\nImproves ON-time ~4-6h/day",RED), ("LEVODOPA-\nCARBIDOPA\nINTESTINAL GEL\n(LCIG / Duodopa)\nContinuous infusion\nvia PEG-J tube\nReduces OFF time",RED), ("FOCUSED\nULTRASOUND\nTHALAMOTOMY\nBest for unilateral\ntremor-dominant PD\nNon-invasive\nNo implant",RED), ("RADIOSURGICAL\nPALLIDOTOMY\n/ THALAMOTOMY\nGamma knife\nFor patients not\nsuitable for DBS\nor FUS",RED), ] arr(ax,8,7.5,8,6.9) for i,(txt,col) in enumerate(surgical): cx=2.5+i*3.7 fbox(ax,cx,6.0,3.3,1.6,txt,col,fs=7.5,lsp=1.4) # MDT box fbox(ax,8,4.5,14,1.2, "MULTIDISCIPLINARY CARE (all stages)\n" "Physiotherapy (gait, balance, exercise) · Speech & Language Therapy (hypophonia, dysphagia)\n" "Occupational Therapy · Neuropsychology · Palliative care (advanced) · Patient support groups", NAVY,fs=8.5,lsp=1.5) # Non-pharm fbox(ax,8,3.2,14,0.9, "NON-PHARMACOLOGICAL: Aerobic exercise (neuroprotective signal) · Tai chi/yoga (balance) · " "Mediterranean diet · Cognitive training · Sleep hygiene", TEAL,fs=8.5) ax.text(8,0.3,"Sources: Katzung Basic & Clinical Pharmacology 16E · AAN Practice Guidelines · " "MDS Evidence-Based Medicine Review · Harrison's 22E", ha="center",fontsize=7,color="#777",style="italic") plt.tight_layout(pad=0.3) plt.savefig(f"{ASSET}/infographic_02_treatment.png",dpi=150,bbox_inches="tight", facecolor=fig.get_facecolor()) plt.close() print("Saved infographic_02") PYEOF
python3 - <<'PYEOF' import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt from matplotlib.patches import FancyBboxPatch, Polygon as MplPoly import textwrap ASSET="/tmp/workspace/parkinsonism-cpg/assets" NAVY="#1A3A5C";GREEN="#1E8449";RED="#922B21";PURPLE="#6C3483" ORANGE="#B7770D";STEEL="#2471A3";TEAL="#117A65";WARN="#C0392B" BLACK="#1A1A1A";LGREY="#F2F3F4";WHITE="white" def fbox(ax,cx,cy,w,h,txt,fc,tc="white",fs=8.5,bold=False,lsp=1.35,wrap=True): p=FancyBboxPatch((cx-w/2,cy-h/2),w,h,boxstyle="round,pad=0.12", fc=fc,ec="white",lw=1.3,zorder=3) ax.add_patch(p) t=textwrap.fill(txt,width=max(6,int(w*8.5))) if wrap else txt ax.text(cx,cy,t,ha="center",va="center",fontsize=fs,color=tc, fontweight="bold" if bold else "normal",linespacing=lsp, zorder=4,multialignment="center") # ════════════════════════════════════════════════════════════════════════════ # INFOGRAPHIC 3 — Atypical Parkinsonism Comparison # ════════════════════════════════════════════════════════════════════════════ fig,ax=plt.subplots(figsize=(18,14)); ax.set_xlim(0,18); ax.set_ylim(0,14); ax.axis("off") fig.patch.set_facecolor("#F7F9FC") ax.text(9,13.55,"ATYPICAL PARKINSONISM: COMPREHENSIVE COMPARISON", ha="center",fontsize=15,fontweight="bold",color=NAVY) ax.text(9,13.15,"PSP · MSA · CBS · DLB vs. Parkinson's Disease | Specialist Reference", ha="center",fontsize=9,color="#555",style="italic") COLS=[(2.2,"PD",GREEN),(5.7,"PSP",RED),(9.2,"MSA",PURPLE),(12.7,"CBS",ORANGE),(16.2,"DLB",STEEL)] ROWS=[ (12.3,"CARDINAL FEATURES"), (10.7,"ONSET / TREMOR"), (9.4,"LEVODOPA"), (8.1,"IMAGING"), (6.8,"PATHOLOGY"), (5.6,"AUTONOMIC"), (4.4,"COGNITIVE"), (3.2,"MANAGEMENT"), (2.0,"PROGNOSIS"), ] # Row label column for y,lbl in ROWS: ax.text(0.35,y,lbl,ha="center",va="center",fontsize=8,color=WHITE,fontweight="bold", bbox=dict(fc=NAVY,ec="white",pad=3,boxstyle="round,pad=0.2"), rotation=0,zorder=4) # Column headers for cx,name,col in COLS: fbox(ax,cx,12.85,3.2,0.55,name,col,fs=12,bold=True) DATA={ "PD":[ "Bradykinesia\nRest tremor\nRigidity\nPostural instability", "Asymmetric onset\nPill-rolling 4-6 Hz\nUnilateral start", "Excellent sustained\nresponse ✓✓\nDyskinesias develop", "DaTscan: asymm.\nposterior putamen ↓\nMIBG: reduced ✓", "Lewy bodies\nAlpha-synuclein\nSNc depigmentation", "Mild-moderate\n(late in disease)\nOH, constipation", "Late-onset dementia\n(PDD after >1 yr)\nSubcortical pattern", "Levodopa/carbidopa\nDopamine agonists\nDBS for advanced", "Slow progression\n10-20 years\nNear-normal lifespan", ], "PSP":[ "Axial > limb rigidity\nRetroflexion neck\nEarly falls yr 1\nDysphagia", "Symmetric onset\nRest tremor rare\nAxial dominant", "Poor / absent\n(<30% respond)\nBrief if any", "Hummingbird sign\n(midbrain atrophy)\nDaTscan: symmetric ↓", "Tau (4R)\nNeurofibrillary tangles\nSubthalamic/SN", "Mild\nurinary urgency\n(late)", "Frontal/executive\nApathy, disinhibition\nRapid decline", "No effective Rx\nFalls prevention\nPEG tube early", "Rapid 5-7 years\nDeath: aspiration\npneumonia", ], "MSA":[ "Parkinsonism (MSA-P)\nOR Cerebellar (MSA-C)\nInspiratory stridor\nEarly autonomic", "Symmetric onset\nPostural tremor\nMild rest tremor", "Partial 30-40%\nfades over time\nNo dyskinesias", "Hot cross bun sign\n(pons, T2 MRI)\nPutaminal ↓ signal", "Alpha-synuclein\nGlial cytoplasmic\ninclusions (GCIs)", "Severe & EARLY ✓✓\nOH · Incontinence\nImpotence · Stridor", "Mild cognitive\ndecline (late)\nFrontal pattern", "Levodopa (partial)\nFludrocortisone/\nmidodrine; CPAP", "Rapid 6-10 years\nStridor = poor\nprognosis", ], "CBS":[ "Markedly asymm.\nAlien limb ✓✓\nIdeomotor apraxia\nMyoclonus", "Markedly asymm.\nPostural/action\nStimulus myoclonus", "Poor/absent\nNo significant\nresponse", "Asymm. frontoparietal\ncortical atrophy\nDaTscan: asymm. ↓", "Tau (4R)\nCorticobasal\ninclusions/astrocytes", "Urinary (late)\nMild autonomic", "Apraxia · Aphasia\nExecutive · Spatial\nPrefrontal syndrome", "No effective Rx\nClonazepam (myo.)\nOT/Speech therapy", "Rapid 6-8 years\nDysarthria &\ndysphagia late", ], "DLB":[ "Parkinsonism mild\nSymmetric motor\nFluctuating alertness\nVisual hallucinations ✓✓", "Symmetric, mild\nRest tremor mild\nMotor after dementia", "Partial response\nCan worsen\npsychiatric sx", "DaTscan: bilat. ↓\nMIBG: reduced ✓\nEEG: posterior slow", "Cortical Lewy bodies\nAlpha-synuclein\nOccipital hypometab.", "Moderate\nOH, syncope\nUrinary urgency", "Dementia ≤1 yr ✓✓\nVisuospatial deficits\nFluctuating attention", "AChEIs (primary)\nAVOID typicals ✓✓\nQuetiapine (psychosis)", "Variable\n5-8 years typical\nNeuroleptics → crisis", ], } row_colours={ "CARDINAL FEATURES": LGREY, "ONSET / TREMOR": "#EAF4FB", "LEVODOPA": "#EAFAF1", "IMAGING": "#EAF2FF", "PATHOLOGY": "#F5EEF8", "AUTONOMIC": "#FEF9E7", "COGNITIVE": "#FDF2F8", "MANAGEMENT": "#E8F8F5", "PROGNOSIS": "#FDEDEC", } for (y,lbl),((_,name,col),dlist) in zip(ROWS, [(c,DATA[c[1]]) for c in COLS]): pass # just to confirm structure # Draw all data cells for ri,(y,lbl) in enumerate(ROWS): bg = row_colours.get(lbl,LGREY) for ci,(cx,name,col) in enumerate(COLS): txt = DATA[name][ri] # highlight special cells cell_bg = bg cell_tc = BLACK if "✓✓" in txt: cell_tc = col p=FancyBboxPatch((cx-1.55,y-0.57),3.1,1.14, boxstyle="round,pad=0.06",fc=cell_bg, ec="#D5D8DC",lw=0.5,zorder=2) ax.add_patch(p) ax.text(cx,y,txt.replace("✓✓","★★").replace("✓","★"), ha="center",va="center",fontsize=7.2, color=cell_tc,linespacing=1.3, zorder=4,multialignment="center", fontweight="bold" if "★★" in txt.replace("✓✓","★★") else "normal") # Row alternating left border for ri,(y,lbl) in enumerate(ROWS): col_val = list(row_colours.values())[ri % len(row_colours)] ax.plot([0.7,0.7],[y-0.6,y+0.6],color=NAVY,lw=2,zorder=5) ax.text(9,0.25, "★★ = Highly characteristic / critical feature " "Sources: Harrison's 22E · Bradley & Daroff's Neurology · Washington Manual · Kaplan & Sadock", ha="center",fontsize=7.5,color="#555",style="italic") plt.tight_layout(pad=0.2) plt.savefig(f"{ASSET}/infographic_03_atypical.png",dpi=150,bbox_inches="tight", facecolor=fig.get_facecolor()) plt.close() print("Saved infographic_03") PYEOF
python3 - <<'PYEOF' import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt from matplotlib.patches import FancyBboxPatch import textwrap, numpy as np ASSET="/tmp/workspace/parkinsonism-cpg/assets" NAVY="#1A3A5C";GREEN="#1E8449";RED="#922B21";PURPLE="#6C3483" ORANGE="#B7770D";STEEL="#2471A3";TEAL="#117A65";WARN="#C0392B" BLACK="#1A1A1A";LGREY="#F4F6F7";WHITE="white";MGREY="#BDC3C7" GOLD="#D4AC0D" def fbox(ax,cx,cy,w,h,txt,fc,tc="white",fs=8.5,bold=False,lsp=1.35,wrap=True): p=FancyBboxPatch((cx-w/2,cy-h/2),w,h,boxstyle="round,pad=0.1", fc=fc,ec="white",lw=1.3,zorder=3) ax.add_patch(p) t=textwrap.fill(txt,width=max(6,int(w*8))) if wrap else txt ax.text(cx,cy,t,ha="center",va="center",fontsize=fs,color=tc, fontweight="bold" if bold else "normal",linespacing=lsp, zorder=4,multialignment="center") # ════════════════════════════════════════════════════════════════════════════ # INFOGRAPHIC 4 — Non-Motor Features + Drug Profile # ════════════════════════════════════════════════════════════════════════════ fig = plt.figure(figsize=(18,22)) fig.patch.set_facecolor("#F7F9FC") # ── TOP HALF: Non-motor wheel ──────────────────────────────────────────── ax1 = fig.add_axes([0.0,0.52,1.0,0.48]) ax1.set_xlim(0,18); ax1.set_ylim(0,10); ax1.axis("off") ax1.text(9,9.55,"NON-MOTOR FEATURES OF PARKINSON'S DISEASE", ha="center",fontsize=14,fontweight="bold",color=NAVY) ax1.text(9,9.2,"Recognition, Timing & Management | Harrison's 22E · Bradley & Daroff's Neurology", ha="center",fontsize=8.5,color="#555",style="italic") # Timeline bar for i,(stage,col,xr) in enumerate([ ("PRE-MOTOR PHASE\n(Years before diagnosis)",GREEN,(1.0,5.5)), ("EARLY MOTOR\n(Diagnosis to ~3 yrs)",STEEL,(5.7,10.5)), ("MODERATE\n(3-8 years)",ORANGE,(10.7,14.5)), ("ADVANCED\n(>8-10 years)",RED,(14.7,17.5)), ]): x1,x2=xr ax1.fill_betweenx([8.4,8.85],[x1],[x2],color=col,alpha=0.9,zorder=2) ax1.text((x1+x2)/2,8.62,stage,ha="center",va="center",fontsize=7.5, color="white",fontweight="bold",zorder=3,multialignment="center",linespacing=1.25) # Non-motor feature boxes features = [ # (cx, cy, title, details, colour, timing_x) (2.2,7.1,"ANOSMIA\n/ HYPOSMIA", "Earliest pre-motor marker\n90% of PD patients affected\nAlpha-syn in olfactory bulb\nTest: UPSIT / sniff sticks",GREEN,2.5), (5.5,7.1,"REM SLEEP\nBEHAVIOUR DISORDER", "Acts out vivid dreams\n>80% idiopathic RBD → PD\nPredates motor by 10-25 yrs\nRx: Melatonin / clonazepam",GREEN,5.5), (8.8,7.1,"CONSTIPATION\n/ GI DYSMOTILITY", "Braak stage 1-2 (enteric)\nPrecedes motor by years\nEnema / osmotic laxatives\nDopamine in gut plexus",GREEN,8.5), (12.1,7.1,"DEPRESSION\n/ ANXIETY", "40-50% prevalence\nDopamine & serotonin ↓\nSSRIs preferred (avoid TCAs)\nCBT beneficial",STEEL,11.5), (15.4,7.1,"ORTHOSTATIC\nHYPOTENSION", "Cardiac sympathetic loss\nMIBG: reduced uptake\nRx: fludrocortisone,\nmidodrine, compression",ORANGE,14.5), (2.2,5.1,"URINARY\nDYSFUNCTION", "Urgency, frequency, nocturia\nDetrusor overactivity\nRx: oxybutynin (avoid in elderly)\nOnabotulinumtoxin A",STEEL,4.0), (5.5,5.1,"PAIN /\nSENSORY SX", "Central pain, akathisia\n40% report pain as main sx\nMusculoskeletal most common\nDopaminergic Rx may help",STEEL,6.5), (8.8,5.1,"HALLUCINATIONS\n/ PSYCHOSIS", "Usually visual (formed images)\nLevodopa-related (peak dose)\nRisk: age, cognitive decline\nRx: AChEIs → quetiapine",ORANGE,10.5), (12.1,5.1,"DEMENTIA\n(PDD)", "~80% at 20 years\nSubcortical + cortical\nRivastigmine (FDA-approved)\nDistinct from DLB by timing",RED,14.0), (15.4,5.1,"DYSPHAGIA\n/ SIALORRHOEA", "Late feature, major mortality\nAspiration pneumonia risk\nSpeech therapy, modified diet\nBotox for drooling",RED,16.0), ] for cx,cy,title,detail,col,_ in features: fbox(ax1,cx,cy+0.35,3.3,0.6,title,col,fs=8,bold=True) fbox(ax1,cx,cy-0.5,3.3,1.05,detail,col,fs=7.2,tc="white",lsp=1.4) ax1.text(9,3.75,"MONITORING SCHEDULE", ha="center",fontsize=11,fontweight="bold",color=NAVY) mon_items=[ ("EVERY\nVISIT",["Motor exam (UPDRS-III)","Non-motor review","Falls assessment","Medication side-effects"],NAVY), ("EVERY\n3 MONTHS",["Orthostatic BP","Weight / nutrition","Bowel & bladder Hx","Sleep disorders screen"],STEEL), ("EVERY\n6 MONTHS",["Cognitive screen (MoCA)","Depression screen (GDS)","Swallowing assessment","DBS programming (if implanted)"],TEAL), ("ANNUALLY",["Full neuropsych assessment","Bone density (fall risk)","Driving fitness review","Advance care planning"],ORANGE), ("AS NEEDED",["DaTscan (dx uncertainty)","MIBG (PDD vs DLB)","Genetic counselling","Multidisciplinary meeting"],RED), ] for i,(freq,items,col) in enumerate(mon_items): cx=1.8+i*3.5 fbox(ax1,cx,3.1,3.2,0.65,freq,col,fs=9,bold=True) txt="\n".join([f"☐ {it}" for it in items]) fbox(ax1,cx,2.0,3.2,1.4,txt,col,fs=7.2,tc="white",lsp=1.5) ax1.text(9,0.35,"Sources: Harrison's Principles of Internal Medicine 22E · Bradley & Daroff's Neurology · " "Katzung Pharmacology 16E · Adams & Victor 12E", ha="center",fontsize=7,color="#777",style="italic") # ── BOTTOM HALF: Drug profile table ────────────────────────────────────── ax2 = fig.add_axes([0.0,0.0,1.0,0.50]) ax2.set_xlim(0,18); ax2.set_ylim(0,11); ax2.axis("off") ax2.text(9,10.6,"ANTIPARKINSONIAN DRUGS: QUICK REFERENCE PROFILE", ha="center",fontsize=13,fontweight="bold",color=NAVY) # Header row headers=["DRUG CLASS","MECHANISM","DOSE (typical)","KEY ADVERSE EFFECTS","USE WHEN","AVOID WHEN"] col_w=[2.8,2.4,2.5,4.0,3.0,3.2] hx=[0.3+sum(col_w[:i])+col_w[i]/2 for i in range(len(col_w))] hy=10.1 for cx,h,w in zip(hx,headers,col_w): fbox(ax2,cx,hy,w-0.08,0.55,h,NAVY,fs=8.5,bold=True) drugs=[ # class, mechanism, dose, AEs, use_when, avoid_when, colour ("Levodopa /\nCarbidopa", "Dopamine precursor\n+ peripheral DDC inhibitor", "Start 50/12.5 mg TID\n→ titrate to response\n(max ~1000mg LD/day)", "Nausea, dyskinesias,\nwearing-off, hallucinations,\northostatic hypotension", "All PD stages\nGold standard\nElderly / cognitive impairment", "Active psychosis\n(relative)\nCareful with MAOIs", GREEN), ("Dopamine\nAgonists\n(Pramipexole,\nRopinirole,\nRotigotine)", "D2/D3 receptor\ndirect agonist\n(non-ergoline preferred)", "Pramipexole:\n0.5-1.5 mg TID\nRopinirole: 2-8 mg TID\nRotigotine: 2-8 mg/24h", "ICD (gambling,\nhypersexuality, binge eating)\nSomnolence, oedema,\nnausea, hallucinations", "Young patients <70\nEarly PD monotherapy\nAdjunct for fluctuations", "Dementia / psychosis\nSevere cardiac disease\nPregnancy", STEEL), ("MAO-B\nInhibitors\n(Rasagiline,\nSelegiline,\nSafinamide)", "Irreversible MAO-B block\n→ ↓ dopamine breakdown\nin striatum", "Rasagiline: 0.5-1 mg OD\nSelegiline: 5 mg BD\nSafinamide: 50-100 mg OD", "Insomnia, headache\nSelegiline: serotonin\nsyndrome (avoid SSRIs/SNRIs)\nNausea", "Early mild PD mono.\nAdjunct: wearing-off\nPossible neuroprotection", "Selegiline + SSRIs/\nSNRIs / meperidine\nSevere hepatic disease", TEAL), ("COMT\nInhibitors\n(Entacapone,\nOpicapone,\nTolcapone)", "Inhibit peripheral\n(+ central for tolcapone)\ncatechol-O-methyltransf.\n→ prolong LD effect", "Entacapone: 200 mg\nwith each LD dose\nOpicapone: 50 mg OD\nTolcapone: 100 mg TID", "Diarrhoea, dyskinesias,\norange urine (entacapone)\nTolcapone: hepatotoxicity\n(monitor LFTs q2-4 wks)", "Wearing-off\nMotor fluctuations\nWith levodopa only", "Tolcapone: liver disease\nHistory of NMS\nActive liver disease", ORANGE), ("Amantadine\n(IR / ER\nGocovri)", "NMDA receptor\nantagonist; also\n↑ dopamine release\n/ reuptake inhibition", "IR: 100 mg BD/TID\nER (Gocovri): 137-274mg\nat bedtime\n(extended-release)", "Livedo reticularis,\nperipheral oedema,\nhallucinations, confusion\nDo NOT stop abruptly", "Mild early PD\nLevodopa dyskinesias\n(ER formulation)", "Renal impairment\n(reduce dose)\nSeizure history\nAbrupt withdrawal", PURPLE), ("AChEIs\n(Rivastigmine,\nDonepezil)", "Acetylcholinesterase\ninhibitor → ↑ ACh\nin cortex & striatum", "Rivastigmine:\n1.5→6 mg BD oral\n4.6→9.5 mg/24h patch\nDonepezil: 5-10 mg OD", "Nausea, vomiting\nBradycardia (caution\nin cardiac disease)\n↑ tremor (rivastigmine)", "PDD (rivastigmine\nFDA-approved)\nDLB cognitive sx\nFirst-line for hallucinations", "Active peptic ulcer\nConducting system\ncardiac disease", RED), ("Quetiapine /\nClozapine", "Atypical antipsychotics\n(D2 weak block +\n5-HT2A antagonism)\n→ low EPS risk", "Quetiapine: 12.5-100mg\nat bedtime\nClozapine: 6.25-50mg\n(requires WBC monitoring)", "Sedation, falls (Q)\nAgranulocytosis: clozapine\n(WBC every 1-4 wks)\nQT prolongation", "PD / DLB psychosis\nIF AChEIs insufficient\nUse lowest effective dose", "Typical antipsychotics\nRisperidone, olanzapine\nAVOID in DLB (mortality ↑)", WARN), ] row_ys=[i*1.22 for i in range(len(drugs),0,-1)] row_ys=[y+0.2 for y in row_ys] for ri,(cls,mech,dose,aes,use,avoid,col) in enumerate(drugs): y=row_ys[ri] bg="#F9F9F9" if ri%2==0 else "#FFFFFF" cells=[cls,mech,dose,aes,use,avoid] tcs=[WHITE,BLACK,BLACK,WARN,GREEN,RED] fcs=[col,bg,bg,bg,bg,bg] for ci,(txt,tc2,fc2,w) in enumerate(zip(cells,tcs,fcs,col_w)): cx=0.3+sum(col_w[:ci])+col_w[ci]/2 p=FancyBboxPatch((cx-w/2+0.04,y-0.52),w-0.08,1.04, boxstyle="round,pad=0.05",fc=fc2,ec=MGREY if fc2!=col else col, lw=0.6,zorder=2) ax2.add_patch(p) wrapped=textwrap.fill(str(txt),width=max(5,int(w*9))) ax2.text(cx,y,wrapped,ha="center",va="center",fontsize=7, color=tc2 if fc2==col else (WARN if tc2==WARN else (GREEN if tc2==GREEN else (RED if tc2==RED else BLACK))), linespacing=1.3,zorder=3,multialignment="center") plt.savefig(f"{ASSET}/infographic_04_nonmotor_drugs.png",dpi=140,bbox_inches="tight", facecolor=fig.get_facecolor()) plt.close() print("Saved infographic_04") PYEOF
python3 - <<'PYEOF' 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.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY, TA_RIGHT from reportlab.platypus import ( SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable, KeepTogether, PageBreak, Image ) from reportlab.platypus.flowables import Flowable import os, glob ASSET = "/tmp/workspace/parkinsonism-cpg/assets" OUT = "/tmp/workspace/parkinsonism-cpg/Parkinsonism_Clinical_Practice_Guideline.pdf" # ── Colours ────────────────────────────────────────────────────────────────── NAVY = colors.HexColor("#1A3A5C"); GREEN = colors.HexColor("#1E8449") RED = colors.HexColor("#922B21"); PURPLE = colors.HexColor("#6C3483") ORANGE = colors.HexColor("#B7770D"); STEEL = colors.HexColor("#2471A3") TEAL = colors.HexColor("#117A65"); WARN = colors.HexColor("#C0392B") LGREY = colors.HexColor("#F2F3F4"); MGREY = colors.HexColor("#D5D8DC") WHITE = colors.white; BLACK = colors.HexColor("#1A1A1A") GOLD = colors.HexColor("#D4AC0D") # ── Document ───────────────────────────────────────────────────────────────── doc = SimpleDocTemplate(OUT, pagesize=A4, leftMargin=16*mm, rightMargin=16*mm, topMargin=14*mm, bottomMargin=14*mm, title="Parkinsonism Clinical Practice Guideline", author="Orris Medical Intelligence") W = A4[0] - 32*mm # ── Styles ─────────────────────────────────────────────────────────────────── def S(name,**kw): return ParagraphStyle(name,**kw) sTitle = S("sTitle", fontSize=20,textColor=WHITE,alignment=TA_CENTER, fontName="Helvetica-Bold",leading=24) sSub = S("sSub", fontSize=9, textColor=WHITE,alignment=TA_CENTER, fontName="Helvetica",leading=13) sH1 = S("sH1", fontSize=12,textColor=WHITE,fontName="Helvetica-Bold", leading=15,leftIndent=6) sH2 = S("sH2", fontSize=10,textColor=NAVY, fontName="Helvetica-Bold", leading=13,spaceBefore=6) sH3 = S("sH3", fontSize=9, textColor=STEEL,fontName="Helvetica-Bold", leading=12,spaceBefore=4) sBody = S("sBody", fontSize=8.5,textColor=BLACK,fontName="Helvetica", leading=12.5,leftIndent=0,spaceAfter=3) sJust = S("sJust", fontSize=8.5,textColor=BLACK,fontName="Helvetica", leading=12.5,alignment=TA_JUSTIFY,spaceAfter=3) sBull = S("sBull", fontSize=8.5,textColor=BLACK,fontName="Helvetica", leading=12.5,leftIndent=12,bulletIndent=4,bulletText="•") sWarn = S("sWarn", fontSize=8.5,textColor=WARN, fontName="Helvetica-Bold", leading=12,leftIndent=12,bulletIndent=4,bulletText="⚠") sNote = S("sNote", fontSize=7.5,textColor=colors.HexColor("#666666"), fontName="Helvetica",leading=10,alignment=TA_CENTER,style="italic") sRec = S("sRec", fontSize=8.5,textColor=NAVY, fontName="Helvetica-Bold", leading=12,leftIndent=12,bulletIndent=4) sGrade = S("sGrade", fontSize=7.5,textColor=WHITE,fontName="Helvetica-Bold", leading=10,alignment=TA_CENTER) def sp(h=5): return Spacer(1,h) def hr(c=MGREY): return HRFlowable(width=W,thickness=0.5,color=c,spaceAfter=3) def colheader(text,sub,col=NAVY): t = Table([[Paragraph(text,sTitle)],[Paragraph(sub,sSub)]],colWidths=[W]) t.setStyle(TableStyle([ ("BACKGROUND",(0,0),(-1,-1),col), ("TOPPADDING",(0,0),(-1,-1),8),("BOTTOMPADDING",(0,0),(-1,-1),8), ("LEFTPADDING",(0,0),(-1,-1),10),("RIGHTPADDING",(0,0),(-1,-1),10), ])) return t def secheader(text,col=NAVY): t = Table([[Paragraph(text,sH1)]],colWidths=[W]) t.setStyle(TableStyle([ ("BACKGROUND",(0,0),(-1,-1),col), ("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5), ("LEFTPADDING",(0,0),(-1,-1),10),("RIGHTPADDING",(0,0),(-1,-1),10), ])) return t def rec_box(grade,text,col=GREEN): gs = ParagraphStyle("g",fontSize=7,textColor=WHITE,fontName="Helvetica-Bold", leading=9,alignment=TA_CENTER) rs = ParagraphStyle("r",fontSize=8.5,textColor=BLACK,fontName="Helvetica",leading=12) t = Table([[Paragraph(grade,gs),Paragraph(text,rs)]], colWidths=[12*mm,W-12*mm]) t.setStyle(TableStyle([ ("BACKGROUND",(0,0),(0,-1),col), ("BACKGROUND",(1,0),(1,-1),LGREY), ("BOX",(0,0),(-1,-1),0.5,col), ("TOPPADDING",(0,0),(-1,-1),3),("BOTTOMPADDING",(0,0),(-1,-1),3), ("LEFTPADDING",(0,0),(-1,-1),4),("RIGHTPADDING",(0,0),(-1,-1),4), ("VALIGN",(0,0),(-1,-1),"MIDDLE"), ("GRID",(0,0),(-1,-1),0.3,MGREY), ])) return t def two_col(items1,items2,h1="",h2="",c1=STEEL,c2=STEEL): hs=ParagraphStyle("th",fontSize=8.5,textColor=WHITE,fontName="Helvetica-Bold", leading=11,alignment=TA_CENTER) cw=W/2-1*mm rows=[[Paragraph(h1,hs),Paragraph(h2,hs)]] if h1 or h2 else [] for i in range(max(len(items1),len(items2))): l=Paragraph(f"• {items1[i]}",sBull) if i<len(items1) else Paragraph("",sBody) r=Paragraph(f"• {items2[i]}",sBull) if i<len(items2) else Paragraph("",sBody) rows.append([l,r]) t=Table(rows,colWidths=[cw,cw]) cmds=[("GRID",(0,0),(-1,-1),0.3,MGREY), ("TOPPADDING",(0,0),(-1,-1),2),("BOTTOMPADDING",(0,0),(-1,-1),2), ("LEFTPADDING",(0,0),(-1,-1),5),("RIGHTPADDING",(0,0),(-1,-1),5), ("VALIGN",(0,0),(-1,-1),"TOP"), ("ROWBACKGROUNDS",(0,1 if (h1 or h2) else 0),(-1,-1),[WHITE,LGREY])] if h1 or h2: cmds+=[("BACKGROUND",(0,0),(0,0),c1),("BACKGROUND",(1,0),(1,0),c2)] t.setStyle(TableStyle(cmds)) return t def img(path,W=W,max_h=200*mm): from reportlab.lib.utils import ImageReader from PIL import Image as PILImage im=PILImage.open(path) iw,ih=im.size ratio=ih/iw ow=W oh=min(ow*ratio,max_h) if oh==max_h: ow=oh/ratio return Image(path,width=ow,height=oh) # ════════════════════════════════════════════════════════════════════════════ # BUILD STORY # ════════════════════════════════════════════════════════════════════════════ story=[] # ── COVER ─────────────────────────────────────────────────────────────────── story.append(colheader( "PARKINSONISM", "Clinical Practice Guideline · Diagnosis · Management · Monitoring\n" "Specialist Reference · August 2026 · Orris Medical Intelligence" )) story.append(sp(8)) # Cover metadata table meta=[ ["Target Users","Neurologists, Movement Disorder Specialists, Geriatricians, General Physicians"], ["Topic","Parkinsonism: Differential Diagnosis and Evidence-Based Management"], ["Edition","2026 (based on MDS Criteria, AAN Guidelines, Harrison's 22E)"], ["Grading System","A=Strong evidence (RCTs/meta-analyses) · B=Moderate (cohort/controlled) · C=Expert consensus/practice"], ["Disclaimer","This guideline is an educational reference. Clinical decisions require individual patient assessment."], ] ms=ParagraphStyle("ms",fontSize=8.5,textColor=BLACK,fontName="Helvetica",leading=12) mb=ParagraphStyle("mb",fontSize=8.5,textColor=NAVY,fontName="Helvetica-Bold",leading=12) meta_rows=[[Paragraph(k,mb),Paragraph(v,ms)] for k,v in meta] mt=Table(meta_rows,colWidths=[35*mm,W-35*mm]) mt.setStyle(TableStyle([ ("GRID",(0,0),(-1,-1),0.3,MGREY), ("BACKGROUND",(0,0),(0,-1),LGREY), ("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4), ("LEFTPADDING",(0,0),(-1,-1),6),("RIGHTPADDING",(0,0),(-1,-1),6), ("VALIGN",(0,0),(-1,-1),"TOP"), ])) story.append(mt) story.append(sp(8)) # Table of contents story.append(secheader("TABLE OF CONTENTS",NAVY)) story.append(sp(4)) toc_items=[ ("1.","Introduction & Scope"), ("2.","Definition & Pathophysiology"), ("3.","Classification of Parkinsonism"), ("4.","Clinical Assessment & Diagnostic Criteria [Infographic 1]"), ("5.","Red Flags & Supportive Features"), ("6.","Investigations"), ("7.","Pharmacological Management [Infographic 2]"), ("8.","Non-Pharmacological Management"), ("9.","Non-Motor Features & Their Management [Infographic 4]"), ("10.","Atypical Parkinsonism Syndromes [Infographic 3]"), ("11.","Special Populations (Young-onset, Elderly, Pregnancy)"), ("12.","Monitoring & Follow-up"), ("13.","Patient Information & Shared Decision Making"), ("14.","References & Evidence Base"), ] toc_s=ParagraphStyle("toc",fontSize=9,textColor=BLACK,fontName="Helvetica", leading=14,leftIndent=12) toc_n=ParagraphStyle("tocn",fontSize=9,textColor=NAVY,fontName="Helvetica-Bold", leading=14) for num,item in toc_items: story.append(Table([[Paragraph(num,toc_n),Paragraph(item,toc_s)]], colWidths=[10*mm,W-10*mm])) story.append(PageBreak()) # ── SECTION 1 ─────────────────────────────────────────────────────────────── story.append(secheader("1. INTRODUCTION & SCOPE",NAVY)) story.append(sp(5)) story.append(Paragraph( "Parkinsonism is the second most common neurodegenerative syndrome worldwide, affecting approximately " "1% of individuals over 60 years and 3% over 80 years. This Clinical Practice Guideline (CPG) provides " "evidence-based recommendations for the diagnosis, differential diagnosis, and management of all major " "forms of parkinsonism in adult patients. It is intended for use by neurologists, movement disorder " "specialists, geriatricians, and general physicians.", sJust)) story.append(sp(4)) story.append(Paragraph( "This guideline covers: idiopathic Parkinson's Disease (PD), Atypical Parkinsonism syndromes " "(Progressive Supranuclear Palsy [PSP], Multiple System Atrophy [MSA], Corticobasal Syndrome [CBS], " "Dementia with Lewy Bodies [DLB]), and Secondary Parkinsonism. It does not address paediatric cases, " "Huntington's disease, or Wilson's disease in detail.", sJust)) story.append(sp(6)) story.append(Paragraph("Key objectives of this guideline:", sH3)) for obj in [ "Provide a structured, stepwise diagnostic framework for parkinsonism using MDS Clinical Diagnostic Criteria", "Define red flags that distinguish PD from atypical and secondary parkinsonism", "Offer evidence-graded pharmacological management recommendations for each stage of PD", "Address the full spectrum of non-motor features and their management", "Guide appropriate investigation ordering and interpretation", "Support multidisciplinary care planning and patient-centred decision making", ]: story.append(Paragraph(obj,sBull)) story.append(sp(8)) # ── SECTION 2 ─────────────────────────────────────────────────────────────── story.append(secheader("2. DEFINITION & PATHOPHYSIOLOGY",TEAL)) story.append(sp(5)) story.append(Paragraph("<b>Parkinsonism</b> is a clinical syndrome defined by bradykinesia (mandatory) " "combined with at least one of: muscular rigidity, rest tremor (4-6 Hz), or postural instability. " "The additional features of flexed posture and freezing of gait complete the full TRAP+2 syndrome " "(Tremor, Rigidity, Akinesia, Postural instability, flexed posture, freezing).", sJust)) story.append(sp(4)) story.append(Paragraph("<b>Pathophysiology — Basal Ganglia Circuit:</b>", sH3)) story.append(Paragraph( "Motor symptoms arise from degeneration of dopaminergic neurons in the Substantia Nigra pars compacta (SNc). " "These neurons project via the nigrostriatal pathway to the striatum (putamen > caudate). " "Dopamine normally modulates two competing pathways:", sJust)) story.append(sp(3)) story.append(two_col( ["Direct pathway (D1): Striatum → GPi inhibition → Thalamus disinhibition → Cortex activation → Movement facilitated", "In PD: D1 activity ↓ → GPi less inhibited → Thalamus over-inhibited → Movement suppressed"], ["Indirect pathway (D2): Striatum → GPe → STN → GPi excitation → Thalamus inhibited → Movement suppressed", "In PD: D2 inhibition lost → STN over-active → GPi hyperactive → Net thalamic inhibition → Bradykinesia"], h1="DIRECT PATHWAY",h2="INDIRECT PATHWAY",c1=GREEN,c2=RED )) story.append(sp(5)) story.append(Paragraph( "<b>Alpha-synuclein & Lewy Bodies:</b> The pathological hallmark of PD is the misfolding and aggregation of " "alpha-synuclein protein into Lewy bodies within surviving neurons. This process follows the Braak staging " "model, beginning in the enteric/autonomic nervous system and olfactory bulb (stages 1-2), progressing to " "the substantia nigra (stage 3-4), and ultimately involving the neocortex (stages 5-6). This explains why " "non-motor features (anosmia, constipation, RBD) precede motor symptoms by 10-25 years.", sJust)) story.append(sp(8)) # ── SECTION 3 ─────────────────────────────────────────────────────────────── story.append(secheader("3. CLASSIFICATION OF PARKINSONISM",STEEL)) story.append(sp(5)) class_data=[ ["CATEGORY","SUBTYPES","KEY FEATURES"], ["Parkinson's Disease\n(~75% of parkinsonism)", "Sporadic (90%)\nGenetic: LRRK2, Parkin, PINK1, SNCA, GBA1\nPD + Dementia (PDD)", "Asymmetric onset · Lewy body pathology · Good levodopa response"], ["Atypical Parkinsonism\n(~15-20%)", "PSP (tau) · MSA (alpha-syn GCIs)\nCBS (tau) · DLB (alpha-syn Lewy)", "Poor levodopa response · Rapid progression · Additional neurological features"], ["Secondary Parkinsonism\n(~5-10%)", "Drug-induced · Vascular · NPH\nToxic · Infective · Metabolic · Neoplastic", "Identifiable cause · Potentially reversible · Normal DaTscan (drug-induced)"], ["Other Neurodegenerative", "Wilson's disease · Huntington's\nSCA3 · Prion disease · X-linked dystonia-parkinsonism", "Systemic or multi-system features · Age of onset often younger"], ] cs=ParagraphStyle("cs",fontSize=8,textColor=BLACK,fontName="Helvetica",leading=11) ch=ParagraphStyle("ch",fontSize=8.5,textColor=WHITE,fontName="Helvetica-Bold",leading=11,alignment=TA_CENTER) ct=Table([[Paragraph(c,ch) for c in class_data[0]]]+ [[Paragraph(c,cs) for c in row] for row in class_data[1:]], colWidths=[45*mm,60*mm,W-105*mm]) ct.setStyle(TableStyle([ ("BACKGROUND",(0,0),(-1,0),NAVY), ("BACKGROUND",(0,1),(0,1),GREEN),("BACKGROUND",(0,2),(0,2),PURPLE), ("BACKGROUND",(0,3),(0,3),STEEL),("BACKGROUND",(0,4),(0,4),ORANGE), ("GRID",(0,0),(-1,-1),0.3,MGREY), ("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4), ("LEFTPADDING",(0,0),(-1,-1),5),("RIGHTPADDING",(0,0),(-1,-1),5), ("VALIGN",(0,0),(-1,-1),"TOP"), ("ROWBACKGROUNDS",(0,1),(-1,-1),[WHITE,LGREY]), ("FONTNAME",(0,1),(0,-1),"Helvetica-Bold"), ("TEXTCOLOR",(0,1),(0,-1),WHITE), ])) story.append(ct) story.append(sp(8)) story.append(PageBreak()) # ── SECTION 4 + INFOGRAPHIC 1 ─────────────────────────────────────────────── story.append(secheader("4. CLINICAL ASSESSMENT & DIAGNOSTIC CRITERIA",GREEN)) story.append(sp(5)) story.append(Paragraph( "<b>MDS Clinical Diagnostic Criteria for Parkinson's Disease (Berg et al., 2015)</b> — the current " "international standard — requires bradykinesia plus rigidity and/or rest tremor as the mandatory " "motor syndrome (parkinsonism). Diagnosis of PD then relies on three additional categories:", sJust)) story.append(sp(4)) for cat,txt in [ ("Supportive Criteria (each increases confidence):", "Unilateral onset, clear rest tremor, excellent levodopa response, levodopa-induced dyskinesias, " "anosmia, cardiac sympathetic denervation on MIBG, REM sleep behaviour disorder, asymmetric DaTscan"), ("Absolute Exclusion Criteria (any single one rules out PD):", "Cerebellar abnormalities, downward vertical gaze palsy, FTD/PPA in first 5 years, " "lower limb parkinsonism only for >3 years, dopaminergic drug exposure, no levodopa response to ≥1g/day, " "cortical sensory loss or apraxia, normal FP-CIT SPECT"), ("Red Flags (must be counterbalanced by supportive criteria):", "Early severe autonomic failure, early recurrent falls, inspiratory stridor, " "absent non-motor features, severe dysautonomia within first year, symmetric parkinsonism"), ]: story.append(Paragraph(f"<b>{cat}</b> {txt}", sBull)) story.append(sp(2)) story.append(sp(4)) story.append(rec_box("A","Diagnosis of PD should use MDS Criteria. Clinically Established PD requires " "parkinsonism + ≥2 supportive features + no red flags + no absolute exclusion criteria. " "Clinically Probable PD requires ≥1 supportive feature with red flags balanced by equal supportive criteria.",GREEN)) story.append(sp(8)) story.append(Paragraph("<b>Infographic 1: Step-by-Step Diagnostic Algorithm</b>", S("ih",fontSize=9,textColor=NAVY,fontName="Helvetica-Bold", leading=12,alignment=TA_CENTER))) story.append(sp(3)) story.append(img(f"{ASSET}/infographic_01_diagnosis.png",W=W,max_h=240*mm)) story.append(sp(4)) story.append(Paragraph( "Figure 1. Diagnostic algorithm for parkinsonism from first presentation through differential diagnosis " "to confirmed Parkinson's Disease or atypical syndrome. Based on MDS Criteria and Harrison's 22E.", sNote)) story.append(PageBreak()) # ── SECTION 5 ─────────────────────────────────────────────────────────────── story.append(secheader("5. RED FLAGS & SUPPORTIVE FEATURES",WARN)) story.append(sp(5)) rf_data=[ ["RED FLAG","MOST LIKELY DIAGNOSIS"], ["Vertical supranuclear gaze palsy (especially downgaze slowing)","PSP"], ["Recurrent unexplained falls within first year of onset","PSP / MSA"], ["Severe autonomic failure (OH, urinary) within first year","MSA"], ["Cerebellar ataxia / nystagmus","MSA-C"], ["Inspiratory stridor or nocturnal laryngeal spasm","MSA"], ["Alien limb phenomenon / ideomotor apraxia","CBS"], ["Dementia onset ≤1 year of motor features","DLB"], ["Recurrent, well-formed visual hallucinations (early)","DLB"], ["Bilateral symmetric onset from day one","Drug-induced / MSA / PSP"], ["Antipsychotic or metoclopramide exposure","Drug-induced"], ["Normal DaTscan / FP-CIT SPECT","Drug-induced / Essential Tremor"], ["Rapid progression to wheelchair within 5 years","MSA / PSP"], ["Pyramidal signs (Babinski, hyperreflexia)","MSA / CBS"], ["Absence of any non-motor PD features despite years of disease","Atypical"], ["No response to levodopa ≥1000 mg/day for adequate duration","Atypical"], ["Age of onset <40 years","Genetic PD / Wilson's / DRD"], ["Hot cross bun sign on brain MRI","MSA"], ["Hummingbird sign on brain MRI sagittal","PSP"], ] rh=ParagraphStyle("rh",fontSize=8,textColor=WHITE,fontName="Helvetica-Bold",leading=11,alignment=TA_CENTER) rc=ParagraphStyle("rc",fontSize=8,textColor=BLACK,fontName="Helvetica",leading=11) rd=ParagraphStyle("rd",fontSize=8,textColor=WARN,fontName="Helvetica-Bold",leading=11) rfrows=[[Paragraph(rf_data[0][0],rh),Paragraph(rf_data[0][1],rh)]] for flag,dx in rf_data[1:]: rfrows.append([Paragraph(f"⚠ {flag}",rc),Paragraph(dx,rd)]) rft=Table(rfrows,colWidths=[130*mm,W-130*mm]) rft.setStyle(TableStyle([ ("BACKGROUND",(0,0),(-1,0),WARN), ("GRID",(0,0),(-1,-1),0.3,MGREY), ("TOPPADDING",(0,0),(-1,-1),3),("BOTTOMPADDING",(0,0),(-1,-1),3), ("LEFTPADDING",(0,0),(-1,-1),5),("RIGHTPADDING",(0,0),(-1,-1),5), ("VALIGN",(0,0),(-1,-1),"MIDDLE"), ("ROWBACKGROUNDS",(0,1),(-1,-1),[WHITE,colors.HexColor("#FEF9F9")]), ])) story.append(rft) story.append(sp(8)) # ── SECTION 6 ─────────────────────────────────────────────────────────────── story.append(secheader("6. INVESTIGATIONS",STEEL)) story.append(sp(5)) story.append(Paragraph( "Investigation selection should be guided by clinical presentation. Not all tests are required in every patient. " "In a patient with classic asymmetric PD presenting after age 60 with excellent levodopa response, " "DaTscan may not be necessary. Investigations should target clinical uncertainty.", sJust)) story.append(sp(5)) inv_data=[ ["INVESTIGATION","CLINICAL USE","RESULT INTERPRETATION","GRADE"], ["DaTscan (FP-CIT SPECT) /\n[18F]FDOPA PET", "Confirm nigrostriatal degeneration; exclude drug-induced parkinsonism and essential tremor", "Reduced: PD, PSP, MSA, CBS (all equally)\nNormal: drug-induced, ET, psychogenic\nPattern: asymm. post. putamen = PD", "A"], ["Brain MRI (3T preferred)", "Exclude structural causes; identify atypical MRI patterns", "Hummingbird/penguin sign = PSP\nHot cross bun = MSA\nAsymm. frontoparietal = CBS\nWM lacunes = vascular", "B"], ["MIBG cardiac scintigraphy", "Differentiate PD/DLB from MSA/PSP/drug-induced", "Reduced H/M ratio = PD or DLB\nPreserved = MSA, PSP, drug-induced", "B"], ["Levodopa challenge\n(carbidopa/levodopa)", "Confirm dopaminergic response; support PD diagnosis", "≥30% UPDRS-III improvement = strong PD support\n<30% = consider atypical", "A"], ["Autonomic battery\n(tilt-table, QSART, urodynamics)", "Quantify autonomic failure; differentiate MSA from PD", "Severe early OH + urinary failure = MSA\nMild-moderate = PD autonomic", "B"], ["Neuropsychological testing", "Characterise cognitive profile; distinguish PDD, DLB, CBS, PSP", "Visuospatial+fluctuation = DLB\nFrontal/executive = PSP\nApraxia+aphasia = CBS\nSubcortical = PD", "B"], ["Ceruloplasmin + 24h urine copper", "Exclude Wilson's disease", "Mandatory if age <50 at onset\nLow ceruloplasmin + high Cu = Wilson's", "A"], ["Thyroid function (TSH, fT4)", "Exclude hypothyroid tremor/bradykinesia", "Hypothyroidism can mimic parkinsonism; reverses with levothyroxine", "C"], ["Genetic panel\n(LRRK2, Parkin, PINK1, SNCA, GBA1)", "Identify monogenic PD; genetic counselling", "Parkin/PINK1: early AR onset\nLRRK2: typical PD, AD\nGBA1: risk + faster progression", "B"], ["CSF alpha-synuclein seed amplification assay (SAA)", "Biomarker for synucleinopathy (emerging)", "High sensitivity/specificity for PD/DLB/MSA\nNegative in PSP/CBS (tauopathies)", "B"], ["Polysomnography", "Confirm REM sleep behaviour disorder", "RBD present in >80% of prodromal PD\nAlso present in MSA, DLB", "B"], ] ih=ParagraphStyle("ih2",fontSize=7.5,textColor=WHITE,fontName="Helvetica-Bold", leading=10,alignment=TA_CENTER) ic=ParagraphStyle("ic",fontSize=7.5,textColor=BLACK,fontName="Helvetica",leading=10) ig=ParagraphStyle("ig",fontSize=8,textColor=WHITE,fontName="Helvetica-Bold", leading=10,alignment=TA_CENTER) invrows=[[Paragraph(c,ih) for c in inv_data[0]]] grade_cols={ "A":colors.HexColor("#1E8449"), "B":colors.HexColor("#2471A3"), "C":colors.HexColor("#B7770D"), } for test,use,interp,grade in inv_data[1:]: gc=grade_cols.get(grade,STEEL) invrows.append([ Paragraph(test,ParagraphStyle("it",fontSize=7.5,textColor=NAVY, fontName="Helvetica-Bold",leading=10)), Paragraph(use,ic), Paragraph(interp,ic), Paragraph(grade,ParagraphStyle("ig2",fontSize=9,textColor=WHITE, fontName="Helvetica-Bold",leading=11, alignment=TA_CENTER)), ]) invt=Table(invrows,colWidths=[38*mm,45*mm,W-97*mm,14*mm]) inv_cmds=[ ("BACKGROUND",(0,0),(-1,0),STEEL), ("GRID",(0,0),(-1,-1),0.3,MGREY), ("TOPPADDING",(0,0),(-1,-1),3),("BOTTOMPADDING",(0,0),(-1,-1),3), ("LEFTPADDING",(0,0),(-1,-1),4),("RIGHTPADDING",(0,0),(-1,-1),4), ("VALIGN",(0,0),(-1,-1),"TOP"), ("ROWBACKGROUNDS",(0,1),(-1,-1),[WHITE,LGREY]), ] for ri,row in enumerate(inv_data[1:],1): gc=grade_cols.get(row[3],STEEL) inv_cmds.append(("BACKGROUND",(3,ri),(3,ri),gc)) invt.setStyle(TableStyle(inv_cmds)) story.append(invt) story.append(sp(4)) story.append(Paragraph( "Grade A = RCT/meta-analysis evidence · Grade B = Cohort/controlled study · Grade C = Expert consensus", sNote)) story.append(PageBreak()) # ── SECTION 7 + INFOGRAPHIC 2 ─────────────────────────────────────────────── story.append(secheader("7. PHARMACOLOGICAL MANAGEMENT",GREEN)) story.append(sp(5)) story.append(Paragraph( "Pharmacological therapy in PD is symptomatic — no disease-modifying treatment has been conclusively " "established. The goal is to maintain function and quality of life with minimal adverse effects. " "Treatment should be individualised, considering age, cognitive status, comorbidities, patient preference, " "and stage of disease.", sJust)) story.append(sp(5)) for title,recs,col in [ ("EARLY PD — MILD SYMPTOMS (Hoehn & Yahr 1-2)",[ ("A","Levodopa/carbidopa is the most effective symptomatic treatment and remains the gold standard at all stages. " "Start low and titrate to symptom control. Target the lowest effective dose to minimise dyskinesia risk."), ("A","In patients aged <70 years with no significant cognitive impairment, a dopamine agonist (pramipexole, " "ropinirole, or rotigotine) may be used as initial monotherapy to delay levodopa exposure and reduce " "early dyskinesia risk. Inform patients of impulse control disorder risk (5-17%)."), ("A","MAO-B inhibitors (rasagiline, selegiline, safinamide) provide mild symptomatic benefit and may be " "used as initial monotherapy in very mild disease or as an adjunct. Selegiline: avoid with SSRIs/SNRIs."), ("C","Physiotherapy, exercise (aerobic + resistance), and speech therapy should be initiated at diagnosis " "alongside pharmacotherapy."), ],GREEN), ("MODERATE PD — MOTOR FLUCTUATIONS",[ ("A","Wearing-off: Add a COMT inhibitor (entacapone with each levodopa dose, or opicapone 50mg OD) " "OR add a MAO-B inhibitor OR switch to controlled-release levodopa formulations."), ("A","Alternatively, add a dopamine agonist if not already prescribed, to smooth motor response " "and extend ON-time."), ("B","Istradefylline (adenosine A2A antagonist, 20-40mg OD) reduces OFF-time by ~45 min/day as adjunct " "to levodopa/carbidopa and is well tolerated."), ("B","Divide total daily levodopa into smaller, more frequent doses (e.g. 4-6 times daily) " "to reduce peak-dose dyskinesias while maintaining total daily exposure."), ],STEEL), ("ADVANCED PD — DYSKINESIAS & REFRACTORY FLUCTUATIONS",[ ("A","Amantadine (NMDA antagonist) reduces levodopa-induced dyskinesias. " "Extended-release amantadine (Gocovri 274mg at bedtime) is FDA-approved for dyskinesias."), ("A","Deep Brain Stimulation (DBS) of the subthalamic nucleus (STN) or globus pallidus internus (GPi) " "significantly improves motor fluctuations and dyskinesias in carefully selected patients. " "Best candidates: good levodopa response, age <70, no significant dementia or psychosis."), ("B","Levodopa-carbidopa intestinal gel (LCIG/Duodopa) via PEG-jejunal infusion provides continuous " "dopaminergic stimulation and markedly reduces OFF-time in patients not suitable for DBS."), ("B","Focused ultrasound thalamotomy provides unilateral tremor suppression in tremor-dominant PD " "where DBS is not suitable."), ("C","For PD-related psychosis: first reduce/eliminate anticholinergics and dopamine agonists. " "If necessary add: AChEI (rivastigmine) → quetiapine → clozapine (with WBC monitoring). " "NEVER use haloperidol, risperidone, or olanzapine in PD/DLB."), ],ORANGE), ]: story.append(Paragraph(title, sH2)) story.append(sp(3)) for grade,text in recs: story.append(rec_box(f"Grade\n{grade}",text, grade_cols.get(grade,STEEL))) story.append(sp(3)) story.append(sp(4)) story.append(Paragraph("<b>Infographic 2: Pharmacological Management Algorithm</b>", S("ih3",fontSize=9,textColor=NAVY,fontName="Helvetica-Bold", leading=12,alignment=TA_CENTER))) story.append(sp(3)) story.append(img(f"{ASSET}/infographic_02_treatment.png",W=W,max_h=250*mm)) story.append(sp(3)) story.append(Paragraph( "Figure 2. Parkinson's Disease pharmacological management algorithm from early through advanced disease " "and surgical options. Based on AAN Practice Guidelines, MDS Evidence Review, and Katzung Pharmacology 16E.",sNote)) story.append(PageBreak()) # ── SECTION 8 ─────────────────────────────────────────────────────────────── story.append(secheader("8. NON-PHARMACOLOGICAL MANAGEMENT",TEAL)) story.append(sp(5)) story.append(two_col( ["Physiotherapy: gait training, balance, posture, fall prevention, cueing strategies", "Aerobic exercise (150 min/week moderate intensity): neuroprotective signal in animal models; improves motor scores", "Resistance training: muscle strength, freezing of gait, functional independence", "Tai Chi / yoga: balance and fall reduction (RCT evidence)", "Dance therapy (tango): gait and balance improvement (pilot evidence)", "Occupational therapy: adaptive equipment, home hazard assessment, driving review", ], ["Speech & Language Therapy: Lee Silverman Voice Treatment (LSVT LOUD) for hypophonia", "Swallowing assessment and modified diet for dysphagia (refer early in MSA/PSP)", "Neuropsychology: cognitive rehabilitation, depression/anxiety management, CBT", "Dietitian: Mediterranean diet, nutritional assessment, protein redistribution (with levodopa)", "Palliative care: advance care planning, goals of care, end-of-life symptom management", "Patient support groups: Parkinson's UK, Michael J. Fox Foundation, World Parkinson Coalition", ], h1="PHYSICAL & FUNCTIONAL",h2="COMMUNICATION & COGNITIVE",c1=TEAL,c2=STEEL )) story.append(sp(6)) story.append(rec_box("A","Regular aerobic exercise (≥150 min/week moderate intensity) is recommended for " "all PD patients for motor and non-motor benefit. Physiotherapy and speech therapy " "should be offered at time of diagnosis.", TEAL)) story.append(sp(8)) # ── SECTION 9 + INFOGRAPHIC 4 ─────────────────────────────────────────────── story.append(secheader("9. NON-MOTOR FEATURES & MANAGEMENT",PURPLE)) story.append(sp(5)) story.append(Paragraph( "Non-motor features are present in >90% of PD patients throughout the disease course and have a greater " "impact on quality of life than motor symptoms in many patients. Pre-motor features (anosmia, constipation, " "RBD) may precede motor onset by 5-25 years. Systematic screening at each visit is recommended.", sJust)) story.append(sp(4)) nm_data=[ ["FEATURE","PREVALENCE","SCREENING","MANAGEMENT","GRADE"], ["Constipation","50-80% (pre-motor)","Bowel habit history","Increase fluid/fibre, osmotic laxatives, polyethylene glycol","C"], ["Anosmia","90%","UPSIT / Sniffin' Sticks","No treatment; prognostic biomarker","C"], ["REM sleep behaviour disorder","40-50% at diagnosis","Polysomnography","Melatonin 2-12mg OR clonazepam 0.25-0.5mg","B"], ["Depression","40-50%","GDS-15 / PHQ-9","SSRIs (sertraline, escitalopram); avoid TCAs","A"], ["Anxiety","30-40%","GAD-7","SSRIs; CBT; avoid benzodiazepines","B"], ["Orthostatic hypotension","30-40%","Standing BP (1,3,5 min)","Head-up tilt, compression stockings, fludrocortisone, midodrine","B"], ["Urinary urgency","40-70%","IPSS questionnaire","Bladder training, solifenacin, botulinum toxin","C"], ["Cognitive impairment (MCI→PDD)","80% by 20 yrs","MoCA (monthly)","Rivastigmine (FDA-approved PDD); donepezil","A"], ["Visual hallucinations","20-40%","Ask directly at each visit","Reduce/stop anticholinergics; rivastigmine; quetiapine","B"], ["Drooling / sialorrhoea","70-80% advanced","Clinical assessment","Speech therapy; atropine drops; botulinum toxin","B"], ["Pain","40-60%","NRS; pain type classification","Optimise dopaminergic therapy; pregabalin (nociceptive)","C"], ["Impulse control disorder","5-17% on DAs","QUIP-RS screening","Reduce/stop dopamine agonist; CBT","A"], ] nh=ParagraphStyle("nh",fontSize=7.5,textColor=WHITE,fontName="Helvetica-Bold",leading=10,alignment=TA_CENTER) nc=ParagraphStyle("nc",fontSize=7.5,textColor=BLACK,fontName="Helvetica",leading=10) nmrows=[[Paragraph(c,nh) for c in nm_data[0]]] for row in nm_data[1:]: nmrows.append([Paragraph(c,nc) for c in row]) nmt=Table(nmrows,colWidths=[32*mm,22*mm,30*mm,W-98*mm,14*mm]) nm_cmds=[ ("BACKGROUND",(0,0),(-1,0),PURPLE), ("GRID",(0,0),(-1,-1),0.3,MGREY), ("TOPPADDING",(0,0),(-1,-1),3),("BOTTOMPADDING",(0,0),(-1,-1),3), ("LEFTPADDING",(0,0),(-1,-1),4),("RIGHTPADDING",(0,0),(-1,-1),4), ("VALIGN",(0,0),(-1,-1),"TOP"), ("ROWBACKGROUNDS",(0,1),(-1,-1),[WHITE,LGREY]), ] for ri,row in enumerate(nm_data[1:],1): gc=grade_cols.get(row[4],STEEL) nm_cmds.append(("BACKGROUND",(4,ri),(4,ri),gc)) nmt.setStyle(TableStyle(nm_cmds)) story.append(nmt) story.append(sp(5)) story.append(Paragraph("<b>Infographic 4: Non-Motor Features, Timeline & Drug Profile</b>", S("ih4",fontSize=9,textColor=NAVY,fontName="Helvetica-Bold", leading=12,alignment=TA_CENTER))) story.append(sp(3)) story.append(img(f"{ASSET}/infographic_04_nonmotor_drugs.png",W=W,max_h=260*mm)) story.append(sp(3)) story.append(Paragraph( "Figure 4. Non-motor features of Parkinson's Disease mapped to disease timeline, monitoring schedule (top), " "and antiparkinsonian drug quick-reference profile with adverse effects (bottom).", sNote)) story.append(PageBreak()) # ── SECTION 10 + INFOGRAPHIC 3 ────────────────────────────────────────────── story.append(secheader("10. ATYPICAL PARKINSONISM SYNDROMES",RED)) story.append(sp(5)) story.append(Paragraph( "Atypical Parkinsonism syndromes (APS) collectively account for ~15-20% of parkinsonism. They are " "clinically important because they have poor levodopa response, more rapid progression, " "and require different management. Misdiagnosis rates are high: ~25% of PD diagnoses, and up to " "74% of CBS cases may be initially misdiagnosed. Post-mortem studies remain the diagnostic gold standard.", sJust)) story.append(sp(5)) for name,col,features,imaging,path,mgmt in [ ("PROGRESSIVE SUPRANUCLEAR PALSY (PSP)",RED, "Vertical supranuclear gaze palsy (downward >> upward) · Early unexplained falls (retropulsion) · " "Axial rigidity > limb rigidity · Retrocollis · Frontal/executive cognitive decline · " "Eyelid opening apraxia · Dysphagia early", "MRI sagittal: Hummingbird/penguin sign (midbrain atrophy) · Reduced midbrain diameter <14mm · " "DaTscan: symmetric reduction", "4R-Tauopathy · Neurofibrillary tangles in STN, SN, locus coeruleus, frontal cortex", "No effective pharmacotherapy · Falls prevention programme · PEG tube for dysphagia · " "Botulinum toxin for blepharospasm · Supportive/palliative care · Prognosis: 5-7 years"), ("MULTIPLE SYSTEM ATROPHY (MSA)",PURPLE, "MSA-P: Parkinsonism (dominant) · MSA-C: Cerebellar ataxia (dominant) · " "Severe early autonomic failure (OH, urinary incontinence, erectile dysfunction) · " "Inspiratory stridor / nocturnal laryngeal spasm · Emotional incontinence · " "Onset typically age 50-60", "MRI: Hot cross bun sign (pons, T2) · Putaminal hypointensity + slit-like signal (T2*) · " "Cerebellar atrophy (MSA-C) · DaTscan: symmetric bilateral reduction", "Alpha-synuclein in Glial Cytoplasmic Inclusions (GCIs) in oligodendrocytes · " "Olivopontocerebellar atrophy (MSA-C) · Striatonigral degeneration (MSA-P)", "Levodopa trial (partial response 30-40%, fades) · Fludrocortisone + midodrine for OH · " "CPAP or tracheostomy for stridor · Urological referral · PEG tube · " "Physiotherapy for ataxia · Prognosis: 6-10 years"), ("CORTICOBASAL SYNDROME (CBS)",ORANGE, "Markedly asymmetric parkinsonism · Alien limb phenomenon · Ideomotor limb apraxia · " "Cortical sensory loss (astereognosis, graphaesthesia) · Focal limb dystonia · " "Stimulus-sensitive myoclonus · Nonfluent aphasia (if frontal involvement)", "MRI: Asymmetric frontoparietal cortical atrophy (contralateral to affected limb) · " "FDG-PET: Asymmetric frontoparietal hypometabolism · DaTscan: Asymmetric reduction", "4R-Tauopathy · Corticobasal inclusions (astrocytic plaques + NT inclusions) · " "Also: TDP-43 pathology in some CBS presentations", "No effective pharmacotherapy · Clonazepam for myoclonus · " "OT for limb apraxia and function · Speech therapy for aphasia · " "Physiotherapy · Prognosis: 6-8 years · Botulinum toxin for focal dystonia"), ("DEMENTIA WITH LEWY BODIES (DLB)",STEEL, "Dementia onset ≤1 year of motor parkinsonism (vs. PDD where dementia comes >1 year after motor) · " "Recurrent well-formed visual hallucinations · Fluctuating cognition and alertness · " "REM sleep behaviour disorder · SEVERE neuroleptic sensitivity (risk of death) · " "Repeated unexplained falls · Syncope", "DaTscan: Bilateral reduced dopamine transporter · MIBG cardiac scintigraphy: Reduced H/M ratio · " "FDG-PET: Occipital hypometabolism · EEG: Posterior slow waves", "Cortical and subcortical Lewy bodies (alpha-synuclein) · " "Cholinergic deficit more severe than PD or AD · " "Some patients have concurrent AD pathology", "AChEIs (rivastigmine, donepezil) — first-line for cognition AND hallucinations · " "ABSOLUTELY AVOID: haloperidol, olanzapine, risperidone (mortality risk) · " "Quetiapine or clozapine ONLY if AChEIs insufficient for psychosis · " "Low-dose levodopa for motor symptoms · Melatonin/clonazepam for RBD"), ]: story.append(Paragraph(name, sH2)) story.append(sp(3)) feat_style=ParagraphStyle("fss",fontSize=8,textColor=BLACK,fontName="Helvetica",leading=12) ks=ParagraphStyle("ks",fontSize=8,textColor=WHITE,fontName="Helvetica-Bold",leading=11,alignment=TA_CENTER) block=Table([ [Paragraph("CLINICAL FEATURES",ks),Paragraph("IMAGING",ks), Paragraph("PATHOLOGY",ks),Paragraph("MANAGEMENT",ks)], [Paragraph(features,feat_style),Paragraph(imaging,feat_style), Paragraph(path,feat_style),Paragraph(mgmt,feat_style)], ],colWidths=[W/4]*4) block.setStyle(TableStyle([ ("BACKGROUND",(0,0),(-1,0),col), ("GRID",(0,0),(-1,-1),0.3,MGREY), ("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4), ("LEFTPADDING",(0,0),(-1,-1),5),("RIGHTPADDING",(0,0),(-1,-1),5), ("VALIGN",(0,0),(-1,-1),"TOP"), ("ROWBACKGROUNDS",(0,1),(-1,-1),[colors.HexColor("#FDF2F2") if col==RED else colors.HexColor("#F5EEF8") if col==PURPLE else colors.HexColor("#FDFBE4") if col==ORANGE else LGREY]), ])) story.append(block) story.append(sp(6)) story.append(Paragraph("<b>Infographic 3: Atypical Parkinsonism At-a-Glance Comparison</b>", S("ih5",fontSize=9,textColor=NAVY,fontName="Helvetica-Bold", leading=12,alignment=TA_CENTER))) story.append(sp(3)) story.append(img(f"{ASSET}/infographic_03_atypical.png",W=W,max_h=230*mm)) story.append(sp(3)) story.append(Paragraph( "Figure 3. Comprehensive comparison of PD vs. PSP, MSA, CBS and DLB across 9 clinical, " "imaging, pathological and management domains. ★★ = highly characteristic/critical feature.",sNote)) story.append(PageBreak()) # ── SECTION 11 ────────────────────────────────────────────────────────────── story.append(secheader("11. SPECIAL POPULATIONS",GOLD)) story.append(sp(5)) for pop,items in [ ("YOUNG-ONSET PD (Age <50 years)",[ "Mandatory Wilson's disease screen: ceruloplasmin, 24h urine copper, slit-lamp examination", "Genetic testing recommended: Parkin (PARK2) accounts for up to 50% of early-onset AR cases; " "also PINK1, DJ-1, GBA1", "Higher risk of early levodopa-induced motor complications — start dopamine agonist first where possible", "DaTscan useful to confirm diagnosis; FDG-PET may aid differential", "Genetic counselling for patient and family members; consider cascade testing", "Employment, fertility, and insurance implications must be discussed proactively", ]), ("ELDERLY PATIENTS (Age >80 years)",[ "Levodopa/carbidopa is the preferred first-line treatment — dopamine agonists poorly tolerated (falls, somnolence, ICD)", "Avoid anticholinergics (trihexyphenidyl, benztropine): high risk of confusion, urinary retention, falls", "Orthostatic hypotension is common — check lying and standing BP at every visit", "Fall risk assessment and home hazard modification are mandatory at diagnosis", "Cognitive assessment (MoCA) at baseline and every 6-12 months", "Drug-induced parkinsonism must be excluded before commencing dopaminergic therapy", ]), ("PREGNANCY",[ "No antiparkinsonian drug is established as safe in pregnancy — counsel carefully", "If treatment essential: levodopa is the most studied; animal studies show no teratogenicity", "Dopamine agonists: limited data; generally avoided in first trimester", "Multidisciplinary team approach: obstetrician + neurologist + neonatologist", "Genetic counselling: LRRK2 (AD) and Parkin (AR) — implications for offspring", "Postpartum monitoring: disease may worsen after delivery", ]), ("HEPATIC / RENAL IMPAIRMENT",[ "Pramipexole: renal excretion — reduce dose if eGFR <50 ml/min", "Tolcapone: avoid in liver disease (hepatotoxic — monitor LFTs q2-4 wks)", "Amantadine: reduce dose in renal impairment; avoid if eGFR <15", "Levodopa/carbidopa: no dose adjustment for renal/hepatic impairment", "Selegiline: caution in severe hepatic impairment", ]), ]: story.append(Paragraph(pop,sH2)) for item in items: story.append(Paragraph(item,sBull)) story.append(sp(5)) story.append(PageBreak()) # ── SECTION 12 ────────────────────────────────────────────────────────────── story.append(secheader("12. MONITORING & FOLLOW-UP",TEAL)) story.append(sp(5)) mon_data=[ ["INTERVAL","CLINICAL ASSESSMENT","INVESTIGATIONS","MANAGEMENT REVIEW"], ["Every visit\n(3-6 monthly\nearly; 3-monthly\nadvanced)", "UPDRS-III motor score\nFall history + pull test\nNon-motor symptom review (NMSScale)\nOrthostatic BP\nWeight + nutrition\nMedication side-effects", "—","Medication optimisation\nPhysiotherapy referral if new issues\nSpeech therapy if hypophonia/dysphagia"], ["Every 6 months", "MoCA cognitive screening\nDepression screen (GDS-15)\nSwallowing assessment\nSleep disorder assessment (PDSS-2)\nQUIP-RS (if on DA)", "Renal function (amantadine)\nLFTs (tolcapone)\nFull blood count (clozapine)", "Adjust medications for fluctuations\nConsider COMT inhibitor/DA if wearing-off\nRefer neuropsychology if MoCA <24"], ["Annually", "Full neuropsychological assessment\nBone mineral density (DEXA)\nDriving fitness review\nAdvance care planning discussion\nCaregiver burden assessment", "DaTscan (if diagnostic uncertainty remains)\nGenetic counselling update (if relevant)", "Consider DBS assessment if advanced motor complications\nMDT meeting\nPalliative care referral if advanced disease"], ["As clinically\nindicated", "Urodynamics (urinary sx)\nOphthalmology (visual sx)\nCardiology (syncope)", "MIBG if DLB vs PD uncertain\nCSF SAA biomarker\nPolysomnography for RBD\nTilt table for severe OH", "PEG tube assessment (dysphagia)\nLCIG assessment (severe fluctuations)\nFocused ultrasound (tremor)\nHospice referral"], ] mh=ParagraphStyle("mh",fontSize=8,textColor=WHITE,fontName="Helvetica-Bold",leading=10,alignment=TA_CENTER) mc=ParagraphStyle("mc",fontSize=7.5,textColor=BLACK,fontName="Helvetica",leading=11) mrows=[[Paragraph(c,mh) for c in mon_data[0]]] for row in mon_data[1:]: mrows.append([Paragraph(c,mc) for c in row]) mt2=Table(mrows,colWidths=[22*mm,55*mm,45*mm,W-122*mm]) mt2.setStyle(TableStyle([ ("BACKGROUND",(0,0),(-1,0),TEAL), ("GRID",(0,0),(-1,-1),0.3,MGREY), ("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4), ("LEFTPADDING",(0,0),(-1,-1),5),("RIGHTPADDING",(0,0),(-1,-1),5), ("VALIGN",(0,0),(-1,-1),"TOP"), ("ROWBACKGROUNDS",(0,1),(-1,-1),[WHITE,LGREY]), ("BACKGROUND",(0,1),(0,1),colors.HexColor("#0A5C4C")), ("BACKGROUND",(0,2),(0,2),TEAL), ("BACKGROUND",(0,3),(0,3),colors.HexColor("#0D7A64")), ("BACKGROUND",(0,4),(0,4),STEEL), ("TEXTCOLOR",(0,1),(0,-1),WHITE), ("FONTNAME",(0,1),(0,-1),"Helvetica-Bold"), ])) story.append(mt2) story.append(sp(8)) # ── SECTION 13 ────────────────────────────────────────────────────────────── story.append(secheader("13. PATIENT INFORMATION & SHARED DECISION MAKING",NAVY)) story.append(sp(5)) story.append(two_col( ["Inform patients of diagnosis sensitively, with time for questions and follow-up appointment", "Explain the progressive nature of PD but emphasise that many people live well for 10-20+ years", "Discuss treatment options including benefits, risks, and alternatives for each drug class", "Counsel on impulse control disorder risk with dopamine agonists — must be explicit", "Discuss genetic implications if family history is present or onset is early", "Provide written information (Parkinson's UK, EPDA leaflets)", ], ["Driving: notify DVLA (UK) / equivalent authority; reassess annually", "Exercise: emphasise the benefit of regular aerobic exercise — prescribe it", "Diet: Mediterranean diet, avoid protein-heavy meals close to levodopa doses", "Falls prevention: home assessment, avoid rugs, grab rails, alarm device", "Advance care planning: discuss while patient has capacity; include LPA", "Support groups: Parkinson's UK, Michael J Fox Foundation, local carer groups", ], h1="INFORMATION & COUNSELLING",h2="LIFESTYLE & SAFETY",c1=NAVY,c2=STEEL )) story.append(sp(8)) # ── SECTION 14 ────────────────────────────────────────────────────────────── story.append(secheader("14. REFERENCES & EVIDENCE BASE",GREY:=colors.HexColor("#555555"))) story.append(sp(5)) refs=[ "Berg D, et al. MDS Research Criteria for Prodromal Parkinson's Disease. Movement Disorders 2015;30(12):1600-11.", "Postuma RB, et al. MDS Clinical Diagnostic Criteria for Parkinson's Disease. Movement Disorders 2015;30(12):1591-601.", "Harrison's Principles of Internal Medicine, 22nd Edition. McGraw-Hill, 2025. Chapter 446: Parkinson's Disease and Related Disorders.", "Bradley and Daroff's Neurology in Clinical Practice, 8th Edition. Elsevier, 2022. Chapters 24, 95.", "Katzung BG. Basic and Clinical Pharmacology, 16th Edition. McGraw-Hill, 2023. Chapter 28: Pharmacologic Management of Parkinsonism.", "Adams and Victor's Principles of Neurology, 12th Edition. McGraw-Hill, 2023.", "Kaplan & Sadock's Comprehensive Textbook of Psychiatry, 11th Edition.", "Washington Manual of Medical Therapeutics, 36th Edition. Wolters Kluwer, 2020.", "Kalia LV, Lang AE. Parkinson's Disease. Lancet 2015;386(9996):896-912.", "Braak H, et al. Staging of brain pathology related to sporadic Parkinson's disease. Neurobiology of Aging 2003;24(2):197-211.", "Reese R, et al. Invasive therapies for Parkinson's disease: an adapted excerpt from the guidelines of the German Society of Neurology. J Neurology 2025. PMID: 39985674.", "Weaver FM, et al. Bilateral deep brain stimulation vs. best medical therapy for advanced Parkinson's disease: a randomized controlled trial. JAMA 2009;301(1):63-73.", "Rivastigmine for PD dementia (EXPRESS study). Emre M, et al. NEJM 2004;351(24):2509-18.", "McKeith IG, et al. Diagnosis and management of dementia with Lewy bodies: Fourth consensus report of the DLB Consortium. Neurology 2017;89(1):88-100.", "O'Sullivan SS, et al. Clinicopathological findings in PSP. Brain 2008;131(6):1659-73.", ] rs=ParagraphStyle("rs",fontSize=7.5,textColor=BLACK,fontName="Helvetica", leading=11,leftIndent=15,firstLineIndent=-15) for i,ref in enumerate(refs,1): story.append(Paragraph(f"{i}. {ref}",rs)) story.append(sp(2)) story.append(sp(8)) story.append(hr()) story.append(Paragraph( "© 2026 Orris Medical Intelligence. This Clinical Practice Guideline is intended for educational and " "reference purposes only. It does not constitute formal institutional clinical guidelines. " "Clinical decisions should be individualised and made in consultation with the patient. " "Always refer to current national guidelines and drug monographs for prescribing decisions.", sNote)) doc.build(story) print(f"PDF saved: {OUT}") import os; print(f"Size: {os.path.getsize(OUT)//1024} KB, pages ~{os.path.getsize(OUT)//8000}") PYEOF
?
Parkinsonism Clinical Practice Guideline
PDF Document · PDF
Can you make a video explaining drugs use in Parkinson
What would be most useful for you?
best YouTube videos Parkinson disease drugs pharmacology explained levodopa dopamine agonists
265,000+ views · Based on Lippincott Pharmacology
320,000+ views · Ideal for quick review
| Channel | What to search | Style |
|---|---|---|
| Osmosis | "Parkinson's pharmacology" | Animated, visual |
| Armando Hasudungan | "Parkinson's treatment" | Hand-drawn mechanisms |
| Sketchy Medical | "Parkinson's drugs" | Mnemonic stories |
| Boards & Beyond | "Parkinson's medications" | USMLE-focused |
| DirtyUSMLE | "Parkinson's" | High-yield bullet style |
Armando hasudungan
Armando Hasudungan Parkinson's disease treatment drugs YouTube
Osmosis
Osmosis YouTube Parkinson's disease drugs pharmacology treatment video