Epidemiology and prevention of Covid 19
"COVID-19"[MeSH Terms] AND "epidemiology"[MeSH Terms]
COVID-19 epidemiology prevention 2025 2026 WHO update
| Virus | Receptor | Incubation | CFR |
|---|---|---|---|
| SARS-CoV-1 | ACE2 | 2-11 days | ~10% |
| MERS-CoV | DPP4 | 2-13 days | ~30% |
| SARS-CoV-2 | ACE2 | 2-14 days | 2-4% (variable) |
| Comorbidity | Hazard Ratio for Mortality (UK cohort) |
|---|---|
| Cardiovascular disease | 1.16 |
| Chronic kidney disease | 1.33 |
| Obesity (BMI ≥30) | 1.33 |
| Liver disease | 1.51 |
| WHO Label | Lineage | Origin | Designated |
|---|---|---|---|
| Alpha | B.1.1.7 | UK, Sept 2020 | Dec 2020 |
| Beta | B.1.351 | South Africa, May 2020 | Dec 2020 |
| Gamma | P.1 | Brazil, Nov 2020 | Jan 2021 |
| Delta | B.1.617.2 | India, Oct 2020 | May 2021 |
| Omicron (and subvariants) | BA lineages | Multiple | Nov 2021 onwards |
| Intervention | Mechanism |
|---|---|
| Physical distancing (>2 m) | Reduces exposure to respiratory droplets |
| Mask wearing | Blocks droplet and aerosol emission/reception |
| Hand hygiene (soap and water / alcohol-based sanitizers) | Inactivates fomites |
| Ventilation improvement | Dilutes airborne viral concentration indoors |
| Isolation of cases + quarantine of contacts | Interrupts chains of transmission |
| Testing and contact tracing | Early identification and isolation |
| School and workplace closures | Broad reduction of contact rates (also reduced seasonal coronavirus circulation during the pandemic) |
| Vaccine | Platform | Schedule (original) |
|---|---|---|
| Pfizer-BioNTech (BNT162b2) | mRNA | 2 doses, 21 days apart |
| Moderna (mRNA-1273) | mRNA | 2 doses, 28 days apart |
| J&J Janssen (Ad26.CoV2.S) | Adenoviral vector (non-replicating) | Single dose |
| AstraZeneca (AZD1222 / ChAdOx1) | Modified adenoviral vector | 1-2 doses |
| Sputnik V (Gam-COVID-Vac) | Heterologous rAd26 + rAd5 | 2 doses, 21 days apart |
| CoronaVac (Sinovac) | Inactivated SARS-CoV-2 | 2 doses |
| Covaxin (BBV152, Bharat Biotech) | Inactivated whole-virion | 2 doses |
| BBIBP-CorV (Sinopharm) | Inactivated adjuvanted | 2 doses |
| Stage | Timing | Features |
|---|---|---|
| Asymptomatic | Any | No symptoms; ~40-45% of all infections |
| Mild | Days 1-10 | Fever, fatigue, dry cough, anosmia/ageusia, myalgia, diarrhea, ground-glass infiltrates |
| Severe | Usually after day 10 | SpO₂ <94%, RR ≥30/min, lung infiltrates >50%, elevated troponin/BNP/inflammatory markers |
| Critical | Usually after day 10 | ARDS, acute cardiac injury, multi-organ failure, SIRS/shock |
Make pdf
ls -la /tmp/workspace/ 2>/dev/null || mkdir -p /tmp/workspace && echo "created"
mkdir -p /tmp/workspace/covid19-pdf && cat << 'PYEOF' > /tmp/workspace/covid19-pdf/generate.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, KeepTogether ) from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY # Output path OUTPUT = "/tmp/workspace/covid19-pdf/COVID19_Epidemiology_Prevention.pdf" doc = SimpleDocTemplate( OUTPUT, pagesize=A4, leftMargin=2*cm, rightMargin=2*cm, topMargin=2.2*cm, bottomMargin=2.2*cm, title="Epidemiology and Prevention of COVID-19", author="Orris Medical Assistant", ) styles = getSampleStyleSheet() # --- Custom Styles --- title_style = ParagraphStyle( "CustomTitle", parent=styles["Title"], fontSize=22, textColor=colors.HexColor("#1a3c5e"), spaceAfter=6, alignment=TA_CENTER, fontName="Helvetica-Bold", ) subtitle_style = ParagraphStyle( "Subtitle", parent=styles["Normal"], fontSize=11, textColor=colors.HexColor("#4a6e8a"), spaceAfter=4, alignment=TA_CENTER, fontName="Helvetica-Oblique", ) h1_style = ParagraphStyle( "H1", parent=styles["Heading1"], fontSize=13, textColor=colors.white, backColor=colors.HexColor("#1a3c5e"), spaceBefore=14, spaceAfter=6, leftIndent=-0.3*cm, rightIndent=-0.3*cm, borderPad=5, fontName="Helvetica-Bold", ) h2_style = ParagraphStyle( "H2", parent=styles["Heading2"], fontSize=11, textColor=colors.HexColor("#1a3c5e"), spaceBefore=10, spaceAfter=4, fontName="Helvetica-Bold", borderPadding=(0,0,2,0), ) body_style = ParagraphStyle( "Body", parent=styles["Normal"], fontSize=9.5, leading=14, spaceAfter=5, alignment=TA_JUSTIFY, fontName="Helvetica", ) bullet_style = ParagraphStyle( "Bullet", parent=styles["Normal"], fontSize=9.5, leading=13, spaceAfter=3, leftIndent=14, bulletIndent=4, fontName="Helvetica", ) source_style = ParagraphStyle( "Source", parent=styles["Normal"], fontSize=8, textColor=colors.HexColor("#666666"), fontName="Helvetica-Oblique", spaceAfter=3, leftIndent=10, ) note_style = ParagraphStyle( "Note", parent=styles["Normal"], fontSize=8.5, textColor=colors.HexColor("#555555"), backColor=colors.HexColor("#f0f4f8"), fontName="Helvetica-Oblique", borderPad=6, spaceAfter=4, leftIndent=5, rightIndent=5, ) def h1(text): return Paragraph(f" {text}", h1_style) def h2(text): return Paragraph(text, h2_style) def body(text): return Paragraph(text, body_style) def bullet(text): return Paragraph(f"• {text}", bullet_style) def source(text): return Paragraph(f"<i>{text}</i>", source_style) def note(text): return Paragraph(text, note_style) def spacer(h=0.25): return Spacer(1, h*cm) def hr(color="#1a3c5e", thickness=1): return HRFlowable(width="100%", thickness=thickness, color=colors.HexColor(color)) # --- Table helper --- TABLE_HEADER_BG = colors.HexColor("#1a3c5e") TABLE_ROW_ALT = colors.HexColor("#e8f0f7") TABLE_GRID = colors.HexColor("#b0c4d8") def make_table(data, col_widths=None): t = Table(data, colWidths=col_widths, repeatRows=1) style = [ ("BACKGROUND", (0,0), (-1,0), TABLE_HEADER_BG), ("TEXTCOLOR", (0,0), (-1,0), colors.white), ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"), ("FONTSIZE", (0,0), (-1,0), 9), ("ALIGN", (0,0), (-1,0), "CENTER"), ("VALIGN", (0,0), (-1,-1), "MIDDLE"), ("FONTNAME", (0,1), (-1,-1), "Helvetica"), ("FONTSIZE", (0,1), (-1,-1), 8.5), ("GRID", (0,0), (-1,-1), 0.4, TABLE_GRID), ("ROWBACKGROUNDS", (0,1), (-1,-1), [colors.white, TABLE_ROW_ALT]), ("TOPPADDING", (0,0), (-1,-1), 5), ("BOTTOMPADDING",(0,0), (-1,-1), 5), ("LEFTPADDING", (0,0), (-1,-1), 6), ("RIGHTPADDING",(0,0), (-1,-1), 6), ] t.setStyle(TableStyle(style)) return t # ===================== BUILD CONTENT ===================== story = [] # Title block story.append(spacer(0.4)) story.append(Paragraph("Epidemiology and Prevention of COVID-19", title_style)) story.append(Paragraph("A Comprehensive Medical Reference Summary", subtitle_style)) story.append(spacer(0.15)) story.append(hr()) story.append(spacer(0.1)) story.append(Paragraph( "Sources: Harrison's Principles of Internal Medicine 22E · Braunwald's Heart Disease · " "Murray & Nadel's Respiratory Medicine · Fuster & Hurst's The Heart · Goldman-Cecil Medicine", source_style )) story.append(spacer(0.3)) # ==== SECTION 1 ==== story.append(h1("1. The Pathogen and Origin")) story.append(spacer(0.1)) story.append(body( "SARS-CoV-2 is a single-stranded RNA virus of the <b>Betacoronavirus</b> genus (Coronaviridae family). " "It encodes four structural proteins: spike (S), envelope (E), membrane (M), and nucleocapsid (N). " "The spike protein binds to the human <b>angiotensin-converting enzyme 2 (ACE-2)</b> receptor, " "primed by the serine protease TMPRSS2, making ACE-2-expressing tissues - nasal/bronchial epithelium, " "type II alveolar pneumocytes, and vascular endothelium - primary infection targets." )) story.append(body( "The virus likely originated in a bat reservoir before the 2019 Wuhan outbreak. Seven human coronaviruses " "are known; three can cause severe disease. Of these, SARS-CoV-2 has by far the greatest global impact." )) story.append(spacer(0.2)) cov_data = [ ["Virus", "Receptor", "Incubation", "Case Fatality Rate"], ["SARS-CoV-1", "ACE2", "2-11 days", "~10%"], ["MERS-CoV", "DPP4", "2-13 days", "~30%"], ["SARS-CoV-2", "ACE2", "2-14 days", "2-4% (variable)"], ] story.append(make_table(cov_data, col_widths=[4.5*cm, 3.5*cm, 3.5*cm, 4.5*cm])) story.append(source("Braunwald's Heart Disease, Table 94.1")) story.append(spacer(0.2)) # ==== SECTION 2 ==== story.append(h1("2. Global Epidemiology")) story.append(spacer(0.1)) epi_bullets = [ "<b>January 30, 2020:</b> WHO declared a Public Health Emergency of International Concern.", "<b>March 11, 2020:</b> WHO declared a global pandemic.", "<b>May 5, 2023:</b> WHO declared an end to the global COVID-19 emergency.", "<b>By September 2024:</b> >700 million confirmed cases and >7 million deaths worldwide.", "Seroprevalence surveys showed actual prior exposure exceeded reported cases by <b>10-fold or more</b>, " "due to widespread asymptomatic infection and limited testing.", "The <b>basic reproduction number (R\u2080)</b> of SARS-CoV-2 peaked around <b>6</b>, far exceeding " "seasonal influenza (R\u2080 ~1-2), explaining its rapid pandemic spread.", "High-risk transmission settings include: prisons, cruise ships, nursing homes, " "aircraft, large indoor gatherings, and poorly-ventilated enclosed spaces.", ] for b in epi_bullets: story.append(bullet(b)) story.append(source("Harrison's Principles of Internal Medicine 22E, p. 1583")) story.append(spacer(0.2)) # ==== SECTION 3 ==== story.append(h1("3. Transmission Routes")) story.append(spacer(0.1)) story.append(h2("A. Respiratory Droplets (Primary Route)")) story.append(body( "Large droplets (>5 \u03bcm) generated by coughing, sneezing, or talking spread within ~2 meters. " "This is the dominant mode of transmission." )) story.append(h2("B. Aerosol / Airborne Transmission")) story.append(body( "Small particles (<5 \u03bcm) remain suspended in air for up to 3 hours and can travel beyond 2 meters. " "Supporting evidence includes:" )) aerosol_bullets = [ "SARS-CoV-2 remained viable in aerosol up to <b>3 hours</b> in laboratory conditions.", "Viral RNA detected in hospital ventilation systems.", "Superspreading event: choir practice where <b>88% of attendees</b> were infected.", "Greatest risk in <b>enclosed, poorly-ventilated spaces</b>.", ] for b in aerosol_bullets: story.append(bullet(b)) story.append(h2("C. Fomite Transmission")) story.append(body( "SARS-CoV-2 persists on cardboard, steel, and plastic surfaces for days. " "Hand-to-face contact transfers virus to mucous membranes. " "Most disinfectants effectively inactivate the virus." )) story.append(h2("Key Infectivity Timeline")) inf_data = [ ["Timepoint", "Detail"], ["2-3 days before symptoms", "Individuals may already be infectious (presymptomatic transmission)"], ["Day 0-8 of illness", "Culturable (live) virus typically present; drives most transmission"], ["Beyond Day 8", "RNA shedding continues but live virus rarely isolated"], ["~40-45% of infections", "Remain asymptomatic; significant contributor to community spread"], ] story.append(make_table(inf_data, col_widths=[5.5*cm, 10.5*cm])) story.append(source("Murray & Nadel's Textbook of Respiratory Medicine, pp. 1083-1085")) story.append(spacer(0.2)) # ==== SECTION 4 ==== story.append(h1("4. Risk Factors for Severe Disease and Mortality")) story.append(spacer(0.1)) story.append(h2("Age")) story.append(body( "Advanced age is the single strongest predictor of severe disease and death, " "related to immunosenescence and accumulation of comorbidities." )) story.append(h2("Comorbidities")) story.append(body( "In a prospective UK cohort of 208 hospitals, the following comorbidities were associated " "with significantly increased mortality:" )) rf_data = [ ["Comorbidity", "Hazard Ratio for Mortality"], ["Cardiovascular disease", "1.16"], ["Chronic kidney disease", "1.33"], ["Obesity (BMI \u226530)", "1.33"], ["Liver disease", "1.51"], ["Hypertension", "Most prevalent comorbidity (no HR quoted)"], ] story.append(make_table(rf_data, col_widths=[9*cm, 7*cm])) story.append(spacer(0.1)) rf_bullets = [ "Median of <b>4 comorbidities</b> at admission in a 5,700-patient New York State cohort.", "Malignancy and solid organ transplant recipients carry significantly elevated risk.", "Among symptomatic cases: ~80% mild (no hospitalization), ~15% moderate-severe, ~5% critical (ICU).", ] for b in rf_bullets: story.append(bullet(b)) story.append(h2("Racial and Social Disparities")) story.append(body( "Black, Hispanic, Native American, and Alaskan Native populations experienced " "disproportionately higher COVID-19 mortality, driven by structural social determinants, " "access barriers, and higher rates of underlying comorbidities." )) story.append(source("Murray & Nadel's Textbook of Respiratory Medicine, p. 1084")) story.append(spacer(0.2)) # ==== SECTION 5 ==== story.append(h1("5. Variants of Concern (VOC)")) story.append(spacer(0.1)) story.append(body( "The WHO designated successive Variants of Concern as SARS-CoV-2 evolved, " "often with higher transmissibility or immune escape:" )) voc_data = [ ["WHO Label", "Lineage", "Origin", "Designated"], ["Alpha", "B.1.1.7", "UK, Sept 2020", "Dec 2020"], ["Beta", "B.1.351", "South Africa, May 2020", "Dec 2020"], ["Gamma", "P.1", "Brazil, Nov 2020", "Jan 2021"], ["Delta", "B.1.617.2", "India, Oct 2020", "May 2021"], ["Omicron", "BA lineages","Multiple, Nov 2021", "Nov 2021"], ] story.append(make_table(voc_data, col_widths=[3.5*cm, 3.5*cm, 6*cm, 3*cm])) story.append(note( "Note (2025-2026): Omicron-descendant subvariants continue to circulate globally. " "The 'stratus' variant drove elevated activity in the US in mid-2025. " "Public health risk from newer variants has generally been assessed as low globally, " "with approved vaccines expected to remain effective against severe disease." )) story.append(source("Braunwald's Heart Disease, Table 94.1 (etable); WHO/CDC 2025 surveillance data")) story.append(spacer(0.2)) # ==== SECTION 6 ==== story.append(h1("6. Prevention Strategies")) story.append(spacer(0.1)) story.append(h2("A. Non-Pharmaceutical Interventions (NPIs)")) npi_data = [ ["Intervention", "Mechanism / Benefit"], ["Physical distancing (>2 m)", "Reduces exposure to respiratory droplets"], ["Mask wearing (surgical / N95)", "Blocks droplet/aerosol emission and reception"], ["Hand hygiene (soap / sanitizer)", "Inactivates fomites on hands before mucous membrane contact"], ["Ventilation improvement", "Dilutes airborne viral concentration in indoor spaces"], ["Isolation of cases", "Interrupts ongoing chains of transmission"], ["Quarantine of contacts", "Prevents presymptomatic spread to new hosts"], ["Testing and contact tracing", "Early identification, isolation of infected individuals"], ["School / workplace closures", "Broad reduction of contact rates (also reduced seasonal CoV transmission)"], ["Disinfection of surfaces", "Eliminates fomite route in high-touch environments"], ] story.append(make_table(npi_data, col_widths=[6.5*cm, 9.5*cm])) story.append(source("Goldman-Cecil Medicine, Chapter 334; Murray & Nadel, Chapter 46a")) story.append(spacer(0.2)) story.append(h2("B. Vaccines")) story.append(body( "Vaccines were developed at unprecedented speed following genome sequencing. " "Neutralizing antibodies primarily target the <b>receptor-binding domain (RBD) " "of the S1 spike protein</b>. Multiple platforms were deployed:" )) vax_data = [ ["Vaccine", "Platform", "Primary Schedule"], ["Pfizer-BioNTech (BNT162b2)", "mRNA", "2 doses, 21 days apart"], ["Moderna (mRNA-1273)", "mRNA", "2 doses, 28 days apart"], ["J&J Janssen (Ad26.CoV2.S)", "Adenoviral vector", "Single dose"], ["AstraZeneca (AZD1222)", "Modified adenoviral vector", "1-2 doses"], ["Sputnik V (Gam-COVID-Vac)", "Heterologous rAd26 + rAd5", "2 doses, 21 days apart"], ["CoronaVac (Sinovac)", "Inactivated SARS-CoV-2", "2 doses"], ["Covaxin / BBV152 (Bharat)", "Inactivated whole-virion", "2 doses"], ["BBIBP-CorV (Sinopharm)", "Inactivated adjuvanted", "2 doses"], ] story.append(make_table(vax_data, col_widths=[5.5*cm, 5.5*cm, 5*cm])) story.append(spacer(0.1)) story.append(body( "<b>Efficacy:</b> Vaccines demonstrated efficacy in reducing COVID-19 morbidity and mortality " "in RCTs and real-world studies. Widespread vaccination produced a significant decline " "in incident cases and severe disease." )) story.append(h2("Vaccine Adverse Effects of Note")) ae_data = [ ["Adverse Effect", "Details"], ["Myocarditis / Pericarditis", "Predominantly young males; usually after 2nd mRNA dose; onset 3-5 days post-vaccination; " "~24 per million 2nd doses; typically mild and self-resolving. Presents with chest discomfort, " "ECG changes, and troponin elevation."], ["VITT (Vaccine-Induced Immune\nThrombocytopenia and Thrombosis)", "Rare; primarily with adenoviral vector vaccines (AstraZeneca, J&J). " "Arterial/venous thrombosis (cerebral sinus, splanchnic vessels) with thrombocytopenia."], ["Anaphylaxis", "Rare; related to vaccine components (PEG, polysorbate). Contraindication to same platform class."], ] story.append(make_table(ae_data, col_widths=[4.5*cm, 11.5*cm])) story.append(source("Braunwald's Heart Disease, pp. 1110-1111")) story.append(spacer(0.1)) story.append(note( "2025-2026 Update: The CDC recommended an updated COVID-19 vaccine for all individuals aged " "6 months and older for the 2025-2026 season, based on individual decision-making. " "FDA was reported as potentially not renewing Pfizer's EUA for the under-5 formulation." )) story.append(h2("C. Healthcare-Setting Prevention")) hc_bullets = [ "Standard, contact, and <b>droplet precautions</b> for all COVID-19 cases.", "<b>Airborne precautions</b> (N95 respirators) for aerosol-generating procedures (intubation, bronchoscopy, etc.).", "Regular hand hygiene before and after patient contact.", "Environmental disinfection of high-touch surfaces.", "Cohorting of confirmed/suspected cases.", "Special protection for immunocompromised, elderly, and high-comorbidity patients.", ] for b in hc_bullets: story.append(bullet(b)) story.append(spacer(0.2)) # ==== SECTION 7 ==== story.append(h1("7. Disease Severity Spectrum")) story.append(spacer(0.1)) sev_data = [ ["Stage", "Timing", "Key Features"], ["Asymptomatic", "Any time", "No symptoms; ~40-45% of all infections; significant transmission source"], ["Mild", "Days 1-10", "Fever, fatigue, dry cough, anosmia/ageusia, myalgia, diarrhea, ground-glass infiltrates on CXR"], ["Severe", "After day 10", "SpO\u2082 <94%, RR \u226530/min, lung infiltrates >50%, elevated troponin/BNP/CRP"], ["Critical", "After day 10", "ARDS, acute cardiac injury, multi-organ failure, SIRS/septic shock"], ] story.append(make_table(sev_data, col_widths=[3*cm, 3*cm, 10*cm])) story.append(source("Braunwald's Heart Disease, Fig. 94.3")) story.append(spacer(0.3)) # ==== SUMMARY BOX ==== story.append(hr(color="#1a3c5e", thickness=1.5)) story.append(spacer(0.1)) story.append(Paragraph("<b>Clinical Summary</b>", h2_style)) story.append(body( "COVID-19 remains an evolving global health challenge. SARS-CoV-2 spreads primarily via " "respiratory droplets and aerosols, with presymptomatic transmission making containment difficult. " "The highest-risk groups are elderly individuals and those with cardiometabolic comorbidities. " "Prevention rests on a layered approach: <b>vaccination</b> (the most effective single intervention), " "plus NPIs - masking, distancing, ventilation, and hand hygiene. " "Updated vaccines targeting circulating Omicron subvariants are available annually. " "Ongoing genomic surveillance continues to guide public health response as new variants emerge." )) story.append(spacer(0.15)) # Key Sources story.append(Paragraph("<b>Key Textbook Sources</b>", h2_style)) sources = [ "Harrison's Principles of Internal Medicine, 22nd Ed. (2025), SARS-CoV-2 / COVID-19 Chapter", "Braunwald's Heart Disease (2022), Chapter 94 - COVID-19 and the Cardiovascular System", "Fuster and Hurst's The Heart, 15th Ed., Chapter 84", "Murray & Nadel's Textbook of Respiratory Medicine, Chapter 46a", "Goldman-Cecil Medicine, Chapter 334 - Coronaviruses", ] for s in sources: story.append(source(f"• {s}")) story.append(spacer(0.4)) story.append(hr(color="#b0c4d8", thickness=0.5)) story.append(Paragraph( "Generated by Orris Medical Assistant | July 2026 | For educational purposes only", ParagraphStyle("Footer", parent=styles["Normal"], fontSize=7.5, textColor=colors.HexColor("#999999"), alignment=TA_CENTER) )) # ===================== BUILD ===================== doc.build(story) print(f"PDF created: {OUTPUT}") PYEOF python /tmp/workspace/covid19-pdf/generate.py
COVID19 Epidemiology Prevention
PDF Document · PDF
Natural History of Measles
"measles"[MeSH Terms] AND "natural history"
measles natural history stages clinical features complications 2024 2025



| Complication | Frequency / Notes |
|---|---|
| Otitis media | Most common complication; 5-9% of cases |
| Diarrhea / dehydration | 10-16% in US data; leading cause of death in developing countries |
| Pneumonia (secondary bacterial) | Most common life-threatening complication (<10% cases); Staphylococcus, Streptococcus, H. influenzae |
| Laryngotracheobronchitis (croup) | Significant in young children |
| Keratoconjunctivitis | Especially severe in Vitamin A deficiency - can lead to blindness |
| Thrombocytopenic purpura | ~10% in US hospitalized series |
| Syndrome | Timing | Frequency | Outcome |
|---|---|---|---|
| Acute measles encephalitis | During acute illness | 2-3 per 1000 cases | 5-10% of survivors have sensorineural hearing loss |
| Acute demyelinating encephalomyelitis (post-infectious) | Days after rash resolves | ~1 per 1000 cases | Fatal in 20%; >33% of survivors have permanent neurological sequelae (seizures, altered sensorium) |
| Measles Inclusion Body Encephalitis (MIBE) | 1-6 months post-infection | Rare; in immunosuppressed patients | Refractory focal seizures, rapid neurological decline; often fatal |
| Subacute Sclerosing Panencephalitis (SSPE) | 7-10 years after infection | 4-11 per 100,000 survivors (higher in early childhood infection) | Uniformly fatal progressive demyelinating disease |
| Parameter | Value |
|---|---|
| R₀ | 12-18 (highest of all known human pathogens) |
| Incubation period | 10-14 days (fever); 14 days (rash); up to 21 days |
| Infectious period | 4 days before rash to 4 days after rash onset |
| Portal of entry | Respiratory tract; conjunctiva |
| Peak age (developing countries) | 6 months - 3 years |
| Peak age (developed countries) | >5 years, adolescents, adults in outbreak settings |
| Deaths (2024, WHO) | ~95,000 globally, mostly unvaccinated children under 5 |
| Complication rate | ~30% of reported cases |
| Day (from exposure) | Event |
|---|---|
| Day 0 | Exposure; viral entry via respiratory tract |
| Days 1-7 | Silent replication in lymphoid tissue; primary viremia |
| Days 7-10 | Secondary viremia; reticuloendothelial seeding |
| Day 10 | Prodrome onset: fever, 3Cs, Koplik spots |
| Day 14 | Rash appears; antibodies detectable; viremia ends |
| Days 14-21 | Rash spreads cephalocaudally; peak fever and symptoms |
| Days 17-21 | Rash fades (same order); desquamation; fever resolves |
| Weeks-months | Post-measles immune amnesia; secondary infections |
| 7-10 years | SSPE (rare late complication) |
Create a PDF summary of measles natural history for quick reference
ls -la /tmp/workspace/ && mkdir -p /tmp/workspace/measles-pdf
~/measles-pdf/generate.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, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY, TA_RIGHT
import urllib.request, os
OUTPUT = "/tmp/workspace/measles-pdf/Measles_Natural_History_QuickRef.pdf"
# Download images
KOPLIK_URL = "https://cdn.orris.care/cdss_images/d40e8e94e3a17882761c6ba357529f662c3764f6008fbe5e22c31e57054ab668.png"
RASH_URL = "https://cdn.orris.care/cdss_images/8abf15ce7338a465df172b7280b13475f3676b2f1190dfb161742f497ff7fa9a.png"
TIMELINE_URL= "https://cdn.orris.care/cdss_images/8831592f9403ae2fb258fd30c258713c1884d354f415e2cb8716d68dbec4325c.png"
IMG_DIR = "/tmp/workspace/measles-pdf/"
koplik_path = IMG_DIR + "koplik.png"
rash_path = IMG_DIR + "rash.png"
timeline_path= IMG_DIR + "timeline.png"
for url, path in [(KOPLIK_URL, koplik_path), (RASH_URL, rash_path), (TIMELINE_URL, timeline_path)]:
if not os.path.exists(path):
urllib.request.urlretrieve(url, path)
print(f"Downloaded {path}")
from reportlab.platypus import Image as RLImage
W, H = A4
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
leftMargin=1.8*cm, rightMargin=1.8*cm,
topMargin=2*cm, bottomMargin=2*cm,
title="Natural History of Measles – Quick Reference",
author="Orris Medical Assistant",
)
styles = getSampleStyleSheet()
# ── Palette ──────────────────────────────────────────────────
RED = colors.HexColor("#c0392b")
DARKRED = colors.HexColor("#922b21")
AMBER = colors.HexColor("#e67e22")
GREEN = colors.HexColor("#1e8449")
NAVY = colors.HexColor("#1a3c5e")
STEEL = colors.HexColor("#2e86c1")
LTBLUE = colors.HexColor("#d6eaf8")
LTRED = colors.HexColor("#fadbd8")
LTAMBER = colors.HexColor("#fef9e7")
LTGREEN = colors.HexColor("#d5f5e3")
GREY = colors.HexColor("#f2f3f4")
DGREY = colors.HexColor("#566573")
# ── Styles ────────────────────────────────────────────────────
def make_style(name, **kw):
base = kw.pop("parent", styles["Normal"])
s = ParagraphStyle(name, parent=base, **kw)
return s
TITLE = make_style("TITLE",
fontSize=22, fontName="Helvetica-Bold",
textColor=colors.white, alignment=TA_CENTER,
spaceAfter=2, leading=26)
SUBTITLE = make_style("SUBTITLE",
fontSize=10.5, fontName="Helvetica-Oblique",
textColor=colors.HexColor("#d0dce8"), alignment=TA_CENTER, spaceAfter=2)
SEC = make_style("SEC",
fontSize=11, fontName="Helvetica-Bold",
textColor=colors.white, spaceAfter=0,
leftIndent=4, borderPad=4)
H2 = make_style("H2",
fontSize=10, fontName="Helvetica-Bold",
textColor=NAVY, spaceBefore=6, spaceAfter=3)
BODY = make_style("BODY",
fontSize=8.8, fontName="Helvetica",
leading=12.5, spaceAfter=4, alignment=TA_JUSTIFY)
BULLET = make_style("BULLET",
fontSize=8.8, fontName="Helvetica",
leading=12, spaceAfter=2, leftIndent=12)
SMALL = make_style("SMALL",
fontSize=7.5, fontName="Helvetica-Oblique",
textColor=DGREY, spaceAfter=2)
CAPTION = make_style("CAPTION",
fontSize=7.8, fontName="Helvetica-Oblique",
textColor=DGREY, alignment=TA_CENTER, spaceAfter=4)
WARN = make_style("WARN",
fontSize=8.5, fontName="Helvetica-Bold",
textColor=RED, spaceAfter=2)
FOOT = make_style("FOOT",
fontSize=7, fontName="Helvetica",
textColor=colors.HexColor("#aaaaaa"), alignment=TA_CENTER)
# ── Helpers ───────────────────────────────────────────────────
def sp(h=0.2): return Spacer(1, h*cm)
def hr(c=NAVY, t=0.8): return HRFlowable(width="100%", thickness=t, color=c)
def section_header(text, bg=NAVY):
tbl = Table([[Paragraph(f"<b> {text}</b>", SEC)]], colWidths=[W - 3.6*cm])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING",(0,0), (-1,-1), 6),
]))
return tbl
def colored_cell(text, bg, fg=colors.black, bold=False, size=8.5):
fn = "Helvetica-Bold" if bold else "Helvetica"
s = make_style(f"cc_{text[:10]}_{id(text)}", fontSize=size,
fontName=fn, textColor=fg, leading=11,
alignment=TA_CENTER)
return Paragraph(text, s)
def make_table(data, col_widths, header_bg=NAVY, alt=LTBLUE):
t = Table(data, colWidths=col_widths, repeatRows=1)
style = [
("BACKGROUND", (0,0), (-1,0), header_bg),
("TEXTCOLOR", (0,0), (-1,0), colors.white),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,0), 8.5),
("ALIGN", (0,0), (-1,0), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("FONTNAME", (0,1), (-1,-1), "Helvetica"),
("FONTSIZE", (0,1), (-1,-1), 8),
("ROWBACKGROUNDS",(0,1), (-1,-1), [colors.white, alt]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#ccd6df")),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
]
t.setStyle(TableStyle(style))
return t
# ── Title Banner ──────────────────────────────────────────────
def title_banner():
inner = Table(
[[Paragraph("Natural History of Measles", TITLE)],
[Paragraph("Quick Reference Summary | Rubeola (Morbilli)", SUBTITLE)]],
colWidths=[W - 3.6*cm]
)
inner.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), NAVY),
("TOPPADDING", (0,0), (-1,-1), 12),
("BOTTOMPADDING",(0,0),(-1,-1), 10),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING",(0,0), (-1,-1), 10),
]))
return inner
# ── TIMELINE graphic (hand-drawn with ReportLab drawing) ──────
from reportlab.platypus import Flowable
from reportlab.lib.colors import HexColor
class MeaslesTimeline(Flowable):
"""A hand-drawn timeline bar showing the stages of measles."""
W = 16.5*cm
H = 3.6*cm
def wrap(self, *args):
return self.W, self.H
def draw(self):
c = self.canv
w, h = self.W, self.H
stages = [
# (label, day_start, day_end, color, text_color)
("Incubation\n(Days 0–10)", 0, 10, HexColor("#aed6f1"), colors.black),
("Prodrome\n(Days 10–14)", 10, 14, HexColor("#f9e79f"), colors.black),
("Eruptive / Rash\n(Days 14–21)", 14, 21, HexColor("#f1948a"), colors.black),
("Convalescence\n(Days 21+)", 21, 28, HexColor("#a9dfbf"), colors.black),
]
total_days = 28
bar_y = 1.3*cm
bar_h = 1.0*cm
x_start = 0.5*cm
x_end = w - 0.3*cm
x_span = x_end - x_start
def day_to_x(d): return x_start + (d / total_days) * x_span
# Draw segments
for label, d0, d1, col, tc in stages:
x0 = day_to_x(d0)
x1 = day_to_x(d1)
c.setFillColor(col)
c.setStrokeColor(colors.white)
c.setLineWidth(1)
c.rect(x0, bar_y, x1-x0, bar_h, fill=1, stroke=1)
# Label inside bar
cx = (x0+x1)/2
cy = bar_y + bar_h/2
c.setFillColor(tc)
c.setFont("Helvetica-Bold", 6.5)
lines = label.split("\n")
for i, ln in enumerate(lines):
c.drawCentredString(cx, cy + (0.5-i)*0.35*cm, ln)
# Infectivity bar
inf_y = bar_y + bar_h + 0.12*cm
inf_x0 = day_to_x(10) # 4 days before rash ≈ day 10
inf_x1 = day_to_x(18) # 4 days after rash ≈ day 18
c.setFillColor(HexColor("#e74c3c"))
c.setStrokeColor(HexColor("#c0392b"))
c.rect(inf_x0, inf_y, inf_x1-inf_x0, 0.22*cm, fill=1, stroke=1)
c.setFillColor(HexColor("#c0392b"))
c.setFont("Helvetica-Bold", 6)
c.drawString(inf_x0, inf_y + 0.26*cm, "◄ Infectious (4d pre-rash → 4d post-rash) ►")
# Day axis
c.setStrokeColor(HexColor("#555555"))
c.setLineWidth(0.5)
axis_y = bar_y - 0.05*cm
c.line(x_start, axis_y, x_end, axis_y)
for d in [0, 7, 10, 14, 21, 28]:
x = day_to_x(d)
c.setStrokeColor(HexColor("#555555"))
c.line(x, axis_y, x, axis_y - 0.15*cm)
c.setFillColor(colors.black)
c.setFont("Helvetica", 6.5)
c.drawCentredString(x, axis_y - 0.35*cm, f"D{d}")
# Key events labels
c.setFillColor(HexColor("#6d3b00"))
c.setFont("Helvetica-Bold", 6.3)
c.drawCentredString(day_to_x(12.5), bar_y - 0.65*cm, "Koplik spots")
c.setFillColor(HexColor("#922b21"))
c.drawCentredString(day_to_x(14), bar_y - 0.9*cm, "▲ Rash onset + Ab appear")
c.setFillColor(HexColor("#1a5276"))
c.drawCentredString(day_to_x(0), bar_y - 0.9*cm, "Exposure")
# ────────────────────────────────────────────────────────────────
# BUILD STORY
# ────────────────────────────────────────────────────────────────
story = []
# ── TITLE ─────────────────────────────────────────────────────
story.append(title_banner())
story.append(sp(0.3))
# ── QUICK FACTS row ──────────────────────────────────────────
qf_style = make_style("QF", fontSize=8, fontName="Helvetica",
leading=11, alignment=TA_CENTER, textColor=colors.black)
qf_bold = make_style("QFB", fontSize=9.5, fontName="Helvetica-Bold",
leading=13, alignment=TA_CENTER, textColor=NAVY)
qf_data = [
[colored_cell("PATHOGEN", NAVY, colors.white, True, 7.5),
colored_cell("R₀", NAVY, colors.white, True, 7.5),
colored_cell("INCUBATION", NAVY, colors.white, True, 7.5),
colored_cell("INFECTIOUS", NAVY, colors.white, True, 7.5),
colored_cell("RESERVOIR", NAVY, colors.white, True, 7.5),
colored_cell("CFR", NAVY, colors.white, True, 7.5)],
[Paragraph("Measles virus\n(Paramyxoviridae\nMorbillivirus)", qf_style),
Paragraph("<b>12 – 18</b>", qf_bold),
Paragraph("<b>10–14 days</b>\n(up to 21d)", qf_style),
Paragraph("<b>4d pre-rash</b>\nto 4d post-rash", qf_style),
Paragraph("Humans only\n(no animal reservoir)", qf_style),
Paragraph("<b>0.1–0.2%</b>\n(developed)\n<b>1–5%+</b> (LMICs)", qf_style)],
]
qf_tbl = Table(qf_data, colWidths=[2.8*cm]*6)
qf_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("GRID", (0,0), (-1,-1), 0.5, colors.HexColor("#b0c4d8")),
("ROWBACKGROUNDS",(0,1),(-1,1), [LTBLUE]),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0), (-1,-1), 5),
]))
story.append(qf_tbl)
story.append(sp(0.35))
# ── TIMELINE ─────────────────────────────────────────────────
story.append(KeepTogether([
section_header("DISEASE TIMELINE", NAVY),
sp(0.15),
MeaslesTimeline(),
sp(0.05),
Paragraph("Day 0 = Exposure. D10 = Prodrome onset. D14 = Rash onset (antibodies detectable, viremia ceases). D21+ = Convalescence.", SMALL),
sp(0.2),
]))
# ── 3 STAGES in a 3-col table ────────────────────────────────
s_style_head = make_style("SH", fontSize=9.5, fontName="Helvetica-Bold",
textColor=colors.white, alignment=TA_CENTER, leading=12)
s_style_body = make_style("SB", fontSize=8.2, fontName="Helvetica",
leading=11.5, alignment=TA_LEFT)
def stage_cell(title, bg, items):
head = Paragraph(title, s_style_head)
body_items = [Paragraph(f"• {i}", s_style_body) for i in items]
return [head] + body_items
prod_items = [
"Onset: Day 10 post-exposure",
"High fever (39–40.5°C)",
"Cough (brassy/croupy)",
"Coryza (sneezing, nasal discharge)",
"Conjunctivitis + photophobia",
"Koplik spots (pathognomonic):\n bluish-white ulcers on buccal\n mucosa opp. lower molars",
"Lymphopenia on FBC",
"Vomiting / diarrhoea possible",
"Duration: ~4 days",
]
erupt_items = [
"Onset: Day 14 (rash appears)",
"Starts: hairline / behind ears",
"Spreads: face → trunk →\n extremities (2–3 days)",
"Lesions: discrete erythematous\n maculopapules → coalesce",
"Confluent on face, discrete\n distally",
"Brownish discoloration on\n fading; fine desquamation",
"Rash resolves in 6–7 days",
"Fever resolves 1–2d after rash",
"Entire body involved by Day 3",
]
conv_items = [
"Weight loss, debility, weakness",
"Immune amnesia: destruction\n of memory lymphocytes",
"↑ Susceptibility to secondary\n bacterial/viral infections",
"Risk: cancrum oris, TB\n reactivation, candidiasis",
"Growth retardation (children)",
"Pyogenic skin infections",
"Duration: weeks to months",
"SSPE: 7–10 years post-measles\n (rare; 4–11/100,000 survivors)",
]
col1 = stage_cell("1. PRODROMAL STAGE\n(Days 10–14)", AMBER, prod_items)
col2 = stage_cell("2. ERUPTIVE STAGE\n(Days 14–21)", RED, erupt_items)
col3 = stage_cell("3. POST-MEASLES\n(Day 21+)", GREEN, conv_items)
max_rows = max(len(col1), len(col2), len(col3))
for col in [col1, col2, col3]:
while len(col) < max_rows:
col.append(Paragraph("", s_style_body))
stage_data = [[col1[i], col2[i], col3[i]] for i in range(max_rows)]
stage_tbl = Table(stage_data, colWidths=[5.4*cm, 5.4*cm, 5.4*cm])
stage_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), AMBER),
("BACKGROUND", (1,0), (1,0), RED),
("BACKGROUND", (2,0), (2,0), GREEN),
("VALIGN", (0,0), (-1,-1), "TOP"),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#cccccc")),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("ROWBACKGROUNDS",(0,1), (-1,-1), [colors.white, GREY]),
]))
story.append(KeepTogether([
section_header("THREE STAGES OF NATURAL HISTORY", DARKRED),
sp(0.15),
stage_tbl,
sp(0.2),
]))
# ── PATHOGENESIS STEPS ───────────────────────────────────────
path_items = [
("1. Entry", "Virus enters via respiratory tract (nasopharyngeal epithelium) or conjunctiva."),
("2. Local replication", "Multiplies in respiratory mucosa; spreads to regional lymphoid tissue (tonsils, lymph nodes)."),
("3. Primary viremia", "Virus disseminates hematogenously to the reticuloendothelial system (liver, spleen)."),
("4. Secondary viremia", "Seeds all epithelial surfaces: skin, respiratory tract, conjunctiva, GI mucosa."),
("5. Rash mechanism", "CD8+ T cells attack virus-infected endothelial cells in small vessels → maculopapular rash. No rash in immunocompromised (no T-cell response)."),
("6. Immune activation", "IgM detectable at rash onset. IgG rises steadily → lifelong immunity. Viremia ceases; fever falls."),
]
path_data = [[Paragraph(f"<b>{s}</b>", make_style(f"ph{i}", fontSize=8.2, fontName="Helvetica-Bold", textColor=NAVY, leading=11)),
Paragraph(d, BODY)] for i,(s,d) in enumerate(path_items)]
path_tbl = Table(path_data, colWidths=[3.5*cm, 13*cm])
path_tbl.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "TOP"),
("GRID", (0,0), (-1,-1), 0.3, colors.HexColor("#dde4ea")),
("ROWBACKGROUNDS",(0,0),(-1,-1), [LTBLUE, colors.white]),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 5),
]))
story.append(KeepTogether([
section_header("PATHOGENESIS SEQUENCE", STEEL),
sp(0.15),
path_tbl,
sp(0.2),
]))
# ── COMPLICATIONS TABLE ───────────────────────────────────────
comp_data = [
[Paragraph("<b>Complication</b>", make_style("ch1", fontSize=8.5, fontName="Helvetica-Bold", textColor=colors.white, alignment=TA_CENTER)),
Paragraph("<b>Frequency</b>", make_style("ch2", fontSize=8.5, fontName="Helvetica-Bold", textColor=colors.white, alignment=TA_CENTER)),
Paragraph("<b>Notes</b>", make_style("ch3", fontSize=8.5, fontName="Helvetica-Bold", textColor=colors.white, alignment=TA_CENTER))],
[Paragraph("Otitis media", BODY), Paragraph("5–9% of cases", BODY), Paragraph("Most common complication overall", BODY)],
[Paragraph("Diarrhoea / Dehydration", BODY), Paragraph("10–16%", BODY), Paragraph("Leading cause of death in LMICs", BODY)],
[Paragraph("Bacterial pneumonia", BODY), Paragraph("<10%", BODY), Paragraph("Most common life-threatening complication", BODY)],
[Paragraph("Keratoconjunctivitis", BODY), Paragraph("Variable", BODY), Paragraph("Severe with Vitamin A deficiency; can cause blindness", BODY)],
[Paragraph("Thrombocytopenic purpura", BODY), Paragraph("~10% (hospitalised)", BODY), Paragraph("Petechiae/purpura; DIC-like 'black measles' – rare", BODY)],
[Paragraph("Acute encephalitis", BODY), Paragraph("2–3 per 1000", BODY), Paragraph("During acute illness; 5–10% survivors: sensorineural deafness", BODY)],
[Paragraph("Demyelinating encephalomyelitis\n(post-infectious)", BODY), Paragraph("~1 per 1000", BODY), Paragraph("Days after resolution; fatal 20%; >33% survivors: permanent neuro deficits", BODY)],
[Paragraph("Measles Inclusion Body\nEncephalitis (MIBE)", BODY), Paragraph("Rare", BODY), Paragraph("Immunosuppressed; 1–6 months post-infection; refractory seizures; often fatal", BODY)],
[Paragraph("<b>SSPE</b>\n(Subacute Sclerosing\nPanencephalitis)", make_style("sspe", fontSize=8.2, fontName="Helvetica-Bold", textColor=DARKRED, leading=11)),
Paragraph("4–11 per\n100,000 survivors", BODY),
Paragraph("7–10 yrs post-measles. Progressive: behaviour change → motor loss → visual loss → vegetative state → death. UNIFORMLY FATAL.", BODY)],
]
comp_tbl = Table(comp_data, colWidths=[4.5*cm, 3.3*cm, 8.8*cm])
comp_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARKRED),
("ROWBACKGROUNDS",(0,1), (-1,-1), [colors.white, LTRED]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#e8c6c4")),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
]))
story.append(KeepTogether([
section_header("COMPLICATIONS", DARKRED),
sp(0.15),
comp_tbl,
sp(0.2),
]))
# ── TWO-COLUMN SECTION: Risk Factors | Immunity ───────────────
rf_items = [
("Age <5 years", "Highest mortality risk"),
("Malnutrition", "Up to 400× higher mortality"),
("Vitamin A deficiency", "Depresses cell-mediated immunity; blindness risk"),
("Immunocompromise\n(HIV, transplant)", "No rash; no natural immunity; MIBE risk"),
("Overcrowding", "Facilitates droplet spread"),
("Unvaccinated status", "Primary risk factor for infection"),
("Pregnancy", "Fetal death; preterm labour"),
]
imm_items = [
("Post-infection", "Lifelong immunity; 2nd attacks rare"),
("Maternal antibodies", "Protect infants up to 6–9 months"),
("Vaccine-induced", "Solid, long-lasting; two-dose series"),
("Immune amnesia", "Measles destroys memory B + T cells → weeks–months of secondary immunosuppression"),
("Modified measles", "Partial immunity → milder disease, no Koplik spots, prolonged incubation"),
("No animal reservoir", "Eradication theoretically possible"),
]
rf_style = make_style("RFS", fontSize=8, fontName="Helvetica", leading=11)
rf_b_style= make_style("RFB", fontSize=8, fontName="Helvetica-Bold", textColor=DARKRED, leading=11)
im_b_style= make_style("IMB", fontSize=8, fontName="Helvetica-Bold", textColor=GREEN, leading=11)
rf_tbl_data = [[Paragraph(f"<b>{k}</b>", rf_b_style), Paragraph(v, rf_style)] for k,v in rf_items]
rf_tbl = Table(rf_tbl_data, colWidths=[3.4*cm, 4.5*cm])
rf_tbl.setStyle(TableStyle([
("GRID", (0,0), (-1,-1), 0.3, colors.HexColor("#f0c0bc")),
("ROWBACKGROUNDS",(0,0),(-1,-1), [LTRED, colors.white]),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 3), ("BOTTOMPADDING",(0,0),(-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 4),
]))
im_tbl_data = [[Paragraph(f"<b>{k}</b>", im_b_style), Paragraph(v, rf_style)] for k,v in imm_items]
im_tbl = Table(im_tbl_data, colWidths=[3.4*cm, 4.5*cm])
im_tbl.setStyle(TableStyle([
("GRID", (0,0), (-1,-1), 0.3, colors.HexColor("#b2dfcc")),
("ROWBACKGROUNDS",(0,0),(-1,-1), [LTGREEN, colors.white]),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 3), ("BOTTOMPADDING",(0,0),(-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 4),
]))
sec_rf = section_header("RISK FACTORS FOR SEVERE DISEASE", DARKRED)
sec_imm = section_header("IMMUNITY", GREEN)
two_col = Table([
[sec_rf, sec_imm],
[rf_tbl, im_tbl],
], colWidths=[8*cm, 8*cm])
two_col.setStyle(TableStyle([
("LEFTPADDING", (0,0), (-1,-1), 0),
("RIGHTPADDING", (0,0), (-1,-1), 0),
("TOPPADDING", (0,0), (-1,-1), 0),
("BOTTOMPADDING",(0,0), (-1,-1), 3),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(two_col)
story.append(sp(0.2))
# ── CLINICAL PHOTOS ───────────────────────────────────────────
img_koplik = RLImage(koplik_path, width=5.2*cm, height=3.8*cm)
img_rash = RLImage(rash_path, width=10.2*cm, height=3.8*cm)
photo_tbl = Table(
[[img_koplik, img_rash]],
colWidths=[5.4*cm, 10.8*cm]
)
photo_tbl.setStyle(TableStyle([
("ALIGN", (0,0), (-1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1), 2),
("GRID", (0,0), (-1,-1), 0.3, colors.HexColor("#cccccc")),
]))
cap_koplik = Paragraph("Koplik spots on buccal mucosa\n(pathognomonic – appear 1–2d before rash)", CAPTION)
cap_rash = Paragraph("Measles rash: A – Classic erythematous on fair skin | B – Difficult to see on dark skin | C – Desquamating rash in malnutrition", CAPTION)
cap_tbl = Table([[cap_koplik, cap_rash]], colWidths=[5.4*cm, 10.8*cm])
cap_tbl.setStyle(TableStyle([("TOPPADDING",(0,0),(-1,-1),2),("BOTTOMPADDING",(0,0),(-1,-1),0),
("LEFTPADDING",(0,0),(-1,-1),2)]))
story.append(KeepTogether([
section_header("CLINICAL PHOTOS", DGREY),
sp(0.15),
photo_tbl,
cap_tbl,
sp(0.2),
]))
# ── IMMUNE TIMELINE GRAPH ─────────────────────────────────────
img_timeline = RLImage(timeline_path, width=9.5*cm, height=7.5*cm)
# Diagnostic criteria alongside
diag_items = [
("Clinical diagnosis",
"Fever + rash + ≥1 of: cough, coryza, conjunctivitis. Koplik spots pathognomonic but may be absent in modified measles."),
("Serological",
"Measles-specific IgM (ELISA) — detectable at rash onset. Diagnostic if positive ≥3 days after rash."),
("Molecular",
"RT-PCR for measles RNA in throat swabs, oral fluid, nasopharyngeal mucus, or urine. Gold standard for genotyping."),
("Differential",
"Rubella, scarlet fever, roseola, enterovirus, drug eruption, Kawasaki disease, MIS-C (COVID-19 associated)."),
("Note (immunocompromised)",
"Rash may be absent. IgM may be negative. Use RT-PCR for diagnosis."),
]
diag_style = make_style("DS", fontSize=8, fontName="Helvetica", leading=11)
diag_bold = make_style("DB", fontSize=8, fontName="Helvetica-Bold", textColor=STEEL, leading=11)
diag_data = [[Paragraph(f"<b>{k}</b>", diag_bold), Paragraph(v, diag_style)] for k,v in diag_items]
diag_tbl = Table(diag_data, colWidths=[3.2*cm, 4.2*cm])
diag_tbl.setStyle(TableStyle([
("GRID", (0,0), (-1,-1), 0.3, colors.HexColor("#c5d9e8")),
("ROWBACKGROUNDS",(0,0),(-1,-1), [LTBLUE, colors.white]),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 3), ("BOTTOMPADDING",(0,0),(-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 4),
]))
sec_tl = section_header("IMMUNE RESPONSE TIMELINE (Jawetz Microbiology)", STEEL)
sec_diag = section_header("DIAGNOSIS", STEEL)
tl_diag_tbl = Table(
[[sec_tl, sec_diag],
[img_timeline, diag_tbl]],
colWidths=[9.7*cm, 6.7*cm]
)
tl_diag_tbl.setStyle(TableStyle([
("LEFTPADDING", (0,0), (-1,-1), 0),
("RIGHTPADDING", (0,0), (-1,-1), 3),
("TOPPADDING", (0,0), (-1,-1), 0),
("BOTTOMPADDING",(0,0), (-1,-1), 3),
("VALIGN", (0,0), (-1,-1), "TOP"),
("ALIGN", (0,1), (0,1), "CENTER"),
]))
story.append(tl_diag_tbl)
story.append(sp(0.2))
# ── KEY NUMBERS BOX ──────────────────────────────────────────
kn_s = make_style("KN", fontSize=8.2, fontName="Helvetica", leading=12, alignment=TA_CENTER)
kn_b = make_style("KNB", fontSize=12, fontName="Helvetica-Bold", textColor=NAVY, leading=14, alignment=TA_CENTER)
kn_data = [
[colored_cell("~30%", LTRED, DARKRED, True, 14),
colored_cell("1/1000", colors.HexColor("#fdebd0"), AMBER, True, 14),
colored_cell("1/300,000", LTBLUE, STEEL, True, 11),
colored_cell("400×", LTGREEN, GREEN, True, 14),
colored_cell("95,000", LTRED, DARKRED, True, 13)],
[Paragraph("cases have\ncomplications", kn_s),
Paragraph("cases develop\nencephalitis", kn_s),
Paragraph("cases develop\nSSPE", kn_s),
Paragraph("higher mortality\nin malnourished", kn_s),
Paragraph("global deaths\nin 2024 (WHO)", kn_s)],
]
kn_tbl = Table(kn_data, colWidths=[3.26*cm]*5)
kn_tbl.setStyle(TableStyle([
("GRID", (0,0), (-1,-1), 0.5, colors.HexColor("#b0c4d8")),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING",(0,0),(-1,-1), 4),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(KeepTogether([
section_header("KEY NUMBERS AT A GLANCE", NAVY),
sp(0.15),
kn_tbl,
sp(0.25),
]))
# ── FOOTER ────────────────────────────────────────────────────
story.append(hr(colors.HexColor("#b0c4d8"), 0.5))
story.append(sp(0.1))
story.append(Paragraph(
"Sources: Goldman-Cecil Medicine Ch.338 · Park's Preventive & Social Medicine · "
"Jawetz, Melnick & Adelberg's Medical Microbiology 28E · Andrews' Diseases of the Skin · "
"Bradley & Daroff's Neurology · Harrison's Principles 22E (2025) | "
"Generated by Orris Medical Assistant · July 2026 | For educational purposes only",
FOOT
))
doc.build(story)
print(f"PDF saved: {OUTPUT}")
cd /tmp/workspace/measles-pdf && python generate.py 2>&1
Measles Natural History QuickRef
PDF Document · PDF