Explain about descending tract



| Tract | Origin | Decussation | Location in Cord | Controls |
|---|---|---|---|---|
| Lateral corticospinal | Primary motor cortex (area 4) | Pyramidal decussation (medulla) - ~85% | Lateral column | Fine distal voluntary movement (contralateral) |
| Anterior corticospinal | Primary motor cortex | None (crosses at segmental level) | Anterior column | Axial/proximal muscles (bilateral) |
| Rubrospinal | Red nucleus (midbrain) | Immediately in pons | Lateral column | Fine arm/hand movements (contralateral) |
| Vestibulospinal (lateral) | Lateral vestibular nucleus | None (ipsilateral) | Anterior column | Extensor tone in legs, balance |
| Vestibulospinal (medial) | Medial vestibular nucleus | Bilateral | Anterior column | Head/neck posture |
| Tectospinal | Superior colliculus (midbrain) | Dorsal tegmental decussation | Anterior column | Head-turning reflexes (cervical only) |
| Pontine reticulospinal | Pontine reticular formation | None (ipsilateral) | Anterior column | Facilitates extensors (antigravity) |
| Medullary reticulospinal | Medullary reticular formation | Bilateral | Lateral/anterior | Inhibits antigravity stretch reflexes |
| Feature | UMN Lesion | LMN Lesion |
|---|---|---|
| Weakness | Contralateral (CST lesion above decussation) | Ipsilateral |
| Tone | Spasticity (increased) | Flaccidity (decreased) |
| Reflexes | Hyperreflexia | Hyporeflexia / areflexia |
| Babinski sign | Present (upgoing toe) | Absent |
| Atrophy | Mild (disuse) | Significant (denervation) |
| Fasciculations | Absent | Present |
Create a quick reference PDF comparing UMN vs LMN signs with clinical examples
ls /home/daytona/workspace/ 2>/dev/null || echo "workspace empty"
~/umn-lmn-ref/create_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm, mm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether
)
from reportlab.lib.colors import HexColor
import os
output_path = "/home/daytona/workspace/umn-lmn-ref/UMN_vs_LMN_Quick_Reference.pdf"
os.makedirs("/home/daytona/workspace/umn-lmn-ref", exist_ok=True)
# ── Colour palette ──────────────────────────────────────────────────────────
DARK_BLUE = HexColor("#1A3A5C") # header / title
MID_BLUE = HexColor("#2E6DA4") # UMN column header
RED_BROWN = HexColor("#C0392B") # LMN column header
LIGHT_BLUE = HexColor("#D6E8F8") # UMN row shading (light)
LIGHT_RED = HexColor("#FDECEA") # LMN row shading (light)
PALE_GRAY = HexColor("#F4F6F8") # alternating row
DARK_GRAY = HexColor("#2C3E50") # body text
GOLD = HexColor("#D4A017") # accent / rule
WHITE = colors.white
BLACK = colors.black
doc = SimpleDocTemplate(
output_path,
pagesize=A4,
rightMargin=1.8*cm, leftMargin=1.8*cm,
topMargin=1.8*cm, bottomMargin=1.8*cm,
title="UMN vs LMN Quick Reference",
author="Orris Medical"
)
W, H = A4
CONTENT_W = W - 3.6*cm
styles = getSampleStyleSheet()
def sty(name, **kw):
base = styles.get(name, styles["Normal"])
return ParagraphStyle(name + "_custom_" + str(id(kw)), parent=base, **kw)
title_sty = sty("Title",
fontSize=22, textColor=WHITE, alignment=TA_CENTER,
fontName="Helvetica-Bold", spaceAfter=0, spaceBefore=0)
subtitle_sty = sty("Normal",
fontSize=10, textColor=HexColor("#BDD7EE"), alignment=TA_CENTER,
fontName="Helvetica-Oblique", spaceAfter=0)
section_sty = sty("Heading2",
fontSize=13, textColor=DARK_BLUE, fontName="Helvetica-Bold",
spaceBefore=10, spaceAfter=4, borderPad=0)
body_sty = sty("Normal",
fontSize=9, textColor=DARK_GRAY, fontName="Helvetica",
leading=13, spaceAfter=3)
bold_body = sty("Normal",
fontSize=9, textColor=DARK_GRAY, fontName="Helvetica-Bold", leading=13)
col_header_sty = sty("Normal",
fontSize=10, textColor=WHITE, fontName="Helvetica-Bold",
alignment=TA_CENTER, leading=14)
cell_sty = sty("Normal",
fontSize=8.5, textColor=DARK_GRAY, fontName="Helvetica",
leading=12, alignment=TA_LEFT)
cell_bold = sty("Normal",
fontSize=8.5, textColor=DARK_GRAY, fontName="Helvetica-Bold",
leading=12, alignment=TA_LEFT)
umncell = sty("Normal",
fontSize=8.5, textColor=HexColor("#1A3A5C"), fontName="Helvetica",
leading=12, alignment=TA_LEFT)
lmncell = sty("Normal",
fontSize=8.5, textColor=HexColor("#7B1515"), fontName="Helvetica",
leading=12, alignment=TA_LEFT)
note_sty = sty("Normal",
fontSize=8, textColor=HexColor("#5D6D7E"), fontName="Helvetica-Oblique",
leading=11, spaceAfter=2)
example_sty = sty("Normal",
fontSize=8, textColor=HexColor("#196F3D"), fontName="Helvetica-Bold",
leading=11)
# ── Helper: coloured title banner ────────────────────────────────────────────
def banner(story):
banner_data = [[Paragraph("UMN vs LMN", title_sty)],
[Paragraph("Upper Motor Neuron vs Lower Motor Neuron — Quick Reference", subtitle_sty)]]
banner_tbl = Table(banner_data, colWidths=[CONTENT_W])
banner_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), DARK_BLUE),
("TOPPADDING", (0,0), (-1,-1), 10),
("BOTTOMPADDING",(0,0),(-1,-1), 10),
("LEFTPADDING", (0,0), (-1,-1), 12),
("RIGHTPADDING",(0,0), (-1,-1), 12),
("ROUNDEDCORNERS", (0,0),(-1,-1), 6),
]))
story.append(banner_tbl)
story.append(Spacer(1, 10))
# ── Main comparison table ────────────────────────────────────────────────────
def main_table(story):
story.append(Paragraph("Clinical Signs at a Glance", section_sty))
story.append(HRFlowable(width=CONTENT_W, thickness=1.5, color=GOLD, spaceAfter=6))
col_w = [CONTENT_W*0.26, CONTENT_W*0.37, CONTENT_W*0.37]
rows = [
# Header
[
Paragraph("Feature", col_header_sty),
Paragraph("UMN Lesion", col_header_sty),
Paragraph("LMN Lesion", col_header_sty),
],
[
Paragraph("Tone", cell_bold),
Paragraph("Spasticity (clasp-knife)\nIncreased tone in\nflexors (arm) / extensors (leg)", umncell),
Paragraph("Flaccidity\nDecreased / absent\nmuscle tone", lmncell),
],
[
Paragraph("Power", cell_bold),
Paragraph("Weakness (contralateral\nto lesion if above decussation)", umncell),
Paragraph("Weakness / paralysis\n(ipsilateral, segmental\nor peripheral distribution)", lmncell),
],
[
Paragraph("Deep Tendon\nReflexes", cell_bold),
Paragraph("Hyperreflexia\nExaggerated DTRs\n(e.g. brisk knee jerk)", umncell),
Paragraph("Hyporeflexia or\nAreflexia\n(loss of knee / ankle jerk)", lmncell),
],
[
Paragraph("Plantar\nResponse", cell_bold),
Paragraph("Extensor (Babinski +ve)\nBig toe goes UP,\nfanning of other toes", umncell),
Paragraph("Flexor (normal)\nAll toes curl DOWN\n(or no response)", lmncell),
],
[
Paragraph("Clonus", cell_bold),
Paragraph("Present\n(sustained rhythmic\noscillation at ankle/knee)", umncell),
Paragraph("Absent", lmncell),
],
[
Paragraph("Muscle\nAtrophy", cell_bold),
Paragraph("Mild (disuse atrophy only)\noccurs late", umncell),
Paragraph("Significant & early\nDenervation atrophy", lmncell),
],
[
Paragraph("Fasciculations", cell_bold),
Paragraph("Absent", umncell),
Paragraph("Present\n(spontaneous visible\ntwitching of muscle bundles)", lmncell),
],
[
Paragraph("Fibrillations\n(EMG)", cell_bold),
Paragraph("Absent", umncell),
Paragraph("Present on EMG\n(denervation potential)", lmncell),
],
[
Paragraph("Distribution\nof Weakness", cell_bold),
Paragraph("Pyramidal pattern:\nExtensors weak in arm\nFlexors weak in leg\n(whole limb / hemibody)", umncell),
Paragraph("Focal / segmental:\nSingle muscle group or\nperipheral nerve territory", lmncell),
],
[
Paragraph("Wasting", cell_bold),
Paragraph("Absent initially;\nMild later (disuse)", umncell),
Paragraph("Severe wasting\nof affected muscles", lmncell),
],
[
Paragraph("Coordination", cell_bold),
Paragraph("May be impaired due\nto weakness", umncell),
Paragraph("May be impaired due\nto weakness", lmncell),
],
]
tbl = Table(rows, colWidths=col_w, repeatRows=1)
style_cmds = [
# Header row
("BACKGROUND", (0,0), (0,0), DARK_BLUE),
("BACKGROUND", (1,0), (1,0), MID_BLUE),
("BACKGROUND", (2,0), (2,0), RED_BROWN),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,0), 10),
("ALIGN", (0,0), (-1,0), "CENTER"),
("VALIGN", (0,0), (-1,0), "MIDDLE"),
("TOPPADDING", (0,0), (-1,0), 8),
("BOTTOMPADDING",(0,0),(-1,0),8),
# Feature column
("BACKGROUND", (0,1), (0,-1), HexColor("#EAF0F7")),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
# Alternating UMN / LMN shading
("GRID", (0,0), (-1,-1), 0.4, HexColor("#BDC3C7")),
("ROWBACKGROUNDS", (1,1), (1,-1), [LIGHT_BLUE, WHITE]),
("ROWBACKGROUNDS", (2,1), (2,-1), [LIGHT_RED, HexColor("#FFF8F8")]),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,1), (-1,-1), 5),
("BOTTOMPADDING",(0,1),(-1,-1),5),
("LEFTPADDING",(0,0), (-1,-1), 6),
("RIGHTPADDING",(0,0),(-1,-1), 6),
("ROUNDEDCORNERS",(0,0),(-1,-1), 3),
]
# Alternate full row background for better readability
for i in range(1, len(rows)):
bg = PALE_GRAY if i % 2 == 0 else WHITE
style_cmds.append(("BACKGROUND", (0,i), (0,i), HexColor("#EAF0F7")))
style_cmds.append(("BACKGROUND", (1,i), (1,i), LIGHT_BLUE if i % 2 == 1 else WHITE))
style_cmds.append(("BACKGROUND", (2,i), (2,i), LIGHT_RED if i % 2 == 1 else HexColor("#FFF8F8")))
tbl.setStyle(TableStyle(style_cmds))
story.append(tbl)
story.append(Spacer(1, 12))
# ── Lesion localisation table ────────────────────────────────────────────────
def location_table(story):
story.append(Paragraph("Lesion Localisation", section_sty))
story.append(HRFlowable(width=CONTENT_W, thickness=1.5, color=GOLD, spaceAfter=6))
col_w = [CONTENT_W*0.30, CONTENT_W*0.22, CONTENT_W*0.48]
rows = [
[
Paragraph("Location of Lesion", col_header_sty),
Paragraph("Type", col_header_sty),
Paragraph("Signs Produced", col_header_sty),
],
[
Paragraph("Motor cortex / corona radiata\n(e.g. stroke)", cell_bold),
Paragraph("UMN", umncell),
Paragraph("Contralateral hemiplegia (arm > leg usually)\nFace spared if below facial motor area", cell_sty),
],
[
Paragraph("Internal capsule\n(e.g. lacunar stroke)", cell_bold),
Paragraph("UMN", umncell),
Paragraph("Pure motor hemiplegia: face + arm + leg\n(all on contralateral side)", cell_sty),
],
[
Paragraph("Brainstem\n(e.g. Wallenberg, Weber)", cell_bold),
Paragraph("UMN + CN", umncell),
Paragraph("Crossed signs: ipsilateral CN palsy +\ncontralateral UMN limb signs", cell_sty),
],
[
Paragraph("Spinal cord\n(e.g. MS, cord compression)", cell_bold),
Paragraph("UMN below lesion", umncell),
Paragraph("Bilateral spastic paraplegia / quadriplegia;\nLevel can be determined by sensory level", cell_sty),
],
[
Paragraph("Anterior horn cell\n(e.g. polio, ALS*)", cell_bold),
Paragraph("LMN", lmncell),
Paragraph("Focal wasting + fasciculations; areflexia\nNo sensory loss (pure motor)", cell_sty),
],
[
Paragraph("Nerve root\n(e.g. disc prolapse)", cell_bold),
Paragraph("LMN", lmncell),
Paragraph("Dermatomal sensory loss + myotomal weakness\nReduced reflex in that segment", cell_sty),
],
[
Paragraph("Peripheral nerve\n(e.g. carpal tunnel, GBS)", cell_bold),
Paragraph("LMN", lmncell),
Paragraph("Weakness + wasting in nerve territory\n+ sensory loss; areflexia", cell_sty),
],
[
Paragraph("Neuromuscular junction\n(e.g. myasthenia gravis)", cell_bold),
Paragraph("LMN (NMJ)", lmncell),
Paragraph("Fatigable weakness; no wasting, no sensory\nloss, normal reflexes initially", cell_sty),
],
]
tbl = Table(rows, colWidths=col_w, repeatRows=1)
style_cmds = [
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,0), 9.5),
("ALIGN", (0,0), (-1,0), "CENTER"),
("VALIGN", (0,0), (-1,-1), "TOP"),
("GRID", (0,0), (-1,-1), 0.4, HexColor("#BDC3C7")),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0), (-1,-1), 6),
("RIGHTPADDING",(0,0),(-1,-1), 6),
]
for i in range(1, len(rows)):
bg = PALE_GRAY if i % 2 == 0 else WHITE
style_cmds.append(("BACKGROUND", (0,i), (-1,i), bg))
tbl.setStyle(TableStyle(style_cmds))
story.append(tbl)
story.append(Spacer(1, 12))
# ── Clinical examples boxes ──────────────────────────────────────────────────
def clinical_examples(story):
story.append(Paragraph("Clinical Examples", section_sty))
story.append(HRFlowable(width=CONTENT_W, thickness=1.5, color=GOLD, spaceAfter=6))
half_w = (CONTENT_W - 6) / 2
umn_cases = [
("<b>Stroke (MCA territory)</b>",
"Sudden contralateral hemiplegia with face + arm > leg weakness. Brisk reflexes after initial flaccid phase. Babinski positive. Hemisensory loss if parietal cortex involved."),
("<b>Multiple Sclerosis</b>",
"Young adult with relapsing-remitting spastic paraparesis. Lhermitte's sign (electric shock on neck flexion). Hyperreflexia, clonus, bilateral Babinski. Bladder involvement."),
("<b>Cervical Spondylotic Myelopathy</b>",
"Elderly patient with stiff spastic gait, clumsy hands, hyperreflexia. UMN signs in legs, may show LMN signs at the level of compression (mixed picture)."),
("<b>Motor Neuron Disease (ALS)</b>",
"Mixed UMN + LMN: hyperreflexia AND fasciculations present in the SAME muscle. Pathognomonic of ALS. Bulbar palsy also common."),
]
lmn_cases = [
("<b>L4/L5 Disc Prolapse</b>",
"Unilateral foot drop with L5 dermatomal sensory loss. Absent ankle jerk (S1 involvement if L5/S1 level). Straight leg raise test positive. Wasting of tibialis anterior."),
("<b>Guillain-Barre Syndrome</b>",
"Ascending flaccid paralysis, areflexia, and glove-stocking sensory loss following a viral illness. Autonomic instability. Nerve conduction shows demyelination."),
("<b>Bell's Palsy (CN VII)</b>",
"Unilateral complete facial weakness (upper + lower face involved - distinguishes from UMN cause). Loss of corneal reflex. Hyperacusis, altered taste."),
("<b>Carpal Tunnel Syndrome</b>",
"Thenar wasting + weakness of thumb abduction. Sensory loss in lateral 3.5 fingers. Positive Phalen's and Tinel's sign. Worse at night."),
]
def case_cell(cases, bg_color, header_text, header_color):
inner_rows = [[Paragraph(header_text, ParagraphStyle("ch", fontSize=9.5,
textColor=WHITE, fontName="Helvetica-Bold", alignment=TA_CENTER))]]
for title, desc in cases:
inner_rows.append([Paragraph(
f'<font color="#1A3A5C"><b>{title.strip("<b>").strip("</b>")}</b></font><br/>'
f'<font color="#2C3E50" size="7.5">{desc}</font>',
ParagraphStyle("cc", fontSize=8, leading=11, fontName="Helvetica",
spaceAfter=2))])
t = Table(inner_rows, colWidths=[half_w])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), header_color),
("BACKGROUND", (0,1), (-1,-1), bg_color),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING", (0,0), (-1,-1), 7),
("RIGHTPADDING",(0,0), (-1,-1), 7),
("GRID", (0,0), (-1,-1), 0.3, HexColor("#D5D8DC")),
]))
return t
umn_tbl = case_cell(umn_cases, LIGHT_BLUE, "UMN Clinical Examples", MID_BLUE)
lmn_tbl = case_cell(lmn_cases, LIGHT_RED, "LMN Clinical Examples", RED_BROWN)
combined = Table([[umn_tbl, lmn_tbl]], colWidths=[half_w + 3, half_w + 3])
combined.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "TOP"),
("LEFTPADDING", (0,0), (-1,-1), 0),
("RIGHTPADDING", (0,0), (-1,-1), 0),
("TOPPADDING", (0,0), (-1,-1), 0),
("BOTTOMPADDING",(0,0), (-1,-1), 0),
]))
story.append(combined)
story.append(Spacer(1, 10))
# ── Key mnemonics box ────────────────────────────────────────────────────────
def mnemonics(story):
story.append(Paragraph("Memory Aids", section_sty))
story.append(HRFlowable(width=CONTENT_W, thickness=1.5, color=GOLD, spaceAfter=6))
mnem_data = [
[
Paragraph("<b>UMN mnemonic: \"USHHHH\"</b><br/>"
"<font size='8'><b>U</b>pper motor = <b>S</b>pasticity, <b>H</b>yperreflexia, <b>H</b>ypertonia, '\"<b>H</b>\" sign (Babinski), <b>H</b>emiplegia pattern</font>",
ParagraphStyle("m1", fontSize=8.5, fontName="Helvetica", leading=13,
textColor=DARK_GRAY)),
Paragraph("<b>LMN mnemonic: \"FLAWS\"</b><br/>"
"<font size='8'><b>F</b>laccidity, <b>L</b>oss of reflexes (areflexia), <b>A</b>trophy, <b>W</b>asting, <b>F</b>asciculations</font>",
ParagraphStyle("m2", fontSize=8.5, fontName="Helvetica", leading=13,
textColor=DARK_GRAY)),
],
[
Paragraph("<b>Babinski key rule:</b> <font size='8'>Present in UMN lesion AND normal infants (immature tracts). Absent in adults = normal.</font>",
ParagraphStyle("m3", fontSize=8.5, fontName="Helvetica", leading=13,
textColor=DARK_GRAY)),
Paragraph("<b>ALS special rule:</b> <font size='8'>BOTH UMN + LMN signs in the same limb = ALS until proven otherwise. Fasciculations WITH hyperreflexia is pathognomonic.</font>",
ParagraphStyle("m4", fontSize=8.5, fontName="Helvetica", leading=13,
textColor=DARK_GRAY)),
],
]
mnem_tbl = Table(mnem_data, colWidths=[CONTENT_W/2, CONTENT_W/2])
mnem_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), HexColor("#FDFEFE")),
("BOX", (0,0), (-1,-1), 1, HexColor("#AEB6BF")),
("INNERGRID", (0,0), (-1,-1), 0.4, HexColor("#D5D8DC")),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING",(0,0),(-1,-1),7),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING",(0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(mnem_tbl)
story.append(Spacer(1, 10))
# ── Reflex arc reminder ──────────────────────────────────────────────────────
def reflex_table(story):
story.append(Paragraph("Common Reflexes and Spinal Levels", section_sty))
story.append(HRFlowable(width=CONTENT_W, thickness=1.5, color=GOLD, spaceAfter=6))
col_w = [CONTENT_W*0.30, CONTENT_W*0.18, CONTENT_W*0.18, CONTENT_W*0.34]
rows = [
[Paragraph("Reflex", col_header_sty), Paragraph("Level", col_header_sty),
Paragraph("Nerve", col_header_sty), Paragraph("Absent in LMN / Exaggerated in UMN", col_header_sty)],
[Paragraph("Biceps jerk", cell_sty), Paragraph("C5-C6", cell_sty),
Paragraph("Musculocutaneous", cell_sty), Paragraph("Absent: C5/C6 radiculopathy, brachial neuritis", cell_sty)],
[Paragraph("Supinator jerk", cell_sty), Paragraph("C5-C6", cell_sty),
Paragraph("Radial", cell_sty), Paragraph("Inversion in C5/6 lesion (finger flexion instead)", cell_sty)],
[Paragraph("Triceps jerk", cell_sty), Paragraph("C7", cell_sty),
Paragraph("Radial", cell_sty), Paragraph("Absent: C7 radiculopathy (posterior disc)", cell_sty)],
[Paragraph("Knee jerk (patellar)", cell_sty), Paragraph("L3-L4", cell_sty),
Paragraph("Femoral", cell_sty), Paragraph("Absent: femoral neuropathy, L4 disc prolapse", cell_sty)],
[Paragraph("Ankle jerk", cell_sty), Paragraph("S1", cell_sty),
Paragraph("Sciatic/tibial", cell_sty), Paragraph("Absent: S1 radiculopathy, peripheral neuropathy", cell_sty)],
[Paragraph("Plantar (Babinski)", cell_sty), Paragraph("L5-S1", cell_sty),
Paragraph("Sciatic", cell_sty), Paragraph("Extensor response = UMN sign (pathological in adults)", cell_sty)],
[Paragraph("Abdominal reflexes", cell_sty), Paragraph("T8-T12", cell_sty),
Paragraph("Intercostal", cell_sty), Paragraph("Absent early in UMN lesion (before hyperreflexia)", cell_sty)],
]
tbl = Table(rows, colWidths=col_w, repeatRows=1)
style_cmds = [
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("GRID", (0,0), (-1,-1), 0.4, HexColor("#BDC3C7")),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0), (-1,-1), 6),
("RIGHTPADDING",(0,0),(-1,-1), 6),
]
for i in range(1, len(rows)):
bg = PALE_GRAY if i % 2 == 0 else WHITE
style_cmds.append(("BACKGROUND", (0,i), (-1,i), bg))
tbl.setStyle(TableStyle(style_cmds))
story.append(tbl)
story.append(Spacer(1, 8))
# ── Footer note ──────────────────────────────────────────────────────────────
def footer_note(story):
note = ("* ALS = Amyotrophic Lateral Sclerosis. Note: Acute UMN lesions (e.g. acute stroke, acute spinal cord injury) "
"may initially present with FLACCIDITY and AREFLEXIA (spinal shock / cerebral shock) before the classic "
"UMN pattern of spasticity and hyperreflexia develops over days to weeks.")
story.append(Paragraph(note, ParagraphStyle("fn", fontSize=7.5, textColor=HexColor("#717D7E"),
fontName="Helvetica-Oblique", leading=10, borderPad=4,
borderColor=HexColor("#AEB6BF"), borderWidth=0.5,
backColor=HexColor("#F8F9FA"))))
story.append(Spacer(1, 4))
story.append(Paragraph("Orris Medical Quick Reference | July 2026",
ParagraphStyle("credit", fontSize=7, textColor=HexColor("#AEB6BF"),
fontName="Helvetica", alignment=TA_CENTER)))
# ── Build ─────────────────────────────────────────────────────────────────────
story = []
banner(story)
main_table(story)
location_table(story)
clinical_examples(story)
mnemonics(story)
reflex_table(story)
footer_note(story)
doc.build(story)
print(f"PDF created: {output_path}")
cd /home/daytona/workspace/umn-lmn-ref && python create_pdf.py 2>&1
ls -lh /home/daytona/workspace/umn-lmn-ref/
UMN vs LMN Quick Reference
PDF Document · PDF
Make pdf of easy and quick revision for ascending tract and descending tract with comparison of both
~/tracts-revision/build_pdf.py
"""
Ascending & Descending Tracts — Quick Revision PDF
ReportLab-based, A4, colour-coded, exam-ready
"""
import os
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm, mm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether, PageBreak
)
from reportlab.lib.colors import HexColor
os.makedirs("/home/daytona/workspace/tracts-revision", exist_ok=True)
OUT = "/home/daytona/workspace/tracts-revision/Spinal_Tracts_Quick_Revision.pdf"
W, H = A4
MARGIN = 1.6*cm
CONTENT_W = W - 2*MARGIN
# ── Palette ──────────────────────────────────────────────────────────────────
C_DARK_BG = HexColor("#0D2137") # page header bg
C_ASC_HDR = HexColor("#1A6B3A") # ascending header / accent
C_DESC_HDR = HexColor("#8B1A1A") # descending header / accent
C_ASC_LIGHT = HexColor("#D4EDDA") # ascending row bg
C_DESC_LIGHT= HexColor("#FADBD8") # descending row bg
C_GOLD = HexColor("#D4A017") # rule / accent
C_BODY = HexColor("#1C2833") # normal text
C_GRAY = HexColor("#6D7C8A") # footnotes / labels
C_WHITE = colors.white
C_PALE = HexColor("#F4F6F8")
C_BLUE_HDR = HexColor("#154360") # comparison header
C_BLUE_LIGHT= HexColor("#D6EAF8")
C_ORANGE = HexColor("#BA6714")
C_ORANGE_L = HexColor("#FDEBD0")
doc = SimpleDocTemplate(OUT, pagesize=A4,
rightMargin=MARGIN, leftMargin=MARGIN,
topMargin=MARGIN, bottomMargin=MARGIN,
title="Spinal Tracts Quick Revision",
author="Orris Medical")
# ── Style factory ─────────────────────────────────────────────────────────────
def S(parent="Normal", **kw):
base = getSampleStyleSheet().get(parent, getSampleStyleSheet()["Normal"])
return ParagraphStyle("_" + str(id(kw)), parent=base, **kw)
T_TITLE = S("Normal", fontSize=24, textColor=C_WHITE, fontName="Helvetica-Bold",
alignment=TA_CENTER, leading=28)
T_SUB = S("Normal", fontSize=10, textColor=HexColor("#A9CCE3"), fontName="Helvetica-Oblique",
alignment=TA_CENTER, leading=14)
T_H1 = S("Normal", fontSize=13, textColor=C_DARK_BG, fontName="Helvetica-Bold",
spaceBefore=8, spaceAfter=3, leading=16)
T_H2_ASC = S("Normal", fontSize=11, textColor=C_WHITE, fontName="Helvetica-Bold",
alignment=TA_CENTER, leading=14)
T_H2_DESC = S("Normal", fontSize=11, textColor=C_WHITE, fontName="Helvetica-Bold",
alignment=TA_CENTER, leading=14)
T_CELL = S("Normal", fontSize=8, textColor=C_BODY, fontName="Helvetica", leading=11)
T_CELLB = S("Normal", fontSize=8, textColor=C_BODY, fontName="Helvetica-Bold", leading=11)
T_CHDR = S("Normal", fontSize=9, textColor=C_WHITE, fontName="Helvetica-Bold",
alignment=TA_CENTER, leading=12)
T_NOTE = S("Normal", fontSize=7.5, textColor=C_GRAY, fontName="Helvetica-Oblique", leading=10)
T_FOOT = S("Normal", fontSize=7, textColor=C_GRAY, fontName="Helvetica", alignment=TA_CENTER)
T_MNEM = S("Normal", fontSize=8.5, textColor=C_BODY, fontName="Helvetica", leading=13)
T_MNEM_B = S("Normal", fontSize=9, textColor=C_DARK_BG, fontName="Helvetica-Bold", leading=13)
def P(txt, style=T_CELL): return Paragraph(txt, style)
def HR(): return HRFlowable(width=CONTENT_W, thickness=1.2, color=C_GOLD, spaceAfter=5)
def SP(h=6): return Spacer(1, h)
# ── Table helper ──────────────────────────────────────────────────────────────
def make_table(rows, col_widths, style_cmds, repeat=1):
t = Table(rows, colWidths=col_widths, repeatRows=repeat)
t.setStyle(TableStyle(style_cmds))
return t
BASE_STYLE = [
("GRID", (0,0), (-1,-1), 0.4, HexColor("#BFC9CA")),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
]
# ═══════════════════════════════════════════════════════════════════════════════
# PAGE HEADER BANNER
# ═══════════════════════════════════════════════════════════════════════════════
def banner(story):
data = [
[P("Spinal Tracts — Quick Revision", T_TITLE)],
[P("Ascending (Sensory) & Descending (Motor) Tracts | Easy Reference for Exams", T_SUB)],
]
t = Table(data, colWidths=[CONTENT_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_DARK_BG),
("TOPPADDING", (0,0), (-1,-1), 10),
("BOTTOMPADDING", (0,0), (-1,-1), 10),
("LEFTPADDING", (0,0), (-1,-1), 14),
("RIGHTPADDING", (0,0), (-1,-1), 14),
]))
story += [t, SP(10)]
# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 1 — ASCENDING TRACTS DETAIL
# ═══════════════════════════════════════════════════════════════════════════════
def ascending_section(story):
# Section heading bar
hdr = Table([[P("ASCENDING TRACTS (Sensory — carry signals TO brain)", T_H2_ASC)]],
colWidths=[CONTENT_W])
hdr.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_ASC_HDR),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
story += [hdr, SP(6)]
# Intro note
story.append(P(
"<b>Key principle:</b> Ascending tracts carry sensory information (touch, pain, temperature, "
"proprioception) from the body and limbs UP to the brain. They are classified into "
"<b>two main systems</b>: the <b>Dorsal Column–Medial Lemniscal (DCML)</b> system and "
"the <b>Anterolateral (Spinothalamic)</b> system. Cerebellar tracts are a third group.",
T_CELL))
story.append(SP(6))
# ── 1A. DCML Pathway ──────────────────────────────────────────────────────
story.append(P("1A. Dorsal Column – Medial Lemniscal (DCML) System", T_H1))
story.append(HR())
cw = [CONTENT_W*0.18, CONTENT_W*0.19, CONTENT_W*0.19, CONTENT_W*0.22, CONTENT_W*0.22]
rows = [
[P("Tract", T_CHDR), P("Modality", T_CHDR), P("1st Neuron\n(Cell Body)", T_CHDR),
P("2nd Neuron\n(Crosses / Ascends)", T_CHDR), P("3rd Neuron & Cortex", T_CHDR)],
[P("Fasciculus Gracilis\n(Goll's column)", T_CELLB),
P("Fine touch, vibration,\npropriception,\n2-point discrim.\nLower body\n(below T6)", T_CELL),
P("DRG → enters ipsilateral\ndorsal column, ascends\nwithout crossing", T_CELL),
P("Nucleus gracilis\n(medulla) → fibres cross\nmidline → medial\nlemniscus (contralateral)", T_CELL),
P("VPL thalamus →\nprimary somatosensory\ncortex (S1,\npostcentral gyrus)", T_CELL)],
[P("Fasciculus Cuneatus\n(Burdach's column)", T_CELLB),
P("Fine touch, vibration,\npropriception,\n2-point discrim.\nUpper body\n(above T6)", T_CELL),
P("DRG → ipsilateral\ndorsal column,\nascends without\ncrossing", T_CELL),
P("Nucleus cuneatus\n(medulla) → fibres\ncross → medial\nlemniscus", T_CELL),
P("VPL thalamus →\nS1 cortex\n(postcentral gyrus)", T_CELL)],
]
cmds = list(BASE_STYLE) + [
("BACKGROUND", (0,0), (-1,0), C_ASC_HDR),
("BACKGROUND", (0,1), (-1,1), C_ASC_LIGHT),
("BACKGROUND", (0,2), (-1,2), HexColor("#EAFAF1")),
]
story.append(make_table(rows, cw, cmds))
story.append(SP(4))
story.append(P(
"<b>Remember (DCML):</b> 1st neuron enters and ascends IPSILATERAL → crosses in MEDULLA "
"(not spinal cord) → 2nd neuron ascends as medial lemniscus → VPL thalamus → S1 cortex. "
"Lesion below medulla = ipsilateral deficit. Lesion above medulla = contralateral deficit.",
T_NOTE))
story.append(SP(8))
# ── 1B. Anterolateral / Spinothalamic ─────────────────────────────────────
story.append(P("1B. Anterolateral (Spinothalamic) System", T_H1))
story.append(HR())
cw2 = [CONTENT_W*0.18, CONTENT_W*0.20, CONTENT_W*0.20, CONTENT_W*0.20, CONTENT_W*0.22]
rows2 = [
[P("Tract", T_CHDR), P("Modality", T_CHDR), P("1st Neuron", T_CHDR),
P("2nd Neuron\n(Crosses)", T_CHDR), P("3rd Neuron & Cortex", T_CHDR)],
[P("Lateral\nSpinothalamic\nTract (LST)", T_CELLB),
P("Pain\nTemperature\n(sharp, localised)", T_CELL),
P("DRG → enters via\nLissauer's tract →\nsynapses in dorsal\nhorn (Rexed\nlamina I, II, V)", T_CELL),
P("2nd neuron crosses\nvia anterior white\ncommissure within\n1-2 spinal segments\n→ contralateral\nlateral funiculus", T_CELL),
P("VPL thalamus\n(+ intralaminar\nnuclei) → S1 cortex\n+ limbic system", T_CELL)],
[P("Anterior\nSpinothalamic\nTract (AST)", T_CELLB),
P("Crude (light)\ntouch\nPressure", T_CELL),
P("DRG → dorsal horn\n(Rexed laminae\nVI–VII)", T_CELL),
P("Crosses via anterior\nwhite commissure →\ncontralateral anterior\nfuniculus", T_CELL),
P("VPL thalamus →\nS1 cortex\n(bilaterally\nrepresented)", T_CELL)],
[P("Spinoreticular\nTract\n(Paleospinothal.)", T_CELLB),
P("Poorly localised\n(burning) pain\nAffective component\nof pain", T_CELL),
P("DRG → dorsal horn", T_CELL),
P("Short axons → relay\nin brainstem reticular\nformation → bilateral\nascent", T_CELL),
P("Intralaminar nuclei\nof thalamus →\nlimbic cortex", T_CELL)],
]
cmds2 = list(BASE_STYLE) + [
("BACKGROUND", (0,0), (-1,0), HexColor("#1A6B3A")),
("BACKGROUND", (0,1), (-1,1), C_ASC_LIGHT),
("BACKGROUND", (0,2), (-1,2), HexColor("#EAFAF1")),
("BACKGROUND", (0,3), (-1,3), C_ASC_LIGHT),
]
story.append(make_table(rows2, cw2, cmds2))
story.append(SP(4))
story.append(P(
"<b>Remember (Spinothalamic):</b> 1st neuron enters → ascends 1–2 levels in Lissauer's tract "
"→ synapses in dorsal horn → 2nd neuron CROSSES IN SPINAL CORD (anterior commissure) → "
"ascends CONTRALATERAL. "
"Somatotopy: sacral fibres outermost (superficial) at cervical level; cervical fibres innermost. "
"Lesion = contralateral pain & temperature loss BELOW lesion level.",
T_NOTE))
story.append(SP(8))
# ── 1C. Cerebellar Tracts ──────────────────────────────────────────────────
story.append(P("1C. Spinocerebellar Tracts (Unconscious Proprioception)", T_H1))
story.append(HR())
cw3 = [CONTENT_W*0.22, CONTENT_W*0.18, CONTENT_W*0.20, CONTENT_W*0.20, CONTENT_W*0.20]
rows3 = [
[P("Tract", T_CHDR), P("Modality", T_CHDR), P("Origin", T_CHDR),
P("Course", T_CHDR), P("Destination", T_CHDR)],
[P("Dorsal\nSpinocerebellar\n(Flechsig's)", T_CELLB),
P("Unconscious\nproprioception\nLower limbs +\ninferior trunk", T_CELL),
P("Clarke's column\n(nucleus dorsalis)\nC8–L2 → ipsilateral\nlateral funiculus", T_CELL),
P("Does NOT cross\n→ ipsilateral\nlateral column\n→ inferior cerebellar\npeduncle", T_CELL),
P("Ipsilateral\ncerebellum\n(vermis)", T_CELL)],
[P("Ventral\nSpinocerebellar\n(Gowers')", T_CELLB),
P("Unconscious\nproprioception\nLower limbs", T_CELL),
P("Lumbar spinal\nborder cells\n(lamina V–VII)", T_CELL),
P("Crosses TWICE\n(spinal cord then\npons) → superior\ncerebellar peduncle", T_CELL),
P("Contralateral then\nrecrosses back to\nipsilateral cerebellum", T_CELL)],
[P("Cuneocerebellar\n(Posterior ext.\narcuate fibres)", T_CELLB),
P("Unconscious\nproprioception\nUpper limbs +\ntrunk (above T6)", T_CELL),
P("Accessory cuneate\nnucleus (medulla)", T_CELL),
P("Ipsilateral →\ninferior cerebellar\npeduncle", T_CELL),
P("Ipsilateral\ncerebellum", T_CELL)],
[P("Rostral\nSpinocerebellar", T_CELLB),
P("Unconscious\nproprioception\nUpper limbs\n(functional)", T_CELL),
P("Cervical enlargement\nlamina V–VII", T_CELL),
P("Mainly ipsilateral\n→ superior / inferior\npeduncle", T_CELL),
P("Ipsilateral\ncerebellum", T_CELL)],
]
cmds3 = list(BASE_STYLE) + [
("BACKGROUND", (0,0), (-1,0), HexColor("#145A32")),
("BACKGROUND", (0,1), (-1,1), C_ASC_LIGHT),
("BACKGROUND", (0,2), (-1,2), HexColor("#EAFAF1")),
("BACKGROUND", (0,3), (-1,3), C_ASC_LIGHT),
("BACKGROUND", (0,4), (-1,4), HexColor("#EAFAF1")),
]
story.append(make_table(rows3, cw3, cmds3))
story.append(SP(4))
story.append(P(
"<b>Remember (Cerebellar):</b> Dorsal spinocerebellar = ipsilateral, does NOT cross. "
"Ventral spinocerebellar = crosses TWICE (effectively ipsilateral). "
"Cerebellar tracts = UNCONSCIOUS proprioception (no cortical awareness). "
"Lesion → ipsilateral ataxia.",
T_NOTE))
# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 2 — DESCENDING TRACTS
# ═══════════════════════════════════════════════════════════════════════════════
def descending_section(story):
story.append(PageBreak())
hdr = Table([[P("DESCENDING TRACTS (Motor — carry signals FROM brain)", T_H2_DESC)]],
colWidths=[CONTENT_W])
hdr.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_DESC_HDR),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
story += [hdr, SP(6)]
story.append(P(
"<b>Key principle:</b> Descending tracts carry motor commands DOWN from the brain to spinal "
"cord lower motor neurons (LMNs). Divided into <b>Lateral pathways</b> (fine voluntary "
"movement of distal muscles) and <b>Ventromedial (Anteromedial) pathways</b> "
"(posture, balance, axial/proximal muscles).",
T_CELL))
story.append(SP(6))
# ── 2A. Lateral Pathways ───────────────────────────────────────────────────
story.append(P("2A. Lateral Pathways (Fine Voluntary Movement)", T_H1))
story.append(HR())
cw = [CONTENT_W*0.20, CONTENT_W*0.18, CONTENT_W*0.18, CONTENT_W*0.22, CONTENT_W*0.22]
rows = [
[P("Tract", T_CHDR), P("Origin", T_CHDR), P("Decussation", T_CHDR),
P("Cord Position & Course", T_CHDR), P("Function", T_CHDR)],
[P("Lateral\nCorticospinal\nTract (LCST)\n~85%", T_CELLB),
P("Primary motor cortex\n(area 4, layer V)\nPremotor (area 6)\nSMA, parietal cortex", T_CELL),
P("Pyramidal\ndecussation\nat cervicomedullary\njunction (medulla)", T_CELL),
P("Lateral funiculus\n(posterior part)\nSomatotopy:\nArm medial,\nLeg lateral", T_CELL),
P("Voluntary fine\nmovement of\ncontralateral\ndistal limbs\n(fingers, hand)", T_CELL)],
[P("Anterior\nCorticospinal\nTract (ACST)\n~15%", T_CELLB),
P("Primary motor cortex\n(area 4, layer V)", T_CELL),
P("Crosses at\nsegmental level\n(anterior commissure)", T_CELL),
P("Anterior funiculus\n(medial)", T_CELL),
P("Axial + proximal\nmuscles, bilateral\ncontrol", T_CELL)],
[P("Rubrospinal\nTract", T_CELLB),
P("Red nucleus\n(midbrain\ntegmentum)", T_CELL),
P("Immediate\ndecussation\nin ventral pons\n(dorsal tegmental)", T_CELL),
P("Lateral funiculus\n(anterior to LCST)\nOnly to upper\ncervical cord", T_CELL),
P("Fine arm/hand\nmovement\n(minor in humans;\nreplaced by CST\nin evolution)", T_CELL)],
]
cmds = list(BASE_STYLE) + [
("BACKGROUND", (0,0), (-1,0), C_DESC_HDR),
("BACKGROUND", (0,1), (-1,1), C_DESC_LIGHT),
("BACKGROUND", (0,2), (-1,2), HexColor("#FDEDEC")),
("BACKGROUND", (0,3), (-1,3), C_DESC_LIGHT),
]
story.append(make_table(rows, cw, cmds))
story.append(SP(4))
story.append(P(
"<b>Corticobulbar tract:</b> Fibres from motor cortex that project to <i>brainstem cranial nerve "
"nuclei</i> (rather than spinal cord) — controls face, jaw, tongue, palate, pharynx. "
"Most CN nuclei receive BILATERAL cortical input except lower face (CN VII) and hypoglossal "
"(CN XII) which are predominantly contralateral — clinically important in central vs peripheral "
"facial palsy distinction.",
T_NOTE))
story.append(SP(8))
# ── 2B. Ventromedial Pathways ──────────────────────────────────────────────
story.append(P("2B. Ventromedial (Anteromedial) Pathways (Posture & Balance)", T_H1))
story.append(HR())
cw2 = [CONTENT_W*0.22, CONTENT_W*0.18, CONTENT_W*0.17, CONTENT_W*0.21, CONTENT_W*0.22]
rows2 = [
[P("Tract", T_CHDR), P("Origin", T_CHDR), P("Decussation", T_CHDR),
P("Cord Position", T_CHDR), P("Function", T_CHDR)],
[P("Lateral\nVestibulospinal\nTract", T_CELLB),
P("Lateral vestibular\nnucleus (Deiters')\nin medulla", T_CELL),
P("None\n(Ipsilateral)", T_CELL),
P("Anterior funiculus\n→ full length\nof cord", T_CELL),
P("Facilitates EXTENSOR\nmotor neurons\n→ maintains upright\nposture / balance", T_CELL)],
[P("Medial\nVestibulospinal\nTract", T_CELLB),
P("Medial vestibular\nnucleus (medulla)", T_CELL),
P("Bilateral\n(crosses partially)", T_CELL),
P("Anterior funiculus\n→ cervical cord\nonly", T_CELL),
P("Head & neck\nposture, stabilises\nhead during\nbody movement", T_CELL)],
[P("Tectospinal\nTract", T_CELLB),
P("Superior colliculus\n(midbrain)\n[vision + auditory\ninput]", T_CELL),
P("Dorsal tegmental\ndecussation\n(immediately)", T_CELL),
P("Anterior funiculus\n→ cervical cord\nonly (C1-C4)", T_CELL),
P("Reflex head & neck\nturning toward\nvisual / auditory\nstimuli", T_CELL)],
[P("Pontine\nReticulospinal\nTract\n(Medial RST)", T_CELLB),
P("Pontine reticular\nformation (PMRF)\n= nucleus\nreticularis pontis", T_CELL),
P("None\n(Ipsilateral)", T_CELL),
P("Anterior funiculus\n(medial)", T_CELL),
P("FACILITATES\nantigravity extensor\nstretch reflexes\n→ maintains\nstanding posture", T_CELL)],
[P("Medullary\nReticulospinal\nTract\n(Lateral RST)", T_CELLB),
P("Medullary reticular\nformation\n= nucleus\nreticularis gigantocellularis", T_CELL),
P("Bilateral\n(partly crosses)", T_CELL),
P("Lateral funiculus\n(anterior part)", T_CELL),
P("INHIBITS\nantigravity muscles;\nliberates them\nfrom reflex control\n→ enables movement", T_CELL)],
]
cmds2 = list(BASE_STYLE) + [
("BACKGROUND", (0,0), (-1,0), HexColor("#6E2C2C")),
("BACKGROUND", (0,1), (-1,1), C_DESC_LIGHT),
("BACKGROUND", (0,2), (-1,2), HexColor("#FDEDEC")),
("BACKGROUND", (0,3), (-1,3), C_DESC_LIGHT),
("BACKGROUND", (0,4), (-1,4), HexColor("#FDEDEC")),
("BACKGROUND", (0,5), (-1,5), C_DESC_LIGHT),
]
story.append(make_table(rows2, cw2, cmds2))
story.append(SP(4))
story.append(P(
"<b>Reticulospinal clinical note:</b> The pontine RST facilitates extensors; medullary RST "
"inhibits them. In an upper brainstem (midbrain) lesion, the medullary RST is also cut, "
"leaving unopposed pontine facilitation → <b>decerebrate rigidity</b> (all four limbs extended). "
"In a lower brainstem lesion sparing the medullary RST → <b>decorticate posture</b> (arm "
"flexion, leg extension).",
T_NOTE))
# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 3 — MASTER COMPARISON TABLE
# ═══════════════════════════════════════════════════════════════════════════════
def comparison_section(story):
story.append(PageBreak())
hdr = Table([[P("ASCENDING vs DESCENDING — Master Comparison", T_H2_ASC)]],
colWidths=[CONTENT_W])
hdr.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_BLUE_HDR),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
story += [hdr, SP(6)]
cw = [CONTENT_W*0.22, CONTENT_W*0.39, CONTENT_W*0.39]
rows = [
[P("Feature", T_CHDR),
P("ASCENDING Tracts (Sensory)", T_CHDR),
P("DESCENDING Tracts (Motor)", T_CHDR)],
[P("Direction", T_CELLB),
P("Body/periphery → Spinal cord → Brain", T_CELL),
P("Brain → Spinal cord → Muscle / effector", T_CELL)],
[P("Function", T_CELLB),
P("Carry sensory information: touch, pain,\ntemperature, proprioception, vibration", T_CELL),
P("Carry motor commands: voluntary movement,\nposture, balance, reflex control", T_CELL)],
[P("Neuron order", T_CELLB),
P("3 neurons:\n1st = DRG → 2nd = spinal cord/medulla\n→ 3rd = thalamus → cortex", T_CELL),
P("2 neurons (UMN + LMN):\nUMN = cortex → spinal cord\nLMN = spinal cord → muscle", T_CELL)],
[P("Where do fibres\ncross (decussate)?", T_CELLB),
P("DCML: Medulla (nucleus gracilis/cuneatus)\nSpinothalamic: Spinal cord\n(anterior commissure, 1–2 segments above entry)", T_CELL),
P("CST (lateral): Medulla (pyramidal decussation)\nCST (anterior): Spinal cord (segmental)\nRubrospinal: Immediately in pons\nVestibulo/Tecto/Reticulospinal: Mostly ipsilateral", T_CELL)],
[P("Side of cord\n(at spinal level)", T_CELLB),
P("DCML: Ipsilateral dorsal column\nSpinothalamic: Contralateral anterolateral", T_CELL),
P("LCST: Contralateral lateral column\nACT: Ipsilateral anterior column\nVentromedial: Anterior column (mostly)", T_CELL)],
[P("Cortical destination\n/ origin", T_CELLB),
P("Primary somatosensory cortex (S1)\n= postcentral gyrus (areas 3, 1, 2)\nCerebellar tracts → cerebellum (no cortex)", T_CELL),
P("Primary motor cortex (M1)\n= precentral gyrus (area 4)\nPremotor / SMA (area 6)", T_CELL)],
[P("Thalamic relay", T_CELLB),
P("VPL nucleus of thalamus\n(sensory relay for body + limbs)\nVPM for face (trigeminal)", T_CELL),
P("VL nucleus of thalamus\n(motor relay — input from cerebellum\nand basal ganglia to motor cortex)", T_CELL)],
[P("Key clinical sign\nif damaged", T_CELLB),
P("Loss of specific sensory modality\nbelow lesion level\n(pattern depends on tract affected)", T_CELL),
P("Upper Motor Neuron signs if LCST\n(spasticity, hyperreflexia, Babinski)\nLower Motor Neuron signs at level", T_CELL)],
[P("Somatotopic\norganisation", T_CELLB),
P("Spinothalamic: Sacral outermost\n(clinically: central cord → sacral sparing)\nDCML: Sacral medial, cervical lateral", T_CELL),
P("LCST: Arm medial, leg lateral\nInternal capsule: Face ant, leg post\n(Homunculus preserved throughout)", T_CELL)],
[P("Effect of complete\nspinal cord lesion", T_CELLB),
P("All sensation lost below level\n(DCML + spinothalamic both cut)", T_CELL),
P("UMN paralysis below level\n(initially flaccid — spinal shock\nthen spastic with hyperreflexia)", T_CELL)],
[P("Cord syndrome\nexample", T_CELLB),
P("Brown-Sequard: ipsilateral DCML\nloss + contralateral spinothalamic loss\n= hemisection of cord", T_CELL),
P("Brown-Sequard: ipsilateral UMN\nparalysis below lesion level", T_CELL)],
]
cmds = list(BASE_STYLE) + [
("BACKGROUND", (0,0), (0,0), C_BLUE_HDR),
("BACKGROUND", (1,0), (1,0), C_ASC_HDR),
("BACKGROUND", (2,0), (2,0), C_DESC_HDR),
("BACKGROUND", (0,1), (0,-1), HexColor("#EBF5FB")),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("FONTSIZE", (0,1), (0,-1), 8),
]
for i in range(1, len(rows)):
bg_asc = C_ASC_LIGHT if i % 2 == 1 else HexColor("#EAFAF1")
bg_desc = C_DESC_LIGHT if i % 2 == 1 else HexColor("#FDEDEC")
cmds.append(("BACKGROUND", (1,i), (1,i), bg_asc))
cmds.append(("BACKGROUND", (2,i), (2,i), bg_desc))
story.append(make_table(rows, cw, cmds))
story.append(SP(8))
# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 4 — BROWN-SEQUARD + CORD SYNDROMES
# ═══════════════════════════════════════════════════════════════════════════════
def cord_syndromes(story):
story.append(P("Spinal Cord Syndromes — Tract Lesion Patterns", T_H1))
story.append(HR())
cw = [CONTENT_W*0.22, CONTENT_W*0.26, CONTENT_W*0.26, CONTENT_W*0.26]
rows = [
[P("Syndrome", T_CHDR), P("Tracts Affected", T_CHDR),
P("Signs & Symptoms", T_CHDR), P("Classic Cause", T_CHDR)],
[P("Brown-Sequard\n(Hemisection)", T_CELLB),
P("LCST + DCML (ipsilateral)\nSpinothalamic (contralateral)", T_CELL),
P("Ipsilateral: UMN motor loss\n+ proprioception/vibration loss\nContralateral: pain &\ntemperature loss (1–2 levels below)", T_CELL),
P("Penetrating spinal\ntrauma, MS,\ntumour", T_CELL)],
[P("Central Cord\nSyndrome", T_CELLB),
P("Central grey matter\n+ crossing spinothalamic\nfibres first affected", T_CELL),
P("Cape distribution:\nBilateral pain & temp loss\n(arms > legs)\nMotor weakness arms > legs\nSacral sensation SPARED", T_CELL),
P("Hyperextension in\ncervical spondylosis;\nSyringomyelia", T_CELL)],
[P("Anterior Cord\nSyndrome", T_CELLB),
P("Spinothalamic (bilateral)\n+ Corticospinal (bilateral)\nDCML spared", T_CELL),
P("Bilateral motor paralysis +\nbilateral pain & temp loss\nbelow lesion\nPropriocepion & vibration\nINTACT", T_CELL),
P("Anterior spinal\nartery infarct", T_CELL)],
[P("Posterior Cord\nSyndrome", T_CELLB),
P("DCML (bilateral)\nSpinothalaamic spared", T_CELL),
P("Loss of proprioception,\nvibration, fine touch\nSensory ataxia, Romberg +ve\nPain & temp INTACT", T_CELL),
P("Tabes dorsalis\n(syphilis), B12\ndeficiency", T_CELL)],
[P("Conus Medullaris\nSyndrome", T_CELLB),
P("S3–S5 segments\n(LMN + UMN mix)", T_CELL),
P("Saddle anaesthesia\nBladder/bowel/\nsexual dysfunction\nMixed UMN + LMN\nleg signs", T_CELL),
P("L1 fracture,\ntumour, disc prolapse", T_CELL)],
]
cmds = list(BASE_STYLE) + [
("BACKGROUND", (0,0), (-1,0), C_BLUE_HDR),
]
for i in range(1, len(rows)):
bg = C_PALE if i % 2 == 0 else C_WHITE
cmds.append(("BACKGROUND", (0,i), (-1,i), bg))
cmds.append(("BACKGROUND", (0,1), (-1,1), HexColor("#FEF9E7"))) # BS highlight
story.append(make_table(rows, cw, cmds))
story.append(SP(8))
# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 5 — QUICK MNEMONICS + EXAM TIPS
# ═══════════════════════════════════════════════════════════════════════════════
def mnemonics_section(story):
story.append(P("Quick Mnemonics & Exam Tips", T_H1))
story.append(HR())
tips = [
("<b>DCML crossing rule:</b>",
"\"Goes UP FIRST, crosses in MEDULLA\" — fibres travel ipsilaterally until the medulla, "
"then cross. Lesion at or below medulla = ipsilateral deficit."),
("<b>Spinothalamic crossing rule:</b>",
"\"Crosses SOON & BELOW\" — crosses in spinal cord within 1–2 segments of entry. "
"Lesion = contralateral pain/temp loss. Level of sensory loss is 1–2 levels BELOW lesion."),
("<b>LCST crossing rule:</b>",
"\"Crosses in MEDULLA at pyramidal decussation\" — contralateral UMN signs below lesion. "
"Above decussation = contralateral; Below decussation = ipsilateral weakness."),
("<b>Somatotopy trick (spinothalamic):</b>",
"\"SALE\" from outside in at cervical level: Sacral – Lumbar – Thoracic – cErvical "
"(outermost to innermost). Central cord lesion spares sacral = sacral sparing."),
("<b>Dorsal column fibres:</b>",
"Gracilis (medial) = lower body (graceful legs). Cuneatus (lateral) = upper body/arms. "
"Mnemonic: \"Grace is thin (medial, lower)\""),
("<b>Cerebellar tracts memory:</b>",
"Dorsal = \"DOES NOT cross\" (ipsilateral). Ventral = \"crosses TWICE\" (still ipsilateral). "
"Both go to the SAME side cerebellum as origin."),
("<b>Decerebrate vs Decorticate:</b>",
"Decerebrate (midbrain lesion) = ALL four limbs EXTENDED (arms + legs straight). "
"Decorticate (cortical/internal capsule) = Arms FLEXED, legs extended. "
"Mnemonic: deCORticate = COR = arms toward CORe (flex toward chest)"),
("<b>Brown-Sequard shortcut:</b>",
"Ipsilateral side = Motor loss + Fine touch/proprioception loss. "
"Contralateral side = Pain & temperature loss. "
"Mnemonic: \"Same side suffers motor; opposite side loses pain\""),
]
half = (CONTENT_W - 4) / 2
tip_rows = []
for i in range(0, len(tips), 2):
left = tips[i]
right = tips[i+1] if i+1 < len(tips) else ("", "")
def make_cell(tip):
return P(f'<font color="#154360">{tip[0]}</font><br/>'
f'<font color="#2C3E50" size="7.5">{tip[1]}</font>',
S("Normal", fontSize=8, leading=11, fontName="Helvetica"))
tip_rows.append([make_cell(left), make_cell(right)])
mnem_tbl = Table(tip_rows, colWidths=[half, half])
mnem_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), HexColor("#F8F9FA")),
("BOX", (0,0), (-1,-1), 0.8, HexColor("#AEB6BF")),
("INNERGRID", (0,0), (-1,-1), 0.4, HexColor("#D5D8DC")),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(mnem_tbl)
story.append(SP(8))
# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 6 — ONE-LINE FLASH SUMMARY TABLE
# ═══════════════════════════════════════════════════════════════════════════════
def flash_summary(story):
story.append(P("Flash Summary — All Tracts at a Glance", T_H1))
story.append(HR())
cw = [CONTENT_W*0.22, CONTENT_W*0.10, CONTENT_W*0.17, CONTENT_W*0.17, CONTENT_W*0.17, CONTENT_W*0.17]
rows = [
[P("Tract", T_CHDR), P("Type", T_CHDR), P("Crosses Where?", T_CHDR),
P("Cord Column", T_CHDR), P("Modality / Function", T_CHDR), P("Destination", T_CHDR)],
# Ascending
[P("Fasciculus Gracilis", T_CELLB), P("ASC", S("Normal",fontSize=8,textColor=C_ASC_HDR,fontName="Helvetica-Bold")),
P("Medulla (nucleus gracilis)", T_CELL), P("Dorsal (medial)", T_CELL),
P("Proprioception, vibration,\nfine touch (lower body)", T_CELL), P("VPL → S1 cortex", T_CELL)],
[P("Fasciculus Cuneatus", T_CELLB), P("ASC", S("Normal",fontSize=8,textColor=C_ASC_HDR,fontName="Helvetica-Bold")),
P("Medulla (nucleus cuneatus)", T_CELL), P("Dorsal (lateral)", T_CELL),
P("Proprioception, vibration,\nfine touch (upper body)", T_CELL), P("VPL → S1 cortex", T_CELL)],
[P("Lateral Spinothalamic", T_CELLB), P("ASC", S("Normal",fontSize=8,textColor=C_ASC_HDR,fontName="Helvetica-Bold")),
P("Spinal cord\n(ant. commissure)", T_CELL), P("Anterolateral", T_CELL),
P("Pain, Temperature", T_CELL), P("VPL → S1 cortex", T_CELL)],
[P("Anterior Spinothalamic", T_CELLB), P("ASC", S("Normal",fontSize=8,textColor=C_ASC_HDR,fontName="Helvetica-Bold")),
P("Spinal cord\n(ant. commissure)", T_CELL), P("Anterolateral", T_CELL),
P("Crude touch, Pressure", T_CELL), P("VPL → S1 cortex", T_CELL)],
[P("Dorsal Spinocerebellar", T_CELLB), P("ASC", S("Normal",fontSize=8,textColor=C_ASC_HDR,fontName="Helvetica-Bold")),
P("Does NOT cross", T_CELL), P("Lateral (posterior)", T_CELL),
P("Unconscious proprioception\n(lower limbs)", T_CELL), P("Ipsilateral cerebellum", T_CELL)],
[P("Ventral Spinocerebellar", T_CELLB), P("ASC", S("Normal",fontSize=8,textColor=C_ASC_HDR,fontName="Helvetica-Bold")),
P("Crosses TWICE", T_CELL), P("Lateral (anterior)", T_CELL),
P("Unconscious proprioception\n(lower limbs)", T_CELL), P("Ipsilateral cerebellum", T_CELL)],
# Descending
[P("Lateral Corticospinal", T_CELLB), P("DESC", S("Normal",fontSize=8,textColor=C_DESC_HDR,fontName="Helvetica-Bold")),
P("Medulla (pyramidal\ndecussation)", T_CELL), P("Lateral (posterior)", T_CELL),
P("Voluntary fine movement\n(distal, contralateral)", T_CELL), P("Ventral horn LMN", T_CELL)],
[P("Anterior Corticospinal", T_CELLB), P("DESC", S("Normal",fontSize=8,textColor=C_DESC_HDR,fontName="Helvetica-Bold")),
P("Spinal cord\n(segmental)", T_CELL), P("Anterior", T_CELL),
P("Axial/proximal muscles\n(bilateral)", T_CELL), P("Ventral horn LMN", T_CELL)],
[P("Rubrospinal", T_CELLB), P("DESC", S("Normal",fontSize=8,textColor=C_DESC_HDR,fontName="Helvetica-Bold")),
P("Immediately in pons", T_CELL), P("Lateral (anterior)", T_CELL),
P("Fine arm movement\n(minor in humans)", T_CELL), P("Ventral horn LMN", T_CELL)],
[P("Lateral Vestibulospinal", T_CELLB), P("DESC", S("Normal",fontSize=8,textColor=C_DESC_HDR,fontName="Helvetica-Bold")),
P("None (ipsilateral)", T_CELL), P("Anterior", T_CELL),
P("Facilitates extensors\n(balance/posture)", T_CELL), P("Ventral horn LMN", T_CELL)],
[P("Medial Vestibulospinal", T_CELLB), P("DESC", S("Normal",fontSize=8,textColor=C_DESC_HDR,fontName="Helvetica-Bold")),
P("Bilateral", T_CELL), P("Anterior", T_CELL),
P("Head/neck posture", T_CELL), P("Cervical LMN", T_CELL)],
[P("Tectospinal", T_CELLB), P("DESC", S("Normal",fontSize=8,textColor=C_DESC_HDR,fontName="Helvetica-Bold")),
P("Dorsal tegmental\ndecussation", T_CELL), P("Anterior", T_CELL),
P("Reflex head-turn to\naudio-visual stimuli", T_CELL), P("Cervical LMN", T_CELL)],
[P("Pontine Reticulospinal", T_CELLB), P("DESC", S("Normal",fontSize=8,textColor=C_DESC_HDR,fontName="Helvetica-Bold")),
P("None (ipsilateral)", T_CELL), P("Anterior (medial)", T_CELL),
P("Facilitates extensor\nstretch reflexes", T_CELL), P("Ventral horn LMN", T_CELL)],
[P("Medullary Reticulospinal", T_CELLB), P("DESC", S("Normal",fontSize=8,textColor=C_DESC_HDR,fontName="Helvetica-Bold")),
P("Bilateral", T_CELL), P("Lateral (anterior)", T_CELL),
P("Inhibits antigravity\nmuscles", T_CELL), P("Ventral horn LMN", T_CELL)],
]
cmds = list(BASE_STYLE) + [
("BACKGROUND", (0,0), (-1,0), C_BLUE_HDR),
("FONTSIZE", (0,0), (-1,0), 8.5),
]
# Shading by type
for i in range(1, len(rows)):
if i <= 7: # ascending
bg = C_ASC_LIGHT if i % 2 == 1 else HexColor("#EAFAF1")
else: # descending
bg = C_DESC_LIGHT if i % 2 == 1 else HexColor("#FDEDEC")
cmds.append(("BACKGROUND", (0,i), (-1,i), bg))
story.append(make_table(rows, cw, cmds))
story.append(SP(6))
# ═══════════════════════════════════════════════════════════════════════════════
# FOOTER
# ═══════════════════════════════════════════════════════════════════════════════
def footer(story):
notes = (
"Notes: DRG = Dorsal Root Ganglion | VPL = Ventroposterolateral nucleus of thalamus | "
"VPM = Ventroposteromedial | S1 = Primary Somatosensory Cortex | M1 = Primary Motor Cortex | "
"UMN = Upper Motor Neuron | LMN = Lower Motor Neuron | ASC = Ascending | DESC = Descending | "
"LCST = Lateral Corticospinal Tract | DCML = Dorsal Column-Medial Lemniscal | "
"SMA = Supplementary Motor Area | RST = Reticulospinal Tract"
)
story.append(Paragraph(notes, S("Normal", fontSize=7, textColor=C_GRAY,
fontName="Helvetica-Oblique", leading=10)))
story.append(SP(4))
story.append(Paragraph("Orris Medical — Spinal Tracts Quick Revision | July 2026",
S("Normal", fontSize=7.5, textColor=HexColor("#AEB6BF"),
fontName="Helvetica", alignment=TA_CENTER)))
# ── BUILD ─────────────────────────────────────────────────────────────────────
story = []
banner(story)
ascending_section(story)
descending_section(story)
comparison_section(story)
cord_syndromes(story)
mnemonics_section(story)
flash_summary(story)
footer(story)
doc.build(story)
print(f"Done: {OUT}")
cd /home/daytona/workspace/tracts-revision && python build_pdf.py 2>&1
ls -lh /home/daytona/workspace/tracts-revision/
Spinal Tracts Quick Revision
PDF Document · PDF