~/tia-history/generate_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm
from reportlab.lib import colors
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import ListFlowable, ListItem
OUTPUT = "/home/daytona/workspace/tia-history/TIA_History_Presentation.pdf"
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
rightMargin=2*cm, leftMargin=2*cm,
topMargin=2.2*cm, bottomMargin=2.2*cm,
title="TIA Patient History Presentation - Shashi Kumar Mahati",
author="Dhulikhel Hospital Neuro ICU"
)
styles = getSampleStyleSheet()
# ── Custom styles ────────────────────────────────────────────────────
NAVY = colors.HexColor("#1a3557")
TEAL = colors.HexColor("#0e7490")
LBLUE = colors.HexColor("#e8f4f8")
LGREY = colors.HexColor("#f5f5f5")
RED = colors.HexColor("#c0392b")
GREEN = colors.HexColor("#1e7e34")
AMBER = colors.HexColor("#d97706")
WHITE = colors.white
BLACK = colors.black
def S(name, **kw):
"""Quick ParagraphStyle builder."""
base = styles["Normal"]
return ParagraphStyle(name, parent=base, **kw)
cover_title = S("CoverTitle", fontSize=22, textColor=WHITE, alignment=TA_CENTER, leading=28, fontName="Helvetica-Bold")
cover_sub = S("CoverSub", fontSize=13, textColor=LBLUE, alignment=TA_CENTER, leading=18, fontName="Helvetica")
cover_detail = S("CoverDetail", fontSize=11, textColor=WHITE, alignment=TA_CENTER, leading=16, fontName="Helvetica")
h1 = S("H1", fontSize=15, textColor=WHITE, fontName="Helvetica-Bold", leading=20, spaceAfter=4, spaceBefore=10)
h2 = S("H2", fontSize=12, textColor=NAVY, fontName="Helvetica-Bold", leading=16, spaceAfter=3, spaceBefore=8)
h3 = S("H3", fontSize=10, textColor=TEAL, fontName="Helvetica-Bold", leading=14, spaceAfter=2, spaceBefore=6)
body = S("Body", fontSize=9, textColor=BLACK, fontName="Helvetica", leading=13, spaceAfter=3, alignment=TA_JUSTIFY)
body_sm = S("BodySm", fontSize=8, textColor=BLACK, fontName="Helvetica", leading=12, spaceAfter=2)
bold_body = S("BoldBody", fontSize=9, textColor=BLACK, fontName="Helvetica-Bold", leading=13, spaceAfter=3)
note = S("Note", fontSize=8, textColor=colors.HexColor("#555555"), fontName="Helvetica-Oblique", leading=11, leftIndent=10)
red_note = S("RedNote", fontSize=8, textColor=RED, fontName="Helvetica-Bold", leading=11, leftIndent=8)
green_note = S("GreenNote", fontSize=8, textColor=GREEN, fontName="Helvetica-Bold", leading=11, leftIndent=8)
toc_entry = S("TOCEntry", fontSize=10, textColor=NAVY, fontName="Helvetica", leading=16, leftIndent=12)
section_label = S("SectionLabel", fontSize=8, textColor=WHITE, fontName="Helvetica-Bold", leading=10, alignment=TA_CENTER)
def section_header(title, color=NAVY):
"""Full-width coloured section banner."""
tbl = Table([[Paragraph(title, h1)]], colWidths=[17*cm])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), color),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
("ROUNDEDCORNERS", [4]),
]))
return tbl
def subsection_header(title):
return Paragraph(title, h2)
def info_table(rows, col_widths=None):
"""Two-column key-value table."""
if col_widths is None:
col_widths = [5.5*cm, 11.5*cm]
data = []
for k, v in rows:
data.append([
Paragraph(f"<b>{k}</b>", body_sm),
Paragraph(v, body_sm)
])
tbl = Table(data, colWidths=col_widths)
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,-1), LBLUE),
("BACKGROUND", (1,0), (1,-1), WHITE),
("ROWBACKGROUNDS",(0,0), (-1,-1), [LGREY, WHITE]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#cccccc")),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
]))
return tbl
def diff_table(headers, rows, col_widths=None):
"""Multi-column comparison table."""
if col_widths is None:
n = len(headers)
w = 17.0 / n
col_widths = [w*cm]*n
header_row = [Paragraph(f"<b>{h}</b>", S("TH", fontSize=8, textColor=WHITE, fontName="Helvetica-Bold", leading=11, alignment=TA_CENTER)) for h in headers]
data = [header_row]
for i, row in enumerate(rows):
data.append([Paragraph(str(cell), body_sm) for cell in row])
tbl = Table(data, colWidths=col_widths, repeatRows=1)
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("ROWBACKGROUNDS",(0,1), (-1,-1), [LGREY, WHITE]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#aaaaaa")),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("FONTSIZE", (0,0), (-1,-1), 8),
]))
return tbl
def bp(text):
return Paragraph(text, body)
def note_box(text, color=LBLUE, border=TEAL, text_style=None):
ts = text_style or note
tbl = Table([[Paragraph(text, ts)]], colWidths=[17*cm])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), color),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LINEAFTER", (0,0), (0,-1), 2, border),
("BOX", (0,0), (-1,-1), 0.5, border),
]))
return tbl
SP = Spacer(1, 0.25*cm)
HR = HRFlowable(width="100%", thickness=0.5, color=colors.HexColor("#cccccc"), spaceAfter=4)
# ═══════════════════════════════════════════════════════════════════
# BUILD STORY
# ═══════════════════════════════════════════════════════════════════
story = []
# ── COVER PAGE ───────────────────────────────────────────────────────
cover_bg = Table(
[[Paragraph("PATIENT HISTORY PRESENTATION", cover_title)],
[Spacer(1, 0.3*cm)],
[Paragraph("Transient Ischemic Attack (TIA)", S("CT2", fontSize=17, textColor=colors.HexColor("#a8d8ea"), alignment=TA_CENTER, fontName="Helvetica-Bold", leading=22))],
[Spacer(1, 0.4*cm)],
[Paragraph("Dhulikhel Hospital • Neuro ICU", cover_sub)],
[Spacer(1, 0.6*cm)],
[Paragraph("Patient: <b>Mr. Shashi Kumar Mahati</b>", cover_detail)],
[Paragraph("Age / Sex: 54 Years 4 Months / Male", cover_detail)],
[Paragraph("IP No.: 69677 Patient No.: 76064207", cover_detail)],
[Paragraph("Date of Admission: 11 July 2026", cover_detail)],
[Spacer(1, 0.5*cm)],
[Paragraph("Final Diagnosis: <b>TIA with Known Case of T2DM with HTN</b>", cover_detail)],
[Spacer(1, 1.2*cm)],
[Paragraph("Compiled with references from Harrison's 22E • Adams & Victor's Neurology •<br/>Rosen's Emergency Medicine • Tintinalli's Emergency Medicine", S("CS", fontSize=9, textColor=colors.HexColor("#aaccdd"), alignment=TA_CENTER, leading=13))],
],
colWidths=[17*cm]
)
cover_bg.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), NAVY),
("TOPPADDING", (0,0), (-1,-1), 12),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 20),
("RIGHTPADDING", (0,0), (-1,-1), 20),
("ROWBACKGROUNDS",(0,0), (-1,-1), [NAVY]*50),
]))
story.append(cover_bg)
story.append(PageBreak())
# ── SECTION 1: DEMOGRAPHICS ──────────────────────────────────────────
story.append(section_header("SECTION 1 — PATIENT DEMOGRAPHICS"))
story.append(SP)
demo_rows = [
("Patient Name", "Mr. Shashi Kumar Mahati"),
("Patient No.", "76064207"),
("Inpatient No.", "69677"),
("Age / Sex", "54 Years 4 Months / Male"),
("Date of Birth", "17 March 1972 (1972/03/17 AD)"),
("Address", "Kavrepalanchowk"),
("Date of Admission", "11 July 2026 (2083/03/27 BS)"),
("Date of Discharge", "11 July 2026 (2083/03/27 BS)"),
("Duration of Stay", "0 Days (Neuro ICU)"),
("Department", "Neurology / Neuro ICU"),
("Contact No.", "9860431793"),
("Informant", "Patient himself (reliable historian)"),
]
story.append(info_table(demo_rows))
story.append(SP)
story.append(section_header("FINAL DIAGNOSIS", TEAL))
story.append(SP)
story.append(note_box(
"<b>Transient Ischemic Attack (TIA)</b> in a known case of "
"Type 2 Diabetes Mellitus (T2DM) with Hypertension (HTN)",
color=colors.HexColor("#e6f4ea"), border=GREEN,
text_style=S("Dx", fontSize=10, textColor=colors.HexColor("#1e5631"), fontName="Helvetica-Bold", leading=14, leftIndent=8)
))
story.append(SP)
# ── SECTION 2: HISTORY ───────────────────────────────────────────────
story.append(section_header("SECTION 2 — HISTORY OF PRESENT ILLNESS"))
story.append(SP)
story.append(subsection_header("Chief Complaint"))
story.append(info_table([
("Complaint", "Sudden onset slurring of speech (dysarthria)"),
("Duration", "Approximately 8 hours prior to presentation on 11 July 2026"),
("Time", "Onset at 08:00 AM on 11 July 2026"),
]))
story.append(SP)
story.append(subsection_header("History of Present Illness"))
story.append(bp(
"Mr. Shashi Kumar Mahati, a 54-year-and-4-month-old male from Kavrepalanchowk, a known case of "
"Type 2 Diabetes Mellitus and Hypertension on regular medication, was apparently well until "
"<b>8:00 AM on 11 July 2026</b> when he suddenly developed <b>slurring of speech (dysarthria)</b>."
))
story.append(bp(
"The onset was <b>abrupt</b>, occurring without any preceding prodromal symptoms. The speech slurring "
"was <b>persistent</b> from its onset and <b>non-progressive</b> in nature (did not worsen over time). "
"The patient also reported <b>associated dizziness</b> during the same episode. "
"He presented to the Emergency Department at Dhulikhel Hospital on the same day."
))
story.append(SP)
story.append(subsection_header("Characterization of Chief Complaint"))
story.append(info_table([
("Mode of onset", "Sudden / abrupt"),
("Duration", "Approximately 8 hours before presentation; episode was transient in nature and resolved by examination"),
("Character", "Slurring of speech (dysarthria), non-progressive"),
("Associated", "Dizziness"),
("Progression", "Non-progressive"),
("Relieving factors", "None documented"),
("Aggravating factors", "None documented"),
]))
story.append(SP)
story.append(subsection_header("Pertinent Positive and Negative History"))
pos_neg = [
["Symptom", "Present / Absent", "Clinical Significance"],
["Slurring of speech (dysarthria)", "PRESENT", "Focal neurological deficit - hallmark of TIA/stroke"],
["Dizziness", "PRESENT", "Posterior circulation involvement possible"],
["Loss of consciousness", "ABSENT", "Against hemorrhage / severe ischemia"],
["Seizure / abnormal body movements", "ABSENT", "Against Todd's paralysis"],
["Vomiting", "ABSENT", "Against hemorrhagic stroke, raised ICP"],
["Ear or nose bleeding", "ABSENT", "Against basal skull fracture / trauma"],
["Facial deviation (facial palsy)", "ABSENT", "Against significant MCA territory event"],
["Headache", "ABSENT", "Against SAH, hypertensive encephalopathy, migraine"],
["Blurring of vision / diplopia", "ABSENT", "Against ophthalmic TIA, posterior circulation"],
["Limb weakness (hemiparesis)", "ABSENT", "Against large territory ischemia"],
["Sensory loss / numbness", "ABSENT", "Against sensory cortex involvement"],
["Bowel / bladder incontinence", "ABSENT", "Against significant neurological impairment"],
["Recent head trauma", "ABSENT", "Against traumatic cause"],
]
story.append(diff_table(
pos_neg[0], pos_neg[1:],
col_widths=[6*cm, 3.5*cm, 7.5*cm]
))
story.append(SP)
# ── PAST HISTORY ─────────────────────────────────────────────────────
story.append(section_header("SECTION 3 — PAST HISTORY"))
story.append(SP)
past_rows = [
("Similar illness", "No history of prior TIA or stroke"),
("Diabetes Mellitus", "Known case of T2DM - on oral hypoglycemic agents (specific drug not documented)"),
("Hypertension", "Known case of HTN - on antihypertensive medication (specific drug not documented)"),
("Ischemic Heart Disease", "Not documented - should be elicited"),
("Atrial Fibrillation", "Not documented - should be elicited (major cardioembolic cause of TIA)"),
("Hyperlipidemia", "Not documented - should be elicited"),
("Other comorbidities", "None known"),
]
story.append(info_table(past_rows))
story.append(SP)
story.append(note_box(
"PROFESSOR TIP: When presenting, actively document whether atrial fibrillation, prior cardiac history, "
"dyslipidemia, smoking, and alcohol use are present or absent. These are vascular risk factors directly "
"relevant to TIA etiology and will almost certainly be asked.",
color=colors.HexColor("#fff8e1"), border=AMBER,
text_style=S("AmberNote", fontSize=8, textColor=colors.HexColor("#7c4f00"), fontName="Helvetica-Oblique", leading=12, leftIndent=8)
))
story.append(SP)
# ── PERSONAL / SOCIAL / DRUG HISTORY ─────────────────────────────────
story.append(section_header("SECTION 4 — PERSONAL, SOCIAL & DRUG HISTORY"))
story.append(SP)
story.append(subsection_header("Personal History"))
story.append(info_table([
("Bowel habit", "Normal"),
("Bladder habit", "Normal"),
("Smoking", "Not documented (should be elicited - major vascular risk factor)"),
("Alcohol", "Not documented"),
("Diet", "Not documented"),
("Occupation", "Not documented"),
]))
story.append(SP)
story.append(subsection_header("Drug / Treatment History"))
story.append(info_table([
("T2DM medications", "On oral hypoglycemic agents (specific agent not recorded)"),
("HTN medications", "On antihypertensive medication (specific agent not recorded)"),
("Antiplatelet / anticoagulant", "No history of prior use"),
("Allergies", "Not documented"),
]))
story.append(SP)
story.append(subsection_header("Family History"))
story.append(bp("Not documented. Should be elicited: family history of stroke, hypertension, diabetes, ischemic heart disease."))
story.append(SP)
# ── REVIEW OF SYSTEMS ─────────────────────────────────────────────────
story.append(section_header("SECTION 5 — REVIEW OF SYSTEMS"))
story.append(SP)
ros_rows = [
("Neurological", "Dysarthria + dizziness; no limb weakness, no LOC, no visual disturbance, no seizures"),
("Cardiovascular", "No chest pain, no palpitations documented"),
("Respiratory", "No respiratory complaints"),
("Gastrointestinal", "Normal bowel habit; no vomiting"),
("Genitourinary", "Normal bladder habit; no incontinence"),
("Musculoskeletal", "No joint pains; no limb weakness"),
("ENT", "No ear or nose bleeding"),
("Psychiatric", "Not documented"),
]
story.append(info_table(ros_rows))
story.append(SP)
# ── EMERGENCY COURSE ──────────────────────────────────────────────────
story.append(section_header("SECTION 6 — EMERGENCY DEPARTMENT COURSE"))
story.append(SP)
story.append(bp(
"The patient presented to the Emergency Department of Dhulikhel Hospital where a "
"<b>primary assessment (ABCDE approach)</b> was performed."
))
story.append(info_table([
("Airway", "Patent and self-maintained"),
("Breathing", "Normal, no respiratory distress"),
("Circulation", "Hemodynamically stable"),
("Disability (Neuro)", "GCS 15/15 (E4V5M6); alert, oriented"),
("Exposure", "No external injuries noted"),
("CT Head (Urgent)", "Unremarkable - no hemorrhage, no early ischemic changes"),
("Laboratory investigations", "Obtained (specific results not in available record)"),
("Disposition", "Admitted to Neuro ICU for further evaluation, stroke management, and neurological monitoring"),
]))
story.append(SP)
# ── ON EXAMINATION ────────────────────────────────────────────────────
story.append(section_header("SECTION 7 — ON EXAMINATION"))
story.append(SP)
story.append(subsection_header("General Examination"))
story.append(info_table([
("General condition", "Ill-looking, active"),
("Consciousness", "Conscious and cooperative"),
("Orientation", "Oriented to time, place, and person"),
("GCS", "E4V5M6 = 15/15 (Full)"),
("PILCCOD", "Pallor: Absent | Icterus: Absent | Lymphadenopathy: Absent | Cyanosis: Absent | Clubbing: Absent | Oedema: Absent | Dehydration: Absent"),
("Airway", "Patent"),
("Breathing", "Normal"),
("Circulation", "Normal"),
]))
story.append(SP)
story.append(subsection_header("Vital Signs (To Be Recorded)"))
story.append(diff_table(
["Parameter", "Value", "Clinical Relevance"],
[
["Temperature", "To be recorded", "Fever raises concern for infectious mimic"],
["Heart Rate (Pulse)", "To be recorded", "Irregular = possible AF (cardioembolic TIA)"],
["Blood Pressure", "To be recorded", "CRITICAL: Component of ABCD2 score; HTN present"],
["Respiratory Rate", "To be recorded", "Baseline"],
["SpO2", "To be recorded", "Hypoxia can worsen ischemia"],
["Capillary Blood Glucose", "To be recorded", "CRITICAL: T2DM - hypoglycemia is TIA mimic"],
["Weight / BMI", "To be recorded", "Cardiovascular risk assessment"],
],
col_widths=[4.5*cm, 4.5*cm, 8*cm]
))
story.append(SP)
story.append(subsection_header("Neurological Examination"))
story.append(Paragraph("Higher Mental Functions", h3))
story.append(info_table([
("Orientation", "Intact (GCS V5 - oriented)"),
("Memory", "To be formally tested"),
("Speech", "Dysarthria was presenting complaint - document status at examination (resolved / partially resolved / persisting)"),
("Language", "Comprehension and repetition to be assessed"),
]))
story.append(SP)
story.append(Paragraph("Cranial Nerve Examination", h3))
cn_rows = [
["CN", "Nerve", "Examination Finding"],
["I", "Olfactory", "Not routinely tested"],
["II", "Optic", "Visual acuity, visual fields by confrontation - document result"],
["III/IV/VI", "Oculomotor / Trochlear / Abducens", "Pupillary reactions (PEARL); EOM; no diplopia reported"],
["V", "Trigeminal", "Facial sensation"],
["VII", "Facial", "Facial symmetry - NO facial deviation documented"],
["VIII","Vestibulocochlear", "Hearing; HINTS exam - important given dizziness"],
["IX/X","Glossopharyngeal/Vagus","Palatal movement, gag reflex, swallowing - relevant to dysarthria"],
["XI", "Accessory", "SCM, trapezius strength"],
["XII", "Hypoglossal", "Tongue movements - relevant to dysarthria"],
]
story.append(diff_table(cn_rows[0], cn_rows[1:], col_widths=[1.5*cm, 5*cm, 10.5*cm]))
story.append(SP)
story.append(Paragraph("Motor, Sensory & Cerebellar Examination", h3))
story.append(info_table([
("Tone", "To be documented in all four limbs"),
("Power", "To be documented (expected 5/5 - no limb weakness mentioned)"),
("Reflexes", "DTRs: biceps, triceps, supinator, knee, ankle; Plantar response"),
("Coordination","Heel-shin test, finger-nose test, rapid alternating movements"),
("Cerebellar", "Romberg's test, gait examination, nystagmus - assess given dizziness"),
("Sensory", "Light touch, pinprick, proprioception, vibration - no sensory loss documented"),
("Meningeal", "Neck stiffness: absent; Kernig's: to document; Brudzinski's: to document"),
]))
story.append(SP)
# ── INVESTIGATIONS ────────────────────────────────────────────────────
story.append(section_header("SECTION 8 — INVESTIGATIONS"))
story.append(SP)
story.append(subsection_header("Already Performed"))
story.append(info_table([
("CT Head (Non-Contrast)", "UNREMARKABLE - no hemorrhage, no acute infarct visible"),
("Laboratory investigations", "Obtained (specific results not available in the record)"),
]))
story.append(SP)
story.append(subsection_header("Required Investigations for Complete TIA Workup"))
story.append(Paragraph("Blood Tests (Urgent)", h3))
story.append(diff_table(
["Investigation", "Rationale"],
[
["CBC (Complete Blood Count)", "Rule out polycythemia, thrombocytosis, anemia"],
["Blood glucose / HbA1c", "T2DM control assessment; rule out hypoglycemia as TIA mimic"],
["Serum electrolytes", "Metabolic cause of neurological symptoms"],
["Renal function tests (BUN, Creatinine)", "Baseline; vascular risk assessment"],
["Lipid profile (Total chol, LDL, HDL, TG)", "Atherosclerosis risk factor; statin indication"],
["Coagulation profile (PT, aPTT, INR)", "Rule out coagulopathy"],
["Liver function tests", "Baseline"],
["Serum uric acid", "Vascular risk marker"],
],
col_widths=[7*cm, 10*cm]
))
story.append(SP)
story.append(Paragraph("Cardiac Workup", h3))
story.append(diff_table(
["Investigation", "Rationale"],
[
["12-lead ECG", "Rule out atrial fibrillation (cardioembolic TIA), ischemic changes"],
["2D Echocardiography", "Rule out intracardiac thrombus, valvular disease, PFO"],
["Cardiac telemetry / Holter monitoring", "Detect paroxysmal AF (missed on single ECG)"],
["Troponin", "Rule out concurrent ACS"],
],
col_widths=[7*cm, 10*cm]
))
story.append(SP)
story.append(Paragraph("Neuroimaging", h3))
story.append(diff_table(
["Investigation", "Rationale"],
[
["MRI Brain with DWI (PRIORITY)", "Most sensitive - detects acute ischemic lesions; distinguishes TIA from stroke; CT may be normal in early TIA"],
["MRA (Magnetic Resonance Angiography)", "Evaluate intracranial and extracranial vasculature; detect stenosis"],
["Carotid Doppler Ultrasound", "Carotid artery stenosis - major treatable cause of TIA"],
],
col_widths=[7*cm, 10*cm]
))
story.append(SP)
# ── ABCD2 SCORE ───────────────────────────────────────────────────────
story.append(section_header("SECTION 9 — ABCD2 RISK STRATIFICATION"))
story.append(SP)
story.append(bp("The ABCD2 score stratifies patients presenting with TIA by risk of stroke within 48 hours, 7 days, and 90 days. (Source: Harrison's 22E Table 438-5; Rosen's EM Table 87.6)"))
story.append(SP)
story.append(diff_table(
["Parameter", "Criterion", "Score for This Patient"],
[
["A - Age", "Age >= 60 years = 1 point", "Age 54 years = 0"],
["B - Blood Pressure", "SBP >140 or DBP >90 = 1 point", "Not documented - PENDING (likely 1 given HTN)"],
["C - Clinical Features", "Unilateral weakness = 2; Speech disturbance without weakness = 1", "Dysarthria without weakness = 1"],
["D - Duration", ">60 min = 2; 10-59 min = 1; <10 min = 0", "Duration not precisely quantified - PENDING"],
["D - Diabetes", "History of diabetes = 1 point", "T2DM confirmed = 1"],
["MINIMUM SCORE", "0-3 = Low; 4-5 = Moderate; 6-7 = High", "Minimum 2+; rises to 3-4 with BP + duration"],
],
col_widths=[4*cm, 7*cm, 6*cm]
))
story.append(SP)
story.append(diff_table(
["ABCD2 Score", "2-Day Stroke Risk", "7-Day Stroke Risk", "90-Day Stroke Risk", "Recommendation"],
[
["0-3 (Low)", "1.0%", "1.2%", "3.1%", "Outpatient management possible"],
["4-5 (Moderate)","4.1%", "5.9%", "9.8%", "Hospitalization recommended"],
[">=6 (High)", "8.1%", "11.7%", "17.8%", "Hospitalization mandatory"],
],
col_widths=[3.5*cm, 3.5*cm, 3.5*cm, 3.5*cm, 3*cm]
))
story.append(SP)
# ── MANAGEMENT PLAN ───────────────────────────────────────────────────
story.append(section_header("SECTION 10 — MANAGEMENT PLAN"))
story.append(SP)
story.append(subsection_header("Acute Management (Already Initiated)"))
story.append(info_table([
("1", "Admission to Neuro ICU for monitoring"),
("2", "ABCDE stabilization - patient hemodynamically stable"),
("3", "Urgent CT head - unremarkable"),
("4", "Laboratory investigations - obtained"),
("5", "Continuous neurological observation"),
]))
story.append(SP)
story.append(subsection_header("Antiplatelet Therapy (Secondary Prevention)"))
story.append(note_box(
"DUAL ANTIPLATELET THERAPY: Aspirin (75-100 mg/day) + Clopidogrel (75 mg/day) for 21 days, "
"then aspirin monotherapy long-term. Based on POINT and CHANCE trials. "
"Alternative: Ticagrelor 180 mg loading then 90 mg BD + aspirin (Harrison's 22E). "
"NOTE: CYP2C19 polymorphism (common in Asians) may reduce clopidogrel efficacy.",
color=colors.HexColor("#e8f4f8"), border=TEAL,
text_style=S("MgmtNote", fontSize=8.5, textColor=NAVY, fontName="Helvetica", leading=13, leftIndent=8)
))
story.append(SP)
story.append(subsection_header("Risk Factor Management"))
story.append(diff_table(
["Target", "Goal", "Intervention"],
[
["Blood Pressure", "<130/80 mmHg", "Optimize existing antihypertensive regimen"],
["Glycemic Control", "HbA1c <7%", "Review and optimize oral hypoglycemic agents"],
["Lipids (LDL)", "<70 mg/dL", "High-intensity statin: Atorvastatin 40-80 mg/day"],
["Lifestyle", "Comprehensive modification", "Smoking cessation, diet, exercise, weight management"],
],
col_widths=[4*cm, 4*cm, 9*cm]
))
story.append(SP)
story.append(subsection_header("Patient and Family Education"))
story.append(info_table([
("TIA as warning sign", "Educate that TIA is a medical emergency and a strong warning sign of impending stroke"),
("FAST acronym", "Face drooping, Arm weakness, Speech difficulty, Time to call emergency"),
("Medication compliance","Critical importance of taking all medications regularly"),
("Follow-up", "Strict outpatient follow-up with neurology"),
]))
story.append(SP)
# ═══════════════════════════════════════════════════════════════════
# SECTION 11: DIFFERENTIAL DIAGNOSIS
# ═══════════════════════════════════════════════════════════════════
story.append(PageBreak())
story.append(section_header("SECTION 11 — DIFFERENTIAL DIAGNOSES & DIFFERENTIATION FROM TIA", RED))
story.append(SP)
story.append(note_box(
"The following differentials are presented with a detailed comparison for each, followed by a "
"summary master table and a stepwise bedside approach to differentiation.",
color=colors.HexColor("#fef3c7"), border=AMBER,
text_style=S("IntroNote", fontSize=9, textColor=BLACK, fontName="Helvetica", leading=13, leftIndent=8)
))
story.append(SP)
# --- Diff 1: Ischemic Stroke
story.append(subsection_header("1. Ischemic Stroke (Minor Stroke) — Closest Differential"))
story.append(bp("This is the most important differential. TIA and minor ischemic stroke exist on a clinical continuum and are distinguished by MRI DWI."))
story.append(diff_table(
["Feature", "TIA", "Ischemic Stroke"],
[
["Definition", "Focal neurological deficit with NO infarction on imaging (tissue-based)", "Focal neurological deficit WITH infarction on imaging"],
["CT Head", "Normal (as in this patient)", "May show early hypodense area - often normal in first 24h"],
["MRI DWI", "NORMAL - no diffusion restriction", "POSITIVE DWI signal - restricted diffusion confirms infarct"],
["Duration of symptoms", "Typically fully resolves", "Deficit persists or partially resolved"],
["Clinical on exam", "Complete resolution", "Residual deficit on examination"],
["Thrombolysis", "CONTRAINDICATED (no infarct)", "Indicated if within window period"],
],
col_widths=[4.5*cm, 6.25*cm, 6.25*cm]
))
story.append(SP)
story.append(note_box("KEY: MRI Brain with DWI is MANDATORY. If DWI shows restricted diffusion, the diagnosis is minor ischemic stroke, not TIA. This distinction changes management (thrombolysis eligibility).", color=colors.HexColor("#e8f4f8"), border=TEAL))
story.append(SP)
# --- Diff 2: Hemorrhagic Stroke
story.append(subsection_header("2. Hemorrhagic Stroke (ICH / SAH)"))
story.append(diff_table(
["Feature", "TIA", "Hemorrhagic Stroke"],
[
["Headache", "ABSENT", "SEVERE ('thunderclap') - hallmark of SAH"],
["Vomiting", "ABSENT", "COMMON"],
["Loss of consciousness", "ABSENT", "Common in SAH / large ICH"],
["CT Head", "Normal", "HYPERDENSE (white) blood - visible IMMEDIATELY on CT"],
["Neck stiffness", "Absent", "Present in SAH (meningism)"],
["Progression", "Non-progressive, resolving", "Progressive worsening"],
["GCS", "Normal (15/15)", "Reduced in significant hemorrhage"],
["This patient", "No headache, no vomiting, no LOC, CT unremarkable", "EXCLUDED by CT findings in this patient"],
],
col_widths=[4.5*cm, 6.25*cm, 6.25*cm]
))
story.append(SP)
# --- Diff 3: Todd's Paralysis
story.append(subsection_header("3. Focal Seizure with Todd's Paralysis (Post-ictal Deficit)"))
story.append(diff_table(
["Feature", "TIA", "Todd's Paralysis"],
[
["Onset of deficit", "Abrupt NEGATIVE symptoms (loss of function)", "POSITIVE symptoms first (jerking/twitching) then weakness"],
["Seizure activity", "ABSENT", "HISTORY of tonic-clonic or focal jerking immediately before"],
["Loss of consciousness", "ABSENT", "May be present during ictus"],
["Post-ictal confusion", "ABSENT", "PRESENT - key distinguishing feature"],
["Tongue biting / incontinence", "ABSENT", "May be present"],
["Duration", "Minutes to hours", "Minutes to few hours, then resolves"],
["EEG", "Normal", "Epileptiform discharges or postictal slowing"],
["This patient", "No abnormal movements, no LOC, no post-ictal confusion", "Seizure UNLIKELY - all distinguishing features absent"],
],
col_widths=[4.5*cm, 6.25*cm, 6.25*cm]
))
story.append(SP)
story.append(note_box("Adams & Victor's: 'Abrupt onset and absence of positive (muscle-activating) motor symptoms argue in favor of TIA over seizure.'"))
story.append(SP)
# --- Diff 4: Migraine
story.append(subsection_header("4. Hemiplegic / Acephalgic Migraine (Complex Migraine)"))
story.append(diff_table(
["Feature", "TIA", "Migraine with Aura / Hemiplegic Migraine"],
[
["Age / Sex", "Older (>50), male, vascular risk factors", "Often younger, female predominance"],
["Onset of deficit", "ABRUPT (seconds)", "GRADUAL 'march' over minutes"],
["Spread pattern", "Stays within a vascular territory", "CROSSES vascular boundaries"],
["Headache", "ABSENT", "Usually present after aura; absent in acephalgic migraine"],
["Visual symptoms", "Amaurosis fugax (monocular)", "Scintillating scotoma, fortification spectra (binocular)"],
["Prior migraine history", "Not relevant", "Typically present (but not always)"],
["Vascular risk factors", "Present (HTN, DM)", "Usually absent"],
["MRI", "Normal or DWI bright", "Normal; no vascular occlusion; may cross territories"],
["This patient", "54M, HTN, DM2, abrupt onset, no headache, no migraine history", "UNLIKELY - vascular profile and abrupt onset favor TIA"],
],
col_widths=[4.5*cm, 6.25*cm, 6.25*cm]
))
story.append(SP)
story.append(note_box("Harrison's 22E: 'A sensory disturbance tends to migrate slowly across a limb, over minutes rather than seconds as with stroke. The diagnosis of migraine becomes more secure if the cortical disturbance crosses vascular boundaries.'"))
story.append(SP)
# --- Diff 5: Hypoglycemia
story.append(subsection_header("5. Hypoglycemia — MUST NOT MISS (especially in T2DM patient)"))
story.append(diff_table(
["Feature", "TIA", "Hypoglycemia"],
[
["Blood glucose", "Normal", "LOW (<70 mg/dL; often <50 mg/dL for focal symptoms)"],
["Onset", "Abrupt focal neurological deficit", "May be gradual; often associated with autonomic features"],
["Autonomic features", "ABSENT", "Sweating, palpitations, hunger, tremor, anxiety"],
["CT / MRI", "Normal or infarct", "NORMAL (metabolic, not structural)"],
["Response to glucose", "No change", "RAPID RESOLUTION with IV/oral glucose"],
["Diabetic status", "Not required", "Almost always diabetic on insulin or sulfonylureas"],
["This patient", "T2DM on medication - CBG MUST be checked immediately", "Rule out with immediate bedside glucose"],
],
col_widths=[4.5*cm, 6.25*cm, 6.25*cm]
))
story.append(SP)
story.append(note_box("Tintinalli's EM: 'Both hypoglycemia AND hyperglycemia are important stroke mimics.' Rosen's EM: 'Hypoglycemia is a common cause of sustained focal neurologic symptoms that can persist for several days.'", color=colors.HexColor("#fff0f0"), border=RED, text_style=S("WarnNote", fontSize=8, textColor=RED, fontName="Helvetica-Bold", leading=12, leftIndent=8)))
story.append(SP)
# --- Diff 6: Vestibular
story.append(subsection_header("6. Peripheral Vestibular Disorders (BPPV / Labyrinthitis / Vestibular Neuritis / Meniere's)"))
story.append(bp("Relevant because this patient had dizziness as an associated symptom."))
story.append(diff_table(
["Feature", "Posterior Circulation TIA", "Peripheral Vestibular Disorder"],
[
["Focal neurological deficits", "YES - dysarthria, dysphagia, diplopia, ataxia, facial numbness", "NO - isolated dizziness/vertigo ONLY"],
["Nystagmus type", "Direction-changing, vertical, or torsional (CENTRAL pattern)", "Horizontal, unidirectional, fatigable (PERIPHERAL pattern)"],
["Hearing loss / tinnitus", "Absent (unless AICA territory)", "PRESENT in Meniere's, labyrinthitis"],
["HINTS exam", "HINTS negative = central lesion (DANGEROUS)", "HINTS positive = peripheral (reassuring)"],
["Response to position (Dix-Hallpike)", "No change", "WORSENED by position change in BPPV"],
["Vascular risk factors", "Present", "Absent or less relevant"],
["This patient", "DYSARTHRIA alongside dizziness = central cause", "Peripheral vestibular EXCLUDED by presence of dysarthria"],
],
col_widths=[4.5*cm, 6.25*cm, 6.25*cm]
))
story.append(SP)
story.append(note_box("Rosen's EM: 'Meniere disease - dizziness, vertigo, hearing loss, and tinnitus are common; difficulties with vision or speech (focal symptoms) are less common.' Presence of dysarthria in this patient points to a central cause."))
story.append(SP)
# --- Diff 7: Hypertensive Encephalopathy / PRES
story.append(subsection_header("7. Hypertensive Encephalopathy / PRES"))
story.append(diff_table(
["Feature", "TIA", "Hypertensive Encephalopathy / PRES"],
[
["Blood pressure", "May be elevated", "SEVERELY elevated (SBP >180-200 mmHg)"],
["Headache", "ABSENT", "SEVERE headache - hallmark feature"],
["Vomiting", "ABSENT", "COMMON"],
["LOC / Confusion", "ABSENT", "ALTERED consciousness - common"],
["Seizures", "ABSENT", "COMMON - may be the presenting feature"],
["MRI", "Normal or focal infarct", "Posterior white matter T2/FLAIR hyperintensity (parieto-occipital)"],
["Focal deficit", "Specific vascular territory", "Generalized rather than focal"],
["This patient", "No headache, no vomiting, no LOC, no seizures", "UNLIKELY given absence of encephalopathy features"],
],
col_widths=[4.5*cm, 6.25*cm, 6.25*cm]
))
story.append(SP)
# --- Diff 8: Brain Tumor
story.append(subsection_header("8. Intracranial Mass Lesion (Brain Tumor)"))
story.append(diff_table(
["Feature", "TIA", "Brain Tumor"],
[
["Onset", "ABRUPT (seconds to minutes)", "Gradual, progressive (days to weeks)"],
["Progression", "Non-progressive, resolving", "PROGRESSIVE worsening"],
["Headache", "Absent", "Progressive headache, worse in morning"],
["Papilledema", "Absent", "May be present (raised ICP)"],
["CT Head", "Normal", "Mass lesion, ring-enhancing lesion, midline shift"],
["This patient", "Abrupt onset, transient, unremarkable CT - tumor UNLIKELY", "Excluded by CT findings and clinical course"],
],
col_widths=[4.5*cm, 6.25*cm, 6.25*cm]
))
story.append(SP)
# --- Diff 9: Bell's Palsy
story.append(subsection_header("9. Bell's Palsy vs. Central Facial Weakness (for Facial Examination)"))
story.append(diff_table(
["Feature", "Central Facial Weakness (TIA/Stroke - UMN)", "Bell's Palsy (LMN - Peripheral)"],
[
["Forehead involvement", "SPARED (bilateral cortical representation)", "INVOLVED - cannot wrinkle forehead"],
["Eye closure", "Normal", "IMPAIRED - Bell's phenomenon visible"],
["Associated features", "Limb weakness, dysarthria possible", "Taste disturbance, hyperacusis"],
["This patient", "NO facial deviation documented", "Not the primary differential here"],
],
col_widths=[4.5*cm, 6.25*cm, 6.25*cm]
))
story.append(SP)
# --- Diff 10: MS
story.append(subsection_header("10. Multiple Sclerosis (Demyelinating Disease)"))
story.append(diff_table(
["Feature", "TIA", "Multiple Sclerosis"],
[
["Age / Sex", "Older, male predominance, vascular RF", "Younger, female predominance"],
["Onset", "ABRUPT (seconds)", "Subacute (hours to days)"],
["Prior episodes", "First episode", "Relapsing-remitting history"],
["Vascular risk factors", "Present", "Absent"],
["MRI Brain", "Infarct in vascular distribution", "Periventricular / juxtacortical white matter plaques (Dawson's fingers)"],
["CSF", "Normal", "Oligoclonal bands, elevated IgG index"],
["This patient", "Age 54, male, HTN, DM - classic vascular profile", "UNLIKELY - age, sex, vascular risk factors favor TIA"],
],
col_widths=[4.5*cm, 6.25*cm, 6.25*cm]
))
story.append(SP)
# ── MASTER SUMMARY TABLE ──────────────────────────────────────────────
story.append(PageBreak())
story.append(section_header("SECTION 12 — MASTER DIFFERENTIAL DIAGNOSIS SUMMARY TABLE", colors.HexColor("#2d4a7a")))
story.append(SP)
master = [
["Feature", "TIA", "Isch. Stroke", "ICH/SAH", "Todd's", "Migraine", "Hypoglycemia", "Vestibular", "PRES"],
["Onset", "Abrupt", "Abrupt", "Abrupt", "Post-seizure", "Gradual march", "Variable", "Sudden vertigo", "Gradual"],
["Headache", "Absent", "Absent", "SEVERE", "Absent", "Present", "Absent", "Absent", "SEVERE"],
["LOC", "Absent", "Rare", "COMMON", "Present", "Absent", "May occur", "Absent", "COMMON"],
["Seizure", "Absent", "Rare", "Rare", "YES (precedes)", "Rare", "Absent", "Absent", "COMMON"],
["Vomiting", "Absent", "Rare", "COMMON", "Absent", "May occur", "Absent", "May occur", "COMMON"],
["CT Head", "Normal", "Normal/low density", "HYPERDENSE", "Normal", "Normal", "Normal", "Normal", "May be abnormal"],
["MRI DWI", "NORMAL", "BRIGHT (infarct)", "Confirms blood", "Normal", "Normal", "Normal", "Normal", "Posterior T2 signal"],
["Blood glucose", "Normal", "Normal", "Normal", "Normal", "Normal", "LOW", "Normal", "Normal"],
["Resolution", "Complete", "Incomplete", "Incomplete", "Complete", "Complete", "With glucose", "Complete", "With BP control"],
]
tbl = Table(master, colWidths=[3.2*cm, 1.9*cm, 2.0*cm, 1.9*cm, 1.7*cm, 1.9*cm, 2.3*cm, 2.1*cm, 1.9*cm], repeatRows=1)
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 7),
("BACKGROUND", (0,1), (0,-1), LBLUE),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("ROWBACKGROUNDS",(1,1), (-1,-1), [LGREY, WHITE]),
("GRID", (0,0), (-1,-1), 0.3, colors.HexColor("#999999")),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 4),
]))
story.append(tbl)
story.append(SP)
# ── STEPWISE APPROACH TO DIFFERENTIATION ─────────────────────────────
story.append(section_header("SECTION 13 — STEPWISE BEDSIDE APPROACH TO DIFFERENTIATION"))
story.append(SP)
story.append(diff_table(
["Step", "Action", "Differentials Excluded"],
[
["Step 1 - Immediate", "Bedside blood glucose (CBG/RBS)", "Hypoglycemia - MUST check first in any T2DM patient"],
["Step 2 - Immediate", "Non-contrast CT Head (already done)", "Hemorrhagic stroke (ICH/SAH) - EXCLUDED if normal CT"],
["Step 3 - Immediate", "12-lead ECG", "Atrial fibrillation (cardioembolic source), ACS"],
["Step 4 - History", "Was there jerking/convulsive activity before deficit?", "Seizure / Todd's paralysis if NO"],
["Step 5 - History", "Was there severe headache at onset?", "ICH / SAH / Migraine if NO"],
["Step 6 - History", "Did symptoms gradually spread over minutes?", "Migraine if NO (TIA is abrupt)"],
["Step 7 - Examination", "HINTS exam (Head Impulse, Nystagmus, Skew deviation)", "Peripheral vestibular disorder if positive HINTS"],
["Step 8 - Gold Standard", "MRI Brain with DWI", "TIA (normal DWI) vs. ischemic stroke (bright DWI); also identifies MS, tumor, PRES"],
["Step 9 - Vascular", "MRA + Carotid Doppler", "Identifies underlying etiology, guides secondary prevention"],
],
col_widths=[3*cm, 7*cm, 7*cm]
))
story.append(SP)
# ── PROGNOSIS ─────────────────────────────────────────────────────────
story.append(section_header("SECTION 14 — PROGNOSIS"))
story.append(SP)
story.append(info_table([
("Short-term stroke risk", "Per Adams & Victor's: ~6% of strokes following TIA occur within 1 month; another ~6% in the following year. Highest risk is in the first 48-72 hours."),
("Modifiable risk factors", "T2DM and HTN - both present and treatable. Optimal control significantly reduces future vascular events."),
("Favorable indicators", "Hemodynamically stable, GCS 15/15, early presentation, unremarkable CT head, full symptom resolution."),
("With optimal treatment", "Early dual antiplatelet therapy + statin + BP control + glycemic control can reduce 90-day stroke risk by up to 80% (AAFP evidence)."),
]))
story.append(SP)
# ── VERBAL SUMMARY ────────────────────────────────────────────────────
story.append(section_header("SECTION 15 — VERBAL SUMMARY FOR PRESENTATION"))
story.append(SP)
story.append(note_box(
"\"Mr. Shashi Kumar Mahati, a 54-year-old male from Kavrepalanchowk, a known case of T2DM and HTN on "
"regular medication, presented to the Emergency Department of Dhulikhel Hospital on 11 July 2026 with "
"a chief complaint of sudden onset slurring of speech (dysarthria) since 8:00 AM of the same day - "
"approximately 8 hours prior to presentation. The onset was abrupt, the symptom was persistent and "
"non-progressive, and was associated with dizziness. There was no loss of consciousness, seizure "
"activity, vomiting, headache, visual disturbance, facial deviation, limb weakness, sensory loss, or "
"bowel-bladder incontinence. This was his first such episode. On examination, GCS was E4V5M6 (15/15), "
"he appeared ill-looking but active, PILCCOD was nil, and airway-breathing-circulation were all normal. "
"Urgent CT Head was unremarkable. Based on the acute onset focal neurological deficit (dysarthria and "
"dizziness) in a patient with vascular risk factors, with complete/near-complete resolution and a normal "
"CT head, a diagnosis of Transient Ischemic Attack was made. He was admitted for MRI Brain, MRA, "
"cardiac workup, and initiation of dual antiplatelet and vascular risk modification therapy.\"",
color=colors.HexColor("#f0f7ff"), border=NAVY,
text_style=S("Summary", fontSize=9, textColor=NAVY, fontName="Helvetica", leading=14, leftIndent=8)
))
story.append(SP)
# ── REFERENCES ────────────────────────────────────────────────────────
story.append(HRFlowable(width="100%", thickness=1, color=NAVY, spaceAfter=6))
story.append(Paragraph("References", h2))
refs = [
"Harrison's Principles of Internal Medicine, 22nd Edition (2025) — Cerebrovascular Disease (Chapter 437-438), Table 438-5 ABCD2 Score",
"Adams and Victor's Principles of Neurology, 12th Edition — Chapter 33 (TIA)",
"Rosen's Emergency Medicine: Concepts and Clinical Practice — Chapter 87 (Stroke, TIA, Table 87.6)",
"Tintinalli's Emergency Medicine: A Comprehensive Study Guide — Chapter 167 (Stroke Diagnosis, Stroke Mimics)",
"Bradley and Daroff's Neurology in Clinical Practice — TIA and Differential Diagnosis",
"AAFP: Transient Ischemic Attack: Part I. Diagnosis and Evaluation. Am Fam Physician 2012;86(6):521-526",
"Patient Record: Dhulikhel Hospital, Inpatient No. 69677, Patient: Shashi Kumar Mahati, Admitted 11 July 2026",
]
for r in refs:
story.append(Paragraph(f"• {r}", body_sm))
story.append(SP)
# ── BUILD ──────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF created: {OUTPUT}")