Management of acute severe asthama essay note in it
"acute severe asthma" management treatment
A rising PaCO2 indicates impending respiratory failure and requires immediate monitoring and therapy. - Fishman's, p. 812
| Agent | Notes |
|---|---|
| IV aminophylline | Can be used but risks of toxicity are much greater than inhaled beta-2 agonists; use with caution |
| Heliox (helium-oxygen) | Reduces turbulent flow resistance; considered in refractory cases |
| IV ketamine | Bronchodilator properties; used as induction agent for RSI |
| Drug | Role | Dose |
|---|---|---|
| Ketamine | Induction (bronchodilator effect) | 2 mg/kg IV |
| Succinylcholine | Short-term paralysis | <10 kg: 2 mg/kg; >10 kg: 1.5 mg/kg |
| Rocuronium | Non-depolarizing alternative | 1 mg/kg |
Unrecognized barotrauma may cause cardiac arrest. Bedside ultrasound should be used to identify occult pneumothorax. Empirical bilateral tube thoracostomy should be performed if unexplained cardiac arrest occurs in the context of dramatic increases in peak inspiratory pressure. - Rosen's Emergency Medicine, p. 2122
| Response | PEF (% predicted) | Disposition |
|---|---|---|
| Good | ≥60% | Discharge home with follow-up |
| Incomplete | 40-60% | Consider admission vs. observation based on risk factors |
| Poor | <40% | Hospitalize; continue aggressive therapy |
ACUTE SEVERE ASTHMA (PEF <60% predicted)
|
v
Oxygen → SpO2 94-98%
|
v
SABA (salbutamol) - nebulized or pMDI + spacer (high dose, early)
+ Systemic CS (prednisolone PO or methylprednisolone/hydrocortisone IV)
|
v
Not responding?
Add ipratropium bromide (anticholinergic)
IV/SC beta-2 agonist if inhaled route unreliable
IV magnesium sulfate 1-2g over 20-30 min
|
v
Life-threatening features / Failing maximal therapy?
Consider BiPAP (IPAP 12-18 / EPAP 6-12)
|
v
Deteriorating despite BiPAP / Impending arrest?
RSI with ketamine + ETI + Mechanical ventilation
(Permissive hypercapnia strategy)
|
v
Refractory to all → Consider ECMO
Create a one-page quick reference PDF for acute severe asthma management
ls -la /tmp/workspace/ 2>/dev/null || mkdir -p /tmp/workspace && echo "created"
mkdir -p /tmp/workspace/asthma-pdf && python3 << 'EOF' from reportlab.lib.pagesizes import A4 from reportlab.lib import colors from reportlab.lib.units import mm, cm from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer, HRFlowable from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY from reportlab.platypus import KeepTogether from reportlab.lib.colors import HexColor, white, black output_path = "/tmp/workspace/asthma-pdf/Acute_Severe_Asthma_QuickRef.pdf" # Custom colors RED = HexColor("#C0392B") DARK_RED = HexColor("#96281B") ORANGE = HexColor("#E67E22") YELLOW = HexColor("#F39C12") GREEN = HexColor("#27AE60") DARK_BLUE = HexColor("#1A5276") MID_BLUE = HexColor("#2471A3") LIGHT_BLUE= HexColor("#D6EAF8") LIGHT_RED = HexColor("#FADBD8") LIGHT_ORG = HexColor("#FDEBD0") LIGHT_GRN = HexColor("#D5F5E3") LIGHT_YLW = HexColor("#FEF9E7") GRAY_BG = HexColor("#F2F3F4") DARK_GRAY = HexColor("#2C3E50") MID_GRAY = HexColor("#5D6D7E") doc = SimpleDocTemplate( output_path, pagesize=A4, leftMargin=10*mm, rightMargin=10*mm, topMargin=8*mm, bottomMargin=8*mm ) W = A4[0] - 20*mm # usable width styles = getSampleStyleSheet() # Style helpers def S(name, **kw): base = styles["Normal"] return ParagraphStyle(name, parent=base, **kw) title_style = S("title", fontSize=14, textColor=white, alignment=TA_CENTER, fontName="Helvetica-Bold", leading=18) sub_style = S("sub", fontSize=8, textColor=white, alignment=TA_CENTER, fontName="Helvetica", leading=10) sec_hdr_style = S("sechdr", fontSize=7.5, textColor=white, fontName="Helvetica-Bold", leading=9, leftIndent=2) body_style = S("body", fontSize=6.8, textColor=DARK_GRAY, fontName="Helvetica", leading=8.5, leftIndent=3) bold_style = S("bold", fontSize=6.8, textColor=DARK_GRAY, fontName="Helvetica-Bold", leading=8.5, leftIndent=3) warn_style = S("warn", fontSize=6.8, textColor=RED, fontName="Helvetica-Bold", leading=8.5, leftIndent=3) small_style = S("small", fontSize=6.2, textColor=MID_GRAY, fontName="Helvetica", leading=7.5, leftIndent=3) arrow_style = S("arrow", fontSize=7, textColor=DARK_BLUE, fontName="Helvetica-Bold", leading=9, alignment=TA_CENTER) def section_header(text, bg_color): t = Table([[Paragraph(text, sec_hdr_style)]], colWidths=[W]) t.setStyle(TableStyle([ ("BACKGROUND", (0,0), (-1,-1), bg_color), ("TOPPADDING", (0,0), (-1,-1), 2), ("BOTTOMPADDING", (0,0), (-1,-1), 2), ("LEFTPADDING", (0,0), (-1,-1), 4), ("RIGHTPADDING", (0,0), (-1,-1), 4), ("ROUNDEDCORNERS", [3, 3, 3, 3]), ])) return t def two_col_table(left_data, right_data, left_width=0.5, bg_l=GRAY_BG, bg_r=GRAY_BG): lw = W * left_width rw = W * (1 - left_width) data = [[left_data, right_data]] t = Table(data, colWidths=[lw, rw]) t.setStyle(TableStyle([ ("VALIGN", (0,0), (-1,-1), "TOP"), ("LEFTPADDING", (0,0), (-1,-1), 4), ("RIGHTPADDING", (0,0), (-1,-1), 4), ("TOPPADDING", (0,0), (-1,-1), 3), ("BOTTOMPADDING", (0,0), (-1,-1), 3), ("BACKGROUND", (0,0), (0,-1), bg_l), ("BACKGROUND", (1,0), (1,-1), bg_r), ("GRID", (0,0), (-1,-1), 0.3, HexColor("#BDC3C7")), ])) return t story = [] # ────────────────────────────────────────────────────────── # TITLE BLOCK # ────────────────────────────────────────────────────────── title_tbl = Table([ [Paragraph("ACUTE SEVERE ASTHMA", title_style)], [Paragraph("Emergency Quick Reference | Status Asthmaticus", sub_style)], ], colWidths=[W]) title_tbl.setStyle(TableStyle([ ("BACKGROUND", (0,0), (-1,-1), DARK_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), ])) story.append(title_tbl) story.append(Spacer(1, 3*mm)) # ────────────────────────────────────────────────────────── # ROW 1: SEVERITY + RECOGNITION (side by side) # ────────────────────────────────────────────────────────── story.append(section_header("▶ SEVERITY CLASSIFICATION (GINA)", MID_BLUE)) sev_data = [ [Paragraph("<b>Grade</b>", bold_style), Paragraph("<b>PEF</b>", bold_style), Paragraph("<b>SpO2</b>", bold_style), Paragraph("<b>PaCO2</b>", bold_style), Paragraph("<b>Clinical</b>", bold_style)], [Paragraph("Mild", body_style), Paragraph(">80%", body_style), Paragraph("≥95%", body_style), Paragraph("Low", body_style), Paragraph("Mild symptoms, speaks normally", body_style)], [Paragraph("Moderate", body_style), Paragraph("60–80%", body_style), Paragraph("92–95%", body_style), Paragraph("Low", body_style), Paragraph("Partial sentences, tachycardia", body_style)], [Paragraph("<b>Acute Severe</b>", bold_style), Paragraph("<b><60%</b>", bold_style), Paragraph("<b><92%</b>", bold_style), Paragraph("<b>Low→Normal</b>", bold_style), Paragraph("<b>Single words, accessory muscles, pulsus paradoxus</b>", bold_style)], [Paragraph("⚠ LIFE-THREATENING", warn_style), Paragraph("<30%", body_style), Paragraph("<92%", body_style), Paragraph("RISING ⚠", body_style), Paragraph("Silent chest, cyanosis, bradycardia, confusion, exhaustion", body_style)], ] cw = [W*0.15, W*0.09, W*0.09, W*0.13, W*0.54] sev_t = Table(sev_data, colWidths=cw) sev_t.setStyle(TableStyle([ ("BACKGROUND", (0,0), (-1,0), DARK_BLUE), ("TEXTCOLOR", (0,0), (-1,0), white), ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"), ("BACKGROUND", (0,3), (-1,3), LIGHT_ORG), ("BACKGROUND", (0,4), (-1,4), LIGHT_RED), ("GRID", (0,0), (-1,-1), 0.3, HexColor("#BDC3C7")), ("TOPPADDING", (0,0), (-1,-1), 2), ("BOTTOMPADDING", (0,0), (-1,-1), 2), ("LEFTPADDING", (0,0), (-1,-1), 3), ("RIGHTPADDING", (0,0), (-1,-1), 3), ("VALIGN", (0,0), (-1,-1), "MIDDLE"), ("FONTSIZE", (0,0), (-1,0), 6.8), ])) story.append(sev_t) story.append(Spacer(1, 2.5*mm)) # ────────────────────────────────────────────────────────── # ROW 2: STEPWISE MANAGEMENT # ────────────────────────────────────────────────────────── story.append(section_header("▶ STEPWISE MANAGEMENT", RED)) # Step boxes as a 5-column flow steps = [ ("STEP 1\nOXYGEN", "High-flow O2\nby face mask\nTarget SpO2\n94–98%\nContinuous\nmonitoring", GREEN), ("STEP 2\nSABA", "Salbutamol\nnebulized\n(O2-driven)\nor pMDI+spacer\nHigh dose,\nearly, repeat", MID_BLUE), ("STEP 3\nSTEROIDS", "Prednisolone\n40–50mg PO\nOR\nMethylpred.\n125mg IV\nMin. 5 days", ORANGE), ("STEP 4\nADD-ON Rx", "Ipratropium\nBromide neb.\n+\nIV Magnesium\n1–2g over\n20–30 min", HexColor("#8E44AD")), ("STEP 5\nBiPAP/ETI", "BiPAP:\nIPAP 12–18\nEPAP 6–12\ncmH2O\nRSI if failing\n(Ketamine 2mg/kg)", DARK_RED), ] step_cells = [] for (title, body, col) in steps: lines = [Paragraph(t if i == 0 else t, S(f"st{i}", fontSize=6.5 if i > 0 else 7, textColor=white if i == 0 else DARK_GRAY, fontName="Helvetica-Bold" if i == 0 else "Helvetica", alignment=TA_CENTER, leading=8.5)) for i, t in enumerate([title] + body.split("\n"))] cell_content = [Paragraph(title, S("stitle", fontSize=7, textColor=white, fontName="Helvetica-Bold", alignment=TA_CENTER, leading=9))] + \ [Paragraph(l, S("sbody", fontSize=6.3, textColor=DARK_GRAY, fontName="Helvetica", alignment=TA_CENTER, leading=7.8)) for l in body.split("\n")] step_cells.append(cell_content) # Build step table step_rows_content = [step_cells] step_t = Table([[col_content] for col_content in step_cells], colWidths=None) # Use a single row with 5 columns step_t2 = Table([step_cells], colWidths=[W/5]*5) step_t2_styles = [ ("TOPPADDING", (0,0), (-1,-1), 3), ("BOTTOMPADDING", (0,0), (-1,-1), 3), ("LEFTPADDING", (0,0), (-1,-1), 3), ("RIGHTPADDING", (0,0), (-1,-1), 3), ("VALIGN", (0,0), (-1,-1), "TOP"), ("GRID", (0,0), (-1,-1), 0.5, white), ] for i, (_, _, col) in enumerate(steps): step_t2_styles.append(("BACKGROUND", (i,0), (i,0), col)) step_t2.setStyle(TableStyle(step_t2_styles)) # Add white step headers row hdr_cells = [Paragraph(s[0], S(f"hdr{i}", fontSize=7, textColor=white, fontName="Helvetica-Bold", alignment=TA_CENTER, leading=9)) for i, s in enumerate(steps)] body_cells = [ [Paragraph(l, S("sb", fontSize=6.3, textColor=DARK_GRAY, fontName="Helvetica", alignment=TA_CENTER, leading=7.8)) for l in s[1].split("\n")] for i, s in enumerate(steps) ] # Rebuild with proper header + body split final_step_data = [hdr_cells] max_lines = max(len(b) for b in body_cells) for row_i in range(max_lines): row = [] for b in body_cells: if row_i < len(b): row.append(Paragraph(b[row_i], S("sbr", fontSize=6.3, textColor=DARK_GRAY, fontName="Helvetica", alignment=TA_CENTER, leading=7.8))) else: row.append(Paragraph("", body_style)) final_step_data.append(row) final_step_t = Table(final_step_data, colWidths=[W/5]*5) fs_styles = [ ("TOPPADDING", (0,0), (-1,-1), 2), ("BOTTOMPADDING", (0,0), (-1,-1), 2), ("LEFTPADDING", (0,0), (-1,-1), 3), ("RIGHTPADDING", (0,0), (-1,-1), 3), ("VALIGN", (0,0), (-1,-1), "TOP"), ("GRID", (0,0), (-1,-1), 0.4, white), ("BACKGROUND", (0,1), (-1,-1), GRAY_BG), ("BOTTOMPADDING", (0, len(final_step_data)-1), (-1,-1), 4), ] for i, (_, _, col) in enumerate(steps): fs_styles.append(("BACKGROUND", (i,0), (i,0), col)) fs_styles.append(("TEXTCOLOR", (i,0), (i,0), white)) final_step_t.setStyle(TableStyle(fs_styles)) story.append(final_step_t) story.append(Spacer(1, 2.5*mm)) # ────────────────────────────────────────────────────────── # ROW 3: DRUGS TABLE + AVOID/MONITOR # ────────────────────────────────────────────────────────── lc = W * 0.58 rc = W * 0.42 # Drug table (left) story.append(section_header("▶ KEY DRUGS AT A GLANCE", HexColor("#117A65"))) drug_data = [ [Paragraph("<b>Drug</b>", bold_style), Paragraph("<b>Route</b>", bold_style), Paragraph("<b>Dose</b>", bold_style), Paragraph("<b>Note</b>", bold_style)], [Paragraph("Salbutamol (SABA)", body_style), Paragraph("Neb / pMDI", body_style), Paragraph("2.5–5mg neb q20min OR 4–8 puffs", body_style), Paragraph("1st line; O2-driven neb preferred", body_style)], [Paragraph("Salbutamol IV/SC", body_style), Paragraph("IV", body_style), Paragraph("250mcg slow IV; inf 3–20mcg/min", body_style), Paragraph("If inhaled route unreliable", body_style)], [Paragraph("Ipratropium bromide", body_style), Paragraph("Neb", body_style), Paragraph("0.5mg q20min x3 then q4–6h", body_style), Paragraph("Add-on if not responding to SABA", body_style)], [Paragraph("Prednisolone", body_style), Paragraph("PO", body_style), Paragraph("40–50mg once daily × ≥5 days", body_style), Paragraph("Taper over 2 wks if severe episode", body_style)], [Paragraph("Methylprednisolone", body_style), Paragraph("IV", body_style), Paragraph("125mg IV single dose then 40–80mg/day", body_style), Paragraph("Use if PO route not tolerated", body_style)], [Paragraph("MgSO4 (Magnesium)", body_style), Paragraph("IV", body_style), Paragraph("1–2g IV over 20–30 min", body_style), Paragraph("Life-threat / poor response to SABA; monitor BP & DTRs", body_style)], [Paragraph("Ketamine (RSI)", body_style), Paragraph("IV", body_style), Paragraph("2 mg/kg induction", body_style), Paragraph("Bronchodilator; preferred induction agent", body_style)], [Paragraph("Aminophylline", body_style), Paragraph("IV", body_style), Paragraph("5 mg/kg load over 20 min", body_style), Paragraph("Caution: narrow TI; monitor levels", body_style)], ] drug_cw = [W*0.22, W*0.12, W*0.30, W*0.36] drug_t = Table(drug_data, colWidths=drug_cw) drug_t.setStyle(TableStyle([ ("BACKGROUND", (0,0), (-1,0), HexColor("#117A65")), ("TEXTCOLOR", (0,0), (-1,0), white), ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"), ("ROWBACKGROUNDS", (0,1), (-1,-1), [white, LIGHT_GRN]), ("GRID", (0,0), (-1,-1), 0.3, HexColor("#BDC3C7")), ("TOPPADDING", (0,0), (-1,-1), 2), ("BOTTOMPADDING", (0,0), (-1,-1), 2), ("LEFTPADDING", (0,0), (-1,-1), 3), ("RIGHTPADDING", (0,0), (-1,-1), 3), ("VALIGN", (0,0), (-1,-1), "MIDDLE"), ("FONTSIZE", (0,0), (-1,0), 6.8), ])) story.append(drug_t) story.append(Spacer(1, 2.5*mm)) # ────────────────────────────────────────────────────────── # ROW 4: VENTILATION + DISPOSITION + WARNINGS (3 col) # ────────────────────────────────────────────────────────── c1 = W * 0.34 c2 = W * 0.34 c3 = W * 0.32 vent_content = [ Paragraph("VENTILATION (BiPAP / ETI)", S("vh", fontSize=6.8, textColor=white, fontName="Helvetica-Bold", leading=9)), Spacer(1,1.5*mm), Paragraph("<b>BiPAP indications:</b> Poor response to max medical Rx; consider before intubation", body_style), Paragraph("• IPAP: 12–18 cm H2O", body_style), Paragraph("• EPAP: 6–12 cm H2O", body_style), Paragraph("• Nebulized drugs via BiPAP circuit", body_style), Paragraph("• Sedation: midazolam 0.05–0.1 mg/kg OR ketamine 0.5–1 mg/kg", body_style), Spacer(1,1.5*mm), Paragraph("<b>Intubation indicators:</b>", bold_style), Paragraph("• Deteriorating PEF + worsening SpO2", body_style), Paragraph("• Rising PaCO2 / respiratory exhaustion", body_style), Paragraph("• GCS deterioration / impending arrest", body_style), Spacer(1,1.5*mm), Paragraph("<b>Vent strategy (permissive hypercapnia):</b>", bold_style), Paragraph("• TV 6–8 mL/kg RR 10–14/min", body_style), Paragraph("• Prolonged expiratory time (I:E ≥ 1:3)", body_style), Paragraph("• Low PEEP; accept high PaCO2", body_style), Paragraph("• Watch for pneumothorax (bedside USS)", body_style), Paragraph("• ECMO if refractory to all Rx", body_style), ] disp_content = [ Paragraph("DISPOSITION FROM ED", S("dh", fontSize=6.8, textColor=white, fontName="Helvetica-Bold", leading=9)), Spacer(1,1.5*mm), Paragraph("<b>Discharge home</b> (PEF ≥60%):", bold_style), Paragraph("• SABA 2–6 puffs q4h till resolved", body_style), Paragraph("• Prednisolone 40mg OD × 5 days", body_style), Paragraph("• ICS prescribed/reviewed", body_style), Paragraph("• Written asthma action plan", body_style), Paragraph("• Follow-up within 7 days", body_style), Spacer(1,1.5*mm), Paragraph("<b>Admit to ward</b> (PEF 40–60%): if risk factors present", bold_style), Spacer(1,1.5*mm), Paragraph("<b>Admit to ICU:</b>", bold_style), Paragraph("• PEF <40% / not responding", body_style), Paragraph("• Life-threatening features", body_style), Paragraph("• Requires/nearing ventilation", body_style), Spacer(1,1.5*mm), Paragraph("<b>Risk factors → admit:</b>", bold_style), Paragraph("• Prior intubation / ICU admission", body_style), Paragraph("• RR >22, SpO2 <95% on arrival", body_style), Paragraph("• >8 SABA puffs in last 24h", body_style), Paragraph("• Prior OCS use", body_style), ] warn_content = [ Paragraph("⚠ WARNINGS & KEY POINTS", S("wh", fontSize=6.8, textColor=white, fontName="Helvetica-Bold", leading=9)), Spacer(1,1.5*mm), Paragraph("<b>NEVER give:</b>", warn_style), Paragraph("✗ Sedatives (depress ventilation)", body_style), Paragraph("✗ Antibiotics (unless pneumonia)", body_style), Paragraph("✗ Bronchodilators alone (always add steroids)", body_style), Spacer(1,1.5*mm), Paragraph("<b>REMEMBER:</b>", bold_style), Paragraph("★ Silent chest = worse than wheezing", body_style), Paragraph("★ Normal PaCO2 in breathless pt = danger sign", body_style), Paragraph("★ Rising PaCO2 = impending arrest", body_style), Paragraph("★ Hypoxemia kills – maintain SpO2 94–98%", body_style), Spacer(1,1.5*mm), Paragraph("<b>MONITOR:</b>", bold_style), Paragraph("• Continuous SpO2 + ECG (arrhythmia risk)", body_style), Paragraph("• Serial PEF every 20–30 min initially", body_style), Paragraph("• ABG if life-threatening or deteriorating", body_style), Paragraph("• BP + DTRs during MgSO4 infusion", body_style), Spacer(1,1.5*mm), Paragraph("<b>CXR:</b> not routine – only if:", bold_style), Paragraph("• Suspected pneumothorax", body_style), Paragraph("• Consolidation / no response to Rx", body_style), ] def box_col(content, bg_hdr): t = Table([[c] for c in content], colWidths=[None]) styles_list = [ ("TOPPADDING", (0,0), (-1,-1), 1.5), ("BOTTOMPADDING", (0,0), (-1,-1), 1.5), ("LEFTPADDING", (0,0), (-1,-1), 4), ("RIGHTPADDING", (0,0), (-1,-1), 4), ("BACKGROUND", (0,0), (0,0), bg_hdr), ("BACKGROUND", (0,1), (-1,-1), GRAY_BG), ("BOX", (0,0), (-1,-1), 0.5, HexColor("#BDC3C7")), ] t.setStyle(TableStyle(styles_list)) return t vent_box = box_col(vent_content, DARK_BLUE) disp_box = box_col(disp_content, HexColor("#117A65")) warn_box = box_col(warn_content, RED) bottom_t = Table([[vent_box, disp_box, warn_box]], colWidths=[c1, c2, c3]) bottom_t.setStyle(TableStyle([ ("VALIGN", (0,0), (-1,-1), "TOP"), ("LEFTPADDING", (0,0), (-1,-1), 2), ("RIGHTPADDING", (0,0), (-1,-1), 2), ("TOPPADDING", (0,0), (-1,-1), 0), ("BOTTOMPADDING", (0,0), (-1,-1), 0), ])) story.append(bottom_t) story.append(Spacer(1, 2*mm)) # ────────────────────────────────────────────────────────── # FOOTER # ────────────────────────────────────────────────────────── footer_t = Table([[ Paragraph("Sources: Fishman's Pulmonary Diseases | Tintinalli's Emergency Medicine | Rosen's Emergency Medicine", S("ft", fontSize=5.5, textColor=MID_GRAY, fontName="Helvetica", leading=7)), Paragraph("For clinical use under supervision of a licensed physician. Not a substitute for clinical judgment.", S("ft2", fontSize=5.5, textColor=RED, fontName="Helvetica-Oblique", leading=7, alignment=TA_CENTER)), ]], colWidths=[W*0.6, W*0.4]) footer_t.setStyle(TableStyle([ ("TOPPADDING", (0,0), (-1,-1), 2), ("BOTTOMPADDING", (0,0), (-1,-1), 2), ("BACKGROUND", (0,0), (-1,-1), LIGHT_BLUE), ("BOX", (0,0), (-1,-1), 0.4, MID_BLUE), ])) story.append(footer_t) doc.build(story) print(f"PDF created: {output_path}") EOF
~/asthma-pdf/build_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm
from reportlab.platypus import (SimpleDocTemplate, Table, TableStyle,
Paragraph, Spacer)
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.lib.colors import HexColor, white, black
OUTPUT = "/tmp/workspace/asthma-pdf/Acute_Severe_Asthma_QuickRef.pdf"
# ── Colours ──────────────────────────────────────────────
C_DARK_BLUE = HexColor("#1A5276")
C_MID_BLUE = HexColor("#2471A3")
C_LIGHT_BLUE = HexColor("#D6EAF8")
C_RED = HexColor("#C0392B")
C_DARK_RED = HexColor("#96281B")
C_ORANGE = HexColor("#E67E22")
C_GREEN = HexColor("#1E8449")
C_PURPLE = HexColor("#7D3C98")
C_TEAL = HexColor("#117A65")
C_LIGHT_RED = HexColor("#FADBD8")
C_LIGHT_ORG = HexColor("#FDEBD0")
C_LIGHT_GRN = HexColor("#D5F5E3")
C_GRAY_BG = HexColor("#F2F3F4")
C_DARK_GRAY = HexColor("#2C3E50")
C_MID_GRAY = HexColor("#5D6D7E")
C_WHITE = white
# ── Style factory ─────────────────────────────────────────
def P(text, size=6.8, color=C_DARK_GRAY, bold=False, italic=False,
align=TA_LEFT, leading=None, left=2):
fname = "Helvetica-Bold" if bold else ("Helvetica-Oblique" if italic else "Helvetica")
if leading is None:
leading = size + 1.8
style = ParagraphStyle("_", fontSize=size, textColor=color,
fontName=fname, alignment=align,
leading=leading, leftIndent=left,
rightIndent=0, spaceAfter=0, spaceBefore=0)
return Paragraph(text, style)
def SP(h=1.5):
return Spacer(1, h * mm)
# ── Page setup ────────────────────────────────────────────
doc = SimpleDocTemplate(
OUTPUT, pagesize=A4,
leftMargin=9*mm, rightMargin=9*mm,
topMargin=7*mm, bottomMargin=7*mm
)
W = A4[0] - 18*mm # usable width ≈ 174 mm
story = []
# ═══════════════════════════════════════════════════════════
# TITLE BANNER
# ═══════════════════════════════════════════════════════════
title_row = [[
P("ACUTE SEVERE ASTHMA — EMERGENCY QUICK REFERENCE",
size=13, color=white, bold=True, align=TA_CENTER, leading=16),
P("Status Asthmaticus | GINA / BTS Guidelines",
size=7.5, color=C_LIGHT_BLUE, align=TA_CENTER, leading=10),
]]
# flatten to 2 paragraphs in 1 cell, 1 column
banner_data = [[
P("ACUTE SEVERE ASTHMA — EMERGENCY QUICK REFERENCE",
size=13, color=white, bold=True, align=TA_CENTER),
]]
banner_data2 = [[
P("Status Asthmaticus | GINA / BTS / GINA 2024 Guidelines",
size=7.5, color=C_LIGHT_BLUE, align=TA_CENTER),
]]
for bd in [banner_data, banner_data2]:
t = Table(bd, colWidths=[W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_DARK_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),
]))
story.append(t)
story.append(SP(2.5))
# ═══════════════════════════════════════════════════════════
# SECTION 1 – SEVERITY CLASSIFICATION
# ═══════════════════════════════════════════════════════════
def sec_hdr(text, bg):
t = Table([[P(text, size=7.5, color=white, bold=True)]], colWidths=[W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 5),
]))
return t
story.append(sec_hdr("▶ SEVERITY CLASSIFICATION (GINA)", C_MID_BLUE))
sev_cw = [W*0.16, W*0.10, W*0.10, W*0.14, W*0.50]
sev_data = [
# header
[P("Grade", bold=True, color=white), P("PEF", bold=True, color=white),
P("SpO₂", bold=True, color=white), P("PaCO₂", bold=True, color=white),
P("Clinical Features", bold=True, color=white)],
# rows
[P("Mild"), P(">80%"), P("≥95%"), P("Low (↓)"),
P("Mild symptoms; complete sentences; no accessory muscles")],
[P("Moderate"), P("60–80%"), P("92–95%"), P("Low (↓)"),
P("Partial sentences; tachycardia; some accessory muscle use")],
[P("Acute Severe", bold=True), P("<60%", bold=True), P("<92%", bold=True),
P("Low→Normal", bold=True),
P("Single words only; tachycardia; accessory muscles; pulsus paradoxus >10 mmHg", bold=True)],
[P("⚠ LIFE-THREATENING", color=C_RED, bold=True), P("<30%"), P("<92%"),
P("RISING ⚠", color=C_RED, bold=True),
P("Silent chest • Cyanosis • Bradycardia • Hypotension • Confusion / exhaustion")],
]
sev_t = Table(sev_data, colWidths=sev_cw)
sev_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_MID_BLUE),
("BACKGROUND", (0,3), (-1,3), C_LIGHT_ORG),
("BACKGROUND", (0,4), (-1,4), C_LIGHT_RED),
("GRID", (0,0), (-1,-1), 0.3, HexColor("#BDC3C7")),
("TOPPADDING", (0,0), (-1,-1), 2), ("BOTTOMPADDING", (0,0), (-1,-1), 2),
("LEFTPADDING", (0,0), (-1,-1), 3), ("RIGHTPADDING", (0,0), (-1,-1), 3),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(sev_t)
story.append(SP(2.5))
# ═══════════════════════════════════════════════════════════
# SECTION 2 – STEPWISE MANAGEMENT BOXES
# ═══════════════════════════════════════════════════════════
story.append(sec_hdr("▶ STEPWISE MANAGEMENT", C_RED))
steps = [
("STEP 1\nOXYGEN", [
"High-flow O₂ by face mask",
"Target SpO₂ 94–98%",
"Continuous SpO₂ monitoring",
"Hypoxaemia kills – never omit",
], C_GREEN),
("STEP 2\nSABA", [
"Salbutamol 2.5–5mg neb (O₂-driven)",
"OR 4–8 puffs pMDI + spacer",
"Repeat q20min or continuous",
"ECG monitor (arrhythmia risk)",
], C_MID_BLUE),
("STEP 3\nSTEROIDS", [
"Prednisolone 40–50mg PO OD",
"OR Methylprednisolone 125mg IV",
"OR Hydrocortisone 200mg IV",
"Minimum 5 days; taper if severe",
], C_ORANGE),
("STEP 4\nADD-ON", [
"Ipratropium 0.5mg neb q20min×3",
"IV MgSO₄ 1–2g over 20–30 min",
"Monitor BP + DTRs during Mg",
"Consider IV/SC terbutaline",
], C_PURPLE),
("STEP 5\nBiPAP/ETI", [
"BiPAP: IPAP 12–18 / EPAP 6–12",
"RSI: Ketamine 2mg/kg + sux",
"Vent: TV 6–8mL/kg, RR 10–14",
"Permissive hypercapnia; low PEEP",
], C_DARK_RED),
]
# Header row
hdr_row = [P(s[0], size=7, color=white, bold=True, align=TA_CENTER) for s in steps]
# Body rows (each step has 4 body lines)
body_rows = []
for line_i in range(4):
row = []
for s in steps:
row.append(P(s[1][line_i], size=6.2, align=TA_CENTER))
body_rows.append(row)
step_data = [hdr_row] + body_rows
step_t = Table(step_data, colWidths=[W/5]*5)
step_styles = [
("TOPPADDING", (0,0), (-1,-1), 2), ("BOTTOMPADDING", (0,0), (-1,-1), 2),
("LEFTPADDING", (0,0), (-1,-1), 3), ("RIGHTPADDING", (0,0), (-1,-1), 3),
("VALIGN", (0,0), (-1,-1), "TOP"),
("GRID", (0,0), (-1,-1), 0.5, white),
("BACKGROUND", (0,1), (-1,-1), C_GRAY_BG),
("LINEBELOW", (0, len(step_data)-1), (-1, len(step_data)-1), 0.5, HexColor("#BDC3C7")),
]
for i, s in enumerate(steps):
step_styles.append(("BACKGROUND", (i,0), (i,0), s[2]))
step_t.setStyle(TableStyle(step_styles))
story.append(step_t)
story.append(SP(2.5))
# ═══════════════════════════════════════════════════════════
# SECTION 3 – DRUG TABLE
# ═══════════════════════════════════════════════════════════
story.append(sec_hdr("▶ KEY DRUGS AT A GLANCE", C_TEAL))
drug_cw = [W*0.21, W*0.11, W*0.32, W*0.36]
drug_data = [
[P("Drug", bold=True, color=white), P("Route", bold=True, color=white),
P("Dose", bold=True, color=white), P("Notes", bold=True, color=white)],
[P("Salbutamol (SABA)", bold=True), P("Neb / pMDI"),
P("2.5–5mg neb OR 4–8 puffs; repeat q20min"),
P("1st line; O₂-driven nebulisation preferred")],
[P("Salbutamol IV"), P("IV infusion"),
P("250mcg slow IV bolus; then 3–20 mcg/min"),
P("Use if inhaled route unreliable")],
[P("Ipratropium"), P("Neb"),
P("0.5mg q20min × 3 doses, then q4–6h"),
P("Add-on anticholinergic; do not use alone")],
[P("Prednisolone"), P("PO"),
P("40–50mg OD × ≥5 days; taper 2 wks if severe"),
P("Start early; never bronchodilator alone")],
[P("Methylprednisolone"), P("IV"),
P("125mg stat; then 40–80mg q6h"),
P("When PO not tolerated")],
[P("Magnesium sulfate"), P("IV"),
P("1–2g IV over 20–30 min (single dose)"),
P("Life-threatening or poor SABA response; monitor BP + DTRs")],
[P("Ketamine (RSI)"), P("IV"),
P("2 mg/kg induction"),
P("Bronchodilator; preferred induction agent for asthma RSI")],
[P("Aminophylline"), P("IV"),
P("5mg/kg load over 20 min then 0.5mg/kg/h"),
P("⚠ Narrow therapeutic index; monitor levels; last resort")],
]
drug_t = Table(drug_data, colWidths=drug_cw)
drug_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_TEAL),
("ROWBACKGROUNDS", (0,1), (-1,-1), [white, C_LIGHT_GRN]),
("GRID", (0,0), (-1,-1), 0.3, HexColor("#BDC3C7")),
("TOPPADDING", (0,0), (-1,-1), 2), ("BOTTOMPADDING", (0,0), (-1,-1), 2),
("LEFTPADDING", (0,0), (-1,-1), 3), ("RIGHTPADDING", (0,0), (-1,-1), 3),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(drug_t)
story.append(SP(2.5))
# ═══════════════════════════════════════════════════════════
# SECTION 4 – Bottom 3 columns: Ventilation | Disposition | Warnings
# ═══════════════════════════════════════════════════════════
c1w = W * 0.34
c2w = W * 0.34
c3w = W * 0.32
def mini_section(title, bg, lines):
"""Build a bordered box with a coloured header and body lines."""
rows = [[P(title, size=6.8, color=white, bold=True)]]
for item in lines:
if item == "---":
rows.append([SP(0.8)])
elif item.startswith("##"):
rows.append([P(item[2:].strip(), size=6.5, bold=True, color=C_DARK_GRAY)])
elif item.startswith("!"):
rows.append([P(item[1:].strip(), size=6.5, bold=True, color=C_RED)])
else:
rows.append([P(item, size=6.3)])
t = Table(rows)
t_styles = [
("BACKGROUND", (0,0), (0,0), bg),
("BACKGROUND", (0,1), (-1,-1), C_GRAY_BG),
("TOPPADDING", (0,0), (-1,-1), 2), ("BOTTOMPADDING", (0,0), (-1,-1), 2),
("LEFTPADDING", (0,0), (-1,-1), 4), ("RIGHTPADDING", (0,0), (-1,-1), 4),
("BOX", (0,0), (-1,-1), 0.5, HexColor("#BDC3C7")),
("LINEBELOW", (0,0), (0,0), 0.5, HexColor("#BDC3C7")),
]
t.setStyle(TableStyle(t_styles))
return t
vent_box = mini_section("VENTILATION — BiPAP / ETI", C_DARK_BLUE, [
"## BiPAP (try before intubation):",
"• IPAP 12–18 / EPAP 6–12 cmH₂O",
"• Neb meds via BiPAP circuit",
"• Sedation: midazolam 0.05–0.1mg/kg",
" OR ketamine 0.5–1mg/kg IV",
"---",
"## Intubate when:",
"• Deteriorating PEF / SpO₂",
"• Rising PaCO₂ or exhaustion",
"• Altered consciousness / arrest",
"---",
"## Ventilator strategy:",
"• TV 6–8mL/kg | RR 10–14/min",
"• Long expiry (I:E ≥ 1:3)",
"• Low PEEP; accept high PaCO₂",
"• USS: rule out pneumothorax",
"• ECMO if all else fails",
])
disp_box = mini_section("DISPOSITION FROM ED", C_TEAL, [
"## Discharge (PEF ≥60%):",
"• SABA 2–6 puffs q4h till resolved",
"• Prednisolone 40mg OD × 5 days",
"• ICS prescribed / reviewed",
"• Written asthma action plan",
"• Follow-up within 7 days",
"---",
"## Observation/Ward (PEF 40–60%):",
"• Assess risk factors before discharge",
"---",
"## ICU (PEF <40%):",
"• Life-threatening features",
"• Needs/near ventilation",
"---",
"## Admit risk factors:",
"• Prior intubation / ICU",
"• RR >22; SpO₂ <95% on arrival",
"• >8 SABA puffs in last 24h",
"• Prior OCS use",
])
warn_box = mini_section("⚠ WARNINGS & KEY POINTS", C_RED, [
"! NEVER give:",
"✗ Sedatives — suppress ventilation",
"✗ Antibiotics (no pneumonia evidence)",
"✗ Bronchodilators alone — always add CS",
"---",
"## Remember:",
"★ Silent chest = near-complete obstruction",
"★ Normal PaCO₂ in breathless pt = DANGER",
"★ Rising PaCO₂ = impending arrest",
"★ SpO₂ 94–98% — hypoxaemia kills",
"---",
"## Monitor:",
"• Continuous SpO₂ + ECG",
"• Serial PEF q20–30 min",
"• ABG if life-threatening",
"• BP + DTRs during MgSO₄",
"---",
"## CXR — only if:",
"• Suspected pneumothorax",
"• Consolidation / no Rx response",
])
bottom_t = Table([[vent_box, disp_box, warn_box]], colWidths=[c1w, c2w, c3w])
bottom_t.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "TOP"),
("LEFTPADDING", (0,0), (-1,-1), 2),
("RIGHTPADDING", (0,0), (-1,-1), 2),
("TOPPADDING", (0,0), (-1,-1), 0),
("BOTTOMPADDING", (0,0), (-1,-1), 0),
]))
story.append(bottom_t)
story.append(SP(2))
# ═══════════════════════════════════════════════════════════
# FOOTER
# ═══════════════════════════════════════════════════════════
footer_t = Table([[
P("Sources: Fishman's Pulmonary Diseases & Disorders | Tintinalli's Emergency Medicine | Rosen's Emergency Medicine",
size=5.5, color=C_MID_GRAY, italic=True),
P("For use under licensed physician supervision. Not a substitute for clinical judgement.",
size=5.5, color=C_RED, italic=True, align=TA_CENTER),
]], colWidths=[W*0.6, W*0.4])
footer_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_LIGHT_BLUE),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("BOX", (0,0), (-1,-1), 0.4, C_MID_BLUE),
]))
story.append(footer_t)
doc.build(story)
print(f"SUCCESS: {OUTPUT}")
python3 /tmp/workspace/asthma-pdf/build_pdf.py
Acute Severe Asthma QuickRef
PDF Document · PDF
| Section | Content |
|---|---|
| Severity Classification | Color-coded table (Mild → Life-threatening) with PEF, SpO₂, PaCO₂, and clinical features |
| Stepwise Management | 5 color-coded step boxes: Oxygen → SABA → Steroids → Add-on (Ipratropium + MgSO₄) → BiPAP/ETI |
| Key Drugs at a Glance | Drug, route, dose, and notes for all 9 agents including salbutamol, ipratropium, Mg, ketamine, aminophylline |
| Ventilation | BiPAP settings, intubation triggers, permissive hypercapnia strategy, ECMO note |
| Disposition | PEF-based discharge/admit/ICU criteria with risk factor checklist |
| Warnings & Key Points | NEVER give list, red-flag reminders (silent chest, rising PaCO₂), monitoring checklist |