Give history taking and examination Performa for orthopedic malunion of humerus
proximal humerus malunion radiograph deformity

Anteroposterior (AP) radiograph of the right shoulder demonstrating a malunion of a proximal humeral fracture at nine months post-initial stabilization. A proximal humeral locking plate is fixed to the lateral aspect of the humerus, with multiple cortical screws in the shaft and locking screws extending into the humeral head. The humeral head shows significant articular surface irregularity and flattening, consistent with partial collapse and malunion. A prominent bony spur is visible at the superior aspect of the head, likely contributing to mechanical impingement. While the metallic hardware appears intact without acute fracture of the plate or visible screw breakage, the relative alignment of the humeral head to the shaft demonstrates a varus deformity. The glenohumeral joint space appears preserved, but the loss of normal articular congruity is evident. This image illustrates post-traumatic complications of proximal humerus fractures, specifically hardware-associated malunion and secondary morphological changes of the humeral head.

This diagnostic image is an anteroposterior (AP) radiograph of the left shoulder, illustrating a chronic, two-part proximal humerus fracture with malunion. The primary pathology involves a fracture at the surgical neck, resulting in significant varus malalignment of the humeral head relative to the shaft. A distinctive visual feature is the sharp, laterally projecting bony spike originating from the proximal aspect of the humeral shaft fragment. The cortical surface at the fracture site shows clear disruption and displacement, while the humeral head is angulated medially (varus). This imaging demonstrates the anatomical consequences of nonoperative management in certain proximal humerus fractures, emphasizing the structural deformity and the potential for limited range of motion or impingement due to the malaligned bone fragments and the prominent lateral spike.

This diagnostic image is a fluoroscopic radiograph of a human shoulder joint, demonstrating a significant varus deformity of the proximal humerus. The humerus is positioned in abduction, showcasing the dynamic relationship between the glenohumeral structures. Key anatomical features include a malaligned humeral head and an prominent greater tuberosity resulting from a malunited surgical neck fracture. The image captures the mechanical block to abduction where the greater tuberosity makes contact with the superior margin of the glenoid rim, rather than the acromion. This pathological contact illustrates the clinical significance of a reduced neck-shaft angle in post-traumatic deformities. Visible bony landmarks include the humeral shaft, humeral head, glenoid fossa, and the lateral aspect of the scapula. The radiograph is intended for orthopedic education regarding the assessment of shoulder impingement mechanisms and the biomechanical consequences of proximal humeral malunion.
| Feature | Findings |
|---|---|
| Shoulder asymmetry | Lowered or protracted shoulder on affected side |
| Deltoid bulk | Atrophy suggests axillary nerve injury or disuse |
| Muscle wasting | Supraspinatus/infraspinatus fossa wasting = rotator cuff/suprascapular nerve |
| Visible deformity | Varus/valgus angulation, shortening, rotational deformity |
| Skin changes | Scars (operative), sinuses (infection), bruising |
| Scapular position | Scapular winging (serratus anterior/long thoracic nerve) |
| Axillary fold | Symmetry |
| Movement | Normal | Findings |
|---|---|---|
| Shoulder | ||
| Forward flexion | 0-180° | |
| Extension | 0-60° | |
| Abduction | 0-180° | |
| Adduction | 0-45° | |
| External rotation (arm at side) | 0-60° | |
| Internal rotation (hand behind back, level reached) | T7 | |
| Elbow | ||
| Flexion | 0-145° | |
| Extension | 0° | |
| Forearm supination | 0-90° | |
| Forearm pronation | 0-90° | |
| Wrist and hand | ||
| Grip strength (dynamometer) |
| Nerve | Motor test | Sensory area |
|---|---|---|
| Axillary nerve (proximal humerus fracture) | Deltoid abduction (push against resistance) | Regimental badge area (lateral upper arm) |
| Radial nerve (humeral shaft) | Wrist extension, finger/thumb extension | Dorsum of hand, thumb web space (first dorsal web space) |
| Musculocutaneous nerve | Elbow flexion in supination (biceps) | Lateral forearm |
| Median nerve (distal humerus) | Wrist flexion, FPL, thenar pinch | Radial 3.5 digits, palmar |
| Ulnar nerve (distal humerus - tardy ulnar palsy) | Finger abduction/adduction (intrinsics), Froment's sign | Medial 1.5 digits, hypothenar |
| Investigation | Purpose |
|---|---|
| AP and lateral X-rays of affected arm (including joint above and below) | Assess angulation, shortening, rotational malalignment, neck-shaft angle, callus |
| Contralateral X-ray | Comparison of normal anatomy (especially radial bow, neck-shaft angle) |
| CT with 3D reconstruction | Gold standard for complex malunion - multiplanar deformity assessment, rotational malalignment, articular incongruity |
| MRI | Rotator cuff integrity, occult osteonecrosis, residual soft tissue pathology (note: interpretation difficult with hardware in situ) |
| Score | Domain |
|---|---|
| DASH / QuickDASH | Upper limb function |
| Constant-Murley Score | Shoulder-specific (pain, ADL, ROM, strength) |
| ASES Score | Pain + function |
| Oxford Shoulder Score | Patient-reported |
| VAS / NRS Pain Scale | Pain severity |
PATIENT: _________ Age: ___ Sex: ___ Occupation: ___ Dominant hand: R/L
ORIGINAL INJURY: Date: ___ Mechanism: ___ Level: open/closed Treatment: ___
COMPLAINTS: Pain □ Deformity □ Weakness □ Stiffness □ Numbness □ Cosmesis □
LOOK: Atrophy □ Asymmetry □ Scar/sinus □ Visible deformity □ Winging □
FEEL: Tenderness site: ___ Callus/step: ___ Limb length: ___cm (vs. contralateral ___cm)
MOVE (affected / contralateral):
Flexion: ___/___ Abduction: ___/___ ER: ___/___ IR: ___/___
Elbow flexion: ___/___ Extension: ___/___ Supination: ___/___ Pronation: ___/___
SPECIAL TESTS: Neer □ Hawkins □ Empty can □ Drop arm □ Apprehension □
NEUROLOGY:
Axillary: Motor (deltoid) ___/5 Sensory: intact/impaired
Radial: Motor (wrist ext) ___/5 Sensory: intact/impaired
Ulnar: Froment □ Clawing □ Tinel □
Median: Thenar bulk ___ Pinch ___
VASCULAR: Radial pulse: present/absent CRT: ___sec
INVESTIGATIONS ORDERED:
X-ray □ CT 3D □ MRI □ Labs □
SCORES: DASH:___ Constant:___ VAS:___


Create a Word document with this proforma I can print and use in clinic
ls -la /tmp/workspace/ 2>/dev/null || echo "workspace does not exist yet"
mkdir -p /tmp/workspace/humerus-malunion-proforma
~/humerus-malunion-proforma/build_proforma.py
from docx import Document
from docx.shared import Pt, Inches, RGBColor, Cm
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT, WD_ALIGN_VERTICAL
from docx.oxml.ns import qn
from docx.oxml import OxmlElement
import copy
doc = Document()
# ── Page margins (A4, 1.5 cm all round for print) ──────────────────────────
section = doc.sections[0]
section.page_height = Cm(29.7)
section.page_width = Cm(21.0)
section.left_margin = Cm(1.6)
section.right_margin = Cm(1.6)
section.top_margin = Cm(1.5)
section.bottom_margin = Cm(1.5)
# ── Default font ────────────────────────────────────────────────────────────
style = doc.styles["Normal"]
style.font.name = "Arial"
style.font.size = Pt(9)
# ── Helper: set table cell shading ─────────────────────────────────────────
def shade_cell(cell, hex_color):
tc = cell._tc
tcPr = tc.get_or_add_tcPr()
shd = OxmlElement("w:shd")
shd.set(qn("w:val"), "clear")
shd.set(qn("w:color"), "auto")
shd.set(qn("w:fill"), hex_color)
tcPr.append(shd)
def set_cell_border(cell, **kwargs):
"""Set cell borders. kwargs: top, bottom, left, right each a dict with
keys: sz (border size in 1/8pt), val, color."""
tc = cell._tc
tcPr = tc.get_or_add_tcPr()
tcBorders = OxmlElement("w:tcBorders")
for edge in ("top", "left", "bottom", "right", "insideH", "insideV"):
border_data = kwargs.get(edge)
if border_data is not None:
tag = OxmlElement(f"w:{{edge}}".replace("{edge}", edge))
tag.set(qn("w:val"), border_data.get("val", "single"))
tag.set(qn("w:sz"), str(border_data.get("sz", 4)))
tag.set(qn("w:space"), "0")
tag.set(qn("w:color"), border_data.get("color", "000000"))
tcBorders.append(tag)
tcPr.append(tcBorders)
def heading_para(doc, text, level=1, color="1F3864"):
p = doc.add_paragraph()
p.style = f"Heading {level}"
run = p.add_run(text)
run.font.color.rgb = RGBColor.from_string(color)
run.font.name = "Arial"
run.font.size = Pt(11 if level == 1 else 9.5)
run.font.bold = True
return p
def section_bar(doc, text):
"""Dark blue full-width bar heading."""
tbl = doc.add_table(rows=1, cols=1)
tbl.style = "Table Grid"
tbl.autofit = False
tbl.columns[0].width = Inches(7.3)
cell = tbl.rows[0].cells[0]
shade_cell(cell, "1F3864")
p = cell.paragraphs[0]
p.alignment = WD_ALIGN_PARAGRAPH.LEFT
run = p.add_run(f" {text}")
run.font.name = "Arial"
run.font.size = Pt(9.5)
run.font.bold = True
run.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
p.paragraph_format.space_before = Pt(2)
p.paragraph_format.space_after = Pt(2)
doc.add_paragraph() # small spacer
def sub_bar(doc, text):
"""Light blue sub-section bar."""
tbl = doc.add_table(rows=1, cols=1)
tbl.style = "Table Grid"
tbl.autofit = False
tbl.columns[0].width = Inches(7.3)
cell = tbl.rows[0].cells[0]
shade_cell(cell, "BDD7EE")
p = cell.paragraphs[0]
run = p.add_run(f" {text}")
run.font.name = "Arial"
run.font.size = Pt(9)
run.font.bold = True
run.font.color.rgb = RGBColor(0x1F, 0x38, 0x64)
p.paragraph_format.space_before = Pt(1)
p.paragraph_format.space_after = Pt(1)
doc.add_paragraph()
def small(text, bold=False):
return ("**" if bold else "") + text
def add_field_row(table, label, width_label=2.5, width_field=4.8):
row = table.add_row()
c0, c1 = row.cells[0], row.cells[1]
c0.width = Inches(width_label)
c1.width = Inches(width_field)
shade_cell(c0, "EBF3FB")
p0 = c0.paragraphs[0]
r = p0.add_run(label)
r.font.name = "Arial"; r.font.size = Pt(8.5); r.font.bold = True
# leave c1 blank for handwriting
p1 = c1.paragraphs[0]
p1.add_run("")
return row
def make_two_col_table(doc, rows_data, col1_w=3.5, col2_w=3.8):
"""rows_data: list of (label, field_placeholder)"""
tbl = doc.add_table(rows=0, cols=2)
tbl.style = "Table Grid"
tbl.autofit = False
for label, placeholder in rows_data:
row = tbl.add_row()
c0, c1 = row.cells[0], row.cells[1]
c0.width = Inches(col1_w)
c1.width = Inches(col2_w)
shade_cell(c0, "EBF3FB")
p0 = c0.paragraphs[0]
r = p0.add_run(label)
r.font.name = "Arial"; r.font.size = Pt(8.5); r.font.bold = True
p1 = c1.paragraphs[0]
rr = p1.add_run(placeholder)
rr.font.name = "Arial"; rr.font.size = Pt(8); rr.font.color.rgb = RGBColor(0x99,0x99,0x99)
return tbl
def make_check_table(doc, items, cols=3):
"""Checkbox table with items laid out in cols columns."""
n_rows = -(-len(items) // cols) # ceiling division
tbl = doc.add_table(rows=n_rows, cols=cols)
tbl.style = "Table Grid"
tbl.autofit = False
col_w = Inches(7.3 / cols)
idx = 0
for r in range(n_rows):
for c in range(cols):
cell = tbl.rows[r].cells[c]
cell.width = col_w
if idx < len(items):
p = cell.paragraphs[0]
run = p.add_run(f"☐ {items[idx]}")
run.font.name = "Arial"; run.font.size = Pt(8.5)
idx += 1
return tbl
def make_rom_table(doc):
headers = ["Movement", "Normal", "Affected", "Contralateral", "Notes"]
widths = [2.0, 0.9, 1.0, 1.2, 2.2]
rows = [
("SHOULDER", "", "", "", ""),
("Forward Flexion", "0-180°", "", "", ""),
("Extension", "0-60°", "", "", ""),
("Abduction", "0-180°", "", "", ""),
("Adduction", "0-45°", "", "", ""),
("External Rotation (arm at side)", "0-60°", "", "", ""),
("Internal Rotation (hand behind back - level reached)", "T7", "", "", ""),
("ELBOW", "", "", "", ""),
("Flexion", "0-145°", "", "", ""),
("Extension", "0°", "", "", ""),
("Supination", "0-90°", "", "", ""),
("Pronation", "0-90°", "", "", ""),
("WRIST / HAND", "", "", "", ""),
("Grip Strength (dynamometer / comparison)", "Equal", "", "", ""),
]
tbl = doc.add_table(rows=1, cols=5)
tbl.style = "Table Grid"
tbl.autofit = False
hdr = tbl.rows[0]
for i, (h, w) in enumerate(zip(headers, widths)):
cell = hdr.cells[i]
cell.width = Inches(w)
shade_cell(cell, "1F3864")
p = cell.paragraphs[0]
r = p.add_run(h)
r.font.name = "Arial"; r.font.size = Pt(8.5); r.font.bold = True
r.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
for row_data in rows:
row = tbl.add_row()
is_header = row_data[1] == "" and row_data[0] in ("SHOULDER", "ELBOW", "WRIST / HAND")
for i, (val, w) in enumerate(zip(row_data, widths)):
cell = row.cells[i]
cell.width = Inches(w)
if is_header:
shade_cell(cell, "BDD7EE")
p = cell.paragraphs[0]
r = p.add_run(val)
r.font.name = "Arial"
r.font.size = Pt(8.5)
if is_header:
r.font.bold = True; r.font.color.rgb = RGBColor(0x1F, 0x38, 0x64)
return tbl
def make_nerve_table(doc):
headers = ["Nerve", "Motor Test", "Power (/5)", "Sensory Area", "Intact / Impaired"]
widths = [1.5, 2.0, 0.8, 2.0, 1.0]
data = [
("Axillary (C5/6)", "Deltoid abduction vs resistance", "", "Regimental badge area (lat. upper arm)", ""),
("Radial (C6-8)", "Wrist extension, finger/thumb extension", "", "Dorsum hand, 1st dorsal web space", ""),
("Musculocutaneous (C5/6)", "Elbow flexion in supination (biceps)", "", "Lateral forearm", ""),
("Median (C6-T1)", "Wrist flexion, FPL, thenar pinch", "", "Radial 3.5 digits, palm", ""),
("Ulnar (C8/T1)", "Finger abduction/adduction, Froment's sign", "", "Medial 1.5 digits, hypothenar", ""),
]
tbl = doc.add_table(rows=1, cols=5)
tbl.style = "Table Grid"
tbl.autofit = False
hdr = tbl.rows[0]
for i, (h, w) in enumerate(zip(headers, widths)):
cell = hdr.cells[i]
cell.width = Inches(w)
shade_cell(cell, "1F3864")
p = cell.paragraphs[0]
r = p.add_run(h)
r.font.name = "Arial"; r.font.size = Pt(8.5); r.font.bold = True
r.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
for row_data in data:
row = tbl.add_row()
for i, (val, w) in enumerate(zip(row_data, widths)):
cell = row.cells[i]
cell.width = Inches(w)
if i == 0: shade_cell(cell, "EBF3FB")
p = cell.paragraphs[0]
r = p.add_run(val)
r.font.name = "Arial"; r.font.size = Pt(8.5)
if i == 0: r.font.bold = True
return tbl
def make_special_tests_table(doc):
tests = [
("Neer's impingement", "Positive / Negative"),
("Hawkins-Kennedy", "Positive / Negative"),
("Empty Can (supraspinatus)", "Positive / Negative"),
("Drop Arm Test", "Positive / Negative"),
("Lift-Off (subscapularis)", "Positive / Negative"),
("External Rotation Lag Sign", "Positive / Negative"),
("Speed's Test (biceps)", "Positive / Negative"),
("Yergason's Test", "Positive / Negative"),
("Cross-Arm Adduction (AC joint)", "Positive / Negative"),
("Load-and-Shift (instability)", "Grade 0 / 1 / 2 / 3"),
("Sulcus Sign (inferior instability)", "Grade 0 / 1+ / 2+ / 3+"),
("Anterior Apprehension", "Positive / Negative"),
("Posterior Jerk Test", "Positive / Negative"),
("Subacromial Injection Response", "Good / Partial / None"),
]
tbl = doc.add_table(rows=1, cols=4)
tbl.style = "Table Grid"
tbl.autofit = False
widths = [1.9, 1.75, 1.9, 1.75]
for i, (h, w) in enumerate(zip(["Test", "Result", "Test", "Result"], widths)):
cell = tbl.rows[0].cells[i]
cell.width = Inches(w)
shade_cell(cell, "1F3864")
p = cell.paragraphs[0]
r = p.add_run(h)
r.font.name = "Arial"; r.font.size = Pt(8.5); r.font.bold = True
r.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
# fill rows in pairs
for i in range(0, len(tests), 2):
row = tbl.add_row()
t1, v1 = tests[i]
t2, v2 = tests[i+1] if i+1 < len(tests) else ("", "")
for ci, (text, w, bg) in enumerate(zip(
[t1, v1, t2, v2],
widths,
["EBF3FB", "FFFFFF", "EBF3FB", "FFFFFF"]
)):
cell = row.cells[ci]
cell.width = Inches(w)
shade_cell(cell, bg)
p = cell.paragraphs[0]
r = p.add_run(text)
r.font.name = "Arial"; r.font.size = Pt(8.5)
if ci in (0, 2): r.font.bold = True
return tbl
def spacer(doc, pts=4):
p = doc.add_paragraph()
p.paragraph_format.space_before = Pt(0)
p.paragraph_format.space_after = Pt(pts)
return p
# ============================================================
# TITLE HEADER
# ============================================================
tbl_hdr = doc.add_table(rows=1, cols=1)
tbl_hdr.style = "Table Grid"
tbl_hdr.autofit = False
tbl_hdr.columns[0].width = Inches(7.3)
c = tbl_hdr.rows[0].cells[0]
shade_cell(c, "1F3864")
p = c.paragraphs[0]
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
r = p.add_run("ORTHOPAEDIC CLINIC — MALUNION OF THE HUMERUS")
r.font.name = "Arial"; r.font.size = Pt(13); r.font.bold = True
r.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
p.paragraph_format.space_before = Pt(4)
p.paragraph_format.space_after = Pt(4)
spacer(doc, 4)
# ============================================================
# PART 1 — PATIENT DEMOGRAPHICS
# ============================================================
section_bar(doc, "PART 1 — PATIENT DETAILS")
tbl1 = doc.add_table(rows=0, cols=4)
tbl1.style = "Table Grid"
tbl1.autofit = False
widths4 = [1.5, 2.2, 1.5, 2.1]
def add_4col_row(tbl, labels, widths):
row = tbl.add_row()
for i, (lbl, w) in enumerate(zip(labels, widths)):
cell = row.cells[i]
cell.width = Inches(w)
if i % 2 == 0:
shade_cell(cell, "EBF3FB")
p = cell.paragraphs[0]
r = p.add_run(lbl)
r.font.name = "Arial"; r.font.size = Pt(8.5)
if i % 2 == 0: r.font.bold = True
add_4col_row(tbl1, ["Patient Name:", "", "Date:", ""], widths4)
add_4col_row(tbl1, ["Age:", "", "Sex: M / F", ""], widths4)
add_4col_row(tbl1, ["Occupation:", "", "Dominant Hand: R / L", ""], widths4)
add_4col_row(tbl1, ["Referral Source:", "", "Clinician:", ""], widths4)
add_4col_row(tbl1, ["Hospital No:", "", "Clinic:", ""], widths4)
spacer(doc, 4)
# ============================================================
# PART 2 — HISTORY
# ============================================================
section_bar(doc, "PART 2 — HISTORY")
sub_bar(doc, "2A. Chief Complaints (tick all that apply)")
items_cc = ["Pain", "Deformity / cosmesis", "Weakness", "Stiffness / restricted ROM",
"Numbness / tingling", "Inability to perform ADLs", "Night pain", "Other: ________"]
make_check_table(doc, items_cc, cols=4)
spacer(doc, 4)
sub_bar(doc, "2B. Original Injury")
make_two_col_table(doc, [
("Date of original injury:", ""),
("Mechanism:", "Fall on outstretched hand / direct blow / RTA / pathological / other"),
("Energy level:", "Low velocity / High velocity"),
("Fracture type:", "Proximal humerus / Shaft / Distal humerus / Supracondylar"),
("Open or closed:", "Open / Closed"),
("Level of malunion:", "Head-shaft / Tuberosity / Diaphyseal / Distal"),
], col1_w=2.4, col2_w=4.9)
spacer(doc, 4)
sub_bar(doc, "2C. Previous Treatment")
make_two_col_table(doc, [
("Treatment given:", "Non-operative: Sling / Cast / Brace Operative: ORIF / IMN / Arthroplasty"),
("Implant used (if operative):", ""),
("Duration of immobilisation:", ""),
("Date fracture declared united:", ""),
("Previous nerve palsy at time of injury:", "Yes / No — nerve: ________________"),
("Previous vascular injury:", "Yes / No"),
("Infection / wound complications:", "Yes / No — details: _______________"),
], col1_w=2.8, col2_w=4.5)
spacer(doc, 4)
sub_bar(doc, "2D. Current Symptoms")
make_two_col_table(doc, [
("Pain — Site:", "Anterior deltoid / Lateral arm / Elbow / Forearm / Other: _______"),
("Pain — Character:", "Aching / Sharp / Burning / Throbbing"),
("Pain — Aggravated by:", "Overhead activity / Abduction / Forward flexion / Internal rotation / Lifting"),
("Pain — Relieved by:", "Rest / Analgesia / Sling / Other: _______"),
("Pain — Night pain:", "Yes / No"),
("VAS / NRS score (0-10):", " /10"),
("Stiffness — direction:", "Flexion / Abduction / ER / IR"),
("Weakness — movement:", "Abduction / ER / IR / Elbow flexion / Extension"),
("Paraesthesia / numbness:", "Distribution: ______________________ Constant / Intermittent"),
("Duration of symptoms:", ""),
("Progression:", "Getting worse / Static / Improving"),
], col1_w=2.8, col2_w=4.5)
spacer(doc, 4)
sub_bar(doc, "2E. Functional Assessment")
make_two_col_table(doc, [
("Can dress independently:", "Yes / No / With difficulty"),
("Can comb hair / reach shelf:", "Yes / No / With difficulty"),
("Can carry shopping / lift:", "Yes / No / With difficulty"),
("Occupational impact:", "None / Restricted duties / Unable to work"),
("Sport / recreational impact:", "None / Reduced / Unable to participate"),
("DASH Score:", " /100 (complete separately)"),
("Constant-Murley Score:", " /100 (complete separately)"),
("Oxford Shoulder Score:", " /48 (complete separately)"),
], col1_w=2.8, col2_w=4.5)
spacer(doc, 4)
sub_bar(doc, "2F. Past Medical History")
make_two_col_table(doc, [
("Previous fractures same limb:", "Yes / No — details: _______________"),
("Previous shoulder / elbow surgery:", "Yes / No — details: _______________"),
("Osteoporosis / metabolic bone disease:", "Yes / No"),
("Diabetes mellitus:", "Yes / No — HbA1c: _______"),
("Rheumatoid arthritis / inflammatory:", "Yes / No"),
("Malignancy:", "Yes / No — type: _______________"),
("Peripheral neuropathy:", "Yes / No"),
("Other relevant conditions:", ""),
], col1_w=2.8, col2_w=4.5)
spacer(doc, 4)
sub_bar(doc, "2G. Drug, Social & Family History")
make_two_col_table(doc, [
("Current analgesics:", ""),
("Steroids / bisphosphonates / DMARDs:", "Yes / No — details: _______________"),
("Anticoagulants:", "Yes / No — agent: _______________"),
("Smoking:", "Non-smoker / Ex-smoker / Current: ___ pack-years"),
("Alcohol:", "Units/week: _______"),
("Living situation:", "Independent / Family support / Carer"),
("Family history (metabolic bone disease):", "Yes / No — details: _______________"),
], col1_w=2.8, col2_w=4.5)
spacer(doc, 6)
# ============================================================
# PART 3 — EXAMINATION
# ============================================================
section_bar(doc, "PART 3 — CLINICAL EXAMINATION")
sub_bar(doc, "3A. General Inspection")
make_two_col_table(doc, [
("General build / nutritional status:", ""),
("Cervical spine deformity:", "None / Restricted — exclude referred pain"),
("Compensatory posture:", "None / Protracted shoulder / Head tilt / Other"),
], col1_w=2.8, col2_w=4.5)
spacer(doc, 4)
sub_bar(doc, "3B. LOOK (Inspection — both arms exposed)")
make_two_col_table(doc, [
("Shoulder asymmetry:", "None / Lowered / Protracted / Elevated (affected side)"),
("Deltoid bulk:", "Normal / Wasted (axillary nerve / disuse)"),
("Supraspinatus / infraspinatus fossa:", "Normal / Wasted (suprascapular nerve / cuff)"),
("Visible deformity:", "None / Varus / Valgus / Anterior bow / Rotational / Cubitus varus"),
("Scars / sinuses:", "None / Anterior / Lateral / Posterior / Sinus present"),
("Swelling / callus:", "None / Localised — site: _______________"),
("Scapular winging:", "None / Present (long thoracic nerve)"),
("Skin changes:", "Normal / Erythema / Skin tenting / Trophic changes"),
("Greater tuberosity prominence:", "Not visible / Visible"),
("Carrying angle (elbow):", "Normal / Cubitus varus / Cubitus valgus — degrees: ______"),
], col1_w=2.8, col2_w=4.5)
spacer(doc, 4)
sub_bar(doc, "3C. FEEL (Palpation)")
make_two_col_table(doc, [
("Sternoclavicular joint:", "Non-tender / Tender"),
("Clavicle:", "Intact / Tender / Step deformity"),
("Acromioclavicular joint:", "Non-tender / Tender / Step"),
("Acromion process:", "Non-tender / Tender"),
("Coracoid process:", "Non-tender / Tender"),
("Greater tuberosity:", "Normal position / Superior migration / Post-medial"),
("Bicipital groove / biceps tendon:", "Non-tender / Tender"),
("Glenohumeral joint line:", "Anterior: ______ Posterior: ______"),
("Humeral shaft palpation:", "No tenderness / Tender at: ______ Step / Callus / Angulation"),
("Lateral epicondyle:", "Non-tender / Tender"),
("Medial epicondyle:", "Non-tender / Tender / Tinel's sign present"),
("Limb length — acromion to lat. epicondyle:", "Affected: _____ cm Contralateral: _____ cm"),
("Mid-arm girth (deltoid level):", "Affected: _____ cm Contralateral: _____ cm"),
("Local temperature:", "Normal / Warm (infection?) / Cold (vascular?)"),
], col1_w=2.8, col2_w=4.5)
spacer(doc, 4)
sub_bar(doc, "3D. MOVE — Range of Motion (degrees, active / passive)")
make_rom_table(doc)
spacer(doc, 4)
sub_bar(doc, "3E. Special Tests (Shoulder)")
make_special_tests_table(doc)
spacer(doc, 4)
sub_bar(doc, "3F. Neurological Examination")
make_nerve_table(doc)
spacer(doc, 4)
# Additional neuro
make_two_col_table(doc, [
("Biceps reflex (C5/6):", "Normal / Reduced / Absent — Affected / Contralateral"),
("Brachioradialis reflex (C6):", "Normal / Reduced / Absent — Affected / Contralateral"),
("Triceps reflex (C7):", "Normal / Reduced / Absent — Affected / Contralateral"),
("Wrist drop present:", "Yes / No"),
("Finger / thumb extension loss:", "Yes / No"),
("Froment's sign:", "Positive / Negative"),
("Tinel's sign at medial epicondyle:", "Positive / Negative"),
("Elbow flexion test:", "Positive / Negative"),
("Cervical Spurling's test:", "Positive / Negative (exclude cervical root)"),
("Upper Limb Tension Test (ULTT):", "Positive / Negative"),
("Adson's maneuver (thoracic outlet):", "Positive / Negative"),
], col1_w=2.8, col2_w=4.5)
spacer(doc, 4)
sub_bar(doc, "3G. Vascular Examination")
make_two_col_table(doc, [
("Radial pulse — affected:", "Present / Absent / Diminished"),
("Radial pulse — contralateral:", "Present / Absent / Diminished"),
("Capillary refill time:", "< 2 sec / > 2 sec"),
("Skin colour / temperature:", "Normal / Pallor / Mottled / Cold"),
("Brachial pulse:", "Present / Absent"),
("Doppler required:", "Yes / No"),
], col1_w=2.8, col2_w=4.5)
spacer(doc, 6)
# ============================================================
# PART 4 — INVESTIGATIONS
# ============================================================
section_bar(doc, "PART 4 — INVESTIGATIONS")
sub_bar(doc, "4A. Imaging Requested")
items_img = [
"AP X-ray (affected side)",
"Lateral X-ray (affected side)",
"AP X-ray (contralateral — for comparison)",
"Lateral X-ray (contralateral)",
"CT with 3D reconstruction",
"MRI shoulder",
"USS (rotator cuff assessment)",
"CT angiogram",
]
make_check_table(doc, items_img, cols=4)
spacer(doc, 4)
sub_bar(doc, "4B. Radiographic Parameters (to complete after imaging)")
make_two_col_table(doc, [
("Neck-shaft angle (normal 130-140°):", "______° Varus / Normal / Valgus"),
("Greater tuberosity position:", "Normal / Superior migration ____mm / Posteromedial"),
("Head retroversion (normal 20-30°):", "______°"),
("Angular deformity — shaft:", "Anterior / Posterior / Varus / Valgus — ______°"),
("Rotational deformity:", "Internal / External — ______°"),
("Shortening:", "______ mm"),
("Carrying angle (elbow):", "______° Normal / Cubitus varus / Cubitus valgus"),
("Intra-articular involvement:", "Yes / No — site: _______________"),
("Hardware present:", "Yes / No — type: _______________"),
("Signs of osteonecrosis:", "None / Early collapse / Advanced"),
("Degenerative changes:", "None / Mild / Moderate / Severe"),
("Rotator cuff on MRI:", "Intact / Partial tear / Full thickness tear / Atrophy"),
], col1_w=2.8, col2_w=4.5)
spacer(doc, 4)
sub_bar(doc, "4C. Laboratory Investigations")
items_lab = [
"FBC", "ESR", "CRP", "Blood cultures",
"Bone profile (Ca, PO4, ALP)", "Vitamin D", "HbA1c",
"Joint aspirate — MC&S", "Other: ___________",
]
make_check_table(doc, items_lab, cols=3)
spacer(doc, 6)
# ============================================================
# PART 5 — SUMMARY & PLAN
# ============================================================
section_bar(doc, "PART 5 — SUMMARY AND MANAGEMENT PLAN")
sub_bar(doc, "5A. Diagnosis / Impression")
tbl_dx = doc.add_table(rows=1, cols=1)
tbl_dx.style = "Table Grid"
tbl_dx.autofit = False
tbl_dx.columns[0].width = Inches(7.3)
cell = tbl_dx.rows[0].cells[0]
p = cell.paragraphs[0]
for _ in range(3):
p.add_run("\n")
p.paragraph_format.space_before = Pt(4)
p.paragraph_format.space_after = Pt(4)
spacer(doc, 4)
sub_bar(doc, "5B. Management Plan")
items_plan = [
"Observation / watchful waiting",
"Analgesia optimisation",
"Physiotherapy / shoulder rehab programme",
"Activity modification",
"Subacromial corticosteroid injection",
"Corrective osteotomy",
"Rotator cuff repair / tuberosity osteotomy",
"Reverse shoulder arthroplasty",
"Hemiarthroplasty",
"Nerve exploration / decompression",
"Ulnar nerve transposition (tardy palsy)",
"Further imaging / investigations",
"Multidisciplinary team discussion",
"Referral: ___________________________",
]
make_check_table(doc, items_plan, cols=2)
spacer(doc, 4)
sub_bar(doc, "5C. Follow-up & Notes")
tbl_notes = doc.add_table(rows=1, cols=1)
tbl_notes.style = "Table Grid"
tbl_notes.autofit = False
tbl_notes.columns[0].width = Inches(7.3)
cell_n = tbl_notes.rows[0].cells[0]
pn = cell_n.paragraphs[0]
for _ in range(5):
pn.add_run("\n")
pn.paragraph_format.space_before = Pt(4)
pn.paragraph_format.space_after = Pt(4)
spacer(doc, 4)
make_two_col_table(doc, [
("Follow-up appointment:", ""),
("Clinician signature:", ""),
], col1_w=2.8, col2_w=4.5)
spacer(doc, 6)
# ── Footer note ──────────────────────────────────────────────────────────────
p_foot = doc.add_paragraph()
p_foot.alignment = WD_ALIGN_PARAGRAPH.CENTER
r_foot = p_foot.add_run(
"Based on Rockwood & Green's Fractures in Adults 10th Ed. | Campbell's Operative Orthopaedics 15th Ed. | "
"Bailey & Love's Surgery 28th Ed. | Version 1.0 — July 2026"
)
r_foot.font.name = "Arial"
r_foot.font.size = Pt(7)
r_foot.font.color.rgb = RGBColor(0x88, 0x88, 0x88)
# ── Save ─────────────────────────────────────────────────────────────────────
out_path = "/tmp/workspace/humerus-malunion-proforma/Humerus_Malunion_Clinic_Proforma.docx"
doc.save(out_path)
print(f"Saved: {out_path}")
cd /tmp/workspace/humerus-malunion-proforma && python3 build_proforma.py
python3 -c " from docx import Document doc = Document('/tmp/workspace/humerus-malunion-proforma/Humerus_Malunion_Clinic_Proforma.docx') print(f'Paragraphs: {len(doc.paragraphs)}') print(f'Tables: {len(doc.tables)}') # Print first few headings for p in doc.paragraphs[:10]: if p.text.strip(): print(f'[{p.style.name}] {p.text[:80]}') "
ls -lh /tmp/workspace/humerus-malunion-proforma/Humerus_Malunion_Clinic_Proforma.docx
Humerus Malunion Clinic Proforma
Word Document · DOCX
| Section | Content |
|---|---|
| Header | Dark blue title bar — "Orthopaedic Clinic — Malunion of the Humerus" |
| Part 1 — Patient Details | Name, age, sex, occupation, dominant hand, hospital number, date |
| Part 2 — History | Chief complaints (tick-boxes), original injury details, previous treatment, current symptoms (pain/stiffness/weakness/neuro), functional assessment with score fields (DASH, Constant, Oxford), PMH, drug/social/family history |
| Part 3 — Examination | General inspection; Look (asymmetry, atrophy, deformity, scars, carrying angle); Feel (full palpation sequence, limb length, girth); Move (ROM table with normal values vs. affected vs. contralateral); Special tests table (Neer, Hawkins, empty can, drop arm, apprehension, sulcus sign, subacromial injection response, etc.); Neurological table (axillary, radial, musculocutaneous, median, ulnar — motor power + sensory); reflexes, wrist drop, Froment's, Tinel's, Spurling's, ULTT, Adson's; Vascular |
| Part 4 — Investigations | Imaging tick-boxes; radiographic parameters (neck-shaft angle, tuberosity position, angulation, shortening, retroversion); lab tick-boxes |
| Part 5 — Plan | Diagnosis free-text box; management tick-boxes (conservative through to RSA, nerve surgery); follow-up and notes box; clinician signature |