Who pain scale management ladder
WHO pain management analgesic ladder steps 2024

| Step | Pain Level | Drugs Used |
|---|---|---|
| Step 1 | Mild pain | Non-opioids - paracetamol (acetaminophen), NSAIDs (e.g. ibuprofen, diclofenac) ± adjuvants |
| Step 2 | Mild to moderate pain (or Step 1 failed) | Weak opioids - codeine, tramadol ± non-opioid ± adjuvants |
| Step 3 | Moderate to severe pain (or Step 2 failed) | Strong opioids - morphine, oxycodone, fentanyl, hydromorphone ± non-opioid ± adjuvants |
Create a clinical reference card on the WHO pain ladder
ls /home/daytona/workspace/ 2>/dev/null && mkdir -p /home/daytona/workspace/who-…
~/who-pain-ladder/create_card.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm, cm
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import KeepTogether
from reportlab.graphics.shapes import Drawing, Rect, Polygon, String, Line, Arrow
from reportlab.graphics import renderPDF
from reportlab.platypus import Flowable
import reportlab.lib.colors as rcolors
# ── Colour palette ──────────────────────────────────────────────────────────
DARK_BLUE = colors.HexColor("#1A3A5C")
MID_BLUE = colors.HexColor("#2E6DA4")
LIGHT_BLUE = colors.HexColor("#D6E8F7")
STEP1_COL = colors.HexColor("#27AE60") # green – mild
STEP2_COL = colors.HexColor("#F39C12") # amber – moderate
STEP3_COL = colors.HexColor("#E74C3C") # red – severe
STEP4_COL = colors.HexColor("#8E44AD") # purple – interventional
ADJ_COL = colors.HexColor("#2980B9") # blue – adjuvants
HEADER_BG = DARK_BLUE
CARD_BG = colors.HexColor("#F4F8FC")
WHITE = colors.white
GREY_TEXT = colors.HexColor("#4A4A4A")
LIGHT_GREY = colors.HexColor("#ECF0F1")
# ── Page setup ───────────────────────────────────────────────────────────────
OUTPUT = "/home/daytona/workspace/who-pain-ladder/WHO_Pain_Ladder_Reference_Card.pdf"
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
leftMargin=15*mm, rightMargin=15*mm,
topMargin=12*mm, bottomMargin=12*mm,
)
W = A4[0] - 30*mm # usable width
# ── Styles ───────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
def style(name, **kw):
s = ParagraphStyle(name, **kw)
return s
S_TITLE = style("title",
fontName="Helvetica-Bold", fontSize=20, textColor=WHITE,
alignment=TA_CENTER, spaceAfter=2)
S_SUBTITLE = style("subtitle",
fontName="Helvetica", fontSize=10, textColor=colors.HexColor("#AED6F1"),
alignment=TA_CENTER, spaceAfter=0)
S_SECTION = style("section",
fontName="Helvetica-Bold", fontSize=9, textColor=WHITE,
alignment=TA_CENTER)
S_BODY = style("body",
fontName="Helvetica", fontSize=8.2, textColor=GREY_TEXT,
leading=12, spaceAfter=2)
S_BOLD = style("bold",
fontName="Helvetica-Bold", fontSize=8.2, textColor=GREY_TEXT, leading=12)
S_SMALL = style("small",
fontName="Helvetica", fontSize=7.5, textColor=GREY_TEXT, leading=11)
S_SMALL_BOLD = style("small_bold",
fontName="Helvetica-Bold", fontSize=7.5, textColor=GREY_TEXT, leading=11)
S_STEP_HEAD = style("step_head",
fontName="Helvetica-Bold", fontSize=10, textColor=WHITE,
alignment=TA_CENTER, spaceAfter=1)
S_STEP_SUB = style("step_sub",
fontName="Helvetica", fontSize=7.8, textColor=WHITE,
alignment=TA_CENTER)
S_DRUG = style("drug",
fontName="Helvetica", fontSize=8, textColor=GREY_TEXT,
leading=12)
S_DRUG_BOLD = style("drug_bold",
fontName="Helvetica-Bold", fontSize=8, textColor=DARK_BLUE,
leading=12)
S_PRINC_HEAD = style("princ_head",
fontName="Helvetica-Bold", fontSize=8.5, textColor=MID_BLUE)
S_PRINC = style("princ",
fontName="Helvetica", fontSize=8, textColor=GREY_TEXT, leading=11.5)
S_WARN = style("warn",
fontName="Helvetica-Bold", fontSize=7.8, textColor=colors.HexColor("#C0392B"),
leading=11)
S_NOTE = style("note",
fontName="Helvetica-Oblique", fontSize=7.5, textColor=colors.HexColor("#7F8C8D"),
alignment=TA_CENTER)
S_FOOT = style("foot",
fontName="Helvetica", fontSize=7, textColor=colors.HexColor("#95A5A6"),
alignment=TA_CENTER)
# ── Helper: coloured cell paragraph ─────────────────────────────────────────
def cp(text, sty, color=None):
if color:
sty = ParagraphStyle(sty.name+"_c", parent=sty, textColor=color)
return Paragraph(text, sty)
def bullet(text, sty=S_DRUG, indent=8):
s = ParagraphStyle(sty.name+"_b", parent=sty, leftIndent=indent, firstLineIndent=-6)
return Paragraph(f"<bullet>\u2022</bullet> {text}", s)
# ─────────────────────────────────────────────────────────────────────────────
# BUILD CONTENT
# ─────────────────────────────────────────────────────────────────────────────
story = []
# ── 1. HEADER BANNER ─────────────────────────────────────────────────────────
header_data = [[
Paragraph("WHO Analgesic Ladder", S_TITLE),
]]
header_sub_data = [[
Paragraph("Clinical Quick-Reference Card | Pain Management", S_SUBTITLE),
]]
header_tbl = Table([[
Paragraph("WHO Analgesic Ladder", S_TITLE),
],[
Paragraph("Clinical Quick-Reference Card | Pain Management", S_SUBTITLE),
]], colWidths=[W])
# Actually build as a single-column table for clean look
header_content = [
[Paragraph("WHO Analgesic Ladder", S_TITLE)],
[Paragraph("Clinical Quick-Reference Card \u2022 Pain Management", S_SUBTITLE)],
]
h_tbl = Table(header_content, colWidths=[W])
h_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), HEADER_BG),
("TOPPADDING", (0,0), (-1,-1), 10),
("BOTTOMPADDING",(0,-1),(-1,-1), 10),
("TOPPADDING", (0,1), (-1,1), 1),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("ROUNDEDCORNERS", [5]),
]))
story.append(h_tbl)
story.append(Spacer(1, 5*mm))
# ── 2. THREE CORE PRINCIPLES strip ───────────────────────────────────────────
princ_items = [
("By Mouth", "Oral route preferred over\ntransdermal / IV / SC"),
("By the Clock", "Fixed regular intervals\n(not PRN) to prevent pain"),
("By the Ladder", "Escalate stepwise based\non pain severity"),
]
princ_cells = []
for title, desc in princ_items:
cell = [
Paragraph(title, ParagraphStyle("ph", fontName="Helvetica-Bold", fontSize=8.5,
textColor=WHITE, alignment=TA_CENTER, spaceAfter=2)),
Paragraph(desc, ParagraphStyle("pd", fontName="Helvetica", fontSize=7.5,
textColor=colors.HexColor("#D6EAF8"), alignment=TA_CENTER, leading=11)),
]
princ_cells.append(cell)
# Two extra principles
princ_cells2 = []
for title, desc in [
("For the Individual", "Titrate dose to each\npatient's needs"),
("With Attention", "Monitor side effects\n& breakthrough pain"),
]:
cell = [
Paragraph(title, ParagraphStyle("ph2", fontName="Helvetica-Bold", fontSize=8.5,
textColor=WHITE, alignment=TA_CENTER, spaceAfter=2)),
Paragraph(desc, ParagraphStyle("pd2", fontName="Helvetica", fontSize=7.5,
textColor=colors.HexColor("#D6EAF8"), alignment=TA_CENTER, leading=11)),
]
princ_cells2.append(cell)
cw3 = W / 3
cw5 = W / 5
all_princ = princ_cells + princ_cells2
p_tbl = Table([all_princ], colWidths=[cw5]*5)
p_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), MID_BLUE),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING",(0,0), (-1,-1), 7),
("LEFTPADDING", (0,0), (-1,-1), 4),
("RIGHTPADDING", (0,0), (-1,-1), 4),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("LINEAFTER", (0,0), (3,0), 0.5, colors.HexColor("#5D9FCC")),
("ROUNDEDCORNERS", [4]),
]))
story.append(p_tbl)
story.append(Spacer(1, 5*mm))
# ── 3. ANALGESIC STEPS (4 columns) ───────────────────────────────────────────
step_configs = [
{
"num": "Step 1",
"pain": "MILD PAIN",
"pain_score": "(NRS 1-3)",
"color": STEP1_COL,
"light": colors.HexColor("#EAFAF1"),
"class": "Non-Opioids",
"drugs": [
("<b>Paracetamol</b>", "500mg-1g PO q4-6h\n(max 4g/24h)"),
("<b>Ibuprofen</b>", "400mg PO q6-8h\nwith food"),
("<b>Diclofenac</b>", "50mg PO q8h"),
("<b>Aspirin</b>", "300-600mg PO q4-6h"),
("<b>Naproxen</b>", "500mg PO q12h"),
],
"notes": [
"NSAIDs: avoid in CKD,\ncirrhosis, heart failure",
"Paracetamol: CI in\nliver failure",
],
},
{
"num": "Step 2",
"pain": "MILD-MOD PAIN",
"pain_score": "(NRS 4-6)",
"color": STEP2_COL,
"light": colors.HexColor("#FEF9E7"),
"class": "Weak Opioids",
"drugs": [
("<b>Codeine</b>", "30-60mg PO q4-6h\n(+ paracetamol)"),
("<b>Tramadol</b>", "50-100mg PO q4-6h\n(max 400mg/24h)"),
("<b>Co-codamol</b>", "Codeine 30mg +\nParacetamol 500mg"),
("<b>Dihydrocodeine</b>", "30mg PO q4-6h"),
],
"notes": [
"Codeine: causes\nconstipation (common)",
"Tramadol: agitation,\nseizure risk",
"Watch paracetamol\ntotal dose in combos",
],
},
{
"num": "Step 3",
"pain": "MOD-SEVERE PAIN",
"pain_score": "(NRS 7-10)",
"color": STEP3_COL,
"light": colors.HexColor("#FDEDEC"),
"class": "Strong Opioids",
"drugs": [
("<b>Morphine</b>", "2.5-10mg PO q4h\n(titrate to effect)"),
("<b>Oxycodone</b>", "5-10mg PO q4-6h\n(if morphine SE)"),
("<b>Fentanyl patch</b>", "25mcg/h patch\nchange q72h"),
("<b>Hydromorphone</b>", "1-2mg PO q4h\n(renal impairment)"),
("<b>Alfentanil</b>", "SC infusion\n(severe renal failure)"),
],
"notes": [
"No ceiling dose for\npure opioids",
"Always prescribe\nbreakthrough dose",
"Breakthrough = 10-20%\nof 24h total dose",
],
},
{
"num": "Step 4",
"pain": "REFRACTORY PAIN",
"pain_score": "(any NRS)",
"color": STEP4_COL,
"light": colors.HexColor("#F5EEF8"),
"class": "Interventional",
"drugs": [
("<b>Epidural</b>", "Local anaesthetic\n± opioid infusion"),
("<b>Intrathecal pump</b>", "Morphine/ziconotide\nintrathecal delivery"),
("<b>Nerve blocks</b>", "Coeliac plexus,\nganglion impar"),
("<b>Spinal cord stim.</b>", "Neuromodulation\nfor neuropathic pain"),
("<b>Cordotomy</b>", "Neurosurgical\nfor intractable pain"),
],
"notes": [
"Specialist referral\nrequired",
"Can combine with\nStep 3 opioids",
],
},
]
col_w = W / 4
def make_step_col(cfg):
rows = []
# Header
header_cell = [
Paragraph(cfg["num"], ParagraphStyle("sn", fontName="Helvetica-Bold",
fontSize=12, textColor=WHITE, alignment=TA_CENTER, spaceAfter=1)),
Paragraph(cfg["pain"], ParagraphStyle("sp", fontName="Helvetica-Bold",
fontSize=8, textColor=WHITE, alignment=TA_CENTER, spaceAfter=1)),
Paragraph(cfg["pain_score"], ParagraphStyle("ss", fontName="Helvetica",
fontSize=7.5, textColor=colors.HexColor("#FDFEFE"), alignment=TA_CENTER, spaceAfter=2)),
Paragraph(cfg["class"], ParagraphStyle("sc", fontName="Helvetica-Bold",
fontSize=8.5, textColor=WHITE, alignment=TA_CENTER,
borderPad=3)),
]
rows.append([header_cell])
# Drugs
drug_cells = []
for drug_name, dose in cfg["drugs"]:
d = Paragraph(drug_name, ParagraphStyle("dn", fontName="Helvetica-Bold",
fontSize=7.8, textColor=cfg["color"], leading=11))
dose_p = Paragraph(dose, ParagraphStyle("dd", fontName="Helvetica",
fontSize=7.2, textColor=GREY_TEXT, leading=10.5))
drug_cells.append([d, dose_p])
drugs_tbl = Table(drug_cells, colWidths=[col_w*0.4, col_w*0.56])
drugs_tbl.setStyle(TableStyle([
("TOPPADDING", (0,0), (-1,-1), 2),
("BOTTOMPADDING",(0,0), (-1,-1), 2),
("LEFTPADDING", (0,0), (-1,-1), 2),
("RIGHTPADDING", (0,0), (-1,-1), 2),
("VALIGN", (0,0), (-1,-1), "TOP"),
("LINEBELOW", (0,0), (-1,-2), 0.3, colors.HexColor("#D5D8DC")),
]))
rows.append([drugs_tbl])
# Notes / warnings
note_items = []
for n in cfg["notes"]:
note_items.append(Paragraph(
f"\u26a0 {n}",
ParagraphStyle("ni", fontName="Helvetica", fontSize=7,
textColor=colors.HexColor("#7D6608") if cfg["color"]==STEP2_COL
else colors.HexColor("#922B21") if cfg["color"]==STEP3_COL
else colors.HexColor("#1A5276") if cfg["color"]==STEP4_COL
else colors.HexColor("#1D6A39"),
leading=10.5)
))
rows.append([note_items])
tbl = Table(rows, colWidths=[col_w - 4])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), cfg["color"]),
("BACKGROUND", (0,1), (0,1), cfg["light"]),
("BACKGROUND", (0,2), (0,2), colors.HexColor("#FAFAFA")),
("TOPPADDING", (0,0), (0,0), 8),
("BOTTOMPADDING",(0,0), (0,0), 8),
("TOPPADDING", (0,1), (-1,-1), 5),
("BOTTOMPADDING",(0,1), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 4),
("RIGHTPADDING", (0,0), (-1,-1), 4),
("BOX", (0,0), (-1,-1), 1, cfg["color"]),
("LINEBELOW", (0,1), (0,1), 0.5, cfg["color"]),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
return tbl
step_cols = [make_step_col(c) for c in step_configs]
steps_tbl = Table([step_cols], colWidths=[col_w]*4)
steps_tbl.setStyle(TableStyle([
("LEFTPADDING", (0,0), (-1,-1), 2),
("RIGHTPADDING", (0,0), (-1,-1), 2),
("TOPPADDING", (0,0), (-1,-1), 0),
("BOTTOMPADDING",(0,0), (-1,-1), 0),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(steps_tbl)
story.append(Spacer(1, 5*mm))
# ── 4. ADJUVANT ANALGESICS BAR ────────────────────────────────────────────────
adj_title = [[Paragraph(
"ADJUVANT ANALGESICS \u2014 Use at ANY Step",
ParagraphStyle("at", fontName="Helvetica-Bold", fontSize=9,
textColor=WHITE, alignment=TA_CENTER)
)]]
adj_title_tbl = Table(adj_title, colWidths=[W])
adj_title_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), ADJ_COL),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0), (-1,-1), 5),
]))
story.append(adj_title_tbl)
adj_items = [
("Neuropathic Pain", "Gabapentin 100-300mg TDS\nPregabalin 25-75mg BD\nAmitriptyline 10-75mg nocte"),
("Bone Pain", "Dexamethasone 4-8mg OD\nBisphosphonates (zoledronic acid)\nNSAIDs"),
("Nerve Compression", "Dexamethasone 8-16mg OD\nKetamine (sub-anaesthetic)\nMethadone"),
("Muscle Spasm", "Baclofen 5-10mg TDS\nDiazepam 2-5mg TDS\nCyclobenzaprine"),
]
adj_cells = []
for cat, drugs in adj_items:
adj_cells.append([
Paragraph(cat, ParagraphStyle("ac", fontName="Helvetica-Bold",
fontSize=7.8, textColor=MID_BLUE, spaceAfter=2)),
Paragraph(drugs, ParagraphStyle("ad", fontName="Helvetica",
fontSize=7.3, textColor=GREY_TEXT, leading=11)),
])
adj_tbl = Table(adj_cells, colWidths=[W*0.2, W*0.05, W*0.2, W*0.05, W*0.2, W*0.05, W*0.2, W*0.05])
# Simpler approach: flat 4-col table
adj_flat_row = []
for cat, drugs in adj_items:
cell = [
Paragraph(cat, ParagraphStyle("acf", fontName="Helvetica-Bold",
fontSize=7.8, textColor=MID_BLUE, spaceAfter=2, leading=11)),
Paragraph(drugs, ParagraphStyle("adf", fontName="Helvetica",
fontSize=7.3, textColor=GREY_TEXT, leading=11)),
]
adj_flat_row.append(cell)
adj_flat_tbl = Table([adj_flat_row], colWidths=[W/4]*4)
adj_flat_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), colors.HexColor("#EAF3FB")),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING",(0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
("LINEAFTER", (0,0), (2,0), 0.5, colors.HexColor("#AED6F1")),
]))
story.append(adj_flat_tbl)
story.append(Spacer(1, 4*mm))
# ── 5. CLINICAL PEARLS & OPIOID SIDE EFFECTS ─────────────────────────────────
left_col = []
right_col = []
# Clinical pearls
left_col.append(Paragraph("CLINICAL PEARLS", ParagraphStyle("cph",
fontName="Helvetica-Bold", fontSize=9, textColor=DARK_BLUE, spaceAfter=4)))
pearls = [
("Breakthrough pain dose", "10-20% of total 24h opioid dose, q1-4h PRN"),
("Morphine SR (MST)", "Divide 24h total dose into 2 x 12-hourly doses once stable"),
("Fentanyl patch", "Takes 12-24h to reach full effect; lasts 72h after removal"),
("Renal impairment", "Prefer alfentanil or hydromorphone (less renal excretion)"),
("Opioid rotation", "Consider if adequate analgesia but intolerable side effects"),
("Nausea", "Usually transient; treat with antiemetics (metoclopramide, ondansetron)"),
("Constipation", "Persistent - always prescribe laxatives prophylactically"),
]
for key, val in pearls:
left_col.append(Paragraph(
f"<b>{key}:</b> {val}",
ParagraphStyle("pearl", fontName="Helvetica", fontSize=7.5,
textColor=GREY_TEXT, leading=11.5, spaceAfter=2)
))
# Opioid neurotoxicity
left_col.append(Spacer(1, 4))
left_col.append(Paragraph("OPIOID-INDUCED NEUROTOXICITY", ParagraphStyle("oin",
fontName="Helvetica-Bold", fontSize=8.5, textColor=colors.HexColor("#C0392B"), spaceAfter=3)))
left_col.append(Paragraph(
"Signs: myoclonus \u2022 hallucinations \u2022 peripheral shadows \u2022 confusion \u2022 drowsiness",
ParagraphStyle("ois", fontName="Helvetica", fontSize=7.5, textColor=GREY_TEXT, leading=11)))
left_col.append(Spacer(1, 3))
mgmt_steps = [
"Reduce opioid dose (if pain controlled)",
"Increase hydration",
"Switch to alternative opioid (opioid rotation)",
"Involve palliative care / pain team",
]
for s in mgmt_steps:
left_col.append(Paragraph(f"\u2022 {s}",
ParagraphStyle("oim", fontName="Helvetica", fontSize=7.5,
textColor=GREY_TEXT, leading=11, leftIndent=8)))
# Right column: NRS pain scale + opioid SE
right_col.append(Paragraph("NRS PAIN SCALE", ParagraphStyle("npsh",
fontName="Helvetica-Bold", fontSize=9, textColor=DARK_BLUE, spaceAfter=4)))
nrs_data = [
["Score", "Description", "WHO Step"],
["0", "No pain", "-"],
["1-3", "Mild pain", "Step 1"],
["4-6", "Moderate pain", "Step 2"],
["7-10", "Severe pain", "Step 3/4"],
]
nrs_tbl = Table(nrs_data, colWidths=[W*0.06, W*0.19, W*0.1])
nrs_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 7.5),
("BACKGROUND", (0,2), (-1,2), colors.HexColor("#FDEDEC")),
("BACKGROUND", (0,3), (-1,3), colors.HexColor("#FADBD8")),
("BACKGROUND", (0,4), (-1,4), colors.HexColor("#F1948A")),
("TEXTCOLOR", (0,3), (-1,4), colors.HexColor("#7B241C")),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#BFC9CA")),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING",(0,0), (-1,-1), 3),
]))
right_col.append(nrs_tbl)
right_col.append(Spacer(1, 6))
right_col.append(Paragraph("COMMON OPIOID SIDE EFFECTS", ParagraphStyle("oseh",
fontName="Helvetica-Bold", fontSize=8.5, textColor=DARK_BLUE, spaceAfter=3)))
se_data = [
["Side Effect", "Management"],
["Constipation", "Senna + macrogol (always)"],
["Nausea/vomiting", "Metoclopramide, ondansetron"],
["Sedation", "Reduce dose, review other CNS drugs"],
["Resp. depression", "Naloxone 0.1-0.4mg IV/SC"],
["Pruritus", "Antihistamine; opioid switch"],
["Urinary retention", "Bladder scan; catheterisation"],
]
se_tbl = Table(se_data, colWidths=[W*0.2, W*0.28])
se_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), MID_BLUE),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 7.3),
("BACKGROUND", (0,1), (-1,1), LIGHT_GREY),
("BACKGROUND", (0,3), (-1,3), LIGHT_GREY),
("BACKGROUND", (0,5), (-1,5), LIGHT_GREY),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#BFC9CA")),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING",(0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 4),
]))
right_col.append(se_tbl)
# Combine into 2-col layout
bottom_tbl = Table([[left_col, right_col]], colWidths=[W*0.52, W*0.48])
bottom_tbl.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "TOP"),
("LEFTPADDING", (0,0), (-1,-1), 0),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("TOPPADDING", (0,0), (-1,-1), 0),
("BOTTOMPADDING",(0,0), (-1,-1), 0),
("LINEAFTER", (0,0), (0,0), 0.5, colors.HexColor("#AED6F1")),
]))
story.append(bottom_tbl)
story.append(Spacer(1, 4*mm))
# ── 6. FOOTER ─────────────────────────────────────────────────────────────────
story.append(HRFlowable(width=W, thickness=0.5, color=colors.HexColor("#AED6F1")))
story.append(Spacer(1, 2))
story.append(Paragraph(
"WHO Analgesic Ladder (1986, revised 1996) \u2022 4th step added by international expert consensus \u2022 "
"Morphine is gold-standard strong opioid \u2022 Always prescribe laxatives with opioids \u2022 "
"This card is for clinical reference only \u2014 individual patient assessment is required",
S_FOOT
))
# ── BUILD ────────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF saved to: {OUTPUT}")
cd /home/daytona/workspace/who-pain-ladder && python create_card.py 2>&1
~/who-pain-ladder/create_card.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/who-pain-ladder/create_card.py'
cd /home/daytona/workspace/who-pain-ladder && python create_card.py 2>&1
ls -lh /home/daytona/workspace/who-pain-ladder/WHO_Pain_Ladder_Reference_Card.pd…
cd /home/daytona/workspace/who-pain-ladder && python -c " from pypdf import PdfR…
cd /home/daytona/workspace/who-pain-ladder && python -c " from pypdf import PdfR…
~/who-pain-ladder/create_card.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/who-pain-ladder/create_card.py'
~/who-pain-ladder/create_card.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/who-pain-ladder/create_card.py'
~/who-pain-ladder/create_card.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/who-pain-ladder/create_card.py'
~/who-pain-ladder/create_card.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/who-pain-ladder/create_card.py'
~/who-pain-ladder/create_card.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/who-pain-ladder/create_card.py'
cd /home/daytona/workspace/who-pain-ladder && python create_card.py 2>&1 && pyth…
cd /home/daytona/workspace/who-pain-ladder && python -c " from pypdf import PdfR…
cd /home/daytona/workspace/who-pain-ladder && python -c " from pypdf import PdfR…
WHO Pain Ladder Reference Card
PDF Document · PDF
Who pain management ladder updated lettest pdf
WHO analgesic ladder pain management updated
WHO pain management ladder 2024 2025 updated guidelines latest
PMID: 39250736
PMID: 37504360
https://www.ncbi.nlm.nih.gov/books/NBK554435/
~/who-pain-ladder/create_updated_card.py
"""
WHO Pain Management Ladder - UPDATED Clinical Reference Card (2025)
Reflects: WHO 2018 Guidelines + 2024/2025 evidence updates
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm
from reportlab.platypus import (SimpleDocTemplate, Paragraph, Spacer, Table,
TableStyle, HRFlowable, KeepTogether)
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT
# ── Palette ───────────────────────────────────────────────────────────────────
DARK_NAVY = colors.HexColor("#0D2137")
NAVY = colors.HexColor("#1A3A5C")
MID_BLUE = colors.HexColor("#2E6DA4")
STEEL = colors.HexColor("#4A90C4")
STEP1_COL = colors.HexColor("#1E8449") # green
STEP2_COL = colors.HexColor("#CA6F1E") # orange
STEP3_COL = colors.HexColor("#C0392B") # red
STEP4_COL = colors.HexColor("#6C3483") # purple
STEP1_LIGHT = colors.HexColor("#E9F7EF")
STEP2_LIGHT = colors.HexColor("#FEF5E7")
STEP3_LIGHT = colors.HexColor("#FDEDEC")
STEP4_LIGHT = colors.HexColor("#F4ECF7")
BADGE_NEW = colors.HexColor("#E74C3C") # red "NEW 2018" badge
BADGE_UPD = colors.HexColor("#2980B9") # blue "UPDATED" badge
WHITE = colors.white
GREY = colors.HexColor("#3D3D3D")
LGREY = colors.HexColor("#ECF0F1")
WARN_RED = colors.HexColor("#922B21")
WARN_AMB = colors.HexColor("#784212")
WARN_PURP = colors.HexColor("#512E5F")
FOOT_GREY = colors.HexColor("#7F8C8D")
GOLD = colors.HexColor("#B7950B")
ADJ_BG = colors.HexColor("#EBF5FB")
ADJ_HDR = colors.HexColor("#1A5276")
OUTPUT = "/home/daytona/workspace/who-pain-ladder/WHO_Pain_Ladder_UPDATED_2025.pdf"
doc = SimpleDocTemplate(
OUTPUT, pagesize=A4,
leftMargin=13*mm, rightMargin=13*mm,
topMargin=10*mm, bottomMargin=10*mm,
)
W = A4[0] - 26*mm
# ── Style factory ────────────────────────────────────────────────────────────
def S(name, **kw):
return ParagraphStyle(name, **kw)
ST_MAIN = S("main", fontName="Helvetica-Bold", fontSize=18,
textColor=WHITE, alignment=TA_CENTER)
ST_SUB = S("sub", fontName="Helvetica", fontSize=9,
textColor=colors.HexColor("#AED6F1"), alignment=TA_CENTER)
ST_BADGE = S("badge", fontName="Helvetica-Bold", fontSize=7.5,
textColor=WHITE, alignment=TA_CENTER)
ST_BODY = S("body", fontName="Helvetica", fontSize=7.8,
textColor=GREY, leading=11.5)
ST_BOLD = S("bold", fontName="Helvetica-Bold", fontSize=7.8,
textColor=GREY, leading=11.5)
ST_SM = S("sm", fontName="Helvetica", fontSize=7.2,
textColor=GREY, leading=10.5)
ST_SM_B = S("sm_b", fontName="Helvetica-Bold", fontSize=7.2,
textColor=GREY, leading=10.5)
ST_WARN = S("warn", fontName="Helvetica", fontSize=6.8, leading=10)
ST_SEC = S("sec", fontName="Helvetica-Bold", fontSize=8.5,
textColor=NAVY, spaceAfter=3)
ST_FOOT = S("foot", fontName="Helvetica", fontSize=6.8,
textColor=FOOT_GREY, alignment=TA_CENTER)
ST_UPD_LBL= S("upd", fontName="Helvetica-Bold", fontSize=7,
textColor=WHITE, alignment=TA_CENTER)
ST_PRINC = S("princ", fontName="Helvetica-Bold", fontSize=8,
textColor=WHITE, alignment=TA_CENTER, spaceAfter=1)
ST_PRINCD = S("princd", fontName="Helvetica", fontSize=7.2,
textColor=colors.HexColor("#D6EAF8"), alignment=TA_CENTER, leading=10.5)
story = []
# ═══════════════════════════════════════════════════════════════════════════════
# 1. HEADER
# ═══════════════════════════════════════════════════════════════════════════════
# Version badge row
ver_badge = Table([[
Paragraph("WHO 2018 UPDATED GUIDELINES", ST_BADGE),
Paragraph("+ 2024/2025 EVIDENCE", ST_BADGE),
Paragraph("PMID: 39250736 | PMID: 37504360", ST_BADGE),
]], colWidths=[W*0.38, W*0.3, W*0.32])
ver_badge.setStyle(TableStyle([
("BACKGROUND", (0,0),(0,0), colors.HexColor("#E74C3C")),
("BACKGROUND", (1,0),(1,0), colors.HexColor("#E67E22")),
("BACKGROUND", (2,0),(2,0), colors.HexColor("#1A5276")),
("TOPPADDING", (0,0),(-1,-1), 3),
("BOTTOMPADDING",(0,0),(-1,-1), 3),
("LEFTPADDING", (0,0),(-1,-1), 4),
("RIGHTPADDING", (0,0),(-1,-1), 4),
("ALIGN", (0,0),(-1,-1), "CENTER"),
]))
story.append(ver_badge)
hdr = Table([
[Paragraph("WHO Pain Management Ladder", ST_MAIN)],
[Paragraph("Updated Clinical Reference Card \u2022 Incorporating WHO 2018 Guidelines & Latest Evidence", ST_SUB)],
], colWidths=[W])
hdr.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), DARK_NAVY),
("TOPPADDING", (0,0),(0,0), 8),
("BOTTOMPADDING",(0,0),(0,0), 2),
("TOPPADDING", (0,1),(0,1), 1),
("BOTTOMPADDING",(0,1),(0,1), 8),
("ALIGN", (0,0),(-1,-1), "CENTER"),
]))
story.append(hdr)
story.append(Spacer(1, 3*mm))
# ═══════════════════════════════════════════════════════════════════════════════
# 2. NEW 2018 KEY CHANGES ALERT BAR
# ═══════════════════════════════════════════════════════════════════════════════
changes = [
"Step 2 CAN be skipped",
"Bidirectional use (top-down for acute pain)",
"Opioid stewardship mandatory",
"Radiotherapy added as analgesic modality",
"Non-pharmacological therapies integrated",
]
change_cells = [[
Paragraph("\u26a0 WHO 2018 KEY UPDATES", S("chh", fontName="Helvetica-Bold",
fontSize=8, textColor=WHITE, alignment=TA_CENTER))
] + [
Paragraph(f"\u2713 {c}", S("chb", fontName="Helvetica", fontSize=7.3,
textColor=colors.HexColor("#FDFEFE"), leading=10.5))
for c in changes
]]
cw_list = [W*0.14] + [W*0.172]*5
change_tbl = Table(change_cells, colWidths=cw_list)
change_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0),(0,0), colors.HexColor("#C0392B")),
("BACKGROUND", (1,0),(-1,0), colors.HexColor("#E74C3C")),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 5),
("RIGHTPADDING", (0,0),(-1,-1), 5),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
("LINEAFTER", (0,0),(4,0), 0.5, colors.HexColor("#F1948A")),
]))
story.append(change_tbl)
story.append(Spacer(1, 3*mm))
# ═══════════════════════════════════════════════════════════════════════════════
# 3. CORE PRINCIPLES STRIP
# ═══════════════════════════════════════════════════════════════════════════════
principles = [
("By Mouth", "Oral route preferred;\nIV/SC only if unable"),
("By the Clock", "Fixed intervals, not PRN;\nprevent pain recurrence"),
("By the Ladder", "Stepwise escalation\nbased on pain intensity"),
("Individualise", "Titrate to each patient;\nno standard dose"),
("Attention to Detail", "Monitor SE, adjuvants,\nbreakthrough pain"),
]
pcells = []
for t, d in principles:
pcells.append([
Paragraph(t, ST_PRINC),
Paragraph(d, ST_PRINCD),
])
p_tbl = Table([pcells], colWidths=[W/5]*5)
p_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), MID_BLUE),
("TOPPADDING", (0,0),(-1,-1), 6),
("BOTTOMPADDING",(0,0),(-1,-1), 6),
("LEFTPADDING", (0,0),(-1,-1), 3),
("RIGHTPADDING", (0,0),(-1,-1), 3),
("ALIGN", (0,0),(-1,-1), "CENTER"),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
("LINEAFTER", (0,0),(3,0), 0.5, colors.HexColor("#5D9FCC")),
]))
story.append(p_tbl)
story.append(Spacer(1, 3*mm))
# ═══════════════════════════════════════════════════════════════════════════════
# 4. STEP COLUMNS
# ═══════════════════════════════════════════════════════════════════════════════
col_w = W / 4
def mk_step(num, pain, score, col, light, drug_class, drugs, warnings, new_notes=None):
"""Build a single step column as a nested Table."""
# -- header --
hdr_paragraphs = [
Paragraph(num, S("sn", fontName="Helvetica-Bold", fontSize=13,
textColor=WHITE, alignment=TA_CENTER, spaceAfter=0)),
Paragraph(pain, S("sp", fontName="Helvetica-Bold", fontSize=8,
textColor=WHITE, alignment=TA_CENTER, spaceAfter=1)),
Paragraph(score, S("ss", fontName="Helvetica", fontSize=7.5,
textColor=colors.HexColor("#FDFEFE"), alignment=TA_CENTER, spaceAfter=2)),
Paragraph(drug_class, S("sc", fontName="Helvetica-Bold", fontSize=9,
textColor=WHITE, alignment=TA_CENTER)),
]
# -- drug rows --
drug_rows = []
for dname, dose in drugs:
drug_rows.append([
Paragraph(dname, S("dn", fontName="Helvetica-Bold", fontSize=7.5,
textColor=col, leading=10.5)),
Paragraph(dose, S("dd", fontName="Helvetica", fontSize=7,
textColor=GREY, leading=10)),
])
drugs_tbl = Table(drug_rows, colWidths=[col_w*0.42, col_w*0.53])
drugs_tbl.setStyle(TableStyle([
("TOPPADDING", (0,0),(-1,-1), 2),
("BOTTOMPADDING",(0,0),(-1,-1), 2),
("LEFTPADDING", (0,0),(-1,-1), 2),
("RIGHTPADDING", (0,0),(-1,-1), 2),
("VALIGN", (0,0),(-1,-1), "TOP"),
("LINEBELOW", (0,0),(-1,-2), 0.3, colors.HexColor("#D5D8DC")),
]))
# -- warning items --
warn_items = []
for w in warnings:
warn_items.append(
Paragraph(f"\u26a0 {w}", S("wi", fontName="Helvetica", fontSize=6.8,
textColor=WARN_RED if col==STEP3_COL
else WARN_AMB if col==STEP2_COL
else WARN_PURP if col==STEP4_COL
else colors.HexColor("#1D6A39"),
leading=10))
)
if new_notes:
for nn in new_notes:
warn_items.append(
Paragraph(f"\u2605 {nn}", S("nn", fontName="Helvetica-Bold", fontSize=6.8,
textColor=colors.HexColor("#1A5276"), leading=10))
)
tbl = Table([
[hdr_paragraphs],
[drugs_tbl],
[warn_items],
], colWidths=[col_w - 4])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0),(0,0), col),
("BACKGROUND", (0,1),(0,1), light),
("BACKGROUND", (0,2),(0,2), colors.HexColor("#FAFAFA")),
("TOPPADDING", (0,0),(0,0), 7),
("BOTTOMPADDING",(0,0),(0,0), 7),
("TOPPADDING", (0,1),(-1,-1), 4),
("BOTTOMPADDING",(0,1),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 3),
("RIGHTPADDING", (0,0),(-1,-1), 3),
("BOX", (0,0),(-1,-1), 1, col),
("LINEBELOW", (0,1),(0,1), 0.5, col),
("VALIGN", (0,0),(-1,-1), "TOP"),
]))
return tbl
steps = [
mk_step(
"Step 1", "MILD PAIN", "(NRS 1-3)",
STEP1_COL, STEP1_LIGHT, "Non-Opioids + Adjuvants",
[
("<b>Paracetamol</b>", "500mg-1g PO q4-6h\n(max 4g/24h)"),
("<b>Ibuprofen</b>", "200-400mg PO q6-8h\nwith food"),
("<b>Diclofenac</b>", "50mg PO q8h"),
("<b>Naproxen</b>", "250-500mg PO q12h"),
("<b>Celecoxib</b>", "100-200mg PO BD\n(COX-2 selective)"),
],
[
"NSAIDs: avoid CKD,\ncirrhosis, heart failure",
"Paracetamol: CI in\nliver failure",
"NSAIDs: caution if\nasthma history",
],
new_notes=["Non-pharmacological Rx\nalways alongside drugs"]
),
mk_step(
"Step 2", "MILD-MOD PAIN", "(NRS 4-6)",
STEP2_COL, STEP2_LIGHT, "Weak Opioids",
[
("<b>Codeine</b>", "30-60mg PO q4-6h"),
("<b>Tramadol</b>", "50-100mg PO q4-6h\n(max 400mg/24h)"),
("<b>Co-codamol</b>", "Codeine 30mg +\nParacetamol 500mg"),
("<b>Buprenorphine SL</b>","0.2-0.4mg SL q6-8h\n(partial agonist)"),
],
[
"Codeine: constipation,\npoor CYP2D6 metabolisers",
"Tramadol: lowers\nseizure threshold",
"Watch total paracetamol\nin combination products",
],
new_notes=["\u2605 2018: Step 2 may\nbe SKIPPED safely"]
),
mk_step(
"Step 3", "MOD-SEVERE PAIN", "(NRS 7-10)",
STEP3_COL, STEP3_LIGHT, "Strong Opioids",
[
("<b>Morphine IR</b>", "2.5-10mg PO q4h\n(gold standard)"),
("<b>Morphine SR</b>", "12-hourly MST once\ndose established"),
("<b>Oxycodone</b>", "5-10mg PO q4-6h\n(if morphine SE)"),
("<b>Fentanyl patch</b>","25mcg/h q72h\n(stable pain only)"),
("<b>Hydromorphone</b>","1-2mg PO q4h\n(renal impairment)"),
("<b>Alfentanil SC</b>","Infusion - severe\nrenal failure only"),
],
[
"No ceiling dose\nfor pure opioids",
"Breakthrough = 10-20%\nof 24h total dose",
"Always prescribe laxatives\nprophylactically",
],
new_notes=["\u2605 2018: Opioid stewardship;\nassess risk before starting"]
),
mk_step(
"Step 4", "REFRACTORY PAIN", "(any NRS)",
STEP4_COL, STEP4_LIGHT, "Interventional + RT",
[
("<b>Epidural</b>", "LA ± opioid infusion"),
("<b>Intrathecal pump</b>", "Morphine / ziconotide"),
("<b>Nerve blocks</b>", "Coeliac plexus,\nganglion impar"),
("<b>Spinal cord stim.</b>", "Neuromodulation\nneuropathic pain"),
("<b>Radiotherapy</b>", "Bone mets / nerve\ncompression pain"),
("<b>Cordotomy</b>", "Neurosurgical;\nintractable pain"),
],
[
"Specialist referral\nrequired",
"Interventions CI in:\ncoagulopathy, infection",
],
new_notes=["\u2605 NEW 2018: Radiotherapy\nexplicitly included"]
),
]
steps_row = Table([steps], colWidths=[col_w]*4)
steps_row.setStyle(TableStyle([
("LEFTPADDING", (0,0),(-1,-1), 2),
("RIGHTPADDING", (0,0),(-1,-1), 2),
("TOPPADDING", (0,0),(-1,-1), 0),
("BOTTOMPADDING",(0,0),(-1,-1), 0),
("VALIGN", (0,0),(-1,-1), "TOP"),
]))
story.append(steps_row)
story.append(Spacer(1, 3*mm))
# ═══════════════════════════════════════════════════════════════════════════════
# 5. DIRECTION BANNER (new 2018 concept)
# ═══════════════════════════════════════════════════════════════════════════════
dir_data = [[
Paragraph("\u2191 CHRONIC PAIN: escalate bottom-up", S("cu", fontName="Helvetica-Bold",
fontSize=8, textColor=WHITE, alignment=TA_CENTER)),
Paragraph("\u2195 REASSESS frequently; de-escalate when pain resolves", S("cr", fontName="Helvetica",
fontSize=8, textColor=WHITE, alignment=TA_CENTER)),
Paragraph("\u2193 ACUTE PAIN: start at appropriate step; step down", S("cd", fontName="Helvetica-Bold",
fontSize=8, textColor=WHITE, alignment=TA_CENTER)),
]]
dir_tbl = Table(dir_data, colWidths=[W/3]*3)
dir_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0),(0,0), STEP1_COL),
("BACKGROUND", (1,0),(1,0), STEEL),
("BACKGROUND", (2,0),(2,0), STEP3_COL),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 6),
("RIGHTPADDING", (0,0),(-1,-1), 6),
("ALIGN", (0,0),(-1,-1), "CENTER"),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
("LINEAFTER", (0,0),(1,0), 0.5, WHITE),
]))
story.append(dir_tbl)
story.append(Spacer(1, 3*mm))
# ═══════════════════════════════════════════════════════════════════════════════
# 6. ADJUVANTS
# ═══════════════════════════════════════════════════════════════════════════════
adj_hdr = Table([[
Paragraph("ADJUVANT ANALGESICS \u2014 Use at Any Step \u2022 Tailor to Pain Type",
S("ah", fontName="Helvetica-Bold", fontSize=8.5,
textColor=WHITE, alignment=TA_CENTER))
]], colWidths=[W])
adj_hdr.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), ADJ_HDR),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1), 5),
]))
story.append(adj_hdr)
adj_items = [
("Neuropathic Pain",
"Gabapentin 100-300mg TDS\nPregabalin 25-75mg BD\nAmitriptyline 10-75mg nocte\nDuloxetine 30-60mg OD"),
("Bone / Inflammatory",
"Dexamethasone 4-8mg OD\nBisphosphonates (zoledronic acid)\nDenosumab (bone mets)\nNSAIDs"),
("Nerve Compression",
"Dexamethasone 8-16mg OD\nKetamine (sub-anaesthetic)\nMethadone (dual MOR/NMDA)\nLidocaine infusion"),
("Muscle Spasm / Other",
"Baclofen 5-10mg TDS\nDiazepam 2-5mg TDS\nClonidine (central alpha-2)\nCannabinoids (jurisd. specific)"),
]
adj_row = []
for cat, drugs in adj_items:
adj_row.append([
Paragraph(cat, S("ac", fontName="Helvetica-Bold", fontSize=7.8,
textColor=ADJ_HDR, spaceAfter=2, leading=11)),
Paragraph(drugs, S("ad", fontName="Helvetica", fontSize=7.2,
textColor=GREY, leading=11)),
])
adj_body = Table([adj_row], colWidths=[W/4]*4)
adj_body.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), ADJ_BG),
("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"),
("LINEAFTER", (0,0),(2,0), 0.5, colors.HexColor("#AED6F1")),
]))
story.append(adj_body)
story.append(Spacer(1, 3*mm))
# ═══════════════════════════════════════════════════════════════════════════════
# 7. BOTTOM: NRS TABLE | NON-PHARM | SIDE EFFECTS | OPIOID SAFETY
# ═══════════════════════════════════════════════════════════════════════════════
# Column A: NRS + Non-Pharm
col_a = []
col_a.append(Paragraph("NRS PAIN SCALE", ST_SEC))
nrs = Table([
["Score", "Severity", "Starting Step"],
["0", "None", "No analgesia"],
["1-3", "Mild", "Step 1"],
["4-6", "Moderate", "Step 2 (or skip to 3)"],
["7-10", "Severe", "Step 3 or 4"],
], colWidths=[W*0.07, W*0.14, W*0.17])
nrs.setStyle(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), 7.3),
("BACKGROUND", (0,2),(-1,2), STEP1_LIGHT),
("BACKGROUND", (0,3),(-1,3), STEP2_LIGHT),
("BACKGROUND", (0,4),(-1,4), STEP3_LIGHT),
("GRID", (0,0),(-1,-1), 0.4, colors.HexColor("#BFC9CA")),
("TOPPADDING", (0,0),(-1,-1), 3),
("BOTTOMPADDING",(0,0),(-1,-1), 3),
("LEFTPADDING", (0,0),(-1,-1), 4),
("ALIGN", (0,0),(-1,-1), "LEFT"),
]))
col_a.append(nrs)
col_a.append(Spacer(1, 4))
col_a.append(Paragraph("NON-PHARMACOLOGICAL (2018 Addition)", ST_SEC))
nonpharm = [
"Physiotherapy & rehabilitation",
"Psychological therapies (CBT, mindfulness)",
"TENS / acupuncture",
"Radiotherapy (bone mets, nerve compression)",
"Heat / cold therapy",
"Relaxation, guided imagery",
]
for np in nonpharm:
col_a.append(Paragraph(f"\u2022 {np}", ST_SM))
# Column B: Clinical pearls
col_b = []
col_b.append(Paragraph("CLINICAL PEARLS", ST_SEC))
pearls = [
("Breakthrough dose", "10-20% of 24h opioid total, q1-4h PRN"),
("Morphine SR", "Once stable: divide 24h dose into 2 x 12-hourly"),
("Fentanyl patch", "12-24h to reach full effect; change q72h"),
("Renal impairment", "Use alfentanil or hydromorphone"),
("Hepatic failure", "Avoid NSAIDs; use paracetamol cautiously"),
("Elderly patients", "Start low, go slow; higher SE sensitivity"),
("Opioid rotation", "Switch if good analgesia but intolerable SE"),
("Equianalgesic table", "Use when rotating opioids to prevent over/underdose"),
]
for k, v in pearls:
col_b.append(Paragraph(
f"<b>{k}:</b> {v}",
S("pe", fontName="Helvetica", fontSize=7.3, textColor=GREY,
leading=11, spaceAfter=1)
))
col_b.append(Spacer(1, 4))
col_b.append(Paragraph("OPIOID NEUROTOXICITY", S("ont", fontName="Helvetica-Bold",
fontSize=8, textColor=WARN_RED, spaceAfter=2)))
col_b.append(Paragraph(
"Signs: myoclonus \u2022 hallucinations \u2022 confusion \u2022 drowsiness",
S("ons", fontName="Helvetica", fontSize=7.2, textColor=GREY, leading=10.5)))
col_b.append(Spacer(1, 2))
for mg in ["Reduce dose if pain controlled", "Increase hydration",
"Opioid rotation to alternative", "Involve pain/palliative team"]:
col_b.append(Paragraph(f"\u2022 {mg}", ST_SM))
# Column C: Side effects + Opioid stewardship
col_c = []
col_c.append(Paragraph("OPIOID SIDE EFFECTS", ST_SEC))
se = Table([
["Side Effect", "Management"],
["Constipation", "Senna + macrogol always"],
["Nausea/vomiting", "Metoclopramide, ondansetron"],
["Sedation", "Reduce dose; review CNS drugs"],
["Resp. depression", "Naloxone 0.1-0.4mg IV/SC"],
["Pruritus", "Antihistamine; opioid switch"],
["Urinary retention", "Bladder scan; catheterise"],
["Myoclonus", "Opioid rotation; haloperidol"],
], colWidths=[W*0.21, W*0.25])
se.setStyle(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), 7.2),
("BACKGROUND", (0,1),(-1,1), LGREY),
("BACKGROUND", (0,3),(-1,3), LGREY),
("BACKGROUND", (0,5),(-1,5), LGREY),
("BACKGROUND", (0,7),(-1,7), LGREY),
("GRID", (0,0),(-1,-1), 0.4, colors.HexColor("#BFC9CA")),
("TOPPADDING", (0,0),(-1,-1), 2.5),
("BOTTOMPADDING",(0,0),(-1,-1), 2.5),
("LEFTPADDING", (0,0),(-1,-1), 4),
]))
col_c.append(se)
col_c.append(Spacer(1, 4))
col_c.append(Paragraph("OPIOID STEWARDSHIP (2018)", S("osh", fontName="Helvetica-Bold",
fontSize=8, textColor=colors.HexColor("#1A5276"), spaceAfter=2)))
for s in ["Assess pain type before prescribing",
"Document indication, dose, duration",
"Risk-stratify: addiction, respiratory",
"Regular review & plan to taper",
"Avoid in uncontrolled sleep apnoea"]:
col_c.append(Paragraph(f"\u2022 {s}", ST_SM))
bottom_tbl = Table([[col_a, col_b, col_c]], colWidths=[W*0.38, W*0.37, W*0.25])
bottom_tbl.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), 8),
("LINEAFTER", (0,0),(1,0), 0.5, colors.HexColor("#AED6F1")),
]))
story.append(bottom_tbl)
story.append(Spacer(1, 3*mm))
# ═══════════════════════════════════════════════════════════════════════════════
# 8. FOOTER
# ═══════════════════════════════════════════════════════════════════════════════
story.append(HRFlowable(width=W, thickness=0.5, color=colors.HexColor("#AED6F1")))
story.append(Spacer(1, 1.5))
story.append(Paragraph(
"Based on: WHO Analgesic Ladder 1986 (rev. 1996) \u2022 WHO Guidelines for Pharmacological & Radiotherapeutic Management of Cancer Pain 2018 \u2022 "
"Thompson J, Curr Opin Support Palliat Care 2024 (PMID 39250736) \u2022 Mestdagh F et al., Curr Oncol 2023 (PMID 37504360) \u2022 "
"NCCN Adult Cancer Pain v2.2025 \u2022 StatPearls WHO Analgesic Ladder (updated 2025) \u2022 "
"FOR CLINICAL REFERENCE ONLY - Individual patient assessment required",
ST_FOOT
))
doc.build(story)
print(f"Saved: {OUTPUT}")
cd /home/daytona/workspace/who-pain-ladder && python create_updated_card.py 2>&1
cd /home/daytona/workspace/who-pain-ladder && python -c " from pypdf import PdfR…
cd /home/daytona/workspace/who-pain-ladder && python -c " # Quick check: what's …
cd /home/daytona/workspace/who-pain-ladder && python -c " from reportlab.lib.pag…
cd /home/daytona/workspace/who-pain-ladder && python -c " from pypdf import PdfR…
WHO Pain Ladder UPDATED 2025
PDF Document · PDF
| Update | Source |
|---|---|
| Step 2 can be skipped - jumping directly from Step 1 to Step 3 is safe, feasible, and cost-effective | Thompson J, 2024 (PMID 39250736) |
| Bidirectional ladder - acute pain starts at the appropriate step and steps down; chronic pain escalates upward | StatPearls 2025 |
| Opioid stewardship is now mandatory - risk-assess before prescribing, document indication, plan taper from outset | WHO 2018 Guidelines |
| Radiotherapy explicitly added to Step 4 for bone mets and nerve compression pain | WHO 2018 Guidelines |
| Non-pharmacological therapies integrated at every step (CBT, physio, TENS, relaxation) | WHO 2018 Guidelines |
| The original 3-step ladder is no longer recommended as a strict protocol for cancer pain | Thompson J, 2024 |
| ICD-11 cancer pain taxonomy now distinguishes chronic cancer pain from cancer-related pain | Mestdagh F, 2023 (PMID 37504360) |
| Opioid crisis context - reassessment of opioid use even in cancer; non-opioid multimodal approaches prioritised | NCCN 2025 |
Why I can't download
ls -lh /home/daytona/workspace/who-pain-ladder/ && echo "---" && python -c " fro…
WHO Pain Ladder UPDATED 2025
PDF Document · PDF
WHO Pain Ladder Reference Card
PDF Document · PDF
/home/daytona/workspace/... path is the sandbox file path that this platform maps to a download URL; if it shows as plain text rather than a clickable link, your interface may not support file downloads directlyDifficulty in downloading
A clinical reference card for the WHO Pain Management Ladder (Updated 2025). Single page, A4 format, professional medical style. TOP SECTION: - Red badge: "WHO 2018 UPDATED GUIDELINES" - Dark navy header: "WHO Pain Management Ladder" with subtitle "Updated Clinical Reference Card • WHO 2018 Guidelines + Latest Evidence" - Red alert bar listing 5 key 2018 updates: Step 2 can be skipped | Bidirectional (top-down for acute pain) | Opioid stewardship mandatory | Radiotherapy added | Non-pharmacological integrated - Blue strip with 5 principles: By Mouth | By the Clock | By the Ladder | Individualise | Attention to Detail MIDDLE SECTION - 4 columns, each a step: STEP 1 (green): MILD PAIN (NRS 1-3) | Non-Opioids: Paracetamol 500mg-1g q4-6h, Ibuprofen 400mg q6-8h, Diclofenac 50mg q8h, Celecoxib 100-200mg BD | Warnings: avoid NSAIDs in CKD/HF, paracetamol CI in liver failure STEP 2 (orange): MILD-MOD PAIN (NRS 4-6) | Weak Opioids: Codeine 30-60mg q4-6h, Tramadol 50-100mg q4-6h, Co-codamol | Star note: "2018: Step 2 may be SKIPPED safely" STEP 3 (red): MOD-SEVERE PAIN (NRS 7-10) | Strong Opioids: Morphine IR 2.5-10mg q4h (gold standard), Morphine SR, Oxycodone, Fentanyl patch 25mcg/h q72h, Hydromorphone | Breakthrough = 10-20% of 24h dose STEP 4 (purple): REFRACTORY PAIN | Interventional + RT: Epidural, Intrathecal pump, Nerve blocks, Spinal cord stimulation, Radiotherapy (bone mets - NEW 2018) GREEN/BLUE/RED direction banner: ↑ CHRONIC PAIN: escalate bottom-up | ↕ REASSESS frequently | ↓ ACUTE PAIN: start at appropriate step, step down ADJUVANTS BAR (blue): Neuropathic: Gabapentin/Pregabalin/Amitriptyline | Bone: Dexamethasone/Bisphosphonates | Nerve compression: Ketamine/Methadone | Spasm: Baclofen/Clonidine BOTTOM SECTION 3 columns: Left: NRS scale table (0=none, 1-3=mild Step1, 4-6=moderate Step2, 7-10=severe Step3/4) + Non-pharmacological: Physiotherapy, CBT, TENS, Radiotherapy, Heat/cold Middle: Clinical Pearls (breakthrough dose, morphine SR, fentanyl patch timing, renal failure preference, opioid rotation, elderly caution) + Opioid Neurotoxicity signs (myoclonus, hallucinations, confusion) Right: Opioid Side Effects table (Constipation→Senna+macrogol, Nausea→metoclopramide, Sedation→reduce dose, Resp depression→Naloxone, Pruritus→switch opioid) + Opioid Stewardship checklist FOOTER: WHO 1986/2018 • PMID 39250736 • PMID 37504360 • NCCN 2025 • Clinical Reference Only

Difficulty in downloading
══════════════════════════════════════════════════════════════
WHO PAIN MANAGEMENT LADDER — UPDATED 2025
Based on WHO 2018 Guidelines + Latest Evidence
══════════════════════════════════════════════════════════════
5 CORE PRINCIPLES
─────────────────────────────────────────────────────────────
By Mouth | By the Clock | By the Ladder | Individualise | Attention to Detail
WHO 2018 KEY UPDATES
★ Step 2 CAN be skipped (go directly Step 1 → Step 3)
★ Bidirectional: Acute pain = start high, step DOWN
★ Opioid stewardship is now mandatory
★ Radiotherapy added as Step 4 modality
★ Non-pharmacological therapy integrated at every step
══════════════════════════════════════════════════════════════
STEP 1 — MILD PAIN (NRS 1–3) — NON-OPIOIDS
──────────────────────────────────────────────────────────────
• Paracetamol 500mg–1g PO q4-6h (max 4g/24h)
• Ibuprofen 400mg PO q6-8h with food
• Diclofenac 50mg PO q8h
• Naproxen 250–500mg PO q12h
• Celecoxib 100–200mg PO BD (COX-2 selective)
⚠ NSAIDs: avoid in CKD, cirrhosis, heart failure, asthma
⚠ Paracetamol: contraindicated in liver failure
★ Always add non-pharmacological therapy alongside
══════════════════════════════════════════════════════════════
STEP 2 — MILD-MODERATE PAIN (NRS 4–6) — WEAK OPIOIDS
★★ 2018 UPDATE: This step CAN BE SKIPPED safely ★★
──────────────────────────────────────────────────────────────
• Codeine 30–60mg PO q4-6h
• Tramadol 50–100mg PO q4-6h (max 400mg/24h)
• Co-codamol Codeine 30mg + Paracetamol 500mg
• Buprenorphine SL 0.2–0.4mg SL q6-8h
⚠ Codeine: constipation; poor effect in CYP2D6 poor metabolisers
⚠ Tramadol: lowers seizure threshold; serotonin syndrome risk
⚠ Watch total paracetamol dose in combination products
══════════════════════════════════════════════════════════════
STEP 3 — MODERATE-SEVERE PAIN (NRS 7–10) — STRONG OPIOIDS
──────────────────────────────────────────────────────────────
• Morphine IR 2.5–10mg PO q4h (GOLD STANDARD)
• Morphine SR Once stable: divide 24h dose → 2 x 12-hourly
• Oxycodone 5–10mg PO q4-6h (if morphine SE)
• Fentanyl patch 25mcg/h q72h (stable pain only; 12-24h onset)
• Hydromorphone 1–2mg PO q4h (renal impairment)
• Alfentanil SC Infusion — severe renal failure only
⚠ No ceiling dose for pure opioids
⚠ Breakthrough dose = 10–20% of total 24h dose, q1-4h PRN
⚠ ALWAYS prescribe laxatives prophylactically
★ 2018: Risk-assess and document before starting opioids
══════════════════════════════════════════════════════════════
STEP 4 — REFRACTORY PAIN — INTERVENTIONAL + RADIOTHERAPY
──────────────────────────────────────────────────────────────
• Epidural analgesia LA ± opioid infusion
• Intrathecal pump Morphine / ziconotide
• Nerve blocks Coeliac plexus, ganglion impar
• Spinal cord stimulation Neuromodulation (neuropathic)
• Radiotherapy ★ NEW 2018 Bone metastases, nerve compression
• Cordotomy Neurosurgical — intractable pain
⚠ Specialist referral required
⚠ CI: coagulopathy, active infection
══════════════════════════════════════════════════════════════
ADJUVANT ANALGESICS — USE AT ANY STEP
──────────────────────────────────────────────────────────────
NEUROPATHIC: Gabapentin 100–300mg TDS | Pregabalin 25–75mg BD
Amitriptyline 10–75mg nocte | Duloxetine 30–60mg OD
BONE PAIN: Dexamethasone 4–8mg OD | Bisphosphonates | Denosumab
NERVE COMPRES: Dexamethasone 8–16mg OD | Ketamine | Methadone
MUSCLE SPASM: Baclofen 5–10mg TDS | Diazepam 2–5mg TDS | Clonidine
══════════════════════════════════════════════════════════════
NRS PAIN SCALE DIRECTION OF USE
────────────────────── ─────────────────────────────────────
0 = No pain ↑ CHRONIC PAIN: escalate bottom → up
1–3 = Mild → Step 1 ↕ REASSESS: de-escalate when resolved
4–6 = Mod → Step 2 ↓ ACUTE PAIN: start appropriate step;
7–10 = Sev → Step 3/4 step DOWN as pain improves
══════════════════════════════════════════════════════════════
CLINICAL PEARLS
──────────────────────────────────────────────────────────────
Breakthrough dose: 10–20% of 24h opioid total, q1-4h PRN
Morphine SR: Once stable → divide into 2 x 12-hourly
Fentanyl patch: 12–24h to reach effect; change every 72h
Renal failure: Use alfentanil or hydromorphone
Opioid rotation: Good analgesia + intolerable side effects
Elderly: Start low, go slow — higher SE sensitivity
Stewardship: Risk-assess, document, plan taper upfront
══════════════════════════════════════════════════════════════
OPIOID SIDE EFFECTS & MANAGEMENT
──────────────────────────────────────────────────────────────
Constipation → Senna + macrogol (always, from day 1)
Nausea/vomiting → Metoclopramide / ondansetron
Sedation → Reduce dose; review other CNS drugs
Resp. depression → Naloxone 0.1–0.4mg IV/SC
Pruritus → Antihistamine; consider opioid switch
Urinary retention → Bladder scan; catheterise
Myoclonus → Opioid rotation; haloperidol
OPIOID NEUROTOXICITY SIGNS:
Myoclonus • Hallucinations • Peripheral shadows • Confusion • Drowsiness
→ Reduce dose / increase hydration / rotate opioid / involve palliative team
══════════════════════════════════════════════════════════════
NON-PHARMACOLOGICAL (2018 Addition — integrate at every step)
──────────────────────────────────────────────────────────────
• Physiotherapy & rehabilitation
• Psychological therapies (CBT, mindfulness)
• TENS / acupuncture
• Radiotherapy (bone mets, nerve compression)
• Heat / cold therapy
• Relaxation techniques, guided imagery
══════════════════════════════════════════════════════════════
SOURCES: WHO 1986 (rev.1996) • WHO Cancer Pain Guidelines 2018
Thompson J, Curr Opin Support Palliat Care 2024 (PMID 39250736)
Mestdagh F et al., Curr Oncol 2023 (PMID 37504360)
NCCN Adult Cancer Pain v2.2025
FOR CLINICAL REFERENCE ONLY — Individual patient assessment required
══════════════════════════════════════════════════════════════
Make image
A professional, detailed medical clinical reference card poster titled "WHO Pain Management Ladder – Updated 2025". Clean white background, bold colour-coded sections, suitable for hospital wall or pocket card printing. HEADER: Dark navy blue banner. Large bold white title "WHO Pain Management Ladder". Subtitle: "Updated Clinical Reference Card | WHO 2018 Guidelines". Below header: a red alert strip reading "2018 KEY UPDATES: Step 2 can be SKIPPED | Bidirectional use | Opioid Stewardship | Radiotherapy added | Non-pharmacological integrated" FIVE PRINCIPLES ROW (medium blue strip, 5 equal boxes): Box 1: "By Mouth" – oral preferred Box 2: "By the Clock" – fixed intervals Box 3: "By the Ladder" – stepwise Box 4: "Individualise" – titrate per patient Box 5: "Attention to Detail" – monitor SE FOUR STEP COLUMNS (side by side, equal width): STEP 1 – green header: "STEP 1 | MILD PAIN | NRS 1–3 | Non-Opioids" Drugs: Paracetamol 500mg–1g q4–6h | Ibuprofen 400mg q6–8h | Diclofenac 50mg q8h | Celecoxib 100–200mg BD Warning: NSAIDs avoid in CKD/HF | Paracetamol CI in liver failure STEP 2 – orange header: "STEP 2 | MILD–MOD | NRS 4–6 | Weak Opioids ★ CAN BE SKIPPED" Drugs: Codeine 30–60mg q4–6h | Tramadol 50–100mg q4–6h | Co-codamol | Buprenorphine SL Warning: Constipation | Seizure risk (tramadol) STEP 3 – red header: "STEP 3 | MOD–SEVERE | NRS 7–10 | Strong Opioids" Drugs: Morphine IR 2.5–10mg q4h (GOLD STANDARD) | Morphine SR q12h | Oxycodone | Fentanyl patch 25mcg/h q72h | Hydromorphone (renal) Note: Breakthrough = 10–20% of 24h dose | Always prescribe laxatives STEP 4 – purple header: "STEP 4 | REFRACTORY | Any NRS | Interventional + RT" Drugs: Epidural LA ± opioid | Intrathecal pump | Nerve blocks | Spinal cord stimulation | Radiotherapy – bone mets (NEW 2018) | Cordotomy Note: Specialist referral required DIRECTION BANNER (3-colour): Green left: "↑ CHRONIC PAIN: escalate upward" | Blue centre: "↕ REASSESS & de-escalate" | Red right: "↓ ACUTE PAIN: start appropriate step, step down" ADJUVANTS BAR (blue header "ADJUVANTS – Any Step", 4 columns): Neuropathic: Gabapentin | Pregabalin | Amitriptyline | Duloxetine Bone/Inflam: Dexamethasone | Bisphosphonates | Denosumab Nerve Compression: Ketamine | Methadone | Lidocaine Spasm/Other: Baclofen | Clonidine | Diazepam BOTTOM ROW 3 columns: LEFT – NRS table: 0=None | 1–3=Mild Step1 | 4–6=Moderate Step2 | 7–10=Severe Step3/4. Then Non-Pharm list: Physiotherapy | CBT | TENS | Radiotherapy | Heat/Cold CENTRE – Clinical Pearls: Breakthrough=10–20% 24h | Morphine SR=divide 24h÷2 | Fentanyl=12–24h onset q72h | Renal=Alfentanil/Hydromorphone | Opioid rotation if SE | Elderly=start low go slow. Opioid Neurotoxicity: Myoclonus, hallucinations, confusion → rotate opioid RIGHT – Side Effects table: Constipation→Senna+macrogol | Nausea→Metoclopramide | Resp depression→Naloxone 0.4mg | Pruritus→switch opioid | Urinary retention→catheterise. Stewardship: risk-assess, document, plan taper FOOTER (small grey text): WHO 1986/2018 | PMID 39250736 | PMID 37504360 | NCCN 2025 | For Clinical Reference Only
400, message: Got more than 4194304 bytes when reading: b'data: {"candidates": [{"content": {"role": "model","parts": [{"inlineData": {"mimeType": "image/png"...'.
We encountered an error while processing your request. Please try again or reach out to us for help.
Make image
Medical clinical reference card - TOP HALF. Clean white background, professional hospital style. DARK NAVY HEADER: Large bold white text "WHO Pain Management Ladder – Updated 2025". Subtitle in light blue: "WHO 2018 Guidelines + Latest Evidence" RED ALERT BAR below header: white bold text "2018 UPDATES: ✓ Step 2 can be SKIPPED ✓ Bidirectional use ✓ Opioid Stewardship mandatory ✓ Radiotherapy added ✓ Non-pharm integrated" MEDIUM BLUE PRINCIPLES STRIP (5 equal boxes with white text): By Mouth | By the Clock | By the Ladder | Individualise | Attention to Detail FOUR EQUAL STEP COLUMNS: GREEN column – STEP 1: Header "STEP 1 / MILD / NRS 1–3 / Non-Opioids". Drug list: Paracetamol 500mg–1g q4–6h (max 4g/day), Ibuprofen 400mg q6–8h, Diclofenac 50mg q8h, Celecoxib 100–200mg BD. Orange warning text: Avoid NSAIDs in CKD/HF. Blue star: Always add non-pharm therapy. ORANGE column – STEP 2: Header "STEP 2 / MILD-MOD / NRS 4–6 / Weak Opioids". Big star note: "★ 2018: CAN BE SKIPPED". Drugs: Codeine 30–60mg q4–6h, Tramadol 50–100mg q4–6h max 400mg, Co-codamol. Warning: constipation, seizure risk. RED column – STEP 3: Header "STEP 3 / MOD-SEVERE / NRS 7–10 / Strong Opioids". Drugs: Morphine IR 2.5–10mg q4h (GOLD STANDARD), Morphine SR q12h, Oxycodone 5–10mg q4–6h, Fentanyl patch 25mcg/h q72h, Hydromorphone (renal impairment). Key note: Breakthrough = 10–20% of 24h dose. Always prescribe laxatives. PURPLE column – STEP 4: Header "STEP 4 / REFRACTORY / Any NRS / Interventional + RT". Items: Epidural LA±opioid, Intrathecal pump, Nerve blocks (coeliac plexus), Spinal cord stimulation, ★ Radiotherapy – bone mets NEW 2018, Cordotomy. Warning: Specialist referral required. THREE-COLOUR DIRECTION BANNER at bottom: Green left "↑ CHRONIC PAIN: escalate up", Blue centre "↕ REASSESS & de-escalate", Red right "↓ ACUTE PAIN: start high, step down"
Medical clinical reference card - BOTTOM HALF. Clean white background, professional hospital style. This is the continuation of the WHO Pain Ladder card. BLUE ADJUVANTS HEADER BAR: "ADJUVANT ANALGESICS — Use at Any Step — Tailor to Pain Type" Four columns below on light blue background: Neuropathic Pain: Gabapentin 100–300mg TDS, Pregabalin 25–75mg BD, Amitriptyline 10–75mg nocte, Duloxetine 30–60mg OD Bone / Inflammatory: Dexamethasone 4–8mg OD, Bisphosphonates, Denosumab (bone mets), NSAIDs Nerve Compression: Dexamethasone 8–16mg OD, Ketamine (sub-anaesthetic), Methadone (MOR/NMDA), Lidocaine infusion Muscle Spasm / Other: Baclofen 5–10mg TDS, Clonidine (alpha-2), Diazepam 2–5mg TDS, Cannabinoids* THREE COLUMNS BELOW: LEFT COLUMN: NRS PAIN SCALE table with coloured rows: Score 0 = No pain = No analgesia (white) Score 1–3 = Mild = Step 1 (light green) Score 4–6 = Moderate = Step 2 or skip to 3 (light orange) Score 7–10 = Severe = Step 3 or 4 (light red) NON-PHARMACOLOGICAL (2018): • Physiotherapy & rehabilitation • CBT / mindfulness • TENS / acupuncture • Radiotherapy (bone mets) • Heat / cold therapy MIDDLE COLUMN: CLINICAL PEARLS heading in navy blue: Breakthrough: 10–20% of 24h total, q1–4h PRN Morphine SR: divide 24h dose into 2 x 12-hourly Fentanyl patch: 12–24h onset; change q72h Renal failure: prefer alfentanil or hydromorphone Opioid rotation: good analgesia + intolerable SE Elderly: start low go slow; high SE sensitivity OPIOID NEUROTOXICITY in red heading: Signs: myoclonus, hallucinations, confusion, drowsiness Actions: reduce dose / hydrate / rotate opioid / palliative team RIGHT COLUMN: OPIOID SIDE EFFECTS table (navy header, alternating grey rows): Constipation → Senna + macrogol always Nausea → Metoclopramide / ondansetron Sedation → Reduce dose; review CNS drugs Resp. depression → Naloxone 0.1–0.4mg IV/SC Pruritus → Antihistamine; switch opioid Urinary retention → Catheterise OPIOID STEWARDSHIP in blue heading: • Assess pain type; document indication • Risk-stratify (addiction, respiratory) • Plan taper from the outset • Avoid in uncontrolled sleep apnoea FOOTER in small grey text: WHO 1986/2018 Guidelines • PMID 39250736 (Thompson 2024) • PMID 37504360 (Mestdagh 2023) • NCCN Cancer Pain v2.2025 • FOR CLINICAL REFERENCE ONLY


Make image
Professional medical poster. WHO Pain Management Ladder - Steps section. White background. Dark navy blue title bar at top: "WHO PAIN MANAGEMENT LADDER" in large white bold text. Below it in red bar: "WHO 2018 UPDATE: Step 2 can be skipped | Bidirectional | Opioid Stewardship | Radiotherapy added" Blue strip with 5 white boxes: BY MOUTH | BY THE CLOCK | BY THE LADDER | INDIVIDUALISE | ATTENTION TO DETAIL Four tall rectangles side by side showing the 4 steps: Rectangle 1 - Green: "STEP 1" large, "MILD PAIN NRS 1-3" below. Then white box listing: NON-OPIOIDS. Paracetamol 500mg-1g every 4-6h. Ibuprofen 400mg every 6-8h. Diclofenac 50mg every 8h. Celecoxib 100-200mg twice daily. Small warning: Avoid NSAIDs in kidney disease or heart failure. Rectangle 2 - Orange: "STEP 2" large, "MILD-MODERATE NRS 4-6" and star "CAN BE SKIPPED 2018". Then white box: WEAK OPIOIDS. Codeine 30-60mg every 4-6h. Tramadol 50-100mg every 4-6h. Co-codamol tablets. Warning: risk of constipation and seizures. Rectangle 3 - Red: "STEP 3" large, "MODERATE-SEVERE NRS 7-10". Then white box: STRONG OPIOIDS. Morphine 2.5-10mg every 4h GOLD STANDARD. Morphine SR every 12h when stable. Oxycodone 5-10mg every 4-6h. Fentanyl patch 25mcg/h every 72h. Hydromorphone for renal impairment. Breakthrough dose equals 10-20 percent of 24h total. Rectangle 4 - Purple: "STEP 4" large, "REFRACTORY PAIN". Then white box: INTERVENTIONAL and RADIOTHERAPY. Epidural local anaesthetic. Intrathecal pump. Nerve blocks coeliac plexus. Spinal cord stimulation. Radiotherapy for bone metastases NEW 2018. Cordotomy. Specialist referral required. Bottom 3-part banner: green left arrow UP "CHRONIC PAIN escalate upward", blue centre arrows UP and DOWN "REASSESS frequently", red right arrow DOWN "ACUTE PAIN start high step down"
Professional medical reference card section. Clean white background. Hospital clinical style. Section title in dark blue bar: "ADJUVANT ANALGESICS — Use at Any Step" Four equal columns on light blue background: Column 1 heading in blue bold: "Neuropathic Pain" List: Gabapentin 100-300mg three times daily. Pregabalin 25-75mg twice daily. Amitriptyline 10-75mg at night. Duloxetine 30-60mg once daily. Column 2 heading in blue bold: "Bone / Inflammatory" List: Dexamethasone 4-8mg once daily. Bisphosphonates eg zoledronic acid. Denosumab for bone metastases. NSAIDs if tolerated. Column 3 heading in blue bold: "Nerve Compression" List: Dexamethasone 8-16mg once daily. Ketamine sub-anaesthetic dose. Methadone dual MOR and NMDA. Lidocaine infusion. Column 4 heading in blue bold: "Muscle Spasm / Other" List: Baclofen 5-10mg three times daily. Diazepam 2-5mg three times daily. Clonidine central alpha-2. Cannabinoids where available. Below that, a table titled "NRS PAIN SCALE" with coloured rows: Row 1 header dark blue: Score | Severity | WHO Step Row 2 white: 0 | No pain | No analgesia needed Row 3 light green: 1-3 | Mild | Step 1 Row 4 light orange: 4-6 | Moderate | Step 2 or skip to Step 3 Row 5 light red: 7-10 | Severe | Step 3 or Step 4 Then a list titled "NON-PHARMACOLOGICAL THERAPY (Added 2018)": Bullet points: Physiotherapy and rehabilitation. Cognitive behavioural therapy CBT. TENS and acupuncture. Radiotherapy for bone metastases. Heat and cold therapy. Relaxation and guided imagery.
Professional medical reference card. Clean white background. Clinical hospital style. Three columns side by side: LEFT COLUMN titled in navy bold "CLINICAL PEARLS": Breakthrough dose: 10-20 percent of 24h opioid total every 1-4 hours as needed Morphine SR: once pain stable divide total 24h dose into two 12-hourly doses Fentanyl patch: takes 12-24 hours to reach full effect, change every 72 hours Renal failure: prefer alfentanil or hydromorphone, avoid morphine Opioid rotation: consider when good analgesia but intolerable side effects Elderly patients: start low go slow, higher sensitivity to side effects Stewardship: risk-assess, document indication, plan taper from start Below that in red bold heading "OPIOID NEUROTOXICITY SIGNS": Myoclonus, visual hallucinations, confusion, drowsiness, peripheral shadows Management: reduce dose if pain controlled, increase hydration, rotate opioid, involve palliative care team MIDDLE COLUMN titled in navy bold "OPIOID SIDE EFFECTS": Table with alternating grey and white rows: Header dark blue: Side Effect | Management Constipation | Senna plus macrogol always from day one Nausea and vomiting | Metoclopramide or ondansetron Sedation | Reduce dose, review other CNS drugs Respiratory depression | Naloxone 0.1-0.4mg IV or SC Pruritus | Antihistamine, consider opioid switch Urinary retention | Bladder scan then catheterise Myoclonus | Opioid rotation, consider haloperidol RIGHT COLUMN titled in blue bold "OPIOID STEWARDSHIP 2018": Bullet points in blue: Assess pain type before prescribing Document indication, dose and duration Risk-stratify for addiction and respiratory risk Regular review and plan taper from outset Avoid in uncontrolled sleep apnoea Reassess at every consultation Below in dark grey small text footer box: "REFERENCES: WHO Analgesic Ladder 1986 revised 1996. WHO Cancer Pain Guidelines 2018. Thompson J, Curr Opin Support Palliat Care 2024 PMID 39250736. Mestdagh F et al Curr Oncol 2023 PMID 37504360. NCCN Adult Cancer Pain v2.2025. FOR CLINICAL REFERENCE ONLY - Individual patient assessment required."


