Why mannitol is contraindicated in acute pulmonary edema
"Mannitol is rapidly distributed in the extracellular compartment and extracts water from cells. Prior to the diuresis, this leads to expansion of the extracellular volume... This effect can complicate heart failure and may produce florid pulmonary edema."
- Katzung's Basic and Clinical Pharmacology, 16th Ed.
"Because mannitol expands the ECFV [extracellular fluid volume] en route to its diuretic site of action, it may precipitate pulmonary edema in HF patients and must be used cautiously in this circumstance, if at all."
- NKF Primer on Kidney Diseases, 8th Ed.
| Step | What Happens | Effect |
|---|---|---|
| 1. Mannitol given IV | Stays in extracellular compartment (not reabsorbed) | Raises plasma osmolality |
| 2. Osmotic gradient created | Water shifts from intracellular to extracellular space | Acutely expands intravascular volume |
| 3. Increased hydrostatic pressure | Fluid is pushed into pulmonary capillaries | Worsens pulmonary edema |
| 4. Diuresis (delayed) | Eventually excreted via kidneys, with water | Comes too late if cardiac/renal reserve is limited |
"A rapid intracellular-to-extracellular shift of water can transiently increase intravascular volume and precipitate cardiac decompensation and pulmonary edema in patients with limited cardiac reserve."
- Morgan & Mikhail's Clinical Anesthesiology, 7th Ed.
Can you simplify asthma from fishman and gina 2026
GINA 2026 asthma guidelines key updates summary
https://www.pulmonologyadvisor.com/features/asthma-gina-2026…
Asthma is a heterogeneous disease, usually characterized by chronic airway inflammation. It is defined by a history of respiratory symptoms - wheeze, shortness of breath, chest tightness, and cough - that vary over time and in intensity, together with variable expiratory airflow limitation.

| Pathway | Driver | Key Cells | Result |
|---|---|---|---|
| T2 (Type 2) - 65-80% of patients | Allergens, alarmins | Th2, ILC2, eosinophils, mast cells | Eosinophilic inflammation, IgE production |
| Non-T2 | Smoke, pollutants, infections | Th1, Th17 cells | Neutrophilic inflammation |
| Phenotype | Features | Treatment Implication |
|---|---|---|
| Allergic asthma | Childhood onset, family/personal atopy, responds to ICS | Most common |
| Non-allergic asthma | No atopy, neutrophilic/paucigranulocytic | Less ICS-responsive |
| Late-onset eosinophilic | Adult women, high blood eosinophils | Biologic-responsive |
| Exercise-induced | Triggered by exertion | Pre-treatment with SABA |
| Aspirin/NSAID-sensitive | Nasal polyps, chronic sinusitis | Avoid NSAIDs |
| Obesity-associated | Non-eosinophilic, mechanically driven | Weight loss helps |
| Level | Daytime symptoms | Night waking | Reliever use | Activity limitation |
|---|---|---|---|---|
| Controlled | ≤2x/week | None | ≤2x/week | None |
| Partly controlled | >2x/week | Any | >2x/week | Any |
| Uncontrolled | 3+ features of partly controlled |
| Step | Preferred Controller | Preferred Reliever | Notes |
|---|---|---|---|
| Step 1 (mild intermittent) | Low-dose ICS-formoterol as needed | ICS-formoterol (not just SABA alone) | GINA 2026 pushes anti-inflammatory even at Step 1 |
| Step 2 (mild persistent) | Low-dose ICS daily | ICS-formoterol or SABA | LTRA as alternative |
| Step 3 (moderate) | Low-dose ICS-LABA | ICS-formoterol | SMART strategy begins here |
| Step 4 (uncontrolled on Step 3) | Medium-dose ICS-LABA | ICS-formoterol | Add LAMA (tiotropium) |
| Step 5 (severe) | High-dose ICS-LABA + specialist review | ICS-formoterol | Add biologics; minimize OCS |
| Drug | Target | For |
|---|---|---|
| Omalizumab | IgE | Allergic asthma |
| Mepolizumab, Reslizumab | IL-5 | Eosinophilic asthma |
| Benralizumab | IL-5 receptor | Eosinophilic asthma |
| Dupilumab | IL-4Rα (blocks IL-4 and IL-13) | Eosinophilic / type 2 |
| Tezepelumab | TSLP | Broad (all phenotypes) |
| Depemokimab (new 2026) | IL-5 (ultra-long acting) | Eosinophilic asthma |
| Severity | SpO2 | RR | Speech | Wheeze |
|---|---|---|---|---|
| Mild | ≥94% | Normal/mild increase | Full sentences | Mild |
| Moderate | 90-93% | Increased | Phrases | Moderate |
| Severe/Life-threatening | <92% | >30/min | Words or unable | Silent chest |
Create a PDF cheat sheet of GINA 2026 asthma stepwise treatment
ls /home/daytona/workspace/ 2>/dev/null && echo "---" && python3 -c "import repo…
mkdir -p /home/daytona/workspace/gina2026-cheatsheet
~/gina2026-cheatsheet/generate_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether
)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.platypus import BaseDocTemplate, Frame, PageTemplate
OUTPUT = "/home/daytona/workspace/gina2026-cheatsheet/GINA_2026_Asthma_Stepwise_Cheatsheet.pdf"
# ── Colour palette ──────────────────────────────────────────────────────────
BLUE_DARK = colors.HexColor("#1a3a5c")
BLUE_MID = colors.HexColor("#2563a8")
BLUE_LIGHT = colors.HexColor("#dbeafe")
TEAL = colors.HexColor("#0d9488")
TEAL_LIGHT = colors.HexColor("#ccfbf1")
ORANGE = colors.HexColor("#d97706")
ORANGE_LIGHT= colors.HexColor("#fef3c7")
RED = colors.HexColor("#dc2626")
RED_LIGHT = colors.HexColor("#fee2e2")
GREEN = colors.HexColor("#16a34a")
GREEN_LIGHT = colors.HexColor("#dcfce7")
PURPLE = colors.HexColor("#7c3aed")
PURPLE_LIGHT= colors.HexColor("#ede9fe")
GREY_LIGHT = colors.HexColor("#f1f5f9")
GREY_MED = colors.HexColor("#94a3b8")
WHITE = colors.white
BLACK = colors.HexColor("#0f172a")
W, H = A4 # 595.27 x 841.89 pt
# ── Styles ──────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
def S(name, **kw):
return ParagraphStyle(name, **kw)
title_style = S("Title2",
fontName="Helvetica-Bold", fontSize=18, textColor=WHITE,
alignment=TA_CENTER, leading=22)
subtitle_style = S("Sub2",
fontName="Helvetica", fontSize=9, textColor=colors.HexColor("#bfdbfe"),
alignment=TA_CENTER, leading=12)
section_header = S("SecHdr",
fontName="Helvetica-Bold", fontSize=10, textColor=WHITE,
alignment=TA_CENTER, leading=13, spaceAfter=2)
body = S("Body2",
fontName="Helvetica", fontSize=8, textColor=BLACK,
leading=11, spaceAfter=1)
body_bold = S("BodyB",
fontName="Helvetica-Bold", fontSize=8, textColor=BLACK,
leading=11, spaceAfter=1)
small = S("Small",
fontName="Helvetica", fontSize=7, textColor=colors.HexColor("#475569"),
leading=10, spaceAfter=1)
small_bold = S("SmallB",
fontName="Helvetica-Bold", fontSize=7.5, textColor=BLACK,
leading=10)
step_label = S("StepLbl",
fontName="Helvetica-Bold", fontSize=9, textColor=WHITE,
alignment=TA_CENTER, leading=12)
cell_body = S("CellB",
fontName="Helvetica", fontSize=7.5, textColor=BLACK, leading=10)
cell_bold = S("CellBold",
fontName="Helvetica-Bold", fontSize=7.5, textColor=BLACK, leading=10)
cell_small = S("CellSm",
fontName="Helvetica", fontSize=7, textColor=colors.HexColor("#334155"), leading=9)
note_style = S("Note",
fontName="Helvetica-Oblique", fontSize=7.5, textColor=colors.HexColor("#475569"),
leading=10)
warn_style = S("Warn",
fontName="Helvetica-Bold", fontSize=7.5, textColor=RED,
leading=10)
green_style = S("Grn",
fontName="Helvetica-Bold", fontSize=7.5, textColor=GREEN,
leading=10)
# ── Helpers ─────────────────────────────────────────────────────────────────
def colored_header(text, bg, fg=WHITE, height=16):
"""Single-cell table used as a coloured section header bar."""
t = Table([[Paragraph(text, S("h_"+text[:6],
fontName="Helvetica-Bold", fontSize=9.5, textColor=fg,
alignment=TA_CENTER, leading=12))]],
colWidths=[W - 28*mm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("ROUNDEDCORNERS", [4]),
]))
return t
def page_bg(canvas, doc):
"""Draw header banner and footer on every page."""
canvas.saveState()
# header band
canvas.setFillColor(BLUE_DARK)
canvas.rect(0, H - 38*mm, W, 38*mm, fill=1, stroke=0)
# thin accent line under header
canvas.setFillColor(TEAL)
canvas.rect(0, H - 38.8*mm, W, 1.5, fill=1, stroke=0)
# title
canvas.setFillColor(WHITE)
canvas.setFont("Helvetica-Bold", 20)
canvas.drawCentredString(W/2, H - 16*mm, "GINA 2026 — Asthma Stepwise Treatment")
canvas.setFont("Helvetica", 9)
canvas.setFillColor(colors.HexColor("#93c5fd"))
canvas.drawCentredString(W/2, H - 24*mm,
"Global Initiative for Asthma · 2026 Strategy Report · Quick Reference")
canvas.setFont("Helvetica", 8)
canvas.setFillColor(colors.HexColor("#bfdbfe"))
canvas.drawCentredString(W/2, H - 30*mm,
"Adults & Adolescents (≥12 yrs) | Anti-inflammatory first approach")
# footer
canvas.setFillColor(BLUE_DARK)
canvas.rect(0, 0, W, 12*mm, fill=1, stroke=0)
canvas.setFillColor(GREY_MED)
canvas.setFont("Helvetica", 7)
canvas.drawCentredString(W/2, 4*mm,
"Reference: GINA 2026 Strategy Report · ginasthma.org · For educational use only")
canvas.restoreState()
# ── Document setup ───────────────────────────────────────────────────────────
doc = BaseDocTemplate(OUTPUT, pagesize=A4,
leftMargin=14*mm, rightMargin=14*mm,
topMargin=42*mm, bottomMargin=15*mm)
frame = Frame(doc.leftMargin, doc.bottomMargin,
doc.width, doc.height, id="main")
doc.addPageTemplates([PageTemplate(id="main", frames=[frame], onPage=page_bg)])
story = []
COL = doc.width # usable width
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# SECTION 1: KEY GINA 2026 PRINCIPLES (info boxes)
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
story.append(colored_header("▸ KEY GINA 2026 PRINCIPLES", BLUE_MID))
story.append(Spacer(1, 3))
principles = [
("🚫", "No SABA monotherapy", "ICS-formoterol is now the preferred reliever at ALL steps. SABA alone is no longer recommended as first-line reliever."),
("✅", "Anti-inflammatory first", "Every patient with asthma should receive ICS-containing therapy. Inflammation, not just bronchospasm, must be treated."),
("🔄", "SMART strategy", "Single Maintenance And Reliever Therapy (ICS-formoterol) at Steps 3-5: one inhaler for both daily control AND rescue."),
("🎯", "Treat to control", "Assess control every 1-3 months. Step UP if uncontrolled; Step DOWN if well-controlled for ≥3 months."),
("💊", "Minimize OCS", "Optimize ICS, treat triggers, use add-ons and biologics to avoid oral corticosteroids."),
("🩺", "SpO₂ target 92-95%", "New 2026 update: target O₂ saturation 92-95% in acute exacerbations (not 100%)."),
]
pcols = COL / 3
p_data = []
row = []
for i, (icon, title, detail) in enumerate(principles):
cell_content = [
Paragraph(f"<b>{icon} {title}</b>", S("pi_t", fontName="Helvetica-Bold",
fontSize=8, textColor=BLUE_DARK, leading=11)),
Paragraph(detail, S("pi_d", fontName="Helvetica", fontSize=7,
textColor=BLACK, leading=10))
]
row.append(cell_content)
if len(row) == 3:
p_data.append(row)
row = []
if row:
while len(row) < 3:
row.append([""])
p_data.append(row)
ptable = Table(p_data, colWidths=[pcols]*3, rowHeights=None)
ptable.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), BLUE_LIGHT),
("BACKGROUND", (0,1), (-1,1), colors.HexColor("#e0f2fe")),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("GRID", (0,0), (-1,-1), 0.5, WHITE),
("VALIGN", (0,0), (-1,-1), "TOP"),
("ROUNDEDCORNERS", [3]),
]))
story.append(ptable)
story.append(Spacer(1, 6))
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# SECTION 2: STEPWISE TREATMENT TABLE
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
story.append(colored_header("▸ STEPWISE TREATMENT — Adults & Adolescents (≥12 years)", TEAL))
story.append(Spacer(1, 3))
# Step colours
step_colors = [
colors.HexColor("#16a34a"), # step 1 - green
colors.HexColor("#2563a8"), # step 2 - blue
colors.HexColor("#d97706"), # step 3 - amber
colors.HexColor("#dc6f07"), # step 4 - deep orange
colors.HexColor("#dc2626"), # step 5 - red
]
step_data = [
# (step#, label, severity, controller, reliever, add-ons, notes)
(
"STEP 1",
"Intermittent",
"Low-dose ICS-formoterol\nas needed (preferred)\nOR low-dose ICS taken\nwhenever SABA taken",
"Low-dose ICS-formoterol\n(as needed)\n[e.g. budesonide/formoterol\n100/6 mcg]",
"—",
"• No daily controller needed if truly intermittent\n• If using SABA ≥2×/week → Step up\n• Consider daily low-dose ICS if frequent symptoms",
),
(
"STEP 2",
"Mild\nPersistent",
"Low-dose ICS daily\n(preferred)\nOR LTRA daily",
"ICS-formoterol\n(as needed)\nOR SABA",
"LTRA (alternative\nto ICS if ICS refused\nor not tolerated)",
"• Low-dose ICS is the cornerstone\n• ICS+SABA combo inhaler is an alternative\n• Review adherence and inhaler technique",
),
(
"STEP 3",
"Moderate\n(uncontrolled\non Step 2)",
"Low-dose ICS-LABA\ndaily (preferred)\n[SMART therapy preferred]",
"ICS-formoterol\n(SMART reliever)\n[same inhaler as controller]",
"LAMA (tiotropium)\nas add-on\nLTRA as add-on",
"• SMART = one inhaler for maintenance + relief\n• Preferred: budesonide/formoterol or BDP/formoterol\n• Assess FeNO / eosinophils to guide therapy",
),
(
"STEP 4",
"Moderate-Severe\n(uncontrolled\non Step 3)",
"Medium-dose ICS-LABA\ndaily\n[+ consider LAMA]",
"ICS-formoterol\n(SMART reliever)",
"LAMA (tiotropium)\nLTRA\nHigh-dose ICS",
"• Refer to specialist for assessment\n• Check for type 2 biomarkers (eosinophils, FeNO)\n• Rule out: poor adherence, wrong diagnosis, triggers",
),
(
"STEP 5",
"Severe\n(uncontrolled\non Step 4)",
"High-dose ICS-LABA\n+ specialist-directed\nbiologic therapy",
"ICS-formoterol\n(SMART reliever)\nOR SABA",
"Biologics (see below)\nLAMA\nLTRA\nMinimize OCS",
"• Mandatory specialist referral\n• Phenotype-guided biologic selection\n• Add-on tiotropium if not already used\n• OCS only as last resort / short course",
),
]
# Header row
col_widths = [COL*0.085, COL*0.10, COL*0.22, COL*0.20, COL*0.13, COL*0.265]
def mp(txt, sty):
lines = txt.strip().split("\n")
return [Paragraph(l, sty) for l in lines if l.strip()]
hdr_row = [
Paragraph("STEP", S("sh", fontName="Helvetica-Bold", fontSize=8, textColor=WHITE,
alignment=TA_CENTER, leading=11)),
Paragraph("SEVERITY", S("sh2", fontName="Helvetica-Bold", fontSize=8, textColor=WHITE,
alignment=TA_CENTER, leading=11)),
Paragraph("PREFERRED CONTROLLER", S("sh3", fontName="Helvetica-Bold", fontSize=8,
textColor=WHITE, alignment=TA_CENTER, leading=11)),
Paragraph("PREFERRED RELIEVER", S("sh4", fontName="Helvetica-Bold", fontSize=8,
textColor=WHITE, alignment=TA_CENTER, leading=11)),
Paragraph("ADD-ON OPTIONS", S("sh5", fontName="Helvetica-Bold", fontSize=8,
textColor=WHITE, alignment=TA_CENTER, leading=11)),
Paragraph("CLINICAL NOTES", S("sh6", fontName="Helvetica-Bold", fontSize=8,
textColor=WHITE, alignment=TA_CENTER, leading=11)),
]
rows = [hdr_row]
for idx, (step, sev, ctrl, rel, addon, notes) in enumerate(step_data):
col = step_colors[idx]
s_cell = Paragraph(step, S("sc"+str(idx), fontName="Helvetica-Bold", fontSize=9,
textColor=WHITE, alignment=TA_CENTER, leading=12))
sev_cell = mp(sev, S("sv", fontName="Helvetica-Bold", fontSize=7.5, textColor=col, leading=10))
ctrl_cell = mp(ctrl, S("ct", fontName="Helvetica", fontSize=7.5, textColor=BLACK, leading=10))
rel_cell = mp(rel, S("rl", fontName="Helvetica", fontSize=7.5, textColor=BLACK, leading=10))
add_cell = mp(addon, S("ad", fontName="Helvetica", fontSize=7.5, textColor=BLACK, leading=10))
note_cell = mp(notes, S("nt", fontName="Helvetica", fontSize=7.5, textColor=colors.HexColor("#1e293b"), leading=10))
rows.append([s_cell, sev_cell, ctrl_cell, rel_cell, add_cell, note_cell])
step_table = Table(rows, colWidths=col_widths, repeatRows=1)
ts = TableStyle([
# Header
("BACKGROUND", (0,0), (-1,0), BLUE_DARK),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("TOPPADDING", (0,0), (-1,0), 5),
("BOTTOMPADDING", (0,0), (-1,0), 5),
# Step number cells
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("ALIGN", (0,0), (0,-1), "CENTER"),
("TOPPADDING", (0,1), (-1,-1), 5),
("BOTTOMPADDING", (0,1), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 4),
("RIGHTPADDING", (0,0), (-1,-1), 4),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#cbd5e1")),
("ROWBACKGROUNDS",(0,1), (-1,-1), [GREY_LIGHT, WHITE]),
("VALIGN", (0,1), (-1,-1), "TOP"),
])
# Color the step number column per step
for i, col in enumerate(step_colors):
ts.add("BACKGROUND", (0, i+1), (0, i+1), col)
step_table.setStyle(ts)
story.append(step_table)
story.append(Spacer(1, 6))
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# SECTION 3: BIOLOGICS + CONTROL ASSESSMENT (two columns)
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
half = COL / 2 - 2*mm
# -- Biologics table --
bio_hdr_style = S("bhs", fontName="Helvetica-Bold", fontSize=8, textColor=WHITE,
alignment=TA_CENTER, leading=11)
bio_cell_style = S("bcs", fontName="Helvetica", fontSize=7.5, textColor=BLACK, leading=10)
bio_bold_style = S("bbs", fontName="Helvetica-Bold", fontSize=7.5, textColor=PURPLE, leading=10)
bio_rows = [
[Paragraph("BIOLOGIC", bio_hdr_style),
Paragraph("TARGET", bio_hdr_style),
Paragraph("PHENOTYPE", bio_hdr_style)],
[Paragraph("Omalizumab", bio_bold_style), Paragraph("IgE", bio_cell_style), Paragraph("Allergic (T2)", bio_cell_style)],
[Paragraph("Mepolizumab", bio_bold_style), Paragraph("IL-5", bio_cell_style), Paragraph("Eosinophilic", bio_cell_style)],
[Paragraph("Reslizumab", bio_bold_style), Paragraph("IL-5", bio_cell_style), Paragraph("Eosinophilic", bio_cell_style)],
[Paragraph("Benralizumab", bio_bold_style), Paragraph("IL-5R", bio_cell_style), Paragraph("Eosinophilic", bio_cell_style)],
[Paragraph("Dupilumab", bio_bold_style), Paragraph("IL-4Rα", bio_cell_style), Paragraph("T2 (IL-4/IL-13)", bio_cell_style)],
[Paragraph("Tezepelumab", bio_bold_style), Paragraph("TSLP", bio_cell_style), Paragraph("Broad / all phenotypes", bio_cell_style)],
[Paragraph("Depemokimab ★NEW", bio_bold_style), Paragraph("IL-5", bio_cell_style), Paragraph("Eosinophilic (ultra-LA)", bio_cell_style)],
]
bio_table = Table(bio_rows, colWidths=[half*0.38, half*0.25, half*0.37])
bio_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), PURPLE),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("ROWBACKGROUNDS",(0,1), (-1,-1), [PURPLE_LIGHT, WHITE]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#c4b5fd")),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 4),
("RIGHTPADDING", (0,0), (-1,-1), 4),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
# -- Control assessment table --
ctrl_hdr_s = S("chs", fontName="Helvetica-Bold", fontSize=8, textColor=WHITE,
alignment=TA_CENTER, leading=11)
ctrl_cell_s = S("ccs", fontName="Helvetica", fontSize=7.5, textColor=BLACK, leading=10)
def ctrl_label(text, c):
return Paragraph(f"<b>{text}</b>", S("cl_"+text[:3], fontName="Helvetica-Bold",
fontSize=7.5, textColor=c, alignment=TA_CENTER, leading=10))
ctrl_rows = [
[Paragraph("CRITERION\n(last 4 weeks)", ctrl_hdr_s),
ctrl_label("CONTROLLED", GREEN),
ctrl_label("PARTLY\nCONTROLLED", ORANGE),
ctrl_label("UNCONTROLLED", RED)],
[Paragraph("Daytime symptoms", ctrl_cell_s),
Paragraph("≤2×/week", ctrl_cell_s),
Paragraph(">2×/week", ctrl_cell_s),
Paragraph("3-4 features\nof 'partly\ncontrolled'", S("uc", fontName="Helvetica", fontSize=7.5,
textColor=BLACK, leading=10))],
[Paragraph("Night waking", ctrl_cell_s),
Paragraph("None", ctrl_cell_s),
Paragraph("Any", ctrl_cell_s),
Paragraph("", ctrl_cell_s)],
[Paragraph("Reliever use", ctrl_cell_s),
Paragraph("≤2×/week", ctrl_cell_s),
Paragraph(">2×/week", ctrl_cell_s),
Paragraph("", ctrl_cell_s)],
[Paragraph("Activity limitation", ctrl_cell_s),
Paragraph("None", ctrl_cell_s),
Paragraph("Any", ctrl_cell_s),
Paragraph("", ctrl_cell_s)],
[Paragraph("ACTION", S("act", fontName="Helvetica-Bold", fontSize=7.5, textColor=BLACK, leading=10)),
Paragraph("Maintain /\nStep down", S("act_g", fontName="Helvetica-Bold", fontSize=7.5,
textColor=GREEN, leading=10)),
Paragraph("Consider\nStep up", S("act_o", fontName="Helvetica-Bold", fontSize=7.5,
textColor=ORANGE, leading=10)),
Paragraph("Step UP", S("act_r", fontName="Helvetica-Bold", fontSize=7.5,
textColor=RED, leading=10))],
]
ctrl_table = Table(ctrl_rows, colWidths=[half*0.36, half*0.21, half*0.21, half*0.22])
ctrl_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), TEAL),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("BACKGROUND", (0,5), (-1,5), GREY_LIGHT),
("ROWBACKGROUNDS",(0,1), (-1,4), [TEAL_LIGHT, WHITE]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#99f6e4")),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 4),
("RIGHTPADDING", (0,0), (-1,-1), 4),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("SPAN", (3,1), (3,4)),
("ALIGN", (1,0), (-1,-1), "CENTER"),
]))
def section_label(text, bg):
t = Table([[Paragraph(f"<b>{text}</b>", S("slb_"+text[:4],
fontName="Helvetica-Bold", fontSize=8.5, textColor=WHITE,
alignment=TA_CENTER, leading=12))]],
colWidths=[half])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
]))
return t
bio_section = [
[section_label("▸ STEP 5 BIOLOGICS (Severe Asthma)", PURPLE),
section_label("▸ ASTHMA CONTROL ASSESSMENT (GINA 2026)", TEAL)],
[bio_table, ctrl_table],
]
two_col = Table(bio_section, colWidths=[half + 2*mm, half + 2*mm])
two_col.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 0),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 0),
("RIGHTPADDING", (0,0), (-1,-1), 4),
]))
story.append(two_col)
story.append(Spacer(1, 6))
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# SECTION 4: ACUTE EXACERBATION MANAGEMENT + RED FLAGS (two columns)
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# -- Acute Exacerbation --
ae_hdr = S("ae_h", fontName="Helvetica-Bold", fontSize=8, textColor=WHITE,
alignment=TA_CENTER, leading=11)
ae_cell = S("ae_c", fontName="Helvetica", fontSize=7.5, textColor=BLACK, leading=10)
ae_bold = S("ae_b", fontName="Helvetica-Bold", fontSize=7.5, textColor=BLACK, leading=10)
ae_rows = [
[Paragraph("SEVERITY", ae_hdr),
Paragraph("KEY FEATURES", ae_hdr),
Paragraph("TREATMENT", ae_hdr)],
[Paragraph("MILD", S("mild_l", fontName="Helvetica-Bold", fontSize=8, textColor=GREEN,
alignment=TA_CENTER, leading=11)),
Paragraph("SpO₂ ≥94% | Normal-mild ↑RR\nFull sentences | Mild wheeze", ae_cell),
Paragraph("Salbutamol 4 puffs (pMDI + spacer)\nOR ICS-formoterol 2 puffs\nReassess 20 min", ae_cell)],
[Paragraph("MODERATE", S("mod_l", fontName="Helvetica-Bold", fontSize=8, textColor=ORANGE,
alignment=TA_CENTER, leading=11)),
Paragraph("SpO₂ 90-93% | ↑RR | ↑HR\nPhrases only | Mod. wheeze\nAccessory muscles", ae_cell),
Paragraph("Salbutamol 4-6 puffs q20min × 3\n+ Ipratropium 4 puffs (up to 3×)\n+ Oral prednisolone\n+ Controlled O₂ (target 92-95%)", ae_cell)],
[Paragraph("SEVERE /\nLIFE-\nTHREATENING", S("sev_l", fontName="Helvetica-Bold", fontSize=8,
textColor=RED, alignment=TA_CENTER, leading=11)),
Paragraph("SpO₂ <92% | RR >30/min\nWords/unable to speak\nSilent chest | Cyanosis\nDrowsy / confused", ae_cell),
Paragraph("TRANSFER TO ACUTE CARE\nSalbutamol 6-10 puffs q20-30min\n+ Ipratropium + IV/IM corticosteroids\n+ Controlled O₂ (92-95%)\n+ IV Magnesium sulfate\n★ Anaphylaxis → Epinephrine FIRST", ae_bold)],
]
ae_table = Table(ae_rows, colWidths=[half*0.22, half*0.38, half*0.40])
ae_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), RED),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("ROWBACKGROUNDS",(0,1), (-1,-1), [GREEN_LIGHT, ORANGE_LIGHT, RED_LIGHT]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#fca5a5")),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 4),
("RIGHTPADDING", (0,0), (-1,-1), 4),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("ALIGN", (0,0), (0,-1), "CENTER"),
]))
# -- Red Flags --
rf_items = [
"Previous near-fatal attack (ICU / intubation)",
"ER visit or hospitalization in past 12 months",
"Not on ICS, or poor adherence / technique",
"Using >1 SABA canister per month",
"Psychological / socioeconomic problems",
"Food allergy coexisting with asthma",
"Heavy smoking (current or past)",
"Elevated blood eosinophils or FeNO",
]
rf_body = S("rfs", fontName="Helvetica", fontSize=7.5, textColor=BLACK, leading=11)
rf_data = [[Paragraph(f"⚠ {item}", rf_body)] for item in rf_items]
rf_table = Table(rf_data, colWidths=[half])
rf_table.setStyle(TableStyle([
("ROWBACKGROUNDS", (0,0), (-1,-1), [RED_LIGHT, WHITE]),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#fca5a5")),
]))
ae_section = [
[section_label("▸ ACUTE EXACERBATION MANAGEMENT (GINA 2026)", RED),
section_label("▸ RED FLAGS FOR FATAL / NEAR-FATAL ASTHMA", RED)],
[ae_table, rf_table],
]
ae_two_col = Table(ae_section, colWidths=[half + 2*mm, half + 2*mm])
ae_two_col.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 0),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 0),
("RIGHTPADDING", (0,0), (-1,-1), 4),
]))
story.append(ae_two_col)
story.append(Spacer(1, 5))
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# SECTION 5: ICS DOSE TABLE + KEY DRUG CLASSES (bottom strip)
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
story.append(colored_header("▸ ICS DOSE REFERENCE & KEY DRUG CLASSES", BLUE_DARK))
story.append(Spacer(1, 3))
third = COL / 3 - 2*mm
# ICS dose table
ics_hdr = S("ics_h", fontName="Helvetica-Bold", fontSize=7.5, textColor=WHITE,
alignment=TA_CENTER, leading=10)
ics_cell = S("ics_c", fontName="Helvetica", fontSize=7.5, textColor=BLACK, leading=10)
ics_rows = [
[Paragraph("ICS DRUG", ics_hdr),
Paragraph("LOW DOSE\n(mcg/day)", ics_hdr),
Paragraph("MEDIUM DOSE\n(mcg/day)", ics_hdr),
Paragraph("HIGH DOSE\n(mcg/day)", ics_hdr)],
[Paragraph("Beclomethasone\n(HFA pMDI)", ics_cell),
Paragraph("100-200", ics_cell), Paragraph("200-400", ics_cell), Paragraph(">400", ics_cell)],
[Paragraph("Budesonide\n(DPI)", ics_cell),
Paragraph("200-400", ics_cell), Paragraph("400-800", ics_cell), Paragraph(">800", ics_cell)],
[Paragraph("Fluticasone\npropionate (DPI)", ics_cell),
Paragraph("100-250", ics_cell), Paragraph("250-500", ics_cell), Paragraph(">500", ics_cell)],
[Paragraph("Fluticasone\nfuroate (DPI)", ics_cell),
Paragraph("100", ics_cell), Paragraph("—", ics_cell), Paragraph("200", ics_cell)],
[Paragraph("Ciclesonide\n(HFA pMDI)", ics_cell),
Paragraph("80-160", ics_cell), Paragraph("160-320", ics_cell), Paragraph(">320", ics_cell)],
]
ics_t = Table(ics_rows, colWidths=[third*0.37, third*0.21, third*0.21, third*0.21])
ics_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), BLUE_MID),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("ROWBACKGROUNDS",(0,1), (-1,-1), [BLUE_LIGHT, WHITE]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#bfdbfe")),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 4),
("RIGHTPADDING", (0,0), (-1,-1), 4),
("ALIGN", (1,0), (-1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
# Drug classes quick ref
drug_s = S("drg_s", fontName="Helvetica", fontSize=7.5, textColor=BLACK, leading=10)
drug_b = S("drg_b", fontName="Helvetica-Bold", fontSize=7.5, textColor=BLUE_DARK, leading=10)
drug_rows = [
[Paragraph("CLASS", S("dh", fontName="Helvetica-Bold", fontSize=7.5, textColor=WHITE,
alignment=TA_CENTER, leading=10)),
Paragraph("EXAMPLES", S("dh2", fontName="Helvetica-Bold", fontSize=7.5, textColor=WHITE,
alignment=TA_CENTER, leading=10)),
Paragraph("ROLE", S("dh3", fontName="Helvetica-Bold", fontSize=7.5, textColor=WHITE,
alignment=TA_CENTER, leading=10))],
[Paragraph("SABA", drug_b), Paragraph("Salbutamol, Terbutaline", drug_s),
Paragraph("Acute relief (use only with ICS)", drug_s)],
[Paragraph("LABA", drug_b), Paragraph("Formoterol, Salmeterol", drug_s),
Paragraph("Add-on to ICS — NEVER alone", drug_s)],
[Paragraph("ICS", drug_b), Paragraph("Budesonide, BDP,\nFluticasone", drug_s),
Paragraph("Cornerstone — all steps", drug_s)],
[Paragraph("ICS-LABA", drug_b), Paragraph("Budesonide/formoterol\nBDP/formoterol\nFluticasone/salmeterol", drug_s),
Paragraph("Preferred Steps 3-5\n(SMART at Steps 3-5)", drug_s)],
[Paragraph("LAMA", drug_b), Paragraph("Tiotropium", drug_s),
Paragraph("Add-on Steps 4-5", drug_s)],
[Paragraph("LTRA", drug_b), Paragraph("Montelukast", drug_s),
Paragraph("Alternative/add-on\n(less effective than ICS)", drug_s)],
]
drug_t = Table(drug_rows, colWidths=[third*0.25, third*0.38, third*0.37])
drug_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), TEAL),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("ROWBACKGROUNDS",(0,1), (-1,-1), [TEAL_LIGHT, WHITE]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#99f6e4")),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 4),
("RIGHTPADDING", (0,0), (-1,-1), 4),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
# New 2026 highlights
new_items = [
("★", "ICS-formoterol reliever", "Preferred at ALL steps — even Step 1"),
("★", "No SABA monotherapy", "Avoid SABA alone as sole treatment"),
("★", "SpO₂ target 92-95%", "New threshold in acute exacerbation (not 100%)"),
("★", "Depemokimab (biologic)", "Ultra-long-acting anti-IL-5 (q6 months SC)"),
("★", "OCS minimization", "Biologics preferred over chronic OCS"),
("★", "Pediatric PRAM score", "Validated severity score for children <18 yrs"),
("★", "CAAT & Peds-AIRQ", "New control/assessment tools added in 2026"),
("★", "RSV/flu/COVID vaccines", "Updated vaccine evidence included"),
]
new_s = S("nw_s", fontName="Helvetica", fontSize=7.5, textColor=BLACK, leading=10)
new_b = S("nw_b", fontName="Helvetica-Bold", fontSize=7.5, textColor=ORANGE, leading=10)
new_rows = [[Paragraph("★ NEW IN 2026", S("nh", fontName="Helvetica-Bold", fontSize=8,
textColor=WHITE, alignment=TA_CENTER, leading=11)),
Paragraph("DETAIL", S("nh2", fontName="Helvetica-Bold", fontSize=8,
textColor=WHITE, alignment=TA_CENTER, leading=11))]]
for icon, title, detail in new_items:
new_rows.append([Paragraph(f"<b>{title}</b>", new_b),
Paragraph(detail, new_s)])
new_t = Table(new_rows, colWidths=[third*0.44, third*0.56])
new_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), ORANGE),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("ROWBACKGROUNDS",(0,1), (-1,-1), [ORANGE_LIGHT, WHITE]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#fde68a")),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 4),
("RIGHTPADDING", (0,0), (-1,-1), 4),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
# labels
def mini_label(txt, bg):
t = Table([[Paragraph(f"<b>{txt}</b>", S("ml_"+txt[:3], fontName="Helvetica-Bold",
fontSize=7.5, textColor=WHITE, alignment=TA_CENTER, leading=10))]],
colWidths=[third])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
]))
return t
bottom_section = [
[mini_label("ICS DOSE REFERENCE", BLUE_MID),
mini_label("KEY DRUG CLASSES", TEAL),
mini_label("★ WHAT'S NEW IN GINA 2026", ORANGE)],
[ics_t, drug_t, new_t],
]
bottom_col = Table(bottom_section, colWidths=[third + 3*mm, third + 3*mm, third + 3*mm])
bottom_col.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 0),
("BOTTOMPADDING", (0,0), (-1,-1), 0),
("LEFTPADDING", (0,0), (-1,-1), 0),
("RIGHTPADDING", (0,0), (-1,-1), 4),
]))
story.append(bottom_col)
# ── Build ────────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF created: {OUTPUT}")
cd /home/daytona/workspace/gina2026-cheatsheet && python3 generate_pdf.py 2>&1
GINA 2026 Asthma Stepwise Cheatsheet
PDF Document · PDF