Abg analysis from basic to clinic application
"arterial blood gas" AND "acid-base" interpretation
| Parameter | Normal Range | Meaning |
|---|---|---|
| pH | 7.35 - 7.45 | Acidity/alkalinity of blood |
| PaCO2 | 35 - 45 mmHg | Ventilatory (respiratory) component |
| PaO2 | 80 - 100 mmHg | Oxygenation |
| HCO3- | 22 - 26 mEq/L | Metabolic/renal component |
| Base Excess (BE) | -2 to +2 mEq/L | Net metabolic acid-base deviation |
| SaO2 | 95 - 100% | Hemoglobin oxygen saturation |
pH < 7.35 = acidemia | pH > 7.45 = alkalemia
| Disorder | pH | Primary Change | Compensation |
|---|---|---|---|
| Metabolic Acidosis | Low | ↓ HCO3- | ↓ PaCO2 (hyperventilation) |
| Metabolic Alkalosis | High | ↑ HCO3- | ↑ PaCO2 (hypoventilation) |
| Respiratory Acidosis | Low | ↑ PaCO2 | ↑ HCO3- (renal retention) |
| Respiratory Alkalosis | High | ↓ PaCO2 | ↓ HCO3- (renal excretion) |
| Ratio | Interpretation |
|---|---|
| < 1 | Mixed: high AG + normal AG acidosis |
| 1 - 2 | Pure high AG metabolic acidosis |
| > 2 | Mixed: high AG acidosis + metabolic alkalosis |
| System | Effect |
|---|---|
| Cardiovascular | Impaired myocardial contractility, ↓ cardiac output, ↑ pulmonary vascular resistance, arrhythmias, reduced catecholamine responsiveness |
| Respiratory | Hyperventilation, dyspnea, respiratory muscle fatigue |
| Metabolic | Insulin resistance, ↓ ATP synthesis, hyperkalemia, protein catabolism |
| Cerebral | Altered mental status, coma, inhibited cellular metabolism |
| System | Effect |
|---|---|
| Cardiovascular | Arteriolar constriction, ↓ coronary flow, arrhythmias, left shift of O2 dissociation curve |
| Respiratory | Hypoventilation |
| Metabolic | Hypokalemia, ↓ ionized Ca2+, Mg2+, and phosphate |
| Cerebral | ↓ Cerebral blood flow, tetany, seizures, delirium, coma |
| Condition | PaO2 | PaCO2 | A-a Gradient |
|---|---|---|---|
| Hypoventilation | Low | High | Normal |
| V/Q mismatch | Low | Low/Normal | Elevated |
| Diffusion defect | Low | Normal/Low | Elevated |
| Right-to-left shunt | Low | Low | Elevated (doesn't correct with O2) |
DKA and lactic acidosis are exceptions - they often present with low total body K+ despite acidemia due to osmotic diuresis and poor intake.
1. Is the patient acidemic or alkalemic?
├── pH < 7.35 → Acidemia
└── pH > 7.45 → Alkalemia
2. Is the primary disorder metabolic or respiratory?
├── pH↓ + PaCO2↑ → Respiratory Acidosis
├── pH↑ + PaCO2↓ → Respiratory Alkalosis
├── pH↓ + HCO3-↓ → Metabolic Acidosis
└── pH↑ + HCO3-↑ → Metabolic Alkalosis
3. Is compensation appropriate?
└── If not → Mixed disorder present
├── If high-AG acidosis: Calculate delta-delta ratio
└── Interpret oxygenation: P/F ratio, A-a gradient
Create a quick reference PDF with compensation formulas and MUDPILES mnemonics
ls -la /home/daytona/workspace/
mkdir -p /home/daytona/workspace/abg-reference
~/abg-reference/generate_abg_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, TA_JUSTIFY
from reportlab.platypus import PageBreak
OUTPUT = "/home/daytona/workspace/abg-reference/ABG_Quick_Reference.pdf"
# ── Colour palette ─────────────────────────────────────────────────────────────
NAVY = colors.HexColor("#1a2e4a")
TEAL = colors.HexColor("#0d7377")
GOLD = colors.HexColor("#f0a500")
LIGHT = colors.HexColor("#eaf4f4")
RED_BOX = colors.HexColor("#c0392b")
GREEN = colors.HexColor("#1a7a4a")
ACIDRED = colors.HexColor("#d32f2f")
ALKBLUE = colors.HexColor("#1565c0")
WHITE = colors.white
GREY = colors.HexColor("#f5f5f5")
MID_GREY= colors.HexColor("#cccccc")
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
rightMargin=14*mm, leftMargin=14*mm,
topMargin=14*mm, bottomMargin=14*mm,
title="ABG Quick Reference",
author="Orris Medical"
)
W = A4[0] - 28*mm # usable width
# ── Styles ─────────────────────────────────────────────────────────────────────
base = getSampleStyleSheet()
def S(name, **kw):
return ParagraphStyle(name, **kw)
TITLE_STYLE = S("title_s",
fontSize=22, textColor=WHITE, fontName="Helvetica-Bold",
alignment=TA_CENTER, spaceAfter=2)
SUB_STYLE = S("sub_s",
fontSize=10, textColor=LIGHT, fontName="Helvetica",
alignment=TA_CENTER, spaceAfter=0)
SEC_STYLE = S("sec_s",
fontSize=11, textColor=WHITE, fontName="Helvetica-Bold",
alignment=TA_LEFT, leftIndent=4, spaceAfter=0, spaceBefore=0)
BODY = S("body_s",
fontSize=8.5, textColor=NAVY, fontName="Helvetica",
leading=13, spaceAfter=2)
BOLD_BODY = S("bold_body",
fontSize=8.5, textColor=NAVY, fontName="Helvetica-Bold",
leading=13, spaceAfter=2)
FORMULA = S("formula",
fontSize=9, textColor=TEAL, fontName="Helvetica-Bold",
leading=14, leftIndent=8, spaceAfter=1)
MNEMONIC = S("mnemonic",
fontSize=11, textColor=NAVY, fontName="Helvetica-Bold",
leading=16, spaceAfter=1, alignment=TA_CENTER)
SMALL = S("small_s",
fontSize=7.5, textColor=colors.HexColor("#555555"),
fontName="Helvetica", leading=11)
FOOTER_STYLE = S("footer_s",
fontSize=7, textColor=colors.HexColor("#888888"),
fontName="Helvetica", alignment=TA_CENTER)
# ── Helper: Section header ─────────────────────────────────────────────────────
def section_header(text, bg=NAVY):
data = [[Paragraph(text, SEC_STYLE)]]
t = Table(data, colWidths=[W])
t.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), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("ROWBACKGROUNDS", (0,0), (-1,-1), [bg]),
]))
return t
def hr():
return HRFlowable(width="100%", thickness=0.5, color=MID_GREY, spaceAfter=4, spaceBefore=4)
# ══════════════════════════════════════════════════════════════════════════════
# BUILD STORY
# ══════════════════════════════════════════════════════════════════════════════
story = []
# ── TITLE BANNER ──────────────────────────────────────────────────────────────
banner_data = [[
Paragraph("ABG Quick Reference Card", TITLE_STYLE),
Paragraph("Arterial Blood Gas · Acid-Base · Oxygenation", SUB_STYLE),
]]
banner = Table([[Paragraph("ABG Quick Reference Card", TITLE_STYLE)],
[Paragraph("Arterial Blood Gas · Compensation Formulas · MUDPILES", SUB_STYLE)]],
colWidths=[W])
banner.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), NAVY),
("TOPPADDING", (0,0), (-1,-1), 10),
("BOTTOMPADDING", (0,0), (-1,-1), 10),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
]))
story.append(banner)
story.append(Spacer(1, 5))
# ── ROW 1: Normal Values + Henderson-Hasselbalch ─────────────────────────────
# Left: Normal Values table
nv_header = [
[Paragraph("NORMAL ABG VALUES", S("nh", fontSize=9, fontName="Helvetica-Bold",
textColor=WHITE, alignment=TA_CENTER))]
]
nv_rows = [
["pH", "7.35 – 7.45"],
["PaCO₂", "35 – 45 mmHg"],
["PaO₂", "80 – 100 mmHg"],
["HCO₃⁻", "22 – 26 mEq/L"],
["Base Excess", "−2 to +2 mEq/L"],
["SaO₂", "95 – 100%"],
]
nv_style = TableStyle([
("BACKGROUND", (0,0), (-1,0), TEAL),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("ROWBACKGROUNDS",(0,1), (-1,-1), [GREY, WHITE]),
("TEXTCOLOR", (0,1), (-1,-1), NAVY),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("GRID", (0,0), (-1,-1), 0.4, MID_GREY),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("ALIGN", (1,0), (1,-1), "CENTER"),
])
nv_table_data = [["Parameter", "Normal Range"]] + nv_rows
nv_table = Table(nv_table_data, colWidths=[45*mm, 38*mm])
nv_table.setStyle(nv_style)
# Right: Henderson-Hasselbalch + pH rules
hh_content = [
Paragraph("Henderson–Hasselbalch", S("hh_h", fontSize=9, fontName="Helvetica-Bold",
textColor=TEAL)),
Spacer(1,3),
Paragraph("pH = 6.1 + log₁₀( [HCO₃⁻] / 0.03 × PaCO₂ )", FORMULA),
Spacer(1,6),
Paragraph("Buffers", S("buf_h", fontSize=9, fontName="Helvetica-Bold", textColor=TEAL)),
Spacer(1,3),
Paragraph("• Lungs control PaCO₂ (fast: minutes)", BODY),
Paragraph("• Kidneys control HCO₃⁻ (slow: hours–days)", BODY),
Paragraph("• Bicarbonate buffer: H⁺ + HCO₃⁻ ⇌ H₂CO₃ ⇌ H₂O + CO₂", BODY),
Spacer(1,6),
Paragraph("pH Rules", S("buf_h", fontSize=9, fontName="Helvetica-Bold", textColor=TEAL)),
Spacer(1,3),
Paragraph("pH < 7.35 → Acidemia", S("ar", fontSize=9, fontName="Helvetica-Bold", textColor=ACIDRED)),
Paragraph("pH > 7.45 → Alkalemia", S("al", fontSize=9, fontName="Helvetica-Bold", textColor=ALKBLUE)),
Paragraph("pH 7.35–7.45 → Normal (mixed disorder may still exist!)", BODY),
]
row1 = Table([[nv_table, hh_content]],
colWidths=[87*mm, W - 87*mm - 4*mm],
spaceBefore=0)
row1.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "TOP"),
("LEFTPADDING", (0,0), (-1,-1), 0),
("RIGHTPADDING", (0,0), (-1,-1), 4),
("TOPPADDING", (0,0), (-1,-1), 0),
("BOTTOMPADDING", (0,0), (-1,-1), 0),
]))
story.append(row1)
story.append(Spacer(1, 7))
# ── SECTION: Compensation Formulas ───────────────────────────────────────────
story.append(section_header(" COMPENSATION FORMULAS", NAVY))
story.append(Spacer(1, 4))
comp_rows = [
# header
[
Paragraph("Disorder", S("ch", fontSize=9, fontName="Helvetica-Bold", textColor=WHITE, alignment=TA_CENTER)),
Paragraph("Primary Change", S("ch", fontSize=9, fontName="Helvetica-Bold", textColor=WHITE, alignment=TA_CENTER)),
Paragraph("Compensation", S("ch", fontSize=9, fontName="Helvetica-Bold", textColor=WHITE, alignment=TA_CENTER)),
Paragraph("Formula", S("ch", fontSize=9, fontName="Helvetica-Bold", textColor=WHITE, alignment=TA_CENTER)),
Paragraph("Onset", S("ch", fontSize=9, fontName="Helvetica-Bold", textColor=WHITE, alignment=TA_CENTER)),
],
# Metabolic Acidosis
[
Paragraph("Metabolic\nAcidosis", S("d", fontSize=8.5, fontName="Helvetica-Bold", textColor=ACIDRED, leading=12)),
Paragraph("↓ HCO₃⁻\n↓ pH", S("d", fontSize=8.5, fontName="Helvetica", textColor=NAVY, leading=12)),
Paragraph("↓ PaCO₂\n(hyperventilation)", S("d", fontSize=8.5, fontName="Helvetica", textColor=NAVY, leading=12)),
Paragraph("Winter's: PaCO₂ = 1.5×[HCO₃⁻] + 8 ± 2\nor ΔPaCO₂ = 1.1 × ΔHCO₃⁻",
S("f", fontSize=8.5, fontName="Helvetica-Bold", textColor=TEAL, leading=13)),
Paragraph("12–24 h", S("d", fontSize=8.5, fontName="Helvetica", textColor=NAVY, leading=12)),
],
# Metabolic Alkalosis
[
Paragraph("Metabolic\nAlkalosis", S("d", fontSize=8.5, fontName="Helvetica-Bold", textColor=ALKBLUE, leading=12)),
Paragraph("↑ HCO₃⁻\n↑ pH", S("d", fontSize=8.5, fontName="Helvetica", textColor=NAVY, leading=12)),
Paragraph("↑ PaCO₂\n(hypoventilation)", S("d", fontSize=8.5, fontName="Helvetica", textColor=NAVY, leading=12)),
Paragraph("PaCO₂ = 0.7×[HCO₃⁻] + 20 ± 5\nor ΔPaCO₂ = 0.75 × ΔHCO₃⁻",
S("f", fontSize=8.5, fontName="Helvetica-Bold", textColor=TEAL, leading=13)),
Paragraph("24–48 h", S("d", fontSize=8.5, fontName="Helvetica", textColor=NAVY, leading=12)),
],
# Respiratory Acidosis Acute
[
Paragraph("Respiratory\nAcidosis\n(ACUTE)", S("d", fontSize=8.5, fontName="Helvetica-Bold", textColor=ACIDRED, leading=12)),
Paragraph("↑ PaCO₂\n↓ pH", S("d", fontSize=8.5, fontName="Helvetica", textColor=NAVY, leading=12)),
Paragraph("↑ HCO₃⁻\n(renal retention)", S("d", fontSize=8.5, fontName="Helvetica", textColor=NAVY, leading=12)),
Paragraph("ΔHCO₃⁻ = +1 mEq/L per ↑10 mmHg PaCO₂\nΔpH = −0.08 per ↑10 mmHg PaCO₂",
S("f", fontSize=8.5, fontName="Helvetica-Bold", textColor=TEAL, leading=13)),
Paragraph("Minutes\n(immediate)", S("d", fontSize=8.5, fontName="Helvetica", textColor=NAVY, leading=12)),
],
# Respiratory Acidosis Chronic
[
Paragraph("Respiratory\nAcidosis\n(CHRONIC)", S("d", fontSize=8.5, fontName="Helvetica-Bold", textColor=colors.HexColor("#b71c1c"), leading=12)),
Paragraph("↑ PaCO₂\n↓ pH", S("d", fontSize=8.5, fontName="Helvetica", textColor=NAVY, leading=12)),
Paragraph("↑ HCO₃⁻\n(full renal)", S("d", fontSize=8.5, fontName="Helvetica", textColor=NAVY, leading=12)),
Paragraph("ΔHCO₃⁻ = +4 mEq/L per ↑10 mmHg PaCO₂\nΔpH = −0.03 per ↑10 mmHg PaCO₂",
S("f", fontSize=8.5, fontName="Helvetica-Bold", textColor=TEAL, leading=13)),
Paragraph("48–96 h", S("d", fontSize=8.5, fontName="Helvetica", textColor=NAVY, leading=12)),
],
# Respiratory Alkalosis Acute
[
Paragraph("Respiratory\nAlkalosis\n(ACUTE)", S("d", fontSize=8.5, fontName="Helvetica-Bold", textColor=ALKBLUE, leading=12)),
Paragraph("↓ PaCO₂\n↑ pH", S("d", fontSize=8.5, fontName="Helvetica", textColor=NAVY, leading=12)),
Paragraph("↓ HCO₃⁻\n(renal loss)", S("d", fontSize=8.5, fontName="Helvetica", textColor=NAVY, leading=12)),
Paragraph("ΔHCO₃⁻ = −2 mEq/L per ↓10 mmHg PaCO₂",
S("f", fontSize=8.5, fontName="Helvetica-Bold", textColor=TEAL, leading=13)),
Paragraph("Minutes\n(immediate)", S("d", fontSize=8.5, fontName="Helvetica", textColor=NAVY, leading=12)),
],
# Respiratory Alkalosis Chronic
[
Paragraph("Respiratory\nAlkalosis\n(CHRONIC)", S("d", fontSize=8.5, fontName="Helvetica-Bold", textColor=colors.HexColor("#0d47a1"), leading=12)),
Paragraph("↓ PaCO₂\n↑ pH", S("d", fontSize=8.5, fontName="Helvetica", textColor=NAVY, leading=12)),
Paragraph("↓ HCO₃⁻\n(full renal)", S("d", fontSize=8.5, fontName="Helvetica", textColor=NAVY, leading=12)),
Paragraph("ΔHCO₃⁻ = −4 to −5 mEq/L per ↓10 mmHg PaCO₂",
S("f", fontSize=8.5, fontName="Helvetica-Bold", textColor=TEAL, leading=13)),
Paragraph("48–96 h", S("d", fontSize=8.5, fontName="Helvetica", textColor=NAVY, leading=12)),
],
]
comp_table = Table(comp_rows,
colWidths=[30*mm, 25*mm, 32*mm, 68*mm, 22*mm])
comp_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("ROWBACKGROUNDS",(0,1), (-1,-1), [GREY, WHITE, colors.HexColor("#fff0f0"),
colors.HexColor("#ffe8e8"),
colors.HexColor("#e8f0ff"), colors.HexColor("#ddeeff")]),
("GRID", (0,0), (-1,-1), 0.4, MID_GREY),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 4),
("ALIGN", (0,0), (-1,0), "CENTER"),
]))
story.append(comp_table)
story.append(Spacer(1, 7))
# ── ROW 3: MUDPILES + Delta-Delta in two columns ──────────────────────────────
story.append(section_header(" METABOLIC ACIDOSIS CLASSIFICATION & TOOLS", NAVY))
story.append(Spacer(1, 4))
# Left: MUDPILES
mudpiles_letter_style = S("ml", fontSize=16, fontName="Helvetica-Bold",
textColor=GOLD, leading=20)
mudpiles_text_style = S("mt", fontSize=8.5, fontName="Helvetica",
textColor=NAVY, leading=13)
mudpiles_bold_style = S("mb", fontSize=8.5, fontName="Helvetica-Bold",
textColor=NAVY, leading=13)
mudpiles_items = [
("M", "Methanol"),
("U", "Uremia (renal failure)"),
("D", "DKA / Diabetic Ketoacidosis\n (also: alcoholic, starvation)"),
("P", "Propylene glycol / Paraldehyde"),
("I", "Isoniazid / Iron"),
("L", "Lactic Acidosis (sepsis, ischemia,\n metformin, mitochondrial)"),
("E", "Ethylene Glycol"),
("S", "Salicylates"),
]
mudpiles_rows = [[Paragraph(l, mudpiles_letter_style), Paragraph(t, mudpiles_text_style)]
for l, t in mudpiles_items]
mudpiles_header = [[
Paragraph("MUDPILES — High Anion Gap Metabolic Acidosis",
S("mh", fontSize=9, fontName="Helvetica-Bold", textColor=WHITE)),
""
]]
mudpiles_data = mudpiles_header + mudpiles_rows
mudpiles_table = Table(mudpiles_data, colWidths=[12*mm, 75*mm])
mudpiles_table.setStyle(TableStyle([
("SPAN", (0,0), (1,0)),
("BACKGROUND", (0,0), (-1,0), RED_BOX),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("ROWBACKGROUNDS",(0,1), (-1,-1), [colors.HexColor("#fff8e1"), colors.HexColor("#fff3cd")] * 5),
("GRID", (0,0), (-1,-1), 0.4, MID_GREY),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("ALIGN", (0,1), (0,-1), "CENTER"),
]))
# Right column: Anion Gap + Non-AG + Delta-Delta
right_content_items = []
# Anion Gap formula box
ag_box_data = [[
Paragraph("Anion Gap Formula", S("agb_h", fontSize=9, fontName="Helvetica-Bold", textColor=WHITE)),
]],[
Paragraph("AG = [Na⁺] − ([Cl⁻] + [HCO₃⁻])", FORMULA),
Paragraph("Normal: 8–12 mEq/L (up to 13 mEq/L)", BODY),
Paragraph("⚠ Albumin Correction: Add 2.5 mEq/L per\n 1 g/dL albumin below 4 g/dL", BODY),
]]
ag_box = Table([
[Paragraph("Anion Gap Formula", S("agb_h", fontSize=9, fontName="Helvetica-Bold", textColor=WHITE))],
[Paragraph("AG = [Na⁺] − ([Cl⁻] + [HCO₃⁻])", FORMULA)],
[Paragraph("Normal: 8–12 mEq/L (up to 13 mEq/L)", BODY)],
[Paragraph("⚠ Albumin correction: +2.5 per 1 g/dL below 4", BODY)],
], colWidths=[W - 87*mm - 6*mm])
ag_box.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), GREEN),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("BACKGROUND", (0,1), (-1,-1), colors.HexColor("#e8f5e9")),
("GRID", (0,0), (-1,-1), 0.4, MID_GREY),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
]))
# Non-AG causes
nonag_rows = [
[Paragraph("NON-AG (Hyperchloremic) Acidosis",
S("nah", fontSize=9, fontName="Helvetica-Bold", textColor=WHITE))],
[Paragraph("D Diarrhea (GI HCO₃⁻ loss)", BODY)],
[Paragraph("R Renal Tubular Acidosis (RTA I, II, IV)", BODY)],
[Paragraph("U Ureteral diversion", BODY)],
[Paragraph("G Go easy on saline (0.9% NaCl resuscitation)", BODY)],
[Paragraph("S acetazolamide (Carbonic anhydrase inhibitors)", BODY)],
]
nonag_table = Table(nonag_rows, colWidths=[W - 87*mm - 6*mm])
nonag_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), colors.HexColor("#455a64")),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("ROWBACKGROUNDS",(0,1), (-1,-1), [colors.HexColor("#eceff1"), WHITE] * 5),
("GRID", (0,0), (-1,-1), 0.4, MID_GREY),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
]))
# Delta-Delta
dd_rows = [
[Paragraph("Delta–Delta Ratio (High-AG only)",
S("ddh", fontSize=9, fontName="Helvetica-Bold", textColor=WHITE)), ""],
[Paragraph("ΔAG / ΔHCO₃⁻ = (AG−12) / (24−HCO₃⁻)",
S("ddf", fontSize=9, fontName="Helvetica-Bold", textColor=TEAL)), ""],
[Paragraph("< 1", S("d1", fontSize=9, fontName="Helvetica-Bold", textColor=ACIDRED)),
Paragraph("Mixed: High-AG + Normal-AG acidosis", BODY)],
[Paragraph("1 – 2", S("d2", fontSize=9, fontName="Helvetica-Bold", textColor=GREEN)),
Paragraph("Pure High-AG metabolic acidosis", BODY)],
[Paragraph("> 2", S("d3", fontSize=9, fontName="Helvetica-Bold", textColor=ALKBLUE)),
Paragraph("Mixed: High-AG acidosis + Metabolic alkalosis", BODY)],
]
dd_table = Table(dd_rows, colWidths=[18*mm, W - 87*mm - 6*mm - 18*mm])
dd_table.setStyle(TableStyle([
("SPAN", (0,0), (1,0)),
("SPAN", (0,1), (1,1)),
("BACKGROUND", (0,0), (-1,0), TEAL),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("BACKGROUND", (0,1), (-1,1), colors.HexColor("#e0f7f7")),
("ROWBACKGROUNDS",(0,2), (-1,-1), [colors.HexColor("#fce4ec"),
colors.HexColor("#e8f5e9"),
colors.HexColor("#e3f2fd")]),
("GRID", (0,0), (-1,-1), 0.4, MID_GREY),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("ALIGN", (0,2), (0,-1), "CENTER"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
]))
right_stack = Table([
[ag_box],
[Spacer(1, 4)],
[nonag_table],
[Spacer(1, 4)],
[dd_table],
], colWidths=[W - 87*mm - 4*mm])
right_stack.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), 0),
]))
mud_row = Table([[mudpiles_table, right_stack]],
colWidths=[90*mm, W - 90*mm - 2*mm])
mud_row.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "TOP"),
("LEFTPADDING", (0,0), (-1,-1), 0),
("RIGHTPADDING", (0,0), (-1,-1), 3),
("TOPPADDING", (0,0), (-1,-1), 0),
("BOTTOMPADDING", (0,0), (-1,-1), 0),
]))
story.append(mud_row)
story.append(Spacer(1, 7))
# ── SECTION: Step-by-step approach ────────────────────────────────────────────
story.append(section_header(" STEP-BY-STEP ABG INTERPRETATION", TEAL))
story.append(Spacer(1, 4))
steps = [
("1", "Is the patient acidemic or alkalemic?",
"pH < 7.35 → Acidemia | pH > 7.45 → Alkalemia | Normal pH does NOT rule out a mixed disorder"),
("2", "Identify the PRIMARY disorder",
"pH↓ + PaCO₂↑ → Resp. Acidosis | pH↑ + PaCO₂↓ → Resp. Alkalosis\n"
"pH↓ + HCO₃⁻↓ → Met. Acidosis | pH↑ + HCO₃⁻↑ → Met. Alkalosis"),
("3", "Is compensation APPROPRIATE?",
"Apply formulas above. If values fall outside expected range → Mixed disorder present"),
("4", "Calculate Anion Gap (if met. acidosis)",
"AG = Na⁺ − (Cl⁻ + HCO₃⁻). Correct for albumin. If AG elevated → apply Delta–Delta ratio"),
("5", "Assess OXYGENATION",
"P/F ratio = PaO₂/FiO₂ (Normal >400 | Mild ARDS 200–300 | Mod 100–200 | Severe <100)\n"
"A-a gradient = PAO₂ − PaO₂ (PAO₂ = 150 − PaCO₂/0.8 on room air) Normal <15 mmHg"),
]
step_rows = []
for num, title, detail in steps:
step_rows.append([
Paragraph(num, S("sn", fontSize=14, fontName="Helvetica-Bold",
textColor=WHITE, alignment=TA_CENTER)),
Paragraph(title, S("st", fontSize=9, fontName="Helvetica-Bold", textColor=NAVY)),
Paragraph(detail, S("sd", fontSize=8, fontName="Helvetica", textColor=NAVY, leading=12)),
])
steps_table = Table(step_rows, colWidths=[10*mm, 52*mm, W - 62*mm - 2*mm])
steps_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,-1), TEAL),
("ROWBACKGROUNDS",(1,0), (-1,-1), [GREY, WHITE] * 5),
("GRID", (0,0), (-1,-1), 0.4, MID_GREY),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("ALIGN", (0,0), (0,-1), "CENTER"),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("LINEBELOW", (0,0), (-1,-2), 0.5, MID_GREY),
]))
story.append(steps_table)
story.append(Spacer(1, 7))
# ── SECTION: Clinical consequences + worked example in 2 columns ─────────────
story.append(section_header(" PHYSIOLOGIC CONSEQUENCES & WORKED EXAMPLE", NAVY))
story.append(Spacer(1, 4))
# Left: consequences tables
acid_rows = [
[Paragraph("SEVERE ACIDEMIA (pH < 7.2)", S("ah", fontSize=9, fontName="Helvetica-Bold", textColor=WHITE)),
Paragraph("SEVERE ALKALEMIA (pH > 7.6)", S("alh", fontSize=9, fontName="Helvetica-Bold", textColor=WHITE))],
[Paragraph("CV: ↓ contractility, ↑ PVR, arrhythmias\n reduced catecholamine response",
S("d", fontSize=8, fontName="Helvetica", textColor=NAVY, leading=12)),
Paragraph("CV: arteriolar constriction, ↓ coronary flow\n arrhythmias, left-shift O₂ curve",
S("d", fontSize=8, fontName="Helvetica", textColor=NAVY, leading=12))],
[Paragraph("Resp: hyperventilation, dyspnea\n respiratory muscle fatigue",
S("d", fontSize=8, fontName="Helvetica", textColor=NAVY, leading=12)),
Paragraph("Resp: hypoventilation",
S("d", fontSize=8, fontName="Helvetica", textColor=NAVY, leading=12))],
[Paragraph("Metabolic: insulin resistance, ↓ ATP\n HYPERKALEMIA, protein catabolism",
S("d", fontSize=8, fontName="Helvetica-Bold", textColor=ACIDRED, leading=12)),
Paragraph("Metabolic: HYPOKALEMIA\n ↓ ionized Ca²⁺, Mg²⁺, phosphate",
S("d", fontSize=8, fontName="Helvetica-Bold", textColor=ALKBLUE, leading=12))],
[Paragraph("Cerebral: AMS, coma,\n inhibited cellular metabolism",
S("d", fontSize=8, fontName="Helvetica", textColor=NAVY, leading=12)),
Paragraph("Cerebral: ↓ CBF, tetany, seizures\n delirium, coma",
S("d", fontSize=8, fontName="Helvetica", textColor=NAVY, leading=12))],
]
conseq_table = Table(acid_rows, colWidths=[(W*0.52)/2]*2)
conseq_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), ACIDRED),
("BACKGROUND", (1,0), (1,0), ALKBLUE),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("ROWBACKGROUNDS",(0,1), (-1,-1), [colors.HexColor("#fce4ec"), colors.HexColor("#fff"),
colors.HexColor("#ffebee"), colors.HexColor("#fff")]),
("GRID", (0,0), (-1,-1), 0.4, MID_GREY),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
]))
# Right: Worked example - Salicylate toxicity
example_content = [
Paragraph("Worked Example: Salicylate Toxicity",
S("ex_h", fontSize=9, fontName="Helvetica-Bold", textColor=WHITE)),
]
eg_box_data = [
[Paragraph("Worked Example: Salicylate Toxicity",
S("ex_h", fontSize=9, fontName="Helvetica-Bold", textColor=WHITE))],
[Paragraph("ABG: pH 7.47 / PaCO₂ 25 mmHg / PaO₂ 180 mmHg",
S("eg", fontSize=8.5, fontName="Helvetica-Bold", textColor=NAVY))],
[Paragraph("Step 1: pH 7.47 → Alkalemia", BODY)],
[Paragraph("Step 2: PaCO₂ low (25) + pH high → Respiratory alkalosis", BODY)],
[Paragraph("Step 3: Expected pH = 7.40 + [(40−25)/10 × 0.08] = 7.52\n"
"Measured 7.47 < predicted 7.52 → concurrent Metabolic acidosis",
S("eg3", fontSize=8.5, fontName="Helvetica-Bold", textColor=RED_BOX, leading=13))],
[Paragraph("✓ Diagnosis: Mixed Respiratory Alkalosis + Metabolic Acidosis",
S("eg4", fontSize=9, fontName="Helvetica-Bold", textColor=GREEN))],
[Spacer(1, 3)],
[Paragraph("K⁺ – pH Relationship",
S("kph_h", fontSize=9, fontName="Helvetica-Bold", textColor=TEAL))],
[Paragraph("Each ↓0.10 pH unit → K⁺ rises ~0.6 mEq/L\n"
"Metabolic acidosis → Hyperkalemia (exception: DKA, lactic acidosis)\n"
"Metabolic alkalosis → Hypokalemia", BODY)],
]
eg_box = Table(eg_box_data, colWidths=[W - (W*0.52) - 4*mm])
eg_box.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), GOLD),
("TEXTCOLOR", (0,0), (-1,0), NAVY),
("BACKGROUND", (0,1), (-1,-1), colors.HexColor("#fffde7")),
("GRID", (0,0), (-1,-1), 0.4, MID_GREY),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
]))
conseq_row = Table([[conseq_table, eg_box]],
colWidths=[W*0.52, W - W*0.52 - 2*mm])
conseq_row.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "TOP"),
("LEFTPADDING", (0,0), (-1,-1), 0),
("RIGHTPADDING", (0,0), (-1,-1), 3),
("TOPPADDING", (0,0), (-1,-1), 0),
("BOTTOMPADDING", (0,0), (-1,-1), 0),
]))
story.append(conseq_row)
story.append(Spacer(1, 7))
# ── FOOTER ────────────────────────────────────────────────────────────────────
story.append(hr())
story.append(Paragraph(
"Sources: Barash Clinical Anesthesia 9e · Brenner & Rector's The Kidney · Rosen's Emergency Medicine · "
"Sanagustín & Osredkar, Med Int 2026 [PMID 41473681] · Habib et al., S Afr Fam Pract 2025 [PMID 40336441]",
SMALL))
story.append(Spacer(1, 2))
story.append(Paragraph("Generated by Orris Medical AI · For educational use only · Always verify against current clinical guidelines",
FOOTER_STYLE))
# ── BUILD ──────────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF written to {OUTPUT}")
cd /home/daytona/workspace/abg-reference && python generate_abg_pdf.py 2>&1
~/abg-reference/generate_abg_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/abg-reference/generate_abg_pdf.py'
cd /home/daytona/workspace/abg-reference && python generate_abg_pdf.py 2>&1
ABG Quick Reference
PDF Document · PDF