Hyponatremia cause management and diagnostic approach in details with reference from harrison , davidson and uptodate
hyponatremia diagnosis treatment guidelines
| Category | Serum Na⁺ |
|---|---|
| Mild | 130-134 mmol/L |
| Moderate | 125-129 mmol/L |
| Severe | <125 mmol/L (symptomatic risk high at <120) |
"Hyponatremia is almost always the result of an increase in circulating AVP and/or increased renal sensitivity to AVP, combined with an intake of free water." - Harrison's 22e



| Category | Examples |
|---|---|
| CNS | Stroke, SAH, meningitis, encephalitis, Guillain-Barre, head injury, psychosis |
| Pulmonary | Pneumonia, TB, abscess, COPD exacerbation, positive pressure ventilation, empyema |
| Malignancy | Small cell lung carcinoma, carcinoid, lymphoma, mesothelioma, GI/GU tumors (ectopic AVP production) |
| Drugs | Thiazides, SSRIs, TCAs, carbamazepine, oxcarbazepine, vincristine, cyclophosphamide, chlorpropamide, clofibrate, NSAIDs, opiates, MDMA, haloperidol |
| Endocrine | Hypothyroidism, glucocorticoid deficiency |
| Other | Postoperative state, pain, nausea, HIV/AIDS, hereditary (gain-of-function V2 receptor mutations) |
"The degree of hyponatremia provides an indirect index of the associated neurohumoral activation and is an important prognostic indicator in hypervolemic hyponatremia." - Harrison's 22e
| Cause |
|---|
| Postoperative hypotonic fluids (especially premenopausal women) |
| Hypotonic IV fluids with any cause of elevated AVP |
| Glycine irrigation (TURP, uterine surgery) |
| Colonoscopy preparation |
| Thiazide diuretics (recent institution) |
| Primary polydipsia |
| MDMA ("Ecstasy," "Molly") ingestion |
| Exercise-associated hyponatremia (marathons, endurance events) |
| Multifactorial (e.g., thiazide + polydipsia) |
| Severity | Na⁺ | Symptoms |
|---|---|---|
| Mild/asymptomatic | >125 | Usually none; subtle gait/cognitive defects may be present |
| Moderate | 120-125 | Headache, nausea, yawning, lethargy, reversible ataxia |
| Severe | <120 | Psychosis, seizures, coma, respiratory failure, brain herniation |
"Even patients who are judged 'asymptomatic' can manifest subtle gait and cognitive defects that reverse with correction of hyponatremia." - Harrison's 22e
| Urine Na⁺ | Interpretation |
|---|---|
| <10-20 mmol/L | Extrarenal Na⁺ loss or Na⁺-avid hypervolemic state (CHF, cirrhosis, nephrotic syndrome) |
| >20-40 mmol/L | Renal Na⁺ loss, SIAD, hypothyroidism, adrenal insufficiency, AKI/CKD |
| Parameter | SIAD | CSW |
|---|---|---|
| ECF volume | Increased/euvolemic | Decreased |
| Body weight | Increased | Decreased |
| Fluid balance | Positive | Negative |
| Urine volume | Normal or decreased | Normal or increased |
| Tachycardia | Absent | Present |
| Hematocrit | Normal | Increased |
| Albumin | Normal | Increased |
| Serum bicarbonate | Normal or low | Increased |
| BUN | Normal or low | Increased |
| Serum uric acid | Low | Normal or low |
| Urinary Na⁺ | High | High |
| CVP/PCWP | Normal or slightly high | Low |
ΔNa⁺ = (Infusate Na⁺ - Serum Na⁺) / (Total body water + 1)
| Parameter | Hypovolemic | Euvolemic | Hypervolemic |
|---|---|---|---|
| Total body water | ↓ | ↑ | ↑↑ |
| Total body Na⁺ | ↓↓ | Normal | ↑ |
| Urine Na⁺ | <20 (extrarenal) / >20 (renal) | >20 | <10 (CHF/cirrhosis) / >20 (AKI/CKD) |
| Urine Osm | High | High | Variable |
| Typical causes | Diarrhea, vomiting, burns, diuretics, Addison's | SIAD, hypothyroid, sec. adrenal insuff | CHF, cirrhosis, nephrotic, AKI/CKD |
| Treatment | IV NS (0.9%), correct cause | Fluid restriction, treat cause, vaptans/urea | Fluid restriction, diuretics, vaptans, treat cause |
Make in pdf form , note like
ls /home/daytona/workspace/ 2>/dev/null || mkdir -p /home/daytona/workspace/hypo…
mkdir -p /home/daytona/workspace/hyponatremia-notes && python3 -c "import report…
~/hyponatremia-notes/build_pdf.py
"""
Hyponatremia Medical Notes PDF Generator
Styled like clinical study notes: colored headers, tables, boxes, icons
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm, mm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether, PageBreak
)
from reportlab.platypus.flowables import Flowable
from reportlab.pdfgen import canvas
from reportlab.lib.colors import HexColor
import io
# ── Colour palette ────────────────────────────────────────────────────────────
C_NAVY = HexColor("#1A3A5C")
C_BLUE = HexColor("#2563EB")
C_LIGHT_BLUE= HexColor("#DBEAFE")
C_TEAL = HexColor("#0F766E")
C_TEAL_LIGHT= HexColor("#CCFBF1")
C_ORANGE = HexColor("#EA580C")
C_ORANGE_LT = HexColor("#FFF7ED")
C_RED = HexColor("#DC2626")
C_RED_LIGHT = HexColor("#FEF2F2")
C_GREEN = HexColor("#16A34A")
C_GREEN_LT = HexColor("#F0FDF4")
C_YELLOW = HexColor("#CA8A04")
C_YELLOW_LT = HexColor("#FEFCE8")
C_PURPLE = HexColor("#7C3AED")
C_PURPLE_LT = HexColor("#F5F3FF")
C_GREY = HexColor("#64748B")
C_GREY_LT = HexColor("#F8FAFC")
C_GREY_MED = HexColor("#E2E8F0")
C_WHITE = colors.white
C_BLACK = HexColor("#0F172A")
# ── Custom flowables ──────────────────────────────────────────────────────────
class ColorBox(Flowable):
"""A colored background box with left accent bar."""
def __init__(self, content_paragraphs, bg_color, bar_color, width=None, pad=8):
Flowable.__init__(self)
self.content = content_paragraphs
self.bg = bg_color
self.bar = bar_color
self.w = width or (A4[0] - 3.5*cm)
self.pad = pad
self._h = None
def wrap(self, avail_w, avail_h):
self.w = avail_w
inner_w = self.w - 6 - self.pad*2
total_h = self.pad
for p in self.content:
_, ph = p.wrap(inner_w, avail_h)
total_h += ph + 2
total_h += self.pad
self._h = total_h
return self.w, self._h
def draw(self):
c = self.canv
# background
c.setFillColor(self.bg)
c.roundRect(0, 0, self.w, self._h, 4, fill=1, stroke=0)
# left bar
c.setFillColor(self.bar)
c.rect(0, 0, 5, self._h, fill=1, stroke=0)
# content
inner_w = self.w - 6 - self.pad*2
y = self._h - self.pad
for p in self.content:
_, ph = p.wrap(inner_w, self._h)
y -= ph
p.drawOn(c, 6 + self.pad, y)
y -= 2
c.setFillColor(C_BLACK)
class SectionHeader(Flowable):
"""Full-width colored section header bar."""
def __init__(self, text, bg=C_NAVY, fg=C_WHITE, height=22, icon=""):
Flowable.__init__(self)
self.text = icon + " " + text if icon else text
self.bg = bg
self.fg = fg
self.h = height
def wrap(self, aw, ah):
self.w = aw
return aw, self.h
def draw(self):
c = self.canv
c.setFillColor(self.bg)
c.roundRect(0, 0, self.w, self.h, 5, fill=1, stroke=0)
c.setFillColor(self.fg)
c.setFont("Helvetica-Bold", 11)
c.drawString(10, 6, self.text)
class SubHeader(Flowable):
"""Smaller sub-section header."""
def __init__(self, text, bg=C_BLUE, fg=C_WHITE, height=18):
Flowable.__init__(self)
self.text = text
self.bg = bg
self.fg = fg
self.h = height
def wrap(self, aw, ah):
self.w = aw
return aw, self.h
def draw(self):
c = self.canv
c.setFillColor(self.bg)
c.roundRect(0, 0, self.w, self.h, 3, fill=1, stroke=0)
c.setFillColor(self.fg)
c.setFont("Helvetica-Bold", 9.5)
c.drawString(8, 5, self.text)
class TwoColLayout(Flowable):
"""Two-column layout for compact side-by-side content."""
def __init__(self, left_items, right_items, col_headers=("",""), h_bg=(C_TEAL, C_ORANGE)):
Flowable.__init__(self)
self.left = left_items
self.right = right_items
self.col_headers = col_headers
self.h_bg = h_bg
# ── Page template ─────────────────────────────────────────────────────────────
def make_header_footer(canvas_obj, doc):
"""Running header/footer on every page."""
canvas_obj.saveState()
w, h = A4
# Top bar
canvas_obj.setFillColor(C_NAVY)
canvas_obj.rect(0, h-1.1*cm, w, 1.1*cm, fill=1, stroke=0)
canvas_obj.setFillColor(C_WHITE)
canvas_obj.setFont("Helvetica-Bold", 9)
canvas_obj.drawString(1*cm, h-0.75*cm, "HYPONATREMIA — Clinical Study Notes")
canvas_obj.setFont("Helvetica", 8)
canvas_obj.drawRightString(w-1*cm, h-0.75*cm,
"Harrison's 22e | Comprehensive Nephrology 7e | UpToDate")
# Bottom bar
canvas_obj.setFillColor(C_GREY_MED)
canvas_obj.rect(0, 0, w, 0.8*cm, fill=1, stroke=0)
canvas_obj.setFillColor(C_GREY)
canvas_obj.setFont("Helvetica", 7.5)
canvas_obj.drawString(1*cm, 0.25*cm,
"For educational use only | Orris AI Medical Notes | July 2026")
canvas_obj.drawRightString(w-1*cm, 0.25*cm, f"Page {doc.page}")
canvas_obj.restoreState()
# ── Style helpers ─────────────────────────────────────────────────────────────
def styles():
base = getSampleStyleSheet()
S = {}
S['body'] = ParagraphStyle('body',
fontName='Helvetica', fontSize=8.5, leading=13,
textColor=C_BLACK, spaceAfter=3, spaceBefore=2)
S['body_sm'] = ParagraphStyle('body_sm',
fontName='Helvetica', fontSize=7.8, leading=11.5,
textColor=C_BLACK, spaceAfter=2)
S['bold'] = ParagraphStyle('bold',
fontName='Helvetica-Bold', fontSize=8.5, leading=13,
textColor=C_BLACK)
S['blue_bold'] = ParagraphStyle('blue_bold',
fontName='Helvetica-Bold', fontSize=8.5, leading=13,
textColor=C_BLUE)
S['red_bold'] = ParagraphStyle('red_bold',
fontName='Helvetica-Bold', fontSize=8.5, leading=13,
textColor=C_RED)
S['teal_bold'] = ParagraphStyle('teal_bold',
fontName='Helvetica-Bold', fontSize=8.5, leading=13,
textColor=C_TEAL)
S['orange_bold'] = ParagraphStyle('orange_bold',
fontName='Helvetica-Bold', fontSize=8.5, leading=13,
textColor=C_ORANGE)
S['purple_bold'] = ParagraphStyle('purple_bold',
fontName='Helvetica-Bold', fontSize=8.5, leading=13,
textColor=C_PURPLE)
S['title_main'] = ParagraphStyle('title_main',
fontName='Helvetica-Bold', fontSize=26, leading=32,
textColor=C_WHITE, alignment=TA_CENTER)
S['title_sub'] = ParagraphStyle('title_sub',
fontName='Helvetica', fontSize=11, leading=16,
textColor=HexColor("#BFDBFE"), alignment=TA_CENTER)
S['quote'] = ParagraphStyle('quote',
fontName='Helvetica-Oblique', fontSize=8, leading=12,
textColor=C_TEAL, leftIndent=6)
S['bullet'] = ParagraphStyle('bullet',
fontName='Helvetica', fontSize=8.5, leading=13,
textColor=C_BLACK, leftIndent=12, firstLineIndent=-8,
spaceAfter=2)
S['bullet_sm'] = ParagraphStyle('bullet_sm',
fontName='Helvetica', fontSize=7.8, leading=11,
textColor=C_BLACK, leftIndent=12, firstLineIndent=-8,
spaceAfter=1)
S['table_hdr'] = ParagraphStyle('table_hdr',
fontName='Helvetica-Bold', fontSize=8, leading=11,
textColor=C_WHITE, alignment=TA_CENTER)
S['table_cell'] = ParagraphStyle('table_cell',
fontName='Helvetica', fontSize=7.8, leading=11,
textColor=C_BLACK)
S['table_cell_b'] = ParagraphStyle('table_cell_b',
fontName='Helvetica-Bold', fontSize=7.8, leading=11,
textColor=C_BLACK)
S['warn'] = ParagraphStyle('warn',
fontName='Helvetica-Bold', fontSize=8.5, leading=13,
textColor=C_RED)
S['center'] = ParagraphStyle('center',
fontName='Helvetica', fontSize=8.5, leading=13,
textColor=C_BLACK, alignment=TA_CENTER)
return S
# ── Table helper ──────────────────────────────────────────────────────────────
def make_table(data, col_widths, hdr_bg=C_NAVY, alt_row=True, fontsize=7.8):
"""Build a styled reportlab Table."""
S = styles()
# Convert strings to Paragraphs
table_data = []
for ri, row in enumerate(data):
p_row = []
for ci, cell in enumerate(row):
if ri == 0:
st = S['table_hdr']
else:
st = S['table_cell']
p_row.append(Paragraph(str(cell), st))
table_data.append(p_row)
t = Table(table_data, colWidths=col_widths, repeatRows=1)
style_cmds = [
('BACKGROUND', (0,0), (-1,0), hdr_bg),
('TEXTCOLOR', (0,0), (-1,0), C_WHITE),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,0), 8),
('GRID', (0,0), (-1,-1), 0.4, C_GREY_MED),
('ROWBACKGROUNDS', (0,1), (-1,-1),
[C_WHITE, HexColor("#F1F5F9")] if alt_row else [C_WHITE]),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('TOPPADDING', (0,0), (-1,-1), 4),
('BOTTOMPADDING', (0,0), (-1,-1), 4),
('LEFTPADDING', (0,0), (-1,-1), 5),
('RIGHTPADDING', (0,0), (-1,-1), 5),
('ROWBACKGROUNDS', (0,0), (-1,0), [hdr_bg]),
]
t.setStyle(TableStyle(style_cmds))
return t
def bullet(text, style_key='bullet', s=None):
if s is None: s = styles()
return Paragraph(f"• {text}", s[style_key])
def sp(n=4):
return Spacer(1, n)
# ── COVER PAGE ────────────────────────────────────────────────────────────────
def cover_page(story, S):
# Spacer to push down
story.append(Spacer(1, 2.5*cm))
# Title card (manual drawing via canvas-like table trick)
title_data = [[Paragraph("HYPONATREMIA", S['title_main'])]]
t = Table(title_data, colWidths=[17*cm])
t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,-1), C_NAVY),
('ROUNDEDCORNERS', [8]),
('TOPPADDING', (0,0), (-1,-1), 22),
('BOTTOMPADDING', (0,0), (-1,-1), 8),
('LEFTPADDING', (0,0), (-1,-1), 10),
]))
story.append(t)
sub_data = [[Paragraph(
"Cause • Diagnostic Approach • Management", S['title_sub'])]]
t2 = Table(sub_data, colWidths=[17*cm])
t2.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,-1), C_BLUE),
('TOPPADDING', (0,0), (-1,-1), 10),
('BOTTOMPADDING', (0,0), (-1,-1), 14),
]))
story.append(t2)
story.append(sp(12))
# Source badge row
badge_data = [[
Paragraph("<b>Harrison's 22e</b><br/>(2025)", S['center']),
Paragraph("<b>Comp. Nephrology 7e</b>", S['center']),
Paragraph("<b>UpToDate 2026</b>", S['center']),
Paragraph("<b>PubMed Evidence</b>", S['center']),
]]
badge_t = Table(badge_data, colWidths=[4.25*cm]*4)
badge_t.setStyle(TableStyle([
('BACKGROUND', (0,0), (0,0), C_TEAL),
('BACKGROUND', (1,0), (1,0), C_BLUE),
('BACKGROUND', (2,0), (2,0), C_ORANGE),
('BACKGROUND', (3,0), (3,0), C_PURPLE),
('TEXTCOLOR', (0,0), (-1,-1), C_WHITE),
('FONTNAME', (0,0), (-1,-1), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,-1), 9),
('ALIGN', (0,0), (-1,-1), 'CENTER'),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('TOPPADDING', (0,0), (-1,-1), 10),
('BOTTOMPADDING', (0,0), (-1,-1), 10),
('GRID', (0,0), (-1,-1), 1, C_WHITE),
('ROUNDEDCORNERS', [4]),
]))
story.append(badge_t)
story.append(sp(14))
# Quick summary box
summary_items = [
Paragraph("<b>DEFINITION:</b> Plasma Na⁺ < 135 mmol/L | Most common electrolyte disorder", S['body']),
Paragraph("<b>PREVALENCE:</b> Up to 22% of hospitalized patients", S['body']),
Paragraph("<b>KEY MECHANISM:</b> Excess AVP activity + free water intake (>90% of cases)", S['body']),
Paragraph("<b>CLASSIFICATION:</b> Hypovolemic | Euvolemic | Hypervolemic (by volume status)", S['body']),
Paragraph("<b>DANGER:</b> Acute → cerebral edema | Rapid correction → osmotic demyelination", S['body']),
]
story.append(ColorBox(summary_items, C_LIGHT_BLUE, C_BLUE))
story.append(sp(10))
# Date/Author row
meta = [[ Paragraph("Prepared: July 2026", S['body_sm']),
Paragraph("Orris AI Medical Notes", S['body_sm']),
Paragraph("Educational Use Only", S['body_sm']) ]]
mt = Table(meta, colWidths=[5.67*cm]*3)
mt.setStyle(TableStyle([
('TEXTCOLOR', (0,0), (-1,-1), C_GREY),
('ALIGN', (0,0), (-1,-1), 'CENTER'),
('GRID', (0,0), (-1,-1), 0.3, C_GREY_MED),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
]))
story.append(mt)
story.append(PageBreak())
# ── SECTION 1: DEFINITION & PATHOPHYSIOLOGY ──────────────────────────────────
def section_patho(story, S):
story.append(SectionHeader("1. DEFINITION, EPIDEMIOLOGY & PATHOPHYSIOLOGY", C_NAVY, icon="📌"))
story.append(sp(6))
# Severity table
story.append(SubHeader("Severity Classification", C_TEAL))
story.append(sp(4))
sev_data = [
["Category", "Serum Na⁺", "Clinical Risk"],
["Mild", "130–134 mmol/L", "Usually asymptomatic; subtle cognitive/gait defects"],
["Moderate", "125–129 mmol/L", "Headache, nausea, lethargy, ataxia"],
["Severe", "< 125 mmol/L", "Seizures, coma, brain herniation, death"],
]
story.append(make_table(sev_data, [4*cm, 4.5*cm, 8.5*cm], hdr_bg=C_TEAL))
story.append(sp(8))
# Pathophysiology
story.append(SubHeader("Pathophysiology — Why Does Hyponatremia Develop?", C_BLUE))
story.append(sp(4))
patho_box = [
Paragraph("<b>Core mechanism:</b> Impaired urinary dilution → water retention → dilution of serum Na⁺", S['body']),
Paragraph("Three mechanisms (Comprehensive Nephrology 7e, Ch.9):", S['bold']),
Paragraph("1. <b>Nonosmotic AVP release</b> — volume depletion, pain, nausea, drugs → V2 receptor activation → AQP-2 insertion → water retention (most common)", S['body']),
Paragraph("2. <b>Reduced distal delivery</b> — low GFR or increased proximal tubule reabsorption limits diluting segment flow", S['body']),
Paragraph("3. <b>Impaired NaCl transport</b> — thick ascending limb (TAL) / distal convoluted tubule dysfunction (e.g., thiazides)", S['body']),
]
story.append(ColorBox(patho_box, C_LIGHT_BLUE, C_BLUE))
story.append(sp(6))
# Brain adaptation table
story.append(SubHeader("Brain Adaptation: Acute vs Chronic", C_PURPLE))
story.append(sp(4))
brain_data = [
["Phase", "Timing", "Mechanism", "Clinical Implication"],
["Acute", "Minutes–Hours", "ECF→ICF water shift; Na⁺/K⁺/Cl⁻ exit from brain cells", "Cerebral edema → herniation risk"],
["Chronic", "Hours–48h", "Organic osmolyte extrusion (creatine, betaine, myoinositol, taurine, glutamate)", "Brain re-adapts; volume near normal"],
["Correction risk", "> 48h duration", "Brain depleted of osmolytes; cannot rapidly reaccumulate", "Rapid correction → osmotic demyelination (ODS)"],
]
story.append(make_table(brain_data, [2.5*cm, 3*cm, 6*cm, 5.5*cm], hdr_bg=C_PURPLE))
story.append(sp(6))
quote_box = [
Paragraph(
'"Hyponatremia is almost always the result of an increase in circulating AVP '
'and/or increased renal sensitivity to AVP, combined with an intake of free water."',
S['quote']),
Paragraph("— Harrison's Principles of Internal Medicine, 22nd Edition (2025), Ch.56", S['body_sm']),
]
story.append(ColorBox(quote_box, C_TEAL_LIGHT, C_TEAL))
story.append(sp(8))
# ── SECTION 2: CLASSIFICATION & CAUSES ───────────────────────────────────────
def section_causes(story, S):
story.append(SectionHeader("2. CLASSIFICATION & CAUSES", C_NAVY, icon="🗂"))
story.append(sp(6))
# The 3-group overview
overview_data = [
["HYPOVOLEMIC", "EUVOLEMIC", "HYPERVOLEMIC"],
["Total body water ↓\nTotal body Na⁺ ↓↓",
"Total body water ↑\nTotal body Na⁺ → (normal)",
"Total body water ↑↑\nTotal body Na⁺ ↑"],
["Urine Na⁺ <20 → extrarenal\nUrine Na⁺ >20 → renal",
"Urine Na⁺ >20 (usually)",
"Urine Na⁺ <10 (CHF/cirrhosis)\nUrine Na⁺ >20 (AKI/CKD)"],
]
t_ov = Table(overview_data, colWidths=[5.67*cm]*3)
t_ov.setStyle(TableStyle([
('BACKGROUND', (0,0), (0,0), C_ORANGE),
('BACKGROUND', (1,0), (1,0), C_TEAL),
('BACKGROUND', (2,0), (2,0), C_BLUE),
('TEXTCOLOR', (0,0), (-1,0), C_WHITE),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,-1), 8.5),
('ALIGN', (0,0), (-1,-1), 'CENTER'),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('GRID', (0,0), (-1,-1), 0.5, C_WHITE),
('ROWBACKGROUNDS', (0,1), (-1,-1), [C_ORANGE_LT, HexColor("#F0FDF4")]),
('TOPPADDING', (0,0), (-1,-1), 7),
('BOTTOMPADDING', (0,0), (-1,-1), 7),
]))
story.append(t_ov)
story.append(sp(8))
# ── 2A Hypovolemic ──
story.append(SubHeader("A. Hypovolemic Hyponatremia", C_ORANGE))
story.append(sp(4))
hypo_data = [
["Urine Na⁺ < 20 mmol/L (Extrarenal Losses)", "Urine Na⁺ > 20 mmol/L (Renal Losses)"],
[
"• Vomiting / diarrhea / tube drainage\n• Burns\n• Excessive sweating\n"
"• Third-space: peritonitis, pancreatitis, ileus\n"
"⚠ Exception: vomiting + metabolic alkalosis → urine Na⁺ may be >20\n → use urine Cl⁻ (<10 = extrarenal)",
"• Thiazide diuretics (most common)\n• Primary adrenal insufficiency (Addison's)\n"
"• Salt-losing nephropathy (reflux, interstitial, medullary cystic)\n"
"• Renal tubular acidosis / metabolic alkalosis (bicarbonaturia)\n"
"• Ketonuria (alcoholic / starvation)\n• Osmotic diuresis\n"
"• Cerebral salt wasting (SAH, TBI, meningitis)"
],
]
t_hypo = Table(hypo_data, colWidths=[8.5*cm, 8.5*cm])
t_hypo.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), C_ORANGE),
('TEXTCOLOR', (0,0), (-1,0), C_WHITE),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,-1), 8),
('GRID', (0,0), (-1,-1), 0.4, C_GREY_MED),
('BACKGROUND', (0,1), (0,1), C_ORANGE_LT),
('BACKGROUND', (1,1), (1,1), HexColor("#FFF7F0")),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('TOPPADDING', (0,0), (-1,-1), 6),
('BOTTOMPADDING', (0,0), (-1,-1), 6),
('LEFTPADDING', (0,0), (-1,-1), 6),
('ALIGN', (0,0), (-1,0), 'CENTER'),
]))
story.append(t_hypo)
story.append(sp(8))
# Addison's callout
add_items = [
Paragraph("<b>⚠ Addison's Disease Clue:</b> Hyponatremia + Hyperkalemia + Hypotension + High Urine Na⁺", S['warn']),
Paragraph("→ Suggest primary adrenal insufficiency; confirm with AM cortisol / ACTH stimulation test", S['body']),
]
story.append(ColorBox(add_items, C_RED_LIGHT, C_RED))
story.append(sp(8))
# ── 2B Euvolemic ──
story.append(SubHeader("B. Euvolemic Hyponatremia", C_TEAL))
story.append(sp(4))
# SIAD criteria box
siad_items = [
Paragraph("<b>SIAD Diagnostic Criteria (Harrison's 22e, Table 56-1):</b>", S['teal_bold']),
Paragraph("1. Plasma osmolality < 275 mOsm/kg", S['body']),
Paragraph("2. Urine osmolality > 100 mOsm/kg (usually >300 mOsm/kg)", S['body']),
Paragraph("3. Clinical euvolemia (no dehydration, no edema/ascites)", S['body']),
Paragraph("4. Urine Na⁺ > 20–30 mmol/L on normal salt/water intake", S['body']),
Paragraph("5. Normal thyroid (TSH) and adrenal (cortisol) function", S['body']),
Paragraph("6. No recent diuretic therapy", S['body']),
]
story.append(ColorBox(siad_items, C_TEAL_LIGHT, C_TEAL))
story.append(sp(6))
# SIAD causes table
siad_cause_data = [
["Category", "Examples"],
["CNS", "Stroke, SAH, meningitis, encephalitis, Guillain-Barré, TBI, psychosis"],
["Pulmonary", "Pneumonia, TB, lung abscess, COPD exacerbation, PPV, empyema"],
["Malignancy", "Small cell lung Ca, carcinoid, lymphoma, mesothelioma, GI/GU tumors (ectopic AVP)"],
["Drugs", "SSRIs, TCAs, carbamazepine, oxcarbazepine, vincristine, cyclophosphamide,\nchlorpropamide, NSAIDs, opiates, MDMA, haloperidol, thiazides"],
["Other", "Post-operative, pain, nausea, HIV/AIDS, hereditary (V2 gain-of-function)"],
["Endocrine", "Hypothyroidism, secondary glucocorticoid deficiency"],
]
story.append(make_table(siad_cause_data, [3.5*cm, 13.5*cm], hdr_bg=C_TEAL))
story.append(sp(6))
# Other euvolemic causes
eu_other = [
Paragraph("<b>Other Euvolemic Causes:</b>", S['body']),
Paragraph("• <b>Hypothyroidism</b> — moderate to severe; corrects with thyroid hormone replacement", S['body']),
Paragraph("• <b>Secondary adrenal insufficiency</b> (pituitary disease) — glucocorticoid deficiency → loss of AVP inhibition; Note: no hyperkalemia (aldosterone intact)", S['body']),
Paragraph("• <b>Beer potomania / Low solute intake</b> — massive hypotonic fluid intake + insufficient dietary solute → insufficient osmole excretion to drive free water loss", S['body']),
]
story.append(ColorBox(eu_other, C_TEAL_LIGHT, C_TEAL))
story.append(sp(8))
# ── 2C Hypervolemic ──
story.append(SubHeader("C. Hypervolemic Hyponatremia", C_BLUE))
story.append(sp(4))
hyper_data = [
["Urine Na⁺ < 10 mmol/L", "Urine Na⁺ > 20 mmol/L"],
["• Congestive heart failure (CHF)\n — cardiac dysfunction → arterial underfilling\n"
"• Hepatic cirrhosis\n — peripheral vasodilation → reduced arterial filling\n"
"• Nephrotic syndrome\n — hypoalbuminemia → third-space losses",
"• Acute kidney injury (AKI)\n• Chronic kidney disease (CKD)\n — impaired free water excretion\n\n"
"Note: Na⁺-avid state in CHF/cirrhosis may be\nmasked by diuretic therapy"],
]
t_hyper = Table(hyper_data, colWidths=[8.5*cm, 8.5*cm])
t_hyper.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), C_BLUE),
('TEXTCOLOR', (0,0), (-1,0), C_WHITE),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,-1), 8),
('GRID', (0,0), (-1,-1), 0.4, C_GREY_MED),
('BACKGROUND', (0,1), (0,1), C_LIGHT_BLUE),
('BACKGROUND', (1,1), (1,1), HexColor("#EFF6FF")),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('TOPPADDING', (0,0), (-1,-1), 6),
('BOTTOMPADDING', (0,0), (-1,-1), 6),
('LEFTPADDING', (0,0), (-1,-1), 6),
('ALIGN', (0,0), (-1,0), 'CENTER'),
]))
story.append(t_hyper)
story.append(sp(8))
# ── 2D Pseudo / Translocational ──
story.append(SubHeader("D. Pseudohyponatremia & Translocational Hyponatremia", C_GREY))
story.append(sp(4))
pseudo_data = [
["Type", "Serum Osmolality", "Cause", "Action"],
["Pseudohyponatremia", "Normal (275–290)", "Severe hyperlipidemia, hyperproteinemia\n(lab artifact — water displacement)", "Remeasure with direct ISE; no treatment"],
["Translocational", "HIGH (>290)", "Hyperglycemia, mannitol, sorbitol, glycine (TURP)\n(osmotic water shift from ICF)", "Correct glucose; Na⁺ corrects automatically\n(1.6–2.4 mmol/L per 100 mg/dL glucose rise)"],
]
story.append(make_table(pseudo_data, [3.5*cm, 3.5*cm, 5.5*cm, 4.5*cm], hdr_bg=C_GREY))
story.append(sp(8))
# ── SECTION 3: CLINICAL FEATURES ─────────────────────────────────────────────
def section_clinical(story, S):
story.append(SectionHeader("3. CLINICAL FEATURES", C_NAVY, icon="🩺"))
story.append(sp(6))
# Symptoms by severity
sym_data = [
["Na⁺ Level", "Symptoms"],
["> 130 mmol/L", "Usually none; subtle gait instability, mild cognitive slowing (often unrecognized)"],
["125–130 mmol/L", "Nausea, headache, yawning, lethargy, fatigue"],
["120–125 mmol/L", "Confusion, disorientation, reversible ataxia, psychosis"],
["< 120 mmol/L", "Seizures, obtundation, coma, respiratory failure, brain herniation, death"],
]
story.append(make_table(sym_data, [4*cm, 13*cm], hdr_bg=C_RED))
story.append(sp(8))
# Acute vs Chronic two-col
story.append(SubHeader("Acute (<48h) vs Chronic (>48h) — Key Differences", C_BLUE))
story.append(sp(4))
ac_data = [
["ACUTE Hyponatremia (<48h)", "CHRONIC Hyponatremia (>48h)"],
["• Brain has NOT adapted → full osmotic stress\n"
"• Cerebral edema is the main danger\n"
"• Symptoms: nausea, headache, seizures, coma\n"
"• Neurogenic pulmonary edema possible\n"
"• Women (premenopausal) at ↑ risk — estrogen\n inhibits brain osmolyte extrusion\n"
"• Aggressive correction is REQUIRED",
"• Brain has adapted via organic osmolyte loss\n"
"• Reduced acute cerebral edema risk\n"
"• Subtle symptoms: gait disorders, cognitive deficit,\n falls, fractures\n"
"• CAUTION: Rapid correction → osmotic\n demyelination syndrome (ODS)\n"
"• Correction rate must be STRICTLY limited"],
]
t_ac = Table(ac_data, colWidths=[8.5*cm, 8.5*cm])
t_ac.setStyle(TableStyle([
('BACKGROUND', (0,0), (0,0), C_RED),
('BACKGROUND', (1,0), (1,0), C_ORANGE),
('TEXTCOLOR', (0,0), (-1,0), C_WHITE),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,-1), 8),
('GRID', (0,0), (-1,-1), 0.4, C_GREY_MED),
('BACKGROUND', (0,1), (0,1), C_RED_LIGHT),
('BACKGROUND', (1,1), (1,1), C_ORANGE_LT),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('TOPPADDING', (0,0), (-1,-1), 6),
('BOTTOMPADDING', (0,0), (-1,-1), 6),
('LEFTPADDING', (0,0), (-1,-1), 6),
('ALIGN', (0,0), (-1,0), 'CENTER'),
]))
story.append(t_ac)
story.append(sp(8))
# ODS box
ods_items = [
Paragraph("<b>Osmotic Demyelination Syndrome (ODS) / Central Pontine Myelinolysis (CPM)</b>", S['red_bold']),
Paragraph("Cause: Too-rapid correction of chronic hyponatremia → osmotic myelin destruction", S['body']),
Paragraph("Symptoms: Dysarthria, dysphagia, spastic quadriparesis, pseudobulbar palsy, 'locked-in' syndrome, coma", S['body']),
Paragraph("MRI: T2 hyperintensity in pons (±extrapontine — basal ganglia, thalamus, cerebellum)", S['body']),
Paragraph("<b>High-risk patients:</b> Na⁺ <105 | Alcoholism | Malnutrition | Liver disease | Burns | Hypokalemia", S['warn']),
Paragraph("Note: Not uniformly fatal — significant neurological recovery possible with supportive care", S['body']),
]
story.append(ColorBox(ods_items, C_RED_LIGHT, C_RED))
story.append(sp(8))
# Acute hyponatremia causes table
story.append(SubHeader("Causes of Acute Hyponatremia (Harrison's Table 56-2)", C_ORANGE))
story.append(sp(4))
acute_data = [
["Cause"],
["Postoperative hypotonic fluids — especially premenopausal women"],
["Hypotonic IV fluids with any cause of elevated AVP"],
["Glycine irrigation solutions — TURP, uterine surgery"],
["Colonoscopy preparation solutions"],
["Thiazide diuretics — recent initiation"],
["Primary polydipsia"],
["MDMA ('Ecstasy', 'Molly') — potent AVP release + thirst stimulation"],
["Exercise-associated hyponatremia — endurance events (marathons)"],
["Multifactorial, e.g., thiazide + polydipsia"],
]
story.append(make_table(acute_data, [17*cm], hdr_bg=C_ORANGE))
story.append(sp(8))
# ── SECTION 4: DIAGNOSTIC APPROACH ───────────────────────────────────────────
def section_diagnosis(story, S):
story.append(SectionHeader("4. DIAGNOSTIC APPROACH", C_NAVY, icon="🔍"))
story.append(sp(6))
diag_flow = [
Paragraph("<b>Step 1 — Confirm true hyponatremia: Measure Serum Osmolality</b>", S['bold']),
Paragraph("• Low (<275 mOsm/kg) → TRUE hypotonic hyponatremia → proceed to Step 2", S['body']),
Paragraph("• Normal (275–290) → Pseudohyponatremia (lipemia / paraproteinemia) → confirm with direct ISE", S['body']),
Paragraph("• High (>290) → Translocational (hyperglycemia, mannitol, sorbitol, glycine)", S['body']),
]
story.append(ColorBox(diag_flow, C_LIGHT_BLUE, C_BLUE))
story.append(sp(6))
diag_step2 = [
Paragraph("<b>Step 2 — Assess Volume Status (Clinical Examination)</b>", S['bold']),
Paragraph("• <b>Hypovolemic:</b> Dry mucous membranes, ↓ skin turgor, tachycardia, orthostasis, flat neck veins, recent fluid loss", S['body']),
Paragraph("• <b>Euvolemic:</b> No edema, no signs of dehydration, no ascites", S['body']),
Paragraph("• <b>Hypervolemic:</b> Pitting edema, ascites, ↑ JVP, S3 gallop, pulmonary crackles", S['body']),
]
story.append(ColorBox(diag_step2, C_TEAL_LIGHT, C_TEAL))
story.append(sp(6))
diag_step3 = [
Paragraph("<b>Step 3 — Urine Studies</b>", S['bold']),
Paragraph("• <b>Urine osmolality:</b> >100 mOsm/kg → AVP-mediated water retention | <100 mOsm/kg → primary polydipsia or low solute intake", S['body']),
Paragraph("• <b>Urine Na⁺:</b> <10–20 → extrarenal loss or Na⁺-avid state (CHF, cirrhosis, nephrotic) | >20–40 → renal loss, SIAD, hypothyroid, adrenal insuff, AKI", S['body']),
Paragraph("• <b>Urine Cl⁻:</b> Use instead of Na⁺ if vomiting with metabolic alkalosis (bicarbonaturia falsely elevates urine Na⁺)", S['body']),
]
story.append(ColorBox(diag_step3, C_ORANGE_LT, C_ORANGE))
story.append(sp(6))
# Additional tests
story.append(SubHeader("Step 4 — Additional Investigations (to find underlying cause)", C_PURPLE))
story.append(sp(4))
inv_data = [
["Test", "Purpose"],
["Serum glucose, BUN, creatinine", "Exclude translocational; assess renal function"],
["Serum lipids, serum protein (SPEP)", "Exclude pseudohyponatremia"],
["TSH, free T4", "Exclude hypothyroidism"],
["AM cortisol / ACTH stimulation test", "Exclude primary or secondary adrenal insufficiency"],
["Serum potassium", "Hyperkalemia → Addison's; Hypokalemia → ODS risk factor"],
["Serum uric acid", "Low (<4 mg/dL) → SIAD; Normal/high → CSW or hypovolemia"],
["LFTs, albumin, proBNP/BNP", "Assess cirrhosis, cardiac failure"],
["Fractional excretion of urate (FEUA)", ">12% → SIAD; helps distinguish from CSW (2026 evidence)"],
["CXR / CT chest-abdomen", "If SIAD — search for malignancy (SCLC), pulmonary cause"],
["Serum and urine osmolality simultaneously", "Calculate osmolar gap; verify urine diluting ability"],
]
story.append(make_table(inv_data, [6*cm, 11*cm], hdr_bg=C_PURPLE))
story.append(sp(8))
# SIAD vs CSW table
story.append(SubHeader("SIAD vs Cerebral Salt Wasting (CSW) — Critical Distinction", C_RED))
story.append(sp(4))
csw_items = [
Paragraph("<b>Why it matters:</b> SIAD → fluid restriction | CSW → aggressive NaCl + fluid repletion", S['warn']),
Paragraph("Confusing the two is potentially fatal", S['body']),
]
story.append(ColorBox(csw_items, C_RED_LIGHT, C_RED))
story.append(sp(4))
csw_data = [
["Parameter", "SIAD", "CSW"],
["ECF volume", "Normal/increased (euvolemic)", "↓ Decreased"],
["Body weight", "↑ Increased", "↓ Decreased"],
["Fluid balance", "Positive", "Negative"],
["Urine volume", "Normal or ↓", "Normal or ↑"],
["Tachycardia", "Absent", "Present"],
["Hematocrit", "Normal", "↑ Increased"],
["Albumin", "Normal", "↑ Increased"],
["Serum bicarbonate", "Normal or low", "↑ Increased"],
["BUN", "Normal or low", "↑ Increased"],
["Serum uric acid", "⬇ LOW (key feature)", "Normal or low"],
["Urinary Na⁺", "↑ High", "↑ High"],
["CVP/PCWP", "Normal or slightly ↑", "⬇ LOW (key feature)"],
["FEUA", ">12% → SIAD", "May be elevated briefly"],
]
t_csw = Table(csw_data, colWidths=[5.5*cm, 5.75*cm, 5.75*cm])
t_csw.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), C_RED),
('TEXTCOLOR', (0,0), (-1,0), C_WHITE),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,-1), 8),
('GRID', (0,0), (-1,-1), 0.4, C_GREY_MED),
('ROWBACKGROUNDS', (0,1), (-1,-1), [C_WHITE, HexColor("#FFF1F2")]),
('BACKGROUND', (1,10), (1,10), HexColor("#FEE2E2")), # uric acid SIAD
('BACKGROUND', (2,12), (2,12), HexColor("#FEE2E2")), # CVP CSW
('FONTNAME', (0,10), (2,10), 'Helvetica-Bold'),
('FONTNAME', (0,12), (2,12), 'Helvetica-Bold'),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('TOPPADDING', (0,0), (-1,-1), 4),
('BOTTOMPADDING', (0,0), (-1,-1), 4),
('LEFTPADDING', (0,0), (-1,-1), 5),
]))
story.append(t_csw)
story.append(sp(8))
# ── SECTION 5: MANAGEMENT ─────────────────────────────────────────────────────
def section_management(story, S):
story.append(SectionHeader("5. MANAGEMENT", C_NAVY, icon="💊"))
story.append(sp(6))
# Correction rate box
rate_items = [
Paragraph("<b>CORRECTION RATE LIMITS — Must Memorize</b>", S['red_bold']),
Paragraph("• Maximum: <b>10–12 mmol/L per 24 hours</b> (conservative: 8–10 if high ODS risk)", S['body']),
Paragraph("• Maximum in first 24h: <b>10 mmol/L</b>", S['body']),
Paragraph("• Do NOT exceed: <b>18 mmol/L in 48 hours</b>", S['body']),
Paragraph("• Highest ODS-risk patients (Na⁺ <105, alcoholism, malnutrition, liver disease): <b>≤8 mmol/L/24h</b>", S['body']),
Paragraph("• 2026 meta-analysis (PMID 41652262): Overcorrection significantly worsens neurological outcomes & mortality", S['body_sm']),
]
story.append(ColorBox(rate_items, C_RED_LIGHT, C_RED))
story.append(sp(8))
# Adrogué-Madias formula
formula_items = [
Paragraph("<b>Adrogué-Madias Formula — Na⁺ Change from 1L Infusate:</b>", S['bold']),
Paragraph("ΔNa⁺ = (Infusate Na⁺ − Serum Na⁺) ÷ (Total Body Water + 1)", S['blue_bold']),
Paragraph("TBW = 0.6 × lean body weight (men) | 0.5 × lean body weight (women)", S['body']),
Paragraph("3% NaCl = 513 mmol/L Na⁺ | 0.9% NaCl = 154 mmol/L | 0.45% NaCl = 77 mmol/L | D5W = 0 mmol/L", S['body_sm']),
]
story.append(ColorBox(formula_items, C_LIGHT_BLUE, C_BLUE))
story.append(sp(8))
# ── 5A Acute Symptomatic ──
story.append(SubHeader("A. Acute Symptomatic Hyponatremia — EMERGENCY", C_RED))
story.append(sp(4))
acute_rx = [
Paragraph("<b>⚠ Medical Emergency — risk of cerebral edema >>> risk of ODS</b>", S['warn']),
Paragraph("<b>Treatment:</b>", S['bold']),
Paragraph("1. <b>3% NaCl (hypertonic saline)</b>", S['body']),
Paragraph(" • Standard: 1–2 mL/kg IV over 60 min, OR 100 mL IV bolus over 10 min (repeat up to 3×)", S['body_sm']),
Paragraph(" • Severe symptoms (seizures, coma): 4–6 mL/kg/hr", S['body_sm']),
Paragraph("2. <b>Target:</b> Raise Na⁺ by 4–6 mmol/L in first 6h (enough to reverse cerebral edema; full correction not needed)", S['body']),
Paragraph("3. Add <b>furosemide</b> (loop diuretic) to enhance free water excretion", S['body']),
Paragraph("4. Monitor serum electrolytes every <b>2 hours</b>", S['body']),
Paragraph("5. Monitor neurological and pulmonary status continuously", S['body']),
]
story.append(ColorBox(acute_rx, C_RED_LIGHT, C_RED))
story.append(sp(8))
# ── 5B Chronic Symptomatic ──
story.append(SubHeader("B. Chronic Symptomatic Hyponatremia (>48h duration)", C_ORANGE))
story.append(sp(4))
chronic_rx = [
Paragraph("<b>Correction must be cautious</b> — ODS risk when brain depleted of osmolytes", S['orange_bold']),
Paragraph("<b>Moderate symptoms (nausea, confusion — no seizures):</b>", S['bold']),
Paragraph("• 3% NaCl at low rate: 0.5–1 mL/kg/hr", S['body']),
Paragraph("• Raise Na⁺ 1–2 mmol/L per hour until symptoms improve", S['body']),
Paragraph("• STOP/slow once Na⁺ rises by 8–10 mmol/L or reaches 125–130 mmol/L (whichever first)", S['body']),
Paragraph("<b>If Overcorrection Occurs — Rescue Protocol:</b>", S['bold']),
Paragraph("1. STOP all hypertonic saline immediately", S['body']),
Paragraph("2. Give DDAVP 2–4 mcg IV (clamps further correction by restoring AVP effect)", S['body']),
Paragraph("3. Give D5W to re-lower Na⁺ back to safe level", S['body']),
Paragraph("4. Target: re-lower to 8–10 mmol/L below the overcorrected value", S['body']),
]
story.append(ColorBox(chronic_rx, C_ORANGE_LT, C_ORANGE))
story.append(sp(8))
# ── 5C-E Management by type ──
story.append(SubHeader("C–E. Management by Volume Status", C_BLUE))
story.append(sp(4))
mgmt_data = [
["TYPE", "FIRST-LINE", "ADDITIONAL OPTIONS"],
["Hypovolemic",
"0.9% NaCl (isotonic saline)\nCorrects volume → AVP falls → water diuresis\n⚠ Monitor closely — rapid overcorrection possible as AVP drops",
"Fludrocortisone/hydrocortisone if adrenal insufficiency\nStop diuretics"],
["Hypervolemic\n(CHF, cirrhosis, nephrotic)",
"Treat underlying disease\nFluid restriction (1–1.5 L/day)\nLoop diuretics (furosemide)",
"Vaptans (tolvaptan oral, conivaptan IV)\n• Block V2 receptor → aquaresis\n• Start in hospital — overcorrection risk\n⚠ Tolvaptan CONTRAINDICATED in cirrhosis (hepatotoxicity)"],
["Euvolemic — SIAD",
"Step 1: Remove/treat underlying cause\nStep 2: Fluid restriction <800–1000 mL/day\n(fails if urine Osm >500 or >2× serum Osm)",
"Salt tablets + furosemide (long-term)\nOral urea 15–60g/day (European guideline favourite; cheap)\nDemeclocycline (rarely used now; nephrotoxic)\nTolvaptan (short-term hospital use; expensive)"],
["Hypothyroid",
"Thyroid hormone replacement\nNa⁺ corrects spontaneously",
"Avoid aggressive Na⁺ correction\n(allow thyroid hormone to work first)"],
["Adrenal insufficiency",
"Primary: Hydrocortisone + Fludrocortisone + NS\nSecondary: Hydrocortisone alone",
"Na⁺ rapidly improves\nMonitor for overcorrection as AVP rapidly normalizes"],
]
story.append(make_table(mgmt_data, [3.5*cm, 6.5*cm, 7*cm], hdr_bg=C_BLUE))
story.append(sp(8))
# Vaptans box
vaptan_items = [
Paragraph("<b>Vasopressin V2 Receptor Antagonists (Vaptans):</b>", S['blue_bold']),
Paragraph("• Tolvaptan (oral) | Conivaptan (IV, only for euvolemic/hypervolemic)", S['body']),
Paragraph("• Mechanism: Block AVP at V2 receptor → selective aquaresis (free water loss without electrolyte loss)", S['body']),
Paragraph("• Indications: Hypervolemic and euvolemic hyponatremia refractory to fluid restriction", S['body']),
Paragraph("• CONTRAINDICATED: Hypovolemic hyponatremia | Anuric patients | Liver disease (tolvaptan hepatotoxicity)", S['warn']),
Paragraph("• Initiate ONLY in hospital; do not restrict fluids during vaptan therapy; risk of rapid overcorrection", S['body']),
]
story.append(ColorBox(vaptan_items, C_LIGHT_BLUE, C_BLUE))
story.append(sp(8))
# ── SECTION 6: QUICK REFERENCE SUMMARY ───────────────────────────────────────
def section_summary(story, S):
story.append(SectionHeader("6. QUICK REFERENCE SUMMARY TABLE", C_NAVY, icon="📊"))
story.append(sp(6))
sum_data = [
["Feature", "Hypovolemic", "Euvolemic", "Hypervolemic"],
["Total body water", "↓", "↑", "↑↑"],
["Total body Na⁺", "↓↓", "Normal", "↑"],
["Urine Na⁺", "<20 (extra-renal)\n>20 (renal)", ">20", "<10 (CHF/cirrhosis)\n>20 (AKI/CKD)"],
["Urine osmolality", "High", "High", "Variable"],
["Typical causes", "GI losses, burns,\nthiazides, Addison's,\nsalt-losing nephropathy",
"SIAD, hypothyroid,\nsecondary adrenal insuff,\nbeer potomania",
"CHF, cirrhosis,\nnephrotic syndrome,\nAKI/CKD"],
["Treatment", "0.9% NaCl + correct cause", "Fluid restriction;\ntolvaptan/urea if refractory",
"Fluid restriction;\nloop diuretics;\nvaptans; treat cause"],
["Key investigations", "Urine Na/Cl; cortisol;\nserum K; ACTH test",
"TSH; cortisol; urine Osm;\nCXR/CT chest (SIAD search)",
"Echo; LFTs; albumin;\nproBNP; creatinine"],
]
story.append(make_table(sum_data, [3.3*cm, 4.6*cm, 4.6*cm, 4.5*cm], hdr_bg=C_NAVY))
story.append(sp(8))
# Key facts box
kf_items = [
Paragraph("<b>KEY FACTS — High-Yield Points:</b>", S['bold']),
Paragraph("• Hyponatremia is the most common electrolyte abnormality — up to 22% hospitalized patients (Harrison's 22e)", S['body']),
Paragraph("• Classify ALWAYS by volume status first — this determines cause AND treatment", S['body']),
Paragraph("• First step in workup: measure serum osmolality (exclude pseudo/translocational)", S['body']),
Paragraph("• Urine Na⁺ <20 → extrarenal or Na⁺-avid state | >20 → renal/SIAD/adrenal", S['body']),
Paragraph("• Urine Cl⁻ (NOT Na⁺) in vomiting with alkalosis — more reliable", S['body']),
Paragraph("• SIAD: urine Osm > plasma Osm + euvolemia + urine Na⁺ >20 + exclude hypothyroid/adrenal insuff", S['body']),
Paragraph("• Serum uric acid: LOW in SIAD, normal/high in CSW — useful differentiator", S['body']),
Paragraph("• Correction limit: max 10 mmol/L/24h | ODS risk group: max 8 mmol/L/24h", S['body']),
Paragraph("• Acute (<48h) symptomatic: 3% NaCl bolus immediately — cerebral edema risk dominates", S['body']),
Paragraph("• Overcorrection rescue: DDAVP + D5W to re-lower Na⁺", S['body']),
Paragraph("• Beer potomania: low solute → insufficient osmoles for free water excretion; treat with dietary solute", S['body']),
]
story.append(ColorBox(kf_items, C_YELLOW_LT, C_YELLOW))
story.append(sp(8))
# Sources
story.append(SubHeader("References & Sources", C_GREY))
story.append(sp(4))
ref_data = [
["Source", "Coverage"],
["Harrison's Principles of Internal Medicine, 22nd Ed. (2025)\nCh. 56 — Sodium & Water Disorders", "Definition, pathophysiology, SIAD criteria, AVP patterns, acute hyponatremia causes, clinical features, ODS, correction approach"],
["Comprehensive Clinical Nephrology, 7th Ed.\nCh. 9 — Hyponatremia", "Etiology/classification, diluting mechanism, cerebral adaptation, treatment algorithm, acute/chronic management, vaptans, urea"],
["Bradley & Daroff's Neurology in Clinical Practice\nCh. 53 — Fluid & Electrolytes", "SIAD vs CSW comparison table, neurological hyponatremia in ICU"],
["Schneider AR et al. J Gen Intern Med. 2026 Jun\nPMID: 41652262", "Systematic review: sodium overcorrection in chronic hyponatremia → worse outcomes; validates strict correction limits"],
["Assadi F. Clin Endocrinol. 2026 Jan\nPMID: 41058069", "Systematic review: FEUA, urinary phosphate, BNP for distinguishing CSW from SIAD in neurological illness"],
["European Clinical Practice Guideline — Hyponatremia\nSpasovski et al., Eur J Endocrinol (2014)", "Standard thresholds for correction rate; vaptan indications; fluid restriction criteria; urea recommendations"],
]
story.append(make_table(ref_data, [6*cm, 11*cm], hdr_bg=C_GREY))
story.append(sp(8))
# ── MAIN ──────────────────────────────────────────────────────────────────────
def build():
out_path = "/home/daytona/workspace/hyponatremia-notes/Hyponatremia_Medical_Notes.pdf"
doc = SimpleDocTemplate(
out_path,
pagesize=A4,
topMargin=1.4*cm,
bottomMargin=1.2*cm,
leftMargin=1.75*cm,
rightMargin=1.75*cm,
title="Hyponatremia — Clinical Study Notes",
author="Orris AI",
subject="Medical Notes — Hyponatremia",
)
S = styles()
story = []
cover_page(story, S)
section_patho(story, S)
story.append(sp(4))
section_causes(story, S)
story.append(PageBreak())
section_clinical(story, S)
story.append(sp(4))
section_diagnosis(story, S)
story.append(PageBreak())
section_management(story, S)
story.append(sp(4))
section_summary(story, S)
doc.build(story, onFirstPage=make_header_footer, onLaterPages=make_header_footer)
print(f"PDF generated: {out_path}")
return out_path
if __name__ == "__main__":
build()
cd /home/daytona/workspace/hyponatremia-notes && python3 build_pdf.py 2>&1
ls -lh /home/daytona/workspace/hyponatremia-notes/Hyponatremia_Medical_Notes.pdf
Hyponatremia Medical Notes
PDF Document · PDF
| Section | Content |
|---|---|
| Cover Page | Title card with source badges (Harrison's / Nephrology / UpToDate / PubMed), quick summary box |
| 1. Pathophysiology | Severity classification table, AVP mechanism, brain adaptation acute vs chronic table, quote from Harrison's |
| 2. Classification & Causes | 3-group overview (hypovolemic/euvolemic/hypervolemic), detailed cause tables, SIAD diagnostic criteria box, SIAD causes by category, Addison's callout, pseudohyponatremia table |
| 3. Clinical Features | Symptom severity table, acute vs chronic side-by-side comparison, ODS/CPM detail box, acute hyponatremia causes table (Harrison's) |
| 4. Diagnostic Approach | Step-by-step algorithm boxes (serum Osm → volume status → urine studies → investigations), SIAD vs CSW comparison table with highlighted key differentiators |
| 5. Management | Correction rate limits box (with 2026 meta-analysis note), Adrogué-Madias formula, acute emergency protocol, chronic symptomatic + overcorrection rescue, management-by-type table, vaptan guidelines |
| 6. Summary + References | Quick reference master table, 11 high-yield key facts, full reference list |