~/electrolytes/build_pdf.py
#!/usr/bin/env python3
"""
Clinical Guide to Electrolyte Imbalances - PDF Generator
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm, mm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak, KeepTogether
)
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.platypus import BaseDocTemplate, Frame, PageTemplate
from reportlab.platypus.flowables import Flowable
import os
OUTPUT = "/tmp/workspace/electrolytes/Electrolyte_Imbalances_Clinical_Guide.pdf"
# ── Colour palette ──────────────────────────────────────────────────────────
C_NAVY = colors.HexColor("#0D2B55")
C_BLUE = colors.HexColor("#1565C0")
C_LTBLUE = colors.HexColor("#E3F2FD")
C_TEAL = colors.HexColor("#00695C")
C_LTTEAL = colors.HexColor("#E0F2F1")
C_RED = colors.HexColor("#B71C1C")
C_LTRED = colors.HexColor("#FFEBEE")
C_ORANGE = colors.HexColor("#E65100")
C_LTORANGE = colors.HexColor("#FFF3E0")
C_PURPLE = colors.HexColor("#4A148C")
C_LTPURPLE = colors.HexColor("#F3E5F5")
C_GREEN = colors.HexColor("#1B5E20")
C_LTGREEN = colors.HexColor("#E8F5E9")
C_GREY = colors.HexColor("#455A64")
C_LTGREY = colors.HexColor("#ECEFF1")
C_WHITE = colors.white
C_BLACK = colors.black
C_WARN_BG = colors.HexColor("#FFF8E1")
C_WARN_BDR = colors.HexColor("#F9A825")
# ── Styles ───────────────────────────────────────────────────────────────────
base = getSampleStyleSheet()
def S(name, **kw):
"""Build a ParagraphStyle."""
return ParagraphStyle(name, **kw)
ST = {
"title": S("title",
fontSize=26, fontName="Helvetica-Bold",
textColor=C_WHITE, alignment=TA_CENTER,
spaceAfter=4, leading=32),
"subtitle": S("subtitle",
fontSize=13, fontName="Helvetica",
textColor=C_WHITE, alignment=TA_CENTER,
spaceAfter=2, leading=18),
"h1": S("h1",
fontSize=15, fontName="Helvetica-Bold",
textColor=C_WHITE, alignment=TA_LEFT,
spaceBefore=14, spaceAfter=4, leading=20),
"h2": S("h2",
fontSize=12, fontName="Helvetica-Bold",
textColor=C_NAVY, alignment=TA_LEFT,
spaceBefore=10, spaceAfter=3, leading=16),
"h3": S("h3",
fontSize=10.5, fontName="Helvetica-Bold",
textColor=C_TEAL, alignment=TA_LEFT,
spaceBefore=7, spaceAfter=2, leading=14),
"body": S("body",
fontSize=9, fontName="Helvetica",
textColor=C_BLACK, alignment=TA_JUSTIFY,
spaceBefore=2, spaceAfter=2, leading=13),
"bullet": S("bullet",
fontSize=9, fontName="Helvetica",
textColor=C_BLACK, leftIndent=14,
bulletIndent=4, spaceAfter=1, leading=13),
"code": S("code",
fontSize=8.5, fontName="Courier",
textColor=C_NAVY, backColor=C_LTGREY,
leftIndent=10, rightIndent=10,
spaceBefore=4, spaceAfter=4, leading=13),
"warn": S("warn",
fontSize=9, fontName="Helvetica-Bold",
textColor=C_RED, leftIndent=10,
spaceBefore=3, spaceAfter=3, leading=13),
"note": S("note",
fontSize=8.5, fontName="Helvetica-Oblique",
textColor=C_GREY, leftIndent=10,
spaceBefore=1, spaceAfter=1, leading=12),
"sources": S("sources",
fontSize=7.5, fontName="Helvetica-Oblique",
textColor=C_GREY, alignment=TA_CENTER,
spaceBefore=6, spaceAfter=2, leading=11),
}
def hdr_para(text, color):
return Paragraph(f'<font color="white"><b>{text}</b></font>',
ParagraphStyle("hp", fontSize=9, fontName="Helvetica-Bold",
textColor=C_WHITE, alignment=TA_CENTER,
leading=12, backColor=color))
# ── Header / Footer ──────────────────────────────────────────────────────────
def on_page(canvas, doc):
canvas.saveState()
w, h = A4
# Header bar
canvas.setFillColor(C_NAVY)
canvas.rect(0, h-28, w, 28, fill=1, stroke=0)
canvas.setFont("Helvetica-Bold", 10)
canvas.setFillColor(C_WHITE)
canvas.drawString(18, h-18, "CLINICAL GUIDE: ELECTROLYTE IMBALANCES")
canvas.setFont("Helvetica", 8)
canvas.drawRightString(w-18, h-18, "Corrections · Formulas · IV Dilutions · Oral Brands")
# Footer
canvas.setFillColor(C_NAVY)
canvas.rect(0, 0, w, 22, fill=1, stroke=0)
canvas.setFont("Helvetica", 7.5)
canvas.setFillColor(C_WHITE)
canvas.drawString(18, 7, "Sources: Schwartz 11e | Fischer 8e | Tintinalli | Goldman-Cecil | VUMC/Michigan ICU Protocols")
canvas.drawRightString(w-18, 7, f"Page {doc.page}")
canvas.restoreState()
# ── Table helpers ─────────────────────────────────────────────────────────────
def mk_table(data, col_widths, hdr_color=C_NAVY, alt_color=C_LTBLUE, fontsize=8):
"""Create a styled table. First row = header."""
style = TableStyle([
# Header
("BACKGROUND", (0, 0), (-1, 0), hdr_color),
("TEXTCOLOR", (0, 0), (-1, 0), C_WHITE),
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
("FONTSIZE", (0, 0), (-1, 0), fontsize),
("ALIGN", (0, 0), (-1, 0), "CENTER"),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
# Body
("FONTNAME", (0, 1), (-1, -1), "Helvetica"),
("FONTSIZE", (0, 1), (-1, -1), fontsize),
("TEXTCOLOR", (0, 1), (-1, -1), C_BLACK),
# Alternating rows
*[("BACKGROUND", (0, i), (-1, i), alt_color if i % 2 == 0 else C_WHITE)
for i in range(1, 50)],
# Grid
("GRID", (0, 0), (-1, -1), 0.4, colors.HexColor("#B0BEC5")),
("ROWBACKGROUND", (0, 0), (-1, 0), hdr_color),
("TOPPADDING", (0, 0), (-1, -1), 4),
("BOTTOMPADDING",(0, 0), (-1, -1), 4),
("LEFTPADDING", (0, 0), (-1, -1), 5),
("RIGHTPADDING",(0, 0), (-1, -1), 5),
])
t = Table(data, colWidths=col_widths, repeatRows=1)
t.setStyle(style)
return t
def section_hdr(text, color=C_NAVY):
"""Full-width coloured section header."""
data = [[Paragraph(f'<font color="white"><b>{text}</b></font>',
ParagraphStyle("sh", fontSize=12, fontName="Helvetica-Bold",
textColor=C_WHITE, alignment=TA_LEFT, leading=16))]]
t = Table(data, colWidths=[A4[0] - 3.6*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), color),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING",(0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
return t
def warn_box(text):
data = [[Paragraph(f'⚠ {text}',
ParagraphStyle("wb", fontSize=8.5, fontName="Helvetica-Bold",
textColor=C_RED, leading=13))]]
t = Table(data, colWidths=[A4[0] - 3.6*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_LTRED),
("BOX", (0,0), (-1,-1), 1, C_RED),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
return t
def info_box(text, bg=C_LTBLUE, bdr=C_BLUE):
data = [[Paragraph(text,
ParagraphStyle("ib", fontSize=8.5, fontName="Helvetica",
textColor=C_NAVY, leading=13))]]
t = Table(data, colWidths=[A4[0] - 3.6*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("BOX", (0,0), (-1,-1), 0.8, bdr),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
return t
def formula_box(text):
data = [[Paragraph(text,
ParagraphStyle("fb", fontSize=9, fontName="Courier",
textColor=C_NAVY, leading=14))]]
t = Table(data, colWidths=[A4[0] - 3.6*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_LTGREY),
("BOX", (0,0), (-1,-1), 1, C_NAVY),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING",(0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
return t
# ── Cover page ────────────────────────────────────────────────────────────────
def cover_page(elements):
w = A4[0] - 3.6*cm
# Big title block
title_data = [[
Paragraph("CLINICAL GUIDE TO<br/>ELECTROLYTE IMBALANCES",
ParagraphStyle("ct", fontSize=28, fontName="Helvetica-Bold",
textColor=C_WHITE, alignment=TA_CENTER, leading=36)),
]]
tt = Table(title_data, colWidths=[w])
tt.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_NAVY),
("TOPPADDING", (0,0), (-1,-1), 28),
("BOTTOMPADDING",(0,0), (-1,-1), 28),
]))
elements.append(tt)
elements.append(Spacer(1, 6))
sub_data = [[
Paragraph("Corrections per Hour · per Day · IV Dilutions · Exact Formulae · Oral Syrups & Brands",
ParagraphStyle("cs", fontSize=11, fontName="Helvetica-Bold",
textColor=C_WHITE, alignment=TA_CENTER, leading=16)),
]]
st2 = Table(sub_data, colWidths=[w])
st2.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_BLUE),
("TOPPADDING", (0,0), (-1,-1), 10),
("BOTTOMPADDING",(0,0), (-1,-1), 10),
]))
elements.append(st2)
elements.append(Spacer(1, 18))
# Summary cards
cards = [
("Na⁺ SODIUM", "Hypo/Hypernatremia\nFormulas · 3% NaCl · Free water deficit", C_BLUE, C_LTBLUE),
("K⁺ POTASSIUM", "Hypo/Hyperkalemia\nKCl IV rates · Oral brands · ECG guide", C_TEAL, C_LTTEAL),
("Ca²⁺ CALCIUM", "Hypo/Hypercalcemia\nCa Gluconate · Ca Chloride · Dilutions", C_PURPLE, C_LTPURPLE),
("Mg²⁺ MAGNESIUM","Hypo/Hypermagnesemia\nMgSO4 protocols · Oral supplements", C_ORANGE, C_LTORANGE),
("PO₄ PHOSPHATE", "Hypo/Hyperphosphatemia\nK/Na-Phos · Oral brands · IV guide", C_GREEN, C_LTGREEN),
]
for name, desc, dark, light in cards:
row = [[
Paragraph(f'<b>{name}</b>',
ParagraphStyle("cn", fontSize=11, fontName="Helvetica-Bold",
textColor=C_WHITE, leading=15)),
Paragraph(desc.replace("\n","<br/>"),
ParagraphStyle("cd", fontSize=9, fontName="Helvetica",
textColor=dark, leading=13)),
]]
ct = Table(row, colWidths=[w*0.28, w*0.72])
ct.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), dark),
("BACKGROUND", (1,0), (1,0), light),
("BOX", (0,0), (-1,-1), 0.5, dark),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING",(0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
elements.append(ct)
elements.append(Spacer(1, 4))
elements.append(Spacer(1, 14))
elements.append(Paragraph(
"Sources: Schwartz's Principles of Surgery 11e · Fischer's Mastery of Surgery 8e · "
"Tintinalli's Emergency Medicine · Goldman-Cecil Medicine · Current Surgical Therapy 14e · "
"VUMC & Michigan Medicine ICU Protocols",
ST["sources"]))
# ─────────────────────────────────────────────────────────────────────────────
# SECTION BUILDERS
# ─────────────────────────────────────────────────────────────────────────────
def sec_general(e):
e.append(PageBreak())
e.append(section_hdr("GENERAL PRINCIPLES", C_NAVY))
e.append(Spacer(1, 6))
pts = [
"<b>1. Correct the cause</b> - not just the number.",
"<b>2. Chronic imbalances</b> must be corrected slowly (risk: osmotic demyelination, cerebral oedema).",
"<b>3. Monitor</b> serum levels, ECG, urine output, and neurologic status throughout correction.",
"<b>4. Magnesium is the co-factor</b> for K⁺ and Ca²⁺ — always check Mg if K or Ca fails to correct.",
"<b>5. Renal impairment</b> changes every calculation — reduce doses by 50% if CrCl < 20-30 mL/min.",
"<b>6. Protocol exclusions:</b> active HD/PD, AKI, DKA, rhabdomyolysis, crush injury, hypothermia.",
]
for p in pts:
e.append(Paragraph(f"• {p}", ST["bullet"]))
e.append(Spacer(1, 2))
e.append(Spacer(1, 8))
e.append(Paragraph("NORMAL RANGES QUICK REFERENCE", ST["h2"]))
data = [["Electrolyte","Normal Range","Critical Low","Critical High"],
["Sodium (Na⁺)","135–145 mEq/L","< 120 mEq/L","> 160 mEq/L"],
["Potassium (K⁺)","3.5–5.0 mEq/L","< 2.5 mEq/L","> 6.5 mEq/L"],
["Calcium (total)","8.5–10.5 mg/dL","< 7.0 mg/dL","> 14 mg/dL"],
["Calcium (ionised)","4.5–5.6 mg/dL","< 3.0 mg/dL","> 6.5 mg/dL"],
["Magnesium (Mg²⁺)","1.7–2.5 mg/dL","< 1.0 mg/dL","> 7 mg/dL"],
["Phosphate (PO₄)","2.5–4.5 mg/dL","< 1.0 mg/dL","> 6.0 mg/dL"]]
e.append(mk_table(data, [5*cm, 4.5*cm, 4*cm, 4*cm], C_NAVY))
def sec_sodium(e):
e.append(PageBreak())
e.append(section_hdr("SECTION 1 — SODIUM (Na⁺)", C_BLUE))
e.append(Spacer(1, 6))
# --- Hyponatremia ---
e.append(Paragraph("1A. HYPONATREMIA (Na < 135 mEq/L)", ST["h2"]))
e.append(Paragraph("Classification by Severity", ST["h3"]))
data = [["Severity","Na Level","Typical Symptoms"],
["Mild","130–135 mEq/L","Often asymptomatic"],
["Moderate","125–129 mEq/L","Nausea, malaise, headache"],
["Severe","< 125 mEq/L","Confusion, seizures, coma"],
["Critical","< 120 mEq/L","Life-threatening neurologic compromise"]]
e.append(mk_table(data,[3.5*cm,4*cm,10*cm],C_BLUE,C_LTBLUE))
e.append(Spacer(1,6))
e.append(Paragraph("Key Formula — Sodium Deficit", ST["h3"]))
e.append(formula_box(
"Na Deficit (mEq) = TBW × (Desired Na – Current Na)\n\n"
"TBW = 0.60 × lean body weight [kg] (men)\n"
"TBW = 0.50 × lean body weight [kg] (women)\n"
"TBW = 0.45 × lean body weight [kg] (elderly)"
))
e.append(Spacer(1,6))
e.append(Paragraph("Correction Rates — CRITICAL", ST["h3"]))
e.append(warn_box(
"Rapid correction (> 10–12 mEq/L/24h) causes OSMOTIC DEMYELINATION SYNDROME "
"(central pontine myelinolysis) → locked-in syndrome, quadriplegia, death. "
"Risk highest in: chronic hyponatremia, alcoholism, malnutrition, liver transplant."
))
e.append(Spacer(1,4))
data = [["Situation","Max Rate / hour","Max Per 24 h"],
["Asymptomatic / chronic (>48h)","0.5 mEq/L/hr","10–12 mEq/L"],
["Acute symptomatic (seizures, coma)","1–2 mEq/L/hr until sx resolve or Na=120","≤ 12 mEq/L"],
["Chronic (highest ODS risk)","0.5 mEq/L/hr","< 10 mEq/L"]]
e.append(mk_table(data,[7*cm,6*cm,4.5*cm],C_BLUE,C_LTBLUE))
e.append(Spacer(1,6))
e.append(Paragraph("IV Treatment — 3% Hypertonic Saline", ST["h3"]))
e.append(info_box(
"<b>3% NaCl content:</b> 513 mEq Na/L (vs 154 mEq/L in 0.9% NS)<br/>"
"<b>To prepare 3% NaCl:</b> Add 100 mL of 23.4% NaCl to 900 mL 0.9% NS = 1 L of 3% NaCl<br/>"
"<b>Adrogue-Madias Formula:</b> ΔNa per 1L infused = (Infusate Na – Serum Na) / (TBW + 1)<br/>"
"<b>Acute seizures:</b> 3% NaCl 100–150 mL IV bolus over 15–20 min → raise Na by 4–6 mEq/L, then slow correction<br/>"
"<b>Ongoing infusion:</b> 1–2 mL/kg/hr of 3% NaCl; reassess every 1–2 h"
))
e.append(Spacer(1,6))
e.append(Paragraph("Management by Volume Status", ST["h3"]))
data=[["Volume Status","Symptomatic Treatment","Asymptomatic Treatment"],
["Hypovolemic","3% NaCl","0.9% NS until euvolemic"],
["Euvolemic (SIADH)","3% NaCl ± Furosemide 20-40 mg IV","Fluid restriction < 1 L/day"],
["Hypervolemic","3% NaCl + Furosemide IV","Fluid restriction + diuretics"],
["SIADH refractory","Tolvaptan (Samsca) 15 mg PO daily","—"]]
e.append(mk_table(data,[4.5*cm,6*cm,6*cm],C_BLUE,C_LTBLUE))
e.append(Spacer(1,6))
e.append(Paragraph("Oral / Maintenance Brands", ST["h3"]))
data=[["Brand","Generic","Dose","Indication"],
["Slo-Salt","NaCl tablets","1–2 g TID","Mild hypovolemic hyponatremia"],
["ORS (WHO formula)","Na 75 mEq/L oral rehydration","As needed","GI loss hyponatremia"],
["Ure-Na","Urea powder","15–30 g/day","SIADH — free water excretion"],
["Samsca / Jinarc","Tolvaptan 15–60 mg","15 mg PO daily (titrate)","SIADH — V2 antagonist"]]
e.append(mk_table(data,[3.5*cm,5*cm,4*cm,5*cm],C_BLUE,C_LTBLUE))
e.append(Spacer(1,10))
# --- Hypernatremia ---
e.append(Paragraph("1B. HYPERNATREMIA (Na > 145 mEq/L)", ST["h2"]))
e.append(Paragraph("Key Formula — Free Water Deficit", ST["h3"]))
e.append(formula_box(
"Free Water Deficit (L) = TBW × [(Serum Na / 140) – 1]\n"
" OR\n"
"Free Water Deficit (L) = [(Serum Na – 140) / 140] × TBW\n\n"
"TBW = 0.50 × wt [kg] (men) | TBW = 0.40 × wt [kg] (women)\n\n"
"Example: 70 kg man, Na = 160 → FWD = 35 × (160/140 – 1) = 35 × 0.143 = 5.0 L\n\n"
"Paediatric: FWD (mL) = 4 mL × weight [kg] × desired ΔNa [mEq/L]\n"
" Give half over first 8 h, remainder over next 16 h"
))
e.append(Spacer(1,6))
e.append(Paragraph("Correction Rates", ST["h3"]))
e.append(warn_box("Overly rapid correction of hypernatremia causes CEREBRAL OEDEMA and HERNIATION."))
e.append(Spacer(1,4))
data=[["Situation","Max Rate / hour","Max Per 24 h"],
["Acute symptomatic","≤ 1 mEq/L/hr","12 mEq/L"],
["Chronic (> 48h)","0.5–0.7 mEq/L/hr","10 mEq/L"]]
e.append(mk_table(data,[7*cm,5.5*cm,5*cm],C_BLUE,C_LTBLUE))
e.append(Spacer(1,6))
e.append(Paragraph("IV Fluid Selection", ST["h3"]))
data=[["Na Level","Haemodynamic Status","Fluid Choice"],
["Any","Hypovolaemic / unstable","0.9% NS first (restore volume)"],
["> 160 mEq/L","Stable","0.45% NaCl (half-normal saline)"],
["> 155 mEq/L","Stable","D5W or D5 0.25% NaCl"],
["Moderate","Enteral access","Free water via NG (preferred)"]]
e.append(mk_table(data,[3.5*cm,4.5*cm,9.5*cm],C_BLUE,C_LTBLUE))
e.append(Spacer(1,4))
e.append(info_box(
"<b>Dilution tip — D5 0.25% NaCl:</b> Mix 250 mL 0.9% NS + 750 mL D5W → 1 L ≈ 0.22% NaCl<br/>"
"Use D5W cautiously — overly rapid free water delivery if infused too fast."
))
def sec_potassium(e):
e.append(PageBreak())
e.append(section_hdr("SECTION 2 — POTASSIUM (K⁺)", C_TEAL))
e.append(Spacer(1,6))
e.append(info_box(
"<b>Normal range:</b> 3.5–5.0 mEq/L | Cardiac targets: > 4.0 mEq/L<br/>"
"<b>Rule of thumb:</b> Every 10 mEq K⁺ given raises serum K by ~0.1 mEq/L<br/>"
"<b>Always replete Mg²⁺ first</b> if Mg < 2.0 mg/dL — without Mg, K will not move intracellularly.",
C_LTTEAL, C_TEAL
))
e.append(Spacer(1,8))
# --- Hypokalemia ---
e.append(Paragraph("2A. HYPOKALEMIA (K < 3.5 mEq/L)", ST["h2"]))
e.append(Paragraph("Classification", ST["h3"]))
data=[["Severity","K Level","ECG Changes"],
["Mild","3.0–3.5 mEq/L","U waves, T-wave flattening"],
["Moderate","2.5–3.0 mEq/L","ST depression, PR prolongation"],
["Severe","< 2.5 mEq/L","Wide QRS, VT, VF — life-threatening"]]
e.append(mk_table(data,[3.5*cm,4*cm,10*cm],C_TEAL,C_LTTEAL))
e.append(Spacer(1,6))
e.append(Paragraph("IV Replacement Protocol", ST["h3"]))
data=[["Serum K","Oral Dose","IV Dose","Recheck"],
["3.8–3.9 mEq/L","20 mEq PO","20 mEq IVPB","2–4 h"],
["3.5–3.7 mEq/L","40 mEq PO","40 mEq IVPB","2–4 h"],
["3.2–3.4 mEq/L","60 mEq PO","60 mEq IVPB","2–4 h"],
["< 3.1 mEq/L","80 mEq + notify MD","80 mEq IV","Immediately after"],
["< 2.6 mEq/L","—","100 mEq IV","Immediately after"]]
e.append(mk_table(data,[4*cm,3.5*cm,4.5*cm,5.5*cm],C_TEAL,C_LTTEAL))
e.append(Spacer(1,6))
e.append(Paragraph("IV Infusion Rates & Dilution Guide", ST["h3"]))
e.append(warn_box("NEVER give KCl IV push (bolus) — can cause immediate cardiac arrest."))
e.append(Spacer(1,4))
data=[["Access","Max Rate","Max Concentration","Dilution Example"],
["Peripheral IV","10 mEq/hr","40–80 mEq/L","20 mEq KCl in 250 mL NS → infuse over 2 h"],
["Peripheral IV","10 mEq/hr","80 mEq/L","40 mEq KCl in 500 mL NS → infuse over 4 h"],
["Central line (ECG monitoring)","20 mEq/hr","120 mEq/L","40 mEq KCl in 250 mL NS → infuse over 2 h (central)"],
["Central line (emergency)","40 mEq/hr","Concentrated","40 mEq KCl in 100 mL NS → over 1 h (emergency only)"]]
e.append(mk_table(data,[3*cm,3*cm,3.5*cm,8*cm],C_TEAL,C_LTTEAL,fontsize=8))
e.append(Spacer(1,6))
e.append(Paragraph("Oral Potassium Brands", ST["h3"]))
data=[["Brand","Generic","Strength","Form","Notes"],
["Klor-Con","KCl ER","8/10/20 mEq","Tablet","Most widely used; take with full glass of water"],
["K-Dur","KCl ER","10/20 mEq","Tablet","Take with food; wax-matrix"],
["Kay Ciel","KCl","20 mEq/15 mL","Elixir","Syrup; for dysphagia"],
["Kaon-Cl","KCl","20 mEq/15 mL","Liquid","GI-friendly suspension"],
["Slow-K","KCl wax-matrix","8 mEq","Tablet","Less GI irritation"],
["K-Lyte","K bicarbonate effervescent","25 mEq/tab","Dissolve in water","Useful: acidosis + hypoK"],
["K-gluconate syrup","Potassium gluconate","20 mEq/15 mL","Syrup","Better tolerated elderly/children"],
["Oral K packets","KCl powder","20 mEq/packet","Powder","ICU: mix in 4 oz water"]]
e.append(mk_table(data,[2.5*cm,3.5*cm,2.5*cm,2.5*cm,6.5*cm],C_TEAL,C_LTTEAL,fontsize=7.5))
e.append(Spacer(1,8))
# --- Hyperkalemia ---
e.append(Paragraph("2B. HYPERKALEMIA (K > 5.5 mEq/L)", ST["h2"]))
data=[["Severity","K Level","ECG Finding"],
["Mild","5.5–6.0 mEq/L","Peaked / tall T waves"],
["Moderate","6.0–6.5 mEq/L","PR prolongation, wide QRS, short QT"],
["Severe","≥ 6.5 mEq/L","Sine wave, VT/VF — emergency"]]
e.append(mk_table(data,[3.5*cm,4*cm,10*cm],C_RED,C_LTRED))
e.append(Spacer(1,6))
e.append(Paragraph("Treatment Steps (in order)", ST["h3"]))
data=[["Step","Goal","Agent","Dose","Onset","Duration"],
["1","Cardiac membrane\nstabilisation","Calcium gluconate 10%",
"5–10 mL (0.5–1 g) IV over 2–3 min; repeat q5 min\nOR Ca chloride 10%: 5–10 mL IV via central","1–3 min","30–60 min"],
["2a","Shift K into cells","Insulin + Glucose",
"10 U regular insulin IV + 25–50 g dextrose\n(1 amp D50W = 25 g glucose)","15–30 min","2–6 h"],
["2b","Shift K into cells","Sodium bicarbonate",
"50–100 mEq IV (1–2 amps of 8.4%)\nBest in metabolic acidosis; avoid if alkalotic","15–30 min","1–2 h"],
["2c","Shift K into cells","Nebulised albuterol",
"10–20 mg nebulised (4–8× asthma dose)","30–60 min","2–4 h"],
["3a","Remove K (GI)","Kayexalate (Na polystyrene)",
"PO: 15–30 g in 50–100 mL 20% sorbitol\nRectal: 50 g in 200 mL sorbitol","Hours","—"],
["3b","Remove K (GI)","Patiromer (Veltassa)",
"8.4 g PO once daily","4–7 h","Daily dosing"],
["3c","Remove K (GI)","Na zirconium cyclosilicate\n(Lokelma)",
"10 g TID × 48 h, then 5–10 g daily","1–2 h onset","—"],
["3d","Remove K (renal)","Furosemide",
"40–80 mg IV","30–60 min","Needs renal fn"],
["4","Definitive removal","Haemodialysis",
"Emergency use; removes 25–50 mEq K/hr","Minutes","—"]]
e.append(mk_table(data,[1*cm,3*cm,3.5*cm,5.5*cm,2*cm,2*cm],C_RED,C_LTRED,fontsize=7.5))
def sec_calcium(e):
e.append(PageBreak())
e.append(section_hdr("SECTION 3 — CALCIUM (Ca²⁺)", C_PURPLE))
e.append(Spacer(1,6))
e.append(info_box(
"<b>Normal total calcium:</b> 8.5–10.5 mg/dL | "
"<b>Normal ionised (iCa):</b> 4.5–5.6 mg/dL (1.1–1.4 mmol/L)",
C_LTPURPLE, C_PURPLE
))
e.append(Spacer(1,4))
e.append(Paragraph("Albumin Correction Formula", ST["h3"]))
e.append(formula_box(
"Corrected Ca (mg/dL) = Measured Ca + 0.8 × (4.0 – Albumin [g/dL])\n\n"
"Example: Ca = 7.0 mg/dL, Albumin = 2.0 g/dL\n"
" Corrected Ca = 7.0 + 0.8 × (4.0 – 2.0) = 7.0 + 1.6 = 8.6 mg/dL (normal)"
))
e.append(Spacer(1,8))
# Hypocalcemia
e.append(Paragraph("3A. HYPOCALCEMIA (Total Ca < 8.5 mg/dL | iCa < 4.5 mg/dL)", ST["h2"]))
data=[["Severity","Total Ca","iCa","Symptoms"],
["Mild","7.5–8.5 mg/dL","3.8–4.5 mg/dL","Perioral numbness, tingling"],
["Moderate","7.0–7.5 mg/dL","3.0–3.8 mg/dL","Chvostek/Trousseau signs, muscle cramps"],
["Severe","< 7.0 mg/dL","< 3.0 mg/dL","Tetany, laryngospasm, seizures, prolonged QT, cardiac arrest"]]
e.append(mk_table(data,[2.5*cm,3.5*cm,3.5*cm,8*cm],C_PURPLE,C_LTPURPLE))
e.append(Spacer(1,6))
e.append(Paragraph("IV Preparations — Gluconate vs Chloride", ST["h3"]))
data=[["Product","Elemental Ca / mL","Elemental Ca / vial","Access Required","Notes"],
["Ca Gluconate 10%","9 mg/mL","93 mg per 10 mL vial","Peripheral IV ✓","First-line; tissue-safe on extravasation"],
["Ca Chloride 10%","27 mg/mL","273 mg per 10 mL vial","CENTRAL LINE ONLY","3× more elemental Ca; necrosis if extravasated"]]
e.append(mk_table(data,[4*cm,3*cm,3.5*cm,3.5*cm,3.5*cm],C_PURPLE,C_LTPURPLE,fontsize=8))
e.append(Spacer(1,6))
e.append(Paragraph("IV Dosing by Ionised Calcium (VUMC Protocol)", ST["h3"]))
data=[["iCa Level","Dose","IV Dilution","Rate","Recheck"],
["3.5–3.9 mg/dL","4 g Ca Gluconate","4 g in 200 mL NS","2 g/hr","Next AM labs"],
["3.0–3.4 mg/dL","6 g Ca Gluconate","6 g in 300 mL NS","2 g/hr","4 h after replacement"],
["2.5–2.9 mg/dL","8 g Ca Gluconate","8 g in 400 mL NS","2 g/hr","4 h after replacement"],
["< 2.5 mg/dL","10 g Ca Gluconate + notify MD","10 g in 500 mL NS","2 g/hr","4 h after replacement"],
["Tetany/seizures (acute)","1–2 g Ca Gluconate BOLUS","10–20 mL of 10% in 50 mL NS","Over 10–20 min","Then start infusion"]]
e.append(mk_table(data,[3.5*cm,4*cm,4*cm,3*cm,3*cm],C_PURPLE,C_LTPURPLE,fontsize=8))
e.append(Spacer(1,4))
e.append(info_box(
"<b>Maintenance infusion:</b> 0.5–1.5 mg elemental Ca/kg/hr "
"(≈ 1–3 g Ca Gluconate/hr in average adult)<br/>"
"<b>Key warning:</b> Do NOT mix Ca Gluconate with phosphate or bicarbonate in the same line — precipitation occurs.",
C_LTPURPLE, C_PURPLE
))
e.append(Spacer(1,6))
e.append(Paragraph("Oral Calcium Brands", ST["h3"]))
data=[["Brand","Generic","Elemental Ca","Dose","Notes"],
["Caltrate","Ca carbonate 1250 mg","500 mg","1–2 tabs TID with meals","Take with meals (needs acid)"],
["Os-Cal","Ca carbonate 1250 mg","500 mg","2–3 tabs daily with meals","Take with meals"],
["Tums","Ca carbonate 500–750 mg","200–300 mg","PRN","Cheap, widely available"],
["Shelcal","Ca carbonate 1250 mg + D3 250 IU","500 mg","1 tab BD with meals","South Asia popular brand"],
["CalciGel / Calcimax","Ca carbonate + D3","500 mg + 200 IU D3","1 tab TID","Combination supplement"],
["Cal-C-Vita","Ca citrate","250 mg","2–3 tabs daily","No food needed; best in elderly/PPI users"],
["Ca gluconate tabs","Ca gluconate 500–600 mg","45–54 mg","As prescribed","Mild deficiency oral supplement"]]
e.append(mk_table(data,[3*cm,4*cm,2.5*cm,3.5*cm,4.5*cm],C_PURPLE,C_LTPURPLE,fontsize=7.5))
e.append(info_box(
"<b>Ca carbonate</b> requires gastric acid — give WITH meals.<br/>"
"<b>Ca citrate</b> does NOT require acid — preferred in elderly, PPI users, post-gastric surgery.<br/>"
"Chronic hypocalcaemia requires <b>Vitamin D (calcitriol 0.25–0.5 mcg/day)</b> for adequate absorption.",
C_LTPURPLE, C_PURPLE
))
e.append(Spacer(1,8))
# Hypercalcemia
e.append(Paragraph("3B. HYPERCALCEMIA (Total Ca > 10.5 mg/dL | iCa > 5.6 mg/dL)", ST["h2"]))
data=[["Step","Agent","Dose","Mechanism","Onset"],
["1","0.9% NS IV","200–500 mL/hr; goal UO 100–150 mL/hr","Volume expansion + renal Ca excretion","Immediate"],
["2","Furosemide","20–80 mg IV q2–4h (after adequate hydration)","Inhibits tubular Ca reabsorption","30–60 min"],
["3","Calcitonin","4 IU/kg IM/SC q12h","Inhibits osteoclasts; tachyphylaxis in 48–72h","4–6 h"],
["4","Zoledronic acid","4 mg IV over 15 min","Inhibit osteoclasts (long-acting)","4–7 days"],
["4","Pamidronate","60–90 mg IV over 2–4h","Same as above","4–7 days"],
["5","Denosumab","60–120 mg SC","Anti-RANKL; works in renal failure","Days"],
["6","Steroids","Prednisone 40–60 mg/day PO","Granulomatous disease / Vit D toxicity","Days"],
["7","Haemodialysis","—","Renal failure hypercalcaemia","Hours"]]
e.append(mk_table(data,[1*cm,3.5*cm,5.5*cm,5*cm,2.5*cm],C_RED,C_LTRED,fontsize=8))
def sec_magnesium(e):
e.append(PageBreak())
e.append(section_hdr("SECTION 4 — MAGNESIUM (Mg²⁺)", C_ORANGE))
e.append(Spacer(1,6))
e.append(info_box(
"<b>Normal range:</b> 1.7–2.5 mg/dL (1.4–2.0 mEq/L)<br/>"
"<b>Conversions:</b> 1 mEq/L = 1.2 mg/dL = 0.5 mmol/L<br/>"
"<b>MgSO4:</b> 1 g MgSO4 = 98 mg elemental Mg = 4 mEq = ~4 mmol",
C_LTORANGE, C_ORANGE
))
e.append(Spacer(1,8))
# Hypomagnesemia
e.append(Paragraph("4A. HYPOMAGNESEMIA (Mg < 1.7 mg/dL)", ST["h2"]))
e.append(warn_box(
"Hypomagnesemia causes REFRACTORY hypokalemia and hypocalcaemia. "
"Mg is required for PTH secretion and K intracellular transport. "
"Always check and replete Mg when K or Ca fails to correct."
))
e.append(Spacer(1,4))
data=[["Severity","Mg Level","Symptoms"],
["Mild","1.5–1.9 mg/dL","Usually asymptomatic"],
["Moderate","1.0–1.5 mg/dL","Tremor, weakness, anorexia, nausea"],
["Severe","< 1.0 mg/dL","Tetany, seizures, torsades de pointes, AF, hyperreflexia"]]
e.append(mk_table(data,[3*cm,4*cm,10.5*cm],C_ORANGE,C_LTORANGE))
e.append(Spacer(1,6))
e.append(Paragraph("IV Replacement Protocol — MgSO4", ST["h3"]))
data=[["Serum Mg","IV Dose","Dilution","Rate","Recheck"],
["1.5–1.9 mg/dL","2 g MgSO4","2 g in 100 mL NS","Over 2 h","Next AM labs"],
["1.3–1.9 mg/dL","4 g MgSO4","4 g in 250 mL NS","Over 4 h (1 g/hr)","Next AM labs"],
["1.0–1.4 mg/dL","3 g MgSO4 × 3 doses","1 g/100 mL piggyback × 3","1 g/hr each","After each dose"],
["≤ 1.2 mg/dL","8 g MgSO4","8 g in 500 mL NS","Over 8 h (1 g/hr)","6 h after replacement"],
["< 1.0 mg/dL","4–8 g MgSO4 first day","4 g/250 mL NS","1 g/hr continuously","During infusion"],
["Torsades/Eclampsia (EMERGENCY)","1–4 g MgSO4 LOADING","1–4 g in 100 mL D5W or NS","Over 10–60 min (BOLUS)","Continuous monitoring"]]
e.append(mk_table(data,[4*cm,3*cm,3.5*cm,3.5*cm,3.5*cm],C_ORANGE,C_LTORANGE,fontsize=8))
e.append(Spacer(1,4))
e.append(info_box(
"<b>Max standard IV rate:</b> 1 g/hour<br/>"
"<b>Emergency bolus:</b> 1–4 g over 10–60 min with continuous ECG + BP monitoring<br/>"
"<b>Monitor:</b> Deep tendon reflexes (areflexia = pre-respiratory depression warning)<br/>"
"<b>Antidote for MgSO4 toxicity:</b> Calcium gluconate 1–2 g IV over 10 min<br/>"
"<b>Alcoholic delirium tremens:</b> up to 8–12 g MgSO4 IV day 1<br/>"
"<b>Note:</b> ~50% of IV Mg is lost in urine — total body stores replete after serum normalises",
C_LTORANGE, C_ORANGE
))
e.append(Spacer(1,6))
e.append(Paragraph("Dilution Reference Table", ST["h3"]))
data=[["Dose","Diluent","Final Vol","Concentration","Rate"],
["1 g MgSO4","100 mL NS","100 mL","10 mg/mL","Over 1 hour"],
["2 g MgSO4","100 mL NS","100 mL","20 mg/mL","Over 2 hours"],
["4 g MgSO4","250 mL NS","250 mL","16 mg/mL","Over 4 hours (1 g/hr)"],
["8 g MgSO4","500 mL NS","500 mL","16 mg/mL","Over 8 hours (1 g/hr)"],
["4 g premix piggyback (VUMC)","Pre-diluted","100 mL","40 mg/mL","1 g/hr"]]
e.append(mk_table(data,[2.5*cm,3*cm,3*cm,3.5*cm,5.5*cm],C_ORANGE,C_LTORANGE,fontsize=8))
e.append(Spacer(1,6))
e.append(Paragraph("Oral Magnesium Brands", ST["h3"]))
data=[["Brand","Generic","Elemental Mg","Bioavailability","Notes"],
["MgO / Magnesia","Magnesium oxide 400 mg","241 mg","~4% (poor)","High Mg content but poor absorption"],
["Slow-Mag","Mg chloride ER 535 mg","64 mg","Moderate","Better GI tolerance"],
["Mag-Tab SR","Mg lactate ER","84 mg","Good","Slow-release, least diarrhoea"],
["Natural Calm","Mg citrate powder","200–400 mg","~30%","Dissolve in water; good bioavailability"],
["Milk of Magnesia","Mg hydroxide 400 mg/5 mL","~166 mg/5 mL","Moderate","Supplement: 5–15 mL TID; laxative effect"],
["Mg citrate solution","Mg citrate","1745 mg/30 mL","Good","Supplement: 30 mL TID"]]
e.append(mk_table(data,[3*cm,4*cm,3*cm,2.5*cm,5*cm],C_ORANGE,C_LTORANGE,fontsize=7.5))
e.append(Spacer(1,8))
# Hypermagnesemia
e.append(Paragraph("4B. HYPERMAGNESEMIA (Mg > 2.5 mg/dL)", ST["h2"]))
data=[["Mg Level","Clinical Sign","Action"],
["2.5–4 mg/dL","Nausea, flushing (vasodilation)","Stop Mg sources; monitor"],
["4–7 mg/dL","Hyporeflexia, drowsiness, hypotension","Ca gluconate + saline + furosemide"],
["7–12 mg/dL","Respiratory depression, heart block","Ca gluconate + haemodialysis consider"],
["> 12 mg/dL","Cardiac arrest, respiratory paralysis","Ca gluconate + EMERGENCY haemodialysis"]]
e.append(mk_table(data,[3.5*cm,6*cm,8*cm],C_RED,C_LTRED))
def sec_phosphate(e):
e.append(PageBreak())
e.append(section_hdr("SECTION 5 — PHOSPHATE (PO₄)", C_GREEN))
e.append(Spacer(1,6))
e.append(info_box(
"<b>Normal range:</b> 2.5–4.5 mg/dL (0.8–1.45 mmol/L)<br/>"
"<b>Conversions:</b> 1 mmol = 3.1 mg/dL = 31 mg phosphorus<br/>"
"<b>Key rule:</b> Use K-Phos if K < 4.0 mEq/L; use Na-Phos if K ≥ 4.0 mEq/L",
C_LTGREEN, C_GREEN
))
e.append(Spacer(1,8))
# Hypophosphatemia
e.append(Paragraph("5A. HYPOPHOSPHATEMIA (Phos < 2.5 mg/dL)", ST["h2"]))
data=[["Severity","Level","Route","Indication"],
["Mild","2.0–2.5 mg/dL","Oral","Usually asymptomatic"],
["Moderate","1.5–2.0 mg/dL","Oral (preferred); IV if symptomatic","Weakness, fatigue"],
["Severe","< 1.5 mg/dL","IV required","Ventilator failure, arrhythmia"],
["Critical","< 1.0 mg/dL","IV MANDATORY","Cardiac dysfunction, haemolytic anaemia, rhabdo"]]
e.append(mk_table(data,[2.5*cm,3*cm,4.5*cm,7.5*cm],C_GREEN,C_LTGREEN))
e.append(Spacer(1,6))
e.append(Paragraph("Phosphate Product Reference", ST["h3"]))
data=[["Product","Form","Phosphate / unit","Potassium","Sodium"],
["K-Phos Neutral tablet","Oral","250 mg = 8 mmol","1.1 mEq","13 mEq"],
["K-Phos No. 2","Oral tablet","250 mg = 8 mmol","2.3 mEq","5.8 mEq"],
["Neutra-Phos / Phospha 250 Neutral","Oral packet (dissolve)","250 mg = 8 mmol","7 mEq","7 mEq"],
["K-Phos Injection (per mL)","IV","3 mmol","4.4 mEq","0"],
["Na-Phos Injection (per mL)","IV","3 mmol","0","4 mEq"]]
e.append(mk_table(data,[4.5*cm,2.5*cm,3.5*cm,2.5*cm,2.5*cm],C_GREEN,C_LTGREEN))
e.append(Spacer(1,6))
e.append(Paragraph("IV Replacement Protocol", ST["h3"]))
data=[["Serum Phos","IV Dose","Oral Alternative","IV Dilution","Rate","Recheck"],
["2.0–2.5 mg/dL","15 mmol IV","K-Phos Neutral 2 tabs q4h × 3","5 mL in 250 mL NS","Over 2 h","Next AM labs"],
["1.6–1.9 mg/dL","30 mmol IV","K-Phos Neutral 2 tabs q4h × 4","10 mL in 250 mL NS","Over 4 h","Next AM labs"],
["< 1.6 mg/dL","45 mmol IV","—","15 mL in 300 mL NS","Over 6 h","6 h after replacement"]]
e.append(mk_table(data,[3*cm,3*cm,4.5*cm,3.5*cm,2*cm,3.5*cm],C_GREEN,C_LTGREEN,fontsize=7.5))
e.append(Spacer(1,4))
e.append(info_box(
"<b>Max IV rate:</b> 7 mmol phosphate/hour<br/>"
"<b>K load from K-Phos:</b> 15 mmol K-Phos IV ≈ 22 mEq K⁺ — monitor K during infusion<br/>"
"<b>Na load from Na-Phos:</b> 15 mmol Na-Phos IV ≈ 20 mEq Na⁺<br/>"
"<b>Do NOT</b> infuse phosphate with Ca-containing IV fluids — precipitation",
C_LTGREEN, C_GREEN
))
e.append(Spacer(1,8))
# Hyperphosphatemia
e.append(Paragraph("5B. HYPERPHOSPHATEMIA (Phos > 4.5 mg/dL)", ST["h2"]))
data=[["Agent","Brand","Dose","Mechanism","Notes"],
["Sevelamer HCl","Renvela","800–1600 mg PO TID with meals","Non-Ca binder","First-line CKD; no Ca load"],
["Ca acetate","PhosLo","667 mg tabs PO TID with meals","Ca binder","Also raises Ca — useful if hypoCa"],
["Ca carbonate","Tums/Caltrate","500–1000 mg PO TID with meals","Ca binder","Risk of hypercalcaemia"],
["Lanthanum carbonate","Fosrenol","500–1000 mg TID, chew with meals","Non-Ca/Al binder","No Ca or Al load"],
["Sucralfate","Carafate","1 g QID","Al-based binder","Short-term use (Al toxicity risk)"],
["Al(OH)3 antacids","Amphojel/Alternagel","30–40 mL TID OR 600 mg tabs TID","Al binder","Short-term only"],
["Haemodialysis","—","Per session","Direct removal","~1 g phosphate/session in ESRD"]]
e.append(mk_table(data,[3.5*cm,3*cm,4*cm,3*cm,4*cm],C_RED,C_LTRED,fontsize=7.5))
def sec_special(e):
e.append(PageBreak())
e.append(section_hdr("SECTION 6 — SPECIAL SITUATIONS", C_GREY))
e.append(Spacer(1,6))
# Refeeding
e.append(Paragraph("Refeeding Syndrome", ST["h2"]))
e.append(info_box(
"Occurs in malnourished patients when nutrition is reintroduced. Insulin surge drives K⁺, "
"Mg²⁺, and PO₄³⁻ intracellularly causing sudden drops.<br/><br/>"
"<b>Protocol:</b> Begin nutrition at 25% of estimated needs on day 1. "
"Monitor electrolytes q6h. Replete prophylactically BEFORE and DURING refeeding.<br/>"
"<b>Most dangerous:</b> Hypophosphatemia (most severe) → respiratory failure, cardiac arrest."
))
e.append(Spacer(1,6))
# DKA
e.append(Paragraph("DKA Electrolyte Management", ST["h2"]))
data=[["Electrolyte","Issue","Management"],
["Potassium","K looks normal/high initially (acidosis shifts K out of cells)\nbut TOTAL BODY K is depleted.\nAs insulin corrects acidosis, K drops precipitously.",
"Start K replacement when K < 5.0 mEq/L + UO adequate.\nHOLD insulin if K < 3.5 until repleted.\nMonitor hourly."],
["Phosphate","Drops with insulin therapy; total body depletion.",
"Routine supplementation NOT recommended.\nReplace if Phos < 1 mg/dL or cardiac dysfunction."],
["Magnesium","Urinary losses from osmotic diuresis.",
"Check Mg; replace concurrently with K if low."]]
e.append(mk_table(data,[2.5*cm,7.5*cm,7.5*cm],C_GREY,C_LTGREY))
e.append(Spacer(1,6))
# Massive transfusion
e.append(Paragraph("Massive Blood Transfusion", ST["h2"]))
e.append(info_box(
"Citrate in blood products chelates ionised calcium → hypocalcaemia.<br/>"
"Monitor iCa every 4 units pRBC.<br/>"
"Routine Ca supplementation no longer recommended — treat based on iCa levels.<br/>"
"Treat symptomatic hypocalcaemia with Ca Gluconate 1–2 g IV."
))
e.append(Spacer(1,6))
# Eclampsia
e.append(Paragraph("Eclampsia / Pre-eclampsia — MgSO4 Protocol", ST["h2"]))
e.append(formula_box(
"Loading dose: 4–6 g MgSO4 in 100–250 mL NS → over 20–30 min IV\n"
"Maintenance: 1–2 g/hour continuous infusion\n"
"Therapeutic Mg: 4–7 mg/dL (1.7–2.9 mmol/L)\n"
"Antidote (toxicity): Calcium gluconate 1–2 g IV over 10 min"
))
e.append(Spacer(1,6))
# Danger table
e.append(Paragraph("Key Danger Warnings", ST["h2"]))
data=[["Situation","Risk","Prevention"],
["Rapid Na correction (hyponatremia)","Osmotic demyelination (pontine myelinolysis)","Max 10–12 mEq/24h; slower in chronic cases"],
["Rapid Na correction (hypernatremia)","Cerebral oedema, herniation","Max 10 mEq/24h"],
["IV KCl too fast / undiluted","Cardiac arrest","Never push undiluted; max 10 mEq/hr peripheral"],
["Ca Gluconate/Chloride + Phos or HCO3 in same line","Line precipitation","Flush line between agents"],
["Ca Chloride via peripheral line","Tissue necrosis / thrombophlebitis","CENTRAL LINE ONLY"],
["MgSO4 overdose","Respiratory paralysis, cardiac arrest","Monitor DTRs; antidote = Ca gluconate"],
["Phos replacement in hypercalcaemia","Ca-Phos precipitation, soft tissue calcification","Avoid if Ca × Phos product > 55"],
["K replacement without checking Mg","Refractory hypokalemia","Always replete Mg first"],
["Calcitonin in hypercalcaemia","Tachyphylaxis in 48–72h","Use as bridge to bisphosphonate"]]
e.append(mk_table(data,[5*cm,5*cm,7.5*cm],C_RED,C_LTRED,fontsize=8))
def sec_quickref(e):
e.append(PageBreak())
e.append(section_hdr("SECTION 7 — MASTER QUICK REFERENCE TABLE", C_NAVY))
e.append(Spacer(1,6))
data=[
["Electrolyte","Normal","Deficiency IV Drug","Oral Brand Examples","Max IV Rate","Key Formula / Rule"],
["Na⁺ LOW\n(Hyponatremia)","135–145\nmEq/L","3% NaCl (513 mEq Na/L)","NaCl tabs, ORS,\nUre-Na, Tolvaptan","1–2 mEq/L/hr\n(symptomatic)","TBW × (Goal Na – Current Na)\nMax: 12 mEq/L/24h"],
["Na⁺ HIGH\n(Hypernatremia)","135–145\nmEq/L","0.45% NaCl / D5W\nFree water enteral","NaCl tabs","Decrease ≤1 mEq/L/hr\nMax: 10 mEq/L/24h","FWD = TBW × [(Na/140)–1]\nRisk: cerebral oedema"],
["K⁺ LOW\n(Hypokalemia)","3.5–5.0\nmEq/L","KCl IV in NS\n(10/20/40 mEq bags)","Klor-Con, K-Dur,\nKay Ciel 20mEq/15mL","10 mEq/hr periph\n20–40 mEq/hr central","Each 10 mEq → ↑K ~0.1\nCheck Mg first!"],
["K⁺ HIGH\n(Hyperkalemia)","3.5–5.0\nmEq/L","Ca gluconate + Insulin\n+ D50 + Kayexalate/\nLokelma + Dialysis","Lokelma, Veltassa,\nKayexalate","Ca gluconate\n0.5–1 g over 2–3 min","1. Stabilise membrane\n2. Shift K\n3. Remove K"],
["Ca²⁺ LOW\n(Hypocalcemia)","8.5–10.5\nmg/dL","Ca Gluconate 10% IV\n(1–2 g bolus, then\n0.5–2 g/hr infusion)","Caltrate, Os-Cal,\nShelcal, Cal-C-Vita","2 g/hr standard\n(peripheral IV ok)","Corrected Ca =\nMeasured + 0.8×(4–Alb)"],
["Ca²⁺ HIGH\n(Hypercalcemia)","8.5–10.5\nmg/dL","0.9% NS 200–500 mL/hr\n+ Furosemide\n+ Bisphosphonates","—","NS hydration\n200–500 mL/hr","Treat if >12 mg/dL or sx.\nZoledronic acid 4mg/15min"],
["Mg²⁺ LOW\n(Hypomagnesemia)","1.7–2.5\nmg/dL","MgSO4 IV\n1–4 g diluted in NS","Slow-Mag, Natural Calm\nMilk of Magnesia","1 g/hr standard\n(4 g/15-60min emergency)","1 g MgSO4 = 4 mEq\nAntidote: Ca gluconate"],
["Mg²⁺ HIGH\n(Hypermagnesemia)","1.7–2.5\nmg/dL","Ca gluconate (cardiac)\n+ HD if severe","Stop Mg-containing meds","Ca gluconate\n1–2 g over 10 min","Stop source; hydrate;\ndialyse if critical"],
["PO₄ LOW\n(Hypophosphatemia)","2.5–4.5\nmg/dL","K-Phos or Na-Phos IV\n15–45 mmol in 250 mL NS","Neutra-Phos,\nK-Phos Neutral,\nSkim milk","Max 7 mmol/hr","K-Phos if K < 4.0\nNa-Phos if K ≥ 4.0"],
["PO₄ HIGH\n(Hyperphosphatemia)","2.5–4.5\nmg/dL","Phosphate binders PO\n+ HD in ESRD","Renvela, PhosLo,\nFosrenol, Amphojel","—","Diet restriction +\nbinders with meals"]]
t = mk_table(data,
[2.5*cm, 2*cm, 4*cm, 3*cm, 3*cm, 4*cm],
C_NAVY, C_LTBLUE, fontsize=7.5)
e.append(t)
e.append(Spacer(1,12))
e.append(Paragraph(
"Sources: Schwartz's Principles of Surgery 11e · Fischer's Mastery of Surgery 8e · "
"Tintinalli's Emergency Medicine Comprehensive Study Guide · Goldman-Cecil Medicine · "
"Current Surgical Therapy 14e · VUMC Trauma & Surgical Critical Care Protocol (updated 2026) · "
"Michigan Medicine ICU Electrolyte Protocol",
ST["sources"]))
# ── Assemble document ──────────────────────────────────────────────────────────
def build():
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
leftMargin=1.8*cm, rightMargin=1.8*cm,
topMargin=1.8*cm, bottomMargin=1.5*cm,
title="Clinical Guide to Electrolyte Imbalances",
author="Orris Clinical AI",
subject="Electrolyte corrections, formulas, IV dilutions, oral brands"
)
elements = []
cover_page(elements)
sec_general(elements)
sec_sodium(elements)
sec_potassium(elements)
sec_calcium(elements)
sec_magnesium(elements)
sec_phosphate(elements)
sec_special(elements)
sec_quickref(elements)
doc.build(elements, onFirstPage=on_page, onLaterPages=on_page)
print(f"PDF created: {OUTPUT}")
if __name__ == "__main__":
build()