Metabolic Acidosis pdf
mkdir -p /home/daytona/workspace/metabolic-acidosis && ls /home/daytona/workspace/metabolic-acidosis/
~/metabolic-acidosis/generate_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm
from reportlab.lib.colors import HexColor, black, white
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether
)
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.lib import colors
OUTPUT = "/home/daytona/workspace/metabolic-acidosis/Metabolic_Acidosis.pdf"
# Colors
DARK_BLUE = HexColor("#1a3a5c")
MID_BLUE = HexColor("#2c6496")
LIGHT_BLUE = HexColor("#d6e8f7")
ACCENT = HexColor("#e74c3c")
LIGHT_GRAY = HexColor("#f5f5f5")
BORDER_GRAY = HexColor("#cccccc")
GREEN = HexColor("#27ae60")
ORANGE = HexColor("#e67e22")
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
rightMargin=2*cm, leftMargin=2*cm,
topMargin=2*cm, bottomMargin=2*cm
)
styles = getSampleStyleSheet()
# Custom styles
title_style = ParagraphStyle(
'CustomTitle', fontSize=26, textColor=white,
fontName='Helvetica-Bold', alignment=TA_CENTER, leading=32,
spaceAfter=6
)
subtitle_style = ParagraphStyle(
'Subtitle', fontSize=12, textColor=LIGHT_BLUE,
fontName='Helvetica', alignment=TA_CENTER, leading=16
)
h1_style = ParagraphStyle(
'H1', fontSize=16, textColor=white,
fontName='Helvetica-Bold', alignment=TA_LEFT, leading=20,
spaceBefore=14, spaceAfter=6,
leftIndent=0, rightIndent=0,
backColor=MID_BLUE,
borderPad=(6, 8, 6, 8)
)
h2_style = ParagraphStyle(
'H2', fontSize=13, textColor=DARK_BLUE,
fontName='Helvetica-Bold', alignment=TA_LEFT, leading=17,
spaceBefore=12, spaceAfter=4,
borderPad=4
)
h3_style = ParagraphStyle(
'H3', fontSize=11, textColor=MID_BLUE,
fontName='Helvetica-Bold', alignment=TA_LEFT, leading=14,
spaceBefore=8, spaceAfter=3
)
body_style = ParagraphStyle(
'Body', fontSize=10, textColor=black,
fontName='Helvetica', alignment=TA_JUSTIFY, leading=15,
spaceAfter=6
)
bullet_style = ParagraphStyle(
'Bullet', fontSize=10, textColor=black,
fontName='Helvetica', alignment=TA_LEFT, leading=14,
leftIndent=16, spaceAfter=3,
bulletIndent=6
)
formula_style = ParagraphStyle(
'Formula', fontSize=10.5, textColor=DARK_BLUE,
fontName='Helvetica-Bold', alignment=TA_CENTER, leading=14,
spaceAfter=6, spaceBefore=4,
backColor=LIGHT_BLUE, borderPad=8,
borderColor=MID_BLUE, borderWidth=1,
leftIndent=20, rightIndent=20
)
caption_style = ParagraphStyle(
'Caption', fontSize=9, textColor=HexColor("#555555"),
fontName='Helvetica-Oblique', alignment=TA_CENTER, leading=12
)
source_style = ParagraphStyle(
'Source', fontSize=8, textColor=HexColor("#777777"),
fontName='Helvetica', alignment=TA_LEFT, leading=11,
spaceAfter=2
)
warning_style = ParagraphStyle(
'Warning', fontSize=10, textColor=HexColor("#7d2020"),
fontName='Helvetica', alignment=TA_LEFT, leading=14,
leftIndent=8, spaceAfter=3
)
def section_header(text):
"""Returns a blue section header paragraph."""
return Paragraph(f" {text}", h1_style)
def make_key_box(content_rows, bg=LIGHT_BLUE, border=MID_BLUE):
"""Renders a shaded key-fact box as a 1-col table."""
cells = [[Paragraph(row, bullet_style)] for row in content_rows]
t = Table(cells, colWidths=[16.5*cm])
t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,-1), bg),
('BOX', (0,0), (-1,-1), 1, border),
('TOPPADDING', (0,0), (-1,-1), 4),
('BOTTOMPADDING', (0,0), (-1,-1), 4),
('LEFTPADDING', (0,0), (-1,-1), 10),
]))
return t
story = []
# ── COVER BANNER ─────────────────────────────────────────────────────────────
cover = Table(
[[Paragraph("METABOLIC ACIDOSIS", title_style)],
[Paragraph("A Comprehensive Clinical Reference", subtitle_style)],
[Paragraph("Pathophysiology • Classification • Diagnosis • Management", subtitle_style)]],
colWidths=[16.5*cm]
)
cover.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,-1), DARK_BLUE),
('BOX', (0,0), (-1,-1), 2, MID_BLUE),
('TOPPADDING', (0,0), (-1,-1), 18),
('BOTTOMPADDING', (0,0), (-1,-1), 18),
('LEFTPADDING', (0,0), (-1,-1), 12),
]))
story.append(cover)
story.append(Spacer(1, 0.5*cm))
story.append(Paragraph(
"Sources: Harrison's Principles of Internal Medicine 22E (2025) | Rosen's Emergency Medicine | "
"Barash's Clinical Anesthesia 9E | Frameworks for Internal Medicine | Brenner & Rector's The Kidney",
source_style
))
story.append(HRFlowable(width="100%", thickness=1, color=BORDER_GRAY))
story.append(Spacer(1, 0.3*cm))
# ── 1. DEFINITION & OVERVIEW ──────────────────────────────────────────────────
story.append(section_header("1. Definition & Overview"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"Metabolic acidosis is an acid-base disorder characterized by a primary decrease in serum bicarbonate "
"(HCO<sub rise='3'>3</sub><sup>−</sup>) concentration, resulting in a fall in arterial blood pH. "
"It arises either from gain of non-volatile acid (which consumes HCO<sub rise='3'>3</sub><sup>−</sup>) "
"or from direct loss of bicarbonate from the body. Unlike respiratory acidosis, the primary disturbance "
"is metabolic rather than ventilatory.", body_style
))
story.append(Paragraph(
"The physiological response is compensatory hyperventilation (Kussmaul respiration), which lowers "
"PaCO<sub rise='2'>2</sub> and partially restores pH toward normal. Complete normalization of pH does not "
"occur through respiratory compensation alone.", body_style
))
key_facts = [
"• Normal serum HCO<sub rise='3'>3</sub><sup>−</sup>: 22–26 mEq/L",
"• Normal arterial pH: 7.35–7.45",
"• Metabolic acidosis: HCO<sub rise='3'>3</sub><sup>−</sup> < 22 mEq/L with pH < 7.35",
"• Anion gap (AG) = Na<sup>+</sup> − (Cl<sup>−</sup> + HCO<sub rise='3'>3</sub><sup>−</sup>) | Normal AG: 6–12 mEq/L (avg ~10 mEq/L)",
]
story.append(make_key_box(key_facts))
story.append(Spacer(1, 0.3*cm))
# ── 2. PATHOPHYSIOLOGY ────────────────────────────────────────────────────────
story.append(section_header("2. Pathophysiology"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"The body normally generates ~1 mEq/kg/day of non-volatile acid from protein catabolism and cellular "
"metabolism. These are excreted by the kidneys as titratable acid (primarily phosphate) and ammonium "
"(NH<sub rise='4'>4</sub><sup>+</sup>). Disruption of this balance leads to acid accumulation.", body_style
))
story.append(Paragraph("Buffering Systems", h3_style))
story.append(Paragraph(
"Excess H<sup>+</sup> is initially buffered by extracellular bicarbonate, intracellular proteins, "
"hemoglobin, and phosphate. The Henderson-Hasselbalch equation governs the relationship:", body_style
))
story.append(Paragraph(
"pH = 6.1 + log([HCO3<sup>−</sup>] / 0.03 × PaCO2)",
formula_style
))
story.append(Paragraph("Respiratory Compensation (Winters' Formula)", h3_style))
story.append(Paragraph(
"In metabolic acidosis, peripheral and central chemoreceptors detect the fall in pH and stimulate "
"increased ventilation. The expected compensatory PaCO<sub rise='2'>2</sub> is predicted by Winters' formula:", body_style
))
story.append(Paragraph(
"Expected PaCO2 = (1.5 × [HCO3<sup>−</sup>]) + 8 ± 2 mmHg",
formula_style
))
story.append(Paragraph(
"If measured PaCO<sub rise='2'>2</sub> is <b>higher</b> than predicted → concurrent <b>respiratory acidosis</b>. "
"If <b>lower</b> → concurrent <b>respiratory alkalosis</b>.",
body_style
))
story.append(Spacer(1, 0.3*cm))
# ── 3. CLASSIFICATION ─────────────────────────────────────────────────────────
story.append(section_header("3. Classification by Anion Gap"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"The anion gap is the cornerstone of metabolic acidosis classification. "
"It represents unmeasured anions in plasma (albumin, phosphate, sulfate, organic anions). "
"Always <b>correct for hypoalbuminemia</b>: add 2.5 mEq/L to the AG for each 1 g/dL that albumin "
"falls below 4.5 g/dL.", body_style
))
story.append(Paragraph(
"Corrected AG = Measured AG + 2.5 × (4.5 − serum albumin [g/dL])",
formula_style
))
# Classification table
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph("Table 1: Classification of Metabolic Acidosis", h2_style))
class_data = [
[Paragraph("<b>Feature</b>", body_style),
Paragraph("<b>High AG (Wide AG)</b>", body_style),
Paragraph("<b>Normal AG (Hyperchloremic)</b>", body_style)],
[Paragraph("AG threshold", body_style),
Paragraph("> 12–13 mEq/L", body_style),
Paragraph("≤ 12 mEq/L", body_style)],
[Paragraph("Chloride", body_style),
Paragraph("Normal", body_style),
Paragraph("Elevated (hyperchloremia)", body_style)],
[Paragraph("Mechanism", body_style),
Paragraph("Accumulation of unmeasured anions", body_style),
Paragraph("Loss of HCO3− or impaired acid excretion", body_style)],
[Paragraph("Key mnemonic", body_style),
Paragraph("MUDPILES", body_style),
Paragraph("HARDUP", body_style)],
]
ct = Table(class_data, colWidths=[4.5*cm, 6*cm, 6*cm])
ct.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), MID_BLUE),
('TEXTCOLOR', (0,0), (-1,0), white),
('BACKGROUND', (0,1), (-1,-1), LIGHT_GRAY),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, LIGHT_GRAY]),
('GRID', (0,0), (-1,-1), 0.5, BORDER_GRAY),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
]))
story.append(ct)
story.append(Spacer(1, 0.3*cm))
# ── 4. HIGH AG ACIDOSIS ───────────────────────────────────────────────────────
story.append(section_header("4. High Anion Gap Metabolic Acidosis"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"A high-AG acidosis results from accumulation of acid anions that replace bicarbonate but are not "
"measured in the standard electrolyte panel. There are four principal categories:", body_style
))
# MUDPILES table
story.append(Paragraph("Mnemonic: MUDPILES", h2_style))
mudpiles_data = [
[Paragraph("<b>Letter</b>", body_style), Paragraph("<b>Cause</b>", body_style), Paragraph("<b>Accumulated Anion / Notes</b>", body_style)],
[Paragraph("M", body_style), Paragraph("Methanol", body_style), Paragraph("Formate; causes visual disturbance, high osmolar gap", body_style)],
[Paragraph("U", body_style), Paragraph("Uremia (kidney failure)", body_style), Paragraph("Sulfate, phosphate, hippurate; nonmetabolizable", body_style)],
[Paragraph("D", body_style), Paragraph("Diabetic / Alcoholic / Starvation Ketoacidosis", body_style), Paragraph("β-hydroxybutyrate, acetoacetate; metabolizable", body_style)],
[Paragraph("P", body_style), Paragraph("Paraldehyde / Propylene glycol / Paracetamol (acetaminophen)", body_style), Paragraph("Organic acids; drug toxicity", body_style)],
[Paragraph("I", body_style), Paragraph("Iron / Isoniazid", body_style), Paragraph("Lactic acidosis (secondary); overdose scenarios", body_style)],
[Paragraph("L", body_style), Paragraph("Lactic acidosis", body_style), Paragraph("L-lactate; most common cause (~50% of wide-AG cases)", body_style)],
[Paragraph("E", body_style), Paragraph("Ethylene glycol", body_style), Paragraph("Glycolate, oxalate; renal failure, oxalate crystaluria", body_style)],
[Paragraph("S", body_style), Paragraph("Salicylates", body_style), Paragraph("Salicylate anion; also causes respiratory alkalosis", body_style)],
]
mt = Table(mudpiles_data, colWidths=[1.5*cm, 5.5*cm, 9.5*cm])
mt.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), DARK_BLUE),
('TEXTCOLOR', (0,0), (-1,0), white),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, LIGHT_BLUE]),
('GRID', (0,0), (-1,-1), 0.5, BORDER_GRAY),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
('FONTNAME', (0,1), (0,-1), 'Helvetica-Bold'),
('TEXTCOLOR', (0,1), (0,-1), ACCENT),
]))
story.append(mt)
story.append(Spacer(1, 0.3*cm))
story.append(Paragraph("4.1 Lactic Acidosis", h2_style))
story.append(Paragraph(
"Lactic acidosis is the <b>most common</b> cause of high-AG metabolic acidosis. Plasma L-lactate "
"rises when tissue oxygen delivery is insufficient (Type A) or when mitochondrial metabolism is "
"impaired (Type B).", body_style
))
lactic_data = [
[Paragraph("<b>Type A (Tissue Hypoperfusion)</b>", body_style),
Paragraph("<b>Type B (Impaired Metabolism)</b>", body_style)],
[Paragraph(
"• Shock (septic, cardiogenic, hypovolemic)\n"
"• Severe hypoxemia\n"
"• Mesenteric ischemia\n"
"• Carbon monoxide poisoning",
body_style),
Paragraph(
"• Metformin toxicity\n"
"• Hepatic failure\n"
"• Malignancy (Warburg effect)\n"
"• Nucleoside reverse-transcriptase inhibitors\n"
"• Cyanide poisoning",
body_style)],
]
lt = Table(lactic_data, colWidths=[8.25*cm, 8.25*cm])
lt.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), LIGHT_BLUE),
('GRID', (0,0), (-1,-1), 0.5, BORDER_GRAY),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 8),
('VALIGN', (0,0), (-1,-1), 'TOP'),
]))
story.append(lt)
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"Treatment of lactic acidosis focuses on <b>correcting the underlying cause</b> (restoring perfusion, "
"stopping offending drugs). Sodium bicarbonate is not recommended routinely; it may paradoxically worsen "
"intracellular acidosis. Consider NaHCO<sub rise='3'>3</sub> only if pH <7.1 with hemodynamic instability.",
body_style
))
story.append(Paragraph("4.2 Ketoacidosis", h2_style))
story.append(Paragraph(
"Ketoacidosis occurs when insulin deficiency and glucagon excess drive hepatic fatty acid oxidation "
"to produce ketone bodies (β-hydroxybutyrate, acetoacetate). Three forms:", body_style
))
keto_rows = [
"• <b>Diabetic ketoacidosis (DKA)</b>: Most common. Glucose typically >250 mg/dL; absolute or relative insulin deficiency.",
"• <b>Alcoholic ketoacidosis (AKA)</b>: After binge drinking + starvation; glucose normal or low; β-hydroxybutyrate dominant.",
"• <b>Starvation ketoacidosis</b>: Mild; occurs after prolonged fasting; rarely severe.",
]
story.append(make_key_box(keto_rows))
story.append(Spacer(1, 0.15*cm))
story.append(Paragraph(
"Bicarbonate therapy in DKA is reserved for patients with pH <7.00 and/or evidence of shock: "
"50 mEq NaHCO<sub rise='3'>3</sub> in 300 mL saline over 30–45 min. Target HCO<sub rise='3'>3</sub><sup>−</sup> "
"of 10–12 mEq/L and pH ~7.20, not full normalization.", body_style
))
story.append(Paragraph("4.3 Toxic Alcohol Ingestion", h2_style))
story.append(Paragraph(
"Methanol and ethylene glycol both cause a high-AG acidosis <b>with an osmolar gap</b>. "
"The osmolar gap = Measured S<sub>osm</sub> − Calculated S<sub>osm</sub>, where:", body_style
))
story.append(Paragraph(
"Calculated Osmolality = 2[Na<sup>+</sup>] + [BUN]/2.8 + [Glucose]/18",
formula_style
))
story.append(Paragraph(
"<b>Ethylene glycol</b>: Found in antifreeze. Metabolized to glycolate and oxalate → renal failure "
"and oxalate crystaluria. Treatment: fomepizole 15 mg/kg IV load, then 10 mg/kg q12h; thiamine + "
"pyridoxine; hemodialysis if pH <7.3 or osmolar gap >20 or end-organ damage.", body_style
))
story.append(Paragraph(
"<b>Methanol</b>: Wood alcohol. Metabolized to formaldehyde and formate → optic nerve damage, "
"blindness. Treatment: same as EG (fomepizole preferred; dialysis for severe cases).", body_style
))
story.append(Paragraph(
"<b>Note</b>: Isopropyl alcohol causes osmolar gap WITHOUT high-AG acidosis (unless extreme overdose "
"causes hypotension and lactic acidosis).", warning_style
))
story.append(Spacer(1, 0.3*cm))
# ── 5. NORMAL AG ACIDOSIS ─────────────────────────────────────────────────────
story.append(section_header("5. Normal Anion Gap (Hyperchloremic) Metabolic Acidosis"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"Also called hyperchloremic metabolic acidosis. The AG is normal (<12 mEq/L) because the lost "
"bicarbonate is replaced by chloride. Causes are remembered with the mnemonic <b>HARDUP</b>:", body_style
))
hardup_data = [
[Paragraph("<b>Letter</b>", body_style), Paragraph("<b>Cause</b>", body_style), Paragraph("<b>Mechanism</b>", body_style)],
[Paragraph("H", body_style), Paragraph("Hyperalimentation / Hospital-acquired saline administration", body_style),
Paragraph("Large volumes of 0.9% NaCl → hyperchloremia, dilutional HCO3− loss", body_style)],
[Paragraph("A", body_style), Paragraph("Acid infusion / Addison disease / Carbonic anhydrase inhibitors (e.g., acetazolamide)", body_style),
Paragraph("Acetazolamide blocks tubular HCO3− reabsorption; Addison → decreased aldosterone → impaired H+ excretion", body_style)],
[Paragraph("R", body_style), Paragraph("Renal tubular acidosis (RTA)", body_style),
Paragraph("Impaired renal acid excretion (see Section 6)", body_style)],
[Paragraph("D", body_style), Paragraph("Diarrhea", body_style),
Paragraph("GI loss of HCO3−; most common GI cause", body_style)],
[Paragraph("U", body_style), Paragraph("Ureteral diversion (ileal conduit, ureterosigmoidostomy)", body_style),
Paragraph("Bowel reabsorbs urinary NH4Cl, secretes HCO3−", body_style)],
[Paragraph("P", body_style), Paragraph("Pancreatic / biliary fistula; Post-hypocapnia", body_style),
Paragraph("GI HCO3− loss; or renal HCO3− excretion persisting after correction of respiratory alkalosis", body_style)],
]
ht = Table(hardup_data, colWidths=[1.5*cm, 6.5*cm, 8.5*cm])
ht.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), DARK_BLUE),
('TEXTCOLOR', (0,0), (-1,0), white),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, LIGHT_GRAY]),
('GRID', (0,0), (-1,-1), 0.5, BORDER_GRAY),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
('FONTNAME', (0,1), (0,-1), 'Helvetica-Bold'),
('TEXTCOLOR', (0,1), (0,-1), ACCENT),
('VALIGN', (0,0), (-1,-1), 'TOP'),
]))
story.append(ht)
story.append(Spacer(1, 0.3*cm))
# ── 6. RENAL TUBULAR ACIDOSIS ─────────────────────────────────────────────────
story.append(section_header("6. Renal Tubular Acidosis (RTA)"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"RTAs are a group of disorders in which the kidney cannot properly excrete acid despite relatively "
"preserved glomerular filtration. All three types produce non-AG metabolic acidosis.", body_style
))
rta_data = [
[Paragraph("<b>Type</b>", body_style),
Paragraph("<b>Name</b>", body_style),
Paragraph("<b>Defect</b>", body_style),
Paragraph("<b>Serum K+</b>", body_style),
Paragraph("<b>Urine pH</b>", body_style),
Paragraph("<b>Key Causes</b>", body_style)],
[Paragraph("Type I", body_style),
Paragraph("Distal RTA", body_style),
Paragraph("Impaired H+ secretion in collecting duct", body_style),
Paragraph("Low (hypokalemia)", body_style),
Paragraph("> 5.5 (alkaline)", body_style),
Paragraph("Sjögren's, lupus, amphotericin B, medullary sponge kidney", body_style)],
[Paragraph("Type II", body_style),
Paragraph("Proximal RTA", body_style),
Paragraph("Impaired HCO3− reabsorption in proximal tubule", body_style),
Paragraph("Low", body_style),
Paragraph("Acid (< 5.5 when acidotic)", body_style),
Paragraph("Fanconi syndrome, multiple myeloma, acetazolamide, Wilson disease", body_style)],
[Paragraph("Type IV", body_style),
Paragraph("Hypoaldosteronism", body_style),
Paragraph("Reduced aldosterone → impaired NH4+ excretion", body_style),
Paragraph("High (hyperkalemia)", body_style),
Paragraph("Acid (< 5.5)", body_style),
Paragraph("Diabetic nephropathy, ACE inhibitors/ARBs, NSAIDs, adrenal insufficiency", body_style)],
]
rta_t = Table(rta_data, colWidths=[1.5*cm, 2.5*cm, 3.8*cm, 2*cm, 2.2*cm, 4.5*cm])
rta_t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), MID_BLUE),
('TEXTCOLOR', (0,0), (-1,0), white),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, LIGHT_BLUE]),
('GRID', (0,0), (-1,-1), 0.5, BORDER_GRAY),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 5),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('FONTNAME', (0,1), (0,-1), 'Helvetica-Bold'),
]))
story.append(rta_t)
story.append(Paragraph(
"Note: Type III RTA is rarely used as a clinical category (represents a combination of Types I and II).",
caption_style
))
story.append(Spacer(1, 0.3*cm))
# ── 7. DIAGNOSTIC APPROACH ────────────────────────────────────────────────────
story.append(section_header("7. Stepwise Diagnostic Approach"))
story.append(Spacer(1, 0.2*cm))
steps = [
("Step 1", "Obtain simultaneous ABG and serum electrolytes",
"The calculated HCO3− on ABG and measured value on electrolyte panel should agree within ±2 mEq/L. "
"Discordance suggests lab error or timing mismatch."),
("Step 2", "Assess arterial pH",
"pH < 7.35 = acidemia. Confirm the primary process is metabolic (low HCO3−)."),
("Step 3", "Calculate the anion gap",
"AG = Na+ − (Cl− + HCO3−). Correct for albumin if hypoalbuminemic."),
("Step 4", "Classify as high-AG or normal-AG acidosis",
"AG > 12–13: high-AG (MUDPILES). AG ≤ 12: normal-AG (HARDUP). High AG is significant even if pH is normal."),
("Step 5", "Check for compensatory response (Winters' formula)",
"Expected PaCO2 = 1.5 × [HCO3−] + 8 ± 2. Deviation indicates a mixed disorder."),
("Step 6", "Calculate the Delta-Delta (ΔΔ) ratio for high-AG acidosis",
"ΔAG / ΔHCO3− = (AG − 10) / (24 − HCO3−). Ratio 1–2: pure AG acidosis. < 1: concurrent normal-AG acidosis. > 2: concurrent metabolic alkalosis."),
("Step 7", "Specific workup based on AG category",
"High AG: lactate, ketones, BUN/creatinine, osmolar gap, salicylate level. "
"Normal AG: urine AG = (urine Na+ + K+) − Cl−; negative = GI HCO3− loss; positive = RTA."),
]
for step, title, desc in steps:
step_data = [[
Paragraph(f"<b>{step}</b>", ParagraphStyle('StepNum', fontSize=10,
fontName='Helvetica-Bold', textColor=white, alignment=TA_CENTER,
backColor=MID_BLUE, borderPad=4)),
Paragraph(f"<b>{title}</b><br/>{desc}", body_style)
]]
st = Table(step_data, colWidths=[2.5*cm, 14*cm])
st.setStyle(TableStyle([
('BACKGROUND', (0,0), (0,0), MID_BLUE),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('TOPPADDING', (0,0), (-1,-1), 6),
('BOTTOMPADDING', (0,0), (-1,-1), 6),
('LEFTPADDING', (0,0), (-1,-1), 6),
('BOX', (0,0), (-1,-1), 0.5, BORDER_GRAY),
]))
story.append(st)
story.append(Spacer(1, 0.12*cm))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph("Urine Anion Gap (UAG)", h2_style))
story.append(Paragraph(
"UAG = (Urine Na<sup>+</sup> + Urine K<sup>+</sup>) − Urine Cl<sup>−</sup>", formula_style
))
uag_rows = [
"• Negative UAG (Cl− > Na+ + K+): suggests adequate NH4+ excretion → GI cause (e.g., diarrhea)",
"• Positive UAG (Cl− < Na+ + K+): suggests impaired NH4+ excretion → RTA (most types)",
"• Proximal RTA (Type II) may show variable UAG depending on serum HCO3− level",
]
story.append(make_key_box(uag_rows))
story.append(Spacer(1, 0.3*cm))
# ── 8. CLINICAL EFFECTS ───────────────────────────────────────────────────────
story.append(section_header("8. Clinical Manifestations"))
story.append(Spacer(1, 0.2*cm))
effects_data = [
[Paragraph("<b>System</b>", body_style), Paragraph("<b>Effects</b>", body_style)],
[Paragraph("Cardiovascular", body_style),
Paragraph("Decreased myocardial contractility, vasodilation, hypotension, arrhythmias (especially at pH < 7.1); resistance to catecholamines", body_style)],
[Paragraph("Respiratory", body_style),
Paragraph("Compensatory hyperventilation (Kussmaul breathing); respiratory muscle fatigue in severe cases", body_style)],
[Paragraph("Neurological", body_style),
Paragraph("Progressive obtundation, confusion, coma (especially with pH < 7.1)", body_style)],
[Paragraph("Metabolic", body_style),
Paragraph("Hyperkalemia (H+/K+ exchange across cell membranes); insulin resistance; impaired protein synthesis", body_style)],
[Paragraph("Skeletal", body_style),
Paragraph("Bone resorption (buffers chronic acid load); osteopenia/osteoporosis in chronic acidosis", body_style)],
[Paragraph("Renal", body_style),
Paragraph("Impaired ammoniagenesis in chronic acidosis; nephrolithiasis in distal RTA (calcium oxalate/phosphate stones)", body_style)],
]
eff_t = Table(effects_data, colWidths=[3*cm, 13.5*cm])
eff_t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), DARK_BLUE),
('TEXTCOLOR', (0,0), (-1,0), white),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, LIGHT_GRAY]),
('GRID', (0,0), (-1,-1), 0.5, BORDER_GRAY),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('FONTNAME', (0,1), (0,-1), 'Helvetica-Bold'),
]))
story.append(eff_t)
story.append(Spacer(1, 0.3*cm))
# ── 9. MANAGEMENT ─────────────────────────────────────────────────────────────
story.append(section_header("9. Management"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"Treatment of metabolic acidosis is directed at the <b>underlying cause</b>. Specific interventions "
"depend on the type and severity of the acidosis.", body_style
))
story.append(Paragraph("9.1 General Principles", h2_style))
gen_mgmt = [
"• Address the root cause: restore perfusion (lactic acidosis), insulin + IV fluids (DKA), antidotes (toxic alcohols), dialysis (uremia).",
"• In mechanically ventilated patients: maintain compensatory hyperventilation — do not normalize PaCO2 without correcting HCO3−.",
"• Monitor serum K+ closely: correction of acidosis shifts K+ intracellularly and can precipitate hypokalemia.",
"• Avoid aggressive NaHCO3 therapy in most forms of metabolic acidosis — evidence of benefit is limited.",
]
story.append(make_key_box(gen_mgmt))
story.append(Paragraph("9.2 Bicarbonate Therapy", h2_style))
story.append(Paragraph(
"Alkali therapy (NaHCO<sub rise='3'>3</sub>) is appropriate in select situations:", body_style
))
bicarb_data = [
[Paragraph("<b>Indication</b>", body_style), Paragraph("<b>Details</b>", body_style)],
[Paragraph("Non-AG acidosis (e.g., RTA, diarrhea)", body_style),
Paragraph("Oral NaHCO3 tablets or Shohl's solution (sodium citrate); target HCO3− ~22 mEq/L. Avoid overcorrection.", body_style)],
[Paragraph("Uremic acidosis (advanced CKD)", body_style),
Paragraph("Oral bicarbonate to maintain HCO3− ≥ 22 mEq/L; may slow CKD progression.", body_style)],
[Paragraph("DKA with severe acidemia (pH < 7.00)", body_style),
Paragraph("50 mEq NaHCO3 in 300 mL saline over 30–45 min; target pH ~7.20 and HCO3− 10–12 mEq/L.", body_style)],
[Paragraph("Severe lactic acidosis (pH < 7.1 + hemodynamic instability)", body_style),
Paragraph("Controversial; BICAR-ICU trial showed no mortality benefit overall, but possible benefit in AKI subgroup.", body_style)],
[Paragraph("Hyperchloremic post-saline acidosis", body_style),
Paragraph("Usually self-correcting; switch to balanced crystalloids (lactated Ringer's) for ongoing fluid therapy.", body_style)],
]
bicarb_t = Table(bicarb_data, colWidths=[5.5*cm, 11*cm])
bicarb_t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), MID_BLUE),
('TEXTCOLOR', (0,0), (-1,0), white),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, LIGHT_BLUE]),
('GRID', (0,0), (-1,-1), 0.5, BORDER_GRAY),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
('VALIGN', (0,0), (-1,-1), 'TOP'),
]))
story.append(bicarb_t)
story.append(Spacer(1, 0.15*cm))
story.append(Paragraph(
"THAM (tris-hydroxymethyl aminomethane): an alternative buffer that reduces [H+] without generating CO2 "
"or increasing sodium. May be useful when NaHCO3 is contraindicated (sodium overload). No large RCT evidence.",
body_style
))
story.append(Paragraph("9.3 Cause-Specific Management", h2_style))
cause_mgmt_data = [
[Paragraph("<b>Cause</b>", body_style), Paragraph("<b>Key Treatment</b>", body_style)],
[Paragraph("DKA", body_style),
Paragraph("IV insulin infusion + isotonic saline; potassium replacement; glucose monitoring; bicarbonate only if pH < 7.00", body_style)],
[Paragraph("Alcoholic ketoacidosis", body_style),
Paragraph("Dextrose-containing IV fluids; thiamine 100 mg IV before glucose; no insulin required", body_style)],
[Paragraph("Lactic acidosis (Type A)", body_style),
Paragraph("Reverse underlying hypoperfusion; vasopressors/inotropes; antibiotics for sepsis; avoid metformin", body_style)],
[Paragraph("Ethylene glycol", body_style),
Paragraph("Fomepizole (4-MP) 15 mg/kg IV load; thiamine + pyridoxine; hemodialysis if pH < 7.3 or osmolar gap > 20", body_style)],
[Paragraph("Methanol", body_style),
Paragraph("Fomepizole; folate 50 mg IV q4–6h; hemodialysis for visual symptoms or severe acidosis", body_style)],
[Paragraph("Salicylate toxicity", body_style),
Paragraph("Urinary alkalinization with IV NaHCO3; activated charcoal if early; hemodialysis for severe cases", body_style)],
[Paragraph("RTA Type I", body_style),
Paragraph("Potassium citrate (preferred; corrects acidosis and hypokalemia); alkali therapy to prevent nephrolithiasis", body_style)],
[Paragraph("RTA Type II", body_style),
Paragraph("Large doses of oral bicarbonate/citrate; thiazide diuretics (reduce tubular flow); treat underlying Fanconi syndrome", body_style)],
[Paragraph("RTA Type IV", body_style),
Paragraph("Fludrocortisone (if mineralocorticoid deficiency); furosemide (promotes K+ excretion); dietary K+ restriction", body_style)],
]
cm_t = Table(cause_mgmt_data, colWidths=[4*cm, 12.5*cm])
cm_t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), DARK_BLUE),
('TEXTCOLOR', (0,0), (-1,0), white),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, LIGHT_GRAY]),
('GRID', (0,0), (-1,-1), 0.5, BORDER_GRAY),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('FONTNAME', (0,1), (0,-1), 'Helvetica-Bold'),
]))
story.append(cm_t)
story.append(Spacer(1, 0.3*cm))
# ── 10. MIXED DISORDERS ───────────────────────────────────────────────────────
story.append(section_header("10. Mixed Acid-Base Disorders"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"Metabolic acidosis frequently coexists with other acid-base disorders. Recognition requires systematic "
"application of the Delta-Delta ratio and Winters' formula.", body_style
))
mixed_data = [
[Paragraph("<b>Mixed Disorder</b>", body_style), Paragraph("<b>Clinical Example</b>", body_style), Paragraph("<b>Lab Clue</b>", body_style)],
[Paragraph("High-AG + Normal-AG metabolic acidosis", body_style),
Paragraph("Diarrhea + lactic acidosis; toluene toxicity", body_style),
Paragraph("ΔAG + ΔCl− together account for ΔHCO3−; Na 135, K 3.0, Cl 110, HCO3− 10, AG 15, pH 7.20", body_style)],
[Paragraph("Metabolic acidosis + metabolic alkalosis", body_style),
Paragraph("DKA + vomiting; uremia + vomiting", body_style),
Paragraph("ΔAG > ΔHCO3−; pH may be near normal despite high AG", body_style)],
[Paragraph("Metabolic acidosis + respiratory acidosis", body_style),
Paragraph("Septic shock + COPD or sedative overdose", body_style),
Paragraph("Measured PaCO2 > predicted by Winters'", body_style)],
[Paragraph("Metabolic acidosis + respiratory alkalosis", body_style),
Paragraph("Salicylate toxicity; hepatic failure; sepsis", body_style),
Paragraph("Measured PaCO2 < predicted by Winters'; pH may be normal or alkaline", body_style)],
[Paragraph("Triple disorder", body_style),
Paragraph("Alcoholic ketoacidosis + vomiting + liver disease", body_style),
Paragraph("High AG + alkalosis + respiratory alkalosis; pH very variable", body_style)],
]
mix_t = Table(mixed_data, colWidths=[4.5*cm, 5*cm, 7*cm])
mix_t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), DARK_BLUE),
('TEXTCOLOR', (0,0), (-1,0), white),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, LIGHT_BLUE]),
('GRID', (0,0), (-1,-1), 0.5, BORDER_GRAY),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
('VALIGN', (0,0), (-1,-1), 'TOP'),
]))
story.append(mix_t)
story.append(Spacer(1, 0.3*cm))
# ── 11. QUICK REFERENCE ───────────────────────────────────────────────────────
story.append(section_header("11. Quick Reference Summary"))
story.append(Spacer(1, 0.2*cm))
qr_data = [
[Paragraph("<b>Parameter</b>", body_style), Paragraph("<b>Formula / Value</b>", body_style)],
[Paragraph("Anion Gap", body_style), Paragraph("Na+ − (Cl− + HCO3−); normal 6–12 mEq/L", body_style)],
[Paragraph("Corrected AG (hypoalbuminemia)", body_style), Paragraph("AG + 2.5 × (4.5 − albumin g/dL)", body_style)],
[Paragraph("Winters' Formula", body_style), Paragraph("Expected PaCO2 = 1.5 × [HCO3−] + 8 ± 2", body_style)],
[Paragraph("Delta-Delta Ratio", body_style), Paragraph("(AG − 10) / (24 − HCO3−); 1–2 = pure AG acidosis", body_style)],
[Paragraph("Urine Anion Gap", body_style), Paragraph("(Urine Na+ + K+) − Urine Cl−; negative = GI cause", body_style)],
[Paragraph("Osmolar Gap", body_style), Paragraph("Measured Sosm − (2[Na+] + BUN/2.8 + Glucose/18); normal < 10", body_style)],
[Paragraph("DKA NaHCO3 threshold", body_style), Paragraph("pH < 7.00; 50 mEq in 300 mL saline over 30–45 min", body_style)],
[Paragraph("Fomepizole loading dose", body_style), Paragraph("15 mg/kg IV over 30 min (ethylene glycol / methanol)", body_style)],
[Paragraph("BICAR-ICU trial", body_style), Paragraph("No overall mortality benefit from NaHCO3 in severe metabolic acidemia; possible AKI subgroup benefit", body_style)],
]
qr_t = Table(qr_data, colWidths=[5.5*cm, 11*cm])
qr_t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), DARK_BLUE),
('TEXTCOLOR', (0,0), (-1,0), white),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, LIGHT_BLUE]),
('GRID', (0,0), (-1,-1), 0.5, BORDER_GRAY),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
]))
story.append(qr_t)
story.append(Spacer(1, 0.3*cm))
# ── REFERENCES ────────────────────────────────────────────────────────────────
story.append(HRFlowable(width="100%", thickness=1, color=BORDER_GRAY))
story.append(Spacer(1, 0.15*cm))
story.append(Paragraph("References", h2_style))
refs = [
"1. Harrison's Principles of Internal Medicine, 22nd Edition (2025). McGraw Hill Medical. ISBN: 9781265977061.",
"2. Rosen's Emergency Medicine: Concepts and Clinical Practice. Elsevier. ISBN: 9780323757898.",
"3. Barash, Cullen, and Stoelting's Clinical Anesthesia, 9th Edition. Wolters Kluwer. ISBN: 9781975199074.",
"4. Frameworks for Internal Medicine. Wolters Kluwer. ISBN: 9781496359308.",
"5. Brenner and Rector's The Kidney, 2-Volume Set. Elsevier. ISBN: 9780323532655.",
"6. Jaber S, et al. Sodium bicarbonate therapy for patients with severe metabolic acidaemia in the intensive care unit (BICAR-ICU): a multicentre, open-label, randomised controlled, phase 3 trial. Lancet. 2018;392(10141):31-40.",
]
for ref in refs:
story.append(Paragraph(ref, source_style))
# Build PDF
doc.build(story)
print(f"PDF generated: {OUTPUT}")
cd /home/daytona/workspace/metabolic-acidosis && python generate_pdf.py 2>&1
ls -lh /home/daytona/workspace/metabolic-acidosis/Metabolic_Acidosis.pdf
Metabolic Acidosis
PDF Document · PDF
| Section | Content |
|---|---|
| 1. Definition & Overview | Normal values, what constitutes metabolic acidosis |
| 2. Pathophysiology | Buffering systems, Henderson-Hasselbalch, Winters' formula |
| 3. Classification | High-AG vs. Normal-AG comparison table |
| 4. High AG Acidosis | Full MUDPILES table; lactic acidosis (Type A/B), ketoacidosis (DKA/AKA/starvation), toxic alcohols (EG/methanol) with osmolar gap formula |
| 5. Normal AG Acidosis | Full HARDUP mnemonic table with mechanisms |
| 6. Renal Tubular Acidosis | Types I, II, IV - defect, K+, urine pH, key causes |
| 7. Diagnostic Approach | 7-step framework; Urine Anion Gap interpretation |
| 8. Clinical Manifestations | Cardiovascular, respiratory, neurological, metabolic, skeletal, renal effects |
| 9. Management | Bicarbonate therapy indications; cause-specific treatments; BICAR-ICU trial summary |
| 10. Mixed Disorders | Delta-delta ratio; common mixed disorder scenarios |
| 11. Quick Reference | All key formulas at a glance |