Create a pdf on headache?
mkdir -p /home/daytona/workspace/headache-pdf && ls /home/daytona/workspace/headache-pdf/
~/headache-pdf/build_headache_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether
)
from reportlab.platypus import PageBreak
from reportlab.lib.colors import HexColor
# ── colours ──────────────────────────────────────────────────────────────────
DARK_BLUE = HexColor("#1B3A6B")
MID_BLUE = HexColor("#2E6DA4")
LIGHT_BLUE = HexColor("#D6E4F0")
ACCENT_RED = HexColor("#C0392B")
ACCENT_GOLD = HexColor("#D4A017")
WHITE = colors.white
LIGHT_GREY = HexColor("#F4F6F9")
DARK_GREY = HexColor("#2C3E50")
MED_GREY = HexColor("#7F8C8D")
W, H = A4
# ── document ─────────────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
"/home/daytona/workspace/headache-pdf/Headache_Clinical_Overview.pdf",
pagesize=A4,
leftMargin=1.8*cm, rightMargin=1.8*cm,
topMargin=2*cm, bottomMargin=2*cm,
title="Headache – Clinical Overview",
author="Orris Medical Library",
)
# ── styles ────────────────────────────────────────────────────────────────────
base = getSampleStyleSheet()
def S(name, **kw):
s = ParagraphStyle(name, **kw)
return s
TITLE_S = S("title_s", fontName="Helvetica-Bold", fontSize=26,
textColor=WHITE, alignment=TA_CENTER, leading=32, spaceAfter=4)
SUBTITLE_S = S("subtitle_s", fontName="Helvetica", fontSize=13,
textColor=LIGHT_BLUE, alignment=TA_CENTER, leading=18, spaceAfter=6)
META_S = S("meta_s", fontName="Helvetica-Oblique", fontSize=10,
textColor=HexColor("#AED6F1"), alignment=TA_CENTER, leading=14)
H1 = S("h1", fontName="Helvetica-Bold", fontSize=14,
textColor=WHITE, leading=18, spaceAfter=4, spaceBefore=4)
H2 = S("h2", fontName="Helvetica-Bold", fontSize=11,
textColor=DARK_BLUE, leading=15, spaceAfter=3, spaceBefore=8)
H3 = S("h3", fontName="Helvetica-BoldOblique", fontSize=10,
textColor=MID_BLUE, leading=14, spaceAfter=2, spaceBefore=5)
BODY = S("body", fontName="Helvetica", fontSize=9.5, leading=14,
textColor=DARK_GREY, alignment=TA_JUSTIFY, spaceAfter=4)
BULLET = S("bullet", fontName="Helvetica", fontSize=9.5, leading=13,
textColor=DARK_GREY, leftIndent=14, bulletIndent=4, spaceAfter=2)
SMALL = S("small", fontName="Helvetica", fontSize=8.5, leading=12,
textColor=MED_GREY, spaceAfter=2)
SOURCE = S("source", fontName="Helvetica-Oblique", fontSize=8,
textColor=MED_GREY, alignment=TA_CENTER, spaceAfter=0)
RED_FLAG_TITLE = S("rf_title", fontName="Helvetica-Bold", fontSize=10,
textColor=ACCENT_RED, leading=14, spaceAfter=2)
story = []
# ════════════════════════════════════════════════════════════════════════════
# PAGE 1 – Cover banner + Introduction
# ════════════════════════════════════════════════════════════════════════════
# Hero banner table
banner_data = [[
Paragraph("HEADACHE", TITLE_S),
]]
banner = Table(banner_data, colWidths=[W - 3.6*cm])
banner.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), DARK_BLUE),
("TOPPADDING", (0,0), (-1,-1), 22),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 12),
("RIGHTPADDING", (0,0), (-1,-1), 12),
("ROUNDEDCORNERS", [8], (0,0), (-1,-1)),
]))
story.append(banner)
sub_data = [[Paragraph("A Clinical Overview for Medical Students & Clinicians", SUBTITLE_S)]]
sub_table = Table(sub_data, colWidths=[W - 3.6*cm])
sub_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), MID_BLUE),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 12),
("RIGHTPADDING", (0,0), (-1,-1), 12),
]))
story.append(sub_table)
story.append(Paragraph("Sources: Adams & Victor's Neurology · Goldman-Cecil Medicine · Rosen's Emergency Medicine · Harrison's 22E · Goodman & Gilman's Pharmacology", SOURCE))
story.append(Spacer(1, 0.4*cm))
# ── Introduction ─────────────────────────────────────────────────────────────
def section_header(title, colour=DARK_BLUE):
data = [[Paragraph(title, H1)]]
t = Table(data, colWidths=[W - 3.6*cm])
t.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),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("ROUNDEDCORNERS", [5], (0,0), (-1,-1)),
]))
return t
story.append(section_header("1. INTRODUCTION & EPIDEMIOLOGY"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"Headache is one of the most common complaints in clinical practice and a frequent reason for emergency department visits. "
"The vast majority of patients presenting with headache have a benign primary cause such as tension-type headache or migraine. "
"A minority have a secondary headache arising from an underlying medical or surgical condition requiring prompt diagnosis.",
BODY))
story.append(Paragraph(
"The clinician's primary goal is to distinguish primary headache (where head pain is the only identifiable disease) from "
"<b>secondary headache</b> (caused by an underlying structural, vascular, or systemic condition). Headache is "
"disproportionately represented in emergency medicine malpractice claims, largely because serious causes such as "
"subarachnoid haemorrhage (SAH) are missed on first presentation in over 25% of cases.",
BODY))
story.append(Spacer(1, 0.3*cm))
# ── Classification ────────────────────────────────────────────────────────────
story.append(section_header("2. CLASSIFICATION (IHS)"))
story.append(Spacer(1, 0.2*cm))
class_data = [
["Category", "Types"],
["Primary Headaches\n(no underlying cause)", "• Migraine (with/without aura)\n• Tension-type headache\n• Cluster headache & TACs\n• Other primary headaches"],
["Secondary Headaches\n(underlying disease)", "• SAH / Intracranial haemorrhage\n• Meningitis / Encephalitis\n• Raised intracranial pressure\n• Cervical artery dissection\n• CO poisoning · Temporal arteritis\n• Idiopathic intracranial hypertension"],
]
ct = Table(class_data, colWidths=[5.5*cm, 10.5*cm])
ct.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,0), 10),
("BACKGROUND", (0,1), (-1,1), LIGHT_BLUE),
("BACKGROUND", (0,2), (-1,2), LIGHT_GREY),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("FONTSIZE", (0,1), (-1,-1), 9),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 7),
("RIGHTPADDING", (0,0), (-1,-1), 7),
("GRID", (0,0), (-1,-1), 0.5, MID_BLUE),
("ROUNDEDCORNERS", [4], (0,0), (-1,-1)),
]))
story.append(ct)
story.append(Spacer(1, 0.4*cm))
# ── RED FLAGS ─────────────────────────────────────────────────────────────────
story.append(KeepTogether([
section_header("3. RED FLAGS ('SNOOP4' MNEMONIC)", colour=ACCENT_RED),
Spacer(1, 0.2*cm),
Paragraph(
"These features should prompt urgent investigation for a secondary cause:",
BODY),
]))
snoop_data = [
["Letter", "Meaning", "Concern"],
["S", "Systemic symptoms / disease", "Fever, weight loss, HIV, cancer"],
["N", "Neurological signs / symptoms", "Focal deficits, altered consciousness"],
["O", "Onset sudden / thunderclap", "SAH until proven otherwise"],
["O", "Older age (>50 yrs) new headache", "Temporal arteritis, malignancy"],
["P", "Pattern change", "New or progressive in known headache patient"],
["P", "Postural component", "IIH (worse supine) or low CSF pressure"],
["P", "Precipitated by Valsalva", "Mass lesion, AVM, aneurysm"],
["P", "Papilloedema / Pregnancy", "Raised ICP, pre-eclampsia"],
]
st = Table(snoop_data, colWidths=[1.2*cm, 5.8*cm, 9*cm])
st.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), ACCENT_RED),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 9),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("TEXTCOLOR", (0,1), (0,-1), ACCENT_RED),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_GREY]),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("GRID", (0,0), (-1,-1), 0.4, MED_GREY),
]))
story.append(st)
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# PAGE 2 – Primary Headaches
# ════════════════════════════════════════════════════════════════════════════
story.append(section_header("4. PRIMARY HEADACHES"))
story.append(Spacer(1, 0.25*cm))
# ── 4a Migraine ──────────────────────────────────────────────────────────────
story.append(Paragraph("4a. Migraine", H2))
story.append(Paragraph(
"<b>Epidemiology:</b> Affects 10–20% of the population; peak incidence earlier in boys than girls but overall female predominance after puberty.",
BODY))
story.append(Paragraph(
"<b>Types:</b> Migraine <i>without</i> aura (common migraine) and migraine <i>with</i> aura (classic migraine). "
"Aura may begin up to 24 hours before pain onset and often includes photophobia, hyperacusis, polyuria, and mood disturbance.",
BODY))
story.append(Paragraph(
"<b>Pathogenesis:</b> Complex neural and vascular interaction. Serotonin (5-HT) is a key mediator — plasma/platelet 5-HT levels "
"vary across migraine phases, and urinary 5-HT metabolites are elevated during attacks. The trigeminovascular system mediates most of the pain.",
BODY))
mig_data = [
["Feature", "Details"],
["Site", "Unilateral (may be bilateral); frontotemporal"],
["Character", "Pulsating / throbbing"],
["Severity", "Moderate to severe; disabling"],
["Duration", "4–72 hours"],
["Associated", "Nausea, vomiting, photophobia, phonophobia"],
["Aggravated by", "Routine physical activity"],
["Behaviour", "Patient prefers to rest / lie still in dark room"],
]
mt = Table(mig_data, colWidths=[4.5*cm, 11.5*cm])
mt.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), MID_BLUE),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 9),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_BLUE]),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("GRID", (0,0), (-1,-1), 0.4, MED_GREY),
]))
story.append(mt)
story.append(Spacer(1, 0.15*cm))
story.append(Paragraph("<b>Treatment:</b>", H3))
story.append(Paragraph(
"<b>Abortive (acute):</b> NSAIDs (ibuprofen/naproxen) for mild-moderate attacks. "
"Triptans (5-HT1B/1D agonists) — sumatriptan, zolmitriptan, rizatriptan — for moderate-severe attacks; "
"start as early as possible. IV metoclopramide or prochlorperazine (dopamine antagonists) for parenteral management in ED. "
"Opioids are NOT recommended for primary headaches.",
BODY))
story.append(Paragraph(
"<b>Prophylaxis (preventive):</b> Indicated when attacks are frequent or disabling. "
"Options include β-blockers (propranolol, metoprolol), tricyclic antidepressants (amitriptyline), "
"anticonvulsants (valproate, topiramate), and CGRP monoclonal antibodies (newer agents).",
BODY))
story.append(Spacer(1, 0.25*cm))
# ── 4b Tension-Type ───────────────────────────────────────────────────────────
story.append(Paragraph("4b. Tension-Type Headache (TTH)", H2))
story.append(Paragraph(
"The most common primary headache disorder. The term 'tension-type' reflects that actual muscle tension may not always be present.",
BODY))
tth_data = [
["Feature", "Details"],
["Site", "Bilateral"],
["Character", "Pressing / tightening ('band-like'); non-pulsating"],
["Severity", "Mild to moderate; not disabling"],
["Duration", "30 min – 7 days"],
["Associated", "May have photophobia OR phonophobia (not both); no nausea/vomiting"],
["Aggravated by", "Not worsened by routine activity"],
["Behaviour", "Patient can continue daily activities"],
]
tt = Table(tth_data, colWidths=[4.5*cm, 11.5*cm])
tt.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), MID_BLUE),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 9),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_BLUE]),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("GRID", (0,0), (-1,-1), 0.4, MED_GREY),
]))
story.append(tt)
story.append(Paragraph(
"<b>Treatment:</b> Simple analgesics (paracetamol, NSAIDs). Preventive: amitriptyline. "
"Avoid medication overuse (>10–15 days/month leads to medication-overuse headache).",
BODY))
story.append(Spacer(1, 0.25*cm))
# ── 4c Cluster ────────────────────────────────────────────────────────────────
story.append(Paragraph("4c. Cluster Headache & Trigeminal Autonomic Cephalalgias (TACs)", H2))
story.append(Paragraph(
"Cluster headache is the most common TAC. It predominantly affects men (M:F = 3–7:1), "
"onset typically 20–30 years of age. Attacks often precipitated by alcohol, histamine, or nitroglycerin.",
BODY))
cl_data = [
["Feature", "Cluster Headache", "Paroxysmal Hemicrania", "SUNCT"],
["Sex (F:M)", "1 : 3–7", "2 : 1", "1 : 2"],
["Site", "Orbital/temporal (unilateral)", "Periorbital/temporal", "Orbital/temporal"],
["Character", "Boring / stabbing, excruciating", "Severe", "Stabbing"],
["Duration", "15–180 min", "2–30 min", "5–240 sec"],
["Frequency", "1–8 per day", "Up to 40/day", "3–200/day"],
["Autonomic features", "Lacrimation, conjunctival injection,\nptosis, miosis, rhinorrhoea", "Similar", "Conjunctival injection + tearing"],
["Behaviour", "Paces; cannot rest (unlike migraine)", "—", "—"],
["Acute Rx", "O₂ 100%, sumatriptan SC/nasal,\nDHE nasal spray", "None specific", "None specific"],
["Preventive Rx", "Verapamil, lithium, corticosteroids,\ngalcanezumab", "Indomethacin +++", "Lamotrigine, gabapentin"],
]
clt = Table(cl_data, colWidths=[3.8*cm, 4.8*cm, 4*cm, 3.4*cm])
clt.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_BLUE]),
("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"),
("GRID", (0,0), (-1,-1), 0.4, MED_GREY),
]))
story.append(clt)
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# PAGE 3 – Secondary Headaches, Investigations, Management
# ════════════════════════════════════════════════════════════════════════════
story.append(section_header("5. SECONDARY HEADACHES — KEY CAUSES"))
story.append(Spacer(1, 0.2*cm))
sec_data = [
["Condition", "Hallmark Features", "Investigation"],
["Subarachnoid\nHaemorrhage (SAH)", "Thunderclap headache — 'worst of my life'\n>25% missed on first presentation", "CT head → LP (xanthochromia) → CTA"],
["Bacterial Meningitis", "Severe headache + fever + neck stiffness\n± Kernig/Brudzinski signs, purpuric rash", "CT (if indicated) → LP; IV antibiotics BEFORE LP if delay"],
["Idiopathic Intracranial\nHypertension (IIH)", "Obese young woman; bilateral headache\nworse supine, papilloedema, VI nerve palsy", "MRI/MRV brain; LP (opening pressure >25 cmH₂O)"],
["Temporal (Giant Cell)\nArteritis", "Age >50, new headache, temporal artery\ntenderness, jaw claudication, raised ESR/CRP", "ESR, CRP; temporal artery biopsy"],
["Cervical Artery\nDissection", "Neck pain + headache; Horner syndrome\n± stroke symptoms", "MRI/MRA; CTA neck"],
["CO Poisoning", "Multiple household members affected\nHeadache, nausea, confusion", "COHb level; remove from source; 100% O₂"],
["Intracranial Mass", "Progressive headache, worse in morning\n± focal deficits, seizures, papilloedema", "MRI brain with contrast"],
]
secc = Table(sec_data, colWidths=[4*cm, 6.5*cm, 5.5*cm])
secc.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_GREY]),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
("GRID", (0,0), (-1,-1), 0.4, MED_GREY),
]))
story.append(secc)
story.append(Spacer(1, 0.35*cm))
# ── Investigations ────────────────────────────────────────────────────────────
story.append(section_header("6. INVESTIGATIONS"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"<b>Most patients with headache do not require neuroimaging.</b> Investigations are tailored to "
"specific clinical concerns identified by history and examination.",
BODY))
inv_data = [
["Investigation", "Indication"],
["CT Head (non-contrast)", "Thunderclap / suspected SAH, ICH, or acute emergency"],
["LP (Lumbar Puncture)", "Normal CT but suspected SAH (xanthochromia ≥12 h), meningitis"],
["CT/MR Angiography", "Suspected aneurysm, cervical artery dissection"],
["MRI Brain ± contrast", "Suspected mass, IIH, cavernous sinus, posterior fossa lesion"],
["MR Venography (MRV)", "Cerebral venous sinus thrombosis, IIH"],
["Blood tests (ESR, CRP, CBC)", "Temporal arteritis, systemic illness, CO poisoning"],
["Fundoscopy", "Mandatory in all — papilloedema = raised ICP until disproven"],
]
invt = Table(inv_data, colWidths=[5*cm, 11*cm])
invt.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), MID_BLUE),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 9),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_BLUE]),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("GRID", (0,0), (-1,-1), 0.4, MED_GREY),
]))
story.append(invt)
story.append(Spacer(1, 0.35*cm))
# ── Management Summary ────────────────────────────────────────────────────────
story.append(section_header("7. MANAGEMENT SUMMARY"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph("Acute / Abortive Therapy:", H3))
mgmt_data = [
["Headache Type", "First-line Acute Rx", "Parenteral (ED) Option"],
["Tension-type", "Paracetamol or NSAID", "Ketorolac IV"],
["Migraine (mild-mod)", "NSAID ± antiemetic", "Metoclopramide IV (also treats nausea)\nProchlorperazine IV (2nd line)"],
["Migraine (mod-severe)", "Triptan (e.g. sumatriptan 50 mg PO\nor 6 mg SC) ± NSAID", "IV metoclopramide or prochlorperazine;\nTriptan SC if available"],
["Cluster headache", "100% O₂ via non-rebreather 15 L/min\n+ sumatriptan 6 mg SC", "DHE nasal spray; zolmitriptan nasal"],
["Secondary (SAH etc)", "Treat underlying cause urgently", "Neurosurgical/ICU referral"],
]
mgt = Table(mgmt_data, colWidths=[4*cm, 6*cm, 6*cm])
mgt.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_GREY]),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("GRID", (0,0), (-1,-1), 0.4, MED_GREY),
]))
story.append(mgt)
story.append(Spacer(1, 0.25*cm))
story.append(Paragraph("Preventive Therapy (Migraine):", H3))
prev_data = [
["Drug Class", "Examples", "Notes"],
["β-Blockers", "Propranolol, metoprolol", "First-line; avoid in asthma"],
["Tricyclic antidepressants", "Amitriptyline 10–75 mg nocte", "Also for TTH prevention"],
["Anticonvulsants", "Valproate, topiramate", "Valproate: avoid in pregnancy"],
["CGRP mAbs", "Erenumab, fremanezumab", "Newer agents; SC monthly"],
["Calcium channel blockers", "Verapamil", "First choice for cluster headache prevention"],
]
prevt = Table(prev_data, colWidths=[5*cm, 5.5*cm, 5.5*cm])
prevt.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), MID_BLUE),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 9),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_BLUE]),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("GRID", (0,0), (-1,-1), 0.4, MED_GREY),
]))
story.append(prevt)
story.append(Spacer(1, 0.4*cm))
# ── Key Points Box ───────────────────────────────────────────────────────────
kp_data = [[
Paragraph(
"<b>KEY POINTS</b><br/>"
"• Thunderclap headache = SAH until proven otherwise — CT + LP if CT negative.<br/>"
"• Opioids are NOT indicated for primary headache disorders.<br/>"
"• Fundoscopy is mandatory — papilloedema indicates raised ICP.<br/>"
"• Cluster headache patients pace; migraine patients lie still in the dark.<br/>"
"• Paroxysmal hemicrania & hemicrania continua respond dramatically to indomethacin (diagnostic).<br/>"
"• Medication-overuse headache occurs with analgesic use >10–15 days/month — wean the offending drug.",
S("kp", fontName="Helvetica", fontSize=9, leading=14, textColor=DARK_BLUE))
]]
kpt = Table(kp_data, colWidths=[W - 3.6*cm])
kpt.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), LIGHT_BLUE),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("BOX", (0,0), (-1,-1), 1.5, MID_BLUE),
("ROUNDEDCORNERS", [6], (0,0), (-1,-1)),
]))
story.append(kpt)
story.append(Spacer(1, 0.3*cm))
# ── Footer ───────────────────────────────────────────────────────────────────
story.append(HRFlowable(width="100%", thickness=0.5, color=MID_BLUE, spaceAfter=4))
story.append(Paragraph(
"Sources: Adams & Victor's Principles of Neurology 12e | Goldman-Cecil Medicine International Ed. | "
"Rosen's Emergency Medicine | Harrison's Principles of Internal Medicine 22E | "
"Goodman & Gilman's Pharmacological Basis of Therapeutics | Frameworks for Internal Medicine",
SOURCE))
# ── Build ─────────────────────────────────────────────────────────────────────
doc.build(story)
print("PDF built successfully.")
cd /home/daytona/workspace/headache-pdf && python build_headache_pdf.py 2>&1
python3 -c "import reportlab; print(reportlab.Version)"
cd /home/daytona/workspace/headache-pdf && sed -i '/ROUNDEDCORNERS/d' build_headache_pdf.py && python build_headache_pdf.py 2>&1
python3 -c " import re with open('/home/daytona/workspace/headache-pdf/build_headache_pdf.py','r') as f: content = f.read() content2 = re.sub(r'\s*\(\"ROUNDEDCORNERS\".*?\),\n', '\n', content) with open('/home/daytona/workspace/headache-pdf/build_headache_pdf.py','w') as f: f.write(content2) print('done') "
cd /home/daytona/workspace/headache-pdf && python build_headache_pdf.py 2>&1
ls -lh /home/daytona/workspace/headache-pdf/Headache_Clinical_Overview.pdf
Headache Clinical Overview
PDF Document · PDF
What is cancer?
| Feature | Benign Tumor | Malignant Tumor (Cancer) |
|---|---|---|
| Growth | Slow, controlled | Rapid, uncontrolled |
| Borders | Well-defined capsule | Irregular, invasive |
| Invasion | Does NOT invade locally | Invades adjacent tissues |
| Metastasis | Does NOT spread | Spreads to distant sites |
| Cell appearance | Near-normal (differentiated) | Abnormal (poorly differentiated) |
| Outcome | Usually harmless | Can be life-threatening |

| Gene Type | Normal Role | Effect of Mutation |
|---|---|---|
| Proto-oncogenes | Promote controlled cell growth | Become oncogenes - cause uncontrolled proliferation (gain-of-function) |
| Tumor suppressor genes | Inhibit cell division; induce apoptosis | Inactivated - "brakes" are lost (loss-of-function). e.g. TP53, RB1 |
| DNA repair genes | Fix DNA errors | Mutations accumulate unchecked |
| Apoptosis-regulating genes | Control cell death | Cells become immortal |
| Category | Origin | Examples |
|---|---|---|
| Carcinoma | Epithelial cells | Lung, breast, colon, prostate cancer (~85% of all cancers) |
| Sarcoma | Connective tissue (bone, muscle, fat) | Osteosarcoma, liposarcoma |
| Lymphoma | Lymphoid tissue | Hodgkin lymphoma, non-Hodgkin lymphoma |
| Leukaemia | Bone marrow / blood cells | AML, CLL, CML, ALL |
| Glioma | Glial cells of brain | Glioblastoma multiforme |
| Melanoma | Melanocytes (skin) | Cutaneous melanoma |
Cancer = a clonal disease of uncontrolled cell proliferation driven by accumulated genetic mutations in proto-oncogenes, tumor suppressor genes, DNA repair genes, and apoptosis-regulating genes, resulting in a cell that grows without restraint, evades death, recruits blood vessels, invades locally, and spreads to distant organs.