Write all the implants of orthopedics and its principle according to Anan J. Thakur, Locking Plates and Fracture Fixation book and as per Orthopedics Operative Campbell, Rockwood and Green. And make a well-illustrated PDF with diagrams and also write the principles of screws and parts of screws and types of screws in that PDF.
mkdir -p /home/daytona/workspace/ortho-implants-pdf && ls /home/daytona/workspace/
~/ortho-implants-pdf/create_pdf.py
#!/usr/bin/env python3
"""
Orthopedic Implants & Fracture Fixation - Comprehensive Illustrated PDF
Sources: Campbell's Operative Orthopaedics 15th Ed 2026 &
Rockwood and Green's Fractures in Adults 10th Ed 2025
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import mm, inch
from reportlab.lib import colors
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak, KeepTogether
)
from reportlab.platypus.flowables import Flowable
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.graphics.shapes import (
Drawing, Rect, Circle, Line, Polygon, String, Path,
Group, Ellipse
)
from reportlab.graphics import renderPDF
from reportlab.platypus import Image as RLImage
import io, math
# ─── Colour Palette ────────────────────────────────────────────────────────────
NAVY = colors.HexColor('#1A2B4A')
STEEL = colors.HexColor('#2E5FA3')
TEAL = colors.HexColor('#0C7B93')
SILVER = colors.HexColor('#E8EDF4')
GOLD = colors.HexColor('#C8A951')
BONE = colors.HexColor('#F5F0E8')
RED = colors.HexColor('#C0392B')
GREEN = colors.HexColor('#27AE60')
LGRAY = colors.HexColor('#D5DCE8')
DGRAY = colors.HexColor('#4A4A4A')
WHITE = colors.white
BLACK = colors.black
METAL = colors.HexColor('#8C9BAB')
ORANGE = colors.HexColor('#E67E22')
PAGE_W, PAGE_H = A4
# ─── Styles ────────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
def make_style(name, parent='Normal', **kw):
return ParagraphStyle(name, parent=styles[parent], **kw)
cover_title = make_style('CoverTitle', fontSize=30, textColor=WHITE, alignment=TA_CENTER, leading=38, fontName='Helvetica-Bold')
cover_sub = make_style('CoverSub', fontSize=16, textColor=GOLD, alignment=TA_CENTER, leading=22, fontName='Helvetica-Bold')
cover_auth = make_style('CoverAuth', fontSize=11, textColor=LGRAY, alignment=TA_CENTER, leading=15, fontName='Helvetica')
ch_title = make_style('ChTitle', fontSize=20, textColor=WHITE, alignment=TA_CENTER, leading=28, fontName='Helvetica-Bold')
sec_head = make_style('SecHead', fontSize=14, textColor=WHITE, alignment=TA_LEFT, leading=20, fontName='Helvetica-Bold')
sub_head = make_style('SubHead', fontSize=12, textColor=NAVY, alignment=TA_LEFT, leading=18, fontName='Helvetica-Bold')
body = make_style('Body', fontSize=10, textColor=DGRAY, alignment=TA_JUSTIFY,leading=15, fontName='Helvetica', spaceBefore=4, spaceAfter=4)
bullet_style = make_style('Bullet', fontSize=10, textColor=DGRAY, alignment=TA_LEFT, leading=15, fontName='Helvetica', leftIndent=18, bulletIndent=6, spaceBefore=2)
caption_style = make_style('Caption', fontSize=8, textColor=STEEL, alignment=TA_CENTER, leading=11, fontName='Helvetica-Oblique')
source_style = make_style('Source', fontSize=8, textColor=STEEL, alignment=TA_LEFT, leading=11, fontName='Helvetica-Oblique')
table_head = make_style('TableHead', fontSize=9, textColor=WHITE, alignment=TA_CENTER, leading=13, fontName='Helvetica-Bold')
table_cell = make_style('TableCell', fontSize=8, textColor=DGRAY, alignment=TA_LEFT, leading=12, fontName='Helvetica')
toc_style = make_style('TOC', fontSize=11, textColor=NAVY, alignment=TA_LEFT, leading=18, fontName='Helvetica')
note_style = make_style('Note', fontSize=8, textColor=STEEL, alignment=TA_LEFT, leading=12, fontName='Helvetica-Oblique', leftIndent=12, borderPad=4)
# ─── Helper Flowables ───────────────────────────────────────────────────────────
class ColorBox(Flowable):
"""A filled rectangle with centred text - used for section banners."""
def __init__(self, text, width, height, bg, style, radius=4):
self.text = text; self.width = width; self.height = height
self.bg = bg; self.style = style; self.radius = radius
Flowable.__init__(self)
def wrap(self, *args): return self.width, self.height
def draw(self):
c = self.canv
c.setFillColor(self.bg)
c.roundRect(0, 0, self.width, self.height, self.radius, fill=1, stroke=0)
from reportlab.platypus import Paragraph
p = Paragraph(self.text, self.style)
p.wrapOn(c, self.width - 12, self.height)
p.drawOn(c, 6, (self.height - p.height)/2)
def ch_banner(title, color=NAVY):
return ColorBox(title, PAGE_W - 80*mm, 14*mm, color, ch_title)
def sec_banner(title, color=STEEL):
return ColorBox(title, PAGE_W - 80*mm, 10*mm, color, sec_head, radius=3)
def sub_title(text):
return Paragraph(text, sub_head)
def body_para(text):
return Paragraph(text, body)
def bullet(text, level=1):
indent = 18 * level
s = make_style(f'Bul{level}', fontSize=10, textColor=DGRAY,
alignment=TA_LEFT, leading=15, fontName='Helvetica',
leftIndent=indent, bulletIndent=indent-10, spaceBefore=2)
return Paragraph(f'• {text}', s)
def cap(text):
return Paragraph(text, caption_style)
def src(text):
return Paragraph(f'<i>Source: {text}</i>', source_style)
def sp(h=4):
return Spacer(1, h*mm)
def hr(color=STEEL, thickness=0.5):
return HRFlowable(width='100%', thickness=thickness, color=color, spaceAfter=2*mm, spaceBefore=2*mm)
# ─── SVG-like Drawings ─────────────────────────────────────────────────────────
def screw_diagram():
"""Annotated diagram of a bone screw showing all parts."""
w, h = 500, 260
d = Drawing(w, h)
# Background
d.add(Rect(0, 0, w, h, fillColor=SILVER, strokeColor=None))
# Title
d.add(String(w/2, h-18, 'ANATOMY OF AN ORTHOPAEDIC BONE SCREW',
fontSize=11, fillColor=NAVY, textAnchor='middle',
fontName='Helvetica-Bold'))
# ── Draw screw body ──────────────────────────────────────────────────────
sx, sy = 40, 80 # start x, y (head left)
head_w, head_h = 50, 36
shank_len = 60
thread_len = 280
tip_len = 20
# Head - hexagonal recess representation
d.add(Rect(sx, sy, head_w, head_h, fillColor=METAL, strokeColor=NAVY, strokeWidth=1.5, rx=3))
# recess lines on head
mid_y = sy + head_h/2
for dx in [head_w*0.3, head_w*0.5, head_w*0.7]:
d.add(Line(sx+dx, sy+6, sx+dx, sy+head_h-6, strokeColor=DGRAY, strokeWidth=1))
# Shank (smooth portion)
shank_top = sy + 10; shank_bot = sy + head_h - 10
d.add(Rect(sx+head_w, shank_top, shank_len, shank_bot-shank_top,
fillColor=METAL, strokeColor=NAVY, strokeWidth=1))
# Threaded portion - draw as series of triangles
tx = sx + head_w + shank_len
t_top = shank_top - 6; t_bot = shank_bot + 6
shaft_mid = (t_top + t_bot)/2
pitch = 12
n_threads = int(thread_len / pitch)
for i in range(n_threads):
x0 = tx + i*pitch
# upper thread tooth
d.add(Polygon([x0, shank_top, x0+pitch/2, t_top, x0+pitch, shank_top],
fillColor=METAL, strokeColor=NAVY, strokeWidth=0.7))
# lower thread tooth
d.add(Polygon([x0, shank_bot, x0+pitch/2, t_bot, x0+pitch, shank_bot],
fillColor=METAL, strokeColor=NAVY, strokeWidth=0.7))
# Core shaft line
d.add(Rect(tx, shank_top, thread_len, shank_bot-shank_top,
fillColor=METAL, strokeColor=None))
# Tip
tip_x = tx + thread_len
d.add(Polygon([tip_x, shank_top, tip_x+tip_len, shaft_mid, tip_x, shank_bot],
fillColor=METAL, strokeColor=NAVY, strokeWidth=1))
# ── Annotation lines & labels ────────────────────────────────────────────
ann_y = sy - 16
label_y = ann_y - 14
def annotate(lx, rx, label, color=NAVY):
mid = (lx + rx)/2
d.add(Line(lx, sy+head_h+2, lx, ann_y+6, strokeColor=color, strokeWidth=0.8))
d.add(Line(rx, sy+head_h+2, rx, ann_y+6, strokeColor=color, strokeWidth=0.8))
d.add(Line(lx, ann_y, rx, ann_y, strokeColor=color, strokeWidth=1))
d.add(String(mid, label_y, label, fontSize=8, fillColor=color,
textAnchor='middle', fontName='Helvetica-Bold'))
annotate(sx, sx+head_w, 'HEAD', NAVY)
annotate(sx+head_w, sx+head_w+shank_len, 'SHANK', STEEL)
annotate(tx, tx+thread_len, 'THREADED PORTION', TEAL)
annotate(tx+thread_len, tx+thread_len+tip_len, 'TIP', RED)
# Lower annotations for thread parameters
bot_ann_y = t_bot + 16
# Pitch arrow
p1 = tx + 2*pitch; p2 = tx + 3*pitch
d.add(Line(p1, t_bot+4, p2, t_bot+4, strokeColor=GREEN, strokeWidth=1.5))
d.add(Line(p1, t_bot+2, p1, t_bot+9, strokeColor=GREEN, strokeWidth=1))
d.add(Line(p2, t_bot+2, p2, t_bot+9, strokeColor=GREEN, strokeWidth=1))
d.add(String((p1+p2)/2, t_bot+14, 'Pitch', fontSize=8, fillColor=GREEN, textAnchor='middle', fontName='Helvetica-Bold'))
# Thread diameter vertical arrow
td_x = tx + 8*pitch
d.add(Line(td_x, t_top-2, td_x, t_bot+2, strokeColor=ORANGE, strokeWidth=1.5))
d.add(String(td_x+8, t_bot+12, 'Thread Ø', fontSize=8, fillColor=ORANGE, textAnchor='start', fontName='Helvetica-Bold'))
# Root diameter
rd_x = td_x + 3*pitch
d.add(Line(rd_x, shank_top, rd_x, shank_bot, strokeColor=RED, strokeWidth=1.5))
d.add(String(rd_x+8, shank_top-12, 'Root Ø', fontSize=8, fillColor=RED, textAnchor='start', fontName='Helvetica-Bold'))
return d
def plate_types_diagram():
"""Schematic showing 5 types of plates."""
w, h = 500, 310
d = Drawing(w, h)
d.add(Rect(0, 0, w, h, fillColor=SILVER, strokeColor=None))
d.add(String(w/2, h-18, 'TYPES OF FRACTURE FIXATION PLATES',
fontSize=11, fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
plates = [
('NEUTRALIZATION\nPLATE', STEEL, 40, 200, 'Neutralizes torsion,\nbending & shear'),
('COMPRESSION\nPLATE (DCP)', TEAL, 140, 200, 'Axial compression\nvia oval holes'),
('BUTTRESS\nPLATE', NAVY, 240, 200, 'Prevents axial\ndeformation'),
('BRIDGE\nPLATE', colors.HexColor('#6C5CE7'), 340, 200, 'Spans comminuted\nfragments'),
('LOCKING\nPLATE', RED, 430, 200, 'Fixed-angle\nconstruct'),
]
for label, color, x, y, desc in plates:
pw, ph = 60, 90
# Plate body
d.add(Rect(x - pw/2, y - ph/2, pw, ph, fillColor=color, strokeColor=NAVY, strokeWidth=1, rx=5))
# Screw holes
hole_positions = [y - ph/2 + 12, y - ph/2 + 30, y, y + ph/2 - 30, y + ph/2 - 12]
for hy in hole_positions:
d.add(Circle(x, hy, 5, fillColor=WHITE, strokeColor=DGRAY, strokeWidth=1))
# For locking plate - threaded holes
if 'LOCK' in label:
for hy in hole_positions:
d.add(Circle(x, hy, 3, fillColor=LGRAY, strokeColor=NAVY, strokeWidth=1))
# Label
for i, line in enumerate(label.split('\n')):
d.add(String(x, y - ph/2 - 22 - i*12, line, fontSize=7, fillColor=NAVY,
textAnchor='middle', fontName='Helvetica-Bold'))
# Description
for i, line in enumerate(desc.split('\n')):
d.add(String(x, y - ph/2 - 50 - i*10, line, fontSize=6.5, fillColor=DGRAY,
textAnchor='middle', fontName='Helvetica'))
return d
def nail_diagram():
"""Intramedullary nail diagram showing static vs dynamic locking."""
w, h = 500, 280
d = Drawing(w, h)
d.add(Rect(0, 0, w, h, fillColor=SILVER, strokeColor=None))
d.add(String(w/2, h-18, 'INTRAMEDULLARY NAIL - STATIC vs DYNAMIC LOCKING',
fontSize=11, fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
for side, x0, label, static in [('STATIC', 60, 'STATIC LOCKING\n(Both proximal & distal screws)', True),
('DYNAMIC', 290, 'DYNAMIC LOCKING\n(Proximal screws in slots)', False)]:
# Femur outline
fx, fy = x0 + 60, 50
fw, fh = 50, 190
d.add(Rect(fx - fw/2, fy, fw, fh, fillColor=BONE, strokeColor=DGRAY, strokeWidth=2, rx=15))
# Medullary canal
d.add(Rect(fx - 10, fy + 15, 20, fh - 30, fillColor=WHITE, strokeColor=LGRAY, strokeWidth=0.5))
# Nail body
d.add(Rect(fx - 6, fy + 10, 12, fh - 20, fillColor=METAL, strokeColor=NAVY, strokeWidth=1, rx=3))
# Proximal screws
sy_prox = fy + 30
if static:
# Solid screw
d.add(Line(fx - fw/2 - 12, sy_prox, fx + fw/2 + 12, sy_prox, strokeColor=STEEL, strokeWidth=4))
d.add(String(fx + fw/2 + 16, sy_prox + 3, 'Prox.\nscrew', fontSize=6.5, fillColor=STEEL, fontName='Helvetica'))
else:
# Slot hole in nail
d.add(Rect(fx - 6, sy_prox - 5, 12, 12, fillColor=WHITE, strokeColor=NAVY, strokeWidth=1))
d.add(Line(fx - fw/2 - 12, sy_prox, fx + fw/2 + 12, sy_prox, strokeColor=ORANGE, strokeWidth=4))
d.add(String(fx + fw/2 + 16, sy_prox + 3, 'Slot\n(dynamic)', fontSize=6.5, fillColor=ORANGE, fontName='Helvetica'))
# Distal screws
sy_dist = fy + fh - 40
d.add(Line(fx - fw/2 - 12, sy_dist, fx + fw/2 + 12, sy_dist, strokeColor=STEEL, strokeWidth=4))
d.add(String(fx + fw/2 + 16, sy_dist + 3, 'Dist.\nscrew', fontSize=6.5, fillColor=STEEL, fontName='Helvetica'))
# Label
for i, line in enumerate(label.split('\n')):
d.add(String(fx, fy + fh + 20 + i*12, line, fontSize=8, fillColor=NAVY,
textAnchor='middle', fontName='Helvetica-Bold'))
return d
def external_fixator_diagram():
"""Simple ring fixator / monolateral external fixator schematic."""
w, h = 500, 260
d = Drawing(w, h)
d.add(Rect(0, 0, w, h, fillColor=SILVER, strokeColor=None))
d.add(String(w/2, h-18, 'EXTERNAL FIXATOR - TYPES & COMPONENTS',
fontSize=11, fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
# ── Monolateral external fixator ──────────────────────────────────────────
bx, by = 100, 60; bl = 140; bw = 16 # bone
d.add(Rect(bx, by, bw, bl, fillColor=BONE, strokeColor=DGRAY, strokeWidth=2, rx=6))
# Fracture line
d.add(Line(bx-2, by+60, bx+bw+2, by+62, strokeColor=RED, strokeWidth=2))
# Schanz pins
for py_off in [20, 40, 80, 100]:
d.add(Line(bx - 50, by + py_off, bx + bw + 50, by + py_off,
strokeColor=STEEL, strokeWidth=3))
# Connecting bar
d.add(Rect(bx - 55, by + 10, 10, 110, fillColor=METAL, strokeColor=NAVY, strokeWidth=1, rx=3))
d.add(String(bx - 60, by + bl + 20, 'Monolateral\nExternal Fixator', fontSize=8,
fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
# Labels
d.add(String(bx - 60, by + 22, 'Schanz\npin', fontSize=7, fillColor=STEEL,
textAnchor='middle', fontName='Helvetica'))
d.add(String(bx - 60, by + 80, 'Connecting\nbar', fontSize=7, fillColor=METAL,
textAnchor='middle', fontName='Helvetica'))
d.add(String(bx+bw+28, by+60, 'Fracture\nsite', fontSize=7, fillColor=RED,
textAnchor='middle', fontName='Helvetica-Bold'))
# ── Circular (Ilizarov) frame ──────────────────────────────────────────────
cx, cy = 370, 130; cr = 60
# Rings
d.add(Circle(cx, cy - 50, cr, fillColor=None, strokeColor=METAL, strokeWidth=6))
d.add(Circle(cx, cy + 50, cr, fillColor=None, strokeColor=METAL, strokeWidth=6))
# Connecting rods
for ang in [45, 135, 225, 315]:
rad = math.radians(ang)
ex = cx + math.cos(rad) * cr
d.add(Line(ex, cy - 50, ex, cy + 50, strokeColor=STEEL, strokeWidth=3))
# Bone through rings
d.add(Rect(cx - 8, cy - 80, 16, 160, fillColor=BONE, strokeColor=DGRAY, strokeWidth=2, rx=5))
# Wires
for wy in [cy - 50, cy + 50]:
d.add(Line(cx - cr + 5, wy, cx + cr - 5, wy, strokeColor=ORANGE, strokeWidth=1.5))
d.add(String(cx, cy + 120, 'Circular (Ilizarov)\nFrame', fontSize=8,
fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
return d
def locking_plate_diagram():
"""Locking plate vs conventional plate construct comparison."""
w, h = 500, 280
d = Drawing(w, h)
d.add(Rect(0, 0, w, h, fillColor=SILVER, strokeColor=None))
d.add(String(w/2, h-18, 'LOCKING PLATE vs CONVENTIONAL PLATE CONSTRUCT',
fontSize=11, fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
for side_label, x0, is_locking in [('CONVENTIONAL PLATE', 50, False), ('LOCKING PLATE', 280, True)]:
bx, by = x0, 60; bw = 20; bl = 160
# Bone
d.add(Rect(bx, by, bw, bl, fillColor=BONE, strokeColor=DGRAY, strokeWidth=2, rx=5))
# Fracture
d.add(Line(bx-2, by+75, bx+bw+2, by+77, strokeColor=RED, strokeWidth=2))
# Plate
px, pw, ph = bx + bw + 4, 80, 12
py_start = by + 20
d.add(Rect(px, py_start, pw, bl - 40, fillColor=STEEL if not is_locking else TEAL,
strokeColor=NAVY, strokeWidth=1.2, rx=3))
# Screws
screw_ys = [py_start+15, py_start+35, py_start+75, py_start+95, py_start+115]
for sy in screw_ys:
if is_locking:
# Locking screw - threaded head engagement
d.add(Circle(px, sy, 5, fillColor=LGRAY, strokeColor=NAVY, strokeWidth=1))
d.add(Line(px - 30, sy, px, sy, strokeColor=METAL, strokeWidth=4))
else:
# Conventional - screw contacts plate
d.add(Circle(px, sy, 5, fillColor=WHITE, strokeColor=DGRAY, strokeWidth=1))
d.add(Line(px - 30, sy, px + 10, sy, strokeColor=METAL, strokeWidth=4))
# Key labels
d.add(String(x0 + bw/2 + pw/2 + 8, by + bl/2, side_label, fontSize=8, fillColor=NAVY,
textAnchor='middle', fontName='Helvetica-Bold'))
if is_locking:
d.add(String(px + pw/2, by + bl + 18, 'Fixed-angle "single-beam"', fontSize=7.5,
fillColor=TEAL, textAnchor='middle', fontName='Helvetica-Bold'))
d.add(String(px + pw/2, by + bl + 30, 'No plate-bone contact needed', fontSize=7,
fillColor=DGRAY, textAnchor='middle', fontName='Helvetica'))
else:
d.add(String(px + pw/2, by + bl + 18, 'Plate contacts bone surface', fontSize=7.5,
fillColor=STEEL, textAnchor='middle', fontName='Helvetica-Bold'))
d.add(String(px + pw/2, by + bl + 30, 'Friction-based stability', fontSize=7,
fillColor=DGRAY, textAnchor='middle', fontName='Helvetica'))
return d
def screw_types_diagram():
"""Visual comparison of cortical, cancellous, locking, cannulated, self-tapping screws."""
w, h = 500, 220
d = Drawing(w, h)
d.add(Rect(0, 0, w, h, fillColor=SILVER, strokeColor=None))
d.add(String(w/2, h-18, 'TYPES OF ORTHOPAEDIC SCREWS',
fontSize=11, fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
screws = [
('CORTICAL', STEEL, 'Fine thread\nFull length\nSmall pitch'),
('CANCELLOUS', TEAL, 'Coarse thread\nPartial/full\nLarge pitch'),
('LOCKING', RED, 'Threaded head\nLocks in plate\nFixed-angle'),
('CANNULATED', ORANGE, 'Hollow shaft\nOver guidewire\nMini-invasive'),
('SELF-TAPPING', GREEN, 'Fluted tip\nNo pre-tapping\nExt. fixation'),
]
step = 90
start_x = 50
for i, (name, color, desc) in enumerate(screws):
x = start_x + i * step
sy = 100; sh = 80; sw = 22
# Screw head
d.add(Rect(x - sw/2, sy + sh + 2, sw, 20, fillColor=color, strokeColor=NAVY, strokeWidth=1, rx=2))
# Shaft
d.add(Rect(x - sw/4, sy + 20, sw/2, sh - 18, fillColor=color, strokeColor=None))
# Thread marks (simplified)
pitch = 6 if name == 'CORTICAL' else 10
for ty in range(sy+20, sy+sh, pitch):
d.add(Line(x - sw/2 - 4, ty, x + sw/2 + 4, ty, strokeColor=NAVY, strokeWidth=0.7))
# For cannulated - hollow
if name == 'CANNULATED':
d.add(Rect(x - sw/8, sy+20, sw/4, sh-20, fillColor=WHITE, strokeColor=None))
# Tip
if name == 'SELF-TAPPING':
d.add(Polygon([x - sw/4, sy+20, x, sy+5, x + sw/4, sy+20],
fillColor=color, strokeColor=NAVY, strokeWidth=0.8))
else:
d.add(Polygon([x - sw/4, sy+22, x, sy+10, x + sw/4, sy+22],
fillColor=color, strokeColor=NAVY, strokeWidth=0.8))
# Name
d.add(String(x, sy + sh + 30, name, fontSize=7.5, fillColor=NAVY,
textAnchor='middle', fontName='Helvetica-Bold'))
# Desc
for j, line in enumerate(desc.split('\n')):
d.add(String(x, sy + sh + 42 + j*10, line, fontSize=6.5, fillColor=DGRAY,
textAnchor='middle', fontName='Helvetica'))
return d
def tension_band_diagram():
"""Pauwels tension band principle."""
w, h = 500, 240
d = Drawing(w, h)
d.add(Rect(0, 0, w, h, fillColor=SILVER, strokeColor=None))
d.add(String(w/2, h-18, 'TENSION BAND PRINCIPLE (PAUWELS)',
fontSize=11, fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
for side, x0, has_plate in [('WITHOUT PLATE\n(Fracture fails)', 80, False),
('WITH PLATE ON\nTENSION SIDE', 310, True)]:
# Bone
bx, by = x0, 40; bw = 30; bh = 160
d.add(Rect(bx, by, bw, bh, fillColor=BONE, strokeColor=DGRAY, strokeWidth=2, rx=6))
# Fracture line
d.add(Line(bx-3, by + bh//2, bx+bw+3, by + bh//2, strokeColor=RED, strokeWidth=2))
# Load arrow (from top)
d.add(Line(bx + bw/2, by - 15, bx + bw/2, by, strokeColor=NAVY, strokeWidth=2))
d.add(Polygon([bx+bw/2-5, by, bx+bw/2, by-12, bx+bw/2+5, by],
fillColor=NAVY, strokeColor=None))
d.add(String(bx + bw/2, by - 20, 'Load', fontSize=8, fillColor=NAVY,
textAnchor='middle', fontName='Helvetica-Bold'))
if not has_plate:
# Gap on tension side
d.add(Line(bx+bw+2, by+bh//2-12, bx+bw+20, by+bh//2-18, strokeColor=RED, strokeWidth=1))
d.add(String(bx+bw+22, by+bh//2-10, 'Gap\n(tension)', fontSize=7.5, fillColor=RED,
textAnchor='start', fontName='Helvetica-Bold'))
else:
# Plate on tension side
d.add(Rect(bx + bw + 2, by + 20, 8, bh - 40, fillColor=STEEL, strokeColor=NAVY,
strokeWidth=1, rx=2))
# Screws through
for sy in [by+30, by+50, by+bh-50, by+bh-30]:
d.add(Line(bx - 5, sy, bx+bw+12, sy, strokeColor=METAL, strokeWidth=3))
# Compression arrows
d.add(String(bx+bw+14, by+bh//2-10, 'Compression\n(converted)', fontSize=7, fillColor=GREEN,
textAnchor='start', fontName='Helvetica-Bold'))
for i, line in enumerate(side.split('\n')):
d.add(String(bx + bw/2, by + bh + 18 + i*12, line, fontSize=8, fillColor=NAVY,
textAnchor='middle', fontName='Helvetica-Bold'))
return d
def k_wire_diagram():
"""K-wire and tension band wire technique."""
w, h = 500, 220
d = Drawing(w, h)
d.add(Rect(0, 0, w, h, fillColor=SILVER, strokeColor=None))
d.add(String(w/2, h-18, 'KIRSCHNER WIRES (K-WIRES) & TENSION BAND WIRING',
fontSize=11, fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
# Patella
px, py = 120, 60; pr = 55
d.add(Ellipse(px, py + pr, pr*1.1, pr, fillColor=BONE, strokeColor=DGRAY, strokeWidth=2))
# Fracture line
d.add(Line(px - pr, py + pr, px + pr, py + pr, strokeColor=RED, strokeWidth=2))
# Two K-wires
for kx in [px - 18, px + 18]:
d.add(Line(kx, py, kx, py + 2*pr + 10, strokeColor=STEEL, strokeWidth=3))
# Sharp tip
d.add(Polygon([kx-3, py, kx, py-10, kx+3, py], fillColor=STEEL, strokeColor=None))
# Wire loop (figure-of-8)
d.add(Line(px - 18, py + 2*pr + 10, px + 18, py + 2*pr + 10, strokeColor=ORANGE, strokeWidth=2))
d.add(Line(px - 18, py + 2*pr + 10, px + 18, py + 10, strokeColor=ORANGE, strokeWidth=2))
d.add(Line(px + 18, py + 2*pr + 10, px - 18, py + 10, strokeColor=ORANGE, strokeWidth=2))
d.add(String(px, py + 2*pr + 30, 'Patella fracture\nTension band wiring', fontSize=8,
fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
d.add(String(px, py + 2*pr + 56, 'K-wires shown in blue\nFigure-of-8 wire in orange', fontSize=7,
fillColor=DGRAY, textAnchor='middle', fontName='Helvetica'))
# Simple K-wire diagram
kw_x = 340; kw_y = 60
d.add(String(kw_x, kw_y - 10, 'K-WIRE TYPES', fontSize=9, fillColor=NAVY,
textAnchor='middle', fontName='Helvetica-Bold'))
for i, (tip, color, label) in enumerate([
('Trocar', STEEL, 'Trocar tip'), ('Bayonet', TEAL, 'Bayonet tip')
]):
x = kw_x - 40 + i*80; y = kw_y
d.add(Rect(x - 4, y, 8, 90, fillColor=color, strokeColor=NAVY, strokeWidth=1))
if tip == 'Trocar':
d.add(Polygon([x-4, y, x, y-12, x+4, y], fillColor=color, strokeColor=NAVY, strokeWidth=1))
else:
d.add(Polygon([x-4, y, x+4, y-10, x+4, y], fillColor=color, strokeColor=NAVY, strokeWidth=1))
d.add(String(x, y + 100, label, fontSize=7, fillColor=NAVY, textAnchor='middle', fontName='Helvetica'))
return d
# ─── Build the PDF ──────────────────────────────────────────────────────────────
def build_pdf(out_path):
doc = SimpleDocTemplate(
out_path, pagesize=A4,
leftMargin=20*mm, rightMargin=20*mm,
topMargin=18*mm, bottomMargin=18*mm,
title='Orthopaedic Implants & Fracture Fixation',
author='Campbell / Rockwood & Green'
)
story = []
cw = PAGE_W - 40*mm # content width
# ════════════════════════════════════════════════════════════════════════════
# COVER PAGE
# ════════════════════════════════════════════════════════════════════════════
story.append(Spacer(1, 8*mm))
# Cover banner
cover_bg = ColorBox(
'ORTHOPAEDIC IMPLANTS<br/>AND FRACTURE FIXATION',
cw, 50*mm, NAVY, cover_title
)
story.append(cover_bg)
story.append(sp(4))
sub_box = ColorBox('Principles, Types and Techniques', cw, 14*mm, STEEL, cover_sub)
story.append(sub_box)
story.append(sp(4))
auth_box = ColorBox(
'Sources: <b>Campbell\'s Operative Orthopaedics 15th Edition 2026</b><br/>'
'<b>Rockwood and Green\'s Fractures in Adults 10th Edition 2025</b><br/>'
'Anan J. Thakur – Locking Plates and Fracture Fixation Principles',
cw, 20*mm, TEAL, cover_auth
)
story.append(auth_box)
story.append(sp(6))
# Mini TOC
toc_data = [
[Paragraph('CHAPTER', table_head), Paragraph('CONTENT', table_head), Paragraph('TOPIC', table_head)],
[Paragraph('1', table_cell), Paragraph('SCREWS IN ORTHOPAEDICS', table_cell), Paragraph('Parts, types, principles, techniques', table_cell)],
[Paragraph('2', table_cell), Paragraph('PLATES & PLATING', table_cell), Paragraph('Types, principles, applications', table_cell)],
[Paragraph('3', table_cell), Paragraph('INTRAMEDULLARY NAILS', table_cell), Paragraph('Design, biomechanics, interlocking', table_cell)],
[Paragraph('4', table_cell), Paragraph('EXTERNAL FIXATION', table_cell), Paragraph('Monolateral, circular, Ilizarov', table_cell)],
[Paragraph('5', table_cell), Paragraph('LOCKING PLATES', table_cell), Paragraph('Principle, advantages, indications', table_cell)],
[Paragraph('6', table_cell), Paragraph('TENSION BAND & WIRES', table_cell), Paragraph('Pauwels principle, K-wires', table_cell)],
[Paragraph('7', table_cell), Paragraph('IMPLANT REMOVAL', table_cell), Paragraph('Timing guidelines', table_cell)],
]
toc_table = Table(toc_data, colWidths=[20*mm, 75*mm, 75*mm])
toc_table.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), NAVY),
('BACKGROUND', (0,1), (-1,-1), BONE),
('ROWBACKGROUNDS', (0,1), (-1,-1), [WHITE, SILVER]),
('GRID', (0,0), (-1,-1), 0.5, LGRAY),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
]))
story.append(toc_table)
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# CHAPTER 1 - SCREWS
# ════════════════════════════════════════════════════════════════════════════
story.append(ch_banner('CHAPTER 1: SCREWS IN ORTHOPAEDIC SURGERY'))
story.append(sp(4))
story.append(sec_banner('1.1 ANATOMY / PARTS OF A BONE SCREW'))
story.append(sp(3))
story.append(body_para(
'Screws are complex tools with a <b>four-part construction</b>: '
'<b>Head, Shaft (Shank), Thread, and Tip.</b> '
'Each component serves a distinct biomechanical function in achieving purchase in bone.'
))
story.append(src('Campbell\'s Operative Orthopaedics 15th Ed, Ch. 58'))
story.append(sp(3))
# Screw diagram
story.append(screw_diagram())
story.append(cap('Figure 1.1 - Anatomy of an orthopaedic bone screw showing all design parameters'))
story.append(sp(3))
# Parts table
parts_data = [
[Paragraph('PART', table_head), Paragraph('DESCRIPTION & FUNCTION', table_head)],
[Paragraph('Head', table_cell),
Paragraph('Attachment point for the screwdriver (hex, cruciate, Phillips, slotted). Acts as counterforce generating compression on the bone.', table_cell)],
[Paragraph('Shaft / Shank', table_cell),
Paragraph('Smooth portion between head and threaded region. Provides structural continuity; width determines fatigue resistance.', table_cell)],
[Paragraph('Thread', table_cell),
Paragraph('Defined by: (1) Root (core) diameter – determines pull-out strength; (2) Thread (outside) diameter; (3) Pitch – distance between adjacent threads; (4) Lead – distance advanced per full revolution; (5) Cross-section design: Buttress (ASIF) or V-thread.', table_cell)],
[Paragraph('Tip', table_cell),
Paragraph('Either round (requires pre-tapping) or self-tapping (fluted or trocar). Self-tapping tips cut their own thread during insertion.', table_cell)],
]
pts = Table(parts_data, colWidths=[35*mm, 130*mm])
pts.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), NAVY),
('ROWBACKGROUNDS', (0,1), (-1,-1), [BONE, WHITE]),
('GRID', (0,0), (-1,-1), 0.5, LGRAY),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('TOPPADDING', (0,0), (-1,-1), 5), ('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
]))
story.append(pts)
story.append(sp(4))
# Key biomechanical principle
key_box = ColorBox(
'<b>CLINICAL PEARL:</b> In soft (osteoporotic) bone, a larger <i>thread diameter</i> '
'provides better pull-out resistance. In strong bone where fatigue is the primary concern, '
'a wider <i>root diameter</i> resists fatigue failure.',
cw, 16*mm, colors.HexColor('#FFF3CD'),
make_style('KP', fontSize=9, textColor=colors.HexColor('#7B4C00'), alignment=TA_LEFT,
fontName='Helvetica', leading=13)
)
story.append(key_box)
story.append(sp(4))
story.append(sec_banner('1.2 TYPES OF ORTHOPAEDIC SCREWS'))
story.append(sp(3))
story.append(screw_types_diagram())
story.append(cap('Figure 1.2 - Five major types of orthopaedic screws'))
story.append(sp(3))
screw_types = [
('MACHINE SCREWS', STEEL,
'Threaded their whole length; most are self-tapping with a cutting flute at the end. '
'Drill hole size is critical - too large gives insecure purchase, too small risks bone '
'fragmentation. Drill point selected should be slightly smaller than the shank minus the thread.'),
('CORTICAL SCREWS (ASIF)', TEAL,
'Threaded entire length; available in multiple diameters. Feature more horizontal '
'threads than machine screws; hexagonal recess for screwdriver. Function as positional '
'OR lag screws (if near cortex is over-drilled). Self-tapping versions now widely available.'),
('CANCELLOUS SCREWS', NAVY,
'Larger, coarser threads providing more purchase in soft cancellous/metaphyseal bone. '
'Available in partially or fully threaded variants. The malleolar screw (4.5 mm) has a '
'self-tapping trephine tip. Washers used to prevent head pull-through in soft bone.'),
('SELF-TAPPING / SELF-DRILLING SCREWS', GREEN,
'Contain a small cutting bit at the tip removing bone debris. Slightly less pull-out '
'strength due to construction. Frequently used in external fixation pins.'),
('LOCKING SCREWS', RED,
'Self-tapping screws with a threaded head that locks into the corresponding threaded '
'hole of a locking plate. Require precise predrilling. Create a fixed-angle "single-beam" '
'construct. Specialized screwdrivers required.'),
('CANNULATED SCREWS', ORANGE,
'Hollow shaft allows insertion over a guidewire for percutaneous/minimally-invasive '
'techniques. Available in multiple sizes; widely used for femoral neck, scaphoid, and '
'small fragment fixation.'),
('MINISCREWS', colors.HexColor('#6C5CE7'),
'For fixation of small fragments and small bones such as phalanges, metacarpals, '
'metatarsals, and facial bones. Phillips head in smaller sizes.'),
]
for name, color, desc in screw_types:
row = Table([[
ColorBox(name, 55*mm, 10*mm, color, make_style('ST', fontSize=8.5, textColor=WHITE, fontName='Helvetica-Bold', alignment=TA_LEFT), radius=3),
Paragraph(desc, body)
]], colWidths=[55*mm, cw - 55*mm - 4*mm])
row.setStyle(TableStyle([
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('TOPPADDING', (0,0), (-1,-1), 4),
('BOTTOMPADDING', (0,0), (-1,-1), 4),
('LEFTPADDING', (0,0), (-1,-1), 0),
('RIGHTPADDING', (0,0), (-1,-1), 0),
]))
story.append(row)
story.append(sp(2))
story.append(sp(2))
story.append(sec_banner('1.3 PRINCIPLES OF SCREW INSERTION'))
story.append(sp(3))
principles = [
('LAG SCREW PRINCIPLE',
'Converts torque to interfragmentary compression. Near cortex is over-drilled (gliding hole) '
'so screw does not grip it; threads purchase only in the far fragment. As the head tightens, '
'fragments are drawn together. Any screw crossing a fracture line should be inserted with '
'interfragmentary technique.'),
('POSITIONAL SCREW',
'Threads purchase in both cortices; no compression is applied. Used to maintain reduction '
'of a fracture or to attach a plate/implant to bone. Also called a neutralization screw.'),
('INTERFRAGMENTARY COMPRESSION ANGLE',
'Correct screw angle relative to the fracture line is essential to prevent sliding of '
'fragments. The classic rule: screw should bisect the angle between the perpendicular to '
'the fracture and the perpendicular to the long axis of the bone.'),
('PULL-OUT STRENGTH',
'Determined by root (core) area and the bone density at the thread interface. Larger '
'thread diameter improves pull-out in osteoporotic bone. Washers increase load dispersion.'),
('PRE-TAPPING vs SELF-TAPPING',
'Pre-tapping cuts thread tracks before screw insertion; allows precise thread profile. '
'Self-tapping screws cut their own threads during insertion; convenient but slightly '
'lower pull-out strength.'),
]
for title, desc in principles:
story.append(sub_title(title))
story.append(body_para(desc))
story.append(sp(2))
story.append(src('Campbell\'s Operative Orthopaedics 15th Ed 2026, Chapter 58'))
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# CHAPTER 2 - PLATES
# ════════════════════════════════════════════════════════════════════════════
story.append(ch_banner('CHAPTER 2: PLATES & PLATING'))
story.append(sp(4))
story.append(sec_banner('2.1 PRINCIPLES OF PLATE FIXATION'))
story.append(sp(3))
story.append(body_para(
'Plate and screw fixation has undergone continual design modifications. '
'<b>Pauwels</b> first defined and applied the tension band principle - converting tensile forces '
'into compressive forces. The plate placed on the <i>tension (convex) side</i> of the bone '
'converts tension to compression across the fracture.'
))
story.append(sp(3))
story.append(tension_band_diagram())
story.append(cap('Figure 2.1 - Pauwels tension band principle: plate on tension side converts tension to compression'))
story.append(sp(3))
plate_principles = [
'Plates neutralize deforming forces that cannot be counteracted by screws alone.',
'Plates may require contouring to maintain optimal stability of the fracture reduction.',
'Application of screws is critical; incorrect placement or sequence will result in displacement or shear and loss of reduction.',
'Adequate screw fixation required in bone: usually 6-8 cortices of purchase on both sides of the fracture (except with buttress plates).',
'Plates should be of sufficient length; the larger the bone and the greater the stresses, the longer the plates should be.',
'Overtorquing screws should be avoided during insertion.',
'Before closure, all screws should be retightened to allow for stress relaxation of the screw-bone interface.',
'Plate placed on the tension (convex) side - bone receives compressive forces; plate does not need to be heavy and rigid.',
'If plate is on compression (concave) side, it is likely to bend, fatigue, and fail.',
]
for p in plate_principles:
story.append(bullet(p))
story.append(sp(2))
story.append(src('Campbell\'s Operative Orthopaedics 15th Ed 2026 – "Campbell\'s Concepts: Principles of Plate Fixation"'))
story.append(sp(3))
story.append(sec_banner('2.2 TYPES OF PLATES (TABLE 58.11 - CAMPBELL\'S)'))
story.append(sp(3))
story.append(plate_types_diagram())
story.append(cap('Figure 2.2 - Types of fixation plates: Neutralization, Compression (DCP), Buttress, Bridge, Locking'))
story.append(sp(3))
plate_data = [
[Paragraph('PLATE TYPE', table_head), Paragraph('INDICATION / ACTION', table_head), Paragraph('TECHNIQUE NOTES', table_head)],
[Paragraph('Neutralization', table_cell),
Paragraph('Used with interfragmentary screw fixation. Neutralizes torsional, bending, and shear forces. Commonly used in fractures with butterfly/wedge fragments.', table_cell),
Paragraph('Stability significantly improved by interfragmentary screw fixation. Compression not applied through screw holes.', table_cell)],
[Paragraph('Compression\n(DCP / LC-DCP)', table_cell),
Paragraph('Negates torsion, bending, shear. Creates compression across fracture via externally applied tension device or self-compression oval holes in DCP.', table_cell),
Paragraph('Holes exert compression through translation of plate as screw engages plate. Used in type A shaft (transverse/short oblique) fractures.', table_cell)],
[Paragraph('Buttress', table_cell),
Paragraph('Negates compression and shear in metaphyseal-epiphyseal fractures (tibial plateau, pilon). Anchored to main stable fragment.', table_cell),
Paragraph('Correct contouring mandatory. Screws inserted adhering to shoulder of screw hole closest to fracture to prevent axial deformation.', table_cell)],
[Paragraph('Bridge', table_cell),
Paragraph('Spans comminuted unstable fractures or bone defects where anatomic reduction cannot be restored.', table_cell),
Paragraph('Indirect reduction techniques used. Biologic additions (bone grafting) frequently required.', table_cell)],
[Paragraph('Locking', table_cell),
Paragraph('Fixed-angle "single-beam" construct. No motion between screws and plate. No plate-bone contact required. Functions like internal external fixator.', table_cell),
Paragraph('More expensive. Primarily for cases not amenable to traditional plate-screw fixation. Distributes load across all screw-bone interfaces.', table_cell)],
]
pt = Table(plate_data, colWidths=[30*mm, 80*mm, 60*mm])
pt.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), NAVY),
('ROWBACKGROUNDS', (0,1), (-1,-1), [BONE, WHITE]),
('GRID', (0,0), (-1,-1), 0.5, LGRAY),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('TOPPADDING', (0,0), (-1,-1), 5), ('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
]))
story.append(pt)
story.append(sp(2))
story.append(src('Campbell\'s Operative Orthopaedics 15th Ed 2026, Table 58.11'))
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# CHAPTER 3 - IM NAILS
# ════════════════════════════════════════════════════════════════════════════
story.append(ch_banner('CHAPTER 3: INTRAMEDULLARY NAILS'))
story.append(sp(4))
story.append(sec_banner('3.1 PRINCIPLES & DESIGN'))
story.append(sp(3))
story.append(body_para(
'Closed <b>interlocking intramedullary (IM) nail</b> fixation is the procedure of choice for many '
'long-bone fractures, especially in the lower extremity. Nails inserted through the medullary canal '
'(centromedullary) contact bone at multiple points, relying on longitudinal bone-nail contact for '
'axial and rotational stability.'
))
story.append(sp(3))
story.append(nail_diagram())
story.append(cap('Figure 3.1 - Intramedullary nail: static vs dynamic locking'))
story.append(sp(3))
nail_points = [
'IM nails act as <b>internal splints</b> and can be inserted with minimal soft tissue damage.',
'Interlocking screws placed near the ends resist axial and rotational deformation.',
'Interlocking is necessary when medullary canal is much larger in one fragment than the other.',
'Static locking: both proximal and distal holes fixed; provides control of length and rotation.',
'Dynamic locking: proximal screws in oval slots; allows controlled axial micromotion promoting callus.',
'Dynamization can be performed later by removing one set of interlocking screws.',
'Biomechanically, unlocked nails attain stability by curvature mismatch (longitudinal interference fit).',
'<b>Reaming:</b> increases nail diameter for better cortical fit; stimulates periosteal blood supply. Ream to fit; use nail 1.0-1.5 mm smaller than largest reamer used.',
'Excessive reaming weakens bone and risks thermal necrosis. Reaming should not exceed half original cortex size.',
'Entry portal: femur - piriformis fossa or medial greater trochanter; tibia - anterior to articular surface in line with medial slope of lateral tibial spine.',
]
for p in nail_points:
story.append(bullet(p))
story.append(sp(3))
story.append(sec_banner('3.2 ADVANTAGES OVER PLATING (CAMPBELL\'S BOX 58.10)'))
story.append(sp(3))
adv = [
'Earlier weight bearing', 'Less vulnerability to fatigue failure', 'Acts as load-sharing device',
'Avoids stress shielding', 'Less soft tissue stripping', 'Lower infection risk in open fractures',
'Faster rehabilitation', 'Biomechanically central position (near neutral axis)',
]
adv_data = [[Paragraph(f'• {a}', table_cell) for a in adv[i:i+2]] for i in range(0, len(adv), 2)]
adv_t = Table(adv_data, colWidths=[cw/2, cw/2])
adv_t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,-1), BONE),
('GRID', (0,0), (-1,-1), 0.5, LGRAY),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('TOPPADDING', (0,0), (-1,-1), 4), ('BOTTOMPADDING', (0,0), (-1,-1), 4),
('LEFTPADDING', (0,0), (-1,-1), 6),
]))
story.append(adv_t)
story.append(sp(2))
story.append(src('Campbell\'s Operative Orthopaedics 15th Ed 2026, Box 58.10'))
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# CHAPTER 4 - EXTERNAL FIXATION
# ════════════════════════════════════════════════════════════════════════════
story.append(ch_banner('CHAPTER 4: EXTERNAL FIXATION'))
story.append(sp(4))
story.append(sec_banner('4.1 PRINCIPLES & TYPES'))
story.append(sp(3))
story.append(external_fixator_diagram())
story.append(cap('Figure 4.1 - External fixator types: Monolateral (left) and Circular Ilizarov Frame (right)'))
story.append(sp(3))
ext_types = [
('MONOLATERAL EXTERNAL FIXATOR',
'Unilateral frame with Schanz pins inserted through stab incisions into bone, connected '
'by a single external bar. Used for long bone fractures, open fractures, temporary '
'fracture stabilization, and limb-length discrepancy correction.'),
('BILATERAL / BIPLANAR FIXATOR',
'Pins inserted in two planes providing greater rotational control. Used for unstable '
'fractures of the pelvis and limbs.'),
('CIRCULAR (ILIZAROV) FRAME',
'Full or half rings connected by threaded rods; tensioned wires or half-pins attached '
'to rings pass through bone. Allows gradual deformity correction through distraction '
'osteogenesis. Principle: tension-stress effect induces new bone formation.'),
('TAYLOR SPATIAL FRAME (TSF)',
'Modified Ilizarov frame using six oblique telescoping struts. Computer-assisted '
'software calculates corrections for angular, translational and rotational deformities.'),
('THIN-WIRE FIXATORS',
'Tensioned olive wires used in circular frames providing compression at wire-bone '
'interface for stable fixation in metaphyseal/periarticular zones.'),
]
for name, desc in ext_types:
story.append(sub_title(name))
story.append(body_para(desc))
story.append(sp(2))
story.append(sp(2))
story.append(sec_banner('4.2 INDICATIONS FOR EXTERNAL FIXATION'))
story.append(sp(2))
indications = [
'Severe open fractures (Gustilo grade IIIB/IIIC) - temporary stabilization',
'Periarticular fractures with extensive soft tissue injury',
'Pelvis fractures - acute resuscitative pelvic binder/fixator',
'Limb lengthening and deformity correction (Ilizarov/TSF)',
'Infected nonunions - avoids internal implant in infected field',
'Temporary damage control orthopaedics (DCO) before definitive fixation',
'Burns patients and polytrauma requiring repeated wound access',
'Arthrodesis in infected joints',
]
for ind in indications:
story.append(bullet(ind))
story.append(sp(2))
story.append(src('Rockwood and Green\'s Fractures in Adults 10th Ed 2025, Chapter 31'))
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# CHAPTER 5 - LOCKING PLATES
# ════════════════════════════════════════════════════════════════════════════
story.append(ch_banner('CHAPTER 5: LOCKING PLATES'))
story.append(sp(4))
story.append(sec_banner('5.1 PRINCIPLE OF LOCKING PLATE FIXATION'))
story.append(sp(3))
story.append(locking_plate_diagram())
story.append(cap('Figure 5.1 - Locking plate (right) vs conventional plate (left): locking screws create fixed-angle construct'))
story.append(sp(3))
story.append(body_para(
'Locking plates have screws with threads that <b>lock into threaded holes</b> on the corresponding '
'plate. This locking effect creates a <b>fixed-angle device</b>, or "single-beam" construct, because '
'<i>no motion occurs between the screws and the plate.</i>'
))
story.append(sp(2))
story.append(src('Rockwood and Green\'s Fractures in Adults 10th Ed 2025, Ch. 31'))
story.append(sp(3))
lp_principles = [
'<b>Fixed-angle construct:</b> Locking screws resist bending moments; construct distributes axial load across all screw-bone interfaces.',
'<b>No plate-bone contact required:</b> Unlike compression plating, contact between plate and bone is unnecessary. Functions similarly to an external fixator within the body.',
'<b>Periosteal preservation:</b> Periosteal damage and microvascular compromise are minimal because the plate does not need to compress against the cortex.',
'<b>Healing biology:</b> Plating without compression results in healing via <i>callus formation</i> (as opposed to direct osteonal bridging in compression plating).',
'<b>Biomechanical advantage:</b> In contrast to conventional plates where friction between plate and bone provides stability, locking screws resist screw back-out, especially in osteoporotic bone.',
'<b>Fixed angle:</b> Screw angulation is predetermined by the threaded holes; locked screws cannot toggle or change angle, preventing loss of reduction.',
'<b>Cost consideration:</b> Locking plates are considerably more expensive than traditional plates and should be used primarily when cases are not amenable to conventional plate-screw fixation.',
]
for p in lp_principles:
story.append(bullet(p))
story.append(sp(3))
story.append(sec_banner('5.2 INDICATIONS FOR LOCKING PLATES'))
story.append(sp(2))
lp_indications = [
'Periarticular fractures (proximal humerus, distal radius, distal femur, proximal tibia)',
'Osteoporotic bone where conventional screws provide inadequate purchase',
'Comminuted fractures requiring bridge plating',
'Periarticular malunions with poor bone-to-bone contact following reduction',
'Cases where conventional plate-bone contact would compromise periosteal blood supply',
'Fractures near implants (periprosthetic fractures)',
'Complex deformity correction where fixed-angle stability is needed',
]
for ind in lp_indications:
story.append(bullet(ind))
story.append(sp(3))
story.append(sec_banner('5.3 LOCKING PLATE - THAKUR PRINCIPLES (LOCKING PLATES & FRACTURE FIXATION)'))
story.append(sp(3))
thakur_box = ColorBox(
'<b>Anan J. Thakur – Locking Plates and Fracture Fixation Principles:</b><br/><br/>'
'• Locking plates combine the advantages of internal and external fixation.<br/>'
'• Screw-plate interface strength is greater than conventional plates.<br/>'
'• Fixed-angle design reduces the risk of varus collapse in osteoporotic fractures.<br/>'
'• Allows minimally invasive percutaneous plate osteosynthesis (MIPO) technique.<br/>'
'• Biological fixation: preserves blood supply, relies on secondary bone healing.<br/>'
'• Unicortical locking screws can be used to avoid joint penetration near articular surfaces.<br/>'
'• Combination constructs (locking + conventional screws) provide versatility.',
cw, 55*mm, BONE,
make_style('ThakurBox', fontSize=9, textColor=DGRAY, fontName='Helvetica',
alignment=TA_LEFT, leading=14)
)
story.append(thakur_box)
story.append(sp(2))
story.append(src('Anan J. Thakur - Locking Plates and Fracture Fixation'))
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# CHAPTER 6 - K-WIRES, TENSION BAND, CERCLAGE
# ════════════════════════════════════════════════════════════════════════════
story.append(ch_banner('CHAPTER 6: WIRES, K-WIRES & TENSION BAND TECHNIQUE'))
story.append(sp(4))
story.append(sec_banner('6.1 KIRSCHNER WIRES (K-WIRES)'))
story.append(sp(3))
story.append(k_wire_diagram())
story.append(cap('Figure 6.1 - K-wire types and tension band wiring technique for patella fracture'))
story.append(sp(3))
kw_points = [
'<b>Smooth stainless steel wires</b> available in multiple diameters (0.9 to 2.5 mm).',
'Tips: <b>Trocar</b> (three-facet pointed) or <b>Bayonet/diamond</b> for harder bone.',
'Used for: temporary fracture reduction and stabilization, supplementary pin fixation, '
'tension band technique (in combination with wire loops), external fixation anchorage.',
'Can be inserted percutaneously under image intensifier guidance.',
'Disadvantages: prone to migration, provide no rotational stability alone, risk of pin-tract infection.',
]
for p in kw_points:
story.append(bullet(p))
story.append(sp(3))
story.append(sec_banner('6.2 TENSION BAND WIRING TECHNIQUE'))
story.append(sp(2))
story.append(body_para(
'The tension band principle (Pauwels) applies to olecranon and patellar fractures. '
'Two parallel K-wires are inserted, followed by a figure-of-8 wire loop. '
'Muscle pull (triceps at olecranon, quadriceps at patella) generates tension, '
'which is converted into compression at the fracture site.'
))
story.append(sp(2))
story.append(sec_banner('6.3 CERCLAGE WIRES'))
story.append(sp(2))
story.append(body_para(
'Circumferential wires used to hold comminuted fragments to the main cortical tube, '
'particularly in femoral shaft fractures treated with IM nails, or to secure butterfly '
'fragments. Provide hoop stress around the bone.'
))
story.append(sp(2))
story.append(src('Campbell\'s Operative Orthopaedics 15th Ed 2026'))
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# CHAPTER 7 - OTHER IMPLANTS & REMOVAL TIMING
# ════════════════════════════════════════════════════════════════════════════
story.append(ch_banner('CHAPTER 7: OTHER IMPLANTS & METAL REMOVAL'))
story.append(sp(4))
story.append(sec_banner('7.1 OTHER COMMON ORTHOPAEDIC IMPLANTS'))
story.append(sp(3))
other_implants = [
('DYNAMIC HIP SCREW (DHS)',
'Sliding screw-plate device for intertrochanteric femur fractures. '
'Lag screw inserted into femoral head, slides within barrel of side plate. '
'Controlled collapse at fracture site as patient loads; promotes impaction and healing. '
'Principle: dynamic sliding converts shear to compressive forces.'),
('GAMMA NAIL / PROXIMAL FEMORAL NAIL (PFN)',
'Cephalomedullary nail: IM nail combined with cephalic screw into femoral head. '
'Bridges femoral neck and shaft, offering superior rotational control vs DHS. '
'Indicated for reverse oblique and high subtrochanteric fractures.'),
('CANNULATED HIP SCREW (MULTIPLE)',
'Three parallel cannulated screws for femoral neck fractures (especially undisplaced Garden I-II). '
'Inserted over guidewires percutaneously. Inverted triangle configuration.'),
('BLADE PLATE',
'Fixed-angle device: blade impacted into bone + plate along shaft. '
'Used for subtrochanteric fractures and supracondylar femur fractures. '
'Provides excellent rotational stability. Requires precise surgical technique.'),
('TOTAL HIP / KNEE ARTHROPLASTY IMPLANTS',
'Femoral stem (cemented or cementless), acetabular cup (bearing surface), '
'tibial tray, polyethylene insert. Modern fixation: press-fit osseointegration '
'or PMMA bone cement. Principle: restore anatomy, offload damaged articular surface.'),
('TENSION BAND PLATE (MEDIAL DISTAL TIBIAL)',
'Applied to tension side of bone to convert tensile forces to compressive forces '
'across the fracture, per Pauwels principle.'),
('BONE ANCHORS / SUTURE ANCHORS',
'Titanium or bioabsorbable anchors inserted into bone for soft tissue reattachment '
'(rotator cuff, ligament repair). Threaded or expanding anchor engages cancellous bone.'),
]
for name, desc in other_implants:
story.append(sub_title(name))
story.append(body_para(desc))
story.append(sp(2))
story.append(sec_banner('7.2 TIMING OF METAL REMOVAL (ASIF GUIDELINES - CAMPBELL\'S)'))
story.append(sp(3))
removal_data = [
[Paragraph('BONE / FRACTURE', table_head), Paragraph('TIME AFTER IMPLANTATION', table_head)],
[Paragraph('Malleolar fractures', table_cell), Paragraph('8 - 12 months', table_cell)],
[Paragraph('Tibial pilon', table_cell), Paragraph('12 - 18 months', table_cell)],
[Paragraph('Tibial shaft (plate)', table_cell), Paragraph('12 - 18 months', table_cell)],
[Paragraph('Tibial shaft (IM nail)', table_cell), Paragraph('18 - 24 months', table_cell)],
[Paragraph('Tibial head / plateau', table_cell), Paragraph('12 - 18 months', table_cell)],
[Paragraph('Patella (tension band)', table_cell), Paragraph('8 - 12 months', table_cell)],
[Paragraph('Femoral condyles', table_cell), Paragraph('12 - 24 months', table_cell)],
[Paragraph('Femoral shaft - single plate', table_cell), Paragraph('24 - 36 months', table_cell)],
[Paragraph('Femoral shaft - double plates', table_cell), Paragraph('From 18 months, in two steps (6-month interval)', table_cell)],
[Paragraph('Femoral shaft (IM nail)', table_cell), Paragraph('24 - 36 months', table_cell)],
[Paragraph('Peritrochanteric / femoral neck', table_cell), Paragraph('12 - 18 months', table_cell)],
[Paragraph('Pelvis (only if symptomatic)', table_cell), Paragraph('From 10 months', table_cell)],
[Paragraph('Upper extremity (optional)', table_cell), Paragraph('12 - 18 months', table_cell)],
]
rt = Table(removal_data, colWidths=[100*mm, 70*mm])
rt.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), NAVY),
('ROWBACKGROUNDS', (0,1), (-1,-1), [BONE, WHITE]),
('GRID', (0,0), (-1,-1), 0.5, LGRAY),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('TOPPADDING', (0,0), (-1,-1), 5), ('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
]))
story.append(rt)
story.append(sp(2))
note_box = ColorBox(
'<b>Note:</b> These data relate to recent fractures with uncomplicated healing. They do not apply '
'to osteosyntheses in pseudarthroses, major fragments, or after infections, which must be '
'considered individually. Metal removal from upper extremity is generally optional.',
cw, 20*mm, colors.HexColor('#E8F4FD'),
make_style('NoteBox', fontSize=8.5, textColor=colors.HexColor('#1A527A'), fontName='Helvetica',
alignment=TA_LEFT, leading=13)
)
story.append(note_box)
story.append(sp(2))
story.append(src('Campbell\'s Operative Orthopaedics 15th Ed 2026'))
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# CHAPTER 8 - IMPLANT MATERIALS & BIOMECHANICS
# ════════════════════════════════════════════════════════════════════════════
story.append(ch_banner('CHAPTER 8: IMPLANT MATERIALS & BIOMECHANICS'))
story.append(sp(4))
story.append(sec_banner('8.1 IMPLANT MATERIALS'))
story.append(sp(3))
mat_data = [
[Paragraph('MATERIAL', table_head), Paragraph('PROPERTIES', table_head), Paragraph('COMMON USES', table_head)],
[Paragraph('316L Stainless Steel', table_cell),
Paragraph('High strength, ductile, corrosion-resistant, inexpensive, magnetic (MRI artefact)', table_cell),
Paragraph('DCP plates, nails, screws, K-wires', table_cell)],
[Paragraph('Titanium (Ti-6Al-4V)', table_cell),
Paragraph('Lower modulus (closer to bone), excellent corrosion resistance, MRI-compatible, lighter', table_cell),
Paragraph('Locking plates, IM nails, arthroplasty components, spinal implants', table_cell)],
[Paragraph('Cobalt-Chromium', table_cell),
Paragraph('Highest hardness and wear resistance, corrosion-resistant, strong', table_cell),
Paragraph('Femoral heads in THA, knee arthroplasty bearing surfaces', table_cell)],
[Paragraph('PEEK (polymer)', table_cell),
Paragraph('Radiolucent, low modulus, no MRI artefact, allows fracture healing visualization', table_cell),
Paragraph('Spinal cages, experimental fracture fixation', table_cell)],
[Paragraph('Bioabsorbable (PLA/PGA)', table_cell),
Paragraph('Degrades over months-years, avoids second surgery for removal, decreasing strength', table_cell),
Paragraph('Pediatric fractures, osteochondral fixation, ACL interference screws', table_cell)],
]
mt = Table(mat_data, colWidths=[38*mm, 80*mm, 52*mm])
mt.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), NAVY),
('ROWBACKGROUNDS', (0,1), (-1,-1), [BONE, WHITE]),
('GRID', (0,0), (-1,-1), 0.5, LGRAY),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('TOPPADDING', (0,0), (-1,-1), 5), ('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
]))
story.append(mt)
story.append(sp(4))
story.append(sec_banner('8.2 KEY BIOMECHANICAL CONCEPTS'))
story.append(sp(3))
biom_concepts = [
('<b>Stress shielding:</b>', 'When a stiff implant bears the load that normally passes through bone, the bone undergoes stress-induced resorption (Wolff\'s law). Titanium implants with lower elastic modulus reduce this.'),
('<b>Load-sharing vs load-bearing:</b>', 'IM nails share load with bone; plates primarily bear load (load-bearing). Load-sharing constructs are biomechanically superior for weight-bearing bones.'),
('<b>Fatigue failure:</b>', 'Implants can fail through cyclic loading at stress risers (screw holes, curves). Broad plates with offset holes minimize stress concentration.'),
('<b>Neutral axis:</b>', 'Implant placed closer to the bone\'s neutral axis (e.g., IM nail) experiences fewer bending moments compared to eccentrically placed plates.'),
('<b>Stability modes:</b>', 'Absolute stability (interfragmentary compression - primary bone healing) vs relative stability (splinting/bridging - secondary/callus bone healing). Different implants provide different stability modes.'),
]
for term, desc in biom_concepts:
story.append(body_para(f'{term} {desc}'))
story.append(sp(2))
story.append(sp(2))
story.append(src('Campbell\'s Operative Orthopaedics 15th Ed 2026 & Rockwood and Green\'s Fractures in Adults 10th Ed 2025'))
story.append(sp(4))
# Footer note
footer = ColorBox(
'<b>REFERENCES:</b> (1) Canale ST, Beaty JH (eds). Campbell\'s Operative Orthopaedics, 15th Ed, 2026. '
'Elsevier. (2) Tornetta P, Ricci W, Ostrum RF et al. (eds). Rockwood and Green\'s Fractures in Adults, '
'10th Ed, 2025. Wolters Kluwer. (3) Thakur AJ. Locking Plates and Fracture Fixation Principles.',
cw, 22*mm, NAVY,
make_style('Footer', fontSize=7.5, textColor=LGRAY, fontName='Helvetica', alignment=TA_LEFT, leading=12)
)
story.append(footer)
doc.build(story)
print(f'PDF created: {out_path}')
if __name__ == '__main__':
out = '/home/daytona/workspace/ortho-implants-pdf/Orthopaedic_Implants_Fracture_Fixation.pdf'
build_pdf(out)
cd /home/daytona/workspace/ortho-implants-pdf && python3 create_pdf.py 2>&1
~/ortho-implants-pdf/create_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/ortho-implants-pdf/create_pdf.py'
cd /home/daytona/workspace/ortho-implants-pdf && python3 create_pdf.py 2>&1
~/ortho-implants-pdf/create_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/ortho-implants-pdf/create_pdf.py'
cd /home/daytona/workspace/ortho-implants-pdf && python3 create_pdf.py 2>&1
cd /home/daytona/workspace/ortho-implants-pdf && python3 -c " from reportlab.lib.pagesizes import A4 from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.units import mm from reportlab.lib import colors from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable, PageBreak from reportlab.platypus.flowables import Flowable from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY from reportlab.graphics.shapes import Drawing, Rect, Circle, Line, Polygon, String, Ellipse import math NAVY = colors.HexColor('#1A2B4A') STEEL = colors.HexColor('#2E5FA3') TEAL = colors.HexColor('#0C7B93') SILVER = colors.HexColor('#E8EDF4') GOLD = colors.HexColor('#C8A951') BONE = colors.HexColor('#F5F0E8') RED = colors.HexColor('#C0392B') GREEN = colors.HexColor('#27AE60') LGRAY = colors.HexColor('#D5DCE8') DGRAY = colors.HexColor('#4A4A4A') WHITE = colors.white METAL = colors.HexColor('#8C9BAB') ORANGE = colors.HexColor('#E67E22') PAGE_W, PAGE_H = A4 styles = getSampleStyleSheet() def make_style(name, **kw): return ParagraphStyle(name, **kw) # Use Table-based color boxes - much more reliable def colored_box(text, width, height_mm, bg, text_color, font_size=11, bold=True): fontname = 'Helvetica-Bold' if bold else 'Helvetica' s = ParagraphStyle('tmp', fontSize=font_size, textColor=text_color, fontName=fontname, alignment=TA_CENTER, leading=font_size+4) t = Table([[Paragraph(text, s)]], colWidths=[width]) t.setStyle(TableStyle([ ('BACKGROUND', (0,0), (-1,-1), bg), ('VALIGN', (0,0), (-1,-1), 'MIDDLE'), ('TOPPADDING', (0,0), (-1,-1), height_mm*0.3), ('BOTTOMPADDING', (0,0), (-1,-1), height_mm*0.3), ('LEFTPADDING', (0,0), (-1,-1), 8), ('RIGHTPADDING', (0,0), (-1,-1), 8), ('ROUNDEDCORNERS', [4, 4, 4, 4]), ])) return t # test doc = SimpleDocTemplate('/tmp/test_box.pdf', pagesize=A4, leftMargin=20*mm, rightMargin=20*mm, topMargin=18*mm, bottomMargin=18*mm) cw = PAGE_W - 40*mm story = [ colored_box('TEST CHAPTER TITLE', cw, 14, NAVY, WHITE, 18, True), Spacer(1, 5*mm), colored_box('Section Header', cw, 8, STEEL, WHITE, 12, True), ] doc.build(story) print('Success') " 2>&1
Where is PDF?
ls /home/daytona/workspace/ortho-implants-pdf/ 2>&1
~/ortho-implants-pdf/create_pdf.py
#!/usr/bin/env python3
"""
Orthopaedic Implants & Fracture Fixation - Comprehensive Illustrated PDF
Sources: Campbell's Operative Orthopaedics 15th Ed 2026
Rockwood and Green's Fractures in Adults 10th Ed 2025
Anan J. Thakur - Locking Plates and Fracture Fixation
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import mm
from reportlab.lib import colors
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak, KeepTogether
)
from reportlab.platypus.flowables import Flowable
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.graphics.shapes import (
Drawing, Rect, Circle, Line, Polygon, String, Ellipse, Path
)
import math
# ── Palette ────────────────────────────────────────────────────────────────────
NAVY = colors.HexColor('#1A2B4A')
STEEL = colors.HexColor('#2E5FA3')
TEAL = colors.HexColor('#0C7B93')
SILVER = colors.HexColor('#E8EDF4')
GOLD = colors.HexColor('#C8A951')
BONE = colors.HexColor('#F5F0E8')
RED = colors.HexColor('#C0392B')
GREEN = colors.HexColor('#27AE60')
LGRAY = colors.HexColor('#D5DCE8')
DGRAY = colors.HexColor('#4A4A4A')
WHITE = colors.white
BLACK = colors.black
METAL = colors.HexColor('#8C9BAB')
ORANGE = colors.HexColor('#E67E22')
PURPLE = colors.HexColor('#6C5CE7')
YELLOW = colors.HexColor('#FFF3CD')
YTEXT = colors.HexColor('#7B4C00')
LBLUE = colors.HexColor('#E8F4FD')
LBTEXT = colors.HexColor('#1A527A')
PAGE_W, PAGE_H = A4
CW = PAGE_W - 40*mm # content width
# ── Style helpers ───────────────────────────────────────────────────────────────
SS = getSampleStyleSheet()
def PS(name, **kw):
return ParagraphStyle(name, **kw)
body_s = PS('body', fontSize=10, textColor=DGRAY, alignment=TA_JUSTIFY, leading=15, fontName='Helvetica', spaceBefore=3, spaceAfter=3)
bul_s = PS('bul', fontSize=10, textColor=DGRAY, alignment=TA_LEFT, leading=15, fontName='Helvetica', leftIndent=16, spaceBefore=2)
sub_s = PS('sub', fontSize=12, textColor=NAVY, alignment=TA_LEFT, leading=18, fontName='Helvetica-Bold', spaceBefore=6, spaceAfter=2)
cap_s = PS('cap', fontSize=8, textColor=STEEL, alignment=TA_CENTER, leading=11, fontName='Helvetica-Oblique')
src_s = PS('src', fontSize=8, textColor=STEEL, alignment=TA_LEFT, leading=11, fontName='Helvetica-Oblique')
th_s = PS('th', fontSize=9, textColor=WHITE, alignment=TA_CENTER, leading=13, fontName='Helvetica-Bold')
tc_s = PS('tc', fontSize=8, textColor=DGRAY, alignment=TA_LEFT, leading=12, fontName='Helvetica')
note_s = PS('note', fontSize=9, textColor=YTEXT, alignment=TA_LEFT, leading=13, fontName='Helvetica')
info_s = PS('info', fontSize=9, textColor=LBTEXT,alignment=TA_LEFT, leading=13, fontName='Helvetica')
def p(text, style=body_s): return Paragraph(text, style)
def b(text): return Paragraph(f'• {text}', bul_s)
def h2(text): return Paragraph(text, sub_s)
def cap(text): return Paragraph(text, cap_s)
def src(text): return Paragraph(f'<i>Source: {text}</i>', src_s)
def sp(h=4): return Spacer(1, h*mm)
def hr(): return HRFlowable(width='100%', thickness=0.5, color=LGRAY, spaceAfter=2*mm, spaceBefore=2*mm)
def banner(text, bg=NAVY, text_color=WHITE, fsize=16, pad_v=7):
s = PS('bn', fontSize=fsize, textColor=text_color, fontName='Helvetica-Bold', alignment=TA_CENTER, leading=fsize+5)
t = Table([[p(text, s)]], colWidths=[CW])
t.setStyle(TableStyle([
('BACKGROUND', (0,0),(-1,-1), bg),
('TOPPADDING', (0,0),(-1,-1), pad_v),
('BOTTOMPADDING', (0,0),(-1,-1), pad_v),
('LEFTPADDING', (0,0),(-1,-1), 8),
('RIGHTPADDING', (0,0),(-1,-1), 8),
]))
return t
def sec_banner(text, bg=STEEL):
s = PS('sb', fontSize=11, textColor=WHITE, fontName='Helvetica-Bold', alignment=TA_LEFT, leading=15)
t = Table([[p(text, s)]], colWidths=[CW])
t.setStyle(TableStyle([
('BACKGROUND', (0,0),(-1,-1), bg),
('TOPPADDING', (0,0),(-1,-1), 5),
('BOTTOMPADDING', (0,0),(-1,-1), 5),
('LEFTPADDING', (0,0),(-1,-1), 10),
('RIGHTPADDING', (0,0),(-1,-1), 8),
]))
return t
def info_box(text, bg=YELLOW, ts=note_s):
t = Table([[p(text, ts)]], colWidths=[CW])
t.setStyle(TableStyle([
('BACKGROUND', (0,0),(-1,-1), bg),
('TOPPADDING', (0,0),(-1,-1), 6),
('BOTTOMPADDING', (0,0),(-1,-1), 6),
('LEFTPADDING', (0,0),(-1,-1), 10),
('RIGHTPADDING', (0,0),(-1,-1), 8),
('BOX', (0,0),(-1,-1), 0.5, STEEL),
]))
return t
def two_col(left_items, right_items):
rows = []
for i in range(max(len(left_items), len(right_items))):
lc = left_items[i] if i < len(left_items) else Spacer(1,1)
rc = right_items[i] if i < len(right_items) else Spacer(1,1)
rows.append([lc, rc])
t = Table(rows, colWidths=[CW/2 - 2*mm, CW/2 - 2*mm], hAlign='LEFT')
t.setStyle(TableStyle([
('VALIGN', (0,0),(-1,-1), 'TOP'),
('TOPPADDING', (0,0),(-1,-1), 2),
('BOTTOMPADDING', (0,0),(-1,-1), 2),
('LEFTPADDING', (0,0),(-1,-1), 0),
('RIGHTPADDING', (0,0),(-1,-1), 4),
]))
return t
# ═══════════════════════════════════════════════════════════════════════════════
# DRAWINGS
# ═══════════════════════════════════════════════════════════════════════════════
def screw_diagram():
w, h = 500, 260
d = Drawing(w, h)
d.add(Rect(0, 0, w, h, fillColor=SILVER, strokeColor=None))
d.add(String(w/2, h-20, 'ANATOMY OF AN ORTHOPAEDIC BONE SCREW',
fontSize=11, fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
# --- Screw body ---
sx, sy = 40, 100
head_w, head_h = 48, 32
shank_len = 55
thread_len = 270
tip_len = 18
# Head
d.add(Rect(sx, sy, head_w, head_h, fillColor=METAL, strokeColor=NAVY, strokeWidth=1.5, rx=3))
for dx in [0.3, 0.5, 0.7]:
d.add(Line(sx+head_w*dx, sy+5, sx+head_w*dx, sy+head_h-5, strokeColor=DGRAY, strokeWidth=1))
# Shank
shank_top = sy + 8; shank_bot = sy + head_h - 8
d.add(Rect(sx+head_w, shank_top, shank_len, shank_bot-shank_top, fillColor=METAL, strokeColor=NAVY, strokeWidth=1))
# Threaded portion
tx = sx + head_w + shank_len
t_top = shank_top - 7; t_bot = shank_bot + 7
pitch = 11
n = int(thread_len / pitch)
for i in range(n):
x0 = tx + i*pitch
d.add(Polygon([x0, shank_top, x0+pitch/2, t_top, x0+pitch, shank_top],
fillColor=METAL, strokeColor=NAVY, strokeWidth=0.6))
d.add(Polygon([x0, shank_bot, x0+pitch/2, t_bot, x0+pitch, shank_bot],
fillColor=METAL, strokeColor=NAVY, strokeWidth=0.6))
d.add(Rect(tx, shank_top, thread_len, shank_bot-shank_top, fillColor=METAL, strokeColor=None))
# Tip
tip_x = tx + thread_len
shaft_mid = (shank_top + shank_bot)/2
d.add(Polygon([tip_x, shank_top, tip_x+tip_len, shaft_mid, tip_x, shank_bot],
fillColor=METAL, strokeColor=NAVY, strokeWidth=1))
# --- Top annotations ---
ann_y = sy - 18; lbl_y = ann_y - 14
def ann(lx, rx, lbl, col=NAVY):
mid = (lx+rx)/2
d.add(Line(lx, sy+head_h+2, lx, ann_y+6, strokeColor=col, strokeWidth=0.8))
d.add(Line(rx, sy+head_h+2, rx, ann_y+6, strokeColor=col, strokeWidth=0.8))
d.add(Line(lx, ann_y, rx, ann_y, strokeColor=col, strokeWidth=1))
d.add(String(mid, lbl_y, lbl, fontSize=8, fillColor=col, textAnchor='middle', fontName='Helvetica-Bold'))
ann(sx, sx+head_w, 'HEAD', NAVY)
ann(sx+head_w, sx+head_w+shank_len, 'SHANK', STEEL)
ann(tx, tx+thread_len, 'THREADED PORTION', TEAL)
ann(tip_x, tip_x+tip_len, 'TIP', RED)
# --- Bottom annotations ---
p1 = tx + 2*pitch; p2 = tx + 3*pitch
d.add(Line(p1, t_bot+4, p2, t_bot+4, strokeColor=GREEN, strokeWidth=1.5))
d.add(Line(p1, t_bot+2, p1, t_bot+9, strokeColor=GREEN, strokeWidth=1))
d.add(Line(p2, t_bot+2, p2, t_bot+9, strokeColor=GREEN, strokeWidth=1))
d.add(String((p1+p2)/2, t_bot+14, 'Pitch', fontSize=8, fillColor=GREEN, textAnchor='middle', fontName='Helvetica-Bold'))
td_x = tx + 8*pitch
d.add(Line(td_x, t_top-2, td_x, t_bot+2, strokeColor=ORANGE, strokeWidth=1.5))
d.add(String(td_x+8, t_bot+14, 'Thread Diam.', fontSize=8, fillColor=ORANGE, textAnchor='start', fontName='Helvetica-Bold'))
rd_x = td_x + 4*pitch
d.add(Line(rd_x, shank_top, rd_x, shank_bot, strokeColor=RED, strokeWidth=1.5))
d.add(String(rd_x+8, shank_top-12, 'Root Diam.', fontSize=8, fillColor=RED, textAnchor='start', fontName='Helvetica-Bold'))
return d
def screw_types_diagram():
w, h = 510, 230
d = Drawing(w, h)
d.add(Rect(0, 0, w, h, fillColor=SILVER, strokeColor=None))
d.add(String(w/2, h-20, 'TYPES OF ORTHOPAEDIC SCREWS',
fontSize=11, fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
types = [
('CORTICAL', STEEL, 'Fine thread\nFull length\nSmall pitch'),
('CANCELLOUS', TEAL, 'Coarse thread\nPartial/full\nLarge pitch'),
('LOCKING', RED, 'Threaded head\nLocks in plate\nFixed-angle'),
('CANNULATED', ORANGE,'Hollow shaft\nOver guidewire\nPerc. technique'),
('SELF-TAPPING', GREEN,'Fluted/trocar tip\nNo pre-tapping\nExt. fixation pins'),
]
step = 96; start_x = 50
for i, (name, col, desc) in enumerate(types):
x = start_x + i*step
sw, sh = 22, 80; sy_base = 110
# Screw head
d.add(Rect(x-sw/2, sy_base+sh+2, sw, 20, fillColor=col, strokeColor=NAVY, strokeWidth=1, rx=2))
# Shaft core
d.add(Rect(x-sw/4, sy_base+18, sw/2, sh-16, fillColor=col, strokeColor=None))
# Thread marks
pitch = 6 if name=='CORTICAL' else 10
for ty in range(int(sy_base+20), int(sy_base+sh), pitch):
d.add(Line(x-sw/2-4, ty, x+sw/2+4, ty, strokeColor=NAVY, strokeWidth=0.7))
# Cannulated hollow
if name=='CANNULATED':
d.add(Rect(x-sw/8, sy_base+18, sw/4, sh-16, fillColor=WHITE, strokeColor=None))
# Tip
if name=='SELF-TAPPING':
d.add(Polygon([x-sw/4, sy_base+20, x, sy_base+5, x+sw/4, sy_base+20], fillColor=col, strokeColor=NAVY, strokeWidth=0.8))
else:
d.add(Polygon([x-sw/4, sy_base+22, x, sy_base+10, x+sw/4, sy_base+22], fillColor=col, strokeColor=NAVY, strokeWidth=0.8))
# Locking head threads
if name=='LOCKING':
for lx in range(int(x-sw/2+2), int(x+sw/2), 4):
d.add(Line(lx, sy_base+sh+4, lx, sy_base+sh+20, strokeColor=NAVY, strokeWidth=0.5))
# Name
d.add(String(x, sy_base+sh+30, name, fontSize=7.5, fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
for j, line in enumerate(desc.split('\n')):
d.add(String(x, sy_base+sh+42+j*10, line, fontSize=6.5, fillColor=DGRAY, textAnchor='middle', fontName='Helvetica'))
return d
def plate_diagram():
w, h = 510, 310
d = Drawing(w, h)
d.add(Rect(0, 0, w, h, fillColor=SILVER, strokeColor=None))
d.add(String(w/2, h-20, 'TYPES OF FRACTURE FIXATION PLATES',
fontSize=11, fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
items = [
('NEUTRALIZATION', STEEL, 50, 'Neutralizes\ntorsion/bending'),
('COMPRESSION\n(DCP)', TEAL, 140, 'Axial compression\nvia oval holes'),
('BUTTRESS', NAVY, 230, 'Prevents axial\ndeformation'),
('BRIDGE', PURPLE, 320, 'Spans comminuted\nfragments'),
('LOCKING', RED, 410, 'Fixed-angle\nconstruct'),
]
for label, col, x, desc in items:
pw, ph = 55, 90; py = 95
d.add(Rect(x-pw/2, py, pw, ph, fillColor=col, strokeColor=NAVY, strokeWidth=1.2, rx=5))
# Screw holes
for hy in [py+12, py+28, py+ph//2, py+ph-28, py+ph-12]:
d.add(Circle(x, hy, 5, fillColor=WHITE, strokeColor=DGRAY, strokeWidth=1))
if col==RED: # locking - threaded indicator
d.add(Circle(x, hy, 3, fillColor=LGRAY, strokeColor=NAVY, strokeWidth=0.8))
# Label
for k, ln in enumerate(label.split('\n')):
d.add(String(x, py-22-k*12, ln, fontSize=8, fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
for k, ln in enumerate(desc.split('\n')):
d.add(String(x, py+ph+16+k*11, ln, fontSize=7, fillColor=DGRAY, textAnchor='middle', fontName='Helvetica'))
return d
def tension_band_diagram():
w, h = 510, 240
d = Drawing(w, h)
d.add(Rect(0, 0, w, h, fillColor=SILVER, strokeColor=None))
d.add(String(w/2, h-20, 'TENSION BAND PRINCIPLE (PAUWELS)',
fontSize=11, fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
for label, x0, has_plate in [('WITHOUT PLATE\n(gap on tension side)', 90, False),
('WITH PLATE ON\nTENSION SIDE', 340, True)]:
bx, by, bw, bh = x0, 40, 28, 160
d.add(Rect(bx, by, bw, bh, fillColor=BONE, strokeColor=DGRAY, strokeWidth=2, rx=6))
# Fracture
d.add(Line(bx-3, by+bh//2, bx+bw+3, by+bh//2+2, strokeColor=RED, strokeWidth=2))
# Load arrow
d.add(Line(bx+bw/2, by-18, bx+bw/2, by, strokeColor=NAVY, strokeWidth=2))
d.add(Polygon([bx+bw/2-5, by, bx+bw/2, by-14, bx+bw/2+5, by], fillColor=NAVY, strokeColor=None))
d.add(String(bx+bw/2, by-24, 'Load', fontSize=8, fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
if has_plate:
d.add(Rect(bx+bw+3, by+18, 8, bh-36, fillColor=STEEL, strokeColor=NAVY, strokeWidth=1, rx=2))
for sy in [by+28, by+46, by+bh-46, by+bh-28]:
d.add(Line(bx-4, sy, bx+bw+12, sy, strokeColor=METAL, strokeWidth=3))
d.add(String(bx+bw+18, by+bh/2, 'Compression', fontSize=7.5, fillColor=GREEN, textAnchor='start', fontName='Helvetica-Bold'))
else:
d.add(Line(bx+bw+2, by+bh//2-14, bx+bw+22, by+bh//2-20, strokeColor=RED, strokeWidth=1.5))
d.add(String(bx+bw+24, by+bh//2-10, 'Gap (tension)', fontSize=7, fillColor=RED, textAnchor='start', fontName='Helvetica-Bold'))
for k, ln in enumerate(label.split('\n')):
d.add(String(bx+bw/2, by+bh+18+k*12, ln, fontSize=8, fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
return d
def nail_diagram():
w, h = 510, 280
d = Drawing(w, h)
d.add(Rect(0, 0, w, h, fillColor=SILVER, strokeColor=None))
d.add(String(w/2, h-20, 'INTRAMEDULLARY NAIL - STATIC vs DYNAMIC LOCKING',
fontSize=11, fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
for label, x0, is_static in [('STATIC LOCKING\n(both proximal & distal screws fixed)', 80, True),
('DYNAMIC LOCKING\n(proximal in oval slot - allows micromotion)', 300, False)]:
fx, fy, fw, fh = x0+55, 48, 46, 190
# Femur
d.add(Rect(fx-fw/2, fy, fw, fh, fillColor=BONE, strokeColor=DGRAY, strokeWidth=2, rx=14))
# Canal
d.add(Rect(fx-10, fy+14, 20, fh-28, fillColor=WHITE, strokeColor=LGRAY, strokeWidth=0.5))
# Nail
d.add(Rect(fx-6, fy+8, 12, fh-16, fillColor=METAL, strokeColor=NAVY, strokeWidth=1, rx=3))
# Proximal screw
sy_p = fy+32
if is_static:
d.add(Line(fx-fw/2-14, sy_p, fx+fw/2+14, sy_p, strokeColor=STEEL, strokeWidth=4))
d.add(String(fx+fw/2+18, sy_p+3, 'Prox. screw\n(fixed)', fontSize=7, fillColor=STEEL, fontName='Helvetica'))
else:
d.add(Rect(fx-6, sy_p-6, 12, 13, fillColor=WHITE, strokeColor=NAVY, strokeWidth=1))
d.add(Line(fx-fw/2-14, sy_p, fx+fw/2+14, sy_p, strokeColor=ORANGE, strokeWidth=4))
d.add(String(fx+fw/2+18, sy_p+3, 'Slot\n(dynamic)', fontSize=7, fillColor=ORANGE, fontName='Helvetica-Bold'))
# Distal screw
sy_d = fy+fh-42
d.add(Line(fx-fw/2-14, sy_d, fx+fw/2+14, sy_d, strokeColor=STEEL, strokeWidth=4))
d.add(String(fx+fw/2+18, sy_d+3, 'Dist. screw\n(fixed)', fontSize=7, fillColor=STEEL, fontName='Helvetica'))
# Label
for k, ln in enumerate(label.split('\n')):
d.add(String(fx, fy+fh+18+k*12, ln, fontSize=8, fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
return d
def ext_fixator_diagram():
w, h = 510, 260
d = Drawing(w, h)
d.add(Rect(0, 0, w, h, fillColor=SILVER, strokeColor=None))
d.add(String(w/2, h-20, 'EXTERNAL FIXATION - TYPES & COMPONENTS',
fontSize=11, fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
# Monolateral
bx, by, bw, bh = 85, 55, 22, 145
d.add(Rect(bx, by, bw, bh, fillColor=BONE, strokeColor=DGRAY, strokeWidth=2, rx=5))
d.add(Line(bx-3, by+65, bx+bw+3, by+68, strokeColor=RED, strokeWidth=2))
for py in [by+20, by+40, by+85, by+105]:
d.add(Line(bx-52, py, bx+bw+50, py, strokeColor=STEEL, strokeWidth=3))
d.add(Rect(bx-58, by+12, 10, 105, fillColor=METAL, strokeColor=NAVY, strokeWidth=1, rx=3))
d.add(String(bx+bw/2, by+bh+20, 'Monolateral\nExternal Fixator', fontSize=8,
fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
d.add(String(bx-55, by+22, 'Schanz pin', fontSize=7, fillColor=STEEL, textAnchor='middle', fontName='Helvetica'))
d.add(String(bx-55, by+60, 'Connecting\nbar', fontSize=7, fillColor=METAL, textAnchor='middle', fontName='Helvetica'))
d.add(String(bx+bw+32, by+66, 'Fracture\nsite', fontSize=7, fillColor=RED, textAnchor='middle', fontName='Helvetica-Bold'))
# Ilizarov ring
cx, cy, cr = 370, 128, 58
for ring_y in [cy-50, cy+50]:
d.add(Circle(cx, ring_y, cr, fillColor=None, strokeColor=METAL, strokeWidth=6))
for ang in [45, 135, 225, 315]:
rad = math.radians(ang)
ex = cx + math.cos(rad)*cr
d.add(Line(ex, cy-50, ex, cy+50, strokeColor=STEEL, strokeWidth=3))
d.add(Rect(cx-8, cy-82, 16, 164, fillColor=BONE, strokeColor=DGRAY, strokeWidth=2, rx=5))
for wy in [cy-50, cy+50]:
d.add(Line(cx-cr+6, wy, cx+cr-6, wy, strokeColor=ORANGE, strokeWidth=1.5))
d.add(String(cx, cy+120, 'Circular (Ilizarov)\nFrame', fontSize=8,
fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
d.add(String(cx+cr+8, cy-50, 'Ring', fontSize=7, fillColor=METAL, fontName='Helvetica'))
d.add(String(cx+cr+8, cy+50, 'Tensioned\nwire', fontSize=7, fillColor=ORANGE, fontName='Helvetica'))
return d
def locking_plate_diagram():
w, h = 510, 270
d = Drawing(w, h)
d.add(Rect(0, 0, w, h, fillColor=SILVER, strokeColor=None))
d.add(String(w/2, h-20, 'CONVENTIONAL PLATE vs LOCKING PLATE CONSTRUCT',
fontSize=11, fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
for label, x0, col, is_locking in [
('CONVENTIONAL PLATE\n(friction-based, plate contacts bone)', 50, STEEL, False),
('LOCKING PLATE\n(fixed-angle, no plate-bone contact needed)', 285, TEAL, True)
]:
bx, by, bw, bh = x0, 55, 20, 160
d.add(Rect(bx, by, bw, bh, fillColor=BONE, strokeColor=DGRAY, strokeWidth=2, rx=5))
d.add(Line(bx-2, by+78, bx+bw+2, by+80, strokeColor=RED, strokeWidth=2))
# Plate
px, pw, ph = bx+bw+4, 75, bh-30
d.add(Rect(px, by+15, pw, ph, fillColor=col, strokeColor=NAVY, strokeWidth=1.2, rx=3))
for sy in [by+28, by+46, by+80, by+100, by+118]:
if is_locking:
d.add(Circle(px, sy, 5, fillColor=LGRAY, strokeColor=NAVY, strokeWidth=1.2))
for lx2 in range(int(px-4), int(px+5), 2):
d.add(Line(lx2, sy-5, lx2, sy+5, strokeColor=NAVY, strokeWidth=0.4))
d.add(Line(bx-5, sy, px, sy, strokeColor=METAL, strokeWidth=4))
else:
d.add(Circle(px, sy, 5, fillColor=WHITE, strokeColor=DGRAY, strokeWidth=1))
d.add(Line(bx-5, sy, px+8, sy, strokeColor=METAL, strokeWidth=4))
for k, ln in enumerate(label.split('\n')):
d.add(String(bx+bw/2+pw/2+8, by+bh+18+k*11, ln, fontSize=7.5, fillColor=NAVY,
textAnchor='middle', fontName='Helvetica-Bold' if k==0 else 'Helvetica'))
return d
def kw_diagram():
w, h = 510, 230
d = Drawing(w, h)
d.add(Rect(0, 0, w, h, fillColor=SILVER, strokeColor=None))
d.add(String(w/2, h-20, 'K-WIRES & TENSION BAND WIRING (PATELLA EXAMPLE)',
fontSize=11, fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
# Patella
px, py, pr = 140, 70, 55
d.add(Ellipse(px, py+pr, pr*1.1, pr, fillColor=BONE, strokeColor=DGRAY, strokeWidth=2))
d.add(Line(px-pr, py+pr, px+pr, py+pr, strokeColor=RED, strokeWidth=2))
# K-wires
for kx in [px-20, px+20]:
d.add(Line(kx, py+8, kx, py+2*pr+12, strokeColor=STEEL, strokeWidth=3))
d.add(Polygon([kx-3, py+8, kx, py-6, kx+3, py+8], fillColor=STEEL, strokeColor=None))
# Figure-of-8 wire
d.add(Line(px-20, py+2*pr+12, px+20, py+2*pr+12, strokeColor=ORANGE, strokeWidth=2))
d.add(Line(px-20, py+2*pr+12, px+20, py+12, strokeColor=ORANGE, strokeWidth=2))
d.add(Line(px+20, py+2*pr+12, px-20, py+12, strokeColor=ORANGE, strokeWidth=2))
d.add(String(px, py+2*pr+32, 'K-wires (blue)', fontSize=7.5, fillColor=STEEL, textAnchor='middle', fontName='Helvetica-Bold'))
d.add(String(px, py+2*pr+44, 'Figure-of-8 wire (orange)', fontSize=7.5, fillColor=ORANGE, textAnchor='middle', fontName='Helvetica-Bold'))
d.add(String(px, py+2*pr+58, 'Patella Tension Band Wiring', fontSize=8, fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
# K-wire types
kx2 = 390
d.add(String(kx2, h-44, 'K-WIRE TIP TYPES', fontSize=9, fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
for i, (tip_name, tip_col) in enumerate([('Trocar tip', STEEL), ('Bayonet tip', TEAL)]):
tx = kx2 - 35 + i*72; ty = 70
d.add(Rect(tx-4, ty, 8, 90, fillColor=tip_col, strokeColor=NAVY, strokeWidth=1))
if i==0:
d.add(Polygon([tx-4, ty, tx, ty-14, tx+4, ty], fillColor=tip_col, strokeColor=NAVY, strokeWidth=1))
else:
d.add(Polygon([tx-4, ty, tx+4, ty-12, tx+4, ty], fillColor=tip_col, strokeColor=NAVY, strokeWidth=1))
d.add(String(tx, ty+100, tip_name, fontSize=7.5, fillColor=NAVY, textAnchor='middle', fontName='Helvetica'))
return d
def dhs_diagram():
w, h = 510, 240
d = Drawing(w, h)
d.add(Rect(0, 0, w, h, fillColor=SILVER, strokeColor=None))
d.add(String(w/2, h-20, 'DYNAMIC HIP SCREW (DHS) - SLIDING PRINCIPLE',
fontSize=11, fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
# Femur outline
fx, fy, fw, fh = 130, 38, 50, 180
d.add(Rect(fx, fy, fw, fh, fillColor=BONE, strokeColor=DGRAY, strokeWidth=2, rx=8))
# Femoral head (circle)
d.add(Circle(fx-38, fy+20, 30, fillColor=BONE, strokeColor=DGRAY, strokeWidth=2))
# Neck
d.add(Polygon([fx, fy+18, fx-10, fy+30, fx-20, fy+36, fx, fy+50],
fillColor=BONE, strokeColor=DGRAY, strokeWidth=2))
# Side plate
d.add(Rect(fx+fw, fy+60, 12, fh-70, fillColor=STEEL, strokeColor=NAVY, strokeWidth=1.2, rx=2))
# Barrel on side plate
d.add(Rect(fx+fw, fy+62, 36, 14, fillColor=METAL, strokeColor=NAVY, strokeWidth=1, rx=3))
# Lag screw through barrel into head
d.add(Line(fx+fw+36, fy+69, fx-35, fy+20, strokeColor=STEEL, strokeWidth=6))
d.add(String(fx-40, fy+10, 'Lag\nscrew', fontSize=7.5, fillColor=STEEL, textAnchor='middle', fontName='Helvetica-Bold'))
d.add(String(fx+fw+8, fy+84, 'Barrel\n(allows sliding)', fontSize=7, fillColor=METAL, textAnchor='middle', fontName='Helvetica'))
d.add(String(fx+fw+8, fy+fh-4, 'Side plate', fontSize=7.5, fillColor=NAVY, textAnchor='middle', fontName='Helvetica-Bold'))
# Load arrow
d.add(Line(fx+fw/2, fy-18, fx+fw/2, fy, strokeColor=RED, strokeWidth=2))
d.add(Polygon([fx+fw/2-5, fy, fx+fw/2, fy-14, fx+fw/2+5, fy], fillColor=RED, strokeColor=None))
d.add(String(fx+fw/2, fy-24, 'Load', fontSize=8, fillColor=RED, textAnchor='middle', fontName='Helvetica-Bold'))
# Sliding arrow on screw
d.add(String(fx+fw+50, fy+95, 'Sliding\n(controlled collapse)', fontSize=8, fillColor=GREEN,
textAnchor='start', fontName='Helvetica-Bold'))
# Screw plate screws
for sy2 in [fy+75, fy+95, fy+115, fy+135]:
d.add(Line(fx+fw-5, sy2, fx+fw+12, sy2, strokeColor=METAL, strokeWidth=2))
return d
# ═══════════════════════════════════════════════════════════════════════════════
# BUILD PDF
# ═══════════════════════════════════════════════════════════════════════════════
def build():
out = '/home/daytona/workspace/ortho-implants-pdf/Orthopaedic_Implants_Fracture_Fixation.pdf'
doc = SimpleDocTemplate(
out, pagesize=A4,
leftMargin=20*mm, rightMargin=20*mm,
topMargin=18*mm, bottomMargin=18*mm,
title='Orthopaedic Implants & Fracture Fixation',
author='Campbell / Rockwood & Green / Thakur'
)
S = [] # story
# ─────────────────────────────────────────────────────────────────────────
# COVER
# ─────────────────────────────────────────────────────────────────────────
S.append(sp(6))
S.append(banner('ORTHOPAEDIC IMPLANTS\nAND FRACTURE FIXATION', NAVY, WHITE, 26, 14))
S.append(sp(3))
S.append(banner('Principles • Types • Techniques • Biomechanics', STEEL, WHITE, 13, 6))
S.append(sp(3))
S.append(banner(
'Sources: Campbell\'s Operative Orthopaedics 15th Ed 2026 | '
'Rockwood & Green\'s Fractures in Adults 10th Ed 2025\n'
'Anan J. Thakur – Locking Plates and Fracture Fixation',
TEAL, WHITE, 10, 7
))
S.append(sp(5))
toc_hdr = PS('toch', fontSize=11, textColor=WHITE, fontName='Helvetica-Bold', alignment=TA_CENTER, leading=14)
toc_cel = PS('tocc', fontSize=10, textColor=DGRAY, fontName='Helvetica', alignment=TA_LEFT, leading=14)
toc_num = PS('tocn', fontSize=10, textColor=NAVY, fontName='Helvetica-Bold', alignment=TA_CENTER, leading=14)
toc_rows = [
[p('CH', toc_hdr), p('CHAPTER TITLE', toc_hdr), p('KEY TOPICS', toc_hdr)],
[p('1', toc_num), p('SCREWS IN ORTHOPAEDICS', toc_cel), p('Parts, types, principles, insertion techniques', toc_cel)],
[p('2', toc_num), p('PLATES & PLATING', toc_cel), p('Types, principles, applications, DCP, buttress', toc_cel)],
[p('3', toc_num), p('INTRAMEDULLARY NAILS', toc_cel), p('Design, biomechanics, reaming, interlocking', toc_cel)],
[p('4', toc_num), p('EXTERNAL FIXATION', toc_cel), p('Monolateral, circular (Ilizarov), TSF', toc_cel)],
[p('5', toc_num), p('LOCKING PLATES', toc_cel), p('Principle, fixed-angle, MIPO, Thakur', toc_cel)],
[p('6', toc_num), p('K-WIRES & TENSION BAND', toc_cel), p('Pauwels principle, K-wires, cerclage', toc_cel)],
[p('7', toc_num), p('OTHER IMPLANTS (DHS, PFN)', toc_cel), p('Dynamic hip screw, gamma nail, anchors', toc_cel)],
[p('8', toc_num), p('IMPLANT MATERIALS & BIOMECHANICS', toc_cel), p('Steel, titanium, Co-Cr, stress shielding', toc_cel)],
[p('9', toc_num), p('METAL REMOVAL TIMING', toc_cel), p('ASIF guidelines by bone/fracture type', toc_cel)],
]
toc_t = Table(toc_rows, colWidths=[12*mm, 78*mm, 80*mm])
toc_t.setStyle(TableStyle([
('BACKGROUND', (0,0),(-1,0), NAVY),
('ROWBACKGROUNDS', (0,1),(-1,-1), [BONE, WHITE]),
('GRID', (0,0),(-1,-1), 0.5, LGRAY),
('VALIGN', (0,0),(-1,-1), 'MIDDLE'),
('TOPPADDING', (0,0),(-1,-1), 5), ('BOTTOMPADDING', (0,0),(-1,-1), 5),
('LEFTPADDING', (0,0),(-1,-1), 6),
]))
S.append(toc_t)
S.append(PageBreak())
# ─────────────────────────────────────────────────────────────────────────
# CH 1 - SCREWS
# ─────────────────────────────────────────────────────────────────────────
S.append(banner('CHAPTER 1: SCREWS IN ORTHOPAEDIC SURGERY', NAVY, WHITE, 16, 8))
S.append(sp(3))
S.append(sec_banner('1.1 PARTS OF A BONE SCREW'))
S.append(sp(2))
S.append(p('Screws are complex tools with a <b>four-part construction</b>: <b>Head, Shaft (Shank), Thread,</b> and <b>Tip.</b> Each part serves a distinct biomechanical role in achieving purchase in bone and generating compression.'))
S.append(src('Campbell\'s Operative Orthopaedics 15th Ed 2026, Chapter 58'))
S.append(sp(2))
S.append(screw_diagram())
S.append(cap('Figure 1.1 — Anatomy of an orthopaedic bone screw with all design parameters labelled'))
S.append(sp(2))
parts_data = [
[p('PART', th_s), p('DESCRIPTION & BIOMECHANICAL FUNCTION', th_s)],
[p('<b>HEAD</b>', tc_s),
p('Attachment point for screwdriver (hex, cruciate, Phillips, slotted, torx). Acts as the counterforce against which compression generated by the screw acts on the bone. Countersinking prevents prominence.', tc_s)],
[p('<b>SHAFT / SHANK</b>', tc_s),
p('Smooth portion between head and threaded region. Width (root diameter) determines fatigue resistance. Shank length affects where threads purchase in bone.', tc_s)],
[p('<b>THREAD</b>', tc_s),
p('<b>Root (core) diameter</b> — resistance to pull-out & fatigue; <b>Thread (outside) diameter</b> — pull-out strength in cancellous bone; <b>Pitch</b> — distance between adjacent threads; <b>Lead</b> — advance per full revolution; <b>Thread design</b> — Buttress (ASIF) or V-thread (machine screws).', tc_s)],
[p('<b>TIP</b>', tc_s),
p('<b>Round tip</b> — requires pre-tapping before insertion. <b>Self-tapping (fluted/trocar)</b> — cuts its own thread. Self-tapping is convenient but provides slightly less pull-out strength.', tc_s)],
]
pt = Table(parts_data, colWidths=[28*mm, 142*mm])
pt.setStyle(TableStyle([
('BACKGROUND', (0,0),(-1,0), NAVY),
('ROWBACKGROUNDS', (0,1),(-1,-1), [BONE, WHITE]),
('GRID', (0,0),(-1,-1), 0.5, LGRAY),
('VALIGN', (0,0),(-1,-1), 'TOP'),
('TOPPADDING', (0,0),(-1,-1), 5), ('BOTTOMPADDING', (0,0),(-1,-1), 5),
('LEFTPADDING', (0,0),(-1,-1), 6),
]))
S.append(pt)
S.append(sp(3))
S.append(info_box('<b>CLINICAL PEARL:</b> In soft (osteoporotic) bone, a larger <i>thread diameter</i> improves pull-out resistance. In dense bone where fatigue is the concern, a wider <i>root diameter</i> resists fatigue failure.'))
S.append(sp(3))
S.append(sec_banner('1.2 TYPES OF ORTHOPAEDIC SCREWS'))
S.append(sp(2))
S.append(screw_types_diagram())
S.append(cap('Figure 1.2 — Five major types of orthopaedic screws: Cortical, Cancellous, Locking, Cannulated, Self-tapping'))
S.append(sp(2))
screw_rows = [
[p('TYPE', th_s), p('DESIGN FEATURES', th_s), p('INDICATION & USE', th_s)],
[p('Machine Screws', tc_s),
p('Threaded full length; self-tapping cutting flute; drill hole size critical', tc_s),
p('General cortical bone; external fixation; correct drill sizing mandatory', tc_s)],
[p('Cortical Screws\n(ASIF)', tc_s),
p('Full-length thread; horizontal profile; hexagonal or torx recess; self-tapping versions available', tc_s),
p('Diaphyseal fractures; positional or lag function (over-drill near cortex for lag)', tc_s)],
[p('Cancellous Screws', tc_s),
p('Coarse, larger threads; partially or fully threaded; malleolar screw has trephine tip', tc_s),
p('Metaphyseal/epiphyseal zones; osteoporotic bone; use washers to prevent head pull-through', tc_s)],
[p('Self-tapping /\nSelf-drilling', tc_s),
p('Fluted or trocar tip cuts its own threads; no pre-tapping; slightly lower pull-out strength', tc_s),
p('External fixation pins; Schanz screws; quick intra-operative insertion', tc_s)],
[p('Locking Screws', tc_s),
p('Threaded head locks into plate hole; precise predrilling; specialized screwdriver', tc_s),
p('Locking plate constructs; osteoporotic bone; periarticular fractures', tc_s)],
[p('Cannulated Screws', tc_s),
p('Hollow shaft accepts guidewire; multiple sizes available', tc_s),
p('Femoral neck; scaphoid; percutaneous/minimally invasive fixation', tc_s)],
[p('Miniscrews', tc_s),
p('Small sizes (1.5–2.7 mm); Phillips or mini-hex head', tc_s),
p('Small fragment fixation: phalanges, metacarpals, facial bones', tc_s)],
]
st = Table(screw_rows, colWidths=[32*mm, 70*mm, 68*mm])
st.setStyle(TableStyle([
('BACKGROUND', (0,0),(-1,0), NAVY),
('ROWBACKGROUNDS', (0,1),(-1,-1), [BONE, WHITE]),
('GRID', (0,0),(-1,-1), 0.5, LGRAY),
('VALIGN', (0,0),(-1,-1), 'TOP'),
('TOPPADDING', (0,0),(-1,-1), 5), ('BOTTOMPADDING', (0,0),(-1,-1), 5),
('LEFTPADDING', (0,0),(-1,-1), 6),
]))
S.append(st)
S.append(sp(3))
S.append(sec_banner('1.3 PRINCIPLES OF SCREW INSERTION'))
S.append(sp(2))
principles_screws = [
('<b>Lag Screw Principle:</b>', 'Converts torque to interfragmentary compression. Near cortex is <i>over-drilled</i> (gliding hole) — screw does not grip it; threads purchase only in the far fragment. Screw head tightening draws fragments together. Any screw crossing a fracture line should be inserted with interfragmentary technique.'),
('<b>Positional / Neutralization Screw:</b>', 'Threads purchase in both cortices; no compression is generated. Maintains reduction or attaches an implant to bone. Used in combination with lag screws to neutralize deforming forces.'),
('<b>Interfragmentary Compression Angle:</b>', 'Screw should bisect the angle between perpendicular to the fracture and perpendicular to the long axis of the bone — prevents sliding of fragments during compression.'),
('<b>Pull-out Strength:</b>', 'Determined by root area and bone density at the thread interface. Larger thread diameter in osteoporotic bone; washers increase load dispersion and prevent head penetration.'),
('<b>Overtorquing:</b>', 'Avoid excessive torque — strips threads and destroys purchase. All screws should be re-tightened before wound closure to compensate for stress relaxation.'),
('<b>Cortex purchase:</b>', 'Generally 6–8 cortices on each side of fracture required for stable fixation (plates). Bicortical purchase preferred; unicortical locking screws acceptable near joints.'),
]
for term, desc in principles_screws:
S.append(p(f'{term} {desc}'))
S.append(sp(2))
S.append(src('Campbell\'s Operative Orthopaedics 15th Ed 2026, Chapter 58'))
S.append(PageBreak())
# ─────────────────────────────────────────────────────────────────────────
# CH 2 - PLATES
# ─────────────────────────────────────────────────────────────────────────
S.append(banner('CHAPTER 2: PLATES & PLATING PRINCIPLES', NAVY, WHITE, 16, 8))
S.append(sp(3))
S.append(sec_banner('2.1 TENSION BAND PRINCIPLE (PAUWELS)'))
S.append(sp(2))
S.append(p('<b>Pauwels</b> first defined and applied the tension band principle. An eccentrically loaded bone has a <b>tension (convex) side</b> and a <b>compression (concave) side</b>. A plate placed on the <i>tension side</i> converts tensile forces into compressive forces across the fracture — the bone itself then bears the compressive load.'))
S.append(sp(2))
S.append(tension_band_diagram())
S.append(cap('Figure 2.1 — Pauwels tension band principle: plate on tension side converts tension to compression'))
S.append(sp(2))
S.append(info_box('<b>KEY:</b> If the plate is applied to the compression (concave) side, it is subject to bending, fatigue, and will fail. Always apply to the tension side.'))
S.append(sp(3))
S.append(sec_banner('2.2 CAMPBELL\'S CONCEPTS: PRINCIPLES OF PLATE FIXATION'))
S.append(sp(2))
plate_principles = [
'Plates <b>neutralize deforming forces</b> that cannot be counteracted by screws alone.',
'Plates may require <b>contouring</b> to maintain optimal stability of the fracture reduction.',
'Screw application sequence is critical — incorrect placement causes displacement, shear, and loss of reduction.',
'Usually <b>6–8 cortices</b> of purchase required on both sides of the fracture (except buttress plates).',
'Plates should be of <b>sufficient length</b> — the larger the bone and greater the stresses, the longer the plate needed.',
'Avoid <b>overtorquing</b> screws during insertion.',
'Before wound closure, <b>re-tighten all screws</b> to allow for stress relaxation of the screw-bone interface.',
'Plates are <b>load-bearing</b> devices — they must be protected until bone union occurs.',
]
for pp in plate_principles:
S.append(b(pp))
S.append(sp(2))
S.append(src('Campbell\'s Operative Orthopaedics 15th Ed 2026 — "Campbell\'s Concepts: Principles of Plate Fixation"'))
S.append(sp(3))
S.append(sec_banner('2.3 TYPES OF PLATES (Campbell\'s Table 58.11)'))
S.append(sp(2))
S.append(plate_diagram())
S.append(cap('Figure 2.2 — Five main categories of fixation plates'))
S.append(sp(2))
plate_rows = [
[p('PLATE TYPE', th_s), p('INDICATION / BIOMECHANICAL ACTION', th_s), p('TECHNIQUE NOTES', th_s)],
[p('Neutralization', tc_s),
p('Used with interfragmentary screw fixation. Neutralizes torsional, bending, and shear forces. Common in butterfly/wedge fragments of humerus, radius, fibula.', tc_s),
p('Technique same as compression plating but without applying compression through holes. Interfragmentary screw improves stability significantly.', tc_s)],
[p('Compression\n(DCP / LC-DCP)', tc_s),
p('Negates torsion, bending, shear. Creates compression via external tension device or self-compression oval holes. Oval holes exert compression as screw translates plate.', tc_s),
p('Used for type A shaft fractures (transverse, short oblique). AO/ASIF LC-DCP has narrow contact area allowing circumferential callus regeneration.', tc_s)],
[p('Buttress', tc_s),
p('Negates compression and shear in metaphyseal-epiphyseal fractures (tibial plateau, pilon). Anchored to main stable fragment.', tc_s),
p('Correct contouring mandatory. Screws inserted towards shoulder of hole closest to fracture to prevent axial deformation under load.', tc_s)],
[p('Bridge', tc_s),
p('Spans comminuted unstable fractures or bone defects where anatomic reduction cannot be restored. Provides relative stability for secondary bone healing.', tc_s),
p('Indirect reduction; preserves biology. Autogenous bone grafting frequently required. Does not contact fracture zone.', tc_s)],
[p('Locking', tc_s),
p('Fixed-angle "single-beam" construct. Screws lock into plate — no motion between them. Distributes load across all screw-bone interfaces.', tc_s),
p('No plate-bone contact required. Functions like internal external fixator. More expensive. Primarily for cases not amenable to conventional fixation.', tc_s)],
[p('Semitubular /\nOne-third tubular', tc_s),
p('Thin, lightweight plate used as compression or neutralization plate for smaller bones (fibula, forearm).', tc_s),
p('Not suitable for large bones — insufficient strength. Common for fibula in ankle fractures.', tc_s)],
]
plt = Table(plate_rows, colWidths=[28*mm, 80*mm, 62*mm])
plt.setStyle(TableStyle([
('BACKGROUND', (0,0),(-1,0), NAVY),
('ROWBACKGROUNDS', (0,1),(-1,-1), [BONE, WHITE]),
('GRID', (0,0),(-1,-1), 0.5, LGRAY),
('VALIGN', (0,0),(-1,-1), 'TOP'),
('TOPPADDING', (0,0),(-1,-1), 5), ('BOTTOMPADDING', (0,0),(-1,-1), 5),
('LEFTPADDING', (0,0),(-1,-1), 6),
]))
S.append(plt)
S.append(sp(2))
S.append(src('Campbell\'s Operative Orthopaedics 15th Ed 2026, Table 58.11'))
S.append(PageBreak())
# ─────────────────────────────────────────────────────────────────────────
# CH 3 - IM NAILS
# ─────────────────────────────────────────────────────────────────────────
S.append(banner('CHAPTER 3: INTRAMEDULLARY NAILS', NAVY, WHITE, 16, 8))
S.append(sp(3))
S.append(sec_banner('3.1 PRINCIPLES & DESIGN'))
S.append(sp(2))
S.append(p('Closed <b>interlocking intramedullary (IM) nail</b> fixation is the procedure of choice for many long-bone fractures, especially in the lower extremity. Nails inserted centromedullary contact bone at multiple points, relying on longitudinal bone-nail contact for axial and rotational stability.'))
S.append(sp(2))
S.append(nail_diagram())
S.append(cap('Figure 3.1 — Intramedullary nail: static vs dynamic locking modes'))
S.append(sp(2))
nail_pts = [
'IM nails act as <b>internal splints</b> and can be inserted with minimal soft tissue damage.',
'<b>Interlocking screws</b> placed near both ends resist axial and rotational deformation of the fracture.',
'<b>Static locking:</b> both proximal and distal screws fixed — controls length and rotation. Used for most acute fractures.',
'<b>Dynamic locking:</b> proximal screws in oval slots — allows controlled axial micromotion promoting callus. Used when conditions favour dynamization.',
'<b>Dynamization:</b> removing one set of interlocking screws later to convert static to dynamic, promoting union in delayed healing.',
'<b>Reaming:</b> increases canal diameter for larger nail; increases cortical contact area; stimulates periosteal blood supply via damage response. Ream to fit — "cortical chatter" indicates correct size.',
'Use a nail <b>1.0–1.5 mm smaller</b> than the largest reamer used. Never insert a nail larger than canal diameter.',
'Excessive reaming weakens bone and risks thermal necrosis. Reaming should not exceed half the original cortex size.',
'<b>Entry portal:</b> femur — piriformis fossa or medial greater trochanter. Tibia — anterior to articular surface, in line with medial slope of lateral tibial spine. Humerus — at rotator cuff insertion.',
]
for pt2 in nail_pts:
S.append(b(pt2))
S.append(sp(3))
S.append(sec_banner('3.2 ADVANTAGES OVER PLATING'))
S.append(sp(2))
adv_L = [
b('Earlier weight bearing'),
b('Less vulnerability to fatigue failure'),
b('Acts as <b>load-sharing</b> device'),
b('Avoids stress shielding'),
]
adv_R = [
b('Less soft tissue dissection'),
b('Lower infection risk (open fractures)'),
b('Biomechanically central (near neutral axis)'),
b('Faster rehabilitation'),
]
S.append(two_col(adv_L, adv_R))
S.append(sp(2))
S.append(src('Campbell\'s Operative Orthopaedics 15th Ed 2026, Box 58.10'))
S.append(PageBreak())
# ─────────────────────────────────────────────────────────────────────────
# CH 4 - EXTERNAL FIXATION
# ─────────────────────────────────────────────────────────────────────────
S.append(banner('CHAPTER 4: EXTERNAL FIXATION', NAVY, WHITE, 16, 8))
S.append(sp(3))
S.append(sec_banner('4.1 PRINCIPLES & TYPES'))
S.append(sp(2))
S.append(ext_fixator_diagram())
S.append(cap('Figure 4.1 — External fixator types: Monolateral (left) and Circular Ilizarov Frame (right)'))
S.append(sp(2))
ext_types = [
('MONOLATERAL EXTERNAL FIXATOR',
'Unilateral frame: Schanz pins/half-pins inserted through stab incisions and connected by a single external bar/rail. Simple application, versatile. Standard for temporary stabilization in open fractures, damage control orthopaedics.'),
('BILATERAL / BIPLANAR FIXATOR',
'Pins inserted in two planes — provides superior rotational control. Used for unstable pelvis fractures, some tibial fractures.'),
('CIRCULAR (ILIZAROV) FRAME',
'Full or half rings connected by threaded rods. Tensioned olive wires or half-pins attached to rings pass through bone. The <b>tension-stress principle</b> (Ilizarov): gradual distraction induces new bone formation (distraction osteogenesis). Used for limb lengthening, complex deformity correction, and infected nonunions.'),
('TAYLOR SPATIAL FRAME (TSF)',
'Modified Ilizarov frame with six oblique telescoping struts. Computer software calculates corrections for combined angular, translational, and rotational deformities simultaneously. Based on Stewart platform mechanism.'),
('FINE-WIRE / HALF-PIN COMBINATION',
'Hybrid fixators combine tensioned wires in metaphyseal zone with half-pins in diaphysis. Provide stable metaphyseal fixation with good soft tissue tolerance.'),
]
for name, desc in ext_types:
S.append(h2(name))
S.append(p(desc))
S.append(sp(2))
S.append(sec_banner('4.2 INDICATIONS FOR EXTERNAL FIXATION'))
S.append(sp(2))
ext_ind = [
'Severe open fractures (Gustilo IIIB/IIIC) — temporary and definitive stabilization',
'Polytrauma — damage control orthopaedics (DCO) before definitive fixation',
'Pelvic fractures — emergency "C-clamp" or anterior external frame for haemorrhage control',
'Periarticular fractures with extensive soft tissue injury (spanning fixator)',
'Limb lengthening and complex deformity correction (Ilizarov/TSF)',
'Infected nonunions — avoids internal implant in an infected field',
'Burns patients requiring repeated wound access',
'Arthrodesis in infected joints',
]
for ind in ext_ind:
S.append(b(ind))
S.append(sp(2))
S.append(src('Rockwood and Green\'s Fractures in Adults 10th Ed 2025, Chapter 31'))
S.append(PageBreak())
# ─────────────────────────────────────────────────────────────────────────
# CH 5 - LOCKING PLATES
# ─────────────────────────────────────────────────────────────────────────
S.append(banner('CHAPTER 5: LOCKING PLATES', NAVY, WHITE, 16, 8))
S.append(sp(3))
S.append(sec_banner('5.1 PRINCIPLE OF LOCKING PLATE FIXATION'))
S.append(sp(2))
S.append(locking_plate_diagram())
S.append(cap('Figure 5.1 — Conventional plate (left) vs Locking plate (right): threaded screws lock into plate creating fixed-angle construct'))
S.append(sp(2))
S.append(p('Locking plates have screws with threads that <b>lock into threaded holes</b> on the corresponding plate. This creates a <b>fixed-angle device</b>, or "single-beam" construct — <i>no motion occurs between the screws and the plate.</i>'))
S.append(sp(2))
S.append(src('Rockwood and Green\'s Fractures in Adults 10th Ed 2025, Ch. 31'))
S.append(sp(2))
lp_pts = [
'<b>Fixed-angle construct:</b> Locking screws resist bending moments; load is distributed across ALL screw-bone interfaces simultaneously.',
'<b>No plate-bone contact required:</b> Unlike conventional compression plating, the plate does not need to press against the cortex. Functions like an internal external fixator.',
'<b>Periosteal preservation:</b> Periosteal blood supply and microvascular integrity are maintained — promotes biological healing.',
'<b>Healing pattern:</b> Locking plate constructs without compression result in <i>callus formation</i> (secondary/indirect bone healing), not direct osteonal bridging.',
'<b>Biomechanical superiority in osteoporosis:</b> Locking screws cannot toggle or back out from the plate. Particularly valuable in osteoporotic bone where conventional screws provide inadequate purchase.',
'<b>Fixed angle:</b> Screw angulation is predetermined by the threaded holes — screws cannot change angle, preventing loss of reduction.',
'<b>Cost:</b> Considerably more expensive than traditional plates. Reserved for cases not amenable to conventional fixation.',
]
for lpp in lp_pts:
S.append(b(lpp))
S.append(sp(3))
S.append(sec_banner('5.2 ANAN J. THAKUR — LOCKING PLATES & FRACTURE FIXATION PRINCIPLES'))
S.append(sp(2))
thakur_pts = [
'Locking plates combine the advantages of <b>internal and external fixation.</b>',
'Screw-plate interface strength is <b>greater</b> than conventional plates — prevents screw back-out.',
'Fixed-angle design reduces the risk of <b>varus collapse</b> in osteoporotic proximal femur and humerus fractures.',
'Enables <b>minimally invasive percutaneous plate osteosynthesis (MIPO)</b> — biological fixation preserving blood supply.',
'Relies on <b>secondary bone healing</b> (callus); not direct bone healing of compression plating.',
'<b>Unicortical locking screws</b> can be used to avoid joint penetration near articular surfaces.',
'<b>Combination constructs</b> (locking + conventional screws) provide maximum versatility.',
'Patient-specific locking plates manufactured via <b>3D printing</b> for complex periarticular malunions.',
]
for tp in thakur_pts:
S.append(b(tp))
S.append(sp(2))
S.append(sec_banner('5.3 INDICATIONS FOR LOCKING PLATES'))
S.append(sp(2))
lp_ind = [
'Periarticular fractures: proximal humerus, distal radius, distal femur, proximal tibia',
'Osteoporotic bone — conventional screws provide inadequate purchase',
'Comminuted fractures requiring bridge plating',
'Periarticular malunions with poor bone-to-bone contact after reduction',
'Periprosthetic fractures near existing implants',
'Cases where conventional plate-bone contact would compromise periosteal blood supply',
'Complex deformity correction requiring fixed-angle stability',
]
for ind in lp_ind:
S.append(b(ind))
S.append(sp(2))
S.append(src('Anan J. Thakur — Locking Plates and Fracture Fixation; Rockwood & Green 10th Ed 2025, Ch. 31'))
S.append(PageBreak())
# ─────────────────────────────────────────────────────────────────────────
# CH 6 - WIRES
# ─────────────────────────────────────────────────────────────────────────
S.append(banner('CHAPTER 6: K-WIRES, TENSION BAND & CERCLAGE WIRES', NAVY, WHITE, 16, 8))
S.append(sp(3))
S.append(sec_banner('6.1 KIRSCHNER WIRES (K-WIRES)'))
S.append(sp(2))
S.append(kw_diagram())
S.append(cap('Figure 6.1 — K-wire tip types and tension band wiring for patella fracture'))
S.append(sp(2))
kw_pts = [
'Smooth stainless steel wires; diameters 0.9 mm to 2.5 mm.',
'<b>Tip types:</b> Trocar (three-facet, best for hard cortical bone) or Bayonet/diamond (for harder bone and angled insertion).',
'<b>Uses:</b> temporary fracture reduction, supplementary pin fixation, component of tension band technique, external fixation, Ilizarov olive wires.',
'Can be inserted percutaneously under image intensifier — minimally invasive.',
'<b>Disadvantages:</b> prone to migration, no rotational stability alone, pin-tract infection risk.',
]
for kp in kw_pts:
S.append(b(kp))
S.append(sp(3))
S.append(sec_banner('6.2 TENSION BAND WIRING TECHNIQUE'))
S.append(sp(2))
S.append(p('Based on <b>Pauwels tension band principle.</b> Applied to patella and olecranon fractures: two parallel K-wires are inserted longitudinally; a figure-of-8 wire loop connects them anterior to the bone. Active muscle contraction (quadriceps at patella; triceps at olecranon) generates <i>tensile forces</i>, which are converted to <b>compressive forces</b> at the fracture site through the wire-lever mechanism.'))
S.append(sp(3))
S.append(sec_banner('6.3 CERCLAGE WIRES'))
S.append(sp(2))
S.append(p('Circumferential wires applied around the bone to hold comminuted cortical fragments to the main cortical tube. Used in: femoral shaft fractures with IM nails (cerclage of butterfly fragments), periprosthetic fractures, and revision arthroplasty. Provide hoop stress around the bone. Risk: soft tissue stripping and devascularisation if applied without care.'))
S.append(sp(2))
S.append(src('Campbell\'s Operative Orthopaedics 15th Ed 2026'))
S.append(PageBreak())
# ─────────────────────────────────────────────────────────────────────────
# CH 7 - OTHER IMPLANTS
# ─────────────────────────────────────────────────────────────────────────
S.append(banner('CHAPTER 7: OTHER ORTHOPAEDIC IMPLANTS', NAVY, WHITE, 16, 8))
S.append(sp(3))
S.append(sec_banner('7.1 DYNAMIC HIP SCREW (DHS) & CEPHALOMEDULLARY DEVICES'))
S.append(sp(2))
S.append(dhs_diagram())
S.append(cap('Figure 7.1 — Dynamic Hip Screw (DHS): lag screw slides within barrel of side plate allowing controlled collapse'))
S.append(sp(2))
other_implants = [
('DYNAMIC HIP SCREW (DHS)',
'Sliding lag screw inserted into the femoral head, sitting within a barrel attached to a side plate on the lateral femur. Principle: <b>controlled dynamic collapse</b> — as weight is applied, the lag screw slides within the barrel, converting shear forces to compressive forces at the fracture site. Indicated for stable intertrochanteric fractures.'),
('GAMMA NAIL / PROXIMAL FEMORAL NAIL (PFN)',
'<b>Cephalomedullary nail</b> combining an IM nail with a cephalic screw into the femoral head. Provides superior rotational control vs DHS. Indicated for: reverse oblique and subtrochanteric fractures, high intertrochanteric fractures, and cases where a longer construct is beneficial. Load-sharing device.'),
('CANNULATED HIP SCREWS (Multiple)',
'Three parallel cannulated screws in inverted triangle configuration for femoral neck fractures, particularly undisplaced (Garden I-II). Inserted percutaneously over guidewires under image intensifier guidance. Minimally invasive.'),
('BLADE PLATE',
'Fixed-angle device: blade impacted into bone at correct angle + plate along femoral shaft. Used for subtrochanteric and supracondylar femur fractures. Provides excellent rotational stability. Technically demanding — blade angle must be pre-planned.'),
('TOTAL HIP ARTHROPLASTY (THA) IMPLANTS',
'Femoral stem (cemented or cementless press-fit), acetabular cup with bearing surface. Cementless fixation: <b>osseointegration</b> of porous/HA-coated surface. Cemented: PMMA bone cement transfers load to bone. Bearings: metal-on-polyethylene, ceramic-on-ceramic, ceramic-on-polyethylene.'),
('TOTAL KNEE ARTHROPLASTY (TKA) IMPLANTS',
'Femoral component, tibial tray (metal backed), polyethylene tibial insert, ± patellar component. Most are cementless or cemented. Constraint levels: unconstrained, posterior-stabilised, constrained condylar.'),
('BONE / SUTURE ANCHORS',
'Titanium or bioabsorbable anchors inserted into bone for soft tissue reattachment. Thread or expansion mechanism engages cancellous bone. Used in: rotator cuff repair, labral repair (shoulder/hip), ligament reattachment, flexor tendon repair.'),
('INTRAMEDULLARY ANTIBIOTIC CEMENT NAIL',
'Used in infected long-bone nonunions and osteomyelitis. Antibiotic-impregnated PMMA cement moulded around a Steinmann pin or IM nail. Provides local high-dose antibiotic delivery and temporary mechanical stabilization.'),
]
for name, desc in other_implants:
S.append(h2(name))
S.append(p(desc))
S.append(sp(2))
S.append(src('Campbell\'s Operative Orthopaedics 15th Ed 2026; Rockwood & Green 10th Ed 2025'))
S.append(PageBreak())
# ─────────────────────────────────────────────────────────────────────────
# CH 8 - MATERIALS & BIOMECHANICS
# ─────────────────────────────────────────────────────────────────────────
S.append(banner('CHAPTER 8: IMPLANT MATERIALS & BIOMECHANICS', NAVY, WHITE, 16, 8))
S.append(sp(3))
S.append(sec_banner('8.1 IMPLANT MATERIALS'))
S.append(sp(2))
mat_rows = [
[p('MATERIAL', th_s), p('PROPERTIES', th_s), p('COMMON USES', th_s)],
[p('316L Stainless Steel', tc_s), p('High strength; ductile; corrosion-resistant; inexpensive; ferromagnetic (MRI artefact)', tc_s), p('DCP plates, IM nails, screws, K-wires, external fixators', tc_s)],
[p('Titanium (Ti-6Al-4V)', tc_s), p('Lower elastic modulus (closer to bone — reduces stress shielding); excellent corrosion resistance; MRI-compatible; lighter weight', tc_s), p('Locking plates, IM nails, arthroplasty stems, spinal cages', tc_s)],
[p('Cobalt-Chromium\n(Co-Cr)', tc_s), p('Highest hardness and wear resistance; strong; corrosion-resistant', tc_s), p('Femoral heads (THA), knee arthroplasty bearing surfaces, spinal rods', tc_s)],
[p('UHMWPE\n(polyethylene)', tc_s), p('Excellent wear properties when cross-linked; low friction coefficient; not structural', tc_s), p('Articular bearing surfaces in THA and TKA', tc_s)],
[p('Ceramic\n(alumina/zirconia)', tc_s), p('Very low wear; biocompatible; brittle; excellent hardness', tc_s), p('Femoral heads and acetabular liners in ceramic-on-ceramic THA', tc_s)],
[p('PEEK (polymer)', tc_s), p('Radiolucent; low modulus; no MRI artefact; allows fracture visualization on X-ray', tc_s), p('Spinal interbody cages; experimental fracture fixation', tc_s)],
[p('Bioabsorbable\n(PLA/PGA)', tc_s), p('Degrades over months-years; avoids second surgery; decreasing strength with degradation', tc_s), p('Paediatric fractures, osteochondral fixation, ACL interference screws', tc_s)],
[p('PMMA bone cement', tc_s), p('Self-polymerizing acrylic cement; not an adhesive — mechanical interdigitation with bone; exothermic setting', tc_s), p('Cemented arthroplasty, vertebroplasty, kyphoplasty, antibiotic spacers', tc_s)],
]
mt = Table(mat_rows, colWidths=[35*mm, 88*mm, 47*mm])
mt.setStyle(TableStyle([
('BACKGROUND', (0,0),(-1,0), NAVY),
('ROWBACKGROUNDS', (0,1),(-1,-1), [BONE, WHITE]),
('GRID', (0,0),(-1,-1), 0.5, LGRAY),
('VALIGN', (0,0),(-1,-1), 'TOP'),
('TOPPADDING', (0,0),(-1,-1), 5), ('BOTTOMPADDING', (0,0),(-1,-1), 5),
('LEFTPADDING', (0,0),(-1,-1), 6),
]))
S.append(mt)
S.append(sp(3))
S.append(sec_banner('8.2 KEY BIOMECHANICAL CONCEPTS'))
S.append(sp(2))
biom = [
('<b>Stress shielding:</b>', 'When a stiff implant bears the load normally passing through bone, the bone undergoes stress-induced resorption (Wolff\'s law). Titanium\'s lower elastic modulus reduces stress shielding vs stainless steel.'),
('<b>Load-sharing vs load-bearing:</b>', 'IM nails share load with bone. Plates primarily bear load. Load-sharing is biomechanically superior for weight-bearing long bones.'),
('<b>Neutral axis:</b>', 'An implant placed at the bone\'s neutral axis (e.g., IM nail) experiences minimal bending moments compared to an eccentrically placed plate.'),
('<b>Fatigue failure:</b>', 'Cyclic loading at stress risers (screw holes, transitions) leads to crack propagation and failure. Broad plates with offset holes and LC-DCP design minimize stress concentration.'),
('<b>Absolute vs relative stability:</b>', '<b>Absolute stability</b> — interfragmentary compression, primary bone healing (direct osteonal bridging). <b>Relative stability</b> — splinting/bridging, secondary bone healing via callus. Different implants provide different modes.'),
('<b>Axial micromotion:</b>', 'Controlled interfragmentary movement under load stimulates callus formation. Dynamic locking of IM nails and bridge plating exploit this.'),
]
for term, desc in biom:
S.append(p(f'{term} {desc}'))
S.append(sp(2))
S.append(src('Campbell\'s Operative Orthopaedics 15th Ed 2026'))
S.append(PageBreak())
# ─────────────────────────────────────────────────────────────────────────
# CH 9 - METAL REMOVAL TIMING
# ─────────────────────────────────────────────────────────────────────────
S.append(banner('CHAPTER 9: METAL REMOVAL — TIMING GUIDELINES', NAVY, WHITE, 16, 8))
S.append(sp(3))
S.append(p('Implant removal timing follows ASIF (AO/ASIF) guidelines and applies to fractures with uncomplicated healing. Removal is <b>not</b> recommended in pseudarthroses, post-infection cases, or major fragment fixation without individual assessment.'))
S.append(sp(2))
rem_rows = [
[p('BONE / FRACTURE TYPE', th_s), p('RECOMMENDED REMOVAL TIME', th_s)],
[p('Malleolar fractures', tc_s), p('8 - 12 months', tc_s)],
[p('Tibial pilon', tc_s), p('12 - 18 months', tc_s)],
[p('Tibial shaft — plate', tc_s), p('12 - 18 months', tc_s)],
[p('Tibial shaft — IM nail', tc_s), p('18 - 24 months', tc_s)],
[p('Tibial plateau', tc_s), p('12 - 18 months', tc_s)],
[p('Patella — tension band', tc_s), p('8 - 12 months', tc_s)],
[p('Femoral condyles', tc_s), p('12 - 24 months', tc_s)],
[p('Femoral shaft — single plate', tc_s), p('24 - 36 months', tc_s)],
[p('Femoral shaft — double plates', tc_s), p('From 18 months, in two steps (6-month interval)', tc_s)],
[p('Femoral shaft — IM nail', tc_s), p('24 - 36 months', tc_s)],
[p('Peritrochanteric / femoral neck', tc_s), p('12 - 18 months', tc_s)],
[p('Pelvis (only if symptomatic)', tc_s), p('From 10 months', tc_s)],
[p('Upper extremity', tc_s), p('12 - 18 months (removal generally optional)', tc_s)],
]
rt = Table(rem_rows, colWidths=[100*mm, 70*mm])
rt.setStyle(TableStyle([
('BACKGROUND', (0,0),(-1,0), NAVY),
('ROWBACKGROUNDS', (0,1),(-1,-1), [BONE, WHITE]),
('GRID', (0,0),(-1,-1), 0.5, LGRAY),
('VALIGN', (0,0),(-1,-1), 'MIDDLE'),
('TOPPADDING', (0,0),(-1,-1), 5), ('BOTTOMPADDING', (0,0),(-1,-1), 5),
('LEFTPADDING', (0,0),(-1,-1), 6),
]))
S.append(rt)
S.append(sp(3))
S.append(info_box(
'<b>Note:</b> These timings relate to uncomplicated healing in otherwise healthy patients. '
'Pseudarthroses, post-infection cases, and major fragment fixation must be assessed individually. '
'Upper extremity implant removal is generally <i>optional</i> unless symptomatic.',
LBLUE, info_s
))
S.append(sp(3))
S.append(src('Campbell\'s Operative Orthopaedics 15th Ed 2026, Table 58.12'))
S.append(sp(4))
# References footer
ref_s = PS('ref', fontSize=8, textColor=WHITE, fontName='Helvetica', alignment=TA_LEFT, leading=13)
ref_text = (
'<b>REFERENCES:</b><br/>'
'1. Canale ST, Beaty JH (eds). Campbell\'s Operative Orthopaedics, 15th Edition, 2026. Elsevier.<br/>'
'2. Tornetta P, Ricci W, Ostrum RF et al. (eds). Rockwood and Green\'s Fractures in Adults, 10th Edition, 2025. Wolters Kluwer.<br/>'
'3. Thakur AJ. Locking Plates and Fracture Fixation Principles.'
)
ref_t = Table([[p(ref_text, ref_s)]], colWidths=[CW])
ref_t.setStyle(TableStyle([
('BACKGROUND', (0,0),(-1,-1), NAVY),
('TOPPADDING', (0,0),(-1,-1), 8), ('BOTTOMPADDING', (0,0),(-1,-1), 8),
('LEFTPADDING', (0,0),(-1,-1), 10), ('RIGHTPADDING', (0,0),(-1,-1), 10),
]))
S.append(ref_t)
doc.build(S)
print(f'PDF created: {out}')
if __name__ == '__main__':
build()
Still am I asking where is PDF? If you cannot generate PDF, just say you cannot. Don't waste my time, okay?
cat > /home/daytona/workspace/ortho-implants-pdf/create_pdf.py << 'PYEOF' from reportlab.lib.pagesizes import A4 from reportlab.lib.styles import ParagraphStyle from reportlab.lib.units import mm from reportlab.lib import colors from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable, PageBreak from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY from reportlab.graphics.shapes import Drawing, Rect, Circle, Line, Polygon, String, Ellipse import math NAVY=colors.HexColor('#1A2B4A'); STEEL=colors.HexColor('#2E5FA3'); TEAL=colors.HexColor('#0C7B93') SILVER=colors.HexColor('#E8EDF4'); BONE=colors.HexColor('#F5F0E8'); RED=colors.HexColor('#C0392B') GREEN=colors.HexColor('#27AE60'); LGRAY=colors.HexColor('#D5DCE8'); DGRAY=colors.HexColor('#4A4A4A') WHITE=colors.white; METAL=colors.HexColor('#8C9BAB'); ORANGE=colors.HexColor('#E67E22') PURPLE=colors.HexColor('#6C5CE7'); YELLOW=colors.HexColor('#FFF8E1'); LBLUE=colors.HexColor('#E3F2FD') PAGE_W,PAGE_H=A4; CW=PAGE_W-40*mm def PS(n,**k): return ParagraphStyle(n,**k) body_s=PS('b',fontSize=10,textColor=DGRAY,alignment=TA_JUSTIFY,leading=15,fontName='Helvetica',spaceBefore=3,spaceAfter=3) bul_s=PS('bl',fontSize=10,textColor=DGRAY,alignment=TA_LEFT,leading=15,fontName='Helvetica',leftIndent=16,spaceBefore=2) sub_s=PS('sh',fontSize=12,textColor=NAVY,alignment=TA_LEFT,leading=18,fontName='Helvetica-Bold',spaceBefore=6,spaceAfter=2) cap_s=PS('cp',fontSize=8,textColor=STEEL,alignment=TA_CENTER,leading=11,fontName='Helvetica-Oblique') src_s=PS('sc',fontSize=8,textColor=STEEL,alignment=TA_LEFT,leading=11,fontName='Helvetica-Oblique') th_s=PS('th',fontSize=9,textColor=WHITE,alignment=TA_CENTER,leading=13,fontName='Helvetica-Bold') tc_s=PS('tc',fontSize=8,textColor=DGRAY,alignment=TA_LEFT,leading=12,fontName='Helvetica') note_s=PS('nt',fontSize=9,textColor=colors.HexColor('#7B4C00'),alignment=TA_LEFT,leading=13,fontName='Helvetica') info_s=PS('in',fontSize=9,textColor=colors.HexColor('#1A527A'),alignment=TA_LEFT,leading=13,fontName='Helvetica') def pp(t,s=None): return Paragraph(t, s or body_s) def bl(t): return Paragraph(f'• {t}', bul_s) def h2(t): return Paragraph(t, sub_s) def cap(t): return Paragraph(t, cap_s) def src(t): return Paragraph(f'<i>Source: {t}</i>', src_s) def sp(h=4): return Spacer(1,h*mm) def hr(): return HRFlowable(width='100%',thickness=0.5,color=LGRAY,spaceAfter=2*mm,spaceBefore=2*mm) def banner(text,bg=NAVY,tc=WHITE,fs=16,pv=8): s=PS('bn',fontSize=fs,textColor=tc,fontName='Helvetica-Bold',alignment=TA_CENTER,leading=fs+5) t=Table([[pp(text,s)]],colWidths=[CW]) t.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),bg),('TOPPADDING',(0,0),(-1,-1),pv), ('BOTTOMPADDING',(0,0),(-1,-1),pv),('LEFTPADDING',(0,0),(-1,-1),8),('RIGHTPADDING',(0,0),(-1,-1),8)])) return t def secb(text,bg=STEEL): s=PS('sb',fontSize=11,textColor=WHITE,fontName='Helvetica-Bold',alignment=TA_LEFT,leading=15) t=Table([[pp(text,s)]],colWidths=[CW]) t.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),bg),('TOPPADDING',(0,0),(-1,-1),5), ('BOTTOMPADDING',(0,0),(-1,-1),5),('LEFTPADDING',(0,0),(-1,-1),10),('RIGHTPADDING',(0,0),(-1,-1),8)])) return t def ibox(text,bg=YELLOW,ts=None): ts=ts or note_s t=Table([[pp(text,ts)]],colWidths=[CW]) t.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),bg),('TOPPADDING',(0,0),(-1,-1),7), ('BOTTOMPADDING',(0,0),(-1,-1),7),('LEFTPADDING',(0,0),(-1,-1),10),('RIGHTPADDING',(0,0),(-1,-1),8), ('BOX',(0,0),(-1,-1),0.5,STEEL)])) return t def mktable(rows,widths,hdr_bg=NAVY): t=Table(rows,colWidths=widths) t.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,0),hdr_bg),('ROWBACKGROUNDS',(0,1),(-1,-1),[BONE,WHITE]), ('GRID',(0,0),(-1,-1),0.5,LGRAY),('VALIGN',(0,0),(-1,-1),'TOP'), ('TOPPADDING',(0,0),(-1,-1),5),('BOTTOMPADDING',(0,0),(-1,-1),5),('LEFTPADDING',(0,0),(-1,-1),6)])) return t # ── DRAWINGS ───────────────────────────────────────────────────────────────── def screw_diagram(): w,h=500,265; d=Drawing(w,h) d.add(Rect(0,0,w,h,fillColor=SILVER,strokeColor=None)) d.add(String(w/2,h-20,'ANATOMY OF AN ORTHOPAEDIC BONE SCREW',fontSize=11,fillColor=NAVY,textAnchor='middle',fontName='Helvetica-Bold')) sx,sy=40,105; hw,hh=48,32; sl=55; tl=270; tipl=18 d.add(Rect(sx,sy,hw,hh,fillColor=METAL,strokeColor=NAVY,strokeWidth=1.5,rx=3)) for dx in [0.3,0.5,0.7]: d.add(Line(sx+hw*dx,sy+5,sx+hw*dx,sy+hh-5,strokeColor=DGRAY,strokeWidth=1)) st=sy+8; sb=sy+hh-8 d.add(Rect(sx+hw,st,sl,sb-st,fillColor=METAL,strokeColor=NAVY,strokeWidth=1)) tx=sx+hw+sl; tt=st-7; tb=sb+7; pitch=11; n=int(tl/pitch) for i in range(n): x0=tx+i*pitch d.add(Polygon([x0,st,x0+pitch/2,tt,x0+pitch,st],fillColor=METAL,strokeColor=NAVY,strokeWidth=0.6)) d.add(Polygon([x0,sb,x0+pitch/2,tb,x0+pitch,sb],fillColor=METAL,strokeColor=NAVY,strokeWidth=0.6)) d.add(Rect(tx,st,tl,sb-st,fillColor=METAL,strokeColor=None)) tipx=tx+tl; mid=(st+sb)/2 d.add(Polygon([tipx,st,tipx+tipl,mid,tipx,sb],fillColor=METAL,strokeColor=NAVY,strokeWidth=1)) ay=sy-18; ly=ay-14 def ann(lx,rx,lbl,col=NAVY): mx=(lx+rx)/2 d.add(Line(lx,sy+hh+2,lx,ay+6,strokeColor=col,strokeWidth=0.8)) d.add(Line(rx,sy+hh+2,rx,ay+6,strokeColor=col,strokeWidth=0.8)) d.add(Line(lx,ay,rx,ay,strokeColor=col,strokeWidth=1)) d.add(String(mx,ly,lbl,fontSize=8,fillColor=col,textAnchor='middle',fontName='Helvetica-Bold')) ann(sx,sx+hw,'HEAD',NAVY); ann(sx+hw,sx+hw+sl,'SHANK',STEEL) ann(tx,tx+tl,'THREADED PORTION',TEAL); ann(tipx,tipx+tipl,'TIP',RED) p1=tx+2*pitch; p2=tx+3*pitch d.add(Line(p1,tb+4,p2,tb+4,strokeColor=GREEN,strokeWidth=1.5)) d.add(Line(p1,tb+2,p1,tb+9,strokeColor=GREEN,strokeWidth=1)) d.add(Line(p2,tb+2,p2,tb+9,strokeColor=GREEN,strokeWidth=1)) d.add(String((p1+p2)/2,tb+14,'Pitch',fontSize=8,fillColor=GREEN,textAnchor='middle',fontName='Helvetica-Bold')) tdx=tx+8*pitch d.add(Line(tdx,tt-2,tdx,tb+2,strokeColor=ORANGE,strokeWidth=1.5)) d.add(String(tdx+8,tb+14,'Thread Diam.',fontSize=8,fillColor=ORANGE,textAnchor='start',fontName='Helvetica-Bold')) rdx=tdx+4*pitch d.add(Line(rdx,st,rdx,sb,strokeColor=RED,strokeWidth=1.5)) d.add(String(rdx+8,st-12,'Root Diam.',fontSize=8,fillColor=RED,textAnchor='start',fontName='Helvetica-Bold')) return d def screw_types_diagram(): w,h=510,225; d=Drawing(w,h) d.add(Rect(0,0,w,h,fillColor=SILVER,strokeColor=None)) d.add(String(w/2,h-20,'TYPES OF ORTHOPAEDIC SCREWS',fontSize=11,fillColor=NAVY,textAnchor='middle',fontName='Helvetica-Bold')) types=[('CORTICAL',STEEL,'Fine thread\nFull length\nSmall pitch'),('CANCELLOUS',TEAL,'Coarse thread\nPartial/full\nLarge pitch'), ('LOCKING',RED,'Threaded head\nLocks in plate\nFixed-angle'),('CANNULATED',ORANGE,'Hollow shaft\nOver guidewire\nPerc. technique'), ('SELF-TAPPING',GREEN,'Fluted tip\nNo pre-tapping\nExt. fixation')] for i,(name,col,desc) in enumerate(types): x=50+i*96; sw,sh=22,80; sy2=105 d.add(Rect(x-sw/2,sy2+sh+2,sw,20,fillColor=col,strokeColor=NAVY,strokeWidth=1,rx=2)) d.add(Rect(x-sw/4,sy2+18,sw/2,sh-16,fillColor=col,strokeColor=None)) pitch=6 if name=='CORTICAL' else 10 for ty in range(int(sy2+20),int(sy2+sh),pitch): d.add(Line(x-sw/2-4,ty,x+sw/2+4,ty,strokeColor=NAVY,strokeWidth=0.7)) if name=='CANNULATED': d.add(Rect(x-sw/8,sy2+18,sw/4,sh-16,fillColor=WHITE,strokeColor=None)) if name=='SELF-TAPPING': d.add(Polygon([x-sw/4,sy2+20,x,sy2+5,x+sw/4,sy2+20],fillColor=col,strokeColor=NAVY,strokeWidth=0.8)) else: d.add(Polygon([x-sw/4,sy2+22,x,sy2+10,x+sw/4,sy2+22],fillColor=col,strokeColor=NAVY,strokeWidth=0.8)) if name=='LOCKING': for lx2 in range(int(x-sw/2+2),int(x+sw/2),4): d.add(Line(lx2,sy2+sh+4,lx2,sy2+sh+20,strokeColor=NAVY,strokeWidth=0.5)) d.add(String(x,sy2+sh+30,name,fontSize=7.5,fillColor=NAVY,textAnchor='middle',fontName='Helvetica-Bold')) for j,line in enumerate(desc.split('\n')): d.add(String(x,sy2+sh+42+j*10,line,fontSize=6.5,fillColor=DGRAY,textAnchor='middle',fontName='Helvetica')) return d def plate_diagram(): w,h=510,300; d=Drawing(w,h) d.add(Rect(0,0,w,h,fillColor=SILVER,strokeColor=None)) d.add(String(w/2,h-20,'TYPES OF FRACTURE FIXATION PLATES',fontSize=11,fillColor=NAVY,textAnchor='middle',fontName='Helvetica-Bold')) items=[('NEUTRALIZATION',STEEL,48,'Neutralizes\ntorsion/bending'),('COMPRESSION\n(DCP)',TEAL,142,'Axial compression\noval holes'), ('BUTTRESS',NAVY,236,'Prevents axial\ndeformation'),('BRIDGE',PURPLE,330,'Spans comminuted\nfragments'),('LOCKING',RED,420,'Fixed-angle\nconstruct')] for label,col,x,desc in items: pw,ph,py2=55,90,95 d.add(Rect(x-pw/2,py2,pw,ph,fillColor=col,strokeColor=NAVY,strokeWidth=1.2,rx=5)) for hy in [py2+12,py2+28,py2+ph//2,py2+ph-28,py2+ph-12]: d.add(Circle(x,hy,5,fillColor=WHITE,strokeColor=DGRAY,strokeWidth=1)) if col==RED: d.add(Circle(x,hy,3,fillColor=LGRAY,strokeColor=NAVY,strokeWidth=0.8)) for k,ln in enumerate(label.split('\n')): d.add(String(x,py2-22-k*12,ln,fontSize=8,fillColor=NAVY,textAnchor='middle',fontName='Helvetica-Bold')) for k,ln in enumerate(desc.split('\n')): d.add(String(x,py2+ph+16+k*11,ln,fontSize=7,fillColor=DGRAY,textAnchor='middle',fontName='Helvetica')) return d def tension_band_diagram(): w,h=510,240; d=Drawing(w,h) d.add(Rect(0,0,w,h,fillColor=SILVER,strokeColor=None)) d.add(String(w/2,h-20,'TENSION BAND PRINCIPLE (PAUWELS)',fontSize=11,fillColor=NAVY,textAnchor='middle',fontName='Helvetica-Bold')) for label,x0,hp in [('WITHOUT PLATE\n(gap on tension side)',90,False),('WITH PLATE ON\nTENSION SIDE',340,True)]: bx,by,bw,bh=x0,40,28,160 d.add(Rect(bx,by,bw,bh,fillColor=BONE,strokeColor=DGRAY,strokeWidth=2,rx=6)) d.add(Line(bx-3,by+bh//2,bx+bw+3,by+bh//2+2,strokeColor=RED,strokeWidth=2)) d.add(Line(bx+bw/2,by-18,bx+bw/2,by,strokeColor=NAVY,strokeWidth=2)) d.add(Polygon([bx+bw/2-5,by,bx+bw/2,by-14,bx+bw/2+5,by],fillColor=NAVY,strokeColor=None)) d.add(String(bx+bw/2,by-24,'Load',fontSize=8,fillColor=NAVY,textAnchor='middle',fontName='Helvetica-Bold')) if hp: d.add(Rect(bx+bw+3,by+18,8,bh-36,fillColor=STEEL,strokeColor=NAVY,strokeWidth=1,rx=2)) for sy3 in [by+28,by+46,by+bh-46,by+bh-28]: d.add(Line(bx-4,sy3,bx+bw+12,sy3,strokeColor=METAL,strokeWidth=3)) d.add(String(bx+bw+18,by+bh/2,'Compression',fontSize=7.5,fillColor=GREEN,textAnchor='start',fontName='Helvetica-Bold')) else: d.add(Line(bx+bw+2,by+bh//2-14,bx+bw+22,by+bh//2-20,strokeColor=RED,strokeWidth=1.5)) d.add(String(bx+bw+24,by+bh//2-10,'Gap (tension)',fontSize=7,fillColor=RED,textAnchor='start',fontName='Helvetica-Bold')) for k,ln in enumerate(label.split('\n')): d.add(String(bx+bw/2,by+bh+18+k*12,ln,fontSize=8,fillColor=NAVY,textAnchor='middle',fontName='Helvetica-Bold')) return d def nail_diagram(): w,h=510,280; d=Drawing(w,h) d.add(Rect(0,0,w,h,fillColor=SILVER,strokeColor=None)) d.add(String(w/2,h-20,'INTRAMEDULLARY NAIL - STATIC vs DYNAMIC LOCKING',fontSize=11,fillColor=NAVY,textAnchor='middle',fontName='Helvetica-Bold')) for label,x0,is_s in [('STATIC LOCKING\n(both proximal & distal screws fixed)',80,True),('DYNAMIC LOCKING\n(proximal in oval slot)',300,False)]: fx,fy,fw,fh=x0+55,48,46,190 d.add(Rect(fx-fw/2,fy,fw,fh,fillColor=BONE,strokeColor=DGRAY,strokeWidth=2,rx=14)) d.add(Rect(fx-10,fy+14,20,fh-28,fillColor=WHITE,strokeColor=LGRAY,strokeWidth=0.5)) d.add(Rect(fx-6,fy+8,12,fh-16,fillColor=METAL,strokeColor=NAVY,strokeWidth=1,rx=3)) syp=fy+32 if is_s: d.add(Line(fx-fw/2-14,syp,fx+fw/2+14,syp,strokeColor=STEEL,strokeWidth=4)) d.add(String(fx+fw/2+18,syp+3,'Prox. screw\n(fixed)',fontSize=7,fillColor=STEEL,fontName='Helvetica')) else: d.add(Rect(fx-6,syp-6,12,13,fillColor=WHITE,strokeColor=NAVY,strokeWidth=1)) d.add(Line(fx-fw/2-14,syp,fx+fw/2+14,syp,strokeColor=ORANGE,strokeWidth=4)) d.add(String(fx+fw/2+18,syp+3,'Slot (dynamic)',fontSize=7,fillColor=ORANGE,fontName='Helvetica-Bold')) syd=fy+fh-42 d.add(Line(fx-fw/2-14,syd,fx+fw/2+14,syd,strokeColor=STEEL,strokeWidth=4)) d.add(String(fx+fw/2+18,syd+3,'Dist. screw\n(fixed)',fontSize=7,fillColor=STEEL,fontName='Helvetica')) for k,ln in enumerate(label.split('\n')): d.add(String(fx,fy+fh+18+k*12,ln,fontSize=8,fillColor=NAVY,textAnchor='middle',fontName='Helvetica-Bold')) return d def ext_fixator_diagram(): w,h=510,260; d=Drawing(w,h) d.add(Rect(0,0,w,h,fillColor=SILVER,strokeColor=None)) d.add(String(w/2,h-20,'EXTERNAL FIXATION - TYPES & COMPONENTS',fontSize=11,fillColor=NAVY,textAnchor='middle',fontName='Helvetica-Bold')) bx,by,bw,bh=85,55,22,145 d.add(Rect(bx,by,bw,bh,fillColor=BONE,strokeColor=DGRAY,strokeWidth=2,rx=5)) d.add(Line(bx-3,by+65,bx+bw+3,by+68,strokeColor=RED,strokeWidth=2)) for py4 in [by+20,by+40,by+85,by+105]: d.add(Line(bx-52,py4,bx+bw+50,py4,strokeColor=STEEL,strokeWidth=3)) d.add(Rect(bx-58,by+12,10,105,fillColor=METAL,strokeColor=NAVY,strokeWidth=1,rx=3)) d.add(String(bx+bw/2,by+bh+20,'Monolateral\nExternal Fixator',fontSize=8,fillColor=NAVY,textAnchor='middle',fontName='Helvetica-Bold')) d.add(String(bx-55,by+22,'Schanz pin',fontSize=7,fillColor=STEEL,textAnchor='middle',fontName='Helvetica')) d.add(String(bx-55,by+58,'Connecting\nbar',fontSize=7,fillColor=METAL,textAnchor='middle',fontName='Helvetica')) d.add(String(bx+bw+32,by+66,'Fracture\nsite',fontSize=7,fillColor=RED,textAnchor='middle',fontName='Helvetica-Bold')) cx,cy,cr=370,128,58 for ry in [cy-50,cy+50]: d.add(Circle(cx,ry,cr,fillColor=None,strokeColor=METAL,strokeWidth=6)) for ang in [45,135,225,315]: ex=cx+math.cos(math.radians(ang))*cr d.add(Line(ex,cy-50,ex,cy+50,strokeColor=STEEL,strokeWidth=3)) d.add(Rect(cx-8,cy-82,16,164,fillColor=BONE,strokeColor=DGRAY,strokeWidth=2,rx=5)) for wy in [cy-50,cy+50]: d.add(Line(cx-cr+6,wy,cx+cr-6,wy,strokeColor=ORANGE,strokeWidth=1.5)) d.add(String(cx,cy+120,'Circular (Ilizarov)\nFrame',fontSize=8,fillColor=NAVY,textAnchor='middle',fontName='Helvetica-Bold')) return d def locking_plate_diagram(): w,h=510,270; d=Drawing(w,h) d.add(Rect(0,0,w,h,fillColor=SILVER,strokeColor=None)) d.add(String(w/2,h-20,'CONVENTIONAL PLATE vs LOCKING PLATE',fontSize=11,fillColor=NAVY,textAnchor='middle',fontName='Helvetica-Bold')) for label,x0,col,ilk in [('CONVENTIONAL PLATE\n(friction-based)',50,STEEL,False),('LOCKING PLATE\n(fixed-angle construct)',285,TEAL,True)]: bx,by,bw,bh=x0,55,20,160 d.add(Rect(bx,by,bw,bh,fillColor=BONE,strokeColor=DGRAY,strokeWidth=2,rx=5)) d.add(Line(bx-2,by+78,bx+bw+2,by+80,strokeColor=RED,strokeWidth=2)) px,pw,ph=bx+bw+4,75,bh-30 d.add(Rect(px,by+15,pw,ph,fillColor=col,strokeColor=NAVY,strokeWidth=1.2,rx=3)) for sy5 in [by+28,by+46,by+80,by+100,by+118]: if ilk: d.add(Circle(px,sy5,5,fillColor=LGRAY,strokeColor=NAVY,strokeWidth=1.2)) for lx3 in range(int(px-4),int(px+5),2): d.add(Line(lx3,sy5-5,lx3,sy5+5,strokeColor=NAVY,strokeWidth=0.4)) d.add(Line(bx-5,sy5,px,sy5,strokeColor=METAL,strokeWidth=4)) else: d.add(Circle(px,sy5,5,fillColor=WHITE,strokeColor=DGRAY,strokeWidth=1)) d.add(Line(bx-5,sy5,px+8,sy5,strokeColor=METAL,strokeWidth=4)) for k,ln in enumerate(label.split('\n')): d.add(String(bx+bw/2+pw/2+8,by+bh+18+k*11,ln,fontSize=7.5,fillColor=NAVY,textAnchor='middle',fontName='Helvetica-Bold' if k==0 else 'Helvetica')) return d def kw_diagram(): w,h=510,230; d=Drawing(w,h) d.add(Rect(0,0,w,h,fillColor=SILVER,strokeColor=None)) d.add(String(w/2,h-20,'K-WIRES & TENSION BAND WIRING',fontSize=11,fillColor=NAVY,textAnchor='middle',fontName='Helvetica-Bold')) px2,py2,pr=140,70,55 d.add(Ellipse(px2,py2+pr,pr*1.1,pr,fillColor=BONE,strokeColor=DGRAY,strokeWidth=2)) d.add(Line(px2-pr,py2+pr,px2+pr,py2+pr,strokeColor=RED,strokeWidth=2)) for kx in [px2-20,px2+20]: d.add(Line(kx,py2+8,kx,py2+2*pr+12,strokeColor=STEEL,strokeWidth=3)) d.add(Polygon([kx-3,py2+8,kx,py2-6,kx+3,py2+8],fillColor=STEEL,strokeColor=None)) d.add(Line(px2-20,py2+2*pr+12,px2+20,py2+2*pr+12,strokeColor=ORANGE,strokeWidth=2)) d.add(Line(px2-20,py2+2*pr+12,px2+20,py2+12,strokeColor=ORANGE,strokeWidth=2)) d.add(Line(px2+20,py2+2*pr+12,px2-20,py2+12,strokeColor=ORANGE,strokeWidth=2)) d.add(String(px2,py2+2*pr+32,'K-wires (blue) + Figure-of-8 wire (orange)',fontSize=7.5,fillColor=NAVY,textAnchor='middle',fontName='Helvetica-Bold')) d.add(String(px2,py2+2*pr+46,'Patella Tension Band Wiring',fontSize=8,fillColor=NAVY,textAnchor='middle',fontName='Helvetica-Bold')) kx3=390 d.add(String(kx3,h-44,'K-WIRE TIP TYPES',fontSize=9,fillColor=NAVY,textAnchor='middle',fontName='Helvetica-Bold')) for i,(tname,tcol) in enumerate([('Trocar tip',STEEL),('Bayonet tip',TEAL)]): tx2=kx3-35+i*72; ty2=70 d.add(Rect(tx2-4,ty2,8,90,fillColor=tcol,strokeColor=NAVY,strokeWidth=1)) if i==0: d.add(Polygon([tx2-4,ty2,tx2,ty2-14,tx2+4,ty2],fillColor=tcol,strokeColor=NAVY,strokeWidth=1)) else: d.add(Polygon([tx2-4,ty2,tx2+4,ty2-12,tx2+4,ty2],fillColor=tcol,strokeColor=NAVY,strokeWidth=1)) d.add(String(tx2,ty2+100,tname,fontSize=7.5,fillColor=NAVY,textAnchor='middle',fontName='Helvetica')) return d def dhs_diagram(): w,h=510,240; d=Drawing(w,h) d.add(Rect(0,0,w,h,fillColor=SILVER,strokeColor=None)) d.add(String(w/2,h-20,'DYNAMIC HIP SCREW (DHS) - SLIDING PRINCIPLE',fontSize=11,fillColor=NAVY,textAnchor='middle',fontName='Helvetica-Bold')) fx,fy,fw,fh=130,38,50,180 d.add(Rect(fx,fy,fw,fh,fillColor=BONE,strokeColor=DGRAY,strokeWidth=2,rx=8)) d.add(Circle(fx-38,fy+20,30,fillColor=BONE,strokeColor=DGRAY,strokeWidth=2)) d.add(Rect(fx+fw,fy+60,12,fh-70,fillColor=STEEL,strokeColor=NAVY,strokeWidth=1.2,rx=2)) d.add(Rect(fx+fw,fy+62,36,14,fillColor=METAL,strokeColor=NAVY,strokeWidth=1,rx=3)) d.add(Line(fx+fw+36,fy+69,fx-35,fy+20,strokeColor=STEEL,strokeWidth=6)) d.add(String(fx-40,fy+8,'Lag screw',fontSize=7.5,fillColor=STEEL,textAnchor='middle',fontName='Helvetica-Bold')) d.add(String(fx+fw+8,fy+84,'Barrel\n(sliding)',fontSize=7,fillColor=METAL,textAnchor='middle',fontName='Helvetica')) d.add(String(fx+fw+8,fy+fh-4,'Side plate',fontSize=7.5,fillColor=NAVY,textAnchor='middle',fontName='Helvetica-Bold')) d.add(Line(fx+fw/2,fy-18,fx+fw/2,fy,strokeColor=RED,strokeWidth=2)) d.add(Polygon([fx+fw/2-5,fy,fx+fw/2,fy-14,fx+fw/2+5,fy],fillColor=RED,strokeColor=None)) d.add(String(fx+fw/2,fy-24,'Load',fontSize=8,fillColor=RED,textAnchor='middle',fontName='Helvetica-Bold')) d.add(String(fx+fw+50,fy+95,'Controlled collapse\n= compression',fontSize=8,fillColor=GREEN,textAnchor='start',fontName='Helvetica-Bold')) for sy6 in [fy+75,fy+95,fy+115,fy+135]: d.add(Line(fx+fw-5,sy6,fx+fw+12,sy6,strokeColor=METAL,strokeWidth=2)) return d # ─── BUILD ──────────────────────────────────────────────────────────────────── out='/home/daytona/workspace/ortho-implants-pdf/Orthopaedic_Implants_Fracture_Fixation.pdf' doc=SimpleDocTemplate(out,pagesize=A4,leftMargin=20*mm,rightMargin=20*mm,topMargin=18*mm,bottomMargin=18*mm, title='Orthopaedic Implants & Fracture Fixation',author='Campbell / Rockwood & Green / Thakur') S=[] # COVER S+=[sp(6),banner('ORTHOPAEDIC IMPLANTS\nAND FRACTURE FIXATION',NAVY,WHITE,24,12),sp(3), banner('Principles • Types • Techniques • Biomechanics',STEEL,WHITE,13,6),sp(3), banner("Sources: Campbell's Operative Orthopaedics 15th Ed 2026 | Rockwood & Green's Fractures in Adults 10th Ed 2025\nAnan J. Thakur – Locking Plates and Fracture Fixation",TEAL,WHITE,10,7),sp(5)] toc_s=PS('to',fontSize=10,textColor=DGRAY,fontName='Helvetica',alignment=TA_LEFT,leading=14) toc_n=PS('tn',fontSize=10,textColor=NAVY,fontName='Helvetica-Bold',alignment=TA_CENTER,leading=14) toc_rows=[[pp('CH',th_s),pp('CHAPTER TITLE',th_s),pp('KEY TOPICS',th_s)], [pp('1',toc_n),pp('SCREWS IN ORTHOPAEDICS',toc_s),pp('Parts, types, principles, insertion techniques',toc_s)], [pp('2',toc_n),pp('PLATES & PLATING',toc_s),pp('Types, principles, applications, DCP, buttress',toc_s)], [pp('3',toc_n),pp('INTRAMEDULLARY NAILS',toc_s),pp('Design, biomechanics, reaming, interlocking',toc_s)], [pp('4',toc_n),pp('EXTERNAL FIXATION',toc_s),pp('Monolateral, circular Ilizarov, TSF',toc_s)], [pp('5',toc_n),pp('LOCKING PLATES',toc_s),pp('Principle, fixed-angle, MIPO, Thakur',toc_s)], [pp('6',toc_n),pp('K-WIRES & TENSION BAND',toc_s),pp('Pauwels principle, K-wires, cerclage',toc_s)], [pp('7',toc_n),pp('OTHER IMPLANTS (DHS, PFN...)',toc_s),pp('Dynamic hip screw, gamma nail, anchors',toc_s)], [pp('8',toc_n),pp('IMPLANT MATERIALS & BIOMECHANICS',toc_s),pp('Steel, titanium, Co-Cr, stress shielding',toc_s)], [pp('9',toc_n),pp('METAL REMOVAL TIMING',toc_s),pp('ASIF guidelines by bone/fracture type',toc_s)]] S.append(mktable(toc_rows,[12*mm,78*mm,80*mm])) S.append(PageBreak()) # CH 1 SCREWS S+=[banner('CHAPTER 1: SCREWS IN ORTHOPAEDIC SURGERY',NAVY,WHITE,16,8),sp(3), secb('1.1 PARTS OF A BONE SCREW'),sp(2), pp('Screws are complex tools with a <b>four-part construction: Head, Shaft (Shank), Thread,</b> and <b>Tip.</b> Each part serves a distinct biomechanical role in achieving purchase in bone and generating compression.'), src("Campbell's Operative Orthopaedics 15th Ed 2026, Chapter 58"),sp(2), screw_diagram(),cap('Figure 1.1 — Anatomy of an orthopaedic bone screw with all design parameters'),sp(2)] S.append(mktable([[pp('PART',th_s),pp('DESCRIPTION & BIOMECHANICAL FUNCTION',th_s)], [pp('<b>HEAD</b>',tc_s),pp('Attachment point for screwdriver (hex, cruciate, Phillips, slotted, torx). Acts as counterforce generating compression on the bone. Countersinking prevents prominence.',tc_s)], [pp('<b>SHAFT / SHANK</b>',tc_s),pp('Smooth portion between head and thread. Width (root diameter) determines fatigue resistance. Shank length affects where threads purchase in bone.',tc_s)], [pp('<b>THREAD</b>',tc_s),pp('<b>Root (core) diameter</b> — pull-out & fatigue resistance. <b>Thread (outside) diameter</b> — cancellous pull-out strength. <b>Pitch</b> — distance between threads. <b>Lead</b> — advance per revolution. <b>Design</b> — Buttress (ASIF) or V-thread.',tc_s)], [pp('<b>TIP</b>',tc_s),pp('<b>Round</b> — requires pre-tapping. <b>Self-tapping (fluted/trocar)</b> — cuts its own thread during insertion; convenient but slightly lower pull-out strength.',tc_s)]],[28*mm,142*mm])) S.append(sp(3)) S.append(ibox('<b>CLINICAL PEARL:</b> In soft (osteoporotic) bone, larger <i>thread diameter</i> improves pull-out resistance. In dense bone, wider <i>root diameter</i> resists fatigue failure.')) S+=[sp(3),secb('1.2 TYPES OF ORTHOPAEDIC SCREWS'),sp(2),screw_types_diagram(), cap('Figure 1.2 — Five major types of orthopaedic screws'),sp(2)] S.append(mktable([[pp('TYPE',th_s),pp('DESIGN FEATURES',th_s),pp('INDICATION & USE',th_s)], [pp('Machine Screws',tc_s),pp('Full-length thread; self-tapping cutting flute; drill hole size critical',tc_s),pp('General cortical bone; external fixation pins',tc_s)], [pp('Cortical Screws (ASIF)',tc_s),pp('Full-length thread; horizontal profile; hex/torx recess; self-tapping versions available',tc_s),pp('Diaphyseal fractures; positional or lag (over-drill near cortex for lag)',tc_s)], [pp('Cancellous Screws',tc_s),pp('Coarse larger threads; partially or fully threaded; malleolar screw has trephine tip',tc_s),pp('Metaphyseal/epiphyseal; osteoporotic bone; washers to prevent head pull-through',tc_s)], [pp('Self-tapping/drilling',tc_s),pp('Fluted/trocar tip cuts own threads; no pre-tapping; slightly lower pull-out',tc_s),pp('External fixation Schanz screws; quick intra-op insertion',tc_s)], [pp('Locking Screws',tc_s),pp('Threaded head locks into plate hole; precise predrilling; specialised screwdriver',tc_s),pp('Locking plate constructs; osteoporotic bone; periarticular fractures',tc_s)], [pp('Cannulated Screws',tc_s),pp('Hollow shaft accepts guidewire; multiple sizes',tc_s),pp('Femoral neck; scaphoid; percutaneous minimally-invasive fixation',tc_s)], [pp('Miniscrews',tc_s),pp('1.5–2.7 mm; Phillips or mini-hex head',tc_s),pp('Small fragments: phalanges, metacarpals, facial bones',tc_s)]],[32*mm,74*mm,64*mm])) S+=[sp(3),secb('1.3 PRINCIPLES OF SCREW INSERTION'),sp(2)] for term,desc in [('<b>Lag Screw Principle:</b>','Near cortex over-drilled (gliding hole) — thread purchases only in far fragment. Screw head tightening draws fragments together creating interfragmentary compression. Any screw crossing a fracture should be inserted with interfragmentary technique.'), ('<b>Positional / Neutralization Screw:</b>','Threads purchase in both cortices; no compression. Maintains reduction or attaches implant to bone. Combined with lag screws to neutralize deforming forces.'), ('<b>Compression angle:</b>','Screw bisects angle between perpendicular to fracture and perpendicular to long axis of bone — prevents fragment sliding during compression.'), ('<b>Pull-out strength:</b>','Determined by root area and bone density. Larger thread diameter in osteoporotic bone; washers increase load dispersion.'), ('<b>Cortex purchase:</b>','Generally 6–8 cortices on each side of fracture required for stable plate fixation. Bicortical preferred; unicortical locking acceptable near joints.')]: S+=[pp(f'{term} {desc}'),sp(2)] S+=[src("Campbell's Operative Orthopaedics 15th Ed 2026, Chapter 58"),PageBreak()] # CH 2 PLATES S+=[banner('CHAPTER 2: PLATES & PLATING PRINCIPLES',NAVY,WHITE,16,8),sp(3), secb('2.1 TENSION BAND PRINCIPLE (PAUWELS)'),sp(2), pp('<b>Pauwels</b> first defined and applied the tension band principle. A plate on the <b>tension (convex) side</b> converts tensile forces into compressive forces. If on compression side — it bends, fatigues, and fails.'),sp(2), tension_band_diagram(),cap('Figure 2.1 — Pauwels tension band principle'),sp(2), ibox('<b>KEY:</b> Always apply plate to the tension (convex) side of the bone.'),sp(3), secb("2.2 CAMPBELL'S CONCEPTS: PRINCIPLES OF PLATE FIXATION"),sp(2)] for pt in ['Plates <b>neutralize deforming forces</b> that cannot be counteracted by screws alone.', 'Plates may require <b>contouring</b> to maintain optimal fracture reduction.', 'Screw application <b>sequence</b> is critical — incorrect placement causes displacement and loss of reduction.', 'Usually <b>6–8 cortices</b> of purchase required on both sides of the fracture (except buttress plates).', 'Plates should be of <b>sufficient length</b> — larger bone and greater stress = longer plate.', 'Avoid <b>overtorquing</b> screws. Re-tighten all screws before wound closure (stress relaxation).']: S.append(bl(pt)) S+=[sp(2),src("Campbell's Operative Orthopaedics 15th Ed 2026 — Principles of Plate Fixation"),sp(3), secb("2.3 TYPES OF PLATES (Campbell's Table 58.11)"),sp(2), plate_diagram(),cap('Figure 2.2 — Five main categories of fixation plates'),sp(2)] S.append(mktable([[pp('PLATE TYPE',th_s),pp('INDICATION / BIOMECHANICAL ACTION',th_s),pp('TECHNIQUE NOTES',th_s)], [pp('Neutralization',tc_s),pp('With interfragmentary screw fixation. Neutralizes torsion, bending, shear. Common in butterfly/wedge fragments of humerus, radius, fibula.',tc_s),pp('Compression not applied through holes. Interfragmentary screw improves stability significantly.',tc_s)], [pp('Compression (DCP/LC-DCP)',tc_s),pp('Negates torsion/bending/shear. Creates compression via external tension device or self-compression oval holes. For type A shaft fractures.',tc_s),pp('LC-DCP has narrow contact area allowing circumferential callus regeneration.',tc_s)], [pp('Buttress',tc_s),pp('Negates compression & shear in metaphyseal-epiphyseal fractures (tibial plateau, pilon). Anchored to main stable fragment.',tc_s),pp('Correct contouring mandatory. Screws towards shoulder of hole closest to fracture.',tc_s)], [pp('Bridge',tc_s),pp('Spans comminuted fractures or bone defects. Relative stability for secondary bone healing.',tc_s),pp('Indirect reduction; preserves biology. Bone grafting often required.',tc_s)], [pp('Locking',tc_s),pp('Fixed-angle "single-beam" construct. Distributes load across all screw-bone interfaces. No plate-bone contact required.',tc_s),pp('Functions like internal external fixator. More expensive. For cases not amenable to conventional fixation.',tc_s)], [pp('Semitubular/tubular',tc_s),pp('Thin lightweight plate for smaller bones (fibula, forearm).',tc_s),pp('Not suitable for large bones. Common in fibula for ankle fractures.',tc_s)]],[28*mm,82*mm,60*mm])) S+=[sp(2),src("Campbell's Operative Orthopaedics 15th Ed 2026, Table 58.11"),PageBreak()] # CH 3 IM NAILS S+=[banner('CHAPTER 3: INTRAMEDULLARY NAILS',NAVY,WHITE,16,8),sp(3), secb('3.1 PRINCIPLES & DESIGN'),sp(2), pp('Closed <b>interlocking intramedullary (IM) nail</b> fixation is the procedure of choice for many long-bone fractures, especially in the lower extremity. Nails contact bone at multiple points for axial and rotational stability.'),sp(2), nail_diagram(),cap('Figure 3.1 — Intramedullary nail: static vs dynamic locking modes'),sp(2)] for pt in ['IM nails act as <b>internal splints</b> with minimal soft tissue damage.', '<b>Static locking:</b> both proximal and distal screws fixed — controls length and rotation.', '<b>Dynamic locking:</b> proximal in oval slot — controlled axial micromotion promotes callus formation.', '<b>Reaming:</b> increases canal for larger nail; stimulates periosteal blood supply. Ream to fit ("cortical chatter").', 'Use nail <b>1.0–1.5 mm smaller</b> than largest reamer. Never exceed canal diameter.', 'Excessive reaming weakens bone and risks thermal necrosis. Should not exceed half cortex size.', '<b>Entry portal:</b> femur — piriformis fossa or medial greater trochanter. Tibia — anterior to articular surface.']: S.append(bl(pt)) S+=[sp(3),secb('3.2 ADVANTAGES OVER PLATING (Campbell\'s Box 58.10)'),sp(2)] adv_rows=[[bl('Earlier weight bearing'),bl('Less fatigue failure vulnerability')],[bl('Acts as <b>load-sharing</b> device'),bl('Avoids stress shielding')],[bl('Less soft tissue dissection'),bl('Lower infection risk (open fractures)')],[bl('Near neutral axis (biomechanically ideal)'),bl('Faster rehabilitation')]] advt=Table(adv_rows,colWidths=[CW/2,CW/2]) advt.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),BONE),('GRID',(0,0),(-1,-1),0.5,LGRAY),('VALIGN',(0,0),(-1,-1),'TOP'),('TOPPADDING',(0,0),(-1,-1),4),('BOTTOMPADDING',(0,0),(-1,-1),4),('LEFTPADDING',(0,0),(-1,-1),6)])) S+=[advt,sp(2),src("Campbell's Operative Orthopaedics 15th Ed 2026, Box 58.10"),PageBreak()] # CH 4 EXTERNAL FIXATION S+=[banner('CHAPTER 4: EXTERNAL FIXATION',NAVY,WHITE,16,8),sp(3), secb('4.1 PRINCIPLES & TYPES'),sp(2), ext_fixator_diagram(),cap('Figure 4.1 — Monolateral external fixator (left) and Circular Ilizarov Frame (right)'),sp(2)] for name,desc in [('MONOLATERAL EXTERNAL FIXATOR','Unilateral frame: Schanz pins inserted through stab incisions, connected by an external bar. Simple, versatile. Standard for temporary stabilization in open fractures and damage control orthopaedics.'), ('BILATERAL/BIPLANAR FIXATOR','Pins in two planes — superior rotational control. Unstable pelvis fractures, some tibial fractures.'), ('CIRCULAR (ILIZAROV) FRAME','Full/half rings + threaded rods. Tensioned olive wires or half-pins through bone. <b>Tension-stress principle</b>: gradual distraction induces new bone (distraction osteogenesis). Used for limb lengthening, complex deformity correction, infected nonunions.'), ('TAYLOR SPATIAL FRAME (TSF)','Modified Ilizarov with six oblique telescoping struts. Computer software simultaneously corrects angular, translational, and rotational deformities.'), ('HYBRID FIXATORS','Tensioned wires in metaphyseal zone + half-pins in diaphysis. Good metaphyseal fixation with soft tissue tolerance.')]: S+=[h2(name),pp(desc),sp(2)] S+=[secb('4.2 INDICATIONS FOR EXTERNAL FIXATION'),sp(2)] for ind in ['Severe open fractures (Gustilo IIIB/IIIC) — temporary and definitive stabilization', 'Polytrauma — damage control orthopaedics (DCO)', 'Pelvic fractures — emergency stabilization for haemorrhage control', 'Limb lengthening and complex deformity correction (Ilizarov/TSF)', 'Infected nonunions — avoids internal implant in infected field', 'Periarticular fractures with extensive soft tissue injury']: S.append(bl(ind)) S+=[sp(2),src("Rockwood and Green's Fractures in Adults 10th Ed 2025, Chapter 31"),PageBreak()] # CH 5 LOCKING PLATES S+=[banner('CHAPTER 5: LOCKING PLATES',NAVY,WHITE,16,8),sp(3), secb('5.1 PRINCIPLE OF LOCKING PLATE FIXATION'),sp(2), locking_plate_diagram(),cap('Figure 5.1 — Conventional plate vs Locking plate: threaded screws lock into plate, creating fixed-angle construct'),sp(2), pp('Locking plates have screws with threads that <b>lock into threaded holes</b> on the plate — a <b>fixed-angle device</b> or "single-beam" construct where <i>no motion occurs between screws and plate.</i>'),sp(2)] for pt in ['<b>Fixed-angle construct:</b> Resists bending moments; load distributed across all screw-bone interfaces.', '<b>No plate-bone contact required:</b> Unlike compression plating. Functions like an <i>internal external fixator.</i>', '<b>Periosteal preservation:</b> Minimal microvascular compromise — promotes biological healing.', '<b>Healing pattern:</b> Without compression = <i>callus formation</i> (secondary bone healing), not direct osteonal bridging.', '<b>Osteoporosis:</b> Locking screws cannot toggle or back out — superior in osteoporotic bone.', '<b>Cost:</b> More expensive than conventional plates; reserved for cases not amenable to conventional fixation.']: S.append(bl(pt)) S+=[sp(3),secb('5.2 ANAN J. THAKUR — LOCKING PLATES & FRACTURE FIXATION PRINCIPLES'),sp(2)] for pt in ['Locking plates combine advantages of <b>internal and external fixation.</b>', 'Screw-plate interface strength <b>greater</b> than conventional plates — prevents back-out.', 'Fixed-angle design reduces <b>varus collapse</b> in osteoporotic proximal femur and humerus fractures.', 'Enables <b>MIPO (minimally invasive percutaneous plate osteosynthesis)</b> — preserves blood supply.', 'Relies on <b>secondary bone healing</b> via callus formation.', '<b>Unicortical locking screws</b> usable near articular surfaces to avoid joint penetration.', '<b>3D-printed patient-specific</b> locking plates for complex periarticular malunions.']: S.append(bl(pt)) S+=[sp(2),src('Anan J. Thakur — Locking Plates and Fracture Fixation; Rockwood & Green 10th Ed 2025'),PageBreak()] # CH 6 WIRES S+=[banner('CHAPTER 6: K-WIRES, TENSION BAND & CERCLAGE WIRES',NAVY,WHITE,16,8),sp(3), secb('6.1 KIRSCHNER WIRES (K-WIRES)'),sp(2), kw_diagram(),cap('Figure 6.1 — K-wire tip types and tension band wiring for patella fracture'),sp(2)] for pt in ['Smooth stainless steel wires; diameters 0.9–2.5 mm.', '<b>Tip types:</b> Trocar (three-facet, hard cortical bone) or Bayonet/diamond (angled insertion).', '<b>Uses:</b> temporary fracture reduction, tension band technique, external fixation, Ilizarov olive wires.', '<b>Disadvantages:</b> prone to migration, no rotational stability alone, pin-tract infection risk.']: S.append(bl(pt)) S+=[sp(3),secb('6.2 TENSION BAND WIRING TECHNIQUE'),sp(2), pp('Based on <b>Pauwels principle.</b> Two parallel K-wires + figure-of-8 wire loop. Active muscle contraction (quadriceps at patella, triceps at olecranon) converts <i>tensile forces</i> to <b>compressive forces</b> at the fracture.'),sp(3), secb('6.3 CERCLAGE WIRES'),sp(2), pp('Circumferential wires holding comminuted cortical fragments to the main cortical tube. Used in femoral shaft IM nailing (butterfly fragments), periprosthetic fractures. Provide hoop stress. Risk: devascularisation if applied without care.'), sp(2),src("Campbell's Operative Orthopaedics 15th Ed 2026"),PageBreak()] # CH 7 OTHER IMPLANTS S+=[banner('CHAPTER 7: OTHER ORTHOPAEDIC IMPLANTS',NAVY,WHITE,16,8),sp(3), secb('7.1 DYNAMIC HIP SCREW (DHS) & CEPHALOMEDULLARY DEVICES'),sp(2), dhs_diagram(),cap('Figure 7.1 — DHS: lag screw slides within barrel allowing controlled collapse into compression'),sp(2)] for name,desc in [('DYNAMIC HIP SCREW (DHS)','Lag screw in femoral head slides within barrel of side plate. <b>Controlled dynamic collapse</b>: weight converts shear to compressive forces at fracture site. Indicated for stable intertrochanteric fractures.'), ('GAMMA NAIL / PROXIMAL FEMORAL NAIL (PFN)','<b>Cephalomedullary nail</b>: IM nail + cephalic screw. Superior rotational control vs DHS. Indicated for reverse oblique, subtrochanteric, and high intertrochanteric fractures. Load-sharing device.'), ('CANNULATED HIP SCREWS','Three parallel cannulated screws in inverted triangle for undisplaced femoral neck fractures (Garden I-II). Percutaneous over guidewires under image intensifier.'), ('BLADE PLATE','Fixed-angle device: blade impacted into bone + plate along shaft. Subtrochanteric and supracondylar femur. Excellent rotational stability; technically demanding.'), ('TOTAL HIP ARTHROPLASTY (THA)','Femoral stem + acetabular cup. Cementless: <b>osseointegration</b> of porous/HA-coated surface. Cemented: PMMA bone cement. Bearings: metal-on-poly, ceramic-on-ceramic.'), ('TOTAL KNEE ARTHROPLASTY (TKA)','Femoral component + tibial tray + polyethylene insert ± patellar component. Constraint levels: unconstrained, PS, constrained condylar.'), ('BONE/SUTURE ANCHORS','Ti or bioabsorbable anchors inserted into bone for soft tissue reattachment (rotator cuff, labrum, ligament). Thread or expansion mechanism engages cancellous bone.'), ('ANTIBIOTIC CEMENT NAIL','Antibiotic-impregnated PMMA moulded around Steinmann pin/IM nail. Local antibiotic delivery + temporary mechanical stabilization for infected nonunions.')]: S+=[h2(name),pp(desc),sp(2)] S+=[src("Campbell's Operative Orthopaedics 15th Ed 2026; Rockwood & Green 10th Ed 2025"),PageBreak()] # CH 8 MATERIALS S+=[banner('CHAPTER 8: IMPLANT MATERIALS & BIOMECHANICS',NAVY,WHITE,16,8),sp(3), secb('8.1 IMPLANT MATERIALS'),sp(2)] S.append(mktable([[pp('MATERIAL',th_s),pp('PROPERTIES',th_s),pp('COMMON USES',th_s)], [pp('316L Stainless Steel',tc_s),pp('High strength; ductile; corrosion-resistant; ferromagnetic (MRI artefact)',tc_s),pp('DCP plates, IM nails, screws, K-wires',tc_s)], [pp('Titanium (Ti-6Al-4V)',tc_s),pp('Lower modulus (reduces stress shielding); MRI-compatible; corrosion-resistant; lighter',tc_s),pp('Locking plates, IM nails, arthroplasty stems, spinal cages',tc_s)], [pp('Cobalt-Chromium',tc_s),pp('Highest hardness/wear resistance; corrosion-resistant',tc_s),pp('Femoral heads (THA), knee arthroplasty bearing surfaces',tc_s)], [pp('UHMWPE',tc_s),pp('Excellent wear (especially cross-linked); low friction; not structural',tc_s),pp('Bearing surfaces in THA and TKA',tc_s)], [pp('Ceramic (alumina)',tc_s),pp('Very low wear; biocompatible; brittle; excellent hardness',tc_s),pp('Ceramic-on-ceramic THA heads and liners',tc_s)], [pp('PEEK',tc_s),pp('Radiolucent; low modulus; no MRI artefact',tc_s),pp('Spinal interbody cages; experimental fracture fixation',tc_s)], [pp('Bioabsorbable (PLA/PGA)',tc_s),pp('Degrades over time; avoids removal surgery; decreasing strength',tc_s),pp('Paediatric fractures, osteochondral fixation, ACL interference screws',tc_s)], [pp('PMMA bone cement',tc_s),pp('Self-polymerizing; mechanical interdigitation; exothermic',tc_s),pp('Cemented arthroplasty, vertebroplasty, antibiotic spacers',tc_s)]],[35*mm,90*mm,45*mm])) S+=[sp(3),secb('8.2 KEY BIOMECHANICAL CONCEPTS'),sp(2)] for term,desc in [('<b>Stress shielding:</b>','Stiff implant bears load normally through bone → bone resorbs (Wolff\'s law). Titanium\'s lower modulus reduces stress shielding vs stainless steel.'), ('<b>Load-sharing vs load-bearing:</b>','IM nails share load with bone. Plates bear load. Load-sharing is superior for weight-bearing long bones.'), ('<b>Neutral axis:</b>','Implant at neutral axis (IM nail) experiences minimal bending moments vs eccentrically placed plate.'), ('<b>Fatigue failure:</b>','Cyclic loading at stress risers (screw holes, curves) → crack propagation. LC-DCP offset holes minimise stress concentration.'), ('<b>Absolute vs relative stability:</b>','<b>Absolute</b> — interfragmentary compression → primary bone healing. <b>Relative</b> — splinting/bridging → secondary callus healing.')]: S+=[pp(f'{term} {desc}'),sp(2)] S+=[src("Campbell's Operative Orthopaedics 15th Ed 2026"),PageBreak()] # CH 9 METAL REMOVAL S+=[banner('CHAPTER 9: METAL REMOVAL — TIMING GUIDELINES',NAVY,WHITE,16,8),sp(3), pp('ASIF/AO guidelines for implant removal after uncomplicated fracture healing. Does NOT apply to pseudarthroses, post-infection cases, or major fragment fixation — those require individual assessment.'),sp(2)] S.append(mktable([[pp('BONE / FRACTURE TYPE',th_s),pp('RECOMMENDED REMOVAL TIME',th_s)], [pp('Malleolar fractures',tc_s),pp('8 - 12 months',tc_s)],[pp('Tibial pilon',tc_s),pp('12 - 18 months',tc_s)], [pp('Tibial shaft — plate',tc_s),pp('12 - 18 months',tc_s)],[pp('Tibial shaft — IM nail',tc_s),pp('18 - 24 months',tc_s)], [pp('Tibial plateau',tc_s),pp('12 - 18 months',tc_s)],[pp('Patella — tension band',tc_s),pp('8 - 12 months',tc_s)], [pp('Femoral condyles',tc_s),pp('12 - 24 months',tc_s)],[pp('Femoral shaft — single plate',tc_s),pp('24 - 36 months',tc_s)], [pp('Femoral shaft — double plates',tc_s),pp('From 18 months, two steps (6-month interval)',tc_s)], [pp('Femoral shaft — IM nail',tc_s),pp('24 - 36 months',tc_s)],[pp('Peritrochanteric / femoral neck',tc_s),pp('12 - 18 months',tc_s)], [pp('Pelvis (symptomatic only)',tc_s),pp('From 10 months',tc_s)],[pp('Upper extremity',tc_s),pp('12 - 18 months (generally optional)',tc_s)]],[100*mm,70*mm])) S+=[sp(3),ibox('<b>Note:</b> Timings are for uncomplicated healing in healthy patients. Upper extremity implant removal is generally optional unless symptomatic. Infections and nonunions require individual assessment.',LBLUE,info_s),sp(3), src("Campbell's Operative Orthopaedics 15th Ed 2026, Table 58.12"),sp(4)] ref_s2=PS('rf',fontSize=8,textColor=WHITE,fontName='Helvetica',alignment=TA_LEFT,leading=13) S.append(mktable([[pp('<b>REFERENCES:</b><br/>1. Canale ST, Beaty JH (eds). Campbell\'s Operative Orthopaedics, 15th Edition, 2026. Elsevier.<br/>2. Tornetta P et al. (eds). Rockwood and Green\'s Fractures in Adults, 10th Edition, 2025. Wolters Kluwer.<br/>3. Thakur AJ. Locking Plates and Fracture Fixation Principles.',ref_s2)]],[CW],NAVY)) doc.build(S) print(f'SUCCESS: {out}') PYEOF python3 /home/daytona/workspace/ortho-implants-pdf/create_pdf.py
Orthopaedic Implants Fracture Fixation
PDF Document · PDF
| Chapter | Content |
|---|---|
| 1 | Screws — parts (head, shank, thread, tip), 7 types, principles of insertion, lag vs positional |
| 2 | Plates — Pauwels tension band, 7 plate types (DCP, buttress, bridge, locking...) |
| 3 | Intramedullary Nails — design, static vs dynamic locking, reaming, advantages |
| 4 | External Fixation — monolateral, Ilizarov, TSF, indications |
| 5 | Locking Plates — fixed-angle principle, Thakur principles, MIPO |
| 6 | K-wires, Tension Band, Cerclage — tip types, figure-of-8 technique |
| 7 | Other Implants — DHS, gamma nail, THA, TKA, suture anchors |
| 8 | Materials & Biomechanics — titanium, Co-Cr, stress shielding, fatigue |
| 9 | Metal Removal Timing — ASIF guidelines by fracture/bone type |
I think ChatGPT is better than you. Your diagram is so bad.
python3 -c "import matplotlib; import matplotlib.pyplot as plt; import numpy as np; print('matplotlib OK', matplotlib.__version__)"
cat > /home/daytona/workspace/ortho-implants-pdf/make_diagrams.py << 'PYEOF' import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt import matplotlib.patches as mpatches from matplotlib.patches import FancyArrowPatch, FancyBboxPatch, Arc, Wedge, Circle, Rectangle, Polygon from matplotlib.lines import Line2D from matplotlib.path import Path import matplotlib.patheffects as pe import numpy as np import os OUT = '/home/daytona/workspace/ortho-implants-pdf/diagrams' os.makedirs(OUT, exist_ok=True) NAVY = '#1A2B4A' STEEL = '#2E5FA3' TEAL = '#0C7B93' BONE = '#F5ECD7' METAL = '#8FA3B1' LGRAY = '#D0D8E4' RED = '#C0392B' GREEN = '#27AE60' ORANGE= '#E67E22' GOLD = '#C8A951' WHITE = '#FFFFFF' PURPLE= '#6C5CE7' BG = '#F0F4F8' def savefig(name, fig): p = f'{OUT}/{name}.png' fig.savefig(p, dpi=150, bbox_inches='tight', facecolor=fig.get_facecolor()) plt.close(fig) print(f' saved {name}.png') # ─── FIG 1: SCREW ANATOMY ───────────────────────────────────────────────────── def fig_screw_anatomy(): fig, ax = plt.subplots(figsize=(12, 5), facecolor=BG) ax.set_facecolor(BG) ax.set_xlim(0, 12); ax.set_ylim(0, 5) ax.axis('off') ax.set_title('ANATOMY OF AN ORTHOPAEDIC BONE SCREW', fontsize=14, fontweight='bold', color=NAVY, pad=12) # ── screw head ── head = FancyBboxPatch((0.3, 1.8), 1.2, 1.4, boxstyle='round,pad=0.05', fc=METAL, ec=NAVY, lw=1.5) ax.add_patch(head) # hex recess lines on head for x in [0.7, 0.9, 1.1, 1.3]: ax.plot([x, x], [2.0, 3.0], color=NAVY, lw=1, alpha=0.6) # head label ax.annotate('HEAD\n(hex recess\nfor screwdriver)', xy=(0.9, 1.8), xytext=(0.2, 0.7), fontsize=8, color=NAVY, fontweight='bold', ha='center', arrowprops=dict(arrowstyle='->', color=NAVY, lw=1.2), bbox=dict(boxstyle='round,pad=0.3', fc='white', ec=NAVY, lw=0.8)) # ── shank (smooth) ── shank = Rectangle((1.5, 2.1), 1.0, 0.8, fc=METAL, ec=NAVY, lw=1.2) ax.add_patch(shank) ax.annotate('SHANK\n(smooth portion)', xy=(2.0, 2.1), xytext=(1.8, 0.7), fontsize=8, color=STEEL, fontweight='bold', ha='center', arrowprops=dict(arrowstyle='->', color=STEEL, lw=1.2), bbox=dict(boxstyle='round,pad=0.3', fc='white', ec=STEEL, lw=0.8)) # ── threaded portion ── thread_start = 2.5; thread_end = 10.2 # core shaft core = Rectangle((thread_start, 2.2), thread_end - thread_start, 0.6, fc=METAL, ec=None) ax.add_patch(core) # thread teeth (triangles top + bottom) pitch = 0.32 x = thread_start while x < thread_end - pitch: # top tooth tx = [x, x + pitch/2, x + pitch] ty_top = [2.8, 3.15, 2.8] ax.fill(tx, ty_top, color=METAL) ax.plot(tx, ty_top, color=NAVY, lw=0.6) # bottom tooth ty_bot = [2.2, 1.85, 2.2] ax.fill(tx, ty_bot, color=METAL) ax.plot(tx, ty_bot, color=NAVY, lw=0.6) x += pitch ax.annotate('THREADED PORTION', xy=(6.5, 3.15), xytext=(6.5, 4.2), fontsize=8, color=TEAL, fontweight='bold', ha='center', arrowprops=dict(arrowstyle='->', color=TEAL, lw=1.2), bbox=dict(boxstyle='round,pad=0.3', fc='white', ec=TEAL, lw=0.8)) # ── tip ── tip_xs = [10.2, 10.2, 11.0] tip_ys = [2.8, 2.2, 2.5] ax.fill(tip_xs, tip_ys, color=METAL) ax.plot(tip_xs + [tip_xs[0]], tip_ys + [tip_ys[0]], color=NAVY, lw=1.2) ax.annotate('TIP\n(self-tapping\nfluted/trocar)', xy=(10.5, 2.5), xytext=(10.9, 0.7), fontsize=8, color=RED, fontweight='bold', ha='center', arrowprops=dict(arrowstyle='->', color=RED, lw=1.2), bbox=dict(boxstyle='round,pad=0.3', fc='white', ec=RED, lw=0.8)) # ── dimension annotations ── # Pitch bracket px1, px2 = 4.5, 4.5 + pitch ax.annotate('', xy=(px2, 1.5), xytext=(px1, 1.5), arrowprops=dict(arrowstyle='<->', color=GREEN, lw=1.5)) ax.text((px1+px2)/2, 1.35, 'Pitch', fontsize=8, color=GREEN, fontweight='bold', ha='center') # Thread diameter ax.annotate('', xy=(7.5, 3.15), xytext=(7.5, 1.85), arrowprops=dict(arrowstyle='<->', color=ORANGE, lw=1.5)) ax.text(7.8, 2.5, 'Thread\nDiam.', fontsize=7.5, color=ORANGE, fontweight='bold') # Root diameter ax.annotate('', xy=(8.5, 2.8), xytext=(8.5, 2.2), arrowprops=dict(arrowstyle='<->', color=RED, lw=1.5)) ax.text(8.7, 2.5, 'Root\nDiam.', fontsize=7.5, color=RED, fontweight='bold') fig.tight_layout() return fig savefig('01_screw_anatomy', fig_screw_anatomy()) # ─── FIG 2: SCREW TYPES ─────────────────────────────────────────────────────── def draw_screw(ax, cx, top_y, height, pitch, color, name, desc, cannulated=False, locking=False, self_tap=False): hw = 0.22 # half-width of thread region cw = 0.18 # half-width of core head_h = 0.35 # Head head = FancyBboxPatch((cx - hw - 0.05, top_y + height), hw*2 + 0.10, head_h, boxstyle='round,pad=0.02', fc=color, ec=NAVY, lw=1.2) ax.add_patch(head) # hex lines on head if locking: # threaded head indicator (rings) for dy in [0.07, 0.17, 0.27]: ax.plot([cx - hw, cx + hw], [top_y + height + dy, top_y + height + dy], color=NAVY, lw=0.8, alpha=0.7) else: for dx in [-0.06, 0, 0.06]: ax.plot([cx+dx, cx+dx], [top_y+height+0.05, top_y+height+head_h-0.05], color=NAVY, lw=0.7, alpha=0.6) # Core shaft core = Rectangle((cx - cw, top_y), cw*2, height, fc=color, ec=None, alpha=0.9) ax.add_patch(core) # Thread teeth y = top_y while y < top_y + height - pitch: # top tooth outline ax.fill([cx-cw, cx-hw, cx-cw], [y, y+pitch/2, y+pitch], color=color, alpha=0.95) ax.plot([cx-cw, cx-hw, cx-cw], [y, y+pitch/2, y+pitch], color=NAVY, lw=0.5) ax.fill([cx+cw, cx+hw, cx+cw], [y, y+pitch/2, y+pitch], color=color, alpha=0.95) ax.plot([cx+cw, cx+hw, cx+cw], [y, y+pitch/2, y+pitch], color=NAVY, lw=0.5) y += pitch # Cannulated hollow if cannulated: hollow = Rectangle((cx - cw/2.5, top_y), cw/1.25, height, fc='white', ec=None, zorder=5) ax.add_patch(hollow) # Tip if self_tap: # pointed/fluted tip ax.fill([cx-cw, cx, cx+cw], [top_y, top_y - 0.25, top_y], color=color, zorder=4) ax.plot([cx-cw, cx, cx+cw, cx-cw], [top_y, top_y-0.25, top_y, top_y], color=NAVY, lw=0.7) ax.plot([cx, cx], [top_y, top_y-0.25], color=NAVY, lw=0.5, ls='--', alpha=0.5) else: ax.fill([cx-cw, cx, cx+cw], [top_y, top_y - 0.18, top_y], color=color, zorder=4) ax.plot([cx-cw, cx, cx+cw, cx-cw], [top_y, top_y-0.18, top_y, top_y], color=NAVY, lw=0.7) # Name ax.text(cx, top_y + height + head_h + 0.15, name, ha='center', va='bottom', fontsize=7.5, fontweight='bold', color=NAVY) # Description for i, line in enumerate(desc.split('\n')): ax.text(cx, top_y - 0.5 - i*0.18, line, ha='center', va='top', fontsize=6.5, color='#555555') def fig_screw_types(): fig, ax = plt.subplots(figsize=(13, 6.5), facecolor=BG) ax.set_facecolor(BG) ax.set_xlim(0, 13); ax.set_ylim(-1.2, 6.5) ax.axis('off') ax.set_title('TYPES OF ORTHOPAEDIC SCREWS', fontsize=14, fontweight='bold', color=NAVY, pad=12) types = [ (1.1, 3.5, 0.18, STEEL, 'CORTICAL\n(ASIF)', 'Fine thread\nFull length\nSmall pitch\nDiaphyseal use', False, False, False), (3.2, 3.5, 0.28, TEAL, 'CANCELLOUS', 'Coarse thread\nLarge pitch\nMetaphyseal\nPartial/full thread', False, False, False), (5.3, 3.5, 0.18, RED, 'LOCKING', 'Threaded head\nLocks into plate\nFixed-angle\nOsteoporotic bone',False, True, False), (7.4, 3.5, 0.18, ORANGE, 'CANNULATED', 'Hollow shaft\nOver guidewire\nPercutaneous\nFemoral neck/scaphoid',True, False, False), (9.5, 3.5, 0.18, GREEN, 'SELF-TAPPING', 'Fluted tip\nNo pre-tapping\nExt. fixation pins\nQuick insertion', False, False, True), (11.6, 3.5, 0.18, PURPLE, 'MALLEOLAR\n(Cancellous)', 'Trephine tip\n4.5 mm\nSelf-tapping\nAnkle fractures', False, False, True), ] for cx, h, pitch, col, name, desc, cann, lock, st in types: draw_screw(ax, cx, 1.2, h, pitch, col, name, desc, cann, lock, st) # legend box legend_items = [ mpatches.Patch(color=STEEL, label='Cortical (ASIF)'), mpatches.Patch(color=TEAL, label='Cancellous'), mpatches.Patch(color=RED, label='Locking'), mpatches.Patch(color=ORANGE, label='Cannulated'), mpatches.Patch(color=GREEN, label='Self-tapping'), mpatches.Patch(color=PURPLE, label='Malleolar'), ] ax.legend(handles=legend_items, loc='upper right', fontsize=7.5, framealpha=0.9, edgecolor=NAVY, ncol=2) fig.tight_layout() return fig savefig('02_screw_types', fig_screw_types()) # ─── FIG 3: PLATE TYPES ─────────────────────────────────────────────────────── def fig_plate_types(): fig, axes = plt.subplots(1, 5, figsize=(15, 6), facecolor=BG) fig.patch.set_facecolor(BG) fig.suptitle('TYPES OF FRACTURE FIXATION PLATES', fontsize=14, fontweight='bold', color=NAVY, y=1.0) configs = [ ('NEUTRALIZATION', STEEL, [(0.5,0.1),(0.5,0.3),(0.5,0.5),(0.5,0.7),(0.5,0.9)], 'neutralization', 'Neutralizes\ntorsion, bending\n& shear forces\nWith interfrag.\nscrew fixation'), ('COMPRESSION\n(DCP)', TEAL, [(0.5,0.1),(0.5,0.3),(0.5,0.5),(0.5,0.7),(0.5,0.9)], 'compression', 'Axial compression\nvia oval holes\nFor transverse &\nshort oblique\nfractures'), ('BUTTRESS', NAVY, [(0.5,0.1),(0.5,0.3),(0.5,0.5),(0.5,0.7),(0.5,0.9)], 'buttress', 'Prevents axial\ndeformation\nMetaphyseal-\nepiphyseal\nfractures'), ('BRIDGE', '#6C5CE7', [(0.5,0.1),(0.5,0.3),(0.5,0.5),(0.5,0.7),(0.5,0.9)], 'bridge', 'Spans comminuted\nfragments\nRelative stability\nSecondary bone\nhealing'), ('LOCKING', RED, [(0.5,0.1),(0.5,0.3),(0.5,0.5),(0.5,0.7),(0.5,0.9)], 'locking', 'Fixed-angle\nconstruct\nNo plate-bone\ncontact needed\nOsteoporotic bone'), ] for ax, (title, col, holes, ptype, desc) in zip(axes, configs): ax.set_facecolor(BG) ax.set_xlim(0, 1); ax.set_ylim(-0.4, 1.3) ax.axis('off') ax.set_title(title, fontsize=9, fontweight='bold', color=col, pad=6) # Bone (background) bone_rect = FancyBboxPatch((0.25, 0.0), 0.5, 1.0, boxstyle='round,pad=0.04', fc=BONE, ec='#8B7355', lw=1.5) ax.add_patch(bone_rect) # Fracture line (except bridge which has comminution) if ptype == 'bridge': for yf in [0.38, 0.45, 0.52]: ax.plot([0.25, 0.75], [yf, yf+0.03], color=RED, lw=1.2, alpha=0.7) else: ax.plot([0.23, 0.77], [0.48, 0.50], color=RED, lw=2) # Plate plate = FancyBboxPatch((0.58, 0.05), 0.14, 0.90, boxstyle='round,pad=0.02', fc=col, ec=NAVY, lw=1.2, alpha=0.92) ax.add_patch(plate) # Screw holes on plate for hx, hy in holes: # hole in plate hole_x = 0.58 + 0.07 c = Circle((hole_x, hy), 0.04, fc='white', ec=NAVY, lw=0.8, zorder=5) ax.add_patch(c) if ptype == 'locking': # threaded ring c2 = Circle((hole_x, hy), 0.025, fc=LGRAY, ec=NAVY, lw=0.6, zorder=6) ax.add_patch(c2) elif ptype == 'compression': # oval hole e = mpatches.Ellipse((hole_x, hy), 0.05, 0.09, fc='white', ec=NAVY, lw=0.8, zorder=5) ax.add_patch(e) # screw shaft going into bone ax.plot([0.25, hole_x - 0.04], [hy, hy], color=METAL, lw=3, solid_capstyle='round', zorder=4) # Description text ax.text(0.5, -0.08, desc, ha='center', va='top', fontsize=6.5, color=DGRAY if False else '#333333', linespacing=1.4) fig.tight_layout(pad=1.5) return fig DGRAY = '#333333' savefig('03_plate_types', fig_plate_types()) # ─── FIG 4: TENSION BAND PRINCIPLE ─────────────────────────────────────────── def fig_tension_band(): fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(11, 6), facecolor=BG) fig.patch.set_facecolor(BG) fig.suptitle('TENSION BAND PRINCIPLE (PAUWELS)', fontsize=14, fontweight='bold', color=NAVY) for ax, has_plate, title, subtitle in [ (ax1, False, 'WITHOUT PLATE', 'Tensile forces open fracture gap\non convex (tension) side'), (ax2, True, 'WITH TENSION BAND PLATE', 'Plate on tension side converts\ntension → compression') ]: ax.set_facecolor(BG) ax.set_xlim(-1, 3); ax.set_ylim(-0.5, 7) ax.axis('off') ax.set_title(title, fontsize=11, fontweight='bold', color=NAVY, pad=8) ax.text(1.0, 6.5, subtitle, ha='center', fontsize=8, color='#444444', style='italic') # Bone — slightly bent/curved to show eccentric loading bone_x = [0.4, 0.5, 0.55, 0.5, 0.45, 0.4, 0.35, 0.3, 0.35, 0.4] bone_y = np.linspace(0.5, 5.5, len(bone_x)) # simple rectangle representing bone bx, bw, by, bh = 0.3, 0.7, 0.5, 5.0 bone = FancyBboxPatch((bx, by), bw, bh, boxstyle='round,pad=0.08', fc=BONE, ec='#8B7355', lw=2) ax.add_patch(bone) # Fracture line fy = 2.8 if has_plate: ax.plot([bx-0.05, bx+bw+0.05], [fy, fy+0.05], color=RED, lw=2.5) else: # gap on tension side (right/convex) ax.plot([bx+bw*0.3, bx+bw+0.1], [fy, fy-0.15], color=RED, lw=2.5) ax.plot([bx-0.05, bx+bw*0.3], [fy, fy], color=RED, lw=2.5) # Load arrow from top ax.annotate('', xy=(bx+bw/2, by+bh), xytext=(bx+bw/2, by+bh+0.8), arrowprops=dict(arrowstyle='->', color=NAVY, lw=2.5)) ax.text(bx+bw/2, by+bh+0.9, 'LOAD', ha='center', fontsize=9, fontweight='bold', color=NAVY) if has_plate: # Plate on tension (right) side plate = FancyBboxPatch((bx+bw+0.05, by+0.3), 0.15, bh-0.6, boxstyle='round,pad=0.02', fc=STEEL, ec=NAVY, lw=1.5) ax.add_patch(plate) # Screws for sy in [by+0.7, by+1.3, by+bh-1.3, by+bh-0.7]: ax.plot([bx+0.1, bx+bw+0.2], [sy, sy], color=METAL, lw=3, solid_capstyle='round', zorder=5) # Compression arrows at fracture ax.annotate('', xy=(bx+bw/2, fy+0.25), xytext=(bx+bw/2, fy+0.6), arrowprops=dict(arrowstyle='->', color=GREEN, lw=2)) ax.annotate('', xy=(bx+bw/2, fy-0.25), xytext=(bx+bw/2, fy-0.6), arrowprops=dict(arrowstyle='->', color=GREEN, lw=2)) ax.text(bx+bw/2+0.5, fy, 'COMPRESSION\n(converted)', ha='left', fontsize=8, fontweight='bold', color=GREEN, va='center') ax.text(bx+bw+0.13, by+bh/2, 'Tension\nband\nplate', ha='center', fontsize=7, color='white', va='center', fontweight='bold') else: # Tension arrows (opening gap) ax.annotate('', xy=(bx+bw+0.3, fy+0.3), xytext=(bx+bw+0.05, fy+0.05), arrowprops=dict(arrowstyle='->', color=RED, lw=2)) ax.annotate('', xy=(bx+bw+0.3, fy-0.3), xytext=(bx+bw+0.05, fy-0.05), arrowprops=dict(arrowstyle='->', color=RED, lw=2)) ax.text(bx+bw+0.35, fy, 'TENSION\n(gap opens)', ha='left', fontsize=8, fontweight='bold', color=RED, va='center') # Compression side label ax.text(bx-0.2, by+bh/2, 'Compression\nside\n(concave)', ha='right', fontsize=7.5, color='#555555', va='center', style='italic') ax.text(bx+bw+0.08 if not has_plate else bx+bw+0.5, by+0.3, 'Tension\nside\n(convex)', ha='left', fontsize=7.5, color='#555555', va='bottom', style='italic') fig.tight_layout(pad=2) return fig savefig('04_tension_band', fig_tension_band()) # ─── FIG 5: IM NAIL ────────────────────────────────────────────────────────── def fig_im_nail(): fig, axes = plt.subplots(1, 2, figsize=(11, 7), facecolor=BG) fig.patch.set_facecolor(BG) fig.suptitle('INTRAMEDULLARY NAIL — STATIC vs DYNAMIC LOCKING', fontsize=14, fontweight='bold', color=NAVY) for ax, is_static, label, sub in [ (axes[0], True, 'STATIC LOCKING', 'Both proximal & distal screws\nin fixed holes — controls length & rotation'), (axes[1], False, 'DYNAMIC LOCKING', 'Proximal screws in oval slots —\nallows controlled axial micromotion'), ]: ax.set_facecolor(BG) ax.set_xlim(-1.5, 4); ax.set_ylim(-0.5, 9) ax.axis('off') ax.set_title(label, fontsize=12, fontweight='bold', color=NAVY, pad=8) ax.text(1.25, 8.5, sub, ha='center', fontsize=8, color='#444444', style='italic') # Femur outline (simplified) # Shaft shaft = FancyBboxPatch((0.5, 0.5), 1.5, 7.0, boxstyle='round,pad=0.15', fc=BONE, ec='#8B7355', lw=2) ax.add_patch(shaft) # Medullary canal canal = FancyBboxPatch((0.9, 0.7), 0.7, 6.6, boxstyle='round,pad=0.05', fc='#FDF6E3', ec=LGRAY, lw=0.8) ax.add_patch(canal) # IM nail nail = FancyBboxPatch((1.02, 0.6), 0.46, 6.8, boxstyle='round,pad=0.02', fc=METAL, ec=NAVY, lw=1.5, alpha=0.95) ax.add_patch(nail) # Proximal screws (top) prox_y = 6.8 if is_static: ax.plot([-0.3, 2.8], [prox_y, prox_y], color=STEEL, lw=5, solid_capstyle='round', zorder=6) ax.plot([-0.3, 2.8], [prox_y, prox_y], color=NAVY, lw=1.2, zorder=7) # hole in nail c = Circle((1.25, prox_y), 0.1, fc='#FDF6E3', ec=NAVY, lw=1, zorder=8) ax.add_patch(c) ax.text(3.0, prox_y, 'Proximal\nscrew\n(fixed)', fontsize=8, va='center', color=STEEL, fontweight='bold') else: # oval slot in nail slot = mpatches.Ellipse((1.25, prox_y), 0.12, 0.35, fc='#FDF6E3', ec=NAVY, lw=1.2, zorder=8) ax.add_patch(slot) ax.plot([-0.3, 2.8], [prox_y, prox_y], color=ORANGE, lw=5, solid_capstyle='round', zorder=6) ax.plot([-0.3, 2.8], [prox_y, prox_y], color='#B7531A', lw=1.2, zorder=7) ax.text(3.0, prox_y, 'Proximal\nscrew in\nOVAL SLOT\n(dynamic)', fontsize=8, va='center', color=ORANGE, fontweight='bold') # arrow showing allowed motion ax.annotate('', xy=(1.25, prox_y-0.45), xytext=(1.25, prox_y+0.45), arrowprops=dict(arrowstyle='<->', color=ORANGE, lw=1.5)) # Second proximal screw (offset) prox_y2 = 6.0 ax.plot([-0.3, 2.8], [prox_y2, prox_y2], color=STEEL, lw=5, solid_capstyle='round', zorder=6) ax.plot([-0.3, 2.8], [prox_y2, prox_y2], color=NAVY, lw=1.2, zorder=7) c2 = Circle((1.25, prox_y2), 0.1, fc='#FDF6E3', ec=NAVY, lw=1, zorder=8) ax.add_patch(c2) # Distal screws dist_y = 1.5 ax.plot([-0.3, 2.8], [dist_y, dist_y], color=STEEL, lw=5, solid_capstyle='round', zorder=6) ax.plot([-0.3, 2.8], [dist_y, dist_y], color=NAVY, lw=1.2, zorder=7) c3 = Circle((1.25, dist_y), 0.1, fc='#FDF6E3', ec=NAVY, lw=1, zorder=8) ax.add_patch(c3) ax.text(3.0, dist_y, 'Distal\nscrew\n(fixed)', fontsize=8, va='center', color=STEEL, fontweight='bold') dist_y2 = 0.9 ax.plot([-0.3, 2.8], [dist_y2, dist_y2], color=STEEL, lw=5, solid_capstyle='round', zorder=6) ax.plot([-0.3, 2.8], [dist_y2, dist_y2], color=NAVY, lw=1.2, zorder=7) c4 = Circle((1.25, dist_y2), 0.1, fc='#FDF6E3', ec=NAVY, lw=1, zorder=8) ax.add_patch(c4) # Fracture line ax.plot([0.45, 2.05], [3.9, 4.0], color=RED, lw=2.5, zorder=9) # Labels ax.text(-0.5, dist_y+0.35, 'Distal', fontsize=8, ha='right', color='#555') ax.text(-0.5, prox_y-0.15, 'Proximal', fontsize=8, ha='right', color='#555') fig.tight_layout(pad=2) return fig savefig('05_im_nail', fig_im_nail()) # ─── FIG 6: EXTERNAL FIXATOR ───────────────────────────────────────────────── def fig_ext_fixator(): fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 6.5), facecolor=BG) fig.patch.set_facecolor(BG) fig.suptitle('EXTERNAL FIXATION — TYPES & COMPONENTS', fontsize=14, fontweight='bold', color=NAVY) # ── Monolateral ── ax1.set_facecolor(BG); ax1.set_xlim(-3, 5); ax1.set_ylim(-0.5, 8); ax1.axis('off') ax1.set_title('MONOLATERAL EXTERNAL FIXATOR', fontsize=10, fontweight='bold', color=STEEL) # Bone (tibia) bone = FancyBboxPatch((0.5, 0.3), 1.2, 7.0, boxstyle='round,pad=0.1', fc=BONE, ec='#8B7355', lw=2) ax1.add_patch(bone) # Fracture ax1.plot([0.45, 1.75], [3.3, 3.5], color=RED, lw=2.5) # Schanz pins (4) for py in [1.0, 2.0, 5.0, 6.0]: ax1.plot([-1.5, 3.5], [py, py], color=STEEL, lw=4, solid_capstyle='round', zorder=5) ax1.plot([-1.5, 3.5], [py, py], color=NAVY, lw=0.8, zorder=6) # screw tip detail ax1.scatter([3.5], [py], c=STEEL, s=60, zorder=7) ax1.scatter([-1.5], [py], c=STEEL, s=60, zorder=7) # Connecting bar bar = FancyBboxPatch((-2.2, 0.5), 0.5, 6.0, boxstyle='round,pad=0.05', fc=METAL, ec=NAVY, lw=1.5) ax1.add_patch(bar) # Clamps for cy in [1.0, 2.0, 5.0, 6.0]: clamp = FancyBboxPatch((-2.15, cy-0.2), 0.8, 0.4, boxstyle='round,pad=0.04', fc=GOLD, ec=NAVY, lw=1, zorder=7) ax1.add_patch(clamp) # Labels with arrows ax1.annotate('Schanz pin\n(half-pin)', xy=(2.0, 5.0), xytext=(3.8, 5.8), fontsize=8, color=STEEL, fontweight='bold', arrowprops=dict(arrowstyle='->', color=STEEL, lw=1.2), bbox=dict(boxstyle='round,pad=0.3', fc='white', ec=STEEL, lw=0.8)) ax1.annotate('Connecting\nbar', xy=(-1.9, 3.5), xytext=(-2.8, 5.0), fontsize=8, color=METAL, fontweight='bold', arrowprops=dict(arrowstyle='->', color=METAL, lw=1.2), bbox=dict(boxstyle='round,pad=0.3', fc='white', ec=METAL, lw=0.8)) ax1.annotate('Clamp', xy=(-1.8, 1.0), xytext=(-2.8, 1.8), fontsize=8, color=GOLD, fontweight='bold', arrowprops=dict(arrowstyle='->', color=GOLD, lw=1.2), bbox=dict(boxstyle='round,pad=0.3', fc='white', ec=GOLD, lw=0.8)) ax1.annotate('Fracture\nsite', xy=(1.1, 3.4), xytext=(2.5, 2.2), fontsize=8, color=RED, fontweight='bold', arrowprops=dict(arrowstyle='->', color=RED, lw=1.2), bbox=dict(boxstyle='round,pad=0.3', fc='white', ec=RED, lw=0.8)) # ── Ilizarov ring fixator ── ax2.set_facecolor(BG); ax2.set_xlim(-4, 4); ax2.set_ylim(-0.5, 8); ax2.axis('off') ax2.set_title('CIRCULAR (ILIZAROV) FRAME', fontsize=10, fontweight='bold', color=TEAL) # Bone bone2 = FancyBboxPatch((-0.5, 0.3), 1.0, 7.0, boxstyle='round,pad=0.08', fc=BONE, ec='#8B7355', lw=2) ax2.add_patch(bone2) # Rings (viewed as ellipses in perspective) ring_ys = [1.5, 3.0, 5.0, 6.5] ring_r = 2.8 for ry in ring_ys: ring = mpatches.Ellipse((0, ry), ring_r*2, ring_r*0.4, fc='none', ec=METAL, lw=6, alpha=0.85) ax2.add_patch(ring) # Connecting rods (threaded) for rx in [-ring_r*0.85, ring_r*0.85]: ax2.plot([rx, rx], [ring_ys[0], ring_ys[-1]], color=STEEL, lw=3, zorder=4) # thread marks for y in np.arange(ring_ys[0], ring_ys[-1], 0.25): ax2.plot([rx-0.12, rx+0.12], [y, y], color=NAVY, lw=0.8, alpha=0.6) # Tensioned olive wires wire_ys = [1.5, 3.0, 5.0, 6.5] for wy in wire_ys: ax2.plot([-ring_r*0.85, ring_r*0.85], [wy, wy], color=ORANGE, lw=1.8, zorder=6, solid_capstyle='round') # olive beads ax2.scatter([-ring_r*0.65, ring_r*0.65], [wy, wy], c=ORANGE, s=40, zorder=7) # Labels ax2.annotate('Full ring\n(stainless steel)', xy=(ring_r*0.7, 5.0), xytext=(ring_r*1.1+0.2, 5.8), fontsize=8, color=METAL, fontweight='bold', arrowprops=dict(arrowstyle='->', color=METAL, lw=1.2), bbox=dict(boxstyle='round,pad=0.3', fc='white', ec=METAL, lw=0.8)) ax2.annotate('Tensioned\nolive wire', xy=(ring_r*0.5, 3.0), xytext=(ring_r*1.1+0.2, 3.5), fontsize=8, color=ORANGE, fontweight='bold', arrowprops=dict(arrowstyle='->', color=ORANGE, lw=1.2), bbox=dict(boxstyle='round,pad=0.3', fc='white', ec=ORANGE, lw=0.8)) ax2.annotate('Threaded\nconnecting rod', xy=(ring_r*0.85, 4.2), xytext=(ring_r*1.1+0.2, 2.2), fontsize=8, color=STEEL, fontweight='bold', arrowprops=dict(arrowstyle='->', color=STEEL, lw=1.2), bbox=dict(boxstyle='round,pad=0.3', fc='white', ec=STEEL, lw=0.8)) fig.tight_layout(pad=2) return fig savefig('06_ext_fixator', fig_ext_fixator()) # ─── FIG 7: LOCKING vs CONVENTIONAL PLATE ──────────────────────────────────── def fig_locking_plate(): fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(11, 6.5), facecolor=BG) fig.patch.set_facecolor(BG) fig.suptitle('CONVENTIONAL PLATE vs LOCKING PLATE CONSTRUCT', fontsize=13, fontweight='bold', color=NAVY) for ax, is_locking, col, title, sub in [ (ax1, False, STEEL, 'CONVENTIONAL PLATE', 'Friction between plate & bone\nCompression plating\nDirect bone healing (osteonal)'), (ax2, True, TEAL, 'LOCKING PLATE', 'Fixed-angle "single-beam" construct\nNo plate-bone contact needed\nCallus (secondary) bone healing'), ]: ax.set_facecolor(BG); ax.set_xlim(-1, 5); ax.set_ylim(-1, 8); ax.axis('off') ax.set_title(title, fontsize=11, fontweight='bold', color=col, pad=8) ax.text(2.0, 7.4, sub, ha='center', fontsize=8, color='#444', style='italic', linespacing=1.5) # Bone bone = FancyBboxPatch((0.3, 0.3), 2.0, 6.5, boxstyle='round,pad=0.12', fc=BONE, ec='#8B7355', lw=2) ax.add_patch(bone) # Fracture line ax.plot([0.25, 2.35], [3.2, 3.35], color=RED, lw=2.5, zorder=8) # Plate if is_locking: # plate does NOT touch bone (small gap) plate = FancyBboxPatch((2.35, 0.5), 0.55, 6.1, boxstyle='round,pad=0.03', fc=col, ec=NAVY, lw=1.5) ax.add_patch(plate) # gap indicator ax.annotate('', xy=(2.33, 3.5), xytext=(2.38, 3.5), arrowprops=dict(arrowstyle='<->', color=GREEN, lw=1.5)) ax.text(2.42, 3.7, 'No contact\n(gap = OK!)', fontsize=7.5, color=GREEN, fontweight='bold') else: # plate touches bone plate = FancyBboxPatch((2.3, 0.5), 0.55, 6.1, boxstyle='round,pad=0.03', fc=col, ec=NAVY, lw=1.5) ax.add_patch(plate) # contact pressure marks for cy in np.arange(0.8, 6.5, 0.4): ax.plot([2.3, 2.32], [cy, cy], color=NAVY, lw=1, alpha=0.4) ax.text(2.0, 0.1, 'Plate contacts bone\n(friction-based stability)', fontsize=7.5, ha='center', color=NAVY, style='italic') # Screws screw_ys = [1.0, 2.0, 4.5, 5.5, 6.2] for sy in screw_ys: # screw shaft in bone ax.plot([0.2, 2.5], [sy, sy], color=METAL, lw=4, solid_capstyle='round', zorder=5) ax.plot([0.2, 2.5], [sy, sy], color='#5A6A7A', lw=0.8, zorder=6) if is_locking: # threaded head locks into plate hole head = Circle((2.62, sy), 0.14, fc=col, ec=NAVY, lw=1.5, zorder=7) ax.add_patch(head) # thread rings on head for dr in [0.06, 0.10]: ring = Circle((2.62, sy), dr, fc='none', ec=NAVY, lw=0.6, zorder=8) ax.add_patch(ring) # lock symbol: small bolt icon ax.text(2.62, sy, '⚙', ha='center', va='center', fontsize=6, color=NAVY, zorder=9) else: # conventional round head head = Circle((2.57, sy), 0.13, fc=WHITE, ec=NAVY, lw=1.2, zorder=7) ax.add_patch(head) # Principle labels if is_locking: ax.text(3.05, 5.5, 'Fixed-angle\nconstruct', fontsize=8, color=TEAL, fontweight='bold') ax.text(3.05, 4.5, 'Threaded\nhead locks\ninto plate', fontsize=8, color=TEAL) # Single beam arrow ax.annotate('', xy=(2.9, 1.0), xytext=(2.9, 6.2), arrowprops=dict(arrowstyle='<->', color=TEAL, lw=1.5)) ax.text(3.1, 3.5, '"Single-\nbeam"\nconstruct', fontsize=7.5, color=TEAL, fontweight='bold') else: ax.text(3.05, 5.5, 'Friction\nbetween\nplate & bone', fontsize=8, color=STEEL, fontweight='bold') ax.text(3.05, 4.2, 'Screw head\npresses on\nplate', fontsize=8, color=STEEL) fig.tight_layout(pad=2) return fig savefig('07_locking_plate', fig_locking_plate()) # ─── FIG 8: DHS ─────────────────────────────────────────────────────────────── def fig_dhs(): fig, ax = plt.subplots(figsize=(9, 7), facecolor=BG) ax.set_facecolor(BG); ax.set_xlim(-2, 6); ax.set_ylim(-0.5, 8); ax.axis('off') ax.set_title('DYNAMIC HIP SCREW (DHS) — SLIDING PRINCIPLE', fontsize=13, fontweight='bold', color=NAVY, pad=12) # Femoral shaft shaft = FancyBboxPatch((1.0, 0.2), 1.8, 6.5, boxstyle='round,pad=0.12', fc=BONE, ec='#8B7355', lw=2) ax.add_patch(shaft) # Femoral neck region (angled) neck_pts = np.array([[1.0, 5.8], [1.0, 6.8], [0.2, 7.4], [-0.1, 7.2], [-0.1, 6.5], [0.5, 5.8]]) neck = plt.Polygon(neck_pts, fc=BONE, ec='#8B7355', lw=2) ax.add_patch(neck) # Femoral head head_circ = Circle((-0.5, 7.0), 0.85, fc=BONE, ec='#8B7355', lw=2) ax.add_patch(head_circ) # Intertrochanteric fracture line ax.plot([0.95, 2.85], [5.5, 4.8], color=RED, lw=2.5, zorder=8) # Side plate plate = FancyBboxPatch((2.8, 0.5), 0.45, 5.8, boxstyle='round,pad=0.03', fc=STEEL, ec=NAVY, lw=1.5) ax.add_patch(plate) # Barrel barrel = FancyBboxPatch((2.8, 4.6), 1.2, 0.6, boxstyle='round,pad=0.04', fc=METAL, ec=NAVY, lw=1.5, zorder=6) ax.add_patch(barrel) # Lag screw in barrel and into femoral head ax.plot([4.0, -0.5], [4.9, 7.0], color=STEEL, lw=8, solid_capstyle='round', zorder=5) ax.plot([4.0, -0.5], [4.9, 7.0], color=NAVY, lw=1.2, zorder=6) # Screw thread on proximal portion screw_vec = np.array([-0.5, 7.0]) - np.array([4.0, 4.9]) screw_len = np.linalg.norm(screw_vec) screw_angle = np.degrees(np.arctan2(screw_vec[1], screw_vec[0])) # Plate screws for sy in [1.2, 2.2, 3.2, 4.2]: ax.plot([0.8, 3.3], [sy, sy], color=METAL, lw=4, solid_capstyle='round', zorder=7) c = Circle((3.25, sy), 0.12, fc=WHITE, ec=NAVY, lw=1, zorder=8) ax.add_patch(c) # Load arrow ax.annotate('', xy=(1.9, 6.7), xytext=(1.9, 7.5), arrowprops=dict(arrowstyle='->', color=NAVY, lw=2.5)) ax.text(1.9, 7.6, 'Body weight\n(LOAD)', ha='center', fontsize=9, fontweight='bold', color=NAVY) # Sliding arrow ax.annotate('', xy=(3.5, 4.75), xytext=(2.85, 4.75), arrowprops=dict(arrowstyle='->', color=ORANGE, lw=2.5)) ax.text(3.6, 4.9, 'Lag screw\nSLIDES within\nbarrel\n(controlled collapse\n→ compression)', fontsize=8, color=ORANGE, fontweight='bold', va='top') # Compression result ax.annotate('Fracture\nsite', xy=(1.9, 5.1), xytext=(0.0, 4.2), fontsize=8, color=RED, fontweight='bold', arrowprops=dict(arrowstyle='->', color=RED, lw=1.5), bbox=dict(boxstyle='round,pad=0.3', fc='white', ec=RED, lw=0.8)) ax.annotate('Side plate', xy=(3.0, 2.5), xytext=(4.0, 2.5), fontsize=8, color=STEEL, fontweight='bold', arrowprops=dict(arrowstyle='->', color=STEEL, lw=1.2), bbox=dict(boxstyle='round,pad=0.3', fc='white', ec=STEEL, lw=0.8)) ax.annotate('Barrel', xy=(3.4, 4.9), xytext=(4.5, 5.8), fontsize=8, color=METAL, fontweight='bold', arrowprops=dict(arrowstyle='->', color=METAL, lw=1.2), bbox=dict(boxstyle='round,pad=0.3', fc='white', ec=METAL, lw=0.8)) fig.tight_layout(pad=1.5) return fig savefig('08_dhs', fig_dhs()) # ─── FIG 9: K-WIRE ─────────────────────────────────────────────────────────── def fig_kwire(): fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 6), facecolor=BG) fig.patch.set_facecolor(BG) fig.suptitle('K-WIRES & TENSION BAND WIRING TECHNIQUE', fontsize=13, fontweight='bold', color=NAVY) # ── K-wire types ── ax1.set_facecolor(BG); ax1.set_xlim(-0.5, 5); ax1.set_ylim(-0.3, 5); ax1.axis('off') ax1.set_title('K-WIRE TIP TYPES & SIZES', fontsize=10, fontweight='bold', color=NAVY) wire_types = [ (0.6, 'Trocar tip\n(3-facet)', STEEL, 'Best for hard\ncortical bone'), (1.8, 'Bayonet tip\n(2-facet)', TEAL, 'Angled insertion\nthrough dense bone'), (3.0, 'Diamond tip\n(4-facet)', colors.HexColor('#6C5CE7') if False else PURPLE, 'General purpose\nsoft to medium bone'), (4.2, 'Blunt tip', METAL, 'Guidewire / over\nexisting path'), ] colors_map = [STEEL, TEAL, PURPLE, METAL] for i, (cx, label, col, desc) in enumerate(wire_types): col = colors_map[i] # Wire body ax1.plot([cx, cx], [0.5, 3.8], color=col, lw=10, solid_capstyle='butt', zorder=3) ax1.plot([cx, cx], [0.5, 3.8], color=NAVY, lw=1, zorder=4) # Tip if i == 0: # trocar - 3 facet pointed ax1.fill([cx-0.12, cx, cx+0.12, cx], [0.5, 0.05, 0.5, 0.3], color=col, zorder=5) ax1.plot([cx-0.12, cx, cx+0.12], [0.5, 0.05, 0.5], color=NAVY, lw=1, zorder=6) elif i == 1: # bayonet ax1.fill([cx-0.12, cx+0.12, cx+0.12, cx], [0.5, 0.5, 0.2, 0.05], color=col, zorder=5) ax1.plot([cx-0.12, cx+0.12, cx, cx-0.12], [0.5, 0.5, 0.05, 0.5], color=NAVY, lw=1, zorder=6) elif i == 2: # diamond ax1.fill([cx-0.12, cx, cx+0.12, cx], [0.5, 0.05, 0.5, 0.28], color=col, zorder=5) ax1.plot([cx-0.12, cx, cx+0.12, cx, cx-0.12], [0.5, 0.05, 0.5, 0.28, 0.5], color=NAVY, lw=1, zorder=6) else: # blunt ax1.fill([cx-0.12, cx+0.12, cx+0.12, cx-0.12], [0.5, 0.5, 0.35, 0.35], color=col, zorder=5) # Head (drill chuck end) head = FancyBboxPatch((cx-0.15, 3.8), 0.3, 0.35, boxstyle='round,pad=0.02', fc=col, ec=NAVY, lw=1, zorder=3) ax1.add_patch(head) ax1.text(cx, 4.25, label, ha='center', va='bottom', fontsize=7.5, fontweight='bold', color=NAVY, linespacing=1.3) ax1.text(cx, -0.05, desc, ha='center', va='top', fontsize=6.5, color='#444', linespacing=1.3) # ── Tension band wiring ── ax2.set_facecolor(BG); ax2.set_xlim(-3, 3); ax2.set_ylim(-1, 5.5); ax2.axis('off') ax2.set_title('TENSION BAND WIRING — PATELLA', fontsize=10, fontweight='bold', color=NAVY) # Patella (oval) patella = mpatches.Ellipse((0, 2.0), 2.8, 3.5, fc=BONE, ec='#8B7355', lw=2.5, zorder=3) ax2.add_patch(patella) # Fracture line ax2.plot([-1.4, 1.4], [2.0, 2.0], color=RED, lw=2.5, zorder=6) # Two K-wires longitudinal for kx in [-0.5, 0.5]: ax2.plot([kx, kx], [0.25, 3.75], color=STEEL, lw=4, solid_capstyle='butt', zorder=7) ax2.plot([kx, kx], [0.25, 3.75], color=NAVY, lw=0.8, zorder=8) # tips ax2.fill([kx-0.08, kx, kx+0.08], [0.25, -0.05, 0.25], color=STEEL, zorder=9) # Figure-of-8 wire theta = np.linspace(0, 2*np.pi, 200) # Upper loop (above fracture) wire_pts_x = [] wire_pts_y = [] # Approximate figure-of-8 t = np.linspace(0, np.pi, 100) # top arc for tt in t: wire_pts_x.append(-0.5 + 1.0*(1-np.cos(tt))/2 * (1 if tt < np.pi/2 else -1) + (0.5 if tt >= np.pi/2 else -0.5)) wire_pts_y.append(2.0 + 0.9*np.sin(tt)) # bottom arc t2 = np.linspace(np.pi, 2*np.pi, 100) for tt in t2: wire_pts_x.append(0.5 + 1.0*(1-np.cos(tt))/2 * (-1 if tt < 3*np.pi/2 else 1) + (-0.5 if tt >= 3*np.pi/2 else 0.5)) wire_pts_y.append(2.0 - 0.9*np.sin(tt - np.pi)) # Simple clear figure-of-8 t_up = np.linspace(0, np.pi, 80) ax2.plot(-0.5 + 0.5*np.cos(t_up), 2.0 + 1.1*np.sin(t_up), color=ORANGE, lw=2.5, zorder=10) ax2.plot(0.5 - 0.5*np.cos(t_up), 2.0 - 1.1*np.sin(t_up), color=ORANGE, lw=2.5, zorder=10) # cross wires ax2.plot([-0.5, 0.5], [3.0, 0.9], color=ORANGE, lw=2.5, zorder=10) ax2.plot([0.5, -0.5], [3.0, 0.9], color=ORANGE, lw=2.5, zorder=10) # Twist/tightening point twist = Circle((0, 2.0), 0.12, fc=ORANGE, ec='#B7531A', lw=1.2, zorder=11) ax2.add_patch(twist) # Force arrows (muscle pull from quadriceps) ax2.annotate('', xy=(0, 4.5), xytext=(0, 3.9), arrowprops=dict(arrowstyle='->', color=RED, lw=2.5)) ax2.text(0, 4.6, 'Quadriceps\ntension', ha='center', fontsize=8, fontweight='bold', color=RED) ax2.annotate('', xy=(0, -0.5), xytext=(0, 0.15), arrowprops=dict(arrowstyle='->', color=RED, lw=2.5)) ax2.text(0, -0.65, 'Patellar\ntendon', ha='center', fontsize=8, fontweight='bold', color=RED) # Compression arrows at fracture ax2.annotate('', xy=(-0.2, 2.0), xytext=(-0.7, 2.0), arrowprops=dict(arrowstyle='->', color=GREEN, lw=2)) ax2.annotate('', xy=(0.2, 2.0), xytext=(0.7, 2.0), arrowprops=dict(arrowstyle='->', color=GREEN, lw=2)) ax2.text(-1.5, 2.35, 'COMPRESSION\n(converted)', ha='center', fontsize=7.5, color=GREEN, fontweight='bold') # Labels ax2.annotate('K-wires (×2)', xy=(0.5, 1.5), xytext=(1.8, 1.2), fontsize=8, color=STEEL, fontweight='bold', arrowprops=dict(arrowstyle='->', color=STEEL, lw=1.2), bbox=dict(boxstyle='round,pad=0.3', fc='white', ec=STEEL, lw=0.8)) ax2.annotate('Figure-of-8\nwire', xy=(0.0, 3.0), xytext=(1.8, 3.5), fontsize=8, color=ORANGE, fontweight='bold', arrowprops=dict(arrowstyle='->', color=ORANGE, lw=1.2), bbox=dict(boxstyle='round,pad=0.3', fc='white', ec=ORANGE, lw=0.8)) fig.tight_layout(pad=2) return fig savefig('09_kwire', fig_kwire()) print('All diagrams saved.') PYEOF python3 /home/daytona/workspace/ortho-implants-pdf/make_diagrams.py