Posterior approach to elbow in orthopaedics 10 marks pg answer with flow chart and images
| Structure | Relevance |
|---|---|
| Triceps tendon | Main obstacle; must be reflected, split, or detached to enter the joint |
| Ulnar nerve | Runs in the cubital tunnel (medial epicondyle groove); at risk in ALL posterior approaches |
| Olecranon | Blocks direct joint access; may be osteotomized for maximum exposure |
| Anconeus | Lateral landmark; reflects subperiosteally to expose radial head |
| Radial nerve | Limits proximal extension along humerus |
POSTERIOR APPROACH TO ELBOW
|
▼
What is the surgical need?
|
┌──────┴──────────────────────┐
| |
Maximum articular Triceps preservation
exposure needed (elbow arthroplasty,
(intraarticular elderly, soft tissue)
fractures, ORIF)
| |
▼ ▼
OLECRANON OSTEOTOMY EXTENSILE (BRYAN-MORREY)
(MacAusland & Müller) APPROACH
- Chevron osteotomy - Triceps reflected as
at bare zone one unit medial→lateral
- Best articular access - Ulnar nerve transposed
- Tension band/lag - No olecranon division
screw fixation |
▼
Also consider:
┌───────────┴──────────┐
TRICEPS SPLITTING PARATRICIPITAL
(midline split, (Triceps SLIDE)
olecranon intact) Elevate off
intermuscular septa






| Variant | Interval | Key Feature |
|---|---|---|
| Triceps Splitting | Midline split of triceps | Olecranon intact; limited exposure |
| Paratricipital (Triceps Slide) | Triceps elevated off medial + lateral intermuscular septa | Triceps insertion undisturbed; mobilized either direction |
| Structure | Mechanism of Injury |
|---|---|
| Ulnar nerve | Direct injury during dissection; excessive retraction; most common complication |
| Radial nerve | Limits proximal extension along the humerus |
| Triceps mechanism | Over-tension during reflection (Bryan-Morrey) - extend elbow 20-30° to protect |
| Articular cartilage | Saw kerf during osteotomy - always fracture final 1/4 with osteotome |
| Indication | Preferred Variant |
|---|---|
| Intraarticular distal humerus fracture (ORIF) | Olecranon osteotomy (best articular exposure) |
| Total elbow arthroplasty | Bryan-Morrey (extensile, triceps-sparing) |
| Distal humeral non-union | Olecranon osteotomy or Bryan-Morrey |
| Elbow contracture release | Paratricipital or triceps splitting |
| Olecranon fracture fixation | Direct posterior (minimal approach) |
| Elbow arthroscopy (posterior portals) | Direct posterior portal |
Create a detailed PDF surgical guide for posterior approaches with operative flowcharts
mkdir -p /home/daytona/workspace/elbow-surgical-guide && ls /home/daytona/worksp…
~/elbow-surgical-guide/generate_guide.py
#!/usr/bin/env python3
"""
Posterior Approach to the Elbow - Detailed Surgical PDF Guide
Generated using ReportLab
"""
import urllib.request
import os
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm, mm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
PageBreak, HRFlowable, Image, KeepTogether
)
from reportlab.graphics.shapes import Drawing, Rect, String, Line, Polygon, Arrow
from reportlab.graphics.charts.flowchart import (
FlowChart
)
from reportlab.graphics import renderPDF
from reportlab.lib.colors import HexColor, white, black
from io import BytesIO
# ─── COLORS ──────────────────────────────────────────────────────────────────
DARK_BLUE = HexColor("#1A3A5C")
MED_BLUE = HexColor("#2E6DA4")
LIGHT_BLUE = HexColor("#D6E8F7")
ACCENT_RED = HexColor("#C0392B")
ACCENT_GOLD = HexColor("#D4A017")
LIGHT_GRAY = HexColor("#F4F6F8")
MED_GRAY = HexColor("#BDC3C7")
DARK_GRAY = HexColor("#2C3E50")
GREEN = HexColor("#1E8449")
LIGHT_GREEN = HexColor("#D5F5E3")
ORANGE = HexColor("#E67E22")
LIGHT_ORANGE= HexColor("#FDEBD0")
PURPLE = HexColor("#6C3483")
LIGHT_PURPLE= HexColor("#E8DAEF")
OUTPUT_DIR = "/home/daytona/workspace/elbow-surgical-guide"
OUTPUT_FILE = os.path.join(OUTPUT_DIR, "Posterior_Approach_Elbow_Surgical_Guide.pdf")
# ─── IMAGE URLS ──────────────────────────────────────────────────────────────
IMAGE_URLS = {
"fig_superficial_deep": "https://cdn.orris.care/cdss_images/2477dc4444de168dfbb21c1e87ae6eb3d5a3a787def2fe08a24619f0b8eaa291.png",
"fig_wadsworth": "https://cdn.orris.care/cdss_images/81fe72680b1cea6e9254a59cac3bf1120470b50c601a493f523ad081caa236bd.png",
"fig_osteotomy": "https://cdn.orris.care/cdss_images/f75b33e45927a8639dac7a11b3255a6352d3b18cb3c8bff00cbce4fe077138dd.png",
"fig_bryan_A": "https://cdn.orris.care/cdss_images/b0dbc3251824c856d7b480e4ed9cfe9d2eb6512cd6f2a1bfa108875ea682b5e9.png",
"fig_bryan_B": "https://cdn.orris.care/cdss_images/754162cec53c2d11d4028343ba03246214da70d9bd9641686ea2dc15526f4365.png",
"fig_bryan_C": "https://cdn.orris.care/cdss_images/ae89d2832db6e229cbd38e2e90f7b04e94b61a53df6051e8fc3f9bddba0b5468.png",
}
def download_images():
paths = {}
for key, url in IMAGE_URLS.items():
dest = os.path.join(OUTPUT_DIR, f"{key}.png")
if not os.path.exists(dest):
try:
urllib.request.urlretrieve(url, dest)
print(f"Downloaded {key}")
except Exception as e:
print(f"Failed to download {key}: {e}")
dest = None
paths[key] = dest
return paths
# ─── STYLES ──────────────────────────────────────────────────────────────────
def make_styles():
base = getSampleStyleSheet()
styles = {}
styles["cover_title"] = ParagraphStyle(
"cover_title",
fontName="Helvetica-Bold",
fontSize=28,
textColor=white,
leading=34,
alignment=TA_CENTER,
spaceAfter=8,
)
styles["cover_subtitle"] = ParagraphStyle(
"cover_subtitle",
fontName="Helvetica",
fontSize=14,
textColor=HexColor("#B3D4F0"),
leading=20,
alignment=TA_CENTER,
spaceAfter=4,
)
styles["cover_meta"] = ParagraphStyle(
"cover_meta",
fontName="Helvetica",
fontSize=11,
textColor=HexColor("#E0EAF4"),
leading=16,
alignment=TA_CENTER,
)
styles["section_header"] = ParagraphStyle(
"section_header",
fontName="Helvetica-Bold",
fontSize=15,
textColor=white,
leading=20,
spaceBefore=4,
spaceAfter=4,
leftIndent=0,
)
styles["subsection_header"] = ParagraphStyle(
"subsection_header",
fontName="Helvetica-Bold",
fontSize=12,
textColor=DARK_BLUE,
leading=16,
spaceBefore=10,
spaceAfter=4,
borderPad=2,
)
styles["body"] = ParagraphStyle(
"body",
fontName="Helvetica",
fontSize=9.5,
textColor=DARK_GRAY,
leading=14,
spaceAfter=5,
alignment=TA_JUSTIFY,
)
styles["body_bold"] = ParagraphStyle(
"body_bold",
fontName="Helvetica-Bold",
fontSize=9.5,
textColor=DARK_GRAY,
leading=14,
spaceAfter=4,
)
styles["bullet"] = ParagraphStyle(
"bullet",
fontName="Helvetica",
fontSize=9.5,
textColor=DARK_GRAY,
leading=14,
leftIndent=14,
spaceAfter=3,
)
styles["numbered"] = ParagraphStyle(
"numbered",
fontName="Helvetica",
fontSize=9.5,
textColor=DARK_GRAY,
leading=14,
leftIndent=18,
firstLineIndent=-18,
spaceAfter=4,
alignment=TA_JUSTIFY,
)
styles["caption"] = ParagraphStyle(
"caption",
fontName="Helvetica-Oblique",
fontSize=8.5,
textColor=HexColor("#555555"),
leading=12,
alignment=TA_CENTER,
spaceAfter=8,
)
styles["warning"] = ParagraphStyle(
"warning",
fontName="Helvetica-Bold",
fontSize=9.5,
textColor=ACCENT_RED,
leading=14,
leftIndent=10,
spaceAfter=3,
)
styles["tip"] = ParagraphStyle(
"tip",
fontName="Helvetica-Oblique",
fontSize=9,
textColor=GREEN,
leading=13,
leftIndent=10,
spaceAfter=3,
)
styles["flowchart_title"] = ParagraphStyle(
"flowchart_title",
fontName="Helvetica-Bold",
fontSize=11,
textColor=DARK_BLUE,
leading=15,
alignment=TA_CENTER,
spaceAfter=6,
)
styles["toc_title"] = ParagraphStyle(
"toc_title",
fontName="Helvetica-Bold",
fontSize=13,
textColor=DARK_BLUE,
leading=18,
spaceAfter=8,
alignment=TA_CENTER,
)
styles["toc_entry"] = ParagraphStyle(
"toc_entry",
fontName="Helvetica",
fontSize=10,
textColor=DARK_GRAY,
leading=16,
leftIndent=20,
spaceAfter=2,
)
styles["toc_entry_bold"] = ParagraphStyle(
"toc_entry_bold",
fontName="Helvetica-Bold",
fontSize=10,
textColor=DARK_BLUE,
leading=16,
spaceAfter=2,
)
styles["page_header"] = ParagraphStyle(
"page_header",
fontName="Helvetica-Bold",
fontSize=8,
textColor=MED_BLUE,
leading=10,
alignment=TA_CENTER,
)
return styles
# ─── HELPER FLOWCHART DRAWING ─────────────────────────────────────────────────
def make_decision_flowchart():
"""Draws the main decision flowchart for selecting posterior approach variant."""
W, H = 480, 420
d = Drawing(W, H)
# Background
d.add(Rect(0, 0, W, H, fillColor=HexColor("#F7FBFF"), strokeColor=MED_BLUE, strokeWidth=1))
def box(x, y, w, h, text, fill=LIGHT_BLUE, stroke=MED_BLUE, fontsize=8.5, bold=False, textcolor=DARK_GRAY, radius=4):
d.add(Rect(x, y, w, h, rx=radius, ry=radius, fillColor=fill, strokeColor=stroke, strokeWidth=1.5))
fn = "Helvetica-Bold" if bold else "Helvetica"
# Simple centered text (multi-line via newline approximation)
lines = text.split("\n")
line_h = fontsize + 2
total_h = len(lines) * line_h
start_y = y + h/2 + total_h/2 - line_h
for i, line in enumerate(lines):
d.add(String(x + w/2, start_y - i*line_h, line,
fontName=fn, fontSize=fontsize,
fillColor=textcolor, textAnchor="middle"))
def diamond(cx, cy, hw, hh, text, fill=LIGHT_ORANGE, stroke=ORANGE, fontsize=8):
pts = [cx, cy+hh, cx+hw, cy, cx, cy-hh, cx-hw, cy]
d.add(Polygon(pts, fillColor=fill, strokeColor=stroke, strokeWidth=1.5))
lines = text.split("\n")
line_h = fontsize + 2
total_h = len(lines) * line_h
for i, line in enumerate(lines):
d.add(String(cx, cy + total_h/2 - fontsize/2 - i*line_h, line,
fontName="Helvetica-Bold", fontSize=fontsize,
fillColor=DARK_GRAY, textAnchor="middle"))
def arrow(x1, y1, x2, y2):
d.add(Line(x1, y1, x2, y2, strokeColor=DARK_GRAY, strokeWidth=1.2))
# arrowhead
if y2 < y1:
d.add(Polygon([x2-5, y2+8, x2+5, y2+8, x2, y2],
fillColor=DARK_GRAY, strokeColor=DARK_GRAY, strokeWidth=0))
elif y2 > y1:
d.add(Polygon([x2-5, y2-8, x2+5, y2-8, x2, y2],
fillColor=DARK_GRAY, strokeColor=DARK_GRAY, strokeWidth=0))
elif x2 > x1:
d.add(Polygon([x2-8, y2-5, x2-8, y2+5, x2, y2],
fillColor=DARK_GRAY, strokeColor=DARK_GRAY, strokeWidth=0))
elif x2 < x1:
d.add(Polygon([x2+8, y2-5, x2+8, y2+5, x2, y2],
fillColor=DARK_GRAY, strokeColor=DARK_GRAY, strokeWidth=0))
def label(x, y, text, fontsize=8, color=DARK_GRAY):
d.add(String(x, y, text, fontName="Helvetica-Bold", fontSize=fontsize,
fillColor=color, textAnchor="middle"))
# START box
box(175, 380, 130, 30, "POSTERIOR APPROACH\nTO ELBOW",
fill=DARK_BLUE, stroke=DARK_BLUE, bold=True, textcolor=white, fontsize=9)
arrow(240, 380, 240, 340)
# Decision diamond
diamond(240, 310, 110, 35, "Surgical Indication?")
# Left branch: intraarticular fracture
arrow(130, 310, 75, 310)
label(102, 318, "Intra-articular\nfracture / ORIF", 7.5)
box(10, 280, 130, 45, "OLECRANON\nOSTEOTOMY\n(MacAusland & Muller)",
fill=LIGHT_BLUE, stroke=MED_BLUE, bold=True, fontsize=8)
# Right branch: arthroplasty/soft tissue
arrow(350, 310, 405, 310)
label(377, 318, "Arthroplasty /\nSoft tissue", 7.5)
box(340, 280, 130, 45, "EXTENSILE\n(BRYAN-MORREY)\nTriceps-Sparing",
fill=LIGHT_GREEN, stroke=GREEN, bold=True, fontsize=8)
# Middle branch: contracture/limited
arrow(240, 275, 240, 240)
label(255, 260, "Contracture /\nLimited exposure", 7.5)
box(160, 210, 160, 35, "TRICEPS SPLITTING\nor PARATRICIPITAL\n(Triceps Slide)",
fill=LIGHT_PURPLE, stroke=PURPLE, bold=True, fontsize=8)
# Sub-steps for Olecranon Osteotomy
box(10, 215, 130, 55, "1. Identify bare zone\n2. Chevron cut (60°)\n3. Fracture last 1/4\n4. Reflect + fix",
fill=HexColor("#EAF4FB"), stroke=MED_BLUE, fontsize=7.5)
arrow(75, 280, 75, 270)
# Sub-steps for Bryan-Morrey
box(340, 215, 130, 55, "1. Identify ulnar nerve\n2. Elevate triceps medial\n3. Reflect fascia unit\n4. Reflect anconeus",
fill=HexColor("#EAFAF1"), stroke=GREEN, fontsize=7.5)
arrow(405, 280, 405, 270)
# Ulnar Nerve WARNING box
box(135, 130, 210, 35, "! ULNAR NERVE !\nMust be identified &\nprotected in ALL variants",
fill=HexColor("#FDEDEC"), stroke=ACCENT_RED, bold=True, textcolor=ACCENT_RED, fontsize=8)
arrow(240, 210, 240, 165)
# Closure
box(155, 65, 170, 40, "CLOSURE\nRepair triceps via transosseous\nsutures. MCL if released.",
fill=HexColor("#FEF9E7"), stroke=ACCENT_GOLD, fontsize=7.5)
arrow(240, 130, 240, 105)
# Rehab
box(165, 10, 150, 40, "REHABILITATION\nBryan-Morrey: 60° dressing\nOsteotomy: TBW/lag screw",
fill=LIGHT_GRAY, stroke=MED_GRAY, fontsize=7.5)
arrow(240, 65, 240, 50)
return d
def make_nerve_risk_diagram():
"""Compact diagram showing structures at risk."""
W, H = 460, 200
d = Drawing(W, H)
d.add(Rect(0, 0, W, H, fillColor=HexColor("#FFFAF0"), strokeColor=ACCENT_GOLD, strokeWidth=1))
title_y = 183
d.add(String(W/2, title_y, "Structures at Risk in Posterior Approach",
fontName="Helvetica-Bold", fontSize=10, fillColor=DARK_BLUE, textAnchor="middle"))
entries = [
("Ulnar Nerve", "Most common injury; runs in cubital tunnel behind medial epicondyle;\nmust be identified and retracted with Penrose drain", ACCENT_RED, 140),
("Radial Nerve", "Limits proximal extension; courses anterolaterally at spiral groove;\ndo not extend approach too proximally", ORANGE, 85),
("Articular Cartilage", "Saw kerf during osteotomy destroys articular surface;\nalways fracture final 1/4 with osteotome only", MED_BLUE, 30),
]
for title, desc, col, y_pos in entries:
d.add(Rect(10, y_pos, 440, 46, rx=4, ry=4,
fillColor=HexColor("#FFFAF0"), strokeColor=col, strokeWidth=1.5))
d.add(String(18, y_pos + 32, title,
fontName="Helvetica-Bold", fontSize=9, fillColor=col, textAnchor="start"))
lines = desc.split("\n")
for i, line in enumerate(lines):
d.add(String(18, y_pos + 18 - i*12, line,
fontName="Helvetica", fontSize=8, fillColor=DARK_GRAY, textAnchor="start"))
return d
def make_osteotomy_steps_diagram():
"""Visual steps for chevron osteotomy."""
W, H = 460, 100
d = Drawing(W, H)
d.add(Rect(0, 0, W, H, fillColor=LIGHT_BLUE, strokeColor=MED_BLUE, strokeWidth=1))
steps = [
("Step 1", "Pre-drill\nfixation hole\n(6.5mm screw)", MED_BLUE),
("Step 2", "Mark bare zone\n(~2cm from tip)\nK-wire at apex", DARK_BLUE),
("Step 3", "Chevron cut\n60° with thin\noscillating saw\n(3/4 depth only)", ORANGE),
("Step 4", "Fracture last\n1/4 with\nosteotome\n(protect cartilage)", ACCENT_RED),
("Step 5", "Reflect olecranon\nproximal with\ntriceps attached", GREEN),
("Step 6", "Reduce & fix:\nLag screw +\nTension band\nwire (TBW)", PURPLE),
]
col_w = W / len(steps)
for i, (title, desc, col) in enumerate(steps):
x = i * col_w + 4
d.add(Rect(x, 8, col_w - 8, 88, rx=4, ry=4,
fillColor=white, strokeColor=col, strokeWidth=1.5))
d.add(String(x + (col_w-8)/2, 83, title,
fontName="Helvetica-Bold", fontSize=8, fillColor=col, textAnchor="middle"))
lines = desc.split("\n")
for j, line in enumerate(lines):
d.add(String(x + (col_w-8)/2, 68 - j*12, line,
fontName="Helvetica", fontSize=7.5, fillColor=DARK_GRAY, textAnchor="middle"))
if i < len(steps)-1:
ax = x + col_w - 6
d.add(Line(ax, 52, ax+4, 52, strokeColor=MED_GRAY, strokeWidth=1))
d.add(Polygon([ax+4, 56, ax+4, 48, ax+9, 52],
fillColor=MED_GRAY, strokeColor=MED_GRAY, strokeWidth=0))
return d
def make_bryan_morrey_steps():
"""Visual steps for Bryan-Morrey approach."""
W, H = 460, 100
d = Drawing(W, H)
d.add(Rect(0, 0, W, H, fillColor=LIGHT_GREEN, strokeColor=GREEN, strokeWidth=1))
steps = [
("Step 1", "Lateral decubitus\nposition; arm\nacross chest", GREEN),
("Step 2", "Posterior midline\nincision 7cm distal\nto 9cm proximal\nolecranon tip", MED_BLUE),
("Step 3", "Identify ulnar\nnerve at medial\ntriceps border;\ntranspose anteriorly\n(in TEA)", ACCENT_RED),
("Step 4", "Elevate medial\ntriceps from\nhumerus along\nintermuscular\nseptum", ORANGE),
("Step 5", "Reflect periosteum\n+ fascia as ONE\nunit medial to\nlateral; extend\nelbow 20-30°", PURPLE),
("Step 6", "Reflect anconeus;\njoint exposed;\nclosure: transosseous\nsutures for triceps", DARK_BLUE),
]
col_w = W / len(steps)
for i, (title, desc, col) in enumerate(steps):
x = i * col_w + 4
d.add(Rect(x, 8, col_w - 8, 88, rx=4, ry=4,
fillColor=white, strokeColor=col, strokeWidth=1.5))
d.add(String(x + (col_w-8)/2, 83, title,
fontName="Helvetica-Bold", fontSize=8, fillColor=col, textAnchor="middle"))
lines = desc.split("\n")
for j, line in enumerate(lines):
d.add(String(x + (col_w-8)/2, 68 - j*11, line,
fontName="Helvetica", fontSize=7.5, fillColor=DARK_GRAY, textAnchor="middle"))
if i < len(steps)-1:
ax = x + col_w - 6
d.add(Line(ax, 52, ax+4, 52, strokeColor=MED_GRAY, strokeWidth=1))
d.add(Polygon([ax+4, 56, ax+4, 48, ax+9, 52],
fillColor=MED_GRAY, strokeColor=MED_GRAY, strokeWidth=0))
return d
# ─── PAGE CALLBACKS ──────────────────────────────────────────────────────────
def cover_background(canvas, doc):
"""Draw cover page background gradient."""
canvas.saveState()
# Gradient effect via rectangles
for i in range(100):
frac = i / 100.0
r = 0.1 + frac * 0.08
g = 0.22 + frac * 0.06
b = 0.36 + frac * 0.10
canvas.setFillColorRGB(r, g, b)
canvas.rect(0, doc.height - i * (doc.height/100),
doc.width + doc.leftMargin + doc.rightMargin,
doc.height/100 + 2, fill=1, stroke=0)
# Decorative bar top
canvas.setFillColor(HexColor("#1A6B9A"))
canvas.rect(0, doc.height + doc.topMargin - 18,
doc.width + doc.leftMargin + doc.rightMargin, 18, fill=1, stroke=0)
# Decorative bar bottom
canvas.setFillColor(ACCENT_GOLD)
canvas.rect(0, 0,
doc.width + doc.leftMargin + doc.rightMargin, 8, fill=1, stroke=0)
canvas.restoreState()
def regular_page(canvas, doc):
"""Header and footer for regular pages."""
canvas.saveState()
W = doc.width + doc.leftMargin + doc.rightMargin
# Header bar
canvas.setFillColor(DARK_BLUE)
canvas.rect(0, doc.height + doc.topMargin - 22, W, 22, fill=1, stroke=0)
canvas.setFillColor(white)
canvas.setFont("Helvetica-Bold", 8)
canvas.drawCentredString(W/2, doc.height + doc.topMargin - 14,
"POSTERIOR APPROACH TO THE ELBOW | Surgical Guide")
# Gold accent line under header
canvas.setFillColor(ACCENT_GOLD)
canvas.rect(0, doc.height + doc.topMargin - 24, W, 2, fill=1, stroke=0)
# Footer
canvas.setFillColor(LIGHT_GRAY)
canvas.rect(0, 0, W, 20, fill=1, stroke=0)
canvas.setFillColor(MED_GRAY)
canvas.rect(0, 19, W, 1, fill=1, stroke=0)
canvas.setFillColor(DARK_GRAY)
canvas.setFont("Helvetica", 7.5)
canvas.drawCentredString(W/2, 6,
f"Source: Campbell's Operative Orthopaedics 15th Ed (2026) | Miller's Review of Orthopaedics 9th Ed | Page {doc.page}")
canvas.restoreState()
# ─── SECTION HEADER HELPER ───────────────────────────────────────────────────
def section_header(title, styles, bg_color=None, icon=""):
if bg_color is None:
bg_color = DARK_BLUE
data = [[Paragraph(f"{icon} {title}", styles["section_header"])]]
t = Table(data, colWidths=[16.5*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg_color),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
("TOPPADDING", (0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 12),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("ROUNDEDCORNERS", [4, 4, 4, 4]),
]))
return t
def info_box(items, styles, color=LIGHT_BLUE, border=MED_BLUE, label=""):
"""A simple colored information box."""
content = []
if label:
content.append(Paragraph(f"<b>{label}</b>", styles["body_bold"]))
for item in items:
content.append(Paragraph(f"• {item}", styles["bullet"]))
data = [[content]]
t = Table(data, colWidths=[16.5*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), color),
("BOX", (0,0), (-1,-1), 1.5, border),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 12),
("RIGHTPADDING", (0,0), (-1,-1), 8),
]))
return t
def warning_box(items, styles):
content = [Paragraph("⚠ STRUCTURES AT RISK / COMPLICATIONS", styles["warning"])]
for item in items:
content.append(Paragraph(f"▶ {item}", styles["warning"]))
data = [[content]]
t = Table(data, colWidths=[16.5*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), HexColor("#FDEDEC")),
("BOX", (0,0), (-1,-1), 2, ACCENT_RED),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 8),
]))
return t
def tip_box(items, styles):
content = [Paragraph("✔ SURGICAL PEARLS", styles["tip"])]
for item in items:
content.append(Paragraph(f"✓ {item}", styles["tip"]))
data = [[content]]
t = Table(data, colWidths=[16.5*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), LIGHT_GREEN),
("BOX", (0,0), (-1,-1), 1.5, GREEN),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 8),
]))
return t
def safe_image(path, width, caption=None, styles=None):
"""Return Image + optional caption, or fallback text if image missing."""
elems = []
if path and os.path.exists(path):
try:
img = Image(path, width=width)
img.hAlign = "CENTER"
elems.append(img)
except Exception:
elems.append(Spacer(1, 0.3*cm))
else:
elems.append(Spacer(1, 0.3*cm))
if caption and styles:
elems.append(Paragraph(caption, styles["caption"]))
return elems
# ─── BUILD PDF ────────────────────────────────────────────────────────────────
def build_pdf(img_paths):
styles = make_styles()
doc = SimpleDocTemplate(
OUTPUT_FILE,
pagesize=A4,
leftMargin=2*cm, rightMargin=2*cm,
topMargin=2.5*cm, bottomMargin=1.8*cm,
title="Posterior Approach to the Elbow - Surgical Guide",
author="Orris Medical AI",
subject="Orthopaedic Surgery",
)
story = []
# ══════════════════════════════════════════════════════════════════════════
# COVER PAGE
# ══════════════════════════════════════════════════════════════════════════
cover_data = [
[Paragraph("POSTERIOR APPROACH<br/>TO THE ELBOW", styles["cover_title"])],
[Spacer(1, 0.5*cm)],
[Paragraph("A Comprehensive Operative Surgical Guide", styles["cover_subtitle"])],
[Spacer(1, 0.3*cm)],
[Paragraph("Including Variants, Operative Flowcharts,<br/>Anatomical Landmarks & Clinical Pearls", styles["cover_meta"])],
[Spacer(1, 0.8*cm)],
[Paragraph("─────────────────────────────────", styles["cover_meta"])],
[Spacer(1, 0.4*cm)],
[Paragraph("Approach Variants Covered:", styles["cover_meta"])],
[Spacer(1, 0.2*cm)],
[Paragraph("1. Olecranon Osteotomy (MacAusland & Müller)<br/>"
"2. Extensile Posterior - Bryan-Morrey (Triceps-Sparing)<br/>"
"3. Triceps Splitting<br/>"
"4. Paratricipital (Triceps Slide)", styles["cover_meta"])],
[Spacer(1, 0.8*cm)],
[Paragraph("─────────────────────────────────", styles["cover_meta"])],
[Spacer(1, 0.3*cm)],
[Paragraph("Source: Campbell's Operative Orthopaedics 15th Ed (2026)<br/>"
"Miller's Review of Orthopaedics 9th Edition", styles["cover_meta"])],
[Spacer(1, 0.3*cm)],
[Paragraph("Compiled by Orris Medical AI | July 2026", styles["cover_meta"])],
]
for row in cover_data:
story.append(row[0])
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════
# TABLE OF CONTENTS
# ══════════════════════════════════════════════════════════════════════════
story.append(Paragraph("TABLE OF CONTENTS", styles["toc_title"]))
story.append(HRFlowable(width="100%", thickness=2, color=MED_BLUE))
story.append(Spacer(1, 0.3*cm))
toc_entries = [
("1.", "Surgical Anatomy & Overview", True),
("", " Osseous anatomy, soft tissue landmarks, neurovascular", False),
("2.", "Decision Flowchart - Selecting the Approach Variant", True),
("3.", "Approach Variant 1: Olecranon Osteotomy (MacAusland & Müller)", True),
("", " Indications, position, incision, steps, fixation", False),
("4.", "Approach Variant 2: Extensile Posterior (Bryan-Morrey)", True),
("", " Indications, position, steps, triceps reflection, closure", False),
("5.", "Approach Variants 3 & 4: Triceps Splitting / Paratricipital", True),
("6.", "Structures at Risk & Complications", True),
("7.", "Indications Quick Reference", True),
("8.", "Examination Key Points (10-mark answer summary)", True),
]
for num, text, bold in toc_entries:
style = styles["toc_entry_bold"] if bold else styles["toc_entry"]
story.append(Paragraph(f"{num} {text}", style))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════
# SECTION 1: SURGICAL ANATOMY
# ══════════════════════════════════════════════════════════════════════════
story.append(section_header("1. SURGICAL ANATOMY & OVERVIEW", styles))
story.append(Spacer(1, 0.3*cm))
story.append(Paragraph(
"The posterior approach is the primary workhorse approach to the elbow joint. "
"It provides excellent access to the distal humerus, trochlea, capitellum, olecranon, "
"radial head, and the elbow joint capsule. A defining feature of this approach is that "
"it has <b>no true internervous plane</b> - the triceps mechanism must be managed directly.",
styles["body"]
))
story.append(Spacer(1, 0.2*cm))
# Anatomy table
story.append(Paragraph("Key Anatomical Structures", styles["subsection_header"]))
anat_data = [
["Structure", "Location", "Surgical Relevance"],
["Olecranon", "Proximal ulna; forms the 'point' of elbow", "Blocks direct articular access; may be osteotomized"],
["Triceps tendon", "Inserts onto olecranon tip", "Must be reflected, split, or detached for joint entry"],
["Ulnar nerve", "Runs behind medial epicondyle in cubital tunnel", "AT RISK in ALL variants - must be identified first"],
["Anconeus", "Small muscle posterolateral; radial nerve", "Lateral landmark; reflects subperiosteally for radial head"],
["Medial epicondyle", "Medial prominence of distal humerus", "Landmark for ulnar nerve; attached to MCL"],
["Bare zone (olecranon)", "Non-articular isthmus ~2 cm from tip", "Safest site for chevron osteotomy"],
["Radial nerve", "Spiral groove of humerus; continues as PIN", "Limits proximal extension; do not extend too far proximally"],
["MCL (medial collateral lig.)", "Medial joint; fan-shaped", "May need release for joint subluxation in TEA; repair at closure"],
["Posterior capsule", "Posterior joint", "Usually reflects with triceps in Bryan-Morrey approach"],
]
anat_table = Table(anat_data, colWidths=[3.8*cm, 5.5*cm, 7.2*cm])
anat_table.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,0), 9),
("ALIGN", (0,0), (-1,-1), "LEFT"),
("FONTNAME", (0,1), (-1,-1), "Helvetica"),
("FONTSIZE", (0,1), (-1,-1), 8.5),
("ROWBACKGROUNDS", (0,1), (-1,-1), [white, LIGHT_BLUE]),
("GRID", (0,0), (-1,-1), 0.5, MED_GRAY),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("BACKGROUND", (0,3), (-1,3), HexColor("#FDECEA")),
("TEXTCOLOR", (1,3), (1,3), ACCENT_RED),
]))
story.append(anat_table)
story.append(Spacer(1, 0.4*cm))
story.append(Paragraph("Patient Positioning Principles", styles["subsection_header"]))
story.append(info_box([
"Lateral decubitus OR prone position with arm supported on a padded arm board",
"Elbow flexed 90° over the arm support for prone; arm placed across chest for lateral decubitus",
"Tourniquet applied to proximal arm (inflate to 250-300 mmHg)",
"Avoid compression of ulnar nerve at elbow from positioning",
"Ensure free access to posterior elbow throughout ROM",
], styles, color=LIGHT_BLUE, label="Positioning"))
story.append(Spacer(1, 0.3*cm))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════
# SECTION 2: DECISION FLOWCHART
# ══════════════════════════════════════════════════════════════════════════
story.append(section_header("2. DECISION FLOWCHART - SELECTING THE APPROACH VARIANT", styles, bg_color=MED_BLUE))
story.append(Spacer(1, 0.3*cm))
story.append(Paragraph(
"The choice of posterior approach variant depends on the primary surgical indication, "
"requirement for articular exposure, and the need to preserve the triceps mechanism. "
"The flowchart below guides the selection process.",
styles["body"]
))
story.append(Spacer(1, 0.3*cm))
story.append(make_decision_flowchart())
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"Figure 1. Decision flowchart for selecting the appropriate posterior approach to the elbow. "
"Note that the ulnar nerve must be identified and protected in ALL variants.",
styles["caption"]
))
story.append(Spacer(1, 0.4*cm))
# Variant comparison table
story.append(Paragraph("Comparison of Posterior Approach Variants", styles["subsection_header"]))
comp_data = [
["Variant", "Triceps Handling", "Articular Exposure", "Best Indication", "Key Risk"],
["Olecranon Osteotomy", "Reflected with osteotomy fragment", "MAXIMUM\n(>70% articular)", "Intraarticular ORIF\nDistal humerus fractures", "Non-union / malunion\nof osteotomy"],
["Bryan-Morrey\n(Extensile)", "Reflected as one unit\nmedial to lateral", "Excellent\n(whole joint)", "Total elbow arthroplasty\nElbow arthroplasty", "Triceps avulsion if\ncontinuity disrupted"],
["Triceps Splitting", "Split in midline;\nolecranon intact", "Moderate", "Limited access,\ncontracture release", "Weak repair if\npoor tissue"],
["Paratricipital\n(Triceps Slide)", "Elevated off intermuscular\nsepta; insertion intact", "Moderate-Good\n(bilateral)", "Access without\ntriceps detachment", "Ulnar nerve;\nradial nerve proximally"],
]
comp_table = Table(comp_data, colWidths=[3.3*cm, 3.8*cm, 2.8*cm, 3.5*cm, 3.1*cm])
comp_table.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,0), 8.5),
("FONTNAME", (0,1), (-1,-1), "Helvetica"),
("FONTSIZE", (0,1), (-1,-1), 8),
("ROWBACKGROUNDS", (0,1), (-1,-1), [white, LIGHT_GRAY]),
("GRID", (0,0), (-1,-1), 0.5, MED_GRAY),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("BACKGROUND", (2,1), (2,1), LIGHT_GREEN),
("TEXTCOLOR", (2,1), (2,1), GREEN),
("FONTNAME", (2,1), (2,1), "Helvetica-Bold"),
]))
story.append(comp_table)
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════
# SECTION 3: OLECRANON OSTEOTOMY
# ══════════════════════════════════════════════════════════════════════════
story.append(section_header("3. VARIANT 1 — OLECRANON OSTEOTOMY (MacAusland & Müller)", styles, bg_color=MED_BLUE))
story.append(Spacer(1, 0.3*cm))
story.append(info_box([
"Best articular exposure of distal humerus (Wilkinson & Stanley: significantly more articular surface exposed vs triceps-reflecting approach)",
"Intraarticular fractures of the distal humerus requiring ORIF",
"Distal humeral non-union requiring revision fixation",
"Complex elbow reconstruction where full articular visualization is needed",
], styles, color=LIGHT_BLUE, label="INDICATIONS"))
story.append(Spacer(1, 0.25*cm))
story.append(Paragraph("Operative Steps", styles["subsection_header"]))
steps_ost = [
("1", "INCISION", "Begin 5 cm distal to the tip of the olecranon; extend proximally medial to the midline of the arm to 10-12 cm above the olecranon tip."),
("2", "SKIN FLAPS", "Reflect skin and subcutaneous tissue to either side to expose the olecranon and triceps tendon."),
("3", "ULNAR NERVE", "Identify the ulnar nerve in its groove behind the medial epicondyle. Retract gently with a Penrose drain or moist umbilical tape."),
("4", "PRE-DRILL", "Before the osteotomy, place the chosen fixation device (6.5mm cancellous screw, tension band wire, or plate) as a pre-drill step. This assists later reduction - the saw kerf and bone loss make accurate re-reduction challenging."),
("5", "BARE ZONE", "Identify the bare zone of the olecranon - the non-articular isthmus approximately 2 cm from the tip. Use direct visualization or fluoroscopic imaging. Place a Kirschner wire centrally at this point."),
("6", "CHEVRON MARK", "Mark a 60-degree chevron osteotomy with the apex pointing distally at the K-wire position. The chevron shape provides rotational stability and a larger surface area for healing vs a transverse cut."),
("7", "SAW CUT", "Divide THREE-QUARTERS of the depth with a thin oscillating saw. Do not complete the full cut - this protects the articular cartilage from saw kerf damage."),
("8", "OSTEOTOME COMPLETE", "Fracture the remaining one-quarter with an osteotome. This creates a rough cancellous surface which promotes healing and avoids saw kerf through articular cartilage."),
("9", "REFLECT", "Reflect the olecranon fragment and attached triceps proximally - full posterior and articular exposure is now achieved. Use a suture to hold the fragment proximally. Wrap articular surface in a moist laparotomy pad."),
("10", "CLOSURE - FIXATION", "After the intraarticular procedure: reduce the osteotomy fragment accurately, then fix with the pre-placed implant. Options: 6.5mm cancellous lag screw + tension band wire (standard), OR plate and screws, OR independent screws."),
]
for num, title, detail in steps_ost:
data_row = [[
Paragraph(f"<b>{num}</b>", styles["body_bold"]),
[Paragraph(f"<b>{title}</b>", styles["body_bold"]),
Paragraph(detail, styles["body"])]
]]
t = Table(data_row, colWidths=[0.8*cm, 15.7*cm])
t.setStyle(TableStyle([
("ALIGN", (0,0), (0,0), "CENTER"),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 2),
("LEFTPADDING", (0,0), (0,0), 2),
("LEFTPADDING", (1,0), (1,0), 6),
("ROWBACKGROUNDS", (0,0), (-1,-1),
[LIGHT_BLUE if int(num)%2==0 else white]),
]))
story.append(t)
story.append(Spacer(1, 0.3*cm))
# Osteotomy step diagram
story.append(Paragraph("Operative Step Summary - Olecranon Osteotomy", styles["flowchart_title"]))
story.append(make_osteotomy_steps_diagram())
story.append(Paragraph(
"Figure 2. Sequential steps of the chevron olecranon osteotomy.",
styles["caption"]
))
story.append(Spacer(1, 0.3*cm))
# Images
for path, cap in [
(img_paths.get("fig_superficial_deep"),
"Figure 3. Posterior approach to elbow. A: Superficial exposure showing olecranon osteotomy site and ulnar nerve. "
"B: Deep exposure after osteotomy reflection, revealing the trochlea, periosteum, and olecranon."),
(img_paths.get("fig_osteotomy"),
"Figure 4. Olecranon osteotomy technique. A: Pre-drilling. B: Incomplete chevron osteotomy with K-wire. "
"C: Osteotomy completed by fracturing. D: 6.5mm lag screw and tension band wire fixation."),
]:
for elem in safe_image(path, 14*cm, cap, styles):
story.append(elem)
story.append(warning_box([
"Ulnar nerve - identify before all other dissection; retract with Penrose drain",
"Saw kerf - never complete osteotomy with saw; always fracture last 1/4 with osteotome",
"Non-union of osteotomy - pre-drill helps but anatomic reduction at closure is essential",
"Articular cartilage desiccation - always wrap exposed cartilage in moist pads",
], styles))
story.append(Spacer(1, 0.2*cm))
story.append(tip_box([
"Pre-drill the fixation before the osteotomy - prevents difficult reduction later",
"Chevron osteotomy is superior to transverse cut - rotational stability, better healing",
"Fluoroscopy helps identify the bare zone; direct palpation can also be used",
"A suture looped around the reflected fragment prevents it from flopping onto instruments",
], styles))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════
# SECTION 4: BRYAN-MORREY
# ══════════════════════════════════════════════════════════════════════════
story.append(section_header("4. VARIANT 2 — EXTENSILE POSTERIOR (BRYAN-MORREY)", styles, bg_color=GREEN))
story.append(Spacer(1, 0.3*cm))
story.append(Paragraph(
"Bryan and Morrey developed this modified posterior approach to provide excellent exposure "
"while <b>preserving the continuity of the triceps mechanism</b>, allowing easy repair and "
"rapid rehabilitation. This is the preferred approach for total elbow arthroplasty (TEA).",
styles["body"]
))
story.append(Spacer(1, 0.2*cm))
story.append(info_box([
"Total elbow arthroplasty (TEA) - primary indication",
"Distal humeral non-union requiring elbow arthroplasty",
"Revision elbow arthroplasty",
"Situations where triceps continuity and rapid rehabilitation are priorities",
"Elderly patients with poor bone quality (osteotomy fixation unreliable)",
], styles, color=LIGHT_GREEN, label="INDICATIONS"))
story.append(Spacer(1, 0.25*cm))
story.append(Paragraph("Operative Steps", styles["subsection_header"]))
steps_bm = [
("1", "POSITION", "Place patient in lateral decubitus or tilted 45-60 degrees with sandbags under back and hip. Place the limb across the chest."),
("2", "INCISION", "Straight posterior midline incision from 7 cm distal to the tip of the olecranon to 9 cm proximal to it (total ~16 cm)."),
("3", "ULNAR NERVE IDENTIFICATION", "Find the ulnar nerve proximally at the medial border of the medial head of the triceps. Dissect it free from its tunnel distally to its first motor branch into the FCU. In total elbow arthroplasty: transpose the nerve anteriorly into subcutaneous tissue to prevent stretch injury."),
("4", "MEDIAL TRICEPS ELEVATION", "Elevate the medial aspect of the triceps from the humerus, dissecting along the intermuscular septum, down to the level of the posterior capsule."),
("5", "FOREARM FASCIA INCISION", "Incise the superficial fascia of the forearm distally for approximately 6 cm to the periosteum of the medial aspect of the olecranon."),
("6", "REFLECT AS ONE UNIT", "Carefully reflect periosteum + fascia as a SINGLE CONTINUOUS UNIT from medial to lateral. "
"CRITICAL POINT: The medial junction of the triceps insertion, superficial fascia, and ulnar periosteum is the weakest point - "
"keep this intact. Extend the elbow to 20-30 degrees during triceps dissection from olecranon to relieve tissue tension."),
("7", "ANCONEUS", "Reflect the anconeus subperiosteally from the proximal ulna to expose the radial head."),
("8", "FULL EXPOSURE", "The entire joint is now widely exposed. The posterior capsule usually elevates with the triceps mechanism. "
"The tip of the olecranon may be resected to clearly expose the trochlea."),
("9", "MCL RELEASE (if needed)", "For total joint arthroplasty: release the medial collateral ligament from the humerus if needed for adequate joint retraction/dislocation."),
("10", "CLOSURE", "Carefully repair the MCL if it was released. Return triceps to anatomic position and suture through holes drilled in the proximal ulna (transosseous sutures). Suture periosteum to superficial forearm fascia up to the margin of the FCU. Drain the wound. Dress with elbow at 60° flexion in TEA."),
]
for num, title, detail in steps_bm:
data_row = [[
Paragraph(f"<b>{num}</b>", styles["body_bold"]),
[Paragraph(f"<b>{title}</b>", styles["body_bold"]),
Paragraph(detail, styles["body"])]
]]
bg = LIGHT_GREEN if int(num)%2==0 else white
t = Table(data_row, colWidths=[0.8*cm, 15.7*cm])
t.setStyle(TableStyle([
("ALIGN", (0,0), (0,0), "CENTER"),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 2),
("LEFTPADDING", (0,0), (0,0), 2),
("LEFTPADDING", (1,0), (1,0), 6),
("ROWBACKGROUNDS", (0,0), (-1,-1), [bg]),
]))
story.append(t)
story.append(Spacer(1, 0.3*cm))
story.append(Paragraph("Operative Step Summary - Bryan-Morrey Approach", styles["flowchart_title"]))
story.append(make_bryan_morrey_steps())
story.append(Paragraph(
"Figure 5. Sequential steps of the Bryan-Morrey extensile posterior approach.",
styles["caption"]
))
story.append(Spacer(1, 0.2*cm))
# Images
for path, cap in [
(img_paths.get("fig_wadsworth"),
"Figure 6. Bryan-Morrey / Wadsworth posterolateral approach. "
"A: Skin incision (curved paramedian) with patient prone, elbow flexed. "
"B: Superficial layer - triceps tendon with ulnar nerve identified. "
"C: Complete exposure showing capitellum, radius, anconeus, and extensor carpi ulnaris."),
(img_paths.get("fig_bryan_A"),
"Figure 7A. Bryan-Morrey approach - superficial exposure. "
"Olecranon at top, superficial forearm fascia, and dashed green line indicating line of incision. "
"Ulnar nerve and medial epicondyle are clearly labeled."),
(img_paths.get("fig_bryan_B"),
"Figure 7B. Bryan-Morrey approach - intermediate layer. "
"Ulnar nerve retracted with vessel loop, triceps muscle elevated off medial epicondyle."),
(img_paths.get("fig_bryan_C"),
"Figure 7C. Bryan-Morrey approach - deep layer. "
"Periosteum and forearm fascia reflected as one unit. Joint capsule, medial epicondyle, "
"olecranon and FCU visible. Ulnar nerve (yellow vessel loop) protected laterally."),
]:
for elem in safe_image(path, 13*cm, cap, styles):
story.append(elem)
story.append(warning_box([
"Triceps avulsion - highest risk at the medial junction of triceps insertion/fascia/periosteum; keep as ONE unit",
"Ulnar nerve injury - most common complication; always identify and transpose in TEA",
"Do NOT divide triceps transversely - destroys the mechanism",
"MCL repair at closure is mandatory if it was released",
"Radial nerve limits proximal extension along humerus",
], styles))
story.append(Spacer(1, 0.2*cm))
story.append(tip_box([
"KEY PEARL: Extend elbow 20-30° while dissecting triceps off olecranon - reduces tension at weakest point",
"Anterior transposition of ulnar nerve prevents stretch injury during TEA manipulation",
"Use a periosteal elevator rather than sharp dissection at the medial junction",
"Wrap the articular surface if exposing the joint for extended periods",
"In TEA: dress with 60° elbow flexion to prevent direct pressure on wound from olecranon",
], styles))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════
# SECTION 5: TRICEPS SPLITTING & PARATRICIPITAL
# ══════════════════════════════════════════════════════════════════════════
story.append(section_header("5. VARIANTS 3 & 4 — TRICEPS SPLITTING / PARATRICIPITAL", styles, bg_color=PURPLE))
story.append(Spacer(1, 0.3*cm))
col_data = [
[
[
Paragraph("Triceps Splitting", styles["subsection_header"]),
Paragraph("<b>Interval:</b> Midline split of the triceps muscle and tendon, leaving the olecranon intact.", styles["body"]),
Paragraph("<b>Dissection:</b>", styles["body_bold"]),
Paragraph("• Posterior midline incision", styles["bullet"]),
Paragraph("• Identify and protect ulnar nerve", styles["bullet"]),
Paragraph("• Split triceps in midline from proximal to its insertion", styles["bullet"]),
Paragraph("• Reflect each half laterally for exposure", styles["bullet"]),
Paragraph("• Olecranon remains intact throughout", styles["bullet"]),
Spacer(1, 0.2*cm),
Paragraph("<b>Indications:</b> Limited access, elbow contracture release, simple distal humeral procedures where full articular exposure not needed.", styles["body"]),
Spacer(1, 0.2*cm),
Paragraph("<b>Advantage:</b> No osteotomy required, simpler closure.", styles["body"]),
Paragraph("<b>Limitation:</b> Moderate articular exposure, triceps repair may be weak in poor tissue.", styles["body"]),
],
[
Paragraph("Paratricipital (Triceps Slide)", styles["subsection_header"]),
Paragraph("<b>Interval:</b> The triceps is elevated off the medial AND lateral intermuscular septa, allowing the tendon to be mobilized in either direction. The triceps insertion onto the olecranon remains <b>completely undisturbed</b>.", styles["body"]),
Paragraph("<b>Dissection:</b>", styles["body_bold"]),
Paragraph("• Posterior midline incision", styles["bullet"]),
Paragraph("• Identify and protect ulnar nerve", styles["bullet"]),
Paragraph("• Release triceps off medial intermuscular septum", styles["bullet"]),
Paragraph("• Release triceps off lateral intermuscular septum", styles["bullet"]),
Paragraph("• Retract triceps medially OR laterally as needed", styles["bullet"]),
Spacer(1, 0.2*cm),
Paragraph("<b>Indications:</b> Access without triceps detachment; useful for paediatric distal humeral fractures, lateral condyle, and selected adult cases.", styles["body"]),
Spacer(1, 0.2*cm),
Paragraph("<b>Advantage:</b> Triceps insertion completely intact - no triceps weakness.", styles["body"]),
Paragraph("<b>Limitation:</b> Limited articular window; radial nerve limits proximal extension.", styles["body"]),
]
]
]
t = Table(col_data, colWidths=[8*cm, 8*cm])
t.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("BACKGROUND", (0,0), (0,0), LIGHT_PURPLE),
("BACKGROUND", (1,0), (1,0), LIGHT_BLUE),
("BOX", (0,0), (0,0), 1, PURPLE),
("BOX", (1,0), (1,0), 1, MED_BLUE),
]))
story.append(t)
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════
# SECTION 6: STRUCTURES AT RISK
# ══════════════════════════════════════════════════════════════════════════
story.append(section_header("6. STRUCTURES AT RISK & COMPLICATIONS", styles, bg_color=ACCENT_RED))
story.append(Spacer(1, 0.3*cm))
story.append(make_nerve_risk_diagram())
story.append(Spacer(1, 0.2*cm))
risk_data = [
["Structure at Risk", "Mechanism", "Prevention", "Consequence if Injured"],
["Ulnar Nerve\n(MOST COMMON)", "Direct cut during dissection;\nexcessive retraction;\nstretch during TEA dislocation",
"Identify early; Penrose drain;\nanterior transposition in TEA",
"Cubital tunnel syndrome;\nclaw hand; sensory loss\nring/little fingers"],
["Radial Nerve", "Excessive proximal extension\nof incision along humerus;\nretractor placement",
"Do not extend >10cm proximal\nto lateral epicondyle;\nprotect with retractor under brachialis",
"Wrist drop (posterior\ninterosseous nerve palsy)"],
["Articular Cartilage", "Saw kerf during osteotomy\ncompleting full thickness cut",
"Always fracture final 1/4\nwith osteotome only;\nuse thin oscillating saw",
"Damaged articular surface;\npoor reduction; arthritis"],
["Triceps Mechanism", "Over-tension at medial\njunction in Bryan-Morrey;\ntransverse division",
"Extend elbow 20-30°;\ndo NOT cut triceps transversely;\nmaintain tissue as one unit",
"Permanent extensor weakness;\nextension lag at elbow"],
["MCL\n(Medial Collateral Lig.)", "Released for joint dislocation\nin TEA without repair",
"Repair at closure if released",
"Valgus instability;\npoor functional outcome"],
["Olecranon Osteotomy\nNon-union", "Inadequate fixation;\npoor reduction;\nbone loss from saw kerf",
"Pre-drill; accurate reduction;\nchevron cut; rigid fixation",
"Non-union; painful hardware;\nre-operation"],
]
risk_table = Table(risk_data, colWidths=[3.2*cm, 4.5*cm, 4.5*cm, 4.3*cm])
risk_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), ACCENT_RED),
("TEXTCOLOR", (0,0), (-1,0), white),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,0), 8.5),
("ALIGN", (0,0), (-1,-1), "LEFT"),
("FONTNAME", (0,1), (-1,-1), "Helvetica"),
("FONTSIZE", (0,1), (-1,-1), 8),
("ROWBACKGROUNDS", (0,1), (-1,-1), [white, HexColor("#FDEDEC")]),
("GRID", (0,0), (-1,-1), 0.5, MED_GRAY),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 5),
("BACKGROUND", (0,1), (0,1), HexColor("#FDECEA")),
("TEXTCOLOR", (0,1), (0,1), ACCENT_RED),
("FONTNAME", (0,1), (0,1), "Helvetica-Bold"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(risk_table)
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════
# SECTION 7: INDICATIONS QUICK REFERENCE
# ══════════════════════════════════════════════════════════════════════════
story.append(section_header("7. INDICATIONS QUICK REFERENCE", styles, bg_color=ACCENT_GOLD))
story.append(Spacer(1, 0.3*cm))
ind_data = [
["Clinical Scenario", "Preferred Posterior Variant", "Rationale"],
["Intraarticular distal humerus\nfracture (ORIF)", "Olecranon Osteotomy\n(MacAusland-Müller)",
"Maximum articular surface exposure;\nchevron provides stability"],
["Total elbow arthroplasty (TEA)", "Bryan-Morrey\n(Extensile / Triceps-Sparing)",
"Preserves triceps mechanism;\nrapid rehabilitation"],
["Distal humeral non-union", "Olecranon Osteotomy\nOR Bryan-Morrey",
"Depends on bone quality\nand planned reconstruction"],
["Elbow stiffness / contracture\nrelease", "Paratricipital OR\nTriceps Splitting",
"Preserves triceps;\nadequate capsular access"],
["Olecranon fracture ORIF", "Direct posterior\n(minimal approach)",
"Fracture itself provides\ndirect access"],
["Paediatric supracondylar\n/ lateral condyle fractures", "Paratricipital\n(Triceps Slide)",
"Preserves growth plate;\ntriceps insertion intact"],
["Elbow arthroscopy\n(posterior portals)", "Posterior arthroscopic\nportal (direct)",
"Minimally invasive;\nsuperficial insertion only"],
["TEA with poor bone quality\n(elderly)", "Bryan-Morrey exclusively",
"Avoids osteotomy that\nmay not heal reliably"],
]
ind_table = Table(ind_data, colWidths=[5.5*cm, 5*cm, 6*cm])
ind_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), HexColor("#7D6608")),
("TEXTCOLOR", (0,0), (-1,0), white),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,0), 9),
("FONTNAME", (0,1), (-1,-1), "Helvetica"),
("FONTSIZE", (0,1), (-1,-1), 8.5),
("ROWBACKGROUNDS", (0,1), (-1,-1), [white, HexColor("#FEF9E7")]),
("GRID", (0,0), (-1,-1), 0.5, MED_GRAY),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(ind_table)
story.append(Spacer(1, 0.5*cm))
# ══════════════════════════════════════════════════════════════════════════
# SECTION 8: EXAM SUMMARY
# ══════════════════════════════════════════════════════════════════════════
story.append(section_header("8. EXAMINATION KEY POINTS (10-MARK ANSWER SUMMARY)", styles, bg_color=DARK_BLUE))
story.append(Spacer(1, 0.3*cm))
exam_points = [
("1", "NO INTERNERVOUS PLANE", "The posterior approach has no true internervous plane. Access is gained by directly managing the triceps mechanism (reflect, split, or detach)."),
("2", "ULNAR NERVE RULE", "Identify and protect the ulnar nerve in EVERY variant. It runs posterior to the medial epicondyle in the cubital tunnel. Transpose anteriorly in TEA."),
("3", "OSTEOTOMY = MAXIMUM EXPOSURE", "Olecranon osteotomy (Wilkinson & Stanley) exposes significantly more articular surface of the distal humerus than any triceps-reflecting approach."),
("4", "CHEVRON > TRANSVERSE", "Chevron osteotomy (60°, apex distal) is preferred over transverse - better rotational stability and larger healing surface area."),
("5", "BARE ZONE", "The non-articular bare zone (~2 cm from the olecranon tip) is the safest site for osteotomy. Identify with direct visualization or fluoroscopy."),
("6", "3/4 SAW + 1/4 OSTEOTOME RULE", "Divide only 3/4 depth with the saw; complete the remaining 1/4 with an osteotome to prevent saw kerf through articular cartilage."),
("7", "BRYAN-MORREY KEY PEARL", "Periosteum + fascia must be reflected as ONE continuous unit. The medial junction (triceps insertion + fascia + periosteum) is the weakest point. Extend elbow 20-30° to reduce tension."),
("8", "RADIAL NERVE LIMITS EXTENSION", "The radial nerve limits proximal extension of the posterior approach along the humerus. Do not extend beyond ~10 cm proximal to the lateral epicondyle."),
("9", "TEA DRESSING POSITION", "After total elbow arthroplasty via Bryan-Morrey, dress with elbow at 60° flexion to prevent direct pressure on the wound from the olecranon tip."),
("10", "OSTEOTOMY FIXATION", "Pre-drill fixation BEFORE osteotomy. At closure: reduce anatomically and fix with 6.5 mm lag screw + tension band wire (standard), or plate and screws."),
]
for num, title, detail in exam_points:
data_row = [[
Paragraph(f"<b>{num}</b>", styles["body_bold"]),
[Paragraph(f"<b>{title}</b>", styles["body_bold"]),
Paragraph(detail, styles["body"])]
]]
bg = LIGHT_BLUE if int(num)%2==0 else white
t = Table(data_row, colWidths=[0.8*cm, 15.7*cm])
t.setStyle(TableStyle([
("ALIGN", (0,0), (0,0), "CENTER"),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (0,0), 2),
("LEFTPADDING", (1,0), (1,0), 6),
("ROWBACKGROUNDS", (0,0), (-1,-1), [bg]),
]))
story.append(t)
story.append(Spacer(1, 0.3*cm))
story.append(HRFlowable(width="100%", thickness=1.5, color=MED_BLUE))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"Source: Campbell's Operative Orthopaedics 15th Ed 2026 (pp. 133-135) | "
"Miller's Review of Orthopaedics 9th Edition (p. 171) | Compiled by Orris Medical AI",
styles["caption"]
))
# ══════════════════════════════════════════════════════════════════════════
# BUILD
# ══════════════════════════════════════════════════════════════════════════
def page_template(canvas, doc):
if doc.page == 1:
cover_background(canvas, doc)
else:
regular_page(canvas, doc)
doc.build(story, onFirstPage=page_template, onLaterPages=page_template)
print(f"PDF saved to: {OUTPUT_FILE}")
if __name__ == "__main__":
print("Downloading images...")
img_paths = download_images()
print("Building PDF...")
build_pdf(img_paths)
print("Done!")
cd /home/daytona/workspace/elbow-surgical-guide && python3 generate_guide.py 2>&…
~/elbow-surgical-guide/generate_guide.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/elbow-surgical-guide/generate_guide.py'
cd /home/daytona/workspace/elbow-surgical-guide && python3 generate_guide.py 2>&…
~/elbow-surgical-guide/generate_guide.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/elbow-surgical-guide/generate_guide.py'
"safe_image(" in ~/elbow-surgical-guide