Please take reference either dp, ak jain, or guyton
Spinothalamic tract
Important: It takes 2-3 spinal segments for the decussating fibers to fully reach the opposite side. This means a lateral cord lesion causes contralateral pain/temperature loss beginning a few segments below the lesion level.
| Division | Location | Sensations |
|---|---|---|
| Lateral spinothalamic tract | Lateral white column | Pain and temperature (neospinothalamic) |
| Anterior (ventral) spinothalamic tract | Anterior white column | Crude touch, pressure |
Note: Most pain signals go via reticular nuclei → intralaminar thalamic nuclei, NOT directly to VPL. Only a small fraction projects directly to VPL. - Guyton, Chapter 48
| Tract | Termination | Function |
|---|---|---|
| Spinothalamic | VPL thalamus → somatosensory cortex | Discriminative pain/temp (location, intensity) |
| Spinoreticular | Medullary-pontine reticular formation → intralaminar thalamic nuclei → cortex | Emotional/arousal aspects of pain ("ouch, that hurts") |
| Spinomesencephalic | Midbrain periaqueductal gray (PAG), superior colliculi | Central modulation/inhibition of pain ("aah, that feels better") |
| Feature | Anterolateral (Spinothalamic) | Dorsal Column-Medial Lemniscal |
|---|---|---|
| Velocity | 8-40 m/sec (1/3 to 1/2 of DC) | 30-110 m/sec |
| Spatial localization | Poor | Precise |
| Intensity gradations | ~10-20 levels | ~100 levels |
| Rapidly changing signals | Poor | Excellent |
| Type of system | "Crude" | "Discriminative" |

Convert into pdf with good diagrams
mkdir -p /home/daytona/workspace/spinothalamic && ls /home/daytona/workspace/spinothalamic
cd /home/daytona/workspace/spinothalamic && curl -s -o guyton_diagram.png "https://cdn.orris.care/cdss_images/5c7b52f574ec017ec19e24eb5275e8dc4ae32486de1f33cc041b83cabbb3552b.png" && echo "Downloaded: $(ls -lh guyton_diagram.png)"
~/spinothalamic/make_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm, mm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, Image, KeepTogether, PageBreak
)
from reportlab.platypus.flowables import Flowable
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.pdfgen import canvas
from reportlab.graphics.shapes import Drawing, Rect, Line, Circle, String, Arrow, Polygon
from reportlab.graphics import renderPDF
from reportlab.graphics.shapes import Drawing, Path
import os, math
OUTPUT = "/home/daytona/workspace/spinothalamic/Spinothalamic_Tract.pdf"
GUYTON_IMG = "/home/daytona/workspace/spinothalamic/guyton_diagram.png"
# ── Color palette ─────────────────────────────────────────────────────────────
C_NAVY = colors.HexColor("#1a237e")
C_BLUE = colors.HexColor("#1565c0")
C_LBLUE = colors.HexColor("#e3f2fd")
C_TEAL = colors.HexColor("#00838f")
C_LTEAL = colors.HexColor("#e0f7fa")
C_RED = colors.HexColor("#c62828")
C_LRED = colors.HexColor("#ffebee")
C_ORANGE = colors.HexColor("#e65100")
C_AMBER = colors.HexColor("#fff8e1")
C_GREEN = colors.HexColor("#2e7d32")
C_LGREEN = colors.HexColor("#e8f5e9")
C_GRAY = colors.HexColor("#455a64")
C_LGRAY = colors.HexColor("#f5f5f5")
C_WHITE = colors.white
C_PURPLE = colors.HexColor("#6a1b9a")
C_LPURPLE = colors.HexColor("#f3e5f5")
W, H = A4 # 595 x 842 pt
# ── Page template with header/footer ──────────────────────────────────────────
def on_page(canv, doc):
canv.saveState()
# Top bar
canv.setFillColor(C_NAVY)
canv.rect(0, H - 28, W, 28, fill=1, stroke=0)
canv.setFillColor(C_WHITE)
canv.setFont("Helvetica-Bold", 9)
canv.drawString(20, H - 18, "SPINOTHALAMIC TRACT")
canv.setFont("Helvetica", 8)
canv.drawRightString(W - 20, H - 18, "Ref: Guyton & Hall | Neuroanatomy through Clinical Cases 3e")
# Bottom bar
canv.setFillColor(C_NAVY)
canv.rect(0, 0, W, 20, fill=1, stroke=0)
canv.setFillColor(C_WHITE)
canv.setFont("Helvetica", 7.5)
canv.drawCentredString(W / 2, 7, f"Page {doc.page}")
canv.restoreState()
# ── Styles ─────────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
def make_style(name, parent="Normal", **kw):
s = ParagraphStyle(name, parent=styles[parent], **kw)
return s
S_TITLE = make_style("MyTitle", fontSize=26, textColor=C_WHITE,
fontName="Helvetica-Bold", alignment=TA_CENTER, leading=32)
S_SUBTITLE= make_style("MySub", fontSize=11, textColor=C_LBLUE,
fontName="Helvetica", alignment=TA_CENTER, leading=16)
S_H1 = make_style("MyH1", fontSize=14, textColor=C_WHITE,
fontName="Helvetica-Bold", alignment=TA_LEFT, leading=18)
S_H2 = make_style("MyH2", fontSize=11, textColor=C_NAVY,
fontName="Helvetica-Bold", alignment=TA_LEFT, leading=15,
spaceBefore=6, spaceAfter=3)
S_BODY = make_style("MyBody", fontSize=9.5, textColor=C_GRAY,
fontName="Helvetica", alignment=TA_JUSTIFY, leading=14,
spaceBefore=2, spaceAfter=2)
S_BULLET = make_style("MyBullet", fontSize=9.5, textColor=C_GRAY,
fontName="Helvetica", leftIndent=14, leading=14,
spaceBefore=1, spaceAfter=1)
S_CAPTION = make_style("MyCaption", fontSize=8, textColor=C_GRAY,
fontName="Helvetica-Oblique", alignment=TA_CENTER,
spaceBefore=3)
S_SMALL = make_style("MySmall", fontSize=8, textColor=C_GRAY,
fontName="Helvetica", leading=11)
S_BOX = make_style("MyBox", fontSize=9, textColor=C_NAVY,
fontName="Helvetica", leading=13, leftIndent=6, rightIndent=6)
# ── Helper flowables ───────────────────────────────────────────────────────────
class SectionHeader(Flowable):
def __init__(self, text, color=C_NAVY, width=None):
super().__init__()
self.text = text
self.color = color
self._width = width or (W - 80)
self.height = 26
def draw(self):
self.canv.setFillColor(self.color)
self.canv.roundRect(0, 0, self._width, self.height, 4, fill=1, stroke=0)
self.canv.setFillColor(C_WHITE)
self.canv.setFont("Helvetica-Bold", 11)
self.canv.drawString(10, 8, self.text)
def wrap(self, aw, ah):
return self._width, self.height
class ColorBox(Flowable):
"""Colored background box for highlighted content."""
def __init__(self, content_lines, bg=C_LBLUE, border=C_BLUE, width=None):
super().__init__()
self.lines = content_lines
self.bg = bg
self.border = border
self._w = width or (W - 80)
self.height = 14 * len(content_lines) + 16
def draw(self):
c = self.canv
c.setFillColor(self.bg)
c.setStrokeColor(self.border)
c.setLineWidth(0.8)
c.roundRect(0, 0, self._w, self.height, 5, fill=1, stroke=1)
c.setFillColor(C_GRAY)
c.setFont("Helvetica", 9)
y = self.height - 12
for line in self.lines:
c.drawString(10, y, line)
y -= 14
def wrap(self, aw, ah):
return self._w, self.height
# ── Spine diagram (custom drawn) ───────────────────────────────────────────────
class SpinalCordDiagram(Flowable):
"""
Simplified schematic cross-section + pathway diagram of spinothalamic tract.
"""
W = 480
H = 320
def wrap(self, aw, ah):
return self.W, self.H
def draw(self):
c = self.canv
w, h = self.W, self.H
# Background
c.setFillColor(colors.HexColor("#fafafa"))
c.setStrokeColor(colors.HexColor("#cccccc"))
c.roundRect(0, 0, w, h, 6, fill=1, stroke=1)
# Title
c.setFillColor(C_NAVY)
c.setFont("Helvetica-Bold", 10)
c.drawCentredString(w/2, h - 16, "Spinothalamic Tract — Schematic Pathway")
# ── Left side: spinal cord cross-section ──────────────────────
cx, cy = 110, h/2 - 10 # center of cross-section
r = 52 # outer radius
# Outer oval
c.setFillColor(colors.HexColor("#ffe0b2"))
c.setStrokeColor(colors.HexColor("#bf360c"))
c.setLineWidth(1.5)
c.ellipse(cx-r, cy-r*0.85, cx+r, cy+r*0.85, fill=1, stroke=1)
# Butterfly gray matter
c.setFillColor(colors.HexColor("#ffccbc"))
c.setStrokeColor(colors.HexColor("#bf360c"))
c.setLineWidth(1)
# Dorsal horns
c.bezier(cx-8, cy+8, cx-25, cy+30, cx-35, cy+38, cx-22, cy+14)
c.bezier(cx+8, cy+8, cx+25, cy+30, cx+35, cy+38, cx+22, cy+14)
# Ventral horns
c.bezier(cx-8, cy-8, cx-28, cy-26, cx-38, cy-34, cx-20, cy-12)
c.bezier(cx+8, cy-8, cx+28, cy-26, cx+38, cy-34, cx+20, cy-12)
# Gray matter ellipse (central)
c.setFillColor(colors.HexColor("#ffccbc"))
c.setStrokeColor(colors.HexColor("#bf360c"))
c.ellipse(cx-22, cy-18, cx+22, cy+18, fill=1, stroke=1)
# Anterior commissure label line
c.setStrokeColor(C_RED)
c.setLineWidth(1)
c.line(cx-10, cy, cx+10, cy)
c.setFillColor(C_RED)
c.setFont("Helvetica", 6.5)
c.drawCentredString(cx, cy - 8, "ant. commissure")
# Dorsal column (blue, top)
c.setFillColor(colors.HexColor("#bbdefb"))
c.setStrokeColor(C_BLUE)
c.setLineWidth(1)
c.ellipse(cx-16, cy+26, cx+16, cy+44, fill=1, stroke=1)
c.setFillColor(C_BLUE)
c.setFont("Helvetica", 6)
c.drawCentredString(cx, cy+37, "Dorsal col.")
# Lat. spinothalamic (red dot, right side = already crossed)
c.setFillColor(C_RED)
c.circle(cx+36, cy+10, 8, fill=1, stroke=0)
c.setFillColor(C_WHITE)
c.setFont("Helvetica-Bold", 6)
c.drawCentredString(cx+36, cy+8, "LST")
# Ant. spinothalamic (orange dot, right)
c.setFillColor(C_ORANGE)
c.circle(cx+36, cy-12, 7, fill=1, stroke=0)
c.setFillColor(C_WHITE)
c.setFont("Helvetica-Bold", 6)
c.drawCentredString(cx+36, cy-14, "AST")
# Labels
c.setFillColor(C_GRAY)
c.setFont("Helvetica", 7)
c.drawString(cx - r - 5, cy - r*0.85 - 12, "Spinal cord cross-section")
# Dorsal horn label
c.setFillColor(C_TEAL)
c.setFont("Helvetica", 7)
c.drawString(cx - r + 2, cy + 40, "Lamina I & V")
c.drawString(cx - r + 2, cy + 30, "(2nd order neuron)")
# ── Middle: crossing arrow ────────────────────────────────────
mid_x = 210
# Arrow showing crossing
c.setStrokeColor(C_RED)
c.setLineWidth(2)
c.line(cx + r + 5, cy + 10, mid_x - 10, cy + 10)
# Arrowhead
c.setFillColor(C_RED)
p = c.beginPath()
p.moveTo(mid_x - 10, cy + 14)
p.lineTo(mid_x, cy + 10)
p.lineTo(mid_x - 10, cy + 6)
p.close()
c.drawPath(p, fill=1, stroke=0)
c.setFillColor(C_RED)
c.setFont("Helvetica-Bold", 7.5)
c.drawString(cx + r + 6, cy + 14, "Crosses in ant. commissure")
c.setFont("Helvetica", 7)
c.drawString(cx + r + 6, cy + 5, "(2-3 segments)")
# ── Right side: brainstem column ──────────────────────────────
bx = 270 # x of brainstem column
levels = [
(h - 55, "Cortex", C_NAVY, "(Postcentral gyrus)"),
(h - 100, "Thalamus", C_BLUE, "VPL + Intralaminar nuclei"),
(h - 148, "Midbrain", C_TEAL, "Lat. to med. lemniscus"),
(h - 196, "Pons", C_GREEN, "Lat. to med. lemniscus"),
(h - 244, "Medulla", C_ORANGE, "Lat. groove (inf. olive)"),
(h - 292, "Spinal cord", C_RED, "Anterolateral white col."),
]
# Vertical tract line
c.setStrokeColor(C_RED)
c.setLineWidth(2.5)
c.line(bx + 6, h - 295, bx + 6, h - 52)
for (ly, lname, lcol, lsub) in levels:
# Node circle
c.setFillColor(lcol)
c.setStrokeColor(C_WHITE)
c.setLineWidth(1)
c.circle(bx + 6, ly, 7, fill=1, stroke=1)
# Label box
c.setFillColor(lcol)
c.setStrokeColor(lcol)
box_x = bx + 18
c.roundRect(box_x, ly - 8, 150, 18, 3, fill=1, stroke=0)
c.setFillColor(C_WHITE)
c.setFont("Helvetica-Bold", 8)
c.drawString(box_x + 4, ly + 1, lname)
c.setFillColor(colors.HexColor("#eeeeee"))
c.roundRect(box_x, ly - 22, 150, 13, 2, fill=1, stroke=0)
c.setFillColor(C_GRAY)
c.setFont("Helvetica", 7)
c.drawString(box_x + 4, ly - 18, lsub)
# Arrow on tract line
c.setFillColor(C_RED)
p2 = c.beginPath()
p2.moveTo(bx + 1, h - 60)
p2.lineTo(bx + 6, h - 50)
p2.lineTo(bx + 11, h - 60)
p2.close()
c.drawPath(p2, fill=1, stroke=0)
# Legend
legend_y = 15
items = [
(C_RED, "Lateral Spinothalamic Tract (pain & temp)"),
(C_ORANGE, "Anterior Spinothalamic Tract (crude touch)"),
]
lx = 10
for col, label in items:
c.setFillColor(col)
c.rect(lx, legend_y - 2, 12, 8, fill=1, stroke=0)
c.setFillColor(C_GRAY)
c.setFont("Helvetica", 7.5)
c.drawString(lx + 16, legend_y, label)
lx += 200
# ── Comparison diagram ─────────────────────────────────────────────────────────
class ComparisonDiagram(Flowable):
W = 480
H = 210
def wrap(self, aw, ah):
return self.W, self.H
def draw(self):
c = self.canv
w, h = self.W, self.H
# Background
c.setFillColor(colors.HexColor("#fafafa"))
c.setStrokeColor(colors.HexColor("#cccccc"))
c.roundRect(0, 0, w, h, 6, fill=1, stroke=1)
# Title
c.setFillColor(C_NAVY)
c.setFont("Helvetica-Bold", 10)
c.drawCentredString(w/2, h - 14, "Comparison: Spinothalamic vs. Dorsal Column Pathways")
# Two columns
col1_x, col2_x = 30, 270
col_w = 220
# Column headers
for cx_, title_, color_ in [(col1_x, "Spinothalamic (Anterolateral)", C_RED),
(col2_x, "Dorsal Column-Med. Lemniscal", C_BLUE)]:
c.setFillColor(color_)
c.roundRect(cx_, h - 42, col_w, 22, 4, fill=1, stroke=0)
c.setFillColor(C_WHITE)
c.setFont("Helvetica-Bold", 8.5)
c.drawCentredString(cx_ + col_w/2, h - 34, title_)
rows = [
("Sensations", "Pain, Temp, Crude touch", "Proprioception, Vibration,\nFine touch, 2-pt discrim."),
("Fiber type", "Aδ, C (small, slow)", "Aβ (large, fast myelinated)"),
("1st synapse", "Dorsal horn (Lamina I, V)", "Nucleus gracilis / cuneatus\n(medulla)"),
("Decussation", "Spinal cord ant. commissure\n(2-3 segs below entry)",
"Medulla (sensory decussation)"),
("2nd neuron", "→ VPL thalamus & intralaminar", "→ VPL thalamus"),
("Speed", "8-40 m/sec (slower)", "30-110 m/sec (faster)"),
("Localization", "Poor (crude)", "Precise (discriminative)"),
]
row_h = 22
y = h - 50
for i, (feat, left, right) in enumerate(rows):
bg = colors.HexColor("#fff3e0") if i % 2 == 0 else C_WHITE
c.setFillColor(bg)
c.rect(col1_x - 5, y - row_h + 4, col_w * 2 + 20, row_h, fill=1, stroke=0)
# Feature label
c.setFillColor(C_NAVY)
c.setFont("Helvetica-Bold", 7.5)
c.drawString(col1_x - 4, y - 4, feat)
# Left cell
c.setFillColor(C_GRAY)
c.setFont("Helvetica", 7.5)
lines_l = left.split("\n")
for li, line in enumerate(lines_l):
c.drawString(col1_x + 70, y - 4 - li * 10, line)
# Right cell
lines_r = right.split("\n")
for li, line in enumerate(lines_r):
c.drawString(col2_x + 70, y - 4 - li * 10, line)
# Divider
c.setStrokeColor(colors.HexColor("#e0e0e0"))
c.setLineWidth(0.4)
c.line(col1_x - 5, y - row_h + 4, col1_x + col_w * 2 + 15, y - row_h + 4)
y -= row_h
# ── Brown-Séquard diagram ──────────────────────────────────────────────────────
class BrownSequardDiagram(Flowable):
W = 480
H = 200
def wrap(self, aw, ah):
return self.W, self.H
def draw(self):
c = self.canv
w, h = self.W, self.H
c.setFillColor(colors.HexColor("#fafafa"))
c.setStrokeColor(colors.HexColor("#cccccc"))
c.roundRect(0, 0, w, h, 6, fill=1, stroke=1)
c.setFillColor(C_NAVY)
c.setFont("Helvetica-Bold", 10)
c.drawCentredString(w/2, h - 15, "Brown-Séquard Syndrome (Right Hemisection)")
# Spinal cord cross-section (right half lesion)
cx, cy = 100, h/2 - 10
r = 50
# Full outline
c.setFillColor(colors.HexColor("#fff9c4"))
c.setStrokeColor(C_GRAY)
c.setLineWidth(1.2)
c.ellipse(cx-r, cy-r*0.85, cx+r, cy+r*0.85, fill=1, stroke=1)
# Right half hatched (lesion)
c.setFillColor(colors.HexColor("#ffcdd2"))
c.setStrokeColor(C_RED)
c.setLineWidth(1)
# Simple right-half rectangle overlay
c.rect(cx, cy - r*0.85, r, r*1.7, fill=1, stroke=0)
c.setStrokeColor(C_RED)
c.setLineWidth(0.5)
for i in range(8):
yy = cy - r*0.85 + i * (r*1.7/8)
c.line(cx, yy, cx + r, yy + 10)
# Midline
c.setStrokeColor(C_RED)
c.setLineWidth(1.5)
c.setDash([4, 2])
c.line(cx, cy - r*0.85, cx, cy + r*0.85)
c.setDash([])
# Label LESION
c.setFillColor(C_RED)
c.setFont("Helvetica-Bold", 8)
c.drawCentredString(cx + r/2, cy + 4, "LESION")
c.drawCentredString(cx + r/2, cy - 8, "(Right)")
# Results table
tx = 185
c.setFillColor(C_NAVY)
c.setFont("Helvetica-Bold", 9)
c.drawString(tx, h - 30, "Clinical Findings:")
items = [
("IPSILATERAL (Right) — below lesion:", C_BLUE, True),
(" ✗ Loss of proprioception & vibration (dorsal column)", C_BLUE, False),
(" ✗ Loss of fine touch & 2-pt discrimination", C_BLUE, False),
(" ✗ UMN weakness / spasticity (corticospinal)", C_BLUE, False),
("CONTRALATERAL (Left) — below lesion:", C_RED, True),
(" ✗ Loss of PAIN & TEMPERATURE (spinothalamic)", C_RED, False),
(" ✓ Crude touch partially preserved", C_GREEN, False),
]
y = h - 48
for text, col, bold in items:
c.setFillColor(col)
c.setFont("Helvetica-Bold" if bold else "Helvetica", 8)
c.drawString(tx, y, text)
y -= 13
# ── Build document ─────────────────────────────────────────────────────────────
def build():
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
leftMargin=2.2*cm, rightMargin=2.2*cm,
topMargin=1.8*cm, bottomMargin=1.5*cm,
title="Spinothalamic Tract",
author="Orris Medical Reference"
)
story = []
pw = W - 4.4*cm # printable width
# ═══════════════════════════════════════════════════════
# COVER BLOCK
# ═══════════════════════════════════════════════════════
class CoverBlock(Flowable):
def wrap(self, aw, ah):
return pw, 140
def draw(self):
c = self.canv
c.setFillColor(C_NAVY)
c.roundRect(0, 0, pw, 140, 8, fill=1, stroke=0)
# accent strip
c.setFillColor(C_TEAL)
c.roundRect(0, 0, pw, 8, 4, fill=1, stroke=0)
c.setFillColor(C_WHITE)
c.setFont("Helvetica-Bold", 24)
c.drawCentredString(pw/2, 100, "SPINOTHALAMIC TRACT")
c.setFillColor(colors.HexColor("#90caf9"))
c.setFont("Helvetica", 11)
c.drawCentredString(pw/2, 78, "Anterolateral Pathway | Pain & Temperature")
c.setFillColor(colors.HexColor("#80cbc4"))
c.setFont("Helvetica", 9)
c.drawCentredString(pw/2, 58, "Reference: Guyton & Hall Textbook of Medical Physiology | Neuroanatomy through Clinical Cases 3e")
c.setFillColor(colors.HexColor("#b0bec5"))
c.setFont("Helvetica", 8)
c.drawCentredString(pw/2, 30, "Physiology | Neuroanatomy | Clinical Correlations")
story.append(CoverBlock())
story.append(Spacer(1, 14))
# ═══════════════════════════════════════════════════════
# SECTION 1 — Overview
# ═══════════════════════════════════════════════════════
story.append(SectionHeader("1. OVERVIEW", C_NAVY, pw))
story.append(Spacer(1, 6))
story.append(Paragraph(
"The <b>spinothalamic tract</b> is the primary ascending sensory pathway for <b>pain</b>, "
"<b>temperature</b>, <b>crude touch</b>, tickle, itch, and sexual sensations. "
"It forms part of the broader <i>anterolateral pathway</i> — so named because its fibers "
"run in the anterolateral white matter of the spinal cord. It is the clinical counterpart "
"to the dorsal column-medial lemniscal pathway, which handles discriminative touch and proprioception.",
S_BODY))
story.append(Spacer(1, 4))
# Quick-reference colored box
qr_data = [
["Modality", "Pain, Temperature, Crude touch, Tickle, Itch"],
["1st order neuron", "Peripheral sensory neuron (DRG) → dorsal horn"],
["2nd order neuron", "Dorsal horn (Lamina I, IV, V, VI) → crosses → VPL thalamus"],
["3rd order neuron", "Thalamus (VPL) → Postcentral gyrus (areas 3, 1, 2)"],
["Decussation", "Anterior commissure of spinal cord (2–3 segments)"],
["Somatotopy", "Sacral lateral → Cervical medial (legs outermost)"],
]
tbl = Table(qr_data, colWidths=[pw*0.32, pw*0.68])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,-1), C_NAVY),
("TEXTCOLOR", (0,0), (0,-1), C_WHITE),
("BACKGROUND", (1,0), (1,-1), C_LBLUE),
("TEXTCOLOR", (1,0), (1,-1), C_GRAY),
("FONTNAME", (0,0), (0,-1), "Helvetica-Bold"),
("FONTNAME", (1,0), (1,-1), "Helvetica"),
("FONTSIZE", (0,0), (-1,-1), 9),
("ROWBACKGROUNDS", (0,0), (-1,-1), [C_LBLUE, C_WHITE]),
("BACKGROUND", (0,0), (0,-1), C_NAVY),
("GRID", (0,0), (-1,-1), 0.5, colors.HexColor("#b0bec5")),
("LEFTPADDING", (0,0), (-1,-1), 8),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0), (-1,-1), 5),
("ROWBACKGROUNDS", (1,0), (1,-1), [C_LBLUE, colors.HexColor("#f0f8ff")]),
]))
story.append(tbl)
story.append(Spacer(1, 10))
# ═══════════════════════════════════════════════════════
# SECTION 2 — Anatomy (3 neurons)
# ═══════════════════════════════════════════════════════
story.append(SectionHeader("2. ANATOMY — THREE-NEURON ARC", C_TEAL, pw))
story.append(Spacer(1, 6))
story.append(Paragraph("<b>First-Order Neuron (Peripheral)</b>", S_H2))
bullets_1 = [
"Cell body in the <b>dorsal root ganglion (DRG)</b>",
"Peripheral process: free nerve endings in skin/viscera → carries pain (Aδ, C fibers) and temperature",
"Central process enters spinal cord via <b>dorsal root entry zone</b>",
"Many collaterals ascend/descend 1–2 segments in <b>Lissauer's tract</b> (dorsolateral fasciculus) before synapsing",
]
for b in bullets_1:
story.append(Paragraph(f"• {b}", S_BULLET))
story.append(Spacer(1, 4))
story.append(Paragraph("<b>Second-Order Neuron (Spinal Cord → Thalamus)</b>", S_H2))
bullets_2 = [
"Cell body in dorsal horn: mainly <b>Lamina I</b> (marginal zone) and <b>Lamina V</b> (neck of dorsal horn); also laminae IV and VI",
"Axon <b>immediately crosses</b> in the <b>anterior (ventral) commissure</b> to the opposite side",
"<i>Note:</i> Crossing takes 2–3 segments → lateral cord lesion = contralateral sensory loss a few levels <b>below</b> the lesion",
"Ascends in the <b>anterolateral white matter</b> as the spinothalamic tract",
"<b>Lateral spinothalamic tract</b> (neospinothalamic) — pain and temperature (discriminative)",
"<b>Anterior spinothalamic tract</b> — crude touch and pressure",
"Terminates in <b>VPL nucleus</b> of thalamus (and intralaminar nuclei for pain)",
]
for b in bullets_2:
story.append(Paragraph(f"• {b}", S_BULLET))
story.append(Spacer(1, 4))
story.append(Paragraph("<b>Third-Order Neuron (Thalamus → Cortex)</b>", S_H2))
bullets_3 = [
"<b>VPL (ventroposterolateral)</b> nucleus of thalamus → somatosensory radiations → <b>postcentral gyrus</b> (areas 3, 1, 2) via internal capsule",
"<b>Intralaminar nuclei</b> (centromedian) → diffuse cortical projections → arousal and affective pain",
"Face is represented by the trigeminothalamic tract (analogous pathway)",
]
for b in bullets_3:
story.append(Paragraph(f"• {b}", S_BULLET))
story.append(Spacer(1, 10))
# ═══════════════════════════════════════════════════════
# PATHWAY DIAGRAM
# ═══════════════════════════════════════════════════════
story.append(SectionHeader("3. PATHWAY DIAGRAM", C_RED, pw))
story.append(Spacer(1, 8))
story.append(SpinalCordDiagram())
story.append(Spacer(1, 4))
story.append(Paragraph(
"<i>Left: Spinal cord cross-section showing dorsal horn laminae (1st synapse) and lateral (LST) & anterior (AST) "
"spinothalamic tracts in anterolateral white column. Right: Ascending pathway from spinal cord through "
"brainstem to thalamus and cortex. Fibers cross in the anterior commissure.</i>",
S_CAPTION))
story.append(Spacer(1, 10))
# ═══════════════════════════════════════════════════════
# Guyton figure
# ═══════════════════════════════════════════════════════
story.append(SectionHeader("4. GUYTON FIGURE — ANTEROLATERAL PATHWAY", C_BLUE, pw))
story.append(Spacer(1, 6))
if os.path.exists(GUYTON_IMG):
img = Image(GUYTON_IMG, width=pw*0.42, height=pw*0.95)
img.hAlign = "CENTER"
story.append(img)
story.append(Paragraph(
"<i>Fig. 48.13 — Guyton & Hall Textbook of Medical Physiology. Anterior and lateral divisions "
"of the anterolateral sensory pathway. Shows the crossing in the anterior commissure, ascent "
"through the brainstem, and termination in the ventrobasal and intralaminar nuclei of the thalamus.</i>",
S_CAPTION))
story.append(Spacer(1, 10))
# ═══════════════════════════════════════════════════════
# SECTION 5 — Three tracts
# ═══════════════════════════════════════════════════════
story.append(SectionHeader("5. THREE TRACTS OF THE ANTEROLATERAL SYSTEM", C_PURPLE, pw))
story.append(Spacer(1, 6))
tract_data = [
["Tract", "Termination", "Function", "Origin (laminae)"],
["Spinothalamic\n(neospinothalamic)", "VPL thalamus\n→ somatosensory cortex",
"Discriminative pain & temp\n(location, intensity)", "I, V"],
["Spinoreticular\n(paleospinothalamic)", "Reticular formation\n→ intralaminar thalamus\n→ whole cortex",
"Emotional / arousal aspects\nof pain ("ouch!")", "VI–VIII (diffuse)"],
["Spinomesencephalic", "Periaqueductal gray\n(PAG), sup. colliculus",
"Central pain modulation\n("aah, relief")", "I, V"],
]
tbl2 = Table(tract_data, colWidths=[pw*0.22, pw*0.28, pw*0.28, pw*0.22])
tbl2.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_PURPLE),
("TEXTCOLOR", (0,0), (-1,0), C_WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTNAME", (0,1), (-1,-1), "Helvetica"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("ROWBACKGROUNDS",(0,1), (-1,-1), [C_LPURPLE, C_WHITE]),
("GRID", (0,0), (-1,-1), 0.5, colors.HexColor("#ce93d8")),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("LEFTPADDING", (0,0), (-1,-1), 6),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
]))
story.append(tbl2)
story.append(Spacer(1, 10))
# ═══════════════════════════════════════════════════════
# SECTION 6 — Somatotopy
# ═══════════════════════════════════════════════════════
story.append(SectionHeader("6. SOMATOTOPIC ORGANIZATION", C_GREEN, pw))
story.append(Spacer(1, 6))
story.append(Paragraph(
"The anterolateral pathway has a <b>somatotopic arrangement</b> within the spinal cord — "
"this is clinically important for interpreting lesion levels.",
S_BODY))
story.append(Spacer(1, 4))
# Somatotopy visual
class SomatotopyDiagram(Flowable):
W = 460
H = 90
def wrap(self, aw, ah): return self.W, self.H
def draw(self):
c = self.canv
c.setFillColor(colors.HexColor("#fafafa"))
c.setStrokeColor(colors.HexColor("#cccccc"))
c.roundRect(0, 0, self.W, self.H, 5, fill=1, stroke=1)
c.setFillColor(C_NAVY)
c.setFont("Helvetica-Bold", 8.5)
c.drawString(10, self.H - 16, "Cross-section (right):")
# Draw concentric half-circles representing layers
cx, cy = 130, 25
segs = [("S", C_RED, 40), ("L", C_ORANGE, 30), ("T", C_TEAL, 20), ("C", C_BLUE, 10)]
for label, col, r in segs:
c.setFillColor(col)
c.setStrokeColor(C_WHITE)
c.setLineWidth(0.5)
c.circle(cx, cy, r, fill=1, stroke=1)
# Labels
c.setFillColor(C_WHITE)
c.setFont("Helvetica-Bold", 7)
c.drawCentredString(cx, 23, "C")
c.setFillColor(C_NAVY)
c.setFont("Helvetica", 7)
offsets = [("S = Sacral (most lateral)", 50, 60), ("L = Lumbar", 50, 48),
("T = Thoracic", 50, 36), ("C = Cervical (most medial)", 50, 24)]
cols2 = [C_RED, C_ORANGE, C_TEAL, C_BLUE]
for i, (lbl, lx, ly) in enumerate(offsets):
c.setFillColor(cols2[i])
c.rect(lx - 3, ly - 2, 10, 8, fill=1, stroke=0)
c.setFillColor(C_GRAY)
c.setFont("Helvetica", 8)
c.drawString(lx + 12, ly, lbl)
c.setFillColor(C_NAVY)
c.setFont("Helvetica-Bold", 8)
c.drawString(270, 65, "Rule to remember:")
c.setFillColor(C_GRAY)
c.setFont("Helvetica", 8)
c.drawString(270, 52, "Fibers from LOWER segments (sacral)")
c.drawString(270, 40, "are displaced LATERALLY as higher-")
c.drawString(270, 28, "segment fibers add on MEDIALLY.")
c.setFillColor(C_RED)
c.setFont("Helvetica-Bold", 8)
c.drawString(270, 14, "⟹ Lateral = sacral/lower limb")
story.append(SomatotopyDiagram())
story.append(Spacer(1, 4))
story.append(Paragraph(
"<i>Somatotopic layering of the spinothalamic tract in cross-section. "
"Sacral (S) fibers are outermost (most lateral); cervical (C) fibers are innermost. "
"This arrangement is preserved throughout the brainstem ascent.</i>",
S_CAPTION))
story.append(Spacer(1, 10))
# PAGE BREAK before comparison
story.append(PageBreak())
# ═══════════════════════════════════════════════════════
# SECTION 7 — Characteristics (Guyton)
# ═══════════════════════════════════════════════════════
story.append(SectionHeader("7. CHARACTERISTICS OF TRANSMISSION (Guyton, Ch. 48)", C_ORANGE, pw))
story.append(Spacer(1, 6))
char_data = [
["Characteristic", "Spinothalamic / Anterolateral", "Dorsal Column-Med. Lemniscal"],
["Conduction velocity", "8–40 m/sec", "30–110 m/sec"],
["Spatial localization", "Poor", "Precise"],
["Intensity gradations", "~10–20 levels", "~100 levels"],
["Rapidly changing signals", "Poor", "Excellent"],
["System type", "Crude", "Discriminative"],
["Unique modalities", "Pain, Temp, Itch, Tickle, Sexual", "2-pt discrimination, Stereognosis"],
]
tbl3 = Table(char_data, colWidths=[pw*0.30, pw*0.35, pw*0.35])
tbl3.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_ORANGE),
("TEXTCOLOR", (0,0), (-1,0), C_WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTNAME", (0,1), (-1,-1), "Helvetica"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("ROWBACKGROUNDS",(0,1), (-1,-1), [C_AMBER, C_WHITE]),
("GRID", (0,0), (-1,-1), 0.5, colors.HexColor("#ffcc80")),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("LEFTPADDING", (0,0), (-1,-1), 7),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
]))
story.append(tbl3)
story.append(Spacer(1, 10))
# ═══════════════════════════════════════════════════════
# SECTION 8 — Comparison diagram
# ═══════════════════════════════════════════════════════
story.append(SectionHeader("8. PATHWAY COMPARISON DIAGRAM", C_TEAL, pw))
story.append(Spacer(1, 6))
story.append(ComparisonDiagram())
story.append(Spacer(1, 10))
# ═══════════════════════════════════════════════════════
# SECTION 9 — Clinical correlations
# ═══════════════════════════════════════════════════════
story.append(SectionHeader("9. CLINICAL CORRELATIONS", C_RED, pw))
story.append(Spacer(1, 6))
# Brown-Séquard
story.append(Paragraph("<b>A. Brown-Séquard Syndrome (Cord Hemisection)</b>", S_H2))
story.append(BrownSequardDiagram())
story.append(Spacer(1, 6))
# Syringomyelia
story.append(Paragraph("<b>B. Syringomyelia</b>", S_H2))
story.append(Paragraph(
"Cavitation of the <b>central canal</b> preferentially damages the <b>anterior commissure</b> "
"where spinothalamic fibers cross. This produces <b>bilateral loss of pain and temperature</b> "
"at the level of the syrinx in a cape-like (shawl) distribution, while <b>dorsal columns "
"are spared</b> → called <b>dissociated sensory loss</b>. As the cavity enlarges, it eventually "
"damages the dorsal columns and anterior horn cells.",
S_BODY))
story.append(Spacer(1, 6))
# Lateral medullary
story.append(Paragraph("<b>C. Lateral Medullary (Wallenberg) Syndrome</b>", S_H2))
story.append(Paragraph(
"Infarction of the posterolateral medulla (PICA territory) damages the <b>spinothalamic tract</b> "
"after it has already crossed. This causes <b>contralateral loss of pain & temperature on the body</b> "
"plus <b>ipsilateral loss of facial sensation</b> (via trigeminal nucleus also in the lateral medulla) "
"— the classic <b>crossed sensory loss</b>.",
S_BODY))
story.append(Spacer(1, 6))
# Anterolateral cordotomy
story.append(Paragraph("<b>D. Anterolateral Cordotomy</b>", S_H2))
story.append(Paragraph(
"Surgical or percutaneous section of the spinothalamic tract is used for intractable pain. "
"Because the tract has already crossed, the procedure relieves pain <b>contralateral</b> to and "
"<b>below</b> the level of the cut. Pain relief may be temporary due to reorganization.",
S_BODY))
story.append(Spacer(1, 10))
# ═══════════════════════════════════════════════════════
# SECTION 10 — Key points box
# ═══════════════════════════════════════════════════════
story.append(SectionHeader("10. KEY POINTS TO REMEMBER", C_NAVY, pw))
story.append(Spacer(1, 6))
key_pts = [
"1. Spinothalamic tract = Pain, Temperature, Crude touch (NOT fine touch or proprioception)",
"2. Fibers cross in the ANTERIOR COMMISSURE of spinal cord — 2-3 segments after entry",
"3. Somatotopy: Sacral (lateral) → Lumbar → Thoracic → Cervical (medial) — 'SALT'",
"4. Three tracts: Spinothalamic (VPL) | Spinoreticular (arousal) | Spinomesencephalic (PAG, modulation)",
"5. Conduction velocity only 8–40 m/sec (slow, crude), poor localization, 10–20 intensity gradations",
"6. Brown-Séquard: Contralateral pain/temp loss BELOW + Ipsilateral dorsal column loss",
"7. Syringomyelia: Bilateral pain/temp loss at level (ant. commissure damage) = dissociated loss",
"8. Wallenberg: Contralateral body pain/temp loss + Ipsilateral face loss (crossed pattern)",
]
for pt in key_pts:
col = C_LBLUE if int(pt[0]) % 2 == 1 else C_LGREEN
kp_tbl = Table([[Paragraph(pt, S_BOX)]], colWidths=[pw])
kp_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), col),
("LEFTPADDING", (0,0), (-1,-1), 8),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LINEBELOW", (0,0), (-1,-1), 0.5, colors.HexColor("#bbdefb")),
]))
story.append(kp_tbl)
story.append(Spacer(1, 2))
story.append(Spacer(1, 14))
# References
story.append(HRFlowable(width=pw, thickness=0.5, color=C_GRAY))
story.append(Spacer(1, 4))
story.append(Paragraph(
"<b>References:</b> Guyton AC, Hall JE. <i>Textbook of Medical Physiology</i>, 14e — Chapters 48 & 49. | "
"Blumenfeld H. <i>Neuroanatomy through Clinical Cases</i>, 3e — Chapter 7.",
S_SMALL))
doc.build(story, onFirstPage=on_page, onLaterPages=on_page)
print(f"PDF saved: {OUTPUT}")
build()
cd /home/daytona/workspace/spinothalamic && python make_pdf.py 2>&1
~/spinothalamic/make_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/spinothalamic/make_pdf.py'
cd /home/daytona/workspace/spinothalamic && python make_pdf.py 2>&1
~/spinothalamic/make_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/spinothalamic/make_pdf.py'
cd /home/daytona/workspace/spinothalamic && python make_pdf.py 2>&1
~/spinothalamic/make_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/spinothalamic/make_pdf.py'
cd /home/daytona/workspace/spinothalamic && python make_pdf.py 2>&1
Where is the pdf
Spinothalamic Tract
PDF Document · PDF