make a case presentation on osteo arthritis and back pain
make a case presentation on osteo arthritis and back pain
mkdir -p /tmp/workspace/oa-backpain-case && ls /tmp/workspace/oa-backpain-case/
~/oa-backpain-case/build_pptx.py
from pptx import Presentation
from pptx.util import Inches, Pt, Emu
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.util import Inches, Pt
import copy
# ─── Colour palette ───────────────────────────────────────────────────────────
NAVY = RGBColor(0x1A, 0x37, 0x6C) # dark blue – header bars
TEAL = RGBColor(0x00, 0x86, 0x9B) # accent / sub-headers
ORANGE = RGBColor(0xE8, 0x6B, 0x1E) # highlights / badge
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
LIGHT_BG = RGBColor(0xF0, 0xF5, 0xFA) # slide background
DARK_TXT = RGBColor(0x22, 0x22, 0x22)
MID_GRAY = RGBColor(0x88, 0x88, 0x88)
W = Inches(13.333)
H = Inches(7.5)
prs = Presentation()
prs.slide_width = W
prs.slide_height = H
blank = prs.slide_layouts[6] # fully blank
# ─── Helper functions ─────────────────────────────────────────────────────────
def add_rect(slide, x, y, w, h, fill_rgb, alpha=None):
shape = slide.shapes.add_shape(1, x, y, w, h) # MSO_SHAPE_TYPE.RECTANGLE = 1
shape.fill.solid()
shape.fill.fore_color.rgb = fill_rgb
shape.line.fill.background()
return shape
def add_text(slide, text, x, y, w, h, size, bold=False, color=DARK_TXT,
align=PP_ALIGN.LEFT, wrap=True, italic=False, anchor=MSO_ANCHOR.TOP):
tb = slide.shapes.add_textbox(x, y, w, h)
tf = tb.text_frame
tf.word_wrap = wrap
tf.auto_size = None
tf.vertical_anchor = anchor
tf.margin_left = 0; tf.margin_right = 0
tf.margin_top = Pt(2); tf.margin_bottom = 0
p = tf.paragraphs[0]
p.alignment = align
run = p.add_run()
run.text = text
run.font.size = Pt(size)
run.font.bold = bold
run.font.italic = italic
run.font.color.rgb = color
run.font.name = "Calibri"
return tb
def add_multiline(slide, lines, x, y, w, h, size, color=DARK_TXT,
bold_first=False, bullet=False, line_spacing_pt=None):
"""Add a text box with multiple lines (list of strings)."""
tb = slide.shapes.add_textbox(x, y, w, h)
tf = tb.text_frame
tf.word_wrap = True
tf.margin_left = 0; tf.margin_right = 0
tf.margin_top = Pt(2); tf.margin_bottom = 0
for i, line in enumerate(lines):
if i == 0:
p = tf.paragraphs[0]
else:
p = tf.add_paragraph()
p.alignment = PP_ALIGN.LEFT
if line_spacing_pt:
p.line_spacing = Pt(line_spacing_pt)
run = p.add_run()
prefix = "• " if bullet else ""
run.text = prefix + line
run.font.size = Pt(size)
run.font.bold = (i == 0 and bold_first)
run.font.color.rgb = color
run.font.name = "Calibri"
return tb
def header_bar(slide, title, subtitle=None):
"""Dark navy bar at top with white title."""
add_rect(slide, 0, 0, W, Inches(1.15), NAVY)
add_text(slide, title, Inches(0.4), Inches(0.08), Inches(12.5), Inches(0.65),
size=30, bold=True, color=WHITE, align=PP_ALIGN.LEFT)
if subtitle:
add_text(slide, subtitle, Inches(0.4), Inches(0.72), Inches(12.5), Inches(0.38),
size=16, bold=False, color=RGBColor(0xAA, 0xCC, 0xEE), align=PP_ALIGN.LEFT)
def bg_fill(slide):
add_rect(slide, 0, 0, W, H, LIGHT_BG)
def footer(slide, text="Case Presentation | Osteoarthritis & Back Pain"):
add_rect(slide, 0, Inches(7.15), W, Inches(0.35), NAVY)
add_text(slide, text, Inches(0.3), Inches(7.17), Inches(10), Inches(0.3),
size=9, color=RGBColor(0xAA, 0xCC, 0xEE))
def section_badge(slide, label, x, y):
add_rect(slide, x, y, Inches(2.4), Inches(0.38), TEAL)
add_text(slide, label, x + Inches(0.12), y + Inches(0.04), Inches(2.2), Inches(0.32),
size=13, bold=True, color=WHITE)
def divider(slide, y):
add_rect(slide, Inches(0.4), y, Inches(12.5), Pt(2), TEAL)
# ══════════════════════════════════════════════════════════════════════════════
# SLIDE 1 – TITLE SLIDE
# ══════════════════════════════════════════════════════════════════════════════
s1 = prs.slides.add_slide(blank)
add_rect(s1, 0, 0, W, H, NAVY) # full navy background
add_rect(s1, 0, Inches(2.8), W, Inches(2.1), TEAL) # teal band
# Title
add_text(s1, "CASE PRESENTATION", Inches(1), Inches(1.0), Inches(11.3), Inches(0.7),
size=22, bold=False, color=RGBColor(0xAA, 0xCC, 0xEE), align=PP_ALIGN.CENTER)
add_text(s1, "Osteoarthritis &\nLow Back Pain", Inches(0.5), Inches(1.7), Inches(12.3), Inches(1.2),
size=46, bold=True, color=WHITE, align=PP_ALIGN.CENTER)
# Teal band text
add_text(s1, "A Clinical Case for Medical Students", Inches(1), Inches(3.0), Inches(11.3), Inches(0.5),
size=20, bold=False, color=WHITE, align=PP_ALIGN.CENTER)
add_text(s1, "Department of Internal Medicine / Orthopaedics", Inches(1), Inches(3.45), Inches(11.3), Inches(0.4),
size=15, bold=False, color=RGBColor(0xDD, 0xEE, 0xFF), align=PP_ALIGN.CENTER)
# Bottom info
add_text(s1, "July 2026", Inches(1), Inches(5.7), Inches(11.3), Inches(0.4),
size=14, bold=False, color=MID_GRAY, align=PP_ALIGN.CENTER)
add_text(s1, "References: Robbins & Kumar Basic Pathology | Goldman-Cecil Medicine | Bradley & Daroff's Neurology",
Inches(1), Inches(6.2), Inches(11.3), Inches(0.4),
size=11, bold=False, color=MID_GRAY, align=PP_ALIGN.CENTER)
# ══════════════════════════════════════════════════════════════════════════════
# SLIDE 2 – PATIENT PRESENTATION
# ══════════════════════════════════════════════════════════════════════════════
s2 = prs.slides.add_slide(blank)
bg_fill(s2)
header_bar(s2, "Patient Presentation", "Chief Complaint & History of Present Illness")
footer(s2)
section_badge(s2, "PATIENT DEMOGRAPHICS", Inches(0.4), Inches(1.3))
demo_lines = [
"Name: Mrs. E.A. (anonymized)",
"Age: 65 years",
"Sex: Female",
"Occupation: Retired teacher",
"BMI: 30.4 kg/m² (obese class I)",
]
add_multiline(s2, demo_lines, Inches(0.5), Inches(1.75), Inches(4.5), Inches(2.0),
size=15, color=DARK_TXT, bullet=True)
section_badge(s2, "CHIEF COMPLAINT", Inches(5.2), Inches(1.3))
add_multiline(s2, [
'"Persistent pain in both knees and lower back',
' for the past 3 years, worsening over 6 months."',
], Inches(5.3), Inches(1.75), Inches(7.5), Inches(0.9), size=15, color=DARK_TXT)
section_badge(s2, "HISTORY OF PRESENT ILLNESS", Inches(5.2), Inches(2.75))
hpi_lines = [
"Bilateral knee pain – worse with walking & climbing stairs",
"Morning stiffness lasting < 30 minutes",
"Low back pain – dull, aching; radiates to left buttock",
"No bowel or bladder dysfunction",
"Occasional knee swelling after prolonged activity",
"No fever, no significant trauma",
"Pain scale: 6–7/10 at rest, 9/10 on exertion",
]
add_multiline(s2, hpi_lines, Inches(5.3), Inches(3.2), Inches(7.5), Inches(3.0),
size=14, color=DARK_TXT, bullet=True)
# ══════════════════════════════════════════════════════════════════════════════
# SLIDE 3 – PAST HISTORY & RISK FACTORS
# ══════════════════════════════════════════════════════════════════════════════
s3 = prs.slides.add_slide(blank)
bg_fill(s3)
header_bar(s3, "Medical History & Risk Factors", "Past Medical, Surgical & Social History")
footer(s3)
# Left column
section_badge(s3, "PAST MEDICAL HISTORY", Inches(0.4), Inches(1.3))
pmh = ["Type 2 Diabetes Mellitus (10 years)",
"Hypertension",
"Dyslipidaemia",
"Menopause (age 52)"]
add_multiline(s3, pmh, Inches(0.5), Inches(1.75), Inches(5.5), Inches(1.8),
size=15, bullet=True, color=DARK_TXT)
section_badge(s3, "MEDICATIONS", Inches(0.4), Inches(3.7))
meds = ["Metformin 1000 mg BD",
"Amlodipine 5 mg OD",
"Atorvastatin 20 mg ON",
"PRN Ibuprofen (self-medicated)"]
add_multiline(s3, meds, Inches(0.5), Inches(4.15), Inches(5.5), Inches(1.8),
size=15, bullet=True, color=DARK_TXT)
# Right column
section_badge(s3, "RISK FACTORS FOR OA", Inches(6.5), Inches(1.3))
rf_oa = ["Age > 50 (prevalence ~40% beyond age 70)",
"Female sex – disproportionately affected",
"Obesity (increased mechanical load)",
"Diabetes mellitus (secondary OA trigger)",
"No prior joint surgery or fracture"]
add_multiline(s3, rf_oa, Inches(6.6), Inches(1.75), Inches(6.3), Inches(2.0),
size=14, bullet=True, color=DARK_TXT)
section_badge(s3, "RISK FACTORS FOR BACK PAIN", Inches(6.5), Inches(3.9))
rf_bp = ["Sedentary lifestyle post-retirement",
"Obesity – increased lumbar axial load",
"Facet joint arthropathy (age-related)",
"Possible lumbar disc degeneration",
"Prolonged standing history (teaching career)"]
add_multiline(s3, rf_bp, Inches(6.6), Inches(4.35), Inches(6.3), Inches(2.0),
size=14, bullet=True, color=DARK_TXT)
# ══════════════════════════════════════════════════════════════════════════════
# SLIDE 4 – PHYSICAL EXAMINATION
# ══════════════════════════════════════════════════════════════════════════════
s4 = prs.slides.add_slide(blank)
bg_fill(s4)
header_bar(s4, "Physical Examination", "Musculoskeletal & Neurological Findings")
footer(s4)
# Vitals strip
add_rect(s4, Inches(0.4), Inches(1.3), Inches(12.5), Inches(0.6), TEAL)
vitals = "BP: 148/90 mmHg | HR: 78 bpm | Temp: 36.8°C | SpO₂: 98% | BMI: 30.4 kg/m²"
add_text(s4, vitals, Inches(0.6), Inches(1.35), Inches(12.0), Inches(0.5),
size=14, bold=True, color=WHITE, align=PP_ALIGN.CENTER)
# Left: Knee exam
section_badge(s4, "KNEE EXAMINATION", Inches(0.4), Inches(2.1))
knee_findings = [
"Bilateral knee: bony enlargement (osteophytes)",
"Crepitus on passive ROM – bilateral",
"Mild effusion: left > right",
"Decreased ROM: flexion 110° (normal 130–140°)",
"Varus deformity: left knee",
"McMurray test: negative (no meniscal tear)",
"Lachman test: negative",
]
add_multiline(s4, knee_findings, Inches(0.5), Inches(2.55), Inches(5.8), Inches(3.5),
size=13.5, bullet=True, color=DARK_TXT)
# Right: Back exam
section_badge(s4, "LUMBAR SPINE EXAMINATION", Inches(6.8), Inches(2.1))
back_findings = [
"Paraspinal muscle tenderness: L3–L5 level",
"Lumbar flexion: restricted (60°, normal 90°)",
"Straight Leg Raise (SLR): negative bilaterally",
"Patrick (FABER) test: positive left",
"Facet loading test: positive – reproduces LBP",
"Neurological: power 5/5, reflexes intact",
"No saddle anaesthesia; sphincter tone normal",
]
add_multiline(s4, back_findings, Inches(6.9), Inches(2.55), Inches(6.0), Inches(3.5),
size=13.5, bullet=True, color=DARK_TXT)
# ══════════════════════════════════════════════════════════════════════════════
# SLIDE 5 – INVESTIGATIONS
# ══════════════════════════════════════════════════════════════════════════════
s5 = prs.slides.add_slide(blank)
bg_fill(s5)
header_bar(s5, "Investigations", "Laboratory & Imaging Studies")
footer(s5)
# Lab results box (left)
section_badge(s5, "LABORATORY TESTS", Inches(0.4), Inches(1.3))
labs = [
("FBC", "Hb 12.6 g/dL – mild anaemia of chronic disease"),
("ESR", "28 mm/hr (slightly elevated)"),
("CRP", "12 mg/L (mildly elevated)"),
("RF / Anti-CCP", "NEGATIVE – rules out RA"),
("Uric Acid", "4.8 mg/dL – normal"),
("HbA1c", "7.4%"),
("Urea / Creatinine", "Normal"),
("Synovial fluid", "Non-inflammatory: WBC < 2000/mm³"),
]
y = Inches(1.8)
for label, value in labs:
add_rect(s5, Inches(0.5), y, Inches(1.6), Inches(0.35), NAVY)
add_text(s5, label, Inches(0.55), y + Pt(4), Inches(1.5), Inches(0.32),
size=12, bold=True, color=WHITE)
add_text(s5, value, Inches(2.25), y + Pt(4), Inches(4.1), Inches(0.32),
size=12.5, color=DARK_TXT)
y += Inches(0.42)
# Imaging results box (right)
section_badge(s5, "IMAGING FINDINGS", Inches(7.0), Inches(1.3))
img_lines = [
"X-ray Knee (Weight-Bearing AP & Lateral):",
" • Medial joint space narrowing bilaterally",
" • Marginal osteophytes – femoral condyles",
" • Subchondral sclerosis",
" • No acute fracture",
"",
"X-ray Lumbar Spine (AP & Lateral):",
" • Disc space narrowing L4–L5, L5–S1",
" • Osteophyte formation (anterior/posterior)",
" • Facet joint hypertrophy",
"",
"MRI Lumbar Spine (if available):",
" • Mild disc bulge L4–L5",
" • No nerve root compression seen",
" • Facet joint arthropathy confirmed",
]
add_multiline(s5, img_lines, Inches(7.1), Inches(1.78), Inches(5.8), Inches(5.0),
size=13, color=DARK_TXT)
# ══════════════════════════════════════════════════════════════════════════════
# SLIDE 6 – PATHOPHYSIOLOGY (OA)
# ══════════════════════════════════════════════════════════════════════════════
s6 = prs.slides.add_slide(blank)
bg_fill(s6)
header_bar(s6, "Pathophysiology of Osteoarthritis",
"Degenerative Joint Disease – Mechanisms & Morphology")
footer(s6)
# Left: mechanism text
section_badge(s6, "DISEASE MECHANISM", Inches(0.4), Inches(1.3))
mech = [
"OA = failed repair of synovial joint tissues after intra-articular stress",
"Primary pathogenic mechanism: biomechanical stress on articular cartilage",
"Chondrocytes release MMPs, TNF, IL-1 – degrade collagen & proteoglycan",
"Attempted repair exceeds capacity → net cartilage loss",
"Subchondral bone: sclerosis, cyst formation, osteophyte development",
"Inflammation is SECONDARY – exacerbates but does not initiate OA",
"(Unlike RA where autoimmunity drives pannus formation)",
]
add_multiline(s6, mech, Inches(0.5), Inches(1.8), Inches(6.5), Inches(3.5),
size=13.5, bullet=True, color=DARK_TXT)
# OA stages box
section_badge(s6, "MORPHOLOGICAL STAGES", Inches(0.4), Inches(5.25))
stages = [
"Early: chondrocyte injury, matrix changes, proteoglycan loss",
"Established: cartilage fibrillation, clefts, loss of thickness",
"Late: full-thickness cartilage loss, bone eburnation (ivory-like surface),",
" joint mice (loose bodies), subchondral cysts, osteophytes",
]
add_multiline(s6, stages, Inches(0.5), Inches(5.7), Inches(6.2), Inches(1.5),
size=13, bullet=True, color=DARK_TXT)
# Right: OA vs RA comparison table
section_badge(s6, "OA vs RA – KEY DIFFERENCES", Inches(7.2), Inches(1.3))
headers = ["Feature", "OA", "RA"]
rows = [
["Pathology", "Mechanical / degenerative", "Autoimmune"],
["Inflammation", "Secondary", "Primary driver"],
["Joints", "Weight-bearing (knees, hips)", "Small joints (MCP, PIP)"],
["Morning stiffness", "< 30 minutes", "> 1 hour"],
["Serology", "RF / Anti-CCP: negative", "RF / Anti-CCP: positive"],
["Systemic features", "None", "Fever, nodules, systemic"],
["Treatment", "NSAIDs, PT, joint replacement", "DMARDs, biologics"],
]
col_w = [Inches(2.0), Inches(2.2), Inches(2.2)]
col_x = [Inches(7.3), Inches(9.35), Inches(11.6)]
row_h = Inches(0.42)
# header row
for ci, (txt, cw, cx) in enumerate(zip(headers, col_w, col_x)):
add_rect(s6, cx, Inches(1.78), cw - Inches(0.05), row_h, NAVY)
add_text(s6, txt, cx + Inches(0.05), Inches(1.82), cw - Inches(0.1), row_h - Pt(4),
size=12, bold=True, color=WHITE, align=PP_ALIGN.CENTER)
for ri, row in enumerate(rows):
ry = Inches(1.78) + row_h * (ri + 1)
bg = LIGHT_BG if ri % 2 == 0 else WHITE
for ci, (txt, cw, cx) in enumerate(zip(row, col_w, col_x)):
add_rect(s6, cx, ry, cw - Inches(0.05), row_h, bg)
add_text(s6, txt, cx + Inches(0.07), ry + Pt(4), cw - Inches(0.12), row_h - Pt(4),
size=11.5, color=DARK_TXT)
# ══════════════════════════════════════════════════════════════════════════════
# SLIDE 7 – PATHOPHYSIOLOGY (BACK PAIN)
# ══════════════════════════════════════════════════════════════════════════════
s7 = prs.slides.add_slide(blank)
bg_fill(s7)
header_bar(s7, "Pathophysiology of Low Back Pain",
"Lumbar Facet Arthropathy & Disc Degeneration")
footer(s7)
add_text(s7, "Low back pain affects 60–80% of the US population at some point in life and is the most common condition seen in pain clinics.",
Inches(0.4), Inches(1.22), Inches(12.5), Inches(0.45),
size=14, italic=True, color=TEAL)
# 3-column boxes
boxes = [
("MUSCLE STRAIN / SPASM",
["Acute injury or chronic overuse", "Paraspinal tenderness & spasm",
"No neurological deficit", "Responds to NSAIDs, muscle relaxants, PT"]),
("LUMBAR FACET SYNDROME (35%)",
["Arthritis or injury in facet joints", "Pain: low back ± referred to thigh (≤ knee)",
"Back extension worsens pain", "SLR: NEGATIVE", "Tx: NSAIDs → medial branch blocks → RFA"]),
("DISC HERNIATION / RADICULOPATHY",
["L4–L5 / L5–S1 most common levels", "Shooting pain → foot (dorsomedial = L5; lateral = S1)",
"SLR: POSITIVE", "MRI confirms; EMG/NCV may help",
"Tx: NSAIDs → LESI → surgery if neurological deficit"]),
]
bx_starts = [Inches(0.3), Inches(4.55), Inches(8.8)]
bw = Inches(4.1)
for (title, bullets), bx in zip(boxes, bx_starts):
add_rect(s7, bx, Inches(1.8), bw, Inches(0.45), NAVY)
add_text(s7, title, bx + Inches(0.08), Inches(1.84), bw - Inches(0.1), Inches(0.38),
size=12.5, bold=True, color=WHITE)
add_multiline(s7, bullets, bx + Inches(0.1), Inches(2.32), bw - Inches(0.15), Inches(3.0),
size=13, bullet=True, color=DARK_TXT)
# Red flags box
add_rect(s7, Inches(0.3), Inches(5.55), Inches(12.6), Inches(1.35), RGBColor(0xFF, 0xEE, 0xEE))
add_rect(s7, Inches(0.3), Inches(5.55), Inches(2.0), Inches(1.35), RGBColor(0xCC, 0x00, 0x00))
add_text(s7, "⚠ RED\nFLAGS", Inches(0.35), Inches(5.62), Inches(1.9), Inches(1.2),
size=16, bold=True, color=WHITE, align=PP_ALIGN.CENTER)
red_flags = ("Cauda equina syndrome (bowel/bladder dysfunction, saddle anaesthesia) – EMERGENCY | "
"Progressive neurological deficit | Fever + back pain (infective) | "
"Weight loss + night pain (malignancy) | Fracture risk (osteoporosis, trauma)")
add_text(s7, red_flags, Inches(2.45), Inches(5.65), Inches(10.3), Inches(1.2),
size=13, color=RGBColor(0x88, 0x00, 0x00), wrap=True)
# ══════════════════════════════════════════════════════════════════════════════
# SLIDE 8 – DIAGNOSIS
# ══════════════════════════════════════════════════════════════════════════════
s8 = prs.slides.add_slide(blank)
bg_fill(s8)
header_bar(s8, "Diagnosis", "Clinical & Radiological Criteria for OA")
footer(s8)
# Final diagnosis banner
add_rect(s8, Inches(0.4), Inches(1.25), Inches(12.5), Inches(0.7), ORANGE)
add_text(s8, "FINAL DIAGNOSIS: Bilateral Knee Osteoarthritis + Lumbar Facet Arthropathy (Secondary LBP)",
Inches(0.6), Inches(1.3), Inches(12.0), Inches(0.6),
size=18, bold=True, color=WHITE, align=PP_ALIGN.CENTER)
# Left: ACR criteria
section_badge(s8, "ACR CRITERIA FOR KNEE OA", Inches(0.4), Inches(2.15))
acr = [
"Knee pain + at least 3 of 6:",
" 1. Age > 50 years ✓",
" 2. Morning stiffness < 30 min ✓",
" 3. Crepitus on motion ✓",
" 4. Bony tenderness ✓",
" 5. Bony enlargement ✓",
" 6. No palpable warmth ✓",
"",
"This patient meets ALL 6 criteria",
"Sensitivity: 95% | Specificity: 69%",
]
add_multiline(s8, acr, Inches(0.5), Inches(2.6), Inches(5.8), Inches(4.0),
size=14, color=DARK_TXT)
# Right: differential diagnoses
section_badge(s8, "DIFFERENTIAL DIAGNOSES", Inches(7.0), Inches(2.15))
dd = [
("Rheumatoid Arthritis", "RF negative, no systemic features, no small joint involvement → EXCLUDED"),
("Gout / Pseudogout", "Uric acid normal, synovial fluid non-inflammatory → EXCLUDED"),
("Disc Herniation (LBP)", "SLR negative, no radiculopathy → EXCLUDED as primary cause"),
("Lumbar Facet Syndrome", "Patrick + ve, extension worsens pain, normal neurology → INCLUDED"),
("Malignancy / Infection", "No constitutional symptoms, fever, weight loss → EXCLUDED"),
]
y = Inches(2.6)
for dx, comment in dd:
add_rect(s8, Inches(7.1), y, Inches(2.4), Inches(0.55), TEAL)
add_text(s8, dx, Inches(7.15), y + Pt(4), Inches(2.3), Inches(0.48), size=12, bold=True, color=WHITE)
add_text(s8, comment, Inches(9.58), y + Pt(4), Inches(3.8), Inches(0.48), size=12, color=DARK_TXT, wrap=True)
y += Inches(0.65)
# ══════════════════════════════════════════════════════════════════════════════
# SLIDE 9 – MANAGEMENT
# ══════════════════════════════════════════════════════════════════════════════
s9 = prs.slides.add_slide(blank)
bg_fill(s9)
header_bar(s9, "Management Plan", "Non-Pharmacological | Pharmacological | Interventional | Surgical")
footer(s9)
# 4-tier boxes
tiers = [
("NON-PHARMACOLOGICAL",
TEAL,
["Weight reduction (BMI target < 25)",
"Physiotherapy: quad strengthening, core exercises",
"Walking aids (cane/walker if needed)",
"Heat/cold therapy for pain relief",
"Activity modification – avoid high-impact",
"Patient education & self-management"]),
("PHARMACOLOGICAL",
NAVY,
["Paracetamol: first-line analgesic",
"NSAIDs (oral/topical): ibuprofen, naproxen",
"Caution: renal, GI, cardiovascular risk",
"Duloxetine: for chronic neuropathic component",
"Muscle relaxants: cyclobenzaprine (back spasm)",
"Topical diclofenac gel (knee)"]),
("INTERVENTIONAL",
ORANGE,
["Intra-articular corticosteroid injection",
" (knee: short-term relief 4–8 wks)",
"Hyaluronic acid injection (controversial)",
"Medial branch block (facet LBP)",
"Radiofrequency ablation (RFA) if MBB +ve",
"Lumbar epidural steroid injection (if radiculopathy)"]),
("SURGICAL",
RGBColor(0x55, 0x44, 0x88),
["Total Knee Replacement (TKR):",
" • Failed conservative Rx ≥ 3–6 months",
" • Functional limitation affecting ADLs",
" • Severe structural damage on X-ray",
"Lumbar fusion / discectomy:",
" • Only for failed conservative Rx + imaging correlation"]),
]
bw2 = Inches(3.05)
starts2 = [Inches(0.2), Inches(3.38), Inches(6.55), Inches(9.72)]
for (title, col, bullets), bx in zip(tiers, starts2):
add_rect(s9, bx, Inches(1.25), bw2, Inches(0.45), col)
add_text(s9, title, bx + Inches(0.07), Inches(1.28), bw2 - Inches(0.1), Inches(0.4),
size=11.5, bold=True, color=WHITE)
add_multiline(s9, bullets, bx + Inches(0.1), Inches(1.76), bw2 - Inches(0.15), Inches(5.0),
size=12.5, bullet=True, color=DARK_TXT)
# ══════════════════════════════════════════════════════════════════════════════
# SLIDE 10 – LEARNING POINTS & SUMMARY
# ══════════════════════════════════════════════════════════════════════════════
s10 = prs.slides.add_slide(blank)
bg_fill(s10)
header_bar(s10, "Key Learning Points", "Summary for Medical Students")
footer(s10)
points = [
("OA Definition", "Degenerative disease of articular cartilage. Primary pathogenic mechanism is MECHANICAL STRESS. Inflammation is secondary."),
("Epidemiology", "Most common joint disease; prevalence ~40% in >70 yr. Female sex, obesity, DM, age are major risk factors."),
("Clinical Features", "Pain ↑ with use, morning stiffness <30 min, crepitus, osteophytes (Heberden nodes in DIP), decreased ROM."),
("OA vs RA", "OA: seronegative, weight-bearing joints, no systemic features. RA: autoimmune, small joints, RF +ve, systemic."),
("LBP Causes", "Muscle strain, lumbar facet syndrome (35%), disc herniation (radiculopathy), SI joint syndrome, spinal stenosis."),
("Red Flags", "Cauda equina = surgical EMERGENCY. Always screen: bowel/bladder, saddle anaesthesia, progressive weakness."),
("Management", "Step-up: weight loss + PT → NSAIDs/paracetamol → injections → surgery when ADLs affected and conservative Rx fails."),
("Joint Replacement", "TKR is indicated when functional status interferes with ADLs and supportive/pharmacological care is ineffective."),
]
y = Inches(1.28)
for i, (heading, body) in enumerate(points):
col = NAVY if i % 2 == 0 else TEAL
add_rect(s10, Inches(0.35), y, Inches(2.5), Inches(0.65), col)
add_text(s10, heading, Inches(0.42), y + Pt(4), Inches(2.38), Inches(0.58),
size=13, bold=True, color=WHITE, align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE)
add_text(s10, body, Inches(2.95), y + Pt(4), Inches(10.0), Inches(0.58),
size=13, color=DARK_TXT, wrap=True, anchor=MSO_ANCHOR.MIDDLE)
y += Inches(0.68)
# Reference strip
add_rect(s10, 0, Inches(6.85), W, Inches(0.3), TEAL)
add_text(s10, "Sources: Robbins & Kumar Basic Pathology 10e | Goldman-Cecil Medicine 27e | Bradley & Daroff Neurology 8e | Textbook of Family Medicine 9e",
Inches(0.3), Inches(6.87), Inches(12.6), Inches(0.28),
size=9.5, color=WHITE, align=PP_ALIGN.CENTER)
# ─── Save ─────────────────────────────────────────────────────────────────────
out = "/tmp/workspace/oa-backpain-case/OA_BackPain_Case_Presentation.pptx"
prs.save(out)
print(f"Saved → {out}")
cd /tmp/workspace/oa-backpain-case && python build_pptx.py 2>&1
python -c " from pptx import Presentation prs = Presentation('/tmp/workspace/oa-backpain-case/OA_BackPain_Case_Presentation.pptx') print(f'Slides: {len(prs.slides)}') for i, slide in enumerate(prs.slides, 1): texts = [s.text_frame.text[:60].replace(chr(10),' ') for s in slide.shapes if s.has_text_frame and s.text_frame.text.strip()] print(f' Slide {i}: {texts[0] if texts else \"(empty)\"}') "
OA BackPain Case Presentation
Presentation · PPTX
| Slide | Content |
|---|---|
| 1 | Title slide |
| 2 | Patient Presentation - Chief Complaint & HPI (65F, bilateral knee pain + LBP x 3 years) |
| 3 | Medical History & Risk Factors (DM, HTN, obesity; risk factors for OA and LBP) |
| 4 | Physical Examination - Knee & Lumbar findings with vitals strip |
| 5 | Investigations - Lab results table + X-ray / MRI findings |
| 6 | Pathophysiology of OA - Mechanisms, stages, OA vs RA comparison table |
| 7 | Pathophysiology of LBP - 3 cause boxes (strain, facet syndrome, disc) + Red Flags alert |
| 8 | Diagnosis - ACR Criteria (all 6 met) + Differential diagnoses with exclusion reasoning |
| 9 | Management Plan - 4-tier layout: Non-pharmacological, Pharmacological, Interventional, Surgical |
| 10 | Key Learning Points - 8 takeaways for medical students with textbook references |