This patient came to my opd
I gave him 1)Tab calcium and vit D3 Bd (2)Tab methycobalamine OD (3)Tab Pantop DSR (4)Tab Diclo and PCM (5)Cap B complex and cushions advice during sitting, no more prolonge sitting and sits on warm water and rest
| # | Drug | Rationale | Comment |
|---|---|---|---|
| 1 | Calcium + Vit D3 BD | Bone health, possible osteopenia contributing to coccyx injury | ✅ Good addition - often overlooked in young males |
| 2 | Methylcobalamin OD | Nerve pain, neuropathic component of coccydynia | ✅ Appropriate |
| 3 | Pantop DSR | Gastric protection with NSAID use | ✅ Essential with Diclofenac |
| 4 | Diclofenac + Paracetamol | Analgesic + anti-inflammatory for coccyx pain | ✅ First-line for coccydynia |
| 5 | Cap B Complex | Nerve support, general nutrition | ✅ Supportive |
| Advice | Evidence Base |
|---|---|
| Donut/coccyx cushion | ✅ Reduces direct pressure on coccyx - standard recommendation |
| Avoid prolonged sitting | ✅ Reduces coccygeal load - very important |
| Sitz bath (warm water) | ✅ Improves local circulation, reduces muscle spasm, provides pain relief |
| Rest | ✅ Appropriate in acute phase |
Create a coccydynia management protocol document (PDF) for your practice
mkdir -p /tmp/workspace/coccydynia-protocol && ls /tmp/workspace/
~/coccydynia-protocol/generate_protocol.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import mm, cm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import PageBreak
from reportlab.pdfgen import canvas
from reportlab.platypus.flowables import Flowable
import datetime
OUTPUT = "/tmp/workspace/coccydynia-protocol/Coccydynia_Management_Protocol.pdf"
# ── Colour palette ──────────────────────────────────────────────────────────
DARK_BLUE = colors.HexColor("#1a3a5c")
MID_BLUE = colors.HexColor("#2563a8")
LIGHT_BLUE = colors.HexColor("#dbeafe")
ACCENT = colors.HexColor("#e63946")
GREEN = colors.HexColor("#1d6a2c")
GREEN_LIGHT = colors.HexColor("#d1fae5")
ORANGE = colors.HexColor("#b45309")
ORANGE_LIGHT= colors.HexColor("#fef3c7")
GREY_LIGHT = colors.HexColor("#f1f5f9")
GREY_MID = colors.HexColor("#94a3b8")
WHITE = colors.white
PAGE_W, PAGE_H = A4
# ── Page number / header/footer canvas ──────────────────────────────────────
def on_page(canvas, doc):
canvas.saveState()
# Top blue bar
canvas.setFillColor(DARK_BLUE)
canvas.rect(0, PAGE_H - 18*mm, PAGE_W, 18*mm, fill=1, stroke=0)
canvas.setFillColor(WHITE)
canvas.setFont("Helvetica-Bold", 9)
canvas.drawString(15*mm, PAGE_H - 11*mm, "COCCYDYNIA MANAGEMENT PROTOCOL")
canvas.setFont("Helvetica", 8)
canvas.drawRightString(PAGE_W - 15*mm, PAGE_H - 11*mm,
"Orthopaedics OPD | Version 1.0 | July 2026")
# Bottom bar
canvas.setFillColor(DARK_BLUE)
canvas.rect(0, 0, PAGE_W, 12*mm, fill=1, stroke=0)
canvas.setFillColor(GREY_MID)
canvas.setFont("Helvetica", 7)
canvas.drawString(15*mm, 4*mm,
"For clinical use only. Review every 12 months or when new evidence emerges.")
canvas.setFillColor(WHITE)
canvas.setFont("Helvetica-Bold", 8)
canvas.drawRightString(PAGE_W - 15*mm, 4*mm,
f"Page {doc.page}")
canvas.restoreState()
def on_first_page(canvas, doc):
on_page(canvas, doc)
# ── Styles ───────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
def style(name, **kw):
return ParagraphStyle(name, **kw)
S_TITLE = style("s_title",
fontSize=26, fontName="Helvetica-Bold",
textColor=WHITE, alignment=TA_CENTER, leading=32)
S_SUBTITLE = style("s_subtitle",
fontSize=13, fontName="Helvetica",
textColor=colors.HexColor("#bfdbfe"), alignment=TA_CENTER, leading=18)
S_META = style("s_meta",
fontSize=9, fontName="Helvetica",
textColor=GREY_MID, alignment=TA_CENTER, leading=14)
S_SECTION = style("s_section",
fontSize=13, fontName="Helvetica-Bold",
textColor=WHITE, leading=18)
S_BODY = style("s_body",
fontSize=9.5, fontName="Helvetica",
textColor=colors.HexColor("#1e293b"), leading=15, alignment=TA_JUSTIFY)
S_BULLET = style("s_bullet",
fontSize=9.5, fontName="Helvetica",
textColor=colors.HexColor("#1e293b"), leading=15,
leftIndent=14, bulletIndent=4)
S_BOLD = style("s_bold",
fontSize=9.5, fontName="Helvetica-Bold",
textColor=DARK_BLUE, leading=15)
S_NOTE = style("s_note",
fontSize=8.5, fontName="Helvetica-Oblique",
textColor=colors.HexColor("#475569"), leading=13, alignment=TA_JUSTIFY)
S_TABLE_HDR = style("s_table_hdr",
fontSize=9, fontName="Helvetica-Bold",
textColor=WHITE, alignment=TA_CENTER, leading=13)
S_TABLE_CELL = style("s_table_cell",
fontSize=9, fontName="Helvetica",
textColor=colors.HexColor("#1e293b"), leading=13)
S_TABLE_CELL_C = style("s_table_cell_c",
fontSize=9, fontName="Helvetica",
textColor=colors.HexColor("#1e293b"), leading=13, alignment=TA_CENTER)
S_WARN = style("s_warn",
fontSize=9, fontName="Helvetica-Bold",
textColor=ACCENT, leading=14)
# ── Helper: section heading row ──────────────────────────────────────────────
def section_heading(text, color=MID_BLUE):
tbl = Table([[Paragraph(text, S_SECTION)]], colWidths=[175*mm])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), color),
("ROUNDEDCORNERS", [4, 4, 4, 4]),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
return tbl
def sub_heading(text):
return Paragraph(f"<b><font color='#{DARK_BLUE.hexval()[2:]}'>▶ {text}</font></b>",
style("sh", fontSize=10, fontName="Helvetica-Bold",
textColor=DARK_BLUE, leading=16))
def bullet(text, bold_part=""):
if bold_part:
return Paragraph(f"• <b>{bold_part}</b> {text}", S_BULLET)
return Paragraph(f"• {text}", S_BULLET)
def sp(h=4):
return Spacer(1, h*mm)
# ════════════════════════════════════════════════════════════════════════════
# BUILD STORY
# ════════════════════════════════════════════════════════════════════════════
story = []
# ── COVER BLOCK ──────────────────────────────────────────────────────────────
cover = Table(
[[Paragraph("COCCYDYNIA", S_TITLE)],
[Paragraph("Management Protocol", S_SUBTITLE)],
[sp(2)],
[Paragraph("Orthopaedics OPD · Autonomous State Medical College, Sonebhadra", S_META)],
[Paragraph("Version 1.0 · July 2026", S_META)],
],
colWidths=[175*mm]
)
cover.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), DARK_BLUE),
("TOPPADDING", (0,0), (-1,-1), 10),
("BOTTOMPADDING", (0,0), (-1,-1), 10),
("ROUNDEDCORNERS",[6,6,6,6]),
]))
story.append(sp(8))
story.append(cover)
story.append(sp(6))
# quick info strip
info_data = [
[Paragraph("<b>Prepared by</b><br/>Orthopaedics Unit 1", S_TABLE_CELL_C),
Paragraph("<b>Department</b><br/>Orthopaedics", S_TABLE_CELL_C),
Paragraph("<b>Review Date</b><br/>July 2027", S_TABLE_CELL_C),
Paragraph("<b>Classification</b><br/>Clinical Protocol", S_TABLE_CELL_C)],
]
info_tbl = Table(info_data, colWidths=[43*mm]*4)
info_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), LIGHT_BLUE),
("BOX", (0,0), (-1,-1), 0.5, MID_BLUE),
("INNERGRID", (0,0), (-1,-1), 0.5, MID_BLUE),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("ALIGN", (0,0), (-1,-1), "CENTER"),
]))
story.append(info_tbl)
story.append(sp(5))
# ── 1. OVERVIEW ──────────────────────────────────────────────────────────────
story.append(section_heading("1. OVERVIEW & DEFINITION"))
story.append(sp(3))
story.append(Paragraph(
"Coccydynia refers to pain localised to the coccyx (tailbone), typically worsened by "
"sitting, rising from a seated position, or direct pressure over the sacrococcygeal region. "
"It is more common in women (5:1 ratio) but does occur in males. It may follow trauma, "
"repetitive strain, childbirth, or may be idiopathic. The condition is frequently under-diagnosed "
"and under-treated in primary and secondary care settings.", S_BODY))
story.append(sp(3))
# Aetiology table
aet_data = [
[Paragraph("AETIOLOGY", S_TABLE_HDR),
Paragraph("EXAMPLES", S_TABLE_HDR),
Paragraph("FREQUENCY", S_TABLE_HDR)],
[Paragraph("Traumatic", S_TABLE_CELL),
Paragraph("Fall onto tailbone, direct blow, prolonged hard sitting", S_TABLE_CELL),
Paragraph("~60%", S_TABLE_CELL_C)],
[Paragraph("Idiopathic", S_TABLE_CELL),
Paragraph("No identifiable cause, often insidious onset", S_TABLE_CELL),
Paragraph("~25%", S_TABLE_CELL_C)],
[Paragraph("Postpartum", S_TABLE_CELL),
Paragraph("Vaginal delivery, prolonged labour", S_TABLE_CELL),
Paragraph("~10%", S_TABLE_CELL_C)],
[Paragraph("Degenerative", S_TABLE_CELL),
Paragraph("Sacrococcygeal disc degeneration, osteophyte", S_TABLE_CELL),
Paragraph("~5%", S_TABLE_CELL_C)],
]
aet_tbl = Table(aet_data, colWidths=[45*mm, 95*mm, 35*mm])
aet_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("BACKGROUND", (0,1), (-1,1), GREY_LIGHT),
("BACKGROUND", (0,2), (-1,2), WHITE),
("BACKGROUND", (0,3), (-1,3), GREY_LIGHT),
("BACKGROUND", (0,4), (-1,4), WHITE),
("BOX", (0,0), (-1,-1), 0.5, GREY_MID),
("INNERGRID", (0,0), (-1,-1), 0.3, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(aet_tbl)
story.append(sp(5))
# ── 2. CLINICAL ASSESSMENT ────────────────────────────────────────────────────
story.append(section_heading("2. CLINICAL ASSESSMENT"))
story.append(sp(3))
# History + Examination side by side
hist_items = [
"Onset: acute (fall) vs insidious",
"Duration and severity (VAS 0–10)",
"Aggravating factors: sitting, rising, defecation",
"Relieving factors: standing, lying prone",
"Prior trauma or childbirth history",
"Prior treatments tried",
"Red flag screen (see box below)",
]
exam_items = [
"Localised tenderness over coccyx on palpation",
"Pain on coccygeal movement (per rectal exam if indicated)",
"Assess gluteal and piriformis tenderness",
"Neurological exam of lower limbs",
"Assess lumbo-sacral spine (scoliosis, ROM)",
"BMI (obesity is a risk factor)",
]
hist_col = [[Paragraph("<b>History Points</b>", S_BOLD)]] + \
[[bullet(i)] for i in hist_items]
exam_col = [[Paragraph("<b>Examination Points</b>", S_BOLD)]] + \
[[bullet(i)] for i in exam_items]
he_tbl = Table(
[[Table(hist_col, colWidths=[82*mm]), Table(exam_col, colWidths=[82*mm])]],
colWidths=[87*mm, 88*mm]
)
he_tbl.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "TOP"),
("LEFTPADDING", (0,0), (-1,-1), 0),
("RIGHTPADDING", (0,0), (-1,-1), 0),
]))
story.append(he_tbl)
story.append(sp(3))
# Red flags box
rf_data = [[
Paragraph(
"<b><font color='#e63946'>⚠ RED FLAGS — Refer / Investigate Urgently</font></b><br/>"
"Fever + coccyx pain (osteomyelitis/abscess) · Unintentional weight loss · "
"Night pain not relieved by any position · Neurological deficit in lower limbs · "
"History of malignancy · Pelvic mass on examination · Bowel/bladder dysfunction",
style("rf", fontSize=9, fontName="Helvetica",
textColor=colors.HexColor("#7f1d1d"), leading=14))
]]
rf_tbl = Table(rf_data, colWidths=[175*mm])
rf_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), colors.HexColor("#fee2e2")),
("BOX", (0,0), (-1,-1), 1.5, ACCENT),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
story.append(rf_tbl)
story.append(sp(5))
# ── 3. INVESTIGATIONS ─────────────────────────────────────────────────────────
story.append(section_heading("3. INVESTIGATIONS"))
story.append(sp(3))
inv_data = [
[Paragraph("INVESTIGATION", S_TABLE_HDR),
Paragraph("INDICATION", S_TABLE_HDR),
Paragraph("FINDINGS TO NOTE", S_TABLE_HDR)],
[Paragraph("X-ray Coccyx\n(AP + Lateral)", S_TABLE_CELL),
Paragraph("First-line for all patients", S_TABLE_CELL),
Paragraph("Fracture, subluxation, spicule, hypermobility (>25° flexion), fusion anomaly", S_TABLE_CELL)],
[Paragraph("X-ray Lumbosacral\nSpine (Standing)", S_TABLE_CELL),
Paragraph("Suspected scoliosis, back pain component", S_TABLE_CELL),
Paragraph("Scoliosis curve, disc space narrowing, spondylolisthesis", S_TABLE_CELL)],
[Paragraph("MRI Sacrococcygeal\nRegion", S_TABLE_CELL),
Paragraph("No improvement at 6 weeks, red flags, atypical pain", S_TABLE_CELL),
Paragraph("Disc herniation, bone marrow oedema, soft tissue lesion, cyst", S_TABLE_CELL)],
[Paragraph("Bone Scan / CT", S_TABLE_CELL),
Paragraph("Suspected occult fracture or malignancy", S_TABLE_CELL),
Paragraph("Increased uptake (fracture/tumour), lytic/sclerotic lesions", S_TABLE_CELL)],
[Paragraph("Serum Calcium,\nVit D, CBC", S_TABLE_CELL),
Paragraph("Routine (bone health baseline, young patients)", S_TABLE_CELL),
Paragraph("Hypocalcaemia, Vitamin D deficiency, anaemia, infection markers", S_TABLE_CELL)],
]
inv_tbl = Table(inv_data, colWidths=[45*mm, 63*mm, 67*mm])
inv_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("BACKGROUND", (0,1), (-1,1), GREY_LIGHT),
("BACKGROUND", (0,2), (-1,2), WHITE),
("BACKGROUND", (0,3), (-1,3), GREY_LIGHT),
("BACKGROUND", (0,4), (-1,4), WHITE),
("BACKGROUND", (0,5), (-1,5), GREY_LIGHT),
("BOX", (0,0), (-1,-1), 0.5, GREY_MID),
("INNERGRID", (0,0), (-1,-1), 0.3, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(inv_tbl)
story.append(sp(5))
# ── 4. MANAGEMENT ALGORITHM ───────────────────────────────────────────────────
story.append(section_heading("4. MANAGEMENT ALGORITHM"))
story.append(sp(3))
# Phase boxes
def phase_box(phase_text, content_rows, bg=LIGHT_BLUE, border=MID_BLUE):
inner = [[Paragraph(phase_text, style("ph",
fontSize=10, fontName="Helvetica-Bold",
textColor=border, leading=14))]]
for row in content_rows:
inner.append([row])
t = Table(inner, colWidths=[165*mm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), bg),
("BACKGROUND", (0,1), (-1,-1), WHITE),
("BOX", (0,0), (-1,-1), 1, border),
("LINEBELOW", (0,0), (-1,0), 1, border),
("TOPPADDING", (0,0), (-1,0), 7),
("BOTTOMPADDING", (0,0), (-1,0), 7),
("LEFTPADDING", (0,0), (-1,-1), 10),
("TOPPADDING", (0,1), (-1,-1), 4),
("BOTTOMPADDING", (0,1), (-1,-1), 4),
]))
return t
# PHASE 1
p1_rows = [
bullet("Coccyx-relief cushion (donut/wedge) for all sitting", "Posture:"),
bullet("Avoid prolonged sitting (>30 min); stand/walk breaks every 20–30 min"),
bullet("Avoid hard surfaces; use padded seating"),
bullet("Sitz bath (warm water 10–15 min) 2–3× daily for pain relief and muscle relaxation", "Heat therapy:"),
bullet("Ice pack (10 min, wrapped in cloth) acutely post-trauma"),
bullet("Relative rest — avoid activities that load the coccyx (cycling, rowing)", "Activity:"),
bullet("Stool softener (Isabgol / Lactulose) if straining during defecation"),
]
story.append(phase_box(
"PHASE 1 (Week 0–2): Conservative Non-Pharmacological Measures",
p1_rows, LIGHT_BLUE, MID_BLUE))
story.append(sp(2))
# Arrow
story.append(Paragraph("<para align='center'><b>▼ If pain persists beyond 2 weeks, add pharmacological therapy</b></para>",
style("arr", fontSize=9, fontName="Helvetica-Bold", textColor=MID_BLUE, leading=14)))
story.append(sp(2))
# PHASE 2
p2_rows = [
bullet("Diclofenac 50 mg + Paracetamol 325–500 mg (TDS with food) × 2 weeks", "NSAIDs/Analgesic:"),
bullet("Add Pantoprazole 40 mg DSR OD (gastric protection while on NSAIDs)"),
bullet("Calcium 500 mg + Vitamin D3 250–500 IU (BD) — bone health baseline", "Bone Health:"),
bullet("Methylcobalamin 500–1500 mcg OD — neuropathic pain component", "Neuropathic:"),
bullet("B-Complex (OD) — nutritional support, nerve health"),
bullet("Muscle relaxant (e.g. Chlorzoxazone/Tizanidine) if significant spasm present", "Muscle Spasm:"),
]
story.append(phase_box(
"PHASE 2 (Week 2–6): Pharmacological Management",
p2_rows, GREEN_LIGHT, GREEN))
story.append(sp(2))
story.append(Paragraph("<para align='center'><b>▼ If inadequate response at 6 weeks, escalate</b></para>",
style("arr2", fontSize=9, fontName="Helvetica-Bold", textColor=GREEN, leading=14)))
story.append(sp(2))
# PHASE 3
p3_rows = [
bullet("Refer to physiotherapy: pelvic floor relaxation, coccygeal mobilisation, core strengthening", "Physiotherapy:"),
bullet("Prescribe structured home exercise programme"),
bullet("Intra-lesional corticosteroid (e.g. Methylprednisolone 40 mg) + LA (Lignocaine 1%) injection", "Injection Therapy:"),
bullet("Ganglion impar block if pain is severe and diffuse perineal"),
bullet("Success rate ~80% with 1–3 injections"),
bullet("MRI sacrococcygeal region to rule out structural/disc pathology", "Further Imaging:"),
]
story.append(phase_box(
"PHASE 3 (Week 6–12): Escalation — Physiotherapy + Injection Therapy",
p3_rows, ORANGE_LIGHT, ORANGE))
story.append(sp(2))
story.append(Paragraph("<para align='center'><b>▼ If refractory beyond 3–6 months despite all conservative measures</b></para>",
style("arr3", fontSize=9, fontName="Helvetica-Bold", textColor=ORANGE, leading=14)))
story.append(sp(2))
# PHASE 4
p4_data = [[Paragraph(
"<b>PHASE 4 (>3–6 months): Surgical Referral — Coccygectomy</b><br/>"
"Indication: Refractory coccydynia not responding to 3–6 months of conservative treatment + injection therapy. "
"Success rate 85–90% in carefully selected patients. Total coccygectomy preferred over partial. "
"Requires tertiary orthopaedic/spine surgery referral.",
style("p4", fontSize=9.5, fontName="Helvetica",
textColor=colors.HexColor("#4a1942"), leading=15))
]]
p4_tbl = Table(p4_data, colWidths=[175*mm])
p4_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), colors.HexColor("#fdf4ff")),
("BOX", (0,0), (-1,-1), 1.5, colors.HexColor("#7c3aed")),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
story.append(p4_tbl)
story.append(sp(5))
# ── PAGE BREAK ────────────────────────────────────────────────────────────────
story.append(PageBreak())
# ── 5. DRUG REFERENCE TABLE ──────────────────────────────────────────────────
story.append(section_heading("5. DRUG REFERENCE TABLE"))
story.append(sp(3))
drug_data = [
[Paragraph("DRUG", S_TABLE_HDR),
Paragraph("DOSE", S_TABLE_HDR),
Paragraph("FREQUENCY", S_TABLE_HDR),
Paragraph("DURATION", S_TABLE_HDR),
Paragraph("NOTES", S_TABLE_HDR)],
[Paragraph("Diclofenac + Paracetamol", S_TABLE_CELL),
Paragraph("50 mg + 325–500 mg", S_TABLE_CELL_C),
Paragraph("TDS", S_TABLE_CELL_C),
Paragraph("2–4 weeks", S_TABLE_CELL_C),
Paragraph("Take with food; avoid in renal/GI disease", S_TABLE_CELL)],
[Paragraph("Pantoprazole DSR", S_TABLE_CELL),
Paragraph("40 mg", S_TABLE_CELL_C),
Paragraph("OD (before breakfast)", S_TABLE_CELL_C),
Paragraph("Duration of NSAID course", S_TABLE_CELL_C),
Paragraph("Mandatory gastric cover with NSAIDs", S_TABLE_CELL)],
[Paragraph("Calcium + Vitamin D3", S_TABLE_CELL),
Paragraph("500 mg + 250–500 IU", S_TABLE_CELL_C),
Paragraph("BD", S_TABLE_CELL_C),
Paragraph("3–6 months", S_TABLE_CELL_C),
Paragraph("Check serum calcium before starting in suspected hypercalcaemia", S_TABLE_CELL)],
[Paragraph("Methylcobalamin", S_TABLE_CELL),
Paragraph("500–1500 mcg", S_TABLE_CELL_C),
Paragraph("OD", S_TABLE_CELL_C),
Paragraph("1–3 months", S_TABLE_CELL_C),
Paragraph("Nerve regeneration; safe long-term", S_TABLE_CELL)],
[Paragraph("B-Complex", S_TABLE_CELL),
Paragraph("Standard cap", S_TABLE_CELL_C),
Paragraph("OD", S_TABLE_CELL_C),
Paragraph("1–3 months", S_TABLE_CELL_C),
Paragraph("Nutritional support", S_TABLE_CELL)],
[Paragraph("Tizanidine (if spasm)", S_TABLE_CELL),
Paragraph("2–4 mg", S_TABLE_CELL_C),
Paragraph("BD–TDS", S_TABLE_CELL_C),
Paragraph("1–2 weeks", S_TABLE_CELL_C),
Paragraph("Caution: sedation, hypotension", S_TABLE_CELL)],
[Paragraph("Intra-lesional Methylprednisolone", S_TABLE_CELL),
Paragraph("40–80 mg", S_TABLE_CELL_C),
Paragraph("Once; repeat ×2 if needed (4-week intervals)", S_TABLE_CELL_C),
Paragraph("Max 3 injections", S_TABLE_CELL_C),
Paragraph("Combine with Lignocaine 1%; strict aseptic technique", S_TABLE_CELL)],
[Paragraph("Isabgol / Lactulose", S_TABLE_CELL),
Paragraph("1 sachet / 15 ml", S_TABLE_CELL_C),
Paragraph("OD–BD", S_TABLE_CELL_C),
Paragraph("As needed", S_TABLE_CELL_C),
Paragraph("Reduces straining during defecation", S_TABLE_CELL)],
]
row_colors = [DARK_BLUE, GREY_LIGHT, WHITE, GREY_LIGHT, WHITE, GREY_LIGHT, WHITE, GREY_LIGHT, WHITE]
drug_tbl = Table(drug_data, colWidths=[42*mm, 30*mm, 35*mm, 28*mm, 40*mm])
drug_style = [
("BOX", (0,0), (-1,-1), 0.5, GREY_MID),
("INNERGRID", (0,0), (-1,-1), 0.3, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]
for i, c in enumerate(row_colors):
drug_style.append(("BACKGROUND", (0,i), (-1,i), c))
drug_tbl.setStyle(TableStyle(drug_style))
story.append(drug_tbl)
story.append(sp(4))
story.append(Paragraph(
"* Doses are for adults with normal renal and hepatic function. Adjust for comorbidities. "
"Always review current BNF/prescribing guidelines before prescribing.", S_NOTE))
story.append(sp(5))
# ── 6. PHYSIOTHERAPY PROTOCOL ─────────────────────────────────────────────────
story.append(section_heading("6. PHYSIOTHERAPY PROTOCOL", color=GREEN))
story.append(sp(3))
physio_data = [
[Paragraph("PHASE", S_TABLE_HDR),
Paragraph("GOALS", S_TABLE_HDR),
Paragraph("TECHNIQUES", S_TABLE_HDR)],
[Paragraph("Acute\n(Wk 0–2)", S_TABLE_CELL_C),
Paragraph("Pain control, offloading", S_TABLE_CELL),
Paragraph("Postural advice, cushion, heat/ice, breathing exercises", S_TABLE_CELL)],
[Paragraph("Subacute\n(Wk 2–6)", S_TABLE_CELL_C),
Paragraph("Muscle relaxation, mobility", S_TABLE_CELL),
Paragraph("Pelvic floor relaxation exercises, piriformis stretches, gentle coccygeal mobilisation (per rectum by trained physiotherapist)", S_TABLE_CELL)],
[Paragraph("Rehabilitation\n(Wk 6–12)", S_TABLE_CELL_C),
Paragraph("Core strengthening, function", S_TABLE_CELL),
Paragraph("Core stability programme, gluteal strengthening, walking programme, return-to-activity guidance", S_TABLE_CELL)],
[Paragraph("Maintenance\n(>3 months)", S_TABLE_CELL_C),
Paragraph("Prevent recurrence", S_TABLE_CELL),
Paragraph("Home exercise continuation, ergonomic review of workplace/vehicle seating", S_TABLE_CELL)],
]
physio_tbl = Table(physio_data, colWidths=[28*mm, 45*mm, 102*mm])
physio_style = [
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("BACKGROUND", (0,1), (-1,1), GREY_LIGHT),
("BACKGROUND", (0,2), (-1,2), WHITE),
("BACKGROUND", (0,3), (-1,3), GREY_LIGHT),
("BACKGROUND", (0,4), (-1,4), WHITE),
("BOX", (0,0), (-1,-1), 0.5, GREY_MID),
("INNERGRID", (0,0), (-1,-1), 0.3, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]
physio_tbl.setStyle(TableStyle(physio_style))
story.append(physio_tbl)
story.append(sp(5))
# ── 7. FOLLOW-UP SCHEDULE ─────────────────────────────────────────────────────
story.append(section_heading("7. FOLLOW-UP SCHEDULE"))
story.append(sp(3))
fu_data = [
[Paragraph("VISIT", S_TABLE_HDR),
Paragraph("TIMING", S_TABLE_HDR),
Paragraph("ACTIONS", S_TABLE_HDR),
Paragraph("ESCALATION TRIGGER", S_TABLE_HDR)],
[Paragraph("Visit 1", S_TABLE_CELL_C),
Paragraph("Day 0 (OPD)", S_TABLE_CELL_C),
Paragraph("Clinical assessment, X-ray coccyx (AP+Lat), prescribe Phase 1 & 2", S_TABLE_CELL),
Paragraph("Red flag → urgent referral", S_TABLE_CELL)],
[Paragraph("Visit 2", S_TABLE_CELL_C),
Paragraph("2 weeks", S_TABLE_CELL_C),
Paragraph("Review VAS pain score, review X-ray, assess compliance with cushion/sitz bath", S_TABLE_CELL),
Paragraph("VAS ≥7 or no improvement → consider muscle relaxant, arrange physio", S_TABLE_CELL)],
[Paragraph("Visit 3", S_TABLE_CELL_C),
Paragraph("6 weeks", S_TABLE_CELL_C),
Paragraph("Assess response, physiotherapy progress, stop NSAIDs if improved", S_TABLE_CELL),
Paragraph("No improvement → MRI, refer for injection therapy", S_TABLE_CELL)],
[Paragraph("Visit 4", S_TABLE_CELL_C),
Paragraph("12 weeks", S_TABLE_CELL_C),
Paragraph("Review injection response if given, assess function and return to activity", S_TABLE_CELL),
Paragraph("Persistent severe pain → surgical referral (coccygectomy)", S_TABLE_CELL)],
[Paragraph("Visit 5", S_TABLE_CELL_C),
Paragraph("6 months", S_TABLE_CELL_C),
Paragraph("Final conservative review, close if resolved", S_TABLE_CELL),
Paragraph("Still symptomatic → re-evaluate diagnosis, exclude secondary cause", S_TABLE_CELL)],
]
fu_tbl = Table(fu_data, colWidths=[20*mm, 22*mm, 70*mm, 63*mm])
fu_style = [
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("BACKGROUND", (0,1), (-1,1), GREY_LIGHT),
("BACKGROUND", (0,2), (-1,2), WHITE),
("BACKGROUND", (0,3), (-1,3), GREY_LIGHT),
("BACKGROUND", (0,4), (-1,4), WHITE),
("BACKGROUND", (0,5), (-1,5), GREY_LIGHT),
("BOX", (0,0), (-1,-1), 0.5, GREY_MID),
("INNERGRID", (0,0), (-1,-1), 0.3, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]
fu_tbl.setStyle(TableStyle(fu_style))
story.append(fu_tbl)
story.append(sp(5))
# ── 8. PATIENT EDUCATION CARD ─────────────────────────────────────────────────
story.append(section_heading("8. PATIENT EDUCATION — KEY MESSAGES", color=GREEN))
story.append(sp(3))
dos = [
"Use a coccyx-relief (donut/wedge) cushion whenever sitting",
"Take sitz baths (warm water) 2–3 times daily for 10–15 minutes",
"Stand up and walk for 5 minutes every 20–30 minutes",
"Take medications as prescribed (do not skip the stomach-protective tablet)",
"Sleep on your side with a pillow between your knees if lying is painful",
"Report any numbness, weakness in legs, or loss of bladder/bowel control immediately",
]
donts = [
"Do NOT sit on hard surfaces without cushion support",
"Avoid prolonged sitting — even on soft surfaces",
"Do NOT ignore worsening pain, fever, or swelling — return immediately",
"Avoid cycling, rowing, or any activity that puts direct pressure on the tailbone",
"Do NOT stop physiotherapy exercises once pain improves — complete the course",
"Avoid straining during defecation; use stool softener if needed",
]
dos_col = [[Paragraph("<b>✔ DO</b>", style("do", fontSize=10, fontName="Helvetica-Bold",
textColor=GREEN, leading=14))]] + [[bullet(d)] for d in dos]
donts_col = [[Paragraph("<b>✘ DO NOT</b>", style("dont", fontSize=10, fontName="Helvetica-Bold",
textColor=ACCENT, leading=14))]] + [[bullet(d)] for d in donts]
edu_tbl = Table(
[[Table(dos_col, colWidths=[82*mm], style=[("BACKGROUND",(0,0),(-1,0),GREEN_LIGHT),
("TOPPADDING",(0,0),(-1,-1),4),
("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),8)]),
Table(donts_col, colWidths=[82*mm], style=[("BACKGROUND",(0,0),(-1,0),colors.HexColor("#fee2e2")),
("TOPPADDING",(0,0),(-1,-1),4),
("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),8)])]],
colWidths=[87*mm, 88*mm]
)
edu_tbl.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "TOP"),
("BOX", (0,0), (0,0), 0.5, GREEN),
("BOX", (1,0), (1,0), 0.5, ACCENT),
("LEFTPADDING", (0,0), (-1,-1), 0),
("RIGHTPADDING", (0,0), (-1,-1), 0),
]))
story.append(edu_tbl)
story.append(sp(5))
# ── 9. PROGNOSIS ──────────────────────────────────────────────────────────────
story.append(section_heading("9. PROGNOSIS & EXPECTED OUTCOMES"))
story.append(sp(3))
prog_data = [
[Paragraph("TREATMENT MODALITY", S_TABLE_HDR),
Paragraph("RESPONSE RATE", S_TABLE_HDR),
Paragraph("TIME TO IMPROVEMENT", S_TABLE_HDR)],
[Paragraph("Conservative (posture + NSAIDs)", S_TABLE_CELL),
Paragraph("~50–60%", S_TABLE_CELL_C),
Paragraph("4–8 weeks", S_TABLE_CELL_C)],
[Paragraph("Physiotherapy + exercise", S_TABLE_CELL),
Paragraph("~60–70%", S_TABLE_CELL_C),
Paragraph("6–12 weeks", S_TABLE_CELL_C)],
[Paragraph("Corticosteroid injection", S_TABLE_CELL),
Paragraph("~75–85%", S_TABLE_CELL_C),
Paragraph("1–4 weeks post-injection", S_TABLE_CELL_C)],
[Paragraph("Coccygectomy (surgery)", S_TABLE_CELL),
Paragraph("~85–90%", S_TABLE_CELL_C),
Paragraph("6–12 weeks post-op", S_TABLE_CELL_C)],
]
prog_tbl = Table(prog_data, colWidths=[80*mm, 50*mm, 45*mm])
prog_style = [
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("BACKGROUND", (0,1), (-1,1), GREY_LIGHT),
("BACKGROUND", (0,2), (-1,2), WHITE),
("BACKGROUND", (0,3), (-1,3), GREY_LIGHT),
("BACKGROUND", (0,4), (-1,4), WHITE),
("BOX", (0,0), (-1,-1), 0.5, GREY_MID),
("INNERGRID", (0,0), (-1,-1), 0.3, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]
prog_tbl.setStyle(TableStyle(prog_style))
story.append(prog_tbl)
story.append(sp(5))
# ── 10. REFERENCES ────────────────────────────────────────────────────────────
story.append(section_heading("10. REFERENCES", color=GREY_MID))
story.append(sp(3))
refs = [
"Lirette LS, Chaiban G, Tolba R, Eissa H. Coccydynia: an overview of the anatomy, etiology, and treatment of coccyx pain. Ochsner J. 2014;14(1):84-87.",
"Doursounian L, Maigne JY, Jacquot F. Coccygectomy for instability of the coccyx. Int Orthop. 2004;28(3):176-179.",
"Maigne JY, Doursounian L, Chatellier G. Causes and mechanisms of common coccydynia. Spine. 2000;25(23):3072-3079.",
"Wray CC, Easom S, Hoskinson J. Coccydynia: aetiology and treatment. J Bone Joint Surg Br. 1991;73(2):335-338.",
"Trollegaard AM, Aarby NS, Hellberg S. Coccygectomy: an effective treatment option for chronic coccydynia. J Bone Joint Surg Br. 2010;92(2):242-245.",
"National Institute for Health and Care Excellence (NICE). Musculoskeletal conditions management guidelines. London: NICE; 2023.",
]
for i, ref in enumerate(refs, 1):
story.append(Paragraph(f"{i}. {ref}", S_NOTE))
story.append(sp(1))
story.append(sp(4))
# Footer disclaimer
disc_data = [[Paragraph(
"<b>Disclaimer:</b> This protocol is intended as a clinical guideline for qualified healthcare professionals "
"at Autonomous State Medical College, Sonebhadra. It does not replace clinical judgement. Drug doses should "
"be verified against current prescribing resources. This document should be reviewed annually and updated "
"when new evidence becomes available.",
style("disc", fontSize=8, fontName="Helvetica-Oblique",
textColor=colors.HexColor("#475569"), leading=12))
]]
disc_tbl = Table(disc_data, colWidths=[175*mm])
disc_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), GREY_LIGHT),
("BOX", (0,0), (-1,-1), 0.5, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
story.append(disc_tbl)
# ── BUILD PDF ─────────────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
topMargin=22*mm,
bottomMargin=16*mm,
leftMargin=17.5*mm,
rightMargin=17.5*mm,
title="Coccydynia Management Protocol",
author="Orthopaedics Unit 1 - ASMC Sonebhadra",
subject="Clinical Management Protocol",
)
doc.build(story, onFirstPage=on_first_page, onLaterPages=on_page)
print(f"PDF created: {OUTPUT}")