Electrolytes imbalance explain each one of that

| Volume Status | Mechanism | Common Causes |
|---|---|---|
| Hypovolemic | Na+ deficit > water deficit | Diuretics (thiazides), vomiting, diarrhea, burns, Addison's disease, salt-losing nephropathy |
| Euvolemic | Water retention, normal Na+ | SIADH, hypothyroidism, glucocorticoid deficiency, primary polydipsia |
| Hypervolemic | Water retained >> Na+ | CHF, cirrhosis, nephrotic syndrome, AKI/CKD |
Note: Chronic hyponatremia causes fewer symptoms than acute hyponatremia at the same Na+ level, because the brain adapts by extruding osmolytes.
| Step | Drug | Mechanism | Onset |
|---|---|---|---|
| Stabilize membrane | IV Calcium gluconate/chloride | Antagonizes membrane effect | Minutes |
| Shift K+ into cells | IV Insulin + Dextrose | Activates Na+/K+-ATPase | 15-30 min |
| Shift K+ into cells | Nebulized albuterol | Beta-2 stimulation | 30 min |
| Shift K+ into cells | IV Sodium bicarbonate | Alkalinizes ECF | Variable |
| Remove K+ from body | Furosemide, kayexalate, patiromer | Renal/GI excretion | Hours |
| Remove K+ from body | Hemodialysis | Direct removal | Fast (severe) |
| Mg2+ Level | Effects |
|---|---|
| 4-5 mEq/L | Nausea, flushing, lethargy, loss of deep tendon reflexes |
| 5-7 mEq/L | Somnolence, hyporeflexia |
| > 7 mEq/L | Respiratory depression, paralysis |
| > 12 mEq/L | Cardiac arrest |
| Electrolyte | Low | High |
|---|---|---|
| Na+ | Confusion, seizures, cerebral edema; correct slowly | Thirst, brain shrinkage, seizures; correct slowly |
| K+ | U-waves on ECG, arrhythmias, weakness | Peaked T-waves, VF, bradycardia; calcium first |
| Ca2+ | Chvostek's/Trousseau's, prolonged QT, tetany | Bones/Stones/Groans/Moans, short QT |
| Mg2+ | Refractory low K+/Ca2+, arrhythmias, seizures | Loss of DTRs, respiratory arrest |
| PO4 | Muscle weakness, respiratory failure, hemolysis | Hypocalcemia, vascular calcification (CKD) |
| Cl- | Metabolic alkalosis | Non-anion gap metabolic acidosis |
Make pdf of this topic
ls -la /home/daytona/workspace/ 2>/dev/null || echo "workspace not found"
mkdir -p /home/daytona/workspace/electrolytes-pdf
~/electrolytes-pdf/generate_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import Frame, PageTemplate
from reportlab.lib.colors import HexColor
import json, subprocess, base64, os
# ─── Colour palette ────────────────────────────────────────────────────────────
C_NAVY = HexColor("#1B3A6B") # deep blue – headings / title bar
C_TEAL = HexColor("#0F7B8C") # teal – section banners
C_MINT = HexColor("#E8F8F9") # very light teal – section background
C_GOLD = HexColor("#F0A500") # accent / sub-headers
C_LGRAY = HexColor("#F4F6F8") # table row alt
C_WHITE = colors.white
C_BLACK = HexColor("#1A1A1A")
C_RED = HexColor("#C0392B") # danger / severe
C_GRNG = HexColor("#1E8449") # treatment green
PAGE_W, PAGE_H = A4
MARGIN = 1.8 * cm
# ─── Styles ────────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
def S(name, **kw):
return ParagraphStyle(name, **kw)
TITLE_STYLE = S("Title2",
fontSize=26, leading=32, textColor=C_WHITE,
fontName="Helvetica-Bold", alignment=TA_CENTER)
SUBTITLE_STYLE = S("Subtitle2",
fontSize=13, leading=16, textColor=HexColor("#B3D9F0"),
fontName="Helvetica", alignment=TA_CENTER)
SECTION_STYLE = S("Section",
fontSize=14, leading=18, textColor=C_WHITE,
fontName="Helvetica-Bold", alignment=TA_LEFT,
leftIndent=8, spaceBefore=4, spaceAfter=4)
H2_STYLE = S("H2",
fontSize=12, leading=15, textColor=C_NAVY,
fontName="Helvetica-Bold", spaceBefore=10, spaceAfter=4)
H3_STYLE = S("H3",
fontSize=11, leading=14, textColor=C_TEAL,
fontName="Helvetica-Bold", spaceBefore=8, spaceAfter=3)
BODY_STYLE = S("Body2",
fontSize=9.5, leading=14, textColor=C_BLACK,
fontName="Helvetica", alignment=TA_JUSTIFY,
spaceBefore=2, spaceAfter=2)
BULLET_STYLE = S("Bullet2",
fontSize=9.5, leading=14, textColor=C_BLACK,
fontName="Helvetica", leftIndent=14, bulletIndent=4,
spaceBefore=1, spaceAfter=1)
NOTE_STYLE = S("Note",
fontSize=8.5, leading=12, textColor=HexColor("#555555"),
fontName="Helvetica-Oblique", leftIndent=10,
borderPad=4, spaceBefore=2, spaceAfter=4)
SOURCES_STYLE = S("Sources",
fontSize=8, leading=11, textColor=HexColor("#888888"),
fontName="Helvetica-Oblique", alignment=TA_CENTER)
# ─── Helper: section banner ────────────────────────────────────────────────────
def section_banner(title):
tbl = Table([[Paragraph(title, SECTION_STYLE)]], colWidths=[PAGE_W - 2*MARGIN])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_TEAL),
("ROUNDEDCORNERS", [4,4,4,4]),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
return tbl
def subsection_banner(title):
tbl = Table([[Paragraph(title, S("Sub",
fontSize=11, leading=14, textColor=C_WHITE,
fontName="Helvetica-Bold", leftIndent=4))
]], colWidths=[PAGE_W - 2*MARGIN])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_NAVY),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
return tbl
def B(text):
return Paragraph(f"<bullet>•</bullet> {text}", BULLET_STYLE)
def P(text):
return Paragraph(text, BODY_STYLE)
def H2(text):
return Paragraph(text, H2_STYLE)
def H3(text):
return Paragraph(text, H3_STYLE)
def SP(n=6):
return Spacer(1, n)
def HR():
return HRFlowable(width="100%", thickness=0.5, color=HexColor("#CCCCCC"), spaceAfter=4, spaceBefore=4)
def note(text):
return Paragraph(f"<i>{text}</i>", NOTE_STYLE)
def make_table(headers, rows, col_widths=None, alt_color=C_LGRAY):
w = PAGE_W - 2*MARGIN
if col_widths is None:
n = len(headers)
col_widths = [w/n]*n
hdr_cells = [Paragraph(f"<b>{h}</b>", S("TH",
fontSize=9, leading=12, textColor=C_WHITE,
fontName="Helvetica-Bold", alignment=TA_CENTER))
for h in headers]
data = [hdr_cells]
for row in rows:
data.append([Paragraph(str(c), S("TD",
fontSize=8.8, leading=12, textColor=C_BLACK,
fontName="Helvetica", alignment=TA_LEFT))
for c in row])
style = [
("BACKGROUND", (0,0), (-1,0), C_NAVY),
("GRID", (0,0), (-1,-1), 0.4, HexColor("#CCCCCC")),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
]
for i in range(1, len(data)):
if i % 2 == 0:
style.append(("BACKGROUND", (0,i), (-1,i), alt_color))
tbl = Table(data, colWidths=col_widths)
tbl.setStyle(TableStyle(style))
return tbl
# ─── Download hyponatremia diagram ─────────────────────────────────────────────
IMG_URL = "https://cdn.orris.care/cdss_images/150cdcd9c35b577e380e31ff446321d4037d06da30751b5b7a0ba68e23adce55.png"
IMG_PATH = "/home/daytona/workspace/electrolytes-pdf/hyponatremia_algo.png"
img_flowable = None
try:
result = json.loads(subprocess.check_output([
"node", "/home/daytona/skills/shared/scripts/fetch_images.js", IMG_URL
], timeout=30))
if result and result[0].get("base64"):
raw = base64.b64decode(result[0]["base64"].split(",")[1])
with open(IMG_PATH, "wb") as f:
f.write(raw)
from reportlab.platypus import Image as RLImage
avail_w = PAGE_W - 2*MARGIN
img_flowable = RLImage(IMG_PATH, width=avail_w, height=avail_w*0.55)
print("Image downloaded OK")
except Exception as e:
print(f"Image download failed: {e}")
# ─── Build story ───────────────────────────────────────────────────────────────
story = []
# ── Cover / Title block ───────────────────────────────────────────────────────
cover_data = [[
Paragraph("Electrolyte Imbalances", TITLE_STYLE),
Paragraph("A Complete Clinical Overview", SUBTITLE_STYLE),
Spacer(1, 6),
Paragraph("Sodium · Potassium · Calcium · Magnesium · Phosphate · Chloride", SUBTITLE_STYLE),
Spacer(1, 6),
Paragraph("Sources: Morgan & Mikhail's Clinical Anesthesiology 7e | Comprehensive Clinical Nephrology 7e | Miller's Anesthesia 10e", SOURCES_STYLE),
]]
cover_tbl = Table(cover_data, colWidths=[PAGE_W - 2*MARGIN])
cover_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_NAVY),
("TOPPADDING", (0,0), (-1,-1), 24),
("BOTTOMPADDING", (0,0), (-1,-1), 24),
("LEFTPADDING", (0,0), (-1,-1), 20),
("RIGHTPADDING", (0,0), (-1,-1), 20),
("ROUNDEDCORNERS", [6,6,6,6]),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(cover_tbl)
story.append(SP(14))
# ── Intro ──────────────────────────────────────────────────────────────────────
story.append(P("Electrolytes are minerals that carry an electrical charge and are essential for nerve conduction, muscle contraction, fluid balance, and acid-base homeostasis. Dysregulation of any single electrolyte can produce life-threatening cardiac, neurological, and neuromuscular consequences. This document covers each major electrolyte imbalance — its definition, causes, symptoms, ECG changes, and treatment."))
story.append(SP(8))
# ══════════════════════════════════════════════════════════════════════════════
# 1. SODIUM
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_banner("1. SODIUM (Na+) | Normal: 135 – 145 mEq/L"))
story.append(SP(6))
story.append(P("Sodium is the primary <b>extracellular cation</b> and the main determinant of plasma osmolality. Dysnatremia almost always reflects abnormalities in <b>water balance</b>, not sodium balance alone."))
story.append(SP(8))
# ── Hyponatremia ──
story.append(subsection_banner("Hyponatremia (Na+ < 135 mEq/L)"))
story.append(SP(4))
story.append(H3("Classification by Volume Status"))
hypo_na_tbl = make_table(
["Volume Status", "Mechanism", "Common Causes"],
[
["Hypovolemic", "Na+ deficit > water deficit", "Thiazide diuretics, vomiting, diarrhea, burns, Addison's disease, salt-losing nephropathy"],
["Euvolemic", "Water retention, normal Na+", "SIADH, hypothyroidism, glucocorticoid deficiency, primary polydipsia"],
["Hypervolemic", "Water retained >> Na+", "CHF, cirrhosis, nephrotic syndrome, AKI/CKD"],
],
col_widths=[3.5*cm, 4.5*cm, 9.5*cm]
)
story.append(hypo_na_tbl)
story.append(SP(6))
if img_flowable:
story.append(H3("Diagnostic Algorithm for Hyponatremia"))
story.append(img_flowable)
story.append(note("Fig. Algorithm for diagnostic assessment of hyponatremia (Comprehensive Clinical Nephrology 7e, Fig. 9.5)"))
story.append(SP(6))
story.append(H3("SIADH — Key Drug Causes"))
for d in ["Carbamazepine, chlorpropamide, clofibrate, vincristine",
"SSRIs, antipsychotics, opioids, MDMA, ifosfamide",
"NSAIDs, cyclophosphamide (potentiate ADH action)",
"Desmopressin, oxytocin, vasopressin (ADH analogues)"]:
story.append(B(d))
story.append(SP(6))
story.append(H3("Symptoms"))
story.append(make_table(
["Na+ Level", "Symptoms"],
[
["> 125 mEq/L", "Often asymptomatic; anorexia, nausea, weakness"],
["120 – 125 mEq/L", "Lethargy, confusion, headache"],
["< 120 mEq/L", "Seizures, coma, brain herniation — EMERGENCY"],
],
col_widths=[5*cm, 12.5*cm]
))
story.append(SP(4))
story.append(note("Chronic hyponatremia causes fewer symptoms than acute hyponatremia at the same Na+ level — the brain adapts by extruding osmolytes."))
story.append(SP(6))
story.append(H3("Treatment"))
story.append(B("Hypovolemic: Isotonic saline (0.9% NaCl)"))
story.append(B("SIADH / euvolemic: Fluid restriction"))
story.append(B("Hypervolemic: Fluid + Na+ restriction; treat underlying cause"))
story.append(B("Severe / symptomatic: Hypertonic saline (3% NaCl)"))
story.append(B("<b>Correction rate: no faster than 8–10 mEq/L per day</b> — rapid correction risks Osmotic Demyelination Syndrome (ODS)"))
story.append(SP(10))
# ── Hypernatremia ──
story.append(subsection_banner("Hypernatremia (Na+ > 145 mEq/L)"))
story.append(SP(4))
story.append(P("Almost always signals a failure to access or drink adequate water. Represents <b>free water deficit</b> relative to sodium."))
story.append(SP(4))
story.append(H3("Causes"))
for c in ["Water loss: Diabetes insipidus (central or nephrogenic), excessive sweating, respiratory losses, osmotic diuresis",
"Inadequate intake: Elderly, altered consciousness, infants",
"Sodium gain: Hypertonic saline, mineralocorticoid excess, sea water ingestion"]:
story.append(B(c))
story.append(SP(4))
story.append(H3("Symptoms"))
story.append(P("Thirst, headache, lethargy, weakness. Severe: spasms, seizures, intracranial hemorrhage (brain shrinks away from skull)."))
story.append(SP(4))
story.append(H3("Treatment"))
story.append(B("Gradual free water replacement (oral or IV D5W / hypotonic 0.45% saline)"))
story.append(B("<b>Correct no faster than 10–12 mEq/L per day</b> — rapid correction causes cerebral edema"))
story.append(SP(12))
# ══════════════════════════════════════════════════════════════════════════════
# 2. POTASSIUM
# ══════════════════════════════════════════════════════════════════════════════
story.append(PageBreak())
story.append(section_banner("2. POTASSIUM (K+) | Normal: 3.5 – 5.0 mEq/L"))
story.append(SP(6))
story.append(P("~98% of total body potassium is <b>intracellular</b>. Small changes in plasma K+ have major effects on the resting membrane potential of excitable cells — heart, nerves, muscles."))
story.append(SP(6))
story.append(H3("Key Regulators of K+ Distribution (Transcellular Shifts)"))
story.append(make_table(
["Factor", "Effect on Plasma K+", "Mechanism"],
[
["Insulin", "Decreases", "Activates Na+/K+-ATPase -> K+ enters cells"],
["Beta-2 adrenergic activity", "Decreases", "Activates Na+/K+-ATPase"],
["Acidosis (pH falls 0.1)", "Increases ~0.6 mEq/L", "H+ enters cells, K+ exits to maintain electrical balance"],
["Alkalosis (pH rises 0.1)", "Decreases ~0.6 mEq/L", "H+ exits cells, K+ enters"],
["Hyperosmolality (+10 mOsm/L)", "Increases ~0.6 mEq/L", "Water and K+ move out of cells"],
["Hypothermia", "Decreases", "Cellular K+ uptake"],
],
col_widths=[4.5*cm, 3.5*cm, 9.5*cm]
))
story.append(SP(8))
# ── Hypokalemia ──
story.append(subsection_banner("Hypokalemia (K+ < 3.5 mEq/L)"))
story.append(SP(4))
story.append(H3("Causes"))
story.append(B("Transcellular shift: Insulin excess, beta-2 agonists, alkalosis, hypothermia"))
story.append(B("Renal losses: Loop/thiazide diuretics, hyperaldosteronism, Bartter/Gitelman syndromes, hypomagnesemia, osmotic diuresis, vomiting (bicarbonaturia)"))
story.append(B("GI losses: Diarrhea, fistulas, laxative abuse"))
story.append(B("Poor intake: Malnutrition, alcoholism"))
story.append(SP(4))
story.append(H3("Symptoms by Severity"))
story.append(make_table(
["K+ Level", "Symptoms"],
[
["3.0 – 3.5 mEq/L (Mild)", "Fatigue, muscle weakness, constipation"],
["2.5 – 3.0 mEq/L (Moderate)", "Myalgias, cramps, ileus"],
["< 2.5 mEq/L (Severe)", "Profound weakness, paralysis, rhabdomyolysis"],
],
col_widths=[5.5*cm, 12*cm]
))
story.append(SP(4))
story.append(H3("ECG Changes (progressive)"))
story.append(B("Flattened T-waves"))
story.append(B("<b>Prominent U-waves</b> — hallmark finding (positive deflection after T-wave in V2-V3)"))
story.append(B("ST depression"))
story.append(B("Widened QRS at very low levels"))
story.append(SP(4))
story.append(H3("Treatment"))
story.append(B("Mild-moderate: Oral KCl (20-40 mEq doses)"))
story.append(B("Severe / symptomatic: IV potassium at <b>10-20 mEq/h</b> via infusion pump with continuous ECG monitoring"))
story.append(B("<b>Always correct hypomagnesemia first</b> — low Mg2+ causes refractory hypokalemia"))
story.append(SP(10))
# ── Hyperkalemia ──
story.append(subsection_banner("Hyperkalemia (K+ > 5.5 mEq/L)"))
story.append(SP(4))
story.append(H3("Causes"))
story.append(B("<b>Pseudohyperkalemia:</b> Hemolysis in tube, leukocytosis >70,000, thrombocytosis >1,000,000 — always rule out first"))
story.append(B("Transcellular shift out: Acidosis, rhabdomyolysis, hemolysis, succinylcholine, beta-blockers, digitalis toxicity, hyperkalemic periodic paralysis"))
story.append(B("Decreased renal excretion: Kidney failure (most common), Addison's disease, ACE inhibitors/ARBs, K+-sparing diuretics (spironolactone, amiloride, triamterene)"))
story.append(B("Increased intake: Salt substitutes, massive transfusions (especially with renal impairment)"))
story.append(SP(4))
story.append(H3("ECG Changes (by severity — memorize this sequence)"))
story.append(make_table(
["Stage", "ECG Finding"],
[
["Earliest", "Tall, peaked (tented) T-waves — narrow base, symmetric"],
["Early", "Prolonged PR interval"],
["Moderate", "Widened QRS complex"],
["Severe", "Sine-wave pattern (merging P, QRS, T)"],
["Terminal", "Ventricular fibrillation / asystole"],
],
col_widths=[4*cm, 13.5*cm]
))
story.append(SP(4))
story.append(H3("Treatment (ABCD approach)"))
story.append(make_table(
["Step", "Drug / Intervention", "Mechanism", "Onset"],
[
["1 - Stabilize membrane", "IV Calcium gluconate or chloride", "Antagonizes cardiac membrane effect of high K+", "Minutes"],
["2 - Shift into cells", "IV Insulin + Dextrose", "Activates Na+/K+-ATPase", "15-30 min"],
["2 - Shift into cells", "Nebulized salbutamol/albuterol", "Beta-2 stimulation -> cellular uptake", "30 min"],
["2 - Shift into cells", "IV Sodium bicarbonate", "Alkalinizes ECF -> K+ enters cells", "Variable"],
["3 - Remove from body", "Furosemide, kayexalate, patiromer", "Renal/GI K+ excretion", "Hours"],
["3 - Remove from body", "Hemodialysis", "Direct rapid removal", "Fast (severe cases)"],
],
col_widths=[4.5*cm, 4.5*cm, 5*cm, 3.5*cm]
))
story.append(SP(12))
# ══════════════════════════════════════════════════════════════════════════════
# 3. CALCIUM
# ══════════════════════════════════════════════════════════════════════════════
story.append(PageBreak())
story.append(section_banner("3. CALCIUM (Ca2+) | Normal: 8.5 – 10.5 mg/dL"))
story.append(SP(6))
story.append(P("Calcium exists in three forms: <b>protein-bound</b> (~40%), <b>complexed</b> (~10%), and <b>free ionized</b> (~50%) — only ionized Ca2+ is physiologically active. Albumin correction: add 0.8 mg/dL per 1 g/dL fall in albumin below 4. Regulated by PTH, vitamin D (1,25-OH-D3), and calcitonin."))
story.append(SP(8))
# ── Hypocalcemia ──
story.append(subsection_banner("Hypocalcemia (Ca2+ < 8.5 mg/dL)"))
story.append(SP(4))
story.append(H3("Causes"))
story.append(B("Hypoparathyroidism: Post-thyroidectomy/parathyroidectomy (most common surgical cause), autoimmune, DiGeorge syndrome"))
story.append(B("Vitamin D deficiency or resistance"))
story.append(B("<b>Hypomagnesemia:</b> Impairs PTH secretion and end-organ response — refractory until Mg is repleted"))
story.append(B("Massive transfusions: Citrate chelates ionized calcium"))
story.append(B("Acute pancreatitis, rhabdomyolysis (Ca deposits in injured tissue)"))
story.append(B("Chronic kidney disease (decreased 1,25-OH-D3 synthesis)"))
story.append(B("Hungry bone syndrome after parathyroidectomy"))
story.append(SP(4))
story.append(H3("Clinical Signs — Neuromuscular Irritability"))
story.append(make_table(
["Sign / Symptom", "Description"],
[
["Chvostek's sign", "Tapping the facial nerve at cheek -> ipsilateral facial muscle twitching"],
["Trousseau's sign", "BP cuff above systolic for 3 min -> carpal spasm (carpopedal spasm) — more specific"],
["Paresthesias", "Perioral numbness, fingertip/toe tingling (earliest symptom)"],
["Tetany / cramps", "Muscle spasms, laryngospasm (life-threatening)"],
["Seizures", "Generalized tonic-clonic in severe hypocalcemia"],
["ECG: Prolonged QT", "Risk of torsades de pointes; reduced cardiac contractility"],
],
col_widths=[5*cm, 12.5*cm]
))
story.append(SP(4))
story.append(H3("Treatment"))
story.append(B("Symptomatic / severe: IV Calcium gluconate 10% (preferred peripherally — less tissue necrosis) or calcium chloride (ICU)"))
story.append(B("Chronic: Oral calcium carbonate + vitamin D (calcitriol if CKD)"))
story.append(B("<b>Always check and correct magnesium first</b>"))
story.append(SP(10))
# ── Hypercalcemia ──
story.append(subsection_banner("Hypercalcemia (Ca2+ > 10.5 mg/dL)"))
story.append(SP(4))
story.append(H3("Causes"))
story.append(B("<b>Primary hyperparathyroidism</b> — most common outpatient cause (PTH inappropriately elevated)"))
story.append(B("<b>Malignancy</b> — most common inpatient cause (bone mets, PTHrP secretion, osteolytic cytokines)"))
story.append(B("Vitamin D toxicity, granulomatous disease (sarcoidosis, TB — macrophages produce 1,25-OH-D3)"))
story.append(B("Milk-alkali syndrome, Paget's disease, chronic immobilization"))
story.append(B("Drugs: Thiazide diuretics, lithium"))
story.append(SP(4))
story.append(H3("Symptoms — Mnemonic: Bones, Stones, Groans, Psychic Moans"))
story.append(make_table(
["Category", "Manifestations"],
[
["Bones", "Bone pain, pathological fractures, osteitis fibrosa cystica"],
["Stones", "Nephrolithiasis, nephrocalcinosis, polyuria, polydipsia"],
["Groans", "Anorexia, nausea, vomiting, constipation, pancreatitis, peptic ulcer"],
["Psychic Moans", "Fatigue, confusion, lethargy, depression, coma"],
["ECG", "Shortened QT interval, shortened ST segment; increased digitalis sensitivity"],
],
col_widths=[4*cm, 13.5*cm]
))
story.append(SP(4))
story.append(H3("Treatment"))
story.append(B("<b>Step 1: IV saline rehydration</b> — always first; restores renal perfusion"))
story.append(B("<b>Step 2: IV furosemide</b> (loop diuretic) once hydrated — target urine output 200-300 mL/h"))
story.append(B("Step 3: Bisphosphonates (zoledronate, pamidronate) — onset 1-3 days; reduce bone resorption"))
story.append(B("Step 4: Calcitonin — rapid but transient; used as bridge"))
story.append(B("Severe (Ca > 15 mg/dL): Consider hemodialysis"))
story.append(B("Glucocorticoids: For granulomatous disease and vitamin D toxicity"))
story.append(note("Premature diuresis before rehydration may aggravate hypercalcemia by worsening volume depletion."))
story.append(SP(12))
# ══════════════════════════════════════════════════════════════════════════════
# 4. MAGNESIUM
# ══════════════════════════════════════════════════════════════════════════════
story.append(PageBreak())
story.append(section_banner("4. MAGNESIUM (Mg2+) | Normal: 1.5 – 2.5 mEq/L"))
story.append(SP(6))
story.append(P("Magnesium is the <b>second most abundant intracellular cation</b>. It is a cofactor for hundreds of enzyme reactions, ATP metabolism, and Na+/K+-ATPase. Closely linked to both potassium and calcium homeostasis — hypomagnesemia causes refractory hypokalemia and hypocalcemia."))
story.append(SP(8))
# ── Hypomagnesemia ──
story.append(subsection_banner("Hypomagnesemia (Mg2+ < 1.5 mEq/L)"))
story.append(SP(4))
story.append(H3("Causes"))
story.append(B("<b>Alcoholism</b> — most common cause in Western countries"))
story.append(B("Malnutrition, malabsorption, prolonged parenteral nutrition without Mg supplementation"))
story.append(B("Renal wasting: Loop/thiazide diuretics, osmotic diuresis (DKA), nephrotoxic drugs (amphotericin B, cisplatin, aminoglycosides, calcineurin inhibitors)"))
story.append(B("GI losses: Diarrhea, fistulas"))
story.append(B("Post-CPB: Hemodilution with Mg-free fluids"))
story.append(SP(4))
story.append(H3("Clinical Effects"))
story.append(B("Causes <b>refractory hypokalemia and hypocalcemia</b> — always check Mg when K+ or Ca2+ is low and not responding to replacement"))
story.append(B("Neuromuscular: Tremors, tetany, hyperreflexia, seizures"))
story.append(B("Cardiac: New arrhythmias, torsades de pointes, ventricular dysfunction"))
story.append(B("CNS: Confusion, personality changes, nystagmus"))
story.append(SP(4))
story.append(H3("Treatment"))
story.append(B("Symptomatic / severe: IV Magnesium sulfate 1-2 g over 15 min; 2-4 g for dysrhythmias"))
story.append(B("Routine post-CPB: Many centers give 2-4 g Mg to prevent ventricular/atrial arrhythmias"))
story.append(B("Oral magnesium oxide/glycinate for mild asymptomatic cases"))
story.append(B("<b>Use with caution in renal insufficiency</b>"))
story.append(SP(10))
# ── Hypermagnesemia ──
story.append(subsection_banner("Hypermagnesemia (Mg2+ > 2.5 mEq/L)"))
story.append(SP(4))
story.append(P("Almost always iatrogenic or from renal failure. Common in eclampsia treatment with IV Mg, or Mg-containing antacids/laxatives used in CKD patients."))
story.append(SP(4))
story.append(H3("Symptoms by Serum Level"))
story.append(make_table(
["Mg2+ Level", "Clinical Effects"],
[
["4 – 5 mEq/L", "Nausea, flushing, lethargy, loss of deep tendon reflexes (DTRs)"],
["5 – 7 mEq/L", "Somnolence, hyporeflexia, hypotension"],
["> 7 mEq/L", "Respiratory depression, muscle paralysis"],
["> 12 mEq/L", "Cardiac arrest"],
],
col_widths=[4*cm, 13.5*cm]
))
story.append(SP(4))
story.append(H3("Treatment"))
story.append(B("<b>IV Calcium gluconate</b> — immediately antagonizes Mg2+ effects at the membrane"))
story.append(B("Stop all magnesium sources"))
story.append(B("Hemodialysis for severe cases or in renal failure"))
story.append(SP(12))
# ══════════════════════════════════════════════════════════════════════════════
# 5. PHOSPHATE
# ══════════════════════════════════════════════════════════════════════════════
story.append(PageBreak())
story.append(section_banner("5. PHOSPHATE (PO4) | Normal: 2.5 – 4.5 mg/dL"))
story.append(SP(6))
story.append(P("Phosphate is the major <b>intracellular anion</b>, critical for ATP production, 2,3-DPG (oxygen delivery to tissues), bone mineralization, and cell membrane structure (phospholipids)."))
story.append(SP(8))
# ── Hypophosphatemia ──
story.append(subsection_banner("Hypophosphatemia (PO4 < 2.5 mg/dL)"))
story.append(SP(4))
story.append(H3("Causes"))
story.append(B("<b>Refeeding syndrome</b> (most dangerous) — insulin surge after starvation drives PO4 into cells; can be fatal"))
story.append(B("Transcellular shifts: Insulin administration, respiratory alkalosis (hyperventilation), catecholamines"))
story.append(B("Decreased absorption: Malnutrition, Al/Mg-based antacid use (bind phosphate in gut), malabsorption, vitamin D deficiency"))
story.append(B("Increased renal losses: Hyperparathyroidism (PTH reduces tubular PO4 reabsorption), DKA recovery, Fanconi syndrome"))
story.append(B("Alcoholism and alcohol withdrawal"))
story.append(SP(4))
story.append(H3("Symptoms by Severity"))
story.append(make_table(
["Severity", "Clinical Features"],
[
["Mild (1.5–2.5 mg/dL)", "Usually asymptomatic"],
["Moderate-Severe (< 1.5 mg/dL)", "Profound muscle weakness, respiratory failure (diaphragm weakness), rhabdomyolysis"],
["Severe (< 1.0 mg/dL)", "Hemolytic anemia, impaired leukocyte/platelet function, bone pain, confusion, encephalopathy, cardiomyopathy"],
["2,3-DPG depletion", "Oxyhemoglobin curve shifts left -> reduced O2 release to tissues -> tissue hypoxia despite normal SpO2"],
],
col_widths=[5*cm, 12.5*cm]
))
story.append(SP(4))
story.append(H3("Treatment"))
story.append(B("Mild/moderate: Oral phosphate supplements; dietary phosphate (dairy products)"))
story.append(B("Severe (< 1.0 mg/dL or symptomatic): IV sodium phosphate or potassium phosphate"))
story.append(B("Monitor calcium during IV replacement (risk of hypocalcemia)"))
story.append(SP(10))
# ── Hyperphosphatemia ──
story.append(subsection_banner("Hyperphosphatemia (PO4 > 4.5 mg/dL)"))
story.append(SP(4))
story.append(H3("Causes"))
story.append(B("<b>Chronic kidney disease</b> — most common; impaired renal phosphate excretion"))
story.append(B("Hypoparathyroidism (low PTH = reduced renal phosphate excretion)"))
story.append(B("Rhabdomyolysis, tumor lysis syndrome (massive cell breakdown releases intracellular PO4)"))
story.append(B("Excessive phosphate intake: Laxatives, enemas, vitamin D toxicity"))
story.append(SP(4))
story.append(H3("Key Effects"))
story.append(B("<b>Reciprocal hypocalcemia:</b> High PO4 chelates ionized Ca2+, causing tetany/seizures"))
story.append(B("Calcium-phosphate precipitation in soft tissues: Metastatic calcification, vascular calcification"))
story.append(B("In CKD: Renal osteodystrophy, increased cardiovascular mortality (No. 1 cause of death in dialysis patients)"))
story.append(SP(4))
story.append(H3("Treatment"))
story.append(B("Dietary phosphate restriction (avoid dairy, nuts, cola drinks)"))
story.append(B("Phosphate binders taken with meals: Calcium carbonate, sevelamer, lanthanum carbonate"))
story.append(B("Dialysis in end-stage CKD"))
story.append(SP(12))
# ══════════════════════════════════════════════════════════════════════════════
# 6. CHLORIDE
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_banner("6. CHLORIDE (Cl-) | Normal: 98 – 106 mEq/L"))
story.append(SP(6))
story.append(P("Chloride is the main <b>extracellular anion</b> and moves passively with sodium. Disorders are usually secondary to other electrolyte or acid-base disturbances. Electroneutrality dictates that when Cl- falls, HCO3- rises (and vice versa)."))
story.append(SP(6))
story.append(make_table(
["Disorder", "Definition", "Key Causes", "Acid-Base Effect", "Treatment"],
[
["Hypochloremia", "Cl- < 98 mEq/L", "Vomiting, NG suction, loop/thiazide diuretics", "Metabolic alkalosis (HCO3- replaces Cl-)", "IV NaCl or KCl depending on volume/K+ status"],
["Hyperchloremia", "Cl- > 106 mEq/L", "Normal saline excess, RTA, diarrhea (HCO3- loss)", "Non-anion gap metabolic acidosis", "Switch IVF to balanced crystalloids (Lactated Ringer's); treat cause"],
],
col_widths=[3.5*cm, 3*cm, 4.5*cm, 4*cm, 4.5*cm]
))
story.append(SP(12))
# ══════════════════════════════════════════════════════════════════════════════
# QUICK REFERENCE SUMMARY TABLE
# ══════════════════════════════════════════════════════════════════════════════
story.append(PageBreak())
story.append(section_banner("Quick Reference Summary"))
story.append(SP(8))
story.append(make_table(
["Electrolyte", "LOW — Key Features", "HIGH — Key Features"],
[
["Na+ (135–145)", "Cerebral edema, seizures, confusion\nCorrect slowly: max 8–10 mEq/L/day (risk ODS)", "Brain shrinkage, seizures, thirst\nCorrect slowly: max 10–12 mEq/L/day (risk cerebral edema)"],
["K+ (3.5–5.0)", "U-waves, arrhythmias, weakness, ileus\nCorrected by IV KCl + fix Mg", "Peaked T-waves -> VF -> asystole\nCalcium first to stabilize membrane"],
["Ca2+ (8.5–10.5)", "Chvostek's/Trousseau's, tetany, prolonged QT\nIV calcium gluconate; fix Mg", "Bones/Stones/Groans/Moans, short QT\nIV saline -> furosemide -> bisphosphonates"],
["Mg2+ (1.5–2.5)", "Refractory hypoK+/hypoCalc, torsades, seizures\nIV MgSO4 1-2 g; fix before K+ & Ca2+", "Loss of DTRs, respiratory arrest, cardiac arrest\nIV calcium gluconate; dialysis"],
["PO4 (2.5–4.5)", "Respiratory failure, rhabdomyolysis, hemolysis\n2,3-DPG depletion -> tissue hypoxia", "Reciprocal hypocalcemia, vascular calcification\nPhosphate binders, dietary restriction, dialysis"],
["Cl- (98–106)", "Metabolic alkalosis\nIV NaCl or KCl", "Non-anion gap metabolic acidosis\nBalanced crystalloids"],
],
col_widths=[4*cm, 8.5*cm, 8*cm]
))
story.append(SP(10))
# ── Source footer ──
story.append(HR())
story.append(Paragraph(
"Sources: Morgan & Mikhail's Clinical Anesthesiology, 7e | Comprehensive Clinical Nephrology, 7e | Miller's Anesthesia, 10e | Guyton & Hall Textbook of Medical Physiology",
SOURCES_STYLE))
# ─── Build PDF ─────────────────────────────────────────────────────────────────
OUTPUT = "/home/daytona/workspace/electrolytes-pdf/Electrolyte_Imbalances.pdf"
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
rightMargin=MARGIN, leftMargin=MARGIN,
topMargin=MARGIN, bottomMargin=MARGIN,
title="Electrolyte Imbalances",
author="Orris Medical Library",
subject="Complete Clinical Overview of Electrolyte Disorders"
)
doc.build(story)
print(f"PDF created: {OUTPUT}")
cd /home/daytona/workspace/electrolytes-pdf && python generate_pdf.py 2>&1
ls -lh /home/daytona/workspace/electrolytes-pdf/Electrolyte_Imbalances.pdf
Electrolyte Imbalances
PDF Document · PDF
Acid base buffer system in 20 marker question
CO2 + H2O ⇌ H2CO3 ⇌ H+ + HCO3-(catalyzed by carbonic anhydrase in RBCs, lung alveoli, renal tubular cells)
H+ + HCO3- → H2CO3 → CO2 + H2O
- Excess CO2 stimulates respiration, which rapidly eliminates it
NaOH + H2CO3 → NaHCO3 + H2O
- Strong base replaced by weak base NaHCO3
- CO2 levels fall, inhibiting respiration, retaining CO2
pH = pKa + log [HCO3-] / [0.03 × PCO2]pH = 6.1 + log [24 mEq/L] / [0.03 × 40 mmHg]pH = 6.1 + log (24 / 1.2) = 6.1 + log 20 = 6.1 + 1.3 = 7.4
H+ (nmol/L) = 24 × PCO2 / [HCO3-]
| Parameter | Normal Value |
|---|---|
| pH | 7.35 – 7.45 |
| PCO2 | 35 – 45 mmHg |
| HCO3- | 22 – 26 mEq/L |
| [H+] | 35 – 45 nmol/L |
HCl + Na2HPO4 → NaH2PO4 + NaCl (strong acid HCl replaced by weak acid NaH2PO4)
NaOH + NaH2PO4 → Na2HPO4 + H2O (strong base NaOH replaced by weak base Na2HPO4)
CO2 + H2O → H+ + HCO3- H+ + HbO2 → HHb + O2
Fall in pH → stimulates peripheral chemoreceptors → hyperventilation → ↓ PCO2 Lower PCO2 → CO2 + H2O equilibrium shifts left → ↓ H2CO3 → ↓ H+ → pH rises back toward normal Kussmaul breathing (deep, rapid) is the clinical manifestation
Rise in pH → depresses ventilation → ↑ PCO2 → ↑ H+ → pH falls back toward normal Limited by hypoxemia (falling PO2 overrides alkalosis-induced hypoventilation)
Expected PCO2 = (1.5 × HCO3-) + 8 ± 2
- If actual PCO2 < expected → additional respiratory alkalosis
- If actual PCO2 > expected → additional respiratory acidosis (blunted compensation)
Expected PCO2 = (0.7 × HCO3-) + 21 ± 2
For each NH4+ excreted, a new HCO3- is formed in tubular cells and returned to blood
| Disorder | Renal Response | Time |
|---|---|---|
| Respiratory acidosis (↑ PCO2) | ↑ H+ secretion → ↑ HCO3- reabsorption and generation → HCO3- rises | 3-5 days |
| Respiratory alkalosis (↓ PCO2) | ↓ H+ secretion → ↓ HCO3- reabsorption → HCO3- excreted → HCO3- falls | 3-5 days |
Metabolic acidosis: HCO3- = Primary disorder (kidneys compensate via lungs in hours) Chronic respiratory acidosis: HCO3- rises by 3.5 mEq/L per 10 mmHg rise in PCO2 Acute respiratory acidosis: HCO3- rises by 1 mEq/L per 10 mmHg rise in PCO2
| Buffer System | Location | pKa | Speed | Capacity | Corrects to Normal? |
|---|---|---|---|---|---|
| Bicarbonate/CO2 | ECF | 6.1 | Immediate (secs) | Moderate | No (50-75% with lungs) |
| Phosphate | ICF + Renal tubules | 6.8 | Immediate | Small | No |
| Proteins (Hb) | ICF (RBCs) | ~6.8 | Immediate | Large | No |
| Bone carbonate | Bone | Variable | Slow (hours) | Very large | No |
| Respiratory | Lungs | - | 3-12 min | 1-2x chemical buffers | No (50-75%) |
| Renal | Kidney | - | Hours to days | Largest | Yes - complete |
Create a PDF study guide on acid-base buffer systems
mkdir -p /home/daytona/workspace/acid-base-pdf
~/acid-base-pdf/generate_acid_base.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY, TA_RIGHT
from reportlab.lib.colors import HexColor
# ─── Palette ──────────────────────────────────────────────────────────────────
NAVY = HexColor("#1B3A6B")
TEAL = HexColor("#0A7E8C")
PURPLE = HexColor("#5B2D8E")
GREEN = HexColor("#1A6E3C")
RED = HexColor("#B03A2E")
ORANGE = HexColor("#C0680A")
GOLD = HexColor("#D4A017")
LGRAY = HexColor("#F4F6F8")
MGRAY = HexColor("#E0E4EA")
DGRAY = HexColor("#444444")
WHITE = colors.white
BLACK = HexColor("#1A1A1A")
MINTBG = HexColor("#E8F9F4")
YELLOWBG= HexColor("#FEFAE0")
REDBG = HexColor("#FDEDEC")
PURPBG = HexColor("#F4EEFF")
PAGE_W, PAGE_H = A4
M = 1.7 * cm # margin
TW = PAGE_W - 2*M # text width
# ─── Style factory ────────────────────────────────────────────────────────────
def S(name, base="Normal", **kw):
return ParagraphStyle(name, parent=getSampleStyleSheet()[base], **kw)
TITLE = S("TITLE", fontSize=28, leading=34, textColor=WHITE, fontName="Helvetica-Bold", alignment=TA_CENTER)
SUBT = S("SUBT", fontSize=12, leading=16, textColor=HexColor("#B3D9F0"), fontName="Helvetica", alignment=TA_CENTER)
SRCFOOT = S("SRC", fontSize=7.5, leading=10, textColor=HexColor("#999999"), fontName="Helvetica-Oblique", alignment=TA_CENTER)
SEC = S("SEC", fontSize=13, leading=17, textColor=WHITE, fontName="Helvetica-Bold", leftIndent=10)
SUBSEC = S("SUBSEC",fontSize=11, leading=14, textColor=WHITE, fontName="Helvetica-Bold", leftIndent=8)
H3 = S("H3", fontSize=10.5, leading=14, textColor=NAVY, fontName="Helvetica-Bold", spaceBefore=8, spaceAfter=3)
H4 = S("H4", fontSize=10, leading=13, textColor=TEAL, fontName="Helvetica-Bold", spaceBefore=6, spaceAfter=2)
BODY = S("BODY", fontSize=9.3, leading=14, textColor=BLACK, fontName="Helvetica", alignment=TA_JUSTIFY, spaceAfter=2)
BUL = S("BUL", fontSize=9.3, leading=14, textColor=BLACK, fontName="Helvetica", leftIndent=14, bulletIndent=4, spaceAfter=1)
BUL2 = S("BUL2", fontSize=9, leading=13, textColor=DGRAY, fontName="Helvetica", leftIndent=26, bulletIndent=16, spaceAfter=1)
EQ = S("EQ", fontSize=10, leading=15, textColor=PURPLE, fontName="Helvetica-Bold", alignment=TA_CENTER, spaceBefore=4, spaceAfter=4)
NOTE = S("NOTE", fontSize=8.5, leading=12, textColor=DGRAY, fontName="Helvetica-Oblique", leftIndent=10)
MNEMO = S("MNEMO", fontSize=11, leading=16, textColor=PURPLE, fontName="Helvetica-Bold", alignment=TA_CENTER, spaceBefore=4, spaceAfter=4)
BOXHEAD = S("BOXHEAD",fontSize=10, leading=13, textColor=WHITE, fontName="Helvetica-Bold", alignment=TA_CENTER)
BOXTXT = S("BOXTXT",fontSize=9.3, leading=13, textColor=BLACK, fontName="Helvetica", alignment=TA_LEFT)
TABLEHDR= S("THDR", fontSize=9, leading=12, textColor=WHITE, fontName="Helvetica-Bold", alignment=TA_CENTER)
TABLECL = S("TCELL", fontSize=8.8, leading=12, textColor=BLACK, fontName="Helvetica", alignment=TA_LEFT)
# ─── Helpers ──────────────────────────────────────────────────────────────────
def sp(n=6): return Spacer(1, n)
def hr(color=MGRAY): return HRFlowable(width="100%", thickness=0.6, color=color, spaceAfter=4, spaceBefore=4)
def p(text, style=BODY): return Paragraph(text, style)
def b(text): return Paragraph(f"<bullet>\u2022</bullet> {text}", BUL)
def b2(text): return Paragraph(f"<bullet>\u2013</bullet> {text}", BUL2)
def eq(text): return Paragraph(text, EQ)
def note(text): return Paragraph(f"\u24d8 {text}", NOTE)
def banner(title, color=TEAL, style=SEC):
t = Table([[Paragraph(title, style)]], colWidths=[TW])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), color),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("LEFTPADDING", (0,0), (-1,-1), 12),
]))
return t
def subbanner(title, color=NAVY):
return banner(title, color=color, style=SUBSEC)
def make_table(headers, rows, col_widths=None, hdr_color=NAVY, alt=LGRAY):
if col_widths is None:
col_widths = [TW / len(headers)] * len(headers)
hrow = [Paragraph(f"<b>{h}</b>", TABLEHDR) for h in headers]
data = [hrow] + [[Paragraph(str(c), TABLECL) for c in row] for row in rows]
style = [
("BACKGROUND", (0,0), (-1,0), hdr_color),
("GRID", (0,0), (-1,-1), 0.4, HexColor("#BBBBBB")),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
]
for i in range(1, len(data)):
if i % 2 == 0:
style.append(("BACKGROUND", (0,i), (-1,i), alt))
t = Table(data, colWidths=col_widths)
t.setStyle(TableStyle(style))
return t
def colored_box(title, items, bg=MINTBG, border=TEAL, title_color=TEAL):
"""A highlighted info box with title and bullet items."""
rows = [[Paragraph(f"<b>{title}</b>", S("bxh", fontSize=10, leading=13,
textColor=title_color, fontName="Helvetica-Bold"))]]
for item in items:
rows.append([Paragraph(f"\u2022 {item}", BOXTXT)])
t = Table(rows, colWidths=[TW - 1.2*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("BOX", (0,0), (-1,-1), 1.2, border),
("LINEBELOW", (0,0), (0,0), 0.8, border),
]))
outer = Table([[t]], colWidths=[TW])
outer.setStyle(TableStyle([
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 0),
]))
return outer
def two_col(left_items, right_items, left_title, right_title,
lbg=MINTBG, rbg=YELLOWBG, lborder=TEAL, rborder=ORANGE):
lrows = [[Paragraph(f"<b>{left_title}</b>",
S("lt", fontSize=9.5, leading=13, textColor=lborder, fontName="Helvetica-Bold"))]]
for i in left_items:
lrows.append([Paragraph(f"\u2022 {i}", BOXTXT)])
rrows = [[Paragraph(f"<b>{right_title}</b>",
S("rt", fontSize=9.5, leading=13, textColor=rborder, fontName="Helvetica-Bold"))]]
for i in right_items:
rrows.append([Paragraph(f"\u2022 {i}", BOXTXT)])
lt = Table(lrows, colWidths=[(TW/2) - 0.3*cm])
rt = Table(rrows, colWidths=[(TW/2) - 0.3*cm])
for tbl, bg, border in [(lt, lbg, lborder), (rt, rbg, rborder)]:
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), bg),
("LEFTPADDING", (0,0),(-1,-1), 8),
("RIGHTPADDING", (0,0),(-1,-1), 8),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("BOX", (0,0),(-1,-1), 1, border),
("LINEBELOW", (0,0),(0,0), 0.8, border),
]))
outer = Table([[lt, rt]], colWidths=[TW/2, TW/2])
outer.setStyle(TableStyle([
("TOPPADDING", (0,0),(-1,-1), 0),
("BOTTOMPADDING", (0,0),(-1,-1), 0),
("LEFTPADDING", (0,0),(-1,-1), 0),
("RIGHTPADDING", (0,0),(-1,-1), 0),
("VALIGN", (0,0),(-1,-1), "TOP"),
]))
return outer
# ══════════════════════════════════════════════════════════════════════════════
# BUILD STORY
# ══════════════════════════════════════════════════════════════════════════════
story = []
# ── COVER ─────────────────────────────────────────────────────────────────────
cover = Table([[
Paragraph("Acid-Base Buffer Systems", TITLE),
Paragraph("A Complete Study Guide for Medical Examinations", SUBT),
sp(8),
Paragraph("Chemical Buffers \u00b7 Respiratory Regulation \u00b7 Renal Regulation", SUBT),
sp(6),
Paragraph("Based on: Guyton & Hall Textbook of Medical Physiology | Ganong's Review of Medical Physiology | Murray & Nadel's Respiratory Medicine", SRCFOOT),
]], colWidths=[TW])
cover.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), NAVY),
("TOPPADDING", (0,0),(-1,-1), 26),
("BOTTOMPADDING", (0,0),(-1,-1), 26),
("LEFTPADDING", (0,0),(-1,-1), 18),
("RIGHTPADDING", (0,0),(-1,-1), 18),
("ALIGN", (0,0),(-1,-1), "CENTER"),
]))
story.append(cover)
story.append(sp(12))
# ── INTRODUCTION ──────────────────────────────────────────────────────────────
story.append(banner("Introduction & Overview"))
story.append(sp(5))
story.append(p("The body continuously produces acids from metabolism. Normal cellular respiration generates approximately <b>13,000–20,000 mmol of CO\u2082</b> (carbonic acid) daily. Protein catabolism and other metabolic pathways yield ~<b>80 mEq of non-volatile strong acids</b> (H\u2082SO\u2084, H\u2083PO\u2084, HCl) each day. Without a buffering system, these acids would rapidly lower pH to lethal levels."))
story.append(sp(4))
story.append(p("Normal arterial pH is maintained within a tight range of <b>7.35 \u2013 7.45</b>. Below 7.35 = <b>Acidosis</b>. Above 7.45 = <b>Alkalosis</b>. A pH below 6.8 or above 7.8 is incompatible with life."))
story.append(sp(6))
# Three lines of defense
story.append(p("<b>The Three Lines of Defense Against pH Change:</b>"))
story.append(sp(3))
lines_data = [
["Line", "System", "Onset", "Effectiveness", "Corrects to Normal?"],
["1st", "Chemical Buffers (Bicarbonate, Phosphate, Proteins, Bone)", "Immediate (seconds)", "Moderate", "No – partial only"],
["2nd", "Respiratory Regulation (Lungs)", "3 – 12 minutes", "50–75% of change", "No – partial only"],
["3rd", "Renal Regulation (Kidneys)", "Hours to days (2–5 days full)", "Complete", "Yes – fully corrects"],
]
story.append(make_table(
lines_data[0], lines_data[1:],
col_widths=[1.2*cm, 7.5*cm, 3.2*cm, 3.2*cm, 3.4*cm]
))
story.append(sp(12))
# ══════════════════════════════════════════════════════════════════════════════
# PAGE 2 – BICARBONATE BUFFER
# ══════════════════════════════════════════════════════════════════════════════
story.append(PageBreak())
story.append(banner("1. Chemical Buffer Systems", color=PURPLE))
story.append(sp(5))
story.append(p("A <b>buffer</b> is a substance that minimises changes in pH when a strong acid or base is added to a solution, by converting the strong acid/base into a weak one. Chemical buffers act <i>immediately</i> but cannot fully correct a disturbance on their own."))
story.append(sp(8))
# --- 1A: Bicarbonate ---
story.append(subbanner("1A. Bicarbonate – Carbonic Acid Buffer System (Primary ECF Buffer)", color=TEAL))
story.append(sp(5))
story.append(p("This is the <b>most important extracellular buffer</b> despite an apparently unfavourable pKa of 6.1 (far from physiological pH 7.4). Its true power comes from being an <b>open system</b> – both components are independently regulated by the lungs (CO\u2082) and kidneys (HCO\u2083\u207b), allowing precise titration of pH."))
story.append(sp(6))
story.append(H3("Core Reaction Cascade"))
story.append(eq("CO\u2082 + H\u2082O \u21cc H\u2082CO\u2083 \u21cc H\u207a + HCO\u2083\u207b"))
story.append(note("Catalysed by carbonic anhydrase (CA) – found in RBCs, lung alveoli, renal tubular epithelium. Without CA, this reaction is too slow to be physiologically useful."))
story.append(sp(6))
story.append(two_col(
["H\u207a + HCO\u2083\u207b \u2192 H\u2082CO\u2083 \u2192 CO\u2082 + H\u2082O",
"Excess CO\u2082 stimulates chemoreceptors \u2192 hyperventilation",
"CO\u2082 rapidly expelled by lungs",
"Net: strong acid converted to weak volatile acid"],
["NaOH + H\u2082CO\u2083 \u2192 NaHCO\u2083 + H\u2082O",
"Strong base NaOH replaced by weak base NaHCO\u2083",
"CO\u2082 levels fall \u2192 inhibits ventilation \u2192 CO\u2082 retained",
"Net: strong base neutralised by weak acid"],
"Buffering a Strong Acid (e.g., HCl)",
"Buffering a Strong Base (e.g., NaOH)",
lbg=MINTBG, rbg=YELLOWBG, lborder=TEAL, rborder=ORANGE
))
story.append(sp(8))
story.append(H3("Henderson-Hasselbalch Equation"))
story.append(eq("pH = pKa + log [HCO\u2083\u207b] \u00f7 [0.03 \u00d7 PCO\u2082]"))
story.append(eq("pH = 6.1 + log (24 mEq/L) \u00f7 (0.03 \u00d7 40 mmHg) = 6.1 + log 20 = 6.1 + 1.3 = <b>7.4</b>"))
story.append(sp(3))
story.append(p("At physiological pH, the ratio HCO\u2083\u207b : dissolved CO\u2082 = <b>20 : 1</b>. pH depends not on absolute concentrations but on this <i>ratio</i>. Anything that changes the numerator (HCO\u2083\u207b, renal) or denominator (PCO\u2082, respiratory) shifts pH."))
story.append(sp(5))
story.append(note("Kassirer-Bleich clinical approximation: H\u207a (nmol/L) = 24 \u00d7 PCO\u2082 / HCO\u2083\u207b \u2014 useful for checking ABG internal consistency"))
story.append(sp(6))
story.append(H3("Normal ABG Values"))
story.append(make_table(
["Parameter", "Normal Value", "Acidosis Threshold", "Alkalosis Threshold"],
[
["pH", "7.35 – 7.45", "< 7.35", "> 7.45"],
["PCO\u2082", "35 – 45 mmHg", "> 45 (respiratory acidosis)", "< 35 (respiratory alkalosis)"],
["HCO\u2083\u207b", "22 – 26 mEq/L", "< 22 (metabolic acidosis)", "> 26 (metabolic alkalosis)"],
["[H\u207a]", "35 – 45 nmol/L", "> 45", "< 35"],
["Base Excess", "\u00b12 mEq/L", "< -2 (metabolic acidosis)", "> +2 (metabolic alkalosis)"],
],
col_widths=[4*cm, 4*cm, 5*cm, 5.5*cm]
))
story.append(sp(6))
story.append(note("Why is bicarbonate the most powerful ECF buffer despite pKa 6.1? \u2014 Because the open-system regulation by lungs and kidneys effectively extends its buffering range far beyond the normal chemical limits."))
story.append(sp(10))
# --- 1B: Phosphate ---
story.append(subbanner("1B. Phosphate Buffer System (Primary ICF + Renal Tubular Buffer)", color=GREEN))
story.append(sp(5))
story.append(p("The phosphate buffer system plays a limited role in extracellular fluid but is <b>critical in two key compartments:</b> the renal tubular lumen and the intracellular fluid (pKa 6.8 – closer to intracellular pH)."))
story.append(sp(5))
story.append(H3("Components and Reactions"))
story.append(eq("H\u2082PO\u2084\u207b \u21cc H\u207a + HPO\u2084\u00b2\u207b (pKa = 6.8)"))
story.append(sp(3))
story.append(two_col(
["HCl + Na\u2082HPO\u2084 \u2192 NaH\u2082PO\u2084 + NaCl",
"Strong acid HCl replaced by weak acid NaH\u2082PO\u2084",
"pH decrease minimised"],
["NaOH + NaH\u2082PO\u2084 \u2192 Na\u2082HPO\u2084 + H\u2082O",
"Strong base NaOH replaced by weak base Na\u2082HPO\u2084",
"pH rise minimised"],
"Acid Load", "Base Load",
lbg=MINTBG, rbg=YELLOWBG, lborder=GREEN, rborder=ORANGE
))
story.append(sp(5))
story.append(H3("Renal Significance"))
story.append(b("Secreted H\u207a in renal tubules combines with HPO\u2084\u00b2\u207b \u2192 H\u2082PO\u2084\u207b (excreted in urine as titratable acid)"))
story.append(b("For each H\u207a excreted with phosphate, a new HCO\u2083\u207b is generated and returned to blood"))
story.append(b("Titratable acid is measured by titrating urine to pH 7.4 with NaOH \u2013 reflects H\u207a excreted with non-bicarbonate buffers"))
story.append(b("Minimum achievable urine pH = 4.4 to 4.5 (limit of tubular H\u207a secretion gradient)"))
story.append(sp(10))
# --- 1C: Protein buffers ---
story.append(subbanner("1C. Protein Buffer System (Most Abundant Intracellular Buffer)", color=RED))
story.append(sp(5))
story.append(p("Proteins are the <b>most abundant intracellular buffers</b>. Haemoglobin (Hb) in red blood cells is the single most important protein buffer in blood – approximately <b>6 times more potent</b> per gram than plasma proteins, due to abundant histidine residues."))
story.append(sp(5))
story.append(H3("Buffering Mechanism"))
story.append(b("Proteins contain multiple <b>histidine residues</b> whose imidazole side chains have a pKa of 6.0–7.0 \u2013 ideal for physiological pH buffering"))
story.append(b("At low pH: imidazole \u2013NH accepts H\u207a \u2192 \u2013NH\u2082\u207a"))
story.append(b("At high pH: imidazole \u2013NH releases H\u207a"))
story.append(b("Intracellular proteins buffer ~60% of an acute acid load entering cells"))
story.append(sp(6))
story.append(H3("The Haldane Effect (Hb as buffer)"))
story.append(p("Deoxygenated Hb (HHb) is a <i>weaker acid</i> than oxygenated Hb (HbO\u2082). This difference underpins the <b>isohydric shift</b> – massive CO\u2082 transport occurs without significant pH change:"))
story.append(sp(4))
story.append(make_table(
["Location", "Process", "Buffering Action"],
[
["Peripheral tissues", "O\u2082 unloads \u2192 Hb deoxygenated \u2192 becomes weaker acid",
"Better H\u207a acceptor \u2192 buffers CO\u2082-derived H\u207a \u2192 facilitates CO\u2082 transport as HCO\u2083\u207b"],
["Lungs", "O\u2082 loads \u2192 Hb oxygenated \u2192 becomes stronger acid",
"Releases H\u207a \u2192 combines with HCO\u2083\u207b \u2192 forms CO\u2082 + H\u2082O \u2192 CO\u2082 expelled"],
],
col_widths=[3.5*cm, 6.5*cm, 7.5*cm]
))
story.append(sp(5))
story.append(eq("CO\u2082 + H\u2082O \u2192 H\u207a + HCO\u2083\u207b | H\u207a + HbO\u2082 \u2192 HHb + O\u2082"))
story.append(sp(10))
# --- 1D: Bone ---
story.append(subbanner("1D. Bone Buffer System (Slow, High-Capacity Chronic Buffer)", color=ORANGE))
story.append(sp(5))
story.append(b("Bone carbonate (CaCO\u2083) and phosphate (CaHPO\u2084) act as a large-capacity slow buffer"))
story.append(b("In chronic acidosis: H\u207a is absorbed into bone matrix \u2192 Ca\u00b2\u207a is released into blood"))
story.append(b("Clinically: Explains <b>osteoporosis and hypercalciuria</b> in chronic metabolic acidosis (CKD, RTA)"))
story.append(b("ICF buffers 55-60% of an acute acid load; bone buffers contribute significantly over hours"))
story.append(sp(12))
# ══════════════════════════════════════════════════════════════════════════════
# PAGE 3 – RESPIRATORY REGULATION
# ══════════════════════════════════════════════════════════════════════════════
story.append(PageBreak())
story.append(banner("2. Respiratory Regulation of Acid-Base Balance", color=TEAL))
story.append(sp(5))
story.append(p("The respiratory system acts as a <b>physiological buffer</b> – faster than chemical buffers for metabolic disturbances. Its overall buffering power is <b>1 to 2 times</b> greater than all chemical buffers in the ECF combined. Response onset: <b>3–12 minutes</b>."))
story.append(sp(6))
story.append(H3("Chemoreceptor Control"))
story.append(make_table(
["Receptor", "Location", "Stimulated by", "Response"],
[
["Central chemoreceptors", "Ventral medulla", "Rising PCO\u2082 \u2192 falling CSF pH; CO\u2082 crosses BBB freely", "Most powerful driver of ventilation in normal conditions"],
["Peripheral chemoreceptors", "Carotid & aortic bodies", "Falling PO\u2082 (< 60 mmHg), rising PCO\u2082, falling pH", "Critical in hypoxic drive; important in metabolic acidosis"],
],
col_widths=[3.8*cm, 3.8*cm, 5.2*cm, 5.7*cm]
))
story.append(sp(8))
story.append(H3("Respiratory Response to Metabolic Disorders"))
story.append(two_col(
["pH falls \u2192 stimulates peripheral chemoreceptors",
"\u2191 Ventilation (rate and depth) \u2192 \u2193 PCO\u2082",
"\u2193 PCO\u2082 \u2192 \u2193 H\u2082CO\u2083 \u2192 \u2193 H\u207a \u2192 pH rises toward normal",
"Clinical sign: <b>Kussmaul breathing</b> (deep, sighing respirations)",
"Winter's Formula: Expected PCO\u2082 = (1.5 \u00d7 HCO\u2083\u207b) + 8 \u00b1 2"],
["pH rises \u2192 depresses ventilation",
"\u2193 Ventilation \u2192 \u2191 PCO\u2082 retention",
"\u2191 PCO\u2082 \u2192 \u2191 H\u2082CO\u2083 \u2192 \u2191 H\u207a \u2192 pH falls toward normal",
"<b>LIMITED</b> by hypoxemia: falling PO\u2082 overrides alkalosis-driven hypoventilation",
"Expected PCO\u2082 = (0.7 \u00d7 HCO\u2083\u207b) + 21 \u00b1 2"],
"Metabolic Acidosis \u2192 Hyperventilation",
"Metabolic Alkalosis \u2192 Hypoventilation",
lbg=REDBG, rbg=PURPBG, lborder=RED, rborder=PURPLE
))
story.append(sp(8))
story.append(H3("Limitations of Respiratory Compensation"))
story.append(b("Can return pH only <b>50–75% back to normal</b> (feedback gain of 1–3)"))
story.append(b("Example: pH drops 7.4 \u2192 7.0 \u2192 respiratory compensation returns it to ~7.2–7.3, not fully to 7.4"))
story.append(b("Cannot compensate for <i>primary</i> respiratory disorders \u2013 the lungs cannot compensate for their own failure"))
story.append(b("Metabolic alkalosis compensation is limited because hypoxemia prevents adequate hypoventilation"))
story.append(sp(8))
story.append(colored_box(
"Winter's Compensation Formulas (Metabolic Disorders)",
[
"Metabolic Acidosis \u2014 Expected PCO\u2082 = (1.5 \u00d7 HCO\u2083\u207b) + 8 \u00b1 2 mmHg",
"Metabolic Alkalosis \u2014 Expected PCO\u2082 = (0.7 \u00d7 HCO\u2083\u207b) + 21 \u00b1 2 mmHg",
"If actual PCO\u2082 < expected \u2192 additional primary respiratory alkalosis",
"If actual PCO\u2082 > expected \u2192 additional primary respiratory acidosis (blunted compensation)",
],
bg=MINTBG, border=TEAL, title_color=TEAL
))
story.append(sp(12))
# ══════════════════════════════════════════════════════════════════════════════
# PAGE 4 – RENAL REGULATION
# ══════════════════════════════════════════════════════════════════════════════
story.append(PageBreak())
story.append(banner("3. Renal Regulation of Acid-Base Balance", color=GREEN))
story.append(sp(5))
story.append(p("The kidneys are the <b>only system that can fully and completely correct</b> acid-base disturbances. While chemical buffers and the respiratory system only partially compensate, the kidneys can restore pH precisely to normal. However, they act slowly \u2013 requiring <b>hours to days</b> for full effect."))
story.append(sp(5))
story.append(p("Each day, the kidneys filter ~<b>4,320 mEq of HCO\u2083\u207b</b> (180 L/day \u00d7 24 mEq/L). Under normal conditions, virtually all of this is reabsorbed. The kidneys also excrete ~80 mEq of net acid daily to balance dietary acid production."))
story.append(sp(8))
story.append(H3("Three Renal Mechanisms"))
story.append(sp(2))
# Mechanism 1
story.append(subbanner("Mechanism 1: HCO\u2083\u207b Reabsorption (Reclamation)", color=TEAL))
story.append(sp(4))
story.append(b("<b>Location:</b> Proximal tubule (~85%) and thick ascending limb of loop of Henle"))
story.append(b("Tubular cell secretes H\u207a into lumen via Na\u207a/H\u207a exchanger (NHE3)"))
story.append(b("H\u207a + HCO\u2083\u207b (filtered) \u2192 H\u2082CO\u2083 \u2192 CO\u2082 + H\u2082O (by brush-border carbonic anhydrase)"))
story.append(b("CO\u2082 diffuses into tubular cell \u2192 reformed into HCO\u2083\u207b (basolateral carbonic anhydrase) \u2192 returned to blood"))
story.append(b("Net effect: HCO\u2083\u207b is conserved; H\u207a is recycled (not net excreted)"))
story.append(b("In acidosis: H\u207a secretion \u2191 \u2192 more HCO\u2083\u207b reabsorbed \u2192 plasma HCO\u2083\u207b rises (metabolic compensation)"))
story.append(sp(8))
# Mechanism 2
story.append(subbanner("Mechanism 2: Titratable Acid Excretion (Phosphate Buffer)", color=GREEN))
story.append(sp(4))
story.append(b("Secreted H\u207a combines with HPO\u2084\u00b2\u207b (filtered) \u2192 H\u2082PO\u2084\u207b \u2192 excreted in urine"))
story.append(b("For each H\u207a excreted this way, a <b>new HCO\u2083\u207b is generated</b> and added to blood"))
story.append(b("This is <i>true net acid excretion</i> \u2013 H\u207a permanently removed from body"))
story.append(b("Minimum urine pH achievable = <b>4.4 \u2013 4.5</b> (limit of H\u207a secretion gradient)"))
story.append(b("Titratable acid accounts for ~30\u201350% of daily net acid excretion under normal conditions"))
story.append(sp(8))
# Mechanism 3
story.append(subbanner("Mechanism 3: Ammonium Buffer System (Dominant in Chronic Acidosis)", color=PURPLE))
story.append(sp(4))
story.append(b("<b>Substrate:</b> Glutamine deaminated in proximal tubular cells \u2192 NH\u2083 (ammonia) + HCO\u2083\u207b"))
story.append(b("NH\u2083 diffuses freely into tubular lumen (lipid soluble)"))
story.append(b("NH\u2083 + secreted H\u207a \u2192 <b>NH\u2084\u207a</b> (ammonium ion \u2013 not lipid soluble \u2192 <i>trapped</i> in lumen \u2192 excreted)"))
story.append(b("For each NH\u2084\u207a excreted, one new HCO\u2083\u207b is generated in tubular cells and returned to blood"))
story.append(b("Normal output: ~40 mEq/day (30\u201350% of daily net acid excretion)"))
story.append(b("<b>Chronic acidosis:</b> NH\u2084\u207a excretion can increase to <b>500 mEq/day</b> \u2013 the dominant mechanism in prolonged acidosis"))
story.append(b("Impaired in CKD \u2192 reduced capacity to excrete acid \u2192 metabolic acidosis of renal failure"))
story.append(sp(6))
story.append(note("Key rule: Ammonium excretion is the primary mechanism for generating new HCO\u2083\u207b during chronic acidosis (Guyton & Hall)."))
story.append(sp(8))
story.append(H3("Renal Compensation for Primary Respiratory Disorders"))
story.append(make_table(
["Disorder", "Primary Change", "Renal Compensation", "Expected HCO\u2083\u207b Change", "Time Course"],
[
["Acute Respiratory Acidosis", "\u2191 PCO\u2082", "\u2191 H\u207a secretion \u2192 \u2191 HCO\u2083\u207b reabsorption", "+1 mEq/L per 10 mmHg \u2191 PCO\u2082", "Minutes (chemical)"],
["Chronic Respiratory Acidosis", "\u2191 PCO\u2082 (>24 hrs)", "\u2191 HCO\u2083\u207b reabsorption + new HCO\u2083\u207b generation", "+3.5 mEq/L per 10 mmHg \u2191 PCO\u2082", "3–5 days"],
["Acute Respiratory Alkalosis", "\u2193 PCO\u2082", "\u2193 H\u207a secretion \u2192 \u2193 HCO\u2083\u207b reabsorption", "\u22122 mEq/L per 10 mmHg \u2193 PCO\u2082", "Minutes"],
["Chronic Respiratory Alkalosis", "\u2193 PCO\u2082 (>24 hrs)", "\u2193 HCO\u2083\u207b reabsorption + HCO\u2083\u207b excretion", "\u22125 mEq/L per 10 mmHg \u2193 PCO\u2082", "3–5 days"],
],
col_widths=[3.8*cm, 3.2*cm, 5*cm, 4.5*cm, 2.7*cm]
))
story.append(sp(12))
# ══════════════════════════════════════════════════════════════════════════════
# PAGE 5 – ACID-BASE DISORDERS + CLINICAL APPLICATION
# ══════════════════════════════════════════════════════════════════════════════
story.append(PageBreak())
story.append(banner("4. Primary Acid-Base Disorders & Compensation", color=RED))
story.append(sp(6))
story.append(make_table(
["Disorder", "Primary Defect", "pH", "PCO\u2082", "HCO\u2083\u207b", "Compensatory Response", "Common Causes"],
[
["Metabolic Acidosis", "\u2193 HCO\u2083\u207b", "\u2193", "\u2193 (comp.)", "\u2193\u2193", "Hyperventilation; \u2193 PCO\u2082", "DKA, lactic acidosis, diarrhea, renal failure, RTA, salicylate poisoning"],
["Metabolic Alkalosis", "\u2191 HCO\u2083\u207b", "\u2191", "\u2191 (comp.)", "\u2191\u2191", "Hypoventilation; \u2191 PCO\u2082 (limited by hypoxia)", "Vomiting, NG suction, diuretics, hyperaldosteronism, antacid excess"],
["Respiratory Acidosis", "\u2191 PCO\u2082", "\u2193", "\u2191\u2191", "\u2191 (comp.)", "Kidneys retain HCO\u2083\u207b, increase NH\u2084\u207a excretion", "COPD, respiratory failure, opioid overdose, obesity hypoventilation"],
["Respiratory Alkalosis", "\u2193 PCO\u2082", "\u2191", "\u2193\u2193", "\u2193 (comp.)", "Kidneys excrete HCO\u2083\u207b", "Anxiety, hypoxemia, PE, pregnancy, salicylate toxicity (early), sepsis"],
],
col_widths=[3.2*cm, 2.5*cm, 1.2*cm, 1.8*cm, 2*cm, 4*cm, 5*cm]
))
story.append(sp(10))
story.append(banner("5. Anion Gap & Clinical Tools", color=ORANGE))
story.append(sp(6))
story.append(H3("Anion Gap (AG)"))
story.append(eq("AG = Na\u207a \u2013 (Cl\u207b + HCO\u2083\u207b) Normal = 8 – 12 mEq/L (up to 16 with albumin correction)"))
story.append(sp(3))
story.append(p("The AG represents unmeasured anions (albumin, phosphate, sulfate, organic acids). It is used to classify metabolic acidosis:"))
story.append(sp(4))
story.append(two_col(
["Lactic acidosis (sepsis, shock, metformin)",
"Diabetic ketoacidosis (DKA)",
"Alcoholic ketoacidosis",
"Renal failure / uraemia (phosphates, sulfates)",
"Salicylate / aspirin toxicity",
"Methanol / ethylene glycol poisoning",
"Mnemonic: <b>MUDPILES</b> or <b>GOLDMARK</b>"],
["Normal saline infusion (hyperchloraemic)",
"Renal tubular acidosis (RTA)",
"Diarrhoea (HCO\u2083\u207b loss from GI tract)",
"Ureterosigmoidostomy / ileal conduit",
"Carbonic anhydrase inhibitors (acetazolamide)",
"Addison's disease (hypoaldosteronism)"],
"High Anion Gap Metabolic Acidosis",
"Normal Anion Gap (Hyperchloraemic) Metabolic Acidosis",
lbg=REDBG, rbg=YELLOWBG, lborder=RED, rborder=ORANGE
))
story.append(sp(8))
story.append(H3("Delta-Delta Ratio (in high AG metabolic acidosis)"))
story.append(eq("\u0394\u0394 = \u0394 AG \u00f7 \u0394 HCO\u2083\u207b = (Calculated AG \u2013 12) \u00f7 (24 \u2013 Measured HCO\u2083\u207b)"))
story.append(make_table(
["\u0394\u0394 Value", "Interpretation"],
[
["< 1", "Concurrent normal anion gap metabolic acidosis present"],
["1 – 2", "Pure high anion gap metabolic acidosis"],
["> 2", "Concurrent metabolic alkalosis present (masking HCO\u2083\u207b loss)"],
],
col_widths=[4*cm, 14.5*cm]
))
story.append(sp(10))
story.append(banner("6. Systematic ABG Interpretation", color=NAVY))
story.append(sp(6))
steps = [
("Step 1: Assess pH", "Normal 7.35–7.45. < 7.35 = acidosis. > 7.45 = alkalosis. Identifies the <i>primary</i> disorder."),
("Step 2: Check PCO\u2082", "35–45 mmHg. \u2191 PCO\u2082 \u2192 respiratory acidosis. \u2193 PCO\u2082 \u2192 respiratory alkalosis. Does PCO\u2082 match the pH direction?"),
("Step 3: Check HCO\u2083\u207b", "22–26 mEq/L. \u2193 HCO\u2083\u207b \u2192 metabolic acidosis. \u2191 HCO\u2083\u207b \u2192 metabolic alkalosis. Does HCO\u2083\u207b match pH direction?"),
("Step 4: Identify primary disorder", "The parameter that explains the pH change is the primary disorder."),
("Step 5: Assess compensation", "Is compensation present and appropriate? Use Winter's formula for metabolic disorders. Use expected HCO\u2083\u207b change formulas for respiratory disorders."),
("Step 6: Calculate Anion Gap", "If metabolic acidosis present, calculate AG. If high AG, calculate \u0394\u0394 ratio. Albumin correction: AG + 2.5 \u00d7 (4 \u2013 albumin g/dL)."),
("Step 7: Clinical correlation", "Integrate with patient's history, symptoms, and other investigations."),
]
rows = [[Paragraph(f"<b>{s}</b>", S("sh", fontSize=9.5, leading=13, textColor=NAVY, fontName="Helvetica-Bold")),
Paragraph(d, TABLECL)] for s, d in steps]
data = [rows[0]]
for row in rows[1:]:
data.append(row)
step_tbl = Table([[Paragraph(f"<b>{s}</b>", S("sh", fontSize=9.5, leading=13, textColor=NAVY, fontName="Helvetica-Bold")),
Paragraph(d, TABLECL)] for s, d in steps],
colWidths=[4.5*cm, TW - 4.5*cm])
step_tbl.setStyle(TableStyle([
("GRID", (0,0),(-1,-1), 0.4, HexColor("#CCCCCC")),
("BACKGROUND", (0,0),(0,-1), LGRAY),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 7),
("VALIGN", (0,0),(-1,-1), "TOP"),
]))
story.append(step_tbl)
story.append(sp(12))
# ══════════════════════════════════════════════════════════════════════════════
# PAGE 6 – SUMMARY & MNEMONICS
# ══════════════════════════════════════════════════════════════════════════════
story.append(PageBreak())
story.append(banner("7. Quick Reference Summary", color=PURPLE))
story.append(sp(6))
story.append(H3("Buffer Systems at a Glance"))
story.append(make_table(
["Buffer System", "Location", "pKa", "Speed", "Capacity", "Fully Corrects?"],
[
["Bicarbonate/CO\u2082", "ECF (plasma)", "6.1", "Immediate (secs)", "Moderate (open system)", "No \u2013 partial"],
["Phosphate", "ICF + renal tubules", "6.8", "Immediate", "Small extracellularly", "No \u2013 partial"],
["Proteins (Hb)", "ICF (RBCs, cells)", "~6.8 (His)", "Immediate", "Large \u2013 most abundant ICF", "No \u2013 partial"],
["Bone Carbonate", "Bone matrix", "Variable", "Slow (hours)", "Very large (chronic)", "No \u2013 partial"],
["Respiratory (Lungs)", "Extracorporeal", "\u2014", "3\u201312 min", "1\u20132\u00d7 all chemical buffers", "No \u2013 50\u201375%"],
["Renal (Kidneys)", "Systemic", "\u2014", "Hours\u2013days", "Largest \u2013 unlimited", "YES \u2013 complete"],
],
col_widths=[4*cm, 3.5*cm, 1.5*cm, 3*cm, 4*cm, 2.5*cm]
))
story.append(sp(10))
story.append(H3("Key Equations Summary"))
story.append(make_table(
["Equation / Formula", "Expression", "Used For"],
[
["Henderson-Hasselbalch", "pH = 6.1 + log [HCO\u2083\u207b] / (0.03 \u00d7 PCO\u2082)", "Calculate pH from HCO\u2083\u207b and PCO\u2082"],
["Kassirer-Bleich", "H\u207a (nmol/L) = 24 \u00d7 PCO\u2082 / HCO\u2083\u207b", "ABG internal consistency check"],
["Anion Gap", "AG = Na\u207a \u2013 (Cl\u207b + HCO\u2083\u207b); normal 8\u201312", "Classify metabolic acidosis"],
["Delta-Delta", "\u0394\u0394 = (AG\u20131\u20122) / (2\u20134 \u2013 HCO\u2083\u207b)", "Detect mixed metabolic disorders"],
["Winter's (met. acidosis)", "Expected PCO\u2082 = (1.5 \u00d7 HCO\u2083\u207b) + 8 \u00b1 2", "Check respiratory compensation"],
["Winter's (met. alkalosis)", "Expected PCO\u2082 = (0.7 \u00d7 HCO\u2083\u207b) + 21 \u00b1 2", "Check respiratory compensation"],
["Acute resp. acidosis comp.", "HCO\u2083\u207b \u2191 by 1 mEq/L per 10 mmHg \u2191 PCO\u2082", "Renal response check"],
["Chronic resp. acidosis comp.", "HCO\u2083\u207b \u2191 by 3.5 mEq/L per 10 mmHg \u2191 PCO\u2082", "Renal response check"],
["Chronic resp. alkalosis comp.", "HCO\u2083\u207b \u2193 by 5 mEq/L per 10 mmHg \u2193 PCO\u2082", "Renal response check"],
],
col_widths=[5*cm, 6.5*cm, 7*cm]
))
story.append(sp(10))
story.append(colored_box(
"High Anion Gap Metabolic Acidosis \u2014 MUDPILES Mnemonic",
[
"M \u2013 Methanol / Metformin",
"U \u2013 Uraemia (renal failure)",
"D \u2013 Diabetic ketoacidosis",
"P \u2013 Propylene glycol / Paracetamol (late)",
"I \u2013 Isoniazid / Ischaemia (lactic acidosis)",
"L \u2013 Lactic acidosis (type A: hypoperfusion; type B: drugs, liver failure)",
"E \u2013 Ethylene glycol",
"S \u2013 Salicylates (aspirin overdose)",
],
bg=REDBG, border=RED, title_color=RED
))
story.append(sp(8))
story.append(colored_box(
"Key Clinical Pearls",
[
"Bicarbonate is the most important ECF buffer because it is an open system regulated by lungs AND kidneys",
"Haemoglobin is the most important protein buffer; the isohydric shift enables CO\u2082 transport without pH change",
"Respiratory compensation for metabolic disorders begins in minutes but corrects only 50\u201375% of the pH change",
"Renal compensation is the only mechanism that can fully and completely restore pH to normal",
"In chronic acidosis, ammonium excretion is the dominant mechanism \u2013 it can increase 10\u201312\u00d7 above baseline",
"Hypomagnesaemia impairs acid-base regulation indirectly via effects on K\u207a, renal tubular function",
"Always correct albumin before interpreting AG: corrected AG = measured AG + 2.5 \u00d7 (4 \u2013 albumin g/dL)",
"Minimum achievable urine pH = 4.4\u20134.5 \u2013 limited by the H\u207a secretion gradient in collecting duct",
],
bg=MINTBG, border=TEAL, title_color=TEAL
))
story.append(sp(6))
# Footer
story.append(hr())
story.append(p("Sources: Guyton & Hall Textbook of Medical Physiology \u00b7 Ganong's Review of Medical Physiology, 26e \u00b7 Murray & Nadel's Textbook of Respiratory Medicine \u00b7 Comprehensive Clinical Nephrology, 7e", SRCFOOT))
# ─── Build PDF ─────────────────────────────────────────────────────────────────
OUTPUT = "/home/daytona/workspace/acid-base-pdf/Acid_Base_Buffer_Systems.pdf"
doc = SimpleDocTemplate(
OUTPUT, pagesize=A4,
rightMargin=M, leftMargin=M, topMargin=M, bottomMargin=M,
title="Acid-Base Buffer Systems",
author="Orris Medical Library",
subject="Complete Study Guide for Medical Examinations"
)
doc.build(story)
print(f"SUCCESS: {OUTPUT}")
cd /home/daytona/workspace/acid-base-pdf && python generate_acid_base.py 2>&1
~/acid-base-pdf/generate_acid_base.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/acid-base-pdf/generate_acid_base.py'
sed -i 's/story\.append(H3(/story.append(h3(/g; s/story\.append(H4(/story.append…
python3 -c " content = open('/home/daytona/workspace/acid-base-pdf/generate_acid…
cd /home/daytona/workspace/acid-base-pdf && python generate_acid_base.py 2>&1
ls -lh /home/daytona/workspace/acid-base-pdf/Acid_Base_Buffer_Systems.pdf
Acid Base Buffer Systems
PDF Document · PDF
| Section | Content |
|---|---|
| Cover + Intro | Three lines of defense overview table with onset/effectiveness |
| Chemical Buffers | Bicarbonate (H-H equation, reactions, normal ABG table), Phosphate, Proteins/Hb (Haldane effect), Bone buffer |
| Respiratory Regulation | Chemoreceptors, Kussmaul breathing, Winter's formulas, compensation limits |
| Renal Regulation | All 3 mechanisms: HCO3- reclamation, titratable acid (phosphate), ammonium buffer; renal compensation tables |
| Acid-Base Disorders | All 4 primary disorders with pH/PCO2/HCO3- directions and causes |
| Clinical Tools | Anion gap, MUDPILES mnemonic, Delta-Delta ratio, 7-step ABG interpretation guide |
| Quick Reference | All buffer systems compared, all key equations in one table, clinical pearls box |