supraclavicular block and axillary block indetails with images of textbook and which nerve block what spare everything in details make pdf
mkdir -p /tmp/workspace/nerve-blocks-pdf/images && ls /tmp/workspace/nerve-blocks-pdf/
cd /tmp/workspace/nerve-blocks-pdf/images && python3 -c " import urllib.request images = { 'supra_anatomy.png': 'https://cdn.orris.care/cdss_images/0c32a987325ffb358716b14041fefc1986e50ca6615d8ed0762df696bacf2e59.png', 'supra_positioning.png': 'https://cdn.orris.care/cdss_images/5c9e9ce34c4468058873b8c1a7940e546b1dbc46895ab320217d6874e4b7ea34.png', 'supra_ultrasound.png': 'https://cdn.orris.care/cdss_images/f7e24d70664146453d2a9a4b091907aad17271d302dedf5c908f0e1e8ad431e9.png', 'axillary_cross_section.png': 'https://cdn.orris.care/cdss_images/9a2f92c06abdbdf4d9f28b98cdd461129eeddd793362677372cc7eb1cea3eeaa.png', 'axillary_spared.png': 'https://cdn.orris.care/cdss_images/2bf364d6fe2befa8197dba445e573586b0c0de81ac01cdc680bcada60d25efb8.png', 'axillary_multiple_inject.png': 'https://cdn.orris.care/cdss_images/003b9b9bcbb8719de029fe2ebfbe6e61b2db3afe0e86194b3bdd447312b9f0a4.png', 'brachial_distribution.png': 'https://cdn.orris.care/cdss_images/ea3d0a327f4a5172f01a9b718ccdcbf32772a1603a81ddcffd25d24a8cc0b836.png', } for name, url in images.items(): urllib.request.urlretrieve(url, name) print(f'Downloaded: {name}') "
~/nerve-blocks-pdf/generate_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm, mm
from reportlab.lib import colors
from reportlab.platypus import (SimpleDocTemplate, Paragraph, Spacer, Image,
Table, TableStyle, PageBreak, HRFlowable,
KeepTogether)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus.tableofcontents import TableOfContents
from reportlab.pdfgen import canvas
import os
OUTPUT = "/tmp/workspace/nerve-blocks-pdf/Supraclavicular_Axillary_Nerve_Blocks.pdf"
IMG_DIR = "/tmp/workspace/nerve-blocks-pdf/images/"
# ─── Color palette ───────────────────────────────────────────────────────────
BLUE_DARK = colors.HexColor("#1a3a5c")
BLUE_MID = colors.HexColor("#2e6da4")
BLUE_LIGHT = colors.HexColor("#ddeeff")
TEAL = colors.HexColor("#007b7f")
ORANGE = colors.HexColor("#e07020")
RED_WARN = colors.HexColor("#cc2222")
GREY_BG = colors.HexColor("#f4f6f8")
GREY_LINE = colors.HexColor("#cccccc")
WHITE = colors.white
BLACK = colors.black
# ─── Styles ──────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
def S(name, **kw):
return ParagraphStyle(name, **kw)
COVER_TITLE = S("CoverTitle", fontSize=32, fontName="Helvetica-Bold",
textColor=WHITE, alignment=TA_CENTER, leading=40, spaceAfter=8)
COVER_SUB = S("CoverSub", fontSize=18, fontName="Helvetica",
textColor=colors.HexColor("#cce0ff"), alignment=TA_CENTER, leading=26)
COVER_DATE = S("CoverDate", fontSize=11, fontName="Helvetica",
textColor=colors.HexColor("#aaccee"), alignment=TA_CENTER)
H1 = S("H1", fontSize=20, fontName="Helvetica-Bold", textColor=WHITE,
spaceBefore=4, spaceAfter=4, leading=24)
H2 = S("H2", fontSize=15, fontName="Helvetica-Bold", textColor=BLUE_DARK,
spaceBefore=14, spaceAfter=6, leading=20)
H3 = S("H3", fontSize=12, fontName="Helvetica-Bold", textColor=TEAL,
spaceBefore=10, spaceAfter=4, leading=16)
BODY = S("BODY", fontSize=10, fontName="Helvetica", leading=15,
spaceAfter=6, textColor=colors.HexColor("#222222"), alignment=TA_JUSTIFY)
BULLET = S("BULLET", fontSize=10, fontName="Helvetica", leading=14,
leftIndent=18, spaceAfter=3, bulletIndent=6,
textColor=colors.HexColor("#222222"))
CAPTION = S("CAPTION", fontSize=8.5, fontName="Helvetica-Oblique",
textColor=colors.HexColor("#555555"), alignment=TA_CENTER,
spaceBefore=2, spaceAfter=8)
TABLE_HDR = S("TH", fontSize=9, fontName="Helvetica-Bold", textColor=WHITE,
alignment=TA_CENTER)
TABLE_CELL = S("TC", fontSize=9, fontName="Helvetica", textColor=BLACK,
alignment=TA_LEFT, leading=12)
WARN_BOX = S("WARN", fontSize=9.5, fontName="Helvetica", textColor=RED_WARN,
leading=14, leftIndent=8)
INFO_BOX = S("INFO", fontSize=9.5, fontName="Helvetica", textColor=BLUE_DARK,
leading=14, leftIndent=8)
SOURCE = S("SOURCE", fontSize=7.5, fontName="Helvetica-Oblique",
textColor=colors.grey, alignment=TA_RIGHT, spaceAfter=0)
# ─── Helper builders ─────────────────────────────────────────────────────────
def img(fname, width=14*cm, caption="", src=""):
path = IMG_DIR + fname
if not os.path.exists(path):
return []
elems = [Spacer(1, 4*mm)]
try:
im = Image(path, width=width, height=None)
# fix aspect
from PIL import Image as PILImage
with PILImage.open(path) as pil:
w0, h0 = pil.size
ratio = h0 / w0
im = Image(path, width=width, height=width * ratio)
elems.append(im)
except Exception:
elems.append(Image(path, width=width))
if caption:
elems.append(Paragraph(caption, CAPTION))
if src:
elems.append(Paragraph(src, SOURCE))
return elems
def section_header(title, color=BLUE_DARK):
"""Colored banner heading."""
tbl = Table([[Paragraph(title, H1)]], colWidths=[17*cm])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), color),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 12),
("ROUNDEDCORNERS", [4, 4, 4, 4]),
]))
return [Spacer(1, 6*mm), tbl, Spacer(1, 4*mm)]
def info_box(title, items, color=BLUE_LIGHT, title_color=BLUE_DARK):
rows = [[Paragraph(f"<b>{title}</b>", S("IBH", fontSize=10,
fontName="Helvetica-Bold", textColor=title_color))]]
for it in items:
rows.append([Paragraph(f"• {it}", TABLE_CELL)])
tbl = Table(rows, colWidths=[16.5*cm])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), color),
("BACKGROUND", (0,0), (-1,0), colors.HexColor("#c0d8f0")),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 10),
("BOX", (0,0), (-1,-1), 0.5, BLUE_MID),
("LINEBELOW", (0,0), (-1,0), 0.5, BLUE_MID),
]))
return [tbl, Spacer(1, 3*mm)]
def warn_box(title, items):
rows = [[Paragraph(f"⚠ {title}", S("WBH", fontSize=10,
fontName="Helvetica-Bold", textColor=RED_WARN))]]
for it in items:
rows.append([Paragraph(f"• {it}", TABLE_CELL)])
tbl = Table(rows, colWidths=[16.5*cm])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), colors.HexColor("#fff5f5")),
("BACKGROUND", (0,0), (-1,0), colors.HexColor("#ffe0e0")),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 10),
("BOX", (0,0), (-1,-1), 0.5, RED_WARN),
("LINEBELOW", (0,0), (-1,0), 0.5, RED_WARN),
]))
return [tbl, Spacer(1, 3*mm)]
def comparison_table(headers, rows, col_widths):
data = [[Paragraph(h, TABLE_HDR) for h in headers]]
for row in rows:
data.append([Paragraph(str(c), TABLE_CELL) for c in row])
tbl = Table(data, colWidths=col_widths, repeatRows=1)
style = TableStyle([
("BACKGROUND", (0,0), (-1,0), BLUE_DARK),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, GREY_BG]),
("GRID", (0,0), (-1,-1), 0.4, GREY_LINE),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
])
tbl.setStyle(style)
return [tbl, Spacer(1, 4*mm)]
def hr():
return [HRFlowable(width="100%", thickness=0.5, color=GREY_LINE, spaceAfter=4)]
# ─── Page numbering ───────────────────────────────────────────────────────────
class NumberedCanvas(canvas.Canvas):
def __init__(self, *args, **kwargs):
canvas.Canvas.__init__(self, *args, **kwargs)
self._saved_page_states = []
def showPage(self):
self._saved_page_states.append(dict(self.__dict__))
self._startPage()
def save(self):
num_pages = len(self._saved_page_states)
for state in self._saved_page_states:
self.__dict__.update(state)
self.draw_page_number(num_pages)
canvas.Canvas.showPage(self)
canvas.Canvas.save(self)
def draw_page_number(self, page_count):
if self._pageNumber == 1:
return
self.setFont("Helvetica", 8)
self.setFillColor(colors.grey)
self.drawRightString(
A4[0] - 2*cm, 1.5*cm,
f"Page {self._pageNumber} of {page_count}")
self.drawString(2*cm, 1.5*cm,
"Supraclavicular & Axillary Nerve Blocks — Comprehensive Reference")
self.setStrokeColor(GREY_LINE)
self.setLineWidth(0.5)
self.line(2*cm, 1.9*cm, A4[0]-2*cm, 1.9*cm)
# ─── Document ────────────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
OUTPUT, pagesize=A4,
leftMargin=2*cm, rightMargin=2*cm,
topMargin=2.2*cm, bottomMargin=2.5*cm,
title="Supraclavicular and Axillary Nerve Blocks",
author="Compiled from Morgan & Mikhail, Miller's Anesthesia, Barash, Campbell's"
)
story = []
# ════════════════════════════════════════════════════════════════════════════
# COVER PAGE
# ════════════════════════════════════════════════════════════════════════════
def cover_page():
from reportlab.platypus import Frame
cover = []
# Blue gradient box via table
cover_table = Table([
[Paragraph("REGIONAL ANESTHESIA", COVER_DATE)],
[Spacer(1, 6*mm)],
[Paragraph("Supraclavicular Block", COVER_TITLE)],
[Paragraph("&", COVER_TITLE)],
[Paragraph("Axillary Block", COVER_TITLE)],
[Spacer(1, 4*mm)],
[Paragraph("Comprehensive Clinical Reference with Textbook Images", COVER_SUB)],
[Spacer(1, 10*mm)],
[Paragraph("Nerves Blocked • Nerves Spared • Techniques • Complications", COVER_DATE)],
[Spacer(1, 6*mm)],
[Paragraph("Sources: Morgan & Mikhail's Clinical Anesthesiology 7e | Miller's Anesthesia 10e", COVER_DATE)],
[Paragraph("Barash Clinical Anesthesia 9e | Campbell's Operative Orthopaedics 15e | Pye's Surgical Handicraft 22e", COVER_DATE)],
[Spacer(1, 8*mm)],
[Paragraph("August 2026", COVER_DATE)],
], colWidths=[17*cm])
cover_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), BLUE_DARK),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 20),
("RIGHTPADDING", (0,0), (-1,-1), 20),
("ROUNDEDCORNERS", [8, 8, 8, 8]),
]))
cover.append(Spacer(1, 3*cm))
cover.append(cover_table)
cover.append(PageBreak())
return cover
story += cover_page()
# ════════════════════════════════════════════════════════════════════════════
# SECTION 0 — BRACHIAL PLEXUS OVERVIEW
# ════════════════════════════════════════════════════════════════════════════
story += section_header("1. Brachial Plexus — Anatomy Overview", BLUE_DARK)
story.append(Paragraph(
"Both the supraclavicular and axillary blocks target the brachial plexus, "
"which arises from the anterior rami of C5–T1. Understanding the level at which "
"local anesthetic is deposited determines which nerves are blocked and which are spared.",
BODY))
story += img("supra_anatomy.png", width=14*cm,
caption="FIGURE 1: Brachial plexus anatomy showing roots (C4–T1), trunks, divisions, cords, and terminal branches. "
"The supraclavicular block (probe shown) targets the trunks/divisions level.",
src="Source: Morgan & Mikhail's Clinical Anesthesiology, 7e — Figure 46-12")
story.append(Paragraph(
"<b>Key anatomical levels relevant to upper limb blocks:</b>", H3))
story += comparison_table(
["Level", "Brachial Plexus Structure", "Block Applied"],
[
["Interscalene groove (neck)", "Roots/Trunks (C5–C7 mainly)", "Interscalene block"],
["Above clavicle", "Trunks → Divisions", "Supraclavicular block"],
["Below clavicle / coracoid", "Cords", "Infraclavicular block"],
["Axilla (lateral border pect. minor)", "Terminal branches", "Axillary block"],
],
[5.5*cm, 6*cm, 5.5*cm]
)
story += img("brachial_distribution.png", width=15*cm,
caption="FIGURE 2: Distribution of brachial plexus blocks — A) Interscalene, B) Supraclavicular, "
"C) Infraclavicular (single injection), D) Axillary (multiple injections + high humeral block). "
"Pink shading = anesthetized region.",
src="Source: Campbell's Operative Orthopaedics, 15e — Figure 69.4")
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# SECTION 1 — SUPRACLAVICULAR BLOCK
# ════════════════════════════════════════════════════════════════════════════
story += section_header("2. Supraclavicular Block", TEAL)
story.append(Paragraph("<b>Overview</b>", H2))
story.append(Paragraph(
'The supraclavicular block has been described as the "spinal of the arm" — it offers dense '
'anesthesia of the brachial plexus with relatively rapid onset and reliability. The block '
'targets the plexus at the distal trunk / proximal division level, where the trunks are '
'most compact, allowing a small volume of local anesthetic to produce reliable blockade. '
'It provides anesthesia for procedures at or distal to the elbow.',
BODY))
# Indications
story += info_box("Indications", [
"Surgery at or distal to the elbow (forearm, wrist, hand)",
"Elbow surgery",
"Upper arm surgery (distal to shoulder)",
"NOT ideal for shoulder surgery (suprascapular nerve not reliably blocked) — combine with suprascapular nerve block if needed",
], color=BLUE_LIGHT)
# 2.1 Nerves blocked / spared
story.append(Paragraph("2.1 Nerves Blocked and Nerves Spared", H2))
story += comparison_table(
["Nerve / Structure", "Status", "Clinical Consequence"],
[
["Upper trunk (C5–C6) — musculocutaneous, axillary, radial (partial)", "BLOCKED", "Shoulder/elbow flexion, forearm flexion anesthetized"],
["Middle trunk (C7) — radial, median (partial)", "BLOCKED", "Wrist/finger extension, median distribution anesthetized"],
["Lower trunk (C8–T1) — ulnar, median", "BLOCKED (variable)", "Ulnar deviation, intrinsics; may be spared if lower trunk not visualized on US"],
["Suprascapular nerve (C5–C6)", "SPARED", "Shoulder joint not fully anesthetized — supplement for shoulder sx"],
["Phrenic nerve (C3–C4)", "BLOCKED (~40–50%)", "Ipsilateral hemidiaphragm paralysis — avoid bilateral or in severe COPD/contralateral phrenic palsy"],
["Recurrent laryngeal nerve", "Occasional block", "Hoarseness"],
["Cervical sympathetic chain", "Occasional block", "Horner syndrome (ptosis, miosis, anhidrosis)"],
["Intercostobrachial nerve (T2)", "SPARED", "Medial upper arm sensation preserved"],
],
[4.5*cm, 3*cm, 8.5*cm]
)
story.append(Paragraph(
"<b>Note on ulnar nerve sparing:</b> Sparing of distal branches, most commonly the "
"<i>ulnar nerve</i>, may occur. This can be avoided by carefully tracing the plexus "
"cephalad and caudad with ultrasound to identify the lower trunk and ensure it is anesthetized "
"(Morgan & Mikhail, 7e).",
BODY))
# 2.2 Anatomy
story.append(Paragraph("2.2 Relevant Anatomy", H2))
story.append(Paragraph(
"The brachial plexus trunks gather at the lower part of the interscalene space, surrounding "
"the subclavian artery. At the supraclavicular level the trunks/divisions appear as a "
'<i>"cluster of grapes"</i> (multiple hypoechoic disks) just superficial, posterior, and '
"lateral to the subclavian artery. The first rib acts as a medial barrier, protecting the "
"needle from reaching the pleural dome — but pneumothorax remains a recognized risk.",
BODY))
# Ultrasound view
story += img("supra_ultrasound.png", width=13*cm,
caption="FIGURE 3: Ultrasound image of supraclavicular block. Gold = brachial plexus trunks/divisions "
"(hypoechoic cluster). Red = subclavian artery. White arrow = first rib (hyperechoic). "
"Top right: color Doppler showing artery.",
src="Source: Miller's Anesthesia, 10e — Fig. 74.18")
# 2.3 Patient Positioning & Technique
story.append(Paragraph("2.3 Patient Positioning", H2))
story += info_box("Positioning Steps", [
"Patient supine, head turned 30° toward the contralateral side",
"Arm adducted against the side of the body (for US-guided technique)",
"Alternative landmark technique: arm abducted ~45°, sustained traction to relax neck muscles",
], color=GREY_BG, title_color=TEAL)
# Positioning image
story += img("supra_positioning.png", width=10*cm,
caption="FIGURE 4: Supraclavicular block positioning — linear high-frequency transducer "
"placed in supraclavicular fossa, needle advanced in-plane from lateral to medial.",
src="Source: Morgan & Mikhail's Clinical Anesthesiology, 7e — Figure 46-13")
# 2.4 Ultrasound-Guided Technique
story.append(Paragraph("2.4 Ultrasound-Guided Technique", H2))
story.append(Paragraph(
"A high-frequency linear transducer (15 MHz or higher) is placed in the supraclavicular fossa, "
"superior to the clavicle, angled slightly toward the thorax (coronal oblique plane). The "
"subclavian artery is easily identified as a pulsatile hypoechoic circle. The brachial plexus "
"appears as a cluster of hypoechoic nodules lateral, posterior, and superior to the artery, "
"just above the hyperechoic first rib.",
BODY))
story.append(Paragraph(
"The needle is advanced under direct visualization using an <b>in-plane approach from lateral "
"to medial</b> toward the angle formed by the first rib and the subclavian artery. After negative "
"aspiration, local anesthetic (15–30 mL) is deposited around the plexus cluster. Color Doppler "
"should be used to identify surrounding vessels (suprascapular artery, dorsal scapular artery) "
"and avoid inadvertent intravascular injection.",
BODY))
story.append(Paragraph("<b>Confirmation of success (pre-block nerve testing):</b>", H3))
story += info_box("Pre-Block Nerve Integrity Test", [
"Thumbs up gesture — radial nerve (C6–C8)",
'Making an "O" with thumb and index finger — median nerve (C6–T1)',
"Scissoring index and third digit — ulnar nerve (C8–T1)",
], color=colors.HexColor("#e8f5e9"), title_color=TEAL)
# 2.5 Local Anesthetic
story.append(Paragraph("2.5 Local Anesthetic", H2))
story += comparison_table(
["Agent", "Volume", "Onset", "Duration"],
[
["Bupivacaine 0.5%", "15–20 mL", "20–30 min", "8–16 h"],
["Ropivacaine 0.5–0.75%", "15–25 mL", "15–25 min", "8–14 h"],
["Lidocaine 1–1.5% ± epi", "15–30 mL", "10–20 min", "3–5 h"],
["Mepivacaine 1.5%", "15–25 mL", "10–15 min", "4–6 h"],
["Pediatric dose (all agents)", "0.2 mL/kg", "Variable", "Variable"],
],
[4*cm, 3*cm, 3*cm, 5*cm]
)
story.append(Paragraph(
"Note: Use minimal effective volume — higher volumes may cause ischemic compression "
"of neural elements in the compact supraclavicular fossa (Miller's, 10e).",
BODY))
# 2.6 Complications
story.append(Paragraph("2.6 Complications and Contraindications", H2))
story += warn_box("Complications", [
"Pneumothorax — 0.5% to 6%; most serious complication. Risk reduced (not eliminated) with US guidance.",
"Phrenic nerve palsy — ~40–60%. Avoid in patients with contralateral phrenic palsy, severe COPD, or morbid obesity.",
"Horner syndrome — ipsilateral ptosis, miosis, anhidrosis; usually transient.",
"Recurrent laryngeal nerve block — hoarseness.",
"Subclavian artery puncture — use color Doppler to identify vessels.",
"Local anesthetic systemic toxicity (LAST) — vascular proximity high; always aspirate.",
"Ulnar nerve sparing — monitor lower trunk spread on US.",
"Perineural catheter: inferior to infraclavicular; more prone to displacement.",
])
story += info_box("Relative Contraindications", [
"Contralateral phrenic nerve palsy (phrenic palsy on both sides = respiratory failure)",
"Severe COPD / restricted pulmonary reserve (bilateral diaphragm contribution critical)",
"Uncooperative patients",
"Coagulopathy / anticoagulation (relative)",
"Local infection at site",
"Pre-existing significant brachial plexus neuropathy",
], color=colors.HexColor("#fff8e1"), title_color=ORANGE)
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# SECTION 2 — AXILLARY BLOCK
# ════════════════════════════════════════════════════════════════════════════
story += section_header("3. Axillary Block", BLUE_MID)
story.append(Paragraph("<b>Overview</b>", H2))
story.append(Paragraph(
"The axillary block approaches the brachial plexus at the level of its terminal branches, "
"in the axilla at the lateral border of pectoralis minor. It is one of the safest brachial "
"plexus blocks (no risk of pneumothorax, no phrenic nerve block) and provides reliable "
"anesthesia of the forearm and hand. Its principal limitation is sparing of nerves that "
"branch proximal to the axilla: the musculocutaneous nerve, axillary nerve, medial brachial "
"cutaneous nerve, and the intercostobrachial nerve.",
BODY))
# Cross-section
story += img("axillary_cross_section.png", width=14*cm,
caption="FIGURE 5: Cross-sectional anatomy of the axilla. The axillary artery (red) is "
"surrounded by median n. (superolateral), ulnar n. (superomedial), and radial n. "
"(inferior/posterior). The axillary vein (blue) lies medial to the artery. "
"Musculocutaneous n. and intercostobrachial n. lie outside the neurovascular sheath.",
src="Source: Morgan & Mikhail's Clinical Anesthesiology, 7e — Figure 46-18")
# 3.1 Nerves Blocked / Spared
story.append(Paragraph("3.1 Nerves Blocked and Nerves Spared", H2))
story += comparison_table(
["Nerve", "Status at Axilla", "Supplementation Needed?"],
[
["Median nerve (C6–T1)", "BLOCKED — within sheath, superolateral to artery", "No"],
["Ulnar nerve (C8–T1)", "BLOCKED — within sheath, medial to artery", "No"],
["Radial nerve (C5–T1)", "BLOCKED — within sheath, inferior/posterior to artery", "No"],
["Medial cutaneous nerve of forearm (Medial antebrachial cutaneous, T1)", "BLOCKED (variable)", "Rarely needed"],
["Musculocutaneous nerve (C5–C7)", "SPARED — exits sheath proximal to axilla; lies in coracobrachialis m.", "YES — if forearm/lateral forearm surgery"],
["Axillary nerve (C5–C6)", "SPARED — exits posterior cord proximal to axilla", "YES — if deltoid / shoulder surgery (impossible via axilla)"],
["Medial brachial cutaneous nerve (T1)", "SPARED — branches proximal to injection site", "YES — if medial upper arm anesthesia needed"],
["Intercostobrachial nerve (T2)", "SPARED — not part of brachial plexus; thoracic origin", "YES — for tourniquet pain; separate subcutaneous injection proximal to axilla"],
],
[4.5*cm, 6.5*cm, 5*cm]
)
story += img("axillary_spared.png", width=13*cm,
caption="FIGURE 6: Axillary block — spared nerves. The axillary nerve (top), musculocutaneous nerve "
"(top left), and medial brachial cutaneous nerve (bottom) branch proximal to the injection site "
"and are NOT covered by the standard axillary block. Red dot = local anesthetic target.",
src="Source: Morgan & Mikhail's Clinical Anesthesiology, 7e — Figure 46-19")
story.append(Paragraph(
"<b>Key clinical point — tourniquet pain:</b> The intercostobrachial nerve (T2) supplies "
"the medial upper arm and is the main contributor to tourniquet pain. With ultrasound guidance, "
"this nerve can be directly visualized and targeted with a separate subcutaneous injection, "
"overcoming the historical limitation of axillary blocks for tourniquet-related discomfort "
"(Miller's Anesthesia, 10e).",
BODY))
story.append(Paragraph(
"<b>Musculocutaneous nerve supplement:</b> This nerve can be visualized on US either between "
"the biceps and coracobrachialis muscles or within the coracobrachialis muscle itself, and "
"5–10 mL of local anesthetic injected here provides lateral forearm anesthesia.",
BODY))
# 3.2 Patient Positioning
story.append(Paragraph("3.2 Patient Positioning", H2))
story += info_box("Positioning Steps", [
"Patient supine",
"Arm abducted to 90° (or operative hand placed behind the head)",
"Head turned toward the contralateral side",
"Axillary artery pulse palpated and marked as reference",
"Alternative: Rubber tourniquet (e.g. Sterivac) placed 2–3 cm distal to pectoralis major insertion "
"to limit distal spread within the axillary sheath (landmark technique)",
], color=GREY_BG, title_color=BLUE_MID)
# 3.3 Ultrasound-Guided Technique
story.append(Paragraph("3.3 Ultrasound-Guided Technique", H2))
story.append(Paragraph(
"A high-frequency linear array transducer is placed transversely over the axilla. The neurovascular "
"bundle depth is typically shallow (~20 mm), making this technically accessible. The axillary artery "
"and vein(s) are visualized in cross-section. The brachial plexus nerves are identified surrounding "
"the artery as oval/round hyperechoic structures.",
BODY))
story.append(Paragraph(
"The needle is inserted superior (lateral) to the transducer and advanced inferiorly (medially) "
"toward the plexus under direct visualization. <b>Multiple injections are required</b> — 5–10 mL "
"of local anesthetic is deposited around each nerve individually because of fascial separations.",
BODY))
story += img("axillary_multiple_inject.png", width=11*cm,
caption="FIGURE 7: Multiple injection technique for axillary block. Fascial septae separate the "
"major terminal nerves (median, ulnar, radial), requiring individual targeting. "
"The ultrasound probe (right) visualizes each nerve in cross-section.",
src="Source: Morgan & Mikhail's Clinical Anesthesiology, 7e — Figure 46-20")
story.append(Paragraph("<b>Nerve positions around the axillary artery (variable anatomy):</b>", H3))
story += comparison_table(
["Nerve", "Typical Position Relative to Artery"],
[
["Median nerve", "Superolateral (12–3 o'clock position)"],
["Ulnar nerve", "Superomedial (9–12 o'clock position)"],
["Radial nerve", "Posterior / inferior (6–9 o'clock position)"],
["Musculocutaneous nerve", "Outside the sheath; within coracobrachialis muscle (lateral)"],
["Medial brachial cutaneous", "Medial, outside the main sheath"],
["Intercostobrachial nerve", "Subcutaneous, medial upper arm — outside axillary sheath"],
],
[6*cm, 10*cm]
)
# 3.4 Landmark Technique (Pye's)
story.append(Paragraph("3.4 Landmark Technique (Historical / Resource-Limited Settings)", H2))
story.append(Paragraph(
"Abduct the arm to 90°. Apply a rubber tourniquet 2–3 cm distal to the insertion of "
"pectoralis major to limit distal spread of local anesthetic within the axillary sheath. "
"Palpate the axillary artery pulse as it emerges from the edge of pectoralis major. Direct "
"a 25 G or 23 G needle immediately above the arterial pulse. A 'give' is felt as the needle "
"enters the axillary sheath. Inject 20–30 mL of 1% lignocaine or prilocaine (with adrenaline "
"1:200,000). Elicitation of paraesthesiae confirms correct placement. Wait 10–15 min before "
"assessing blockade.",
BODY))
# 3.5 Local Anesthetic
story.append(Paragraph("3.5 Local Anesthetic", H2))
story += comparison_table(
["Agent", "Volume (per nerve)", "Total Volume", "Duration"],
[
["Bupivacaine 0.25–0.5%", "5–10 mL", "20–40 mL", "8–16 h"],
["Ropivacaine 0.5%", "5–10 mL", "20–40 mL", "8–14 h"],
["Lidocaine 1.5% ± epi", "5–10 mL", "20–40 mL", "3–5 h"],
["Mepivacaine 1.5%", "5–10 mL", "20–40 mL", "4–6 h"],
],
[4*cm, 4*cm, 4*cm, 5*cm]
)
story.append(Paragraph(
"Titrate to minimum effective volume. Because the axilla is highly vascularized, monitor "
"closely for local anesthetic systemic toxicity (LAST).",
BODY))
# 3.6 Complications
story.append(Paragraph("3.6 Complications and Contraindications", H2))
story += warn_box("Complications", [
"Vascular puncture — axilla is highly vascularized; always aspirate; risk of LAST is higher than other approaches.",
"Hematoma — use color Doppler; apply gentle pressure post-block.",
"Incomplete block — musculocutaneous, intercostobrachial nerves always require supplementation.",
"Tourniquet pain — intercostobrachial nerve (T2) must be separately blocked for tourniquet tolerance.",
"Nerve injury — mechanical, chemical, or ischemic; permanent neurologic sequelae <1%.",
"Infection — axilla is a suboptimal site for perineural catheters due to elevated infection risk.",
"Catheter dislodgement — axilla is suboptimal for continuous catheter; prefer infraclavicular approach.",
])
story += info_box("Relative Contraindications", [
"Local infection in the axilla",
"Pre-existing peripheral neuropathy",
"Coagulopathy (relative — compressible site is an advantage)",
"Arm cannot be abducted 90° (trauma, contracture, shoulder pathology)",
"Lymphadenopathy / axillary mass",
], color=colors.HexColor("#fff8e1"), title_color=ORANGE)
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# SECTION 3 — HEAD-TO-HEAD COMPARISON
# ════════════════════════════════════════════════════════════════════════════
story += section_header("4. Supraclavicular vs Axillary Block — Comparison", ORANGE)
story += comparison_table(
["Parameter", "Supraclavicular Block", "Axillary Block"],
[
["Target level", "Trunks → Divisions", "Terminal branches"],
["Plexus level", "Distal trunk / proximal division", "Cords → Terminal branches"],
["Classic description", '"Spinal of the arm"', "Safest brachial plexus block"],
["Coverage", "At or distal to elbow (reliable); shoulder (unreliable)", "Forearm, wrist, hand (reliable); NOT shoulder or upper arm"],
["Onset", "Rapid (plexus is compact at this level)", "Slower (requires multiple injections)"],
["Volume needed", "15–30 mL", "20–40 mL (5–10 mL per nerve)"],
["Injections required", "Single injection (or 2 if needed)", "Multiple (3–4 for median, ulnar, radial + musculocutaneous)"],
["Phrenic nerve palsy", "40–60% incidence", "None"],
["Pneumothorax risk", "0.5–6%", "None"],
["Horner syndrome", "Yes (cervical sympathetic)", "No"],
["Nerves reliably blocked", "C5–T1 (with care for lower trunk)", "Median, ulnar, radial (within sheath)"],
["Nerves always spared", "Suprascapular n., intercostobrachial n.", "Musculocutaneous n., axillary n., medial brachial cutaneous n., intercostobrachial n."],
["Tourniquet pain", "Covered (if C8–T1 complete)", "NOT covered — intercostobrachial n. must be blocked separately"],
["Shoulder surgery suitability", "Unsuitable alone (add suprascapular block)", "Unsuitable"],
["Catheter placement", "Possible but inferior to infraclavicular", "Poor — risk of infection, dislodgement"],
["Ultrasound guidance", "Strongly recommended (pneumothorax risk)", "Strongly recommended (multiple injections)"],
["Arm positioning", "Adducted, head turned 30° away", "Abducted 90° or behind head"],
["Main limitation", "Pneumothorax, phrenic nerve palsy", "Nerves spared proximally; tourniquet pain"],
],
[4*cm, 6.5*cm, 6.5*cm]
)
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# SECTION 4 — ULTRASOUND TIPS
# ════════════════════════════════════════════════════════════════════════════
story += section_header("5. Ultrasound Guidance — Tips & Tricks", BLUE_DARK)
story.append(Paragraph("5.1 Supraclavicular US Tips", H2))
story += info_box("Supraclavicular Ultrasound Tips", [
"Use a high-frequency linear transducer (10–15 MHz) in coronal oblique plane above clavicle.",
"Identify subclavian artery first (large, pulsatile, compressible with gentle pressure).",
'Brachial plexus = "cluster of grapes" — multiple hypoechoic disks lateral and posterior to artery.',
"Identify first rib (hyperechoic, curved line just deep to artery) and pleura (moves with breathing).",
"Advance needle in-plane from lateral to medial — keep tip visible at all times.",
"Target the 'corner pocket' — angle between first rib and subclavian artery for optimal spread.",
"Use color Doppler to identify suprascapular and dorsal scapular arteries.",
"Trace plexus caudad (lower trunk) to ensure ulnar nerve territory is covered.",
"Volume 15–20 mL is adequate; 20–30 mL max — avoid over-injection (neural compression risk).",
], color=BLUE_LIGHT)
story.append(Paragraph("5.2 Axillary US Tips", H2))
story += info_box("Axillary Ultrasound Tips", [
"Use high-frequency linear transducer (15 MHz); depth ~20 mm — very superficial block.",
"Identify axillary artery first (pulsatile), then vein (compressible with probe pressure).",
"Three nerves (median, ulnar, radial) identified around artery as oval hyperechoic structures.",
"Musculocutaneous nerve: starts round (adjacent to artery) → flat (inside coracobrachialis) → triangular (exiting muscle).",
"Target each nerve individually (5–10 mL each) — fascial septae prevent spread from single injection.",
"Intercostobrachial nerve (tourniquet): inject subcutaneously along the medial upper arm (5–7 mL).",
"Color Doppler: identify multiple axillary veins (common variation) to avoid puncture.",
"In-plane or out-of-plane approach both acceptable; in-plane preferred for visualization.",
"Confirmation: local anesthetic should surround each nerve individually on real-time US.",
], color=BLUE_LIGHT)
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# SECTION 5 — CLINICAL DECISION GUIDE
# ════════════════════════════════════════════════════════════════════════════
story += section_header("6. Clinical Decision Guide — Which Block to Choose?", TEAL)
story += comparison_table(
["Surgery Type", "Recommended Block", "Rationale"],
[
["Hand / fingers / wrist", "Axillary (multiple injections) OR Supraclavicular", "Both reliable; axillary = no phrenic risk"],
["Forearm fracture / ORIF", "Supraclavicular OR Axillary", "Supraclavicular: single injection, rapid onset"],
["Elbow surgery", "Supraclavicular OR Infraclavicular", "Supraclavicular at elbow level is reliable"],
["Carpal tunnel release", "Axillary (median nerve targeted)", "Direct median nerve targeting under US"],
["AV fistula creation (forearm)", "Axillary OR Supraclavicular", "Axillary: no phrenic risk; supplement ICBN for tourniquet"],
["Tourniquet required (any)", "Axillary + ICBN supplement", "ICBN (T2) must be separately blocked"],
["Shoulder surgery", "Interscalene (not supraclavicular or axillary)", "Neither covers suprascapular n. reliably"],
["Upper arm / deltoid surgery", "Interscalene", "Axillary nerve (C5–C6) is always spared by axillary block"],
["Bilateral upper limb surgery", "Axillary (bilateral) — avoid bilateral supraclavicular", "Bilateral phrenic palsy = respiratory failure"],
["Patient with severe COPD", "Axillary preferred", "Supraclavicular: 40–60% phrenic palsy unacceptable"],
["Contralateral phrenic palsy", "Axillary (contraindicated supraclavicular)", "Phrenic palsy on operated side = bilateral palsy"],
["Arm cannot be abducted", "Supraclavicular OR Infraclavicular", "Axillary requires 90° abduction"],
["Continuous catheter needed", "Infraclavicular preferred", "Axillary and supraclavicular both suboptimal for catheters"],
],
[4.5*cm, 5.5*cm, 6*cm]
)
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# SECTION 6 — SUMMARY CARDS
# ════════════════════════════════════════════════════════════════════════════
story += section_header("7. Quick Reference Summary Cards", BLUE_DARK)
# --- Supraclavicular summary ---
story.append(Paragraph("SUPRACLAVICULAR BLOCK — AT A GLANCE", H2))
card_rows = [
["Level targeted", "Trunks / Divisions (compact, just above clavicle)"],
["Coverage", "Elbow, forearm, wrist, hand"],
["Spared nerves", "Suprascapular n., phrenic n. (partially), intercostobrachial n."],
["Unique complication", "Pneumothorax (0.5–6%), Phrenic palsy (40–60%)"],
["Volume", "15–30 mL"],
["Positioning", "Supine, head 30° contralateral, arm adducted"],
["Probe position", "Coronal oblique above clavicle, in-plane lateral→medial"],
["Needle target", "Lateral-to-medial, 'corner pocket' between first rib and subclavian a."],
["Key advantage", "Rapid onset, dense block, single injection"],
["Key disadvantage", "Pneumothorax risk, phrenic palsy, not for shoulder"],
]
tbl = Table([[Paragraph(r[0], S("CK", fontSize=9, fontName="Helvetica-Bold", textColor=TEAL)),
Paragraph(r[1], TABLE_CELL)] for r in card_rows],
colWidths=[5*cm, 11*cm])
tbl.setStyle(TableStyle([
("ROWBACKGROUNDS", (0,0), (-1,-1), [BLUE_LIGHT, WHITE]),
("GRID", (0,0), (-1,-1), 0.4, GREY_LINE),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(tbl)
story.append(Spacer(1, 6*mm))
# --- Axillary summary ---
story.append(Paragraph("AXILLARY BLOCK — AT A GLANCE", H2))
card_rows2 = [
["Level targeted", "Terminal branches (in axilla at lateral border of pectoralis minor)"],
["Coverage", "Forearm, wrist, hand (NOT shoulder, NOT upper arm)"],
["Spared nerves", "Musculocutaneous n., axillary n., medial brachial cutaneous n., intercostobrachial n. (T2)"],
["Unique complication", "LAST risk (vascular area), tourniquet pain (ICBN not blocked)"],
["Volume", "20–40 mL (5–10 mL per nerve × 3–4 nerves)"],
["Positioning", "Supine, arm abducted 90°, head turned contralateral"],
["Probe position", "Transverse over axilla, artery in cross-section"],
["Needle target", "Each nerve individually (median, ulnar, radial) + musculocutaneous in coracobrachialis"],
["Key advantage", "No phrenic palsy, no pneumothorax, safest approach"],
["Key disadvantage", "Multiple injections, musculocutaneous/ICBN always spared, poor for catheters"],
]
tbl2 = Table([[Paragraph(r[0], S("CK2", fontSize=9, fontName="Helvetica-Bold", textColor=BLUE_MID)),
Paragraph(r[1], TABLE_CELL)] for r in card_rows2],
colWidths=[5*cm, 11*cm])
tbl2.setStyle(TableStyle([
("ROWBACKGROUNDS", (0,0), (-1,-1), [BLUE_LIGHT, WHITE]),
("GRID", (0,0), (-1,-1), 0.4, GREY_LINE),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(tbl2)
story.append(Spacer(1, 6*mm))
story += hr()
story.append(Spacer(1, 4*mm))
story.append(Paragraph(
"<b>Sources:</b> Morgan & Mikhail's Clinical Anesthesiology 7e (pp. 1882–1895) | "
"Miller's Anesthesia 10e (pp. 6244–6252, 11058–11063) | "
"Barash, Cullen & Stoelting's Clinical Anesthesia 9e (pp. 1580–1700) | "
"Campbell's Operative Orthopaedics 15e (pp. 3976–3979) | "
"Pye's Surgical Handicraft 22e (pp. 106–109)",
S("REF", fontSize=8, fontName="Helvetica-Oblique", textColor=colors.grey,
leading=12, alignment=TA_LEFT)))
# ─── Build ────────────────────────────────────────────────────────────────────
doc.build(story, canvasmaker=NumberedCanvas)
print(f"PDF created: {OUTPUT}")