Hypotension during dialysis what should be the management
intradialytic hypotension management hemodialysis
| Factor | Mechanism |
|---|---|
| Excessive ultrafiltration (UF) | Intravascular volume depletion exceeding refilling capacity |
| High interdialytic weight gain (IDWG) | Forces rapid fluid removal |
| Impaired autonomic/vasoactive responses | Diabetic or uremic autonomic dysfunction |
| Osmolar shifts | Rapid solute removal reduces plasma osmolality |
| Antihypertensive drugs | Reduce arteriolar tone before/during dialysis |
| Reduced cardiac reserve | Heart failure, ischemia, pericardial effusion |
| Eating during dialysis | Splanchnic vasodilatation shunts blood to gut |
| High UF rate | >13 mL/kg/h strongly associated with IDH and mortality |
Early IDH (first half of session) is particularly ominous - often triggered independent of volume changes, associated with worse outcomes. Late IDH is typically due to high UF rates from large IDWGs. - Comprehensive Clinical Nephrology, 7th Ed.
- Harrison's Principles of Internal Medicine, 22E (2025)
- Comprehensive Clinical Nephrology, 7th Ed.
| Intervention | Details |
|---|---|
| Assess dry weight accurately | Reassess regularly; overestimated dry weight leads to excessive UF |
| Restrict dietary sodium | Target ~5-6 g salt/day (100 mmol Na/day) to reduce interdialytic weight gain |
| Avoid antihypertensives before dialysis | Especially those reducing arteriolar tone; prefer longer-acting agents taken after dialysis on treatment days |
| No food during dialysis | Eating causes splanchnic vasodilatation - high-risk diabetics should eat after dialysis |
| Correct anemia | Improves cardiac output and hemodynamic tolerance |
| Treat heart failure and arrhythmias | Optimise cardiac reserve |
| Counsel on IDWG limitation | Education on fluid and sodium restriction |
| Intervention | Details |
|---|---|
| Cool dialysate | Reduce dialysate temperature by 0.5-1°C below body temperature (stay above 35°C); increases vascular resistance and cardiac contractility via sympathetic activation; may reduce myocardial stunning and brain ischemia |
| Extend treatment time or increase frequency | More time = lower required UF rate; 6× vs 3× weekly dialysis improves BP control and hemodynamics |
| Bicarbonate dialysate | Use bicarbonate buffer instead of acetate - improves hemodynamic stability |
| Volumetric UF control | UF profiling - remove more fluid early in session when plasma refilling is greatest |
| Sequential dialysis (isolated UF then HD) | Separation of UF from diffusion may improve tolerability, though evidence is limited |
| Lower dialysate sodium | Match dialysate sodium to patient's own serum sodium to avoid positive sodium balance and IDWG; avoid sodium modeling/profiling routinely as it is associated with increased all-cause mortality in one study |
| UF rate ≤13 mL/kg/h | Higher UF rates independently increase mortality risk |
- Comprehensive Clinical Nephrology, 7th Ed., p. 1298-1299
- Brenner and Rector's The Kidney, Box 63.3
- Comprehensive Clinical Nephrology, 7th Ed.
- Brenner and Rector's The Kidney
IDH occurs during session
|
↓
1. Trendelenburg position
2. Stop/reduce ultrafiltration
3. IV 0.9% saline bolus 100-250 mL
4. Repeat saline bolus if needed
|
↓
If chest pain/dyspnea → ECG + Troponin (rule out ACS)
|
↓
If recurrent IDH → Echocardiography (pericardial effusion, LV dysfunction)
|
↓
Prevention:
- Assess dry weight, reduce IDWG
- Cool dialysate
- Extend/increase dialysis sessions
- Hold antihypertensives pre-dialysis
- No food during dialysis
- If persistent → Midodrine 2.5-10 mg pre-dialysis
Create a quick reference guide (PDF) on IDH management for dialysis units
ls -la /home/daytona/workspace/ 2>/dev/null || echo "workspace does not exist"
mkdir -p /home/daytona/workspace/idh-guide && python3 -c "import reportlab; prin…
~/idh-guide/generate_idh_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm, cm
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
)
from reportlab.platypus.flowables import Flowable
from reportlab.lib.colors import HexColor
OUTPUT = "/home/daytona/workspace/idh-guide/IDH_Quick_Reference_Guide.pdf"
# ── Colour palette ────────────────────────────────────────────────────────────
NAVY = HexColor("#1B3A5C")
TEAL = HexColor("#1A7F8E")
RED_ALERT = HexColor("#C0392B")
AMBER = HexColor("#E67E22")
GREEN_DARK = HexColor("#1E8449")
LIGHT_BLUE = HexColor("#D6EAF8")
LIGHT_TEAL = HexColor("#D1F2EB")
LIGHT_AMBER= HexColor("#FDEBD0")
LIGHT_RED = HexColor("#FADBD8")
LIGHT_GREY = HexColor("#F2F3F4")
MID_GREY = HexColor("#BDC3C7")
WHITE = colors.white
BLACK = colors.black
PAGE_W, PAGE_H = A4
MARGIN = 18 * mm
# ── Document ──────────────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
leftMargin=MARGIN, rightMargin=MARGIN,
topMargin=15*mm, bottomMargin=15*mm,
title="IDH Quick Reference Guide",
author="Dialysis Unit Protocol",
)
# ── Styles ────────────────────────────────────────────────────────────────────
base = getSampleStyleSheet()
def S(name, **kw):
return ParagraphStyle(name, **kw)
TITLE_STYLE = S("Title",
fontName="Helvetica-Bold", fontSize=20, textColor=WHITE,
alignment=TA_CENTER, spaceAfter=2)
SUBTITLE_STYLE = S("Subtitle",
fontName="Helvetica", fontSize=10, textColor=HexColor("#D6EAF8"),
alignment=TA_CENTER, spaceAfter=0)
SECTION_HDR = S("SecHdr",
fontName="Helvetica-Bold", fontSize=11, textColor=WHITE,
alignment=TA_LEFT, spaceAfter=0, spaceBefore=0,
leftIndent=4, leading=14)
BODY = S("Body",
fontName="Helvetica", fontSize=8.5, textColor=BLACK,
leading=13, spaceAfter=2)
BODY_BOLD = S("BodyBold",
fontName="Helvetica-Bold", fontSize=8.5, textColor=BLACK,
leading=13, spaceAfter=2)
SMALL = S("Small",
fontName="Helvetica", fontSize=7.5, textColor=HexColor("#555555"),
leading=11, spaceAfter=1)
ALERT = S("Alert",
fontName="Helvetica-Bold", fontSize=9, textColor=RED_ALERT,
leading=12)
BULLET = S("Bullet",
fontName="Helvetica", fontSize=8.5, textColor=BLACK,
leading=13, leftIndent=10, bulletIndent=2, spaceAfter=1)
NOTE = S("Note",
fontName="Helvetica-Oblique", fontSize=7.5, textColor=HexColor("#2C3E50"),
leading=11)
# ── Helper: coloured section header ──────────────────────────────────────────
def section_header(text, bg=NAVY, width=None):
w = width or (PAGE_W - 2*MARGIN)
data = [[Paragraph(text, SECTION_HDR)]]
t = Table(data, colWidths=[w])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
return t
def hline(color=MID_GREY, thickness=0.5):
return HRFlowable(width="100%", thickness=thickness, color=color, spaceAfter=4, spaceBefore=4)
def sp(h=4):
return Spacer(1, h)
def bp(text, bold_part=""):
if bold_part:
return Paragraph(f"<bullet>•</bullet> <b>{bold_part}</b> {text}", BULLET)
return Paragraph(f"<bullet>•</bullet> {text}", BULLET)
# ── TITLE BANNER ──────────────────────────────────────────────────────────────
def title_banner():
data = [[
Paragraph("INTRADIALYTIC HYPOTENSION (IDH)", TITLE_STYLE),
Paragraph("Quick Reference Guide for Dialysis Units", SUBTITLE_STYLE),
]]
# Stack vertically in one cell
inner = [
[Paragraph("INTRADIALYTIC HYPOTENSION (IDH)", TITLE_STYLE)],
[Paragraph("Quick Reference Guide | Hemodialysis Unit Protocol", SUBTITLE_STYLE)],
]
t = Table(inner, colWidths=[PAGE_W - 2*MARGIN])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), NAVY),
("TOPPADDING", (0,0), (-1,-1), 10),
("BOTTOMPADDING", (0,0), (-1,-1), 10),
("LEFTPADDING", (0,0), (-1,-1), 12),
("RIGHTPADDING", (0,0), (-1,-1), 12),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("ROUNDEDCORNERS",(0,0), (-1,-1), [6,6,6,6]), # not supported but harmless
]))
return t
# ── DEFINITION BOX ────────────────────────────────────────────────────────────
def definition_box():
def_style = S("Def", fontName="Helvetica", fontSize=8.5, textColor=NAVY,
leading=13, alignment=TA_CENTER)
def_bold = S("DefB", fontName="Helvetica-Bold", fontSize=9, textColor=NAVY,
leading=14, alignment=TA_CENTER)
data = [
[Paragraph("DEFINITION", S("DH", fontName="Helvetica-Bold", fontSize=9,
textColor=TEAL, alignment=TA_CENTER))],
[Paragraph(
"Systolic BP fall <b>≥20 mmHg</b> during dialysis, "
"<i>OR</i> BP drop to <b><90 mmHg</b> with symptoms",
S("DB2", fontName="Helvetica", fontSize=9, textColor=NAVY,
leading=14, alignment=TA_CENTER))],
[Paragraph(
"Incidence: <b>15 - 50%</b> of HD sessions | Independent risk factor for mortality",
SMALL)],
]
t = Table(data, colWidths=[PAGE_W - 2*MARGIN])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), LIGHT_BLUE),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("LINEBELOW", (0,0), (0,0), 0.5, TEAL),
]))
return t
# ── TWO-COLUMN LAYOUT HELPER ──────────────────────────────────────────────────
def two_col(left_items, right_items, col_ratio=(1,1), bg_left=LIGHT_GREY, bg_right=LIGHT_GREY):
total_w = PAGE_W - 2*MARGIN - 4 # 4mm gutter
lw = total_w * col_ratio[0] / sum(col_ratio)
rw = total_w * col_ratio[1] / sum(col_ratio)
data = [[left_items, right_items]]
t = Table(data, colWidths=[lw, rw], hAlign="LEFT")
t.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 0),
("BOTTOMPADDING", (0,0), (-1,-1), 0),
("LEFTPADDING", (0,0), (-1,-1), 0),
("RIGHTPADDING", (0,0), (-1,-1), 4),
]))
return t
# ── RISK FACTORS TABLE ────────────────────────────────────────────────────────
def risk_factors_table():
header_style = S("RH", fontName="Helvetica-Bold", fontSize=8,
textColor=WHITE, alignment=TA_CENTER)
cell_style = S("RC", fontName="Helvetica", fontSize=8,
textColor=BLACK, leading=11)
data = [
[Paragraph("RISK FACTOR / CAUSE", header_style),
Paragraph("MECHANISM", header_style)],
["Excessive ultrafiltration rate (>13 mL/kg/h)",
"UF rate exceeds intravascular refilling"],
["High interdialytic weight gain (IDWG)",
"Requires rapid, large-volume fluid removal"],
["Diabetic / uremic autonomic dysfunction",
"Impaired vasopressor response"],
["Antihypertensives taken pre-dialysis",
"Reduced arteriolar tone during session"],
["Food / eating during dialysis",
"Splanchnic vasodilatation shunts blood to gut"],
["Reduced cardiac reserve (HF, ischemia)",
"Inability to augment cardiac output"],
["Pericardial effusion / pericarditis",
"Tamponade physiology; impaired filling"],
["Anaemia",
"Reduced oxygen delivery; poor compensation"],
["Osmolar shifts (rapid solute removal)",
"Reduced plasma osmolality; volume redistribution"],
]
col_w = (PAGE_W - 2*MARGIN) / 2
t = Table(data, colWidths=[col_w, col_w])
style = TableStyle([
("BACKGROUND", (0,0), (1,0), NAVY),
("TEXTCOLOR", (0,0), (1,0), WHITE),
("FONTNAME", (0,0), (1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, LIGHT_GREY]),
("GRID", (0,0), (-1,-1), 0.4, MID_GREY),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("ALIGN", (0,0), (1,0), "CENTER"),
])
t.setStyle(style)
return t
# ── IMMEDIATE MANAGEMENT STEPS ────────────────────────────────────────────────
def immediate_mgmt_table():
step_hdr = S("StH", fontName="Helvetica-Bold", fontSize=9,
textColor=WHITE, alignment=TA_CENTER)
step_num = S("SN", fontName="Helvetica-Bold", fontSize=14,
textColor=WHITE, alignment=TA_CENTER, leading=18)
step_act = S("SA", fontName="Helvetica-Bold", fontSize=9,
textColor=NAVY, leading=13)
step_det = S("SD", fontName="Helvetica", fontSize=8,
textColor=HexColor("#333333"), leading=12)
steps = [
("1", RED_ALERT, "TRENDELENBURG POSITION",
"Lay patient supine, elevate legs immediately to improve venous return"),
("2", HexColor("#A93226"), "STOP / REDUCE ULTRAFILTRATION",
"This is the primary intervention. Cease or reduce UF to zero"),
("3", AMBER, "IV ISOTONIC SALINE BOLUS",
"0.9% NaCl 100-250 mL IV bolus. Repeat as needed until BP stabilises"),
("4", HexColor("#1A5276"), "REASSESS & MONITOR",
"Re-check BP every 5 min; assess for chest pain, dyspnoea, arrhythmia"),
("5", GREEN_DARK, "ECG + TROPONIN if chest pain / dyspnoea",
"Rule out ACS. Consider echo if recurrent unexplained IDH (pericardial effusion?)"),
]
rows = []
for num, col, action, detail in steps:
rows.append([
Paragraph(num, step_num),
[Paragraph(action, step_act), Paragraph(detail, step_det)]
])
t = Table(rows, colWidths=[18*mm, PAGE_W - 2*MARGIN - 18*mm - 4])
bg_colors = [s[1] for s in steps]
ts = TableStyle([
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("GRID", (0,0), (-1,-1), 0.3, MID_GREY),
])
for i, (_, col, _, _) in enumerate(steps):
ts.add("BACKGROUND", (0, i), (0, i), col)
t.setStyle(ts)
return t
# ── DO NOT box ────────────────────────────────────────────────────────────────
def do_not_box():
warn = S("Warn", fontName="Helvetica-Bold", fontSize=8.5,
textColor=RED_ALERT, leading=13)
data = [
[Paragraph("DO NOT reduce blood flow rate to manage IDH", warn)],
[Paragraph("Reducing Qb does NOT improve haemodynamics and will compromise solute clearance (Kt/V). "
"Saline bolus is as effective as albumin and far more practical.", SMALL)],
]
t = Table(data, colWidths=[PAGE_W - 2*MARGIN])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), LIGHT_RED),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("LINEAFTER", (0,0), (0,-1), 4, RED_ALERT),
]))
return t
# ── PREVENTION TABLE ──────────────────────────────────────────────────────────
def prevention_table():
cat_style = S("Cat", fontName="Helvetica-Bold", fontSize=8,
textColor=TEAL, leading=12)
act_style = S("PA", fontName="Helvetica-Bold", fontSize=8,
textColor=BLACK, leading=12)
det_style = S("PD", fontName="Helvetica", fontSize=7.5,
textColor=HexColor("#333333"), leading=11)
hdr_style = S("PH", fontName="Helvetica-Bold", fontSize=8,
textColor=WHITE, alignment=TA_CENTER)
rows = [
[Paragraph("CATEGORY", hdr_style),
Paragraph("INTERVENTION", hdr_style),
Paragraph("DETAIL / TARGET", hdr_style)],
# Patient measures
[Paragraph("Patient\nMeasures", cat_style),
Paragraph("Accurate dry weight assessment", act_style),
Paragraph("Reassess regularly; overestimation drives excess UF", det_style)],
["", Paragraph("Dietary sodium restriction", act_style),
Paragraph("Target ~5-6 g salt/day (100 mmol Na/day); reduces IDWG", det_style)],
["", Paragraph("Restrict interdialytic fluid intake", act_style),
Paragraph("Counsel patients on sodium-fluid relationship; IDWG <2.5 kg target", det_style)],
["", Paragraph("Hold antihypertensives before dialysis", act_style),
Paragraph("Especially vasodilators; prefer long-acting agents taken after dialysis", det_style)],
["", Paragraph("No food during dialysis", act_style),
Paragraph("Eating causes splanchnic vasodilatation; eat after session", det_style)],
["", Paragraph("Correct anaemia", act_style),
Paragraph("Target Hb 10-12 g/dL; improves haemodynamic tolerance", det_style)],
["", Paragraph("Treat cardiac disease", act_style),
Paragraph("Optimise HF, arrhythmias; echo if recurrent unexplained IDH", det_style)],
# Dialysis prescription
[Paragraph("Dialysis\nPrescription", cat_style),
Paragraph("Cool dialysate temperature", act_style),
Paragraph("Reduce 0.5-1 degC below body temp (stay >35 degC); increases SVR via sympathetic activation", det_style)],
["", Paragraph("Limit UF rate", act_style),
Paragraph("Target <13 mL/kg/h; higher rates independently increase mortality risk", det_style)],
["", Paragraph("UF profiling / modelling", act_style),
Paragraph("Remove more fluid early in session when refilling is maximal", det_style)],
["", Paragraph("Extend treatment time or increase frequency", act_style),
Paragraph("More time = lower UF rate; 3x to 5-6x/week reduces IDH significantly", det_style)],
["", Paragraph("Bicarbonate dialysate", act_style),
Paragraph("Avoid acetate buffer; bicarbonate improves haemodynamic stability", det_style)],
["", Paragraph("Sequential dialysis (isolated UF then HD)", act_style),
Paragraph("Separate filtration from diffusion; limited evidence but reasonable option", det_style)],
["", Paragraph("Match dialysate sodium to serum sodium", act_style),
Paragraph("Avoid positive Na balance; avoid routine sodium profiling (associated with mortality risk)", det_style)],
# Pharmacological
[Paragraph("Pharmacological\n(if above fail)", cat_style),
Paragraph("Midodrine", act_style),
Paragraph("2.5-10 mg PO, 15-30 min pre-dialysis. Alpha-1 agonist. Second dose mid-session if needed (partial HD removal). SE: supine HTN, urinary retention", det_style)],
]
col_w = [(PAGE_W - 2*MARGIN) * r for r in [0.15, 0.30, 0.55]]
t = Table(rows, colWidths=col_w, repeatRows=1)
style = TableStyle([
("BACKGROUND", (0,0), (2,0), TEAL),
("TEXTCOLOR", (0,0), (2,0), WHITE),
("FONTNAME", (0,0), (2,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("GRID", (0,0), (-1,-1), 0.4, MID_GREY),
("ALIGN", (0,0), (2,0), "CENTER"),
# Patient measures rows 1-7
("BACKGROUND", (0,1), (2,7), WHITE),
("BACKGROUND", (0,2), (2,2), LIGHT_GREY),
("BACKGROUND", (0,4), (2,4), LIGHT_GREY),
("BACKGROUND", (0,6), (2,6), LIGHT_GREY),
# Dialysis prescription rows 8-14
("BACKGROUND", (0,8), (2,14), WHITE),
("BACKGROUND", (0,9), (2,9), LIGHT_TEAL),
("BACKGROUND", (0,11), (2,11), LIGHT_TEAL),
("BACKGROUND", (0,13), (2,13), LIGHT_TEAL),
# Pharmacological row 15
("BACKGROUND", (0,15), (2,15), LIGHT_AMBER),
# Span first column for grouped rows
("SPAN", (0,1), (0,7)),
("SPAN", (0,8), (0,14)),
("SPAN", (0,15), (0,15)),
("VALIGN", (0,1), (0,15), "MIDDLE"),
("ALIGN", (0,1), (0,15), "CENTER"),
])
t.setStyle(style)
return t
# ── SPECIAL SITUATIONS BOX ────────────────────────────────────────────────────
def special_situations():
head = S("SSH", fontName="Helvetica-Bold", fontSize=8.5,
textColor=AMBER, leading=13)
body_s = S("SSB", fontName="Helvetica", fontSize=8,
textColor=BLACK, leading=12)
rows = [
[Paragraph("EARLY IDH (first half of session)", head),
Paragraph("RECURRENT / UNEXPLAINED IDH", head),
Paragraph("IDH IN DIABETIC / AUTONOMIC FAILURE", head)],
[Paragraph("Often cardiac in origin (stunned myocardium), not just volume. "
"Particularly ominous - associated with worse outcomes. "
"Obtain ECG and troponin. Consider echo.", body_s),
Paragraph("Rule out: pericardial effusion, LV dysfunction, access high-output failure. "
"Echocardiography is warranted. Review dry weight and IDWG. "
"Consider adding midodrine.", body_s),
Paragraph("Autonomic neuropathy impairs vasopressor response. "
"Cool dialysate strongly recommended. Midodrine particularly useful. "
"Avoid food before and during dialysis. Frequent sessions preferred.", body_s)],
]
t = Table(rows, colWidths=[(PAGE_W - 2*MARGIN)/3]*3)
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), HexColor("#1C2833")),
("BACKGROUND", (0,1), (-1,-1), LIGHT_AMBER),
("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"),
("GRID", (0,0), (-1,-1), 0.5, MID_GREY),
]))
return t
# ── MIDODRINE DETAIL BOX ──────────────────────────────────────────────────────
def midodrine_box():
title_s = S("MT", fontName="Helvetica-Bold", fontSize=9,
textColor=NAVY, leading=14)
body_s = S("MB", fontName="Helvetica", fontSize=8,
textColor=BLACK, leading=12)
data = [
[Paragraph("MIDODRINE - Pharmacological Prevention", title_s)],
[Paragraph(
"<b>Dose:</b> 2.5-10 mg orally, 15-30 minutes before dialysis "
"| <b>Mechanism:</b> Selective oral alpha-1 adrenergic agonist "
"| <b>Peak level:</b> ~60 minutes<br/>"
"<b>Important:</b> Midodrine is partially removed by HD - a second, smaller dose may be required mid-session.<br/>"
"<b>Side effects:</b> Supine hypertension, urinary retention, pilomotor reactions, GI complaints<br/>"
"<b>Indication:</b> Resistant IDH despite all non-pharmacological strategies; autonomic insufficiency",
body_s)],
]
t = Table(data, colWidths=[PAGE_W - 2*MARGIN])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), LIGHT_BLUE),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("LINEAFTER", (0,0), (0,-1), 4, NAVY),
("LINEBELOW", (0,0), (0,0), 0.5, NAVY),
]))
return t
# ── FOOTER ────────────────────────────────────────────────────────────────────
def footer_table():
footer_s = S("Foot", fontName="Helvetica-Oblique", fontSize=6.5,
textColor=HexColor("#7F8C8D"), alignment=TA_CENTER, leading=10)
data = [[Paragraph(
"Sources: Harrison's Principles of Internal Medicine 22E (2025, McGraw-Hill); "
"Comprehensive Clinical Nephrology 7th Ed (Elsevier); Brenner & Rector's The Kidney (Elsevier) | "
"For clinical decisions, always refer to current institutional protocols and patient clinical context.",
footer_s)]]
t = Table(data, colWidths=[PAGE_W - 2*MARGIN])
t.setStyle(TableStyle([
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 2),
("LINEABOVE", (0,0), (0,0), 0.5, MID_GREY),
]))
return t
# ── BUILD STORY ───────────────────────────────────────────────────────────────
story = []
# Title banner
story.append(title_banner())
story.append(sp(6))
# Definition
story.append(definition_box())
story.append(sp(8))
# Risk factors
story.append(KeepTogether([
section_header(" CAUSES & RISK FACTORS", bg=NAVY),
sp(4),
risk_factors_table(),
sp(6),
]))
# Immediate management
story.append(KeepTogether([
section_header(" IMMEDIATE MANAGEMENT - STEP BY STEP", bg=RED_ALERT),
sp(4),
immediate_mgmt_table(),
sp(4),
do_not_box(),
sp(8),
]))
# Special situations
story.append(KeepTogether([
section_header(" SPECIAL CLINICAL SITUATIONS", bg=HexColor("#1C2833")),
sp(4),
special_situations(),
sp(8),
]))
# Prevention
story.append(section_header(" PREVENTION STRATEGIES", bg=TEAL))
story.append(sp(4))
story.append(prevention_table())
story.append(sp(6))
# Midodrine box
story.append(midodrine_box())
story.append(sp(6))
# Footer
story.append(footer_table())
# ── BUILD ─────────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF created: {OUTPUT}")
cd /home/daytona/workspace/idh-guide && python3 generate_idh_pdf.py 2>&1
ls -lh /home/daytona/workspace/idh-guide/IDH_Quick_Reference_Guide.pdf
cd /home/daytona/workspace/idh-guide && python3 -c " from pypdf import PdfReader…
~/idh-guide/generate_idh_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_CENTER
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether
)
from reportlab.lib.colors import HexColor
OUTPUT = "/home/daytona/workspace/idh-guide/IDH_Quick_Reference_Guide.pdf"
# ── Colour palette ────────────────────────────────────────────────────────────
NAVY = HexColor("#1B3A5C")
TEAL = HexColor("#1A7F8E")
RED_ALERT = HexColor("#C0392B")
AMBER = HexColor("#E67E22")
GREEN_DARK = HexColor("#1E8449")
DARK_BG = HexColor("#1C2833")
LIGHT_BLUE = HexColor("#D6EAF8")
LIGHT_TEAL = HexColor("#D1F2EB")
LIGHT_AMBER = HexColor("#FDEBD0")
LIGHT_RED = HexColor("#FADBD8")
LIGHT_GREY = HexColor("#F2F3F4")
MID_GREY = HexColor("#BDC3C7")
WHITE = colors.white
BLACK = colors.black
PAGE_W, PAGE_H = A4
MARGIN = 18 * mm
CONTENT_W = PAGE_W - 2 * MARGIN
# ── Style factory ─────────────────────────────────────────────────────────────
def S(name, **kw):
return ParagraphStyle(name, **kw)
# ── Reusable styles ───────────────────────────────────────────────────────────
TITLE1 = S("T1", fontName="Helvetica-Bold", fontSize=20, textColor=WHITE, alignment=TA_CENTER, leading=24)
TITLE2 = S("T2", fontName="Helvetica", fontSize=10, textColor=HexColor("#AED6F1"), alignment=TA_CENTER, leading=14)
HDR_W = S("HW", fontName="Helvetica-Bold", fontSize=9, textColor=WHITE, alignment=TA_CENTER, leading=13)
HDR_T = S("HT", fontName="Helvetica-Bold", fontSize=9, textColor=TEAL, leading=13)
BODY = S("Bo", fontName="Helvetica", fontSize=8.5,textColor=BLACK, leading=13)
BODY_B = S("BB", fontName="Helvetica-Bold", fontSize=8.5,textColor=BLACK, leading=13)
BODY_S = S("BS", fontName="Helvetica", fontSize=8, textColor=BLACK, leading=12)
BODY_SB = S("SB", fontName="Helvetica-Bold", fontSize=8, textColor=BLACK, leading=12)
SMALL = S("Sm", fontName="Helvetica", fontSize=7.5,textColor=HexColor("#555555"), leading=11)
NOTE = S("No", fontName="Helvetica-Oblique",fontSize=7.5,textColor=HexColor("#2C3E50"),leading=11, alignment=TA_CENTER)
FOOT = S("Ft", fontName="Helvetica-Oblique",fontSize=6.5,textColor=HexColor("#7F8C8D"), alignment=TA_CENTER, leading=10)
CAT_S = S("CS", fontName="Helvetica-Bold", fontSize=8, textColor=WHITE, alignment=TA_CENTER, leading=12)
STEP_N = S("SN", fontName="Helvetica-Bold", fontSize=15, textColor=WHITE, alignment=TA_CENTER, leading=20)
STEP_A = S("SA", fontName="Helvetica-Bold", fontSize=9, textColor=NAVY, leading=13)
STEP_D = S("SD", fontName="Helvetica", fontSize=8, textColor=HexColor("#333333"), leading=12)
WARN = S("Wn", fontName="Helvetica-Bold", fontSize=9, textColor=RED_ALERT, leading=13)
AMBER_S = S("AS", fontName="Helvetica-Bold", fontSize=8.5,textColor=AMBER, leading=13)
def sp(h=5):
return Spacer(1, h)
# ── Section header ────────────────────────────────────────────────────────────
def sec_hdr(text, bg=NAVY):
p = Paragraph(f"<b>{text}</b>", S("SH", fontName="Helvetica-Bold", fontSize=10,
textColor=WHITE, leading=14, leftIndent=6))
t = Table([[p]], colWidths=[CONTENT_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
]))
return t
# ── Title banner ──────────────────────────────────────────────────────────────
def title_banner():
rows = [
[Paragraph("INTRADIALYTIC HYPOTENSION (IDH)", TITLE1)],
[Paragraph("Quick Reference Guide | Hemodialysis Unit Protocol", TITLE2)],
]
t = Table(rows, colWidths=[CONTENT_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), NAVY),
("TOPPADDING", (0,0), (0,0), 12),
("BOTTOMPADDING", (0,1), (0,1), 12),
("TOPPADDING", (0,1), (0,1), 2),
("BOTTOMPADDING", (0,0), (0,0), 2),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("ALIGN", (0,0), (-1,-1), "CENTER"),
]))
return t
# ── Definition row ────────────────────────────────────────────────────────────
def definition_box():
lw, rw = CONTENT_W * 0.5, CONTENT_W * 0.5
def_left = [
Paragraph("DEFINITION", S("DL", fontName="Helvetica-Bold", fontSize=8.5,
textColor=TEAL, leading=12)),
Paragraph("Systolic BP fall <b>≥20 mmHg</b> during dialysis,<br/>"
"<i>OR</i> SBP drops to <b><90 mmHg</b> with symptoms", BODY),
]
def_right = [
Paragraph("INCIDENCE", S("DL2", fontName="Helvetica-Bold", fontSize=8.5,
textColor=TEAL, leading=12)),
Paragraph("<b>15 - 50%</b> of HD sessions<br/>"
"Independent risk factor for <b>mortality</b>", BODY),
]
def_left_tbl = Table([[item] for item in def_left], colWidths=[lw - 8])
def_right_tbl = Table([[item] for item in def_right], colWidths=[rw - 8])
for tbl in [def_left_tbl, def_right_tbl]:
tbl.setStyle(TableStyle([
("TOPPADDING", (0,0), (-1,-1), 2),
("BOTTOMPADDING", (0,0), (-1,-1), 2),
("LEFTPADDING", (0,0), (-1,-1), 0),
("RIGHTPADDING", (0,0), (-1,-1), 0),
]))
outer = Table([[def_left_tbl, def_right_tbl]], colWidths=[lw, rw])
outer.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), LIGHT_BLUE),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("LINEAFTER", (0,0), (0,-1), 0.5, MID_GREY),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
return outer
# ── Risk factors table ────────────────────────────────────────────────────────
def risk_table():
cw = CONTENT_W / 2
data = [
[Paragraph("RISK FACTOR / CAUSE", HDR_W), Paragraph("MECHANISM", HDR_W)],
[Paragraph("Excessive UF rate (<b>>13 mL/kg/h</b>)", BODY_S),
Paragraph("UF rate exceeds intravascular refilling capacity", BODY_S)],
[Paragraph("High interdialytic weight gain (IDWG)", BODY_S),
Paragraph("Requires rapid, large-volume fluid removal", BODY_S)],
[Paragraph("Diabetic / uremic autonomic dysfunction", BODY_S),
Paragraph("Impaired vasopressor and sympathetic response", BODY_S)],
[Paragraph("Antihypertensives taken pre-dialysis", BODY_S),
Paragraph("Reduced arteriolar tone during session", BODY_S)],
[Paragraph("Food / eating during dialysis", BODY_S),
Paragraph("Splanchnic vasodilatation shunts blood to gut", BODY_S)],
[Paragraph("Reduced cardiac reserve (HF, ischaemia)", BODY_S),
Paragraph("Inability to augment cardiac output", BODY_S)],
[Paragraph("Pericardial effusion / pericarditis", BODY_S),
Paragraph("Impaired cardiac filling; tamponade physiology", BODY_S)],
[Paragraph("Anaemia", BODY_S),
Paragraph("Reduced O2 delivery; poor haemodynamic compensation", BODY_S)],
[Paragraph("Rapid osmolar shifts", BODY_S),
Paragraph("Reduced plasma osmolality; volume redistribution", BODY_S)],
]
t = Table(data, colWidths=[cw, cw])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, LIGHT_GREY]),
("GRID", (0,0), (-1,-1), 0.4, MID_GREY),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
return t
# ── Immediate management steps ────────────────────────────────────────────────
def immediate_mgmt():
steps = [
("1", RED_ALERT, "TRENDELENBURG POSITION",
"Lay patient flat, elevate legs - improves venous return immediately"),
("2", HexColor("#A93226"), "STOP / REDUCE ULTRAFILTRATION",
"Primary intervention. Reduce UF to zero. Restart only once BP stabilises"),
("3", AMBER, "IV 0.9% ISOTONIC SALINE BOLUS",
"Give 100-250 mL IV bolus. Repeat as needed. Albumin offers no proven advantage over saline"),
("4", HexColor("#1A5276"), "REASSESS & MONITOR",
"Re-check BP every 5 min; note symptoms (chest pain, dyspnoea, arrhythmia)"),
("5", GREEN_DARK, "IF CHEST PAIN / DYSPNOEA -> ECG + TROPONIN",
"Rule out ACS. If recurrent unexplained IDH: echocardiogram (pericardial effusion, LV dysfunction)"),
]
nw = 16 * mm
aw = CONTENT_W - nw
rows = []
for num, col, action, detail in steps:
rows.append([
Paragraph(num, STEP_N),
[Paragraph(action, STEP_A), Paragraph(detail, STEP_D)],
])
t = Table(rows, colWidths=[nw, aw])
ts = TableStyle([
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (1,0), (1,-1), 8),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("GRID", (0,0), (-1,-1), 0.3, MID_GREY),
])
for i, (_, col, _, _) in enumerate(steps):
ts.add("BACKGROUND", (0, i), (0, i), col)
ts.add("BACKGROUND", (1, i), (1, i), LIGHT_GREY if i % 2 == 0 else WHITE)
t.setStyle(ts)
return t
# ── Do NOT box ────────────────────────────────────────────────────────────────
def do_not_box():
data = [
[Paragraph("⚠ DO NOT reduce blood flow rate (Qb) to manage IDH", WARN)],
[Paragraph("Reducing Qb does <b>not</b> improve haemodynamics and will compromise solute clearance (Kt/V). "
"Saline bolus is as effective as albumin and far more practical in outpatient settings.", SMALL)],
]
t = Table(data, colWidths=[CONTENT_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), LIGHT_RED),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("LINEAFTER", (0,0), (0,-1), 5, RED_ALERT),
]))
return t
# ── Special situations ────────────────────────────────────────────────────────
def special_situations():
cw = CONTENT_W / 3
data = [
[Paragraph("EARLY IDH", HDR_W),
Paragraph("RECURRENT / UNEXPLAINED IDH", HDR_W),
Paragraph("IDH IN DIABETES / AUTONOMIC FAILURE", HDR_W)],
[Paragraph("Often cardiac origin (myocardial stunning), not just volume depletion. "
"Associated with worst outcomes. ECG + troponin. Consider echo.", BODY_S),
Paragraph("Rule out pericardial effusion, LV dysfunction, high-output access failure. "
"Echocardiogram warranted. Review dry weight and IDWG. Add midodrine.", BODY_S),
Paragraph("Autonomic neuropathy impairs vasopressor response. Cool dialysate strongly recommended. "
"Midodrine particularly useful. No food during dialysis. Frequent sessions preferred.", BODY_S)],
]
t = Table(data, colWidths=[cw, cw, cw])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BG),
("BACKGROUND", (0,1), (-1,-1), LIGHT_AMBER),
("FONTSIZE", (0,0), (-1,-1), 8),
("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"),
("GRID", (0,0), (-1,-1), 0.4, MID_GREY),
]))
return t
# ── Prevention table ──────────────────────────────────────────────────────────
def prevention_table():
cw = [CONTENT_W * r for r in [0.13, 0.30, 0.57]]
def row(cat, action, detail, cat_bg=None):
return [
Paragraph(cat, CAT_S) if cat else Paragraph("", CAT_S),
Paragraph(action, BODY_SB),
Paragraph(detail, BODY_S),
]
data = [
# Header
[Paragraph("CATEGORY", HDR_W), Paragraph("INTERVENTION", HDR_W), Paragraph("DETAILS / TARGET", HDR_W)],
# Patient measures
[Paragraph("PATIENT\nMEASURES", CAT_S),
Paragraph("Accurate dry weight", BODY_SB),
Paragraph("Reassess regularly; overestimation drives excess UF", BODY_S)],
["", Paragraph("Dietary sodium restriction", BODY_SB),
Paragraph("Target ~5-6 g salt/day (100 mmol Na/day) to minimise IDWG", BODY_S)],
["", Paragraph("Restrict fluid intake", BODY_SB),
Paragraph("Patient education; target IDWG <2.5 kg between sessions", BODY_S)],
["", Paragraph("Hold antihypertensives pre-dialysis", BODY_SB),
Paragraph("Especially vasodilators; give after dialysis on treatment days", BODY_S)],
["", Paragraph("No food during dialysis", BODY_SB),
Paragraph("Eating causes splanchnic vasodilatation; schedule meals after session", BODY_S)],
["", Paragraph("Correct anaemia", BODY_SB),
Paragraph("Target Hb 10-12 g/dL; improves haemodynamic tolerance", BODY_S)],
["", Paragraph("Treat cardiac disease", BODY_SB),
Paragraph("Optimise HF and arrhythmias; echo if recurrent unexplained IDH", BODY_S)],
# Dialysis prescription
[Paragraph("DIALYSIS\nPRESCRIPTION", CAT_S),
Paragraph("Cool dialysate temperature", BODY_SB),
Paragraph("Reduce 0.5-1 degC below body temp (stay >35 degC); activates sympathetic nervous system, increases SVR and cardiac contractility", BODY_S)],
["", Paragraph("Limit UF rate to <13 mL/kg/h", BODY_SB),
Paragraph("Higher UF rates independently associated with increased mortality", BODY_S)],
["", Paragraph("UF profiling / modelling", BODY_SB),
Paragraph("Remove more fluid early in session when plasma refilling is maximal", BODY_S)],
["", Paragraph("Extend time or increase dialysis frequency", BODY_SB),
Paragraph("More time = lower required UF rate; 5-6x/week dialysis markedly reduces IDH", BODY_S)],
["", Paragraph("Bicarbonate dialysate", BODY_SB),
Paragraph("Avoid acetate buffer; bicarbonate improves haemodynamic stability", BODY_S)],
["", Paragraph("Sequential dialysis (isolated UF then HD)", BODY_SB),
Paragraph("Separate fluid removal from diffusion; limited but reasonable evidence", BODY_S)],
["", Paragraph("Match dialysate Na to serum Na", BODY_SB),
Paragraph("Avoids positive Na balance; do NOT use routine sodium profiling (linked to increased mortality)", BODY_S)],
# Pharmacological
[Paragraph("PHARMA-\nCOLOGICAL", CAT_S),
Paragraph("Midodrine 2.5-10 mg PO pre-dialysis", BODY_SB),
Paragraph("Oral alpha-1 agonist; give 15-30 min before session. Peak at 60 min. "
"Second smaller dose mid-session may be needed (partial HD removal). "
"SE: supine HTN, urinary retention, pilomotor reactions. "
"Use when non-pharmacological strategies are insufficient.", BODY_S)],
]
t = Table(data, colWidths=cw, repeatRows=1)
ts = TableStyle([
# Header
("BACKGROUND", (0,0), (-1,0), TEAL),
("ALIGN", (0,0), (-1,0), "CENTER"),
("FONTSIZE", (0,0), (-1,-1), 8),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("GRID", (0,0), (-1,-1), 0.4, MID_GREY),
# Patient measures section
("BACKGROUND", (0,1), (0,7), HexColor("#1E8449")),
("BACKGROUND", (1,1), (-1,7), WHITE),
("ROWBACKGROUNDS",(1,2), (-1,7), [LIGHT_GREY, WHITE]),
# Dialysis section
("BACKGROUND", (0,8), (0,14), TEAL),
("BACKGROUND", (1,8), (-1,14), WHITE),
("ROWBACKGROUNDS",(1,8), (-1,14), [LIGHT_TEAL, WHITE]),
# Pharmacological section
("BACKGROUND", (0,15), (0,15), HexColor("#7D3C98")),
("BACKGROUND", (1,15), (-1,15), LIGHT_AMBER),
# Span category cells
("SPAN", (0,1), (0,7)),
("SPAN", (0,8), (0,14)),
("SPAN", (0,15), (0,15)),
("VALIGN", (0,1), (0,15), "MIDDLE"),
("ALIGN", (0,1), (0,15), "CENTER"),
("TEXTCOLOR", (0,1), (0,15), WHITE),
])
t.setStyle(ts)
return t
# ── Midodrine highlight box ───────────────────────────────────────────────────
def midodrine_box():
title_s = S("MB_T", fontName="Helvetica-Bold", fontSize=9, textColor=NAVY, leading=14)
detail_s = S("MB_D", fontName="Helvetica", fontSize=8, textColor=BLACK, leading=12)
data = [
[Paragraph("MIDODRINE - Key Prescribing Points", title_s)],
[Paragraph(
"<b>Dose:</b> 2.5-10 mg orally, 15-30 min before dialysis "
" | <b>Class:</b> Selective oral alpha-1 adrenergic agonist "
" | <b>Peak:</b> ~60 min<br/>"
"<b>Note:</b> Partially removed by HD - second smaller dose may be needed mid-session.<br/>"
"<b>Side effects:</b> Supine hypertension, urinary retention, pilomotor reactions, GI complaints<br/>"
"<b>When to use:</b> Resistant IDH despite non-pharmacological measures; autonomic insufficiency",
detail_s)],
]
t = Table(data, colWidths=[CONTENT_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), LIGHT_BLUE),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("LINEAFTER", (0,0), (0,-1), 5, NAVY),
("LINEBELOW", (0,0), (0,0), 0.5, NAVY),
]))
return t
# ── Footer ────────────────────────────────────────────────────────────────────
def footer():
data = [[Paragraph(
"Sources: Harrison's Principles of Internal Medicine 22E (2025); "
"Comprehensive Clinical Nephrology 7th Ed; Brenner & Rector's The Kidney | "
"For clinical decisions, always apply current institutional protocols and individual patient assessment.",
FOOT)]]
t = Table(data, colWidths=[CONTENT_W])
t.setStyle(TableStyle([
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 2),
("LEFTPADDING", (0,0), (-1,-1), 0),
("RIGHTPADDING", (0,0), (-1,-1), 0),
("LINEABOVE", (0,0), (0,0), 0.5, MID_GREY),
]))
return t
# ── Assemble story ────────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
OUTPUT, pagesize=A4,
leftMargin=MARGIN, rightMargin=MARGIN,
topMargin=14*mm, bottomMargin=14*mm,
title="IDH Quick Reference Guide",
author="Dialysis Unit Protocol",
)
story = []
story.append(title_banner())
story.append(sp(6))
story.append(definition_box())
story.append(sp(8))
story.append(KeepTogether([
sec_hdr(" CAUSES & RISK FACTORS", bg=NAVY),
sp(4),
risk_table(),
sp(8),
]))
story.append(KeepTogether([
sec_hdr(" IMMEDIATE MANAGEMENT - STEP BY STEP", bg=RED_ALERT),
sp(4),
immediate_mgmt(),
sp(4),
do_not_box(),
sp(8),
]))
story.append(KeepTogether([
sec_hdr(" SPECIAL CLINICAL SITUATIONS", bg=DARK_BG),
sp(4),
special_situations(),
sp(8),
]))
story.append(sec_hdr(" PREVENTION STRATEGIES", bg=TEAL))
story.append(sp(4))
story.append(prevention_table())
story.append(sp(6))
story.append(midodrine_box())
story.append(sp(6))
story.append(footer())
doc.build(story)
print(f"PDF saved: {OUTPUT}")
~/idh-guide/generate_idh_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/idh-guide/generate_idh_pdf.py'
rm /home/daytona/workspace/idh-guide/generate_idh_pdf.py && echo "deleted"
~/idh-guide/generate_idh_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_CENTER
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether
)
from reportlab.lib.colors import HexColor
OUTPUT = "/home/daytona/workspace/idh-guide/IDH_Quick_Reference_Guide.pdf"
NAVY = HexColor("#1B3A5C")
TEAL = HexColor("#1A7F8E")
RED_ALERT = HexColor("#C0392B")
AMBER = HexColor("#E67E22")
GREEN_DARK = HexColor("#1E8449")
DARK_BG = HexColor("#1C2833")
LIGHT_BLUE = HexColor("#D6EAF8")
LIGHT_TEAL = HexColor("#D1F2EB")
LIGHT_AMBER = HexColor("#FDEBD0")
LIGHT_RED = HexColor("#FADBD8")
LIGHT_GREY = HexColor("#F2F3F4")
MID_GREY = HexColor("#BDC3C7")
WHITE = colors.white
BLACK = colors.black
PAGE_W, PAGE_H = A4
MARGIN = 18 * mm
CONTENT_W = PAGE_W - 2 * MARGIN
def S(name, **kw):
return ParagraphStyle(name, **kw)
TITLE1 = S("T1", fontName="Helvetica-Bold", fontSize=20, textColor=WHITE, alignment=TA_CENTER, leading=24)
TITLE2 = S("T2", fontName="Helvetica", fontSize=10, textColor=HexColor("#AED6F1"), alignment=TA_CENTER, leading=14)
HDR_W = S("HW", fontName="Helvetica-Bold", fontSize=9, textColor=WHITE, alignment=TA_CENTER, leading=13)
BODY_S = S("BS", fontName="Helvetica", fontSize=8, textColor=BLACK, leading=12)
BODY_SB = S("SB", fontName="Helvetica-Bold", fontSize=8, textColor=BLACK, leading=12)
BODY = S("Bo", fontName="Helvetica", fontSize=8.5,textColor=BLACK, leading=13)
SMALL = S("Sm", fontName="Helvetica", fontSize=7.5,textColor=HexColor("#555555"), leading=11)
FOOT = S("Ft", fontName="Helvetica-Oblique",fontSize=6.5,textColor=HexColor("#7F8C8D"), alignment=TA_CENTER, leading=10)
CAT_S = S("CS", fontName="Helvetica-Bold", fontSize=8, textColor=WHITE, alignment=TA_CENTER, leading=12)
STEP_N = S("SN", fontName="Helvetica-Bold", fontSize=15, textColor=WHITE, alignment=TA_CENTER, leading=20)
STEP_A = S("SA", fontName="Helvetica-Bold", fontSize=9, textColor=NAVY, leading=13)
STEP_D = S("SD", fontName="Helvetica", fontSize=8, textColor=HexColor("#333333"), leading=12)
WARN = S("Wn", fontName="Helvetica-Bold", fontSize=9, textColor=RED_ALERT, leading=13)
def sp(h=5):
return Spacer(1, h)
def sec_hdr(text, bg=NAVY):
p = Paragraph(f"<b>{text}</b>",
S("SH", fontName="Helvetica-Bold", fontSize=10,
textColor=WHITE, leading=14, leftIndent=6))
t = Table([[p]], colWidths=[CONTENT_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
]))
return t
def cell_stack(*paras):
"""Return a Table wrapping multiple Paragraphs stacked vertically in one cell."""
t = Table([[p] for p in paras], colWidths=[CONTENT_W]) # width set later by parent
t.setStyle(TableStyle([
("TOPPADDING", (0,0), (-1,-1), 1),
("BOTTOMPADDING", (0,0), (-1,-1), 1),
("LEFTPADDING", (0,0), (-1,-1), 0),
("RIGHTPADDING", (0,0), (-1,-1), 0),
]))
return t
# ── Title banner ──────────────────────────────────────────────────────────────
def title_banner():
rows = [
[Paragraph("INTRADIALYTIC HYPOTENSION (IDH)", TITLE1)],
[Paragraph("Quick Reference Guide | Hemodialysis Unit Protocol", TITLE2)],
]
t = Table(rows, colWidths=[CONTENT_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), NAVY),
("TOPPADDING", (0,0), (0,0), 12),
("BOTTOMPADDING", (0,1), (0,1), 12),
("TOPPADDING", (0,1), (0,1), 2),
("BOTTOMPADDING", (0,0), (0,0), 2),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("ALIGN", (0,0), (-1,-1), "CENTER"),
]))
return t
# ── Definition box ────────────────────────────────────────────────────────────
def definition_box():
lw = rw = CONTENT_W / 2
def_left = Table([
[Paragraph("DEFINITION", S("DL", fontName="Helvetica-Bold", fontSize=8.5,
textColor=TEAL, leading=12))],
[Paragraph("Systolic BP fall <b>≥20 mmHg</b> during dialysis,<br/>"
"<i>OR</i> SBP drops to <b><90 mmHg</b> with symptoms", BODY)],
], colWidths=[lw - 16])
def_left.setStyle(TableStyle([("TOPPADDING",(0,0),(-1,-1),2),
("BOTTOMPADDING",(0,0),(-1,-1),2),
("LEFTPADDING",(0,0),(-1,-1),0),
("RIGHTPADDING",(0,0),(-1,-1),0)]))
def_right = Table([
[Paragraph("INCIDENCE", S("DL2", fontName="Helvetica-Bold", fontSize=8.5,
textColor=TEAL, leading=12))],
[Paragraph("<b>15 - 50%</b> of HD sessions<br/>"
"Independent risk factor for <b>mortality</b>", BODY)],
], colWidths=[rw - 16])
def_right.setStyle(TableStyle([("TOPPADDING",(0,0),(-1,-1),2),
("BOTTOMPADDING",(0,0),(-1,-1),2),
("LEFTPADDING",(0,0),(-1,-1),0),
("RIGHTPADDING",(0,0),(-1,-1),0)]))
outer = Table([[def_left, def_right]], colWidths=[lw, rw])
outer.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), LIGHT_BLUE),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("LINEAFTER", (0,0), (0,-1), 0.5, MID_GREY),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
return outer
# ── Risk factors ──────────────────────────────────────────────────────────────
def risk_table():
cw = CONTENT_W / 2
data = [
[Paragraph("RISK FACTOR / CAUSE", HDR_W), Paragraph("MECHANISM", HDR_W)],
[Paragraph("Excessive UF rate (<b>>13 mL/kg/h</b>)", BODY_S),
Paragraph("UF rate exceeds intravascular refilling capacity", BODY_S)],
[Paragraph("High interdialytic weight gain (IDWG)", BODY_S),
Paragraph("Requires rapid, large-volume fluid removal", BODY_S)],
[Paragraph("Diabetic / uremic autonomic dysfunction", BODY_S),
Paragraph("Impaired vasopressor and sympathetic response", BODY_S)],
[Paragraph("Antihypertensives taken pre-dialysis", BODY_S),
Paragraph("Reduced arteriolar tone during session", BODY_S)],
[Paragraph("Food / eating during dialysis", BODY_S),
Paragraph("Splanchnic vasodilatation shunts blood to gut", BODY_S)],
[Paragraph("Reduced cardiac reserve (HF, ischaemia)", BODY_S),
Paragraph("Inability to augment cardiac output", BODY_S)],
[Paragraph("Pericardial effusion / pericarditis", BODY_S),
Paragraph("Impaired cardiac filling; tamponade physiology", BODY_S)],
[Paragraph("Anaemia", BODY_S),
Paragraph("Reduced O2 delivery; poor haemodynamic compensation", BODY_S)],
[Paragraph("Rapid osmolar shifts", BODY_S),
Paragraph("Reduced plasma osmolality; volume redistribution", BODY_S)],
]
t = Table(data, colWidths=[cw, cw])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("FONTSIZE", (0,0), (-1,-1), 8),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, LIGHT_GREY]),
("GRID", (0,0), (-1,-1), 0.4, MID_GREY),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
return t
# ── Immediate management ──────────────────────────────────────────────────────
def immediate_mgmt():
steps = [
("1", RED_ALERT, "TRENDELENBURG POSITION",
"Lay patient flat, elevate legs - improves venous return immediately"),
("2", HexColor("#A93226"), "STOP / REDUCE ULTRAFILTRATION",
"Primary intervention. Reduce UF to zero. Restart only once BP stabilises"),
("3", AMBER, "IV 0.9% ISOTONIC SALINE BOLUS",
"100-250 mL IV bolus. Repeat as needed. Albumin offers no proven advantage over saline"),
("4", HexColor("#1A5276"), "REASSESS & MONITOR",
"Re-check BP every 5 min; note chest pain, dyspnoea, arrhythmia"),
("5", GREEN_DARK, "IF CHEST PAIN / DYSPNOEA -> ECG + TROPONIN",
"Rule out ACS. Recurrent unexplained IDH: arrange echocardiogram (pericardial effusion, LV dysfunction)"),
]
nw = 16 * mm
aw = CONTENT_W - nw
rows = []
for num, col, action, detail in steps:
action_cell = Table(
[[Paragraph(action, STEP_A)],
[Paragraph(detail, STEP_D)]],
colWidths=[aw - 10]
)
action_cell.setStyle(TableStyle([
("TOPPADDING", (0,0), (-1,-1), 1),
("BOTTOMPADDING", (0,0), (-1,-1), 1),
("LEFTPADDING", (0,0), (-1,-1), 0),
("RIGHTPADDING", (0,0), (-1,-1), 0),
]))
rows.append([Paragraph(num, STEP_N), action_cell])
t = Table(rows, colWidths=[nw, aw])
ts = TableStyle([
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (1,0), (1,-1), 8),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("GRID", (0,0), (-1,-1), 0.3, MID_GREY),
])
row_bgs = [LIGHT_GREY, WHITE, LIGHT_GREY, WHITE, LIGHT_GREY]
for i, ((_, col, _, _), row_bg) in enumerate(zip(steps, row_bgs)):
ts.add("BACKGROUND", (0, i), (0, i), col)
ts.add("BACKGROUND", (1, i), (1, i), row_bg)
t.setStyle(ts)
return t
def do_not_box():
data = [
[Paragraph("DO NOT reduce blood flow rate (Qb) to manage IDH", WARN)],
[Paragraph("Reducing Qb does <b>not</b> improve haemodynamics and will compromise solute clearance (Kt/V). "
"Saline bolus is as effective as albumin and far more practical in outpatient settings.", SMALL)],
]
t = Table(data, colWidths=[CONTENT_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), LIGHT_RED),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("LINEAFTER", (0,0), (0,-1), 5, RED_ALERT),
]))
return t
# ── Special situations ────────────────────────────────────────────────────────
def special_situations():
cw = CONTENT_W / 3
data = [
[Paragraph("EARLY IDH", HDR_W),
Paragraph("RECURRENT / UNEXPLAINED IDH", HDR_W),
Paragraph("IDH IN DIABETES / AUTONOMIC FAILURE", HDR_W)],
[Paragraph("Often cardiac origin (myocardial stunning), not just volume depletion. "
"Associated with worst outcomes. ECG + troponin. Consider echo.", BODY_S),
Paragraph("Rule out pericardial effusion, LV dysfunction, high-output access failure. "
"Echocardiogram warranted. Review dry weight and IDWG. Add midodrine.", BODY_S),
Paragraph("Autonomic neuropathy impairs vasopressor response. Cool dialysate strongly recommended. "
"Midodrine particularly useful. No food during dialysis. Frequent sessions preferred.", BODY_S)],
]
t = Table(data, colWidths=[cw, cw, cw])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BG),
("BACKGROUND", (0,1), (-1,-1), LIGHT_AMBER),
("FONTSIZE", (0,0), (-1,-1), 8),
("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"),
("GRID", (0,0), (-1,-1), 0.4, MID_GREY),
]))
return t
# ── Prevention table ──────────────────────────────────────────────────────────
def prevention_table():
cw = [CONTENT_W * r for r in [0.13, 0.30, 0.57]]
data = [
[Paragraph("CATEGORY", HDR_W), Paragraph("INTERVENTION", HDR_W), Paragraph("DETAILS / TARGET", HDR_W)],
# Patient measures
[Paragraph("PATIENT\nMEASURES", CAT_S),
Paragraph("Accurate dry weight", BODY_SB),
Paragraph("Reassess regularly; overestimation drives excess UF", BODY_S)],
["",
Paragraph("Dietary sodium restriction", BODY_SB),
Paragraph("Target ~5-6 g salt/day (100 mmol Na/day) to minimise IDWG", BODY_S)],
["",
Paragraph("Restrict fluid intake", BODY_SB),
Paragraph("Patient education; target IDWG <2.5 kg between sessions", BODY_S)],
["",
Paragraph("Hold antihypertensives pre-dialysis", BODY_SB),
Paragraph("Especially vasodilators; give after dialysis on treatment days", BODY_S)],
["",
Paragraph("No food during dialysis", BODY_SB),
Paragraph("Eating causes splanchnic vasodilatation; schedule meals after session", BODY_S)],
["",
Paragraph("Correct anaemia", BODY_SB),
Paragraph("Target Hb 10-12 g/dL; improves haemodynamic tolerance", BODY_S)],
["",
Paragraph("Treat cardiac disease", BODY_SB),
Paragraph("Optimise HF and arrhythmias; echo if recurrent unexplained IDH", BODY_S)],
# Dialysis prescription
[Paragraph("DIALYSIS\nPRESCRIPTION", CAT_S),
Paragraph("Cool dialysate temperature", BODY_SB),
Paragraph("Reduce 0.5-1 degC below body temp (stay >35 degC); activates sympathetic NS, increases SVR and cardiac contractility", BODY_S)],
["",
Paragraph("Limit UF rate to <13 mL/kg/h", BODY_SB),
Paragraph("Higher UF rates independently associated with increased mortality", BODY_S)],
["",
Paragraph("UF profiling / modelling", BODY_SB),
Paragraph("Remove more fluid early in session when plasma refilling is maximal", BODY_S)],
["",
Paragraph("Extend time or increase dialysis frequency", BODY_SB),
Paragraph("More time = lower required UF rate; 5-6x/week dialysis markedly reduces IDH", BODY_S)],
["",
Paragraph("Bicarbonate dialysate", BODY_SB),
Paragraph("Avoid acetate buffer; bicarbonate improves haemodynamic stability", BODY_S)],
["",
Paragraph("Sequential dialysis (isolated UF then HD)", BODY_SB),
Paragraph("Separate fluid removal from diffusion; limited but reasonable evidence", BODY_S)],
["",
Paragraph("Match dialysate Na to serum Na", BODY_SB),
Paragraph("Avoids positive Na balance; do NOT use routine sodium profiling (linked to increased mortality)", BODY_S)],
# Pharmacological
[Paragraph("PHARMA-\nCOLOGICAL", CAT_S),
Paragraph("Midodrine 2.5-10 mg PO pre-dialysis", BODY_SB),
Paragraph("Oral alpha-1 agonist; give 15-30 min before session. Peak at 60 min. "
"Second smaller dose mid-session may be needed (partial HD removal). "
"SE: supine HTN, urinary retention, pilomotor reactions. "
"Use when non-pharmacological strategies are insufficient.", BODY_S)],
]
t = Table(data, colWidths=cw, repeatRows=1)
ts = TableStyle([
("BACKGROUND", (0,0), (-1,0), TEAL),
("ALIGN", (0,0), (-1,0), "CENTER"),
("FONTSIZE", (0,0), (-1,-1), 8),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("GRID", (0,0), (-1,-1), 0.4, MID_GREY),
# Category cell backgrounds
("BACKGROUND", (0,1), (0,7), HexColor("#1E8449")),
("BACKGROUND", (0,8), (0,14), TEAL),
("BACKGROUND", (0,15),(0,15), HexColor("#7D3C98")),
# Data row backgrounds
("ROWBACKGROUNDS",(1,1), (-1,7), [WHITE, LIGHT_GREY]),
("ROWBACKGROUNDS",(1,8), (-1,14), [LIGHT_TEAL, WHITE]),
("BACKGROUND", (1,15),(-1,15), LIGHT_AMBER),
# Span category cells
("SPAN", (0,1), (0,7)),
("SPAN", (0,8), (0,14)),
("SPAN", (0,15),(0,15)),
("VALIGN", (0,1), (0,15), "MIDDLE"),
("ALIGN", (0,1), (0,15), "CENTER"),
("TEXTCOLOR", (0,1), (0,15), WHITE),
])
t.setStyle(ts)
return t
# ── Midodrine box ─────────────────────────────────────────────────────────────
def midodrine_box():
title_s = S("MBT", fontName="Helvetica-Bold", fontSize=9, textColor=NAVY, leading=14)
detail_s = S("MBD", fontName="Helvetica", fontSize=8, textColor=BLACK, leading=12)
data = [
[Paragraph("MIDODRINE - Key Prescribing Points", title_s)],
[Paragraph(
"<b>Dose:</b> 2.5-10 mg orally, 15-30 min before dialysis "
" | <b>Class:</b> Selective oral alpha-1 adrenergic agonist "
" | <b>Peak:</b> ~60 min<br/>"
"<b>Note:</b> Partially removed by HD - second smaller dose may be needed mid-session.<br/>"
"<b>Side effects:</b> Supine hypertension, urinary retention, pilomotor reactions, GI complaints<br/>"
"<b>When to use:</b> Resistant IDH despite non-pharmacological measures; autonomic insufficiency",
detail_s)],
]
t = Table(data, colWidths=[CONTENT_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), LIGHT_BLUE),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("LINEAFTER", (0,0), (0,-1), 5, NAVY),
("LINEBELOW", (0,0), (0,0), 0.5, NAVY),
]))
return t
# ── Footer ────────────────────────────────────────────────────────────────────
def footer():
data = [[Paragraph(
"Sources: Harrison's Principles of Internal Medicine 22E (2025); "
"Comprehensive Clinical Nephrology 7th Ed; Brenner & Rector's The Kidney | "
"For clinical decisions, always apply current institutional protocols and individual patient assessment.",
FOOT)]]
t = Table(data, colWidths=[CONTENT_W])
t.setStyle(TableStyle([
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 2),
("LEFTPADDING", (0,0), (-1,-1), 0),
("RIGHTPADDING", (0,0), (-1,-1), 0),
("LINEABOVE", (0,0), (0,0), 0.5, MID_GREY),
]))
return t
# ── Build ─────────────────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
OUTPUT, pagesize=A4,
leftMargin=MARGIN, rightMargin=MARGIN,
topMargin=14*mm, bottomMargin=14*mm,
title="IDH Quick Reference Guide",
author="Dialysis Unit Protocol",
)
story = []
story.append(title_banner())
story.append(sp(6))
story.append(definition_box())
story.append(sp(8))
story.append(KeepTogether([
sec_hdr(" CAUSES & RISK FACTORS", bg=NAVY),
sp(4),
risk_table(),
sp(8),
]))
story.append(KeepTogether([
sec_hdr(" IMMEDIATE MANAGEMENT - STEP BY STEP", bg=RED_ALERT),
sp(4),
immediate_mgmt(),
sp(4),
do_not_box(),
sp(8),
]))
story.append(KeepTogether([
sec_hdr(" SPECIAL CLINICAL SITUATIONS", bg=DARK_BG),
sp(4),
special_situations(),
sp(8),
]))
story.append(sec_hdr(" PREVENTION STRATEGIES", bg=TEAL))
story.append(sp(4))
story.append(prevention_table())
story.append(sp(6))
story.append(midodrine_box())
story.append(sp(6))
story.append(footer())
doc.build(story)
print(f"PDF saved: {OUTPUT}")
cd /home/daytona/workspace/idh-guide && python3 generate_idh_pdf.py 2>&1
python3 -c " from pypdf import PdfReader r = PdfReader('/home/daytona/workspace/…
IDH Quick Reference Guide
PDF Document · PDF
| Section | Content |
|---|---|
| Title Banner | Dark navy header with guide title and unit protocol label |
| Definition Box | BP criteria + incidence data side by side |
| Causes & Risk Factors | 9-row two-column table covering all major IDH triggers |
| Immediate Management | 5 colour-coded numbered steps (red -> amber -> blue -> green) with a red "DO NOT" warning box |
| Special Clinical Situations | 3-column panel: Early IDH / Recurrent IDH / Diabetic-autonomic IDH |
| Prevention Strategies | Detailed 3-section table (Patient Measures / Dialysis Prescription / Pharmacological) with colour-coded category bands |
| Midodrine Highlight Box | Dose, timing, mechanism, side effects, indication - all at a glance |
| Footer | Source citations (Harrison's, Comprehensive Clinical Nephrology, Brenner & Rector) |