make flow charts in pdf
~/attachments/61540d64-392d-4807-93f8-09a7e822ebf6
cd /home/daytona/workspace && python3 -c " import pdfplumber path = '/home/daytona/workspace/attachments/61540d64-392d-4807-93f8-09a7e822ebf6/I now have extensive rich content from the THIEME .pdf' with pdfplumber.open(path) as pdf: print(f'Total pages: {len(pdf.pages)}') for i, page in enumerate(pdf.pages[:5]): print(f'\\n=== PAGE {i+1} ===') print(page.extract_text()[:2000]) "
mkdir -p /home/daytona/workspace/thieme-flowcharts && python3 -c " import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt import matplotlib.patches as mpatches from matplotlib.patches import FancyBboxPatch, FancyArrowPatch import matplotlib.patheffects as pe from matplotlib.backends.backend_pdf import PdfPages import numpy as np # ─── Color palette ──────────────────────────────────────────────────────────── ROOT_CLR = '#1B3A6B' LVL1_CLR = '#2E6DA4' LVL2_CLR = '#4A9FC7' LVL3_CLR = '#7FCCDD' LEAF_CLR = '#D6EEF5' CARD_CLR = '#F0F7FB' ARROW_CLR = '#555555' TEXT_DARK = '#FFFFFF' TEXT_LIGHT = '#1A1A1A' ACCENT1 = '#E84545' ACCENT2 = '#F5A623' ACCENT3 = '#27AE60' def draw_box(ax, x, y, w, h, text, color, fontsize=9, text_color=TEXT_DARK, bold=False, radius=0.04, wrap=True): box = FancyBboxPatch((x - w/2, y - h/2), w, h, boxstyle=f'round,pad=0.01,rounding_size={radius}', linewidth=0.8, edgecolor='#CCCCCC', facecolor=color, zorder=3) ax.add_patch(box) weight = 'bold' if bold else 'normal' ax.text(x, y, text, ha='center', va='center', fontsize=fontsize, color=text_color, fontweight=weight, wrap=True, multialignment='center', zorder=4, bbox=dict(boxstyle='round', facecolor='none', edgecolor='none')) def arrow(ax, x1, y1, x2, y2): ax.annotate('', xy=(x2, y2+0.025), xytext=(x1, y1-0.025), arrowprops=dict(arrowstyle='->', color=ARROW_CLR, lw=1.2, connectionstyle='arc3,rad=0')) print('helpers defined') "
~/thieme-flowcharts/make_charts.py
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.patches import FancyBboxPatch
from matplotlib.backends.backend_pdf import PdfPages
import textwrap
# ── Palette ────────────────────────────────────────────────────────────────────
ROOT = '#1B3A6B'
L1 = '#2E6DA4'
L2 = '#3A8FBF'
L3 = '#5BAED4'
LEAF = '#D6EEF5'
LEAF2 = '#FEF3CD'
LEAF3 = '#D4EDDA'
LEAF4 = '#F8D7DA'
HEADER = '#0D2240'
ARROW = '#444444'
W, H = '#FFFFFF', '#1A1A1A'
def box(ax, x, y, w, h, text, fc, tc='white', fs=8.5, bold=False, radius=0.035):
p = FancyBboxPatch((x-w/2, y-h/2), w, h,
boxstyle=f'round,pad=0.008,rounding_size={radius}',
linewidth=0.6, edgecolor='#BBBBBB', facecolor=fc, zorder=3)
ax.add_patch(p)
ax.text(x, y, text, ha='center', va='center', fontsize=fs, color=tc,
fontweight='bold' if bold else 'normal',
multialignment='center', zorder=4, linespacing=1.3)
def arr(ax, x1,y1,x2,y2):
ax.annotate('', xy=(x2, y2+0.02), xytext=(x1, y1-0.02),
arrowprops=dict(arrowstyle='->', color=ARROW, lw=1.1,
connectionstyle='arc3,rad=0'))
def hline(ax, x1, y, x2, color=ARROW):
ax.plot([x1, x2], [y, y], color=color, lw=1.1, zorder=3)
def vline(ax, x, y1, y2, color=ARROW):
ax.plot([x, x], [y1, y2], color=color, lw=1.1, zorder=3)
def title_page(pdf):
fig, ax = plt.subplots(figsize=(11, 8.5))
ax.set_xlim(0,1); ax.set_ylim(0,1); ax.axis('off')
fig.patch.set_facecolor(HEADER)
ax.text(0.5, 0.72, 'MUSCLES', ha='center', va='center',
fontsize=44, color='white', fontweight='bold', fontfamily='DejaVu Sans')
ax.text(0.5, 0.60, 'Types · Classification · Function', ha='center', va='center',
fontsize=20, color='#7EC8E3')
ax.text(0.5, 0.47, 'Flowchart Reference Guide', ha='center', va='center',
fontsize=14, color='#AAAAAA')
ax.text(0.5, 0.35, 'Source: THIEME Atlas of Anatomy\nGeneral Anatomy and Musculoskeletal System',
ha='center', va='center', fontsize=11, color='#CCCCCC', multialignment='center')
ax.plot([0.15, 0.85], [0.28, 0.28], color='#7EC8E3', lw=1.5)
topics = ['1. Muscle Tissue Types','2. Fiber Type Classification',
'3. Architectural Classification','4. Histological Organization',
'5. Motor Units','6. Muscle Function & Biomechanics',
'7. Tendons & Insertions']
for i, t in enumerate(topics):
ax.text(0.22, 0.23 - i*0.025, t, ha='left', va='center',
fontsize=9, color='#E0E0E0')
pdf.savefig(fig, bbox_inches='tight')
plt.close()
# ══════════════════════════════════════════════════════════════════════════════
# CHART 1 — Muscle Tissue Types Overview
# ══════════════════════════════════════════════════════════════════════════════
def chart1(pdf):
fig, ax = plt.subplots(figsize=(11, 8.5))
ax.set_xlim(0,1); ax.set_ylim(0,1); ax.axis('off')
fig.patch.set_facecolor('#F8FAFC')
ax.text(0.5, 0.96, 'Chart 1 — Muscle Tissue Types', ha='center', va='top',
fontsize=14, fontweight='bold', color=HEADER)
ax.text(0.5, 0.925, 'Three fundamental types with distinct structural & functional properties',
ha='center', va='top', fontsize=9, color='#555555')
# Root
box(ax, 0.5, 0.85, 0.32, 0.06, 'MUSCLE TISSUE', ROOT, fs=11, bold=True)
# Level 1 – 3 types
types = [('SKELETAL\nMUSCLE', 0.18, L1),
('CARDIAC\nMUSCLE', 0.50, '#8B3A8B'),
('SMOOTH\nMUSCLE', 0.82, '#2E7D52')]
for name, xp, clr in types:
arr(ax, 0.5, 0.82, xp, 0.76)
box(ax, xp, 0.73, 0.28, 0.06, name, clr, fs=10, bold=True)
# Properties rows
props = [
('Location', 'Attached\nto skeleton', 'Heart wall', 'Viscera /\nblood vessels'),
('Appearance', 'Striated', 'Striated', 'Non-striated'),
('Control', 'Voluntary', 'Involuntary', 'Involuntary'),
('Nuclei', 'Multiple,\nperipheral', 'Single,\ncentral', 'Single,\ncentral'),
('Speed', 'Fast', 'Intermediate', 'Slow'),
('Fatigue', 'Yes (phasic)', 'No', 'No'),
]
row_colors = [LEAF, '#E8D5F0', '#C8E6C9']
label_x = [0.18, 0.50, 0.82]
bw, bh = 0.25, 0.055
for ri, (label, v1, v2, v3) in enumerate(props):
y_row = 0.65 - ri*0.065
# connector from type box to first property box
if ri == 0:
for xi in label_x:
arr(ax, xi, 0.70, xi, y_row+bh/2+0.005)
ax.text(0.01, y_row, label, ha='left', va='center',
fontsize=8.5, fontweight='bold', color='#333333')
for xi, val, clr in zip(label_x, [v1,v2,v3], row_colors):
box(ax, xi, y_row, bw, bh-0.005, val, clr, tc=H, fs=8)
ax.text(0.5, 0.02, 'Source: THIEME Atlas of Anatomy — General Anatomy & Musculoskeletal System, Sections 5.1–5.3',
ha='center', fontsize=7.5, color='#888888')
pdf.savefig(fig, bbox_inches='tight')
plt.close()
# ══════════════════════════════════════════════════════════════════════════════
# CHART 2 — Skeletal Muscle Fiber Type Classification
# ══════════════════════════════════════════════════════════════════════════════
def chart2(pdf):
fig, ax = plt.subplots(figsize=(11, 8.5))
ax.set_xlim(0,1); ax.set_ylim(0,1); ax.axis('off')
fig.patch.set_facecolor('#F8FAFC')
ax.text(0.5, 0.96, 'Chart 2 — Skeletal Muscle Fiber Type Classification', ha='center',
va='top', fontsize=14, fontweight='bold', color=HEADER)
ax.text(0.5, 0.925, 'Based on metabolic, physiological & biochemical characteristics',
ha='center', va='top', fontsize=9, color='#555555')
box(ax, 0.5, 0.865, 0.40, 0.058, 'SKELETAL MUSCLE FIBERS\n(all are twitch fibers – all-or-none response)', ROOT, fs=9.5, bold=True)
# Type I vs Type II
arr(ax, 0.5, 0.836, 0.25, 0.78)
arr(ax, 0.5, 0.836, 0.75, 0.78)
box(ax, 0.25, 0.755, 0.38, 0.055, 'TYPE I — Slow-Twitch (ST) Fibers\n"Red / Postural muscles"', '#A0522D', fs=9, bold=True)
box(ax, 0.75, 0.755, 0.38, 0.055, 'TYPE II — Fast-Twitch (FT) Fibers\n"White / Movement muscles"', L1, fs=9, bold=True)
# Type I properties
t1_props = [
('Twitch duration', '~100 ms (slower)'),
('Fatigue', 'Slow – endurance activity'),
('Motor unit size', 'Large (thousands of fibers)'),
('Myoglobin', 'Rich → red color'),
('Mitochondria', 'Abundant'),
('Metabolism', 'Oxidative (aerobic)'),
('Glycogen (PAS)', 'Little – PAS negative'),
('Vascularity', 'Highly vascularized'),
('Tendency', 'Shortening → needs stretching'),
('Examples', 'Intercostals, Trapezius,\nMasticatory mm.'),
]
t2_props = [
('Twitch duration', '~30 ms (faster)'),
('Fatigue', 'Rapid – intense brief activity'),
('Motor unit size', 'Small (<100 fibers)'),
('Myoglobin', 'Scant → pale color'),
('Mitochondria', 'Few'),
('Metabolism', 'Anaerobic glycolysis'),
('Glycogen (PAS)', 'Abundant – PAS positive'),
('Vascularity', 'Poor capillary supply'),
('Tendency', 'Atrophy → needs strengthening'),
('Examples', 'Gastrocnemius,\nTibialis anterior'),
]
bw, bh, gap = 0.17, 0.05, 0.002
for i, (lbl, val) in enumerate(t1_props):
y = 0.69 - i*(bh+gap)
box(ax, 0.13, y, 0.12, bh, lbl, '#D4856A', tc='white', fs=7.5, bold=True)
box(ax, 0.29, y, 0.22, bh, val, LEAF4, tc=H, fs=7.5)
for i, (lbl, val) in enumerate(t2_props):
y = 0.69 - i*(bh+gap)
box(ax, 0.63, y, 0.12, bh, lbl, L2, tc='white', fs=7.5, bold=True)
box(ax, 0.79, y, 0.22, bh, val, LEAF, tc=H, fs=7.5)
# Type II subtypes
arr(ax, 0.75, 0.728, 0.65, 0.685)
arr(ax, 0.75, 0.728, 0.85, 0.685)
box(ax, 0.63, 0.065, 0.18, 0.045, 'Type IIA\nFast Oxidative-Glycolytic', '#1565C0', fs=7.5, bold=True)
box(ax, 0.85, 0.065, 0.18, 0.045, 'Type IIB\nFast Glycolytic', '#6A1B9A', fs=7.5, bold=True)
ax.text(0.74, 0.040, '(differ by myosin heavy-chain isoforms)', ha='center',
fontsize=7, color='#666666')
# Clinical note
note = ('Clinical Note: Fiber distribution is genetically determined but adaptable.\n'
'Endurance athletes → Type I dominant | Power/sprint athletes → Type II dominant\n'
'(Phenotypic plasticity of muscle — Pette & Saron, 2001)')
ax.text(0.5, 0.115, note, ha='center', fontsize=7.8, color='#333333',
multialignment='center',
bbox=dict(boxstyle='round,pad=0.4', facecolor='#FFFDE7', edgecolor='#F5A623', lw=1.2))
ax.text(0.5, 0.015, 'Source: THIEME Atlas of Anatomy — Sections 5.1–5.3',
ha='center', fontsize=7.5, color='#888888')
pdf.savefig(fig, bbox_inches='tight')
plt.close()
# ══════════════════════════════════════════════════════════════════════════════
# CHART 3 — Architectural Classification (Pennate vs Non-Pennate)
# ══════════════════════════════════════════════════════════════════════════════
def chart3(pdf):
fig, ax = plt.subplots(figsize=(11, 8.5))
ax.set_xlim(0,1); ax.set_ylim(0,1); ax.axis('off')
fig.patch.set_facecolor('#F8FAFC')
ax.text(0.5, 0.96, 'Chart 3 — Muscle Architectural Classification', ha='center',
va='top', fontsize=14, fontweight='bold', color=HEADER)
ax.text(0.5, 0.925, 'Classification by fiber arrangement relative to the tendon',
ha='center', va='top', fontsize=9, color='#555555')
box(ax, 0.5, 0.865, 0.36, 0.055, 'SKELETAL MUSCLE ARCHITECTURE', ROOT, fs=10, bold=True)
arr(ax, 0.5, 0.838, 0.22, 0.78)
arr(ax, 0.5, 0.838, 0.78, 0.78)
box(ax, 0.22, 0.755, 0.36, 0.055, 'NON-PENNATE\n(Parallel-Fibered)', '#2E7D52', fs=10, bold=True)
box(ax, 0.78, 0.755, 0.36, 0.055, 'PENNATE\n(Oblique-Fibered, penna=feather)', '#8B3A3A', fs=10, bold=True)
# Non-pennate properties
np_props = [
'Fibers parallel to long axis of muscle/tendon',
'Greater force production\n(direct force transmission)',
'Physiological CSA = Anatomic CSA',
'Larger range of shortening (excursion)',
]
for i, p in enumerate(np_props):
y = 0.685 - i*0.075
arr(ax, 0.22, 0.728, 0.22, y+0.03) if i==0 else None
box(ax, 0.22, y, 0.36, 0.06, p, LEAF3, tc=H, fs=8.5)
if i > 0:
vline(ax, 0.22, y+0.03, 0.685-( i-1)*0.075-0.03)
# Pennate subtypes
subtypes = [
('Unipennate', 0.58, '#C0392B',
'Fibers angle from\none side of tendon'),
('Bipennate', 0.78, '#E67E22',
'Fibers angle from\nboth sides'),
('Multipennate', 0.97, '#8E44AD',
'Multiple angles\nof insertion'),
]
arr(ax, 0.78, 0.728, 0.58, 0.66)
arr(ax, 0.78, 0.728, 0.78, 0.66)
arr(ax, 0.78, 0.728, 0.97, 0.66)
for name, xp, clr, desc in subtypes:
box(ax, xp, 0.635, 0.17, 0.055, name, clr, fs=9, bold=True)
arr(ax, xp, 0.608, xp, 0.555)
box(ax, xp, 0.535, 0.17, 0.055, desc, LEAF4, tc=H, fs=8)
# Pennate key properties
pens = [
('Pennation angle', 'Force vector per fiber reduced\nbut more fibers packed per CSA'),
('Force development', 'Greater force despite less raw force/fiber'),
('Size efficiency', 'Smaller size for similar power output'),
('Trade-off', 'Reduced excursion / range of shortening'),
]
for i, (lbl, val) in enumerate(pens):
y = 0.44 - i*0.07
box(ax, 0.66, y, 0.16, 0.055, lbl, '#8B3A3A', tc='white', fs=7.5, bold=True)
box(ax, 0.84, y, 0.26, 0.055, val, LEAF4, tc=H, fs=7.5)
ax.text(0.5, 0.09,
'"If there were only non-pennate muscles, the body in many places\n'
'would not have space for a sufficient number of strong muscles."\n'
'— THIEME Atlas of Anatomy',
ha='center', fontsize=8.5, style='italic', color='#444444',
multialignment='center',
bbox=dict(boxstyle='round,pad=0.4', facecolor='#F0F7FB', edgecolor=L1, lw=1))
ax.text(0.5, 0.02, 'Source: THIEME Atlas of Anatomy — Section 5.2',
ha='center', fontsize=7.5, color='#888888')
pdf.savefig(fig, bbox_inches='tight')
plt.close()
# ══════════════════════════════════════════════════════════════════════════════
# CHART 4 — Histological Organization of Skeletal Muscle
# ══════════════════════════════════════════════════════════════════════════════
def chart4(pdf):
fig, ax = plt.subplots(figsize=(11, 8.5))
ax.set_xlim(0,1); ax.set_ylim(0,1); ax.axis('off')
fig.patch.set_facecolor('#F8FAFC')
ax.text(0.5, 0.96, 'Chart 4 — Histological Organization of Skeletal Muscle',
ha='center', va='top', fontsize=14, fontweight='bold', color=HEADER)
ax.text(0.5, 0.925, 'Hierarchical connective tissue sheath system',
ha='center', va='top', fontsize=9, color='#555555')
# Hierarchy chain (top-down, left column)
levels = [
('ENTIRE MUSCLE', ROOT, 0.86),
('Muscle Fascicles\n(secondary bundles)', L1, 0.755),
('Primary Bundles\n(primary fascicles)', L2, 0.65),
('Individual Muscle\nFibers (cells)', L3, 0.545),
('Myofibrils\n(within each fiber)', '#5BAD8E', 0.44),
]
for label, clr, y in levels:
box(ax, 0.22, y, 0.35, 0.06, label, clr, fs=9.5, bold=True)
if y < 0.86:
arr(ax, 0.22, y+0.06/2+0.005, 0.22, y+0.03+0.005)
# Connective tissue labels (right side)
sheaths = [
(0.82, 'EPIMYSIUM\n(loose CT, beneath fascia)', '#1B3A6B',
'Surrounds entire muscle;\nconnects to muscle fascia'),
(0.72, 'PERIMYSIUM\n(secondary → primary bundles)', '#C0392B',
'Transmits tensile force\nto tendons'),
(0.615, 'ENDOMYSIUM\n(individual fibers)', '#27AE60',
'200-250 μm thick;\n300-400 capillaries/mm²;\nholds motor end plates'),
]
for y, name, clr, desc in sheaths:
box(ax, 0.63, y, 0.26, 0.07, name, clr, fs=8.5, bold=True)
box(ax, 0.89, y, 0.20, 0.07, desc, LEAF, tc=H, fs=7.8)
# connecting bracket line
ax.annotate('', xy=(0.50, y), xytext=(0.60, y),
arrowprops=dict(arrowstyle='->', color='#888888', lw=0.9))
# Muscle fiber details
fiber_facts = [
'Avg diameter: ~60 μm (range 10–100 μm)',
'Length: up to 20 cm',
'Multinucleated (peripheral nuclei)',
'Contains myofibrils, mitochondria,\nL-system & T-system',
]
box(ax, 0.5, 0.36, 0.60, 0.055, 'THE MUSCLE FIBER (Cell) — Key Facts', L1, fs=9, bold=True)
for i, f in enumerate(fiber_facts):
y = 0.295 - i*0.06
ax.plot([0.22], [y], 's', color=L1, markersize=7, zorder=5)
ax.text(0.255, y, f, va='center', fontsize=8.5, color=H)
# T & L system
systems = [
('L-SYSTEM\n(Sarcoplasmic Reticulum)',
'Runs longitudinally alongside myofibrils;\nstores Ca²⁺ ions;\nreleases Ca²⁺ on excitation → contraction',
'#8B3A8B', LEAF),
('T-SYSTEM\n(Transverse Tubules)',
'Runs perpendicular to myofibrils;\nconducts action potentials from\ncell surface deep into fiber',
'#C0392B', LEAF4),
]
for i, (name, desc, hclr, bclr) in enumerate(systems):
xc = 0.28 + i*0.44
box(ax, xc, 0.10, 0.38, 0.055, name, hclr, fs=8.5, bold=True)
box(ax, xc, 0.04, 0.38, 0.055, desc, bclr, tc=H, fs=7.5)
ax.text(0.5, 0.005, 'Source: THIEME Atlas of Anatomy — Section 5.3',
ha='center', fontsize=7.5, color='#888888')
pdf.savefig(fig, bbox_inches='tight')
plt.close()
# ══════════════════════════════════════════════════════════════════════════════
# CHART 5 — Motor Units
# ══════════════════════════════════════════════════════════════════════════════
def chart5(pdf):
fig, ax = plt.subplots(figsize=(11, 8.5))
ax.set_xlim(0,1); ax.set_ylim(0,1); ax.axis('off')
fig.patch.set_facecolor('#F8FAFC')
ax.text(0.5, 0.96, 'Chart 5 — Motor Units', ha='center',
va='top', fontsize=14, fontweight='bold', color=HEADER)
ax.text(0.5, 0.925, '1 Motor Neuron + All Muscle Fibers It Innervates = 1 Motor Unit',
ha='center', va='top', fontsize=10, color='#555555')
box(ax, 0.5, 0.855, 0.60, 0.058,
'MOTOR UNIT = 1 Motor Neuron + All innervated muscle fibers', ROOT, fs=10, bold=True)
arr(ax, 0.5, 0.826, 0.22, 0.77)
arr(ax, 0.5, 0.826, 0.78, 0.77)
box(ax, 0.22, 0.745, 0.38, 0.055,
'LARGE Motor Units\n(Type I — Slow fibers)', '#A0522D', fs=9.5, bold=True)
box(ax, 0.78, 0.745, 0.38, 0.055,
'SMALL Motor Units\n(Type II — Fast fibers)', L1, fs=9.5, bold=True)
large_props = [
('Fibers per unit', 'Thousands of fibers'),
('Function', 'Postural maintenance\n(sustained, low-force)'),
('Fatigue resistance', 'High (slow twitch)'),
('Example muscles', 'Postural muscles\n(back extensors, intercostals)'),
]
small_props = [
('Fibers per unit', '<100 fibers'),
('Function', 'Fine/rapid movements\n(precise, high-force bursts)'),
('Fatigue resistance', 'Low (fast twitch)'),
('Example muscles', 'Hand intrinsics\n(precise control)'),
]
bw1, bw2, bh = 0.14, 0.22, 0.055
for i, (lbl, val) in enumerate(large_props):
y = 0.67 - i*(bh+0.005)
box(ax, 0.12, y, bw1, bh, lbl, '#A0522D', tc='white', fs=7.5, bold=True)
box(ax, 0.27, y, bw2, bh, val, LEAF2, tc=H, fs=7.5)
for i, (lbl, val) in enumerate(small_props):
y = 0.67 - i*(bh+0.005)
box(ax, 0.68, y, bw1, bh, lbl, L2, tc='white', fs=7.5, bold=True)
box(ax, 0.83, y, bw2, bh, val, LEAF, tc=H, fs=7.5)
key_points = [
'• All fibers within one motor unit are the SAME fiber type (I or II)',
'• Fiber type is determined by its innervating motor neuron',
'• Henneman\'s Size Principle: smaller motor units recruited first',
'• Gradation of force: achieved by recruiting additional motor units (summation)',
]
box(ax, 0.5, 0.37, 0.85, 0.055, 'KEY PRINCIPLES', '#27AE60', fs=9.5, bold=True)
for i, kp in enumerate(key_points):
y = 0.315 - i*0.055
box(ax, 0.5, y, 0.85, 0.048, kp, LEAF3, tc=H, fs=8.5)
ax.text(0.5, 0.02, 'Source: THIEME Atlas of Anatomy — Section 5.1–5.3',
ha='center', fontsize=7.5, color='#888888')
pdf.savefig(fig, bbox_inches='tight')
plt.close()
# ══════════════════════════════════════════════════════════════════════════════
# CHART 6 — Muscle Function & Biomechanics
# ══════════════════════════════════════════════════════════════════════════════
def chart6(pdf):
fig, ax = plt.subplots(figsize=(11, 8.5))
ax.set_xlim(0,1); ax.set_ylim(0,1); ax.axis('off')
fig.patch.set_facecolor('#F8FAFC')
ax.text(0.5, 0.96, 'Chart 6 — Muscle Function & Biomechanics',
ha='center', va='top', fontsize=14, fontweight='bold', color=HEADER)
ax.text(0.5, 0.925, 'Postural/Phasic roles, Lever mechanics, and Synergist-Antagonist relationships',
ha='center', va='top', fontsize=9, color='#555555')
# ── Postural vs Phasic ──
box(ax, 0.5, 0.865, 0.55, 0.055, 'FUNCTIONAL CLASSIFICATION BY ROLE', ROOT, fs=10, bold=True)
arr(ax, 0.5, 0.838, 0.22, 0.78)
arr(ax, 0.5, 0.838, 0.78, 0.78)
box(ax, 0.22, 0.755, 0.38, 0.055, 'POSTURAL Muscles\n(Type I dominant)', '#2E7D52', fs=9.5, bold=True)
box(ax, 0.78, 0.755, 0.38, 0.055, 'PHASIC/MOVEMENT Muscles\n(Type II dominant)', '#C0392B', fs=9.5, bold=True)
post = ['Maintain body position vs gravity', 'Active continuously', 'Resist fatigue', 'Prone to shortening → stretch regularly']
phas = ['Produce rapid, powerful movements', 'Activate in bursts', 'Fatigue quickly', 'Prone to atrophy → strengthen regularly']
for i, (p, ph) in enumerate(zip(post, phas)):
y = 0.685 - i*0.058
box(ax, 0.22, y, 0.38, 0.05, p, LEAF3, tc=H, fs=8)
box(ax, 0.78, y, 0.38, 0.05, ph, LEAF4, tc=H, fs=8)
# ── Lever Mechanics ──
box(ax, 0.5, 0.415, 0.55, 0.055, 'LEVER MECHANICS (Torque = F × d)', L1, fs=10, bold=True)
arr(ax, 0.5, 0.388, 0.25, 0.33)
arr(ax, 0.5, 0.388, 0.75, 0.33)
box(ax, 0.25, 0.305, 0.40, 0.055, 'One-Arm Lever', '#8B4513', fs=9.5, bold=True)
box(ax, 0.75, 0.305, 0.40, 0.055, 'Two-Arm Lever', '#6A1B9A', fs=9.5, bold=True)
box(ax, 0.25, 0.235, 0.40, 0.055,
'Muscle force & load on SAME side\nof joint rotation center\nEx: Elbow — biceps brachii', LEAF2, tc=H, fs=8)
box(ax, 0.75, 0.235, 0.40, 0.055,
'Muscle force on ONE side,\nbody weight on OTHER side\nEx: Hip joint', LEAF, tc=H, fs=8)
# ── Agonist / Synergist / Antagonist ──
box(ax, 0.5, 0.14, 0.90, 0.055, 'MUSCLE ACTION ROLES', '#1B3A6B', fs=10, bold=True)
roles = [
('Agonist\n(Prime Mover)', 'Primary muscle producing movement', '#1B6B3A', LEAF3),
('Synergist', 'Assists agonist; stabilizes joints during movement', '#1B3A6B', LEAF),
('Antagonist', 'Opposes agonist; provides smooth eccentric control', '#8B3A3A', LEAF4),
('Fixator/Stabilizer', 'Isometric contraction; stabilizes proximal segments', '#5B4A8B', '#EAE4F0'),
]
for i, (name, desc, hclr, bclr) in enumerate(roles):
x = 0.13 + i*0.245
arr(ax, 0.5, 0.113, x, 0.085)
box(ax, x, 0.062, 0.22, 0.05, name, hclr, fs=8, bold=True)
box(ax, x, 0.012, 0.22, 0.045, desc, bclr, tc=H, fs=7)
ax.text(0.5, -0.01, 'Source: THIEME Atlas of Anatomy — Sections 5.1–5.3',
ha='center', fontsize=7.5, color='#888888')
pdf.savefig(fig, bbox_inches='tight')
plt.close()
# ══════════════════════════════════════════════════════════════════════════════
# CHART 7 — Tendons & Insertions
# ══════════════════════════════════════════════════════════════════════════════
def chart7(pdf):
fig, ax = plt.subplots(figsize=(11, 8.5))
ax.set_xlim(0,1); ax.set_ylim(0,1); ax.axis('off')
fig.patch.set_facecolor('#F8FAFC')
ax.text(0.5, 0.96, 'Chart 7 — Tendons & Insertions',
ha='center', va='top', fontsize=14, fontweight='bold', color=HEADER)
ax.text(0.5, 0.925, 'Tendon types classified by stress and insertion characteristics',
ha='center', va='top', fontsize=9, color='#555555')
box(ax, 0.5, 0.865, 0.35, 0.055, 'TENDONS', ROOT, fs=11, bold=True)
arr(ax, 0.5, 0.838, 0.25, 0.78)
arr(ax, 0.5, 0.838, 0.75, 0.78)
box(ax, 0.25, 0.755, 0.38, 0.055, 'TRACTION Tendons\n(Tensile stress)', '#2E7D52', fs=9.5, bold=True)
box(ax, 0.75, 0.755, 0.38, 0.055, 'PRESSURE Tendons\n(Compressive stress)', '#C0392B', fs=9.5, bold=True)
traction = [
('Stress type', 'Tensile (pulling)'),
('Structure', 'Strong parallel collagen fibers'),
('Vascularity', 'Well vascularized'),
('Function', 'Direct force transmission'),
]
pressure = [
('Stress type', 'Compressive'),
('Structure', 'Fibrocartilage on compressed side'),
('Vascularity', 'Avascular in compressed area'),
('Function', 'Change direction around bone;\nbone acts as fulcrum'),
]
bh = 0.058
for i, (lbl, val) in enumerate(traction):
y = 0.69 - i*(bh+0.004)
box(ax, 0.13, y, 0.12, bh, lbl, '#2E7D52', tc='white', fs=7.5, bold=True)
box(ax, 0.29, y, 0.24, bh, val, LEAF3, tc=H, fs=8)
for i, (lbl, val) in enumerate(pressure):
y = 0.69 - i*(bh+0.004)
box(ax, 0.63, y, 0.12, bh, lbl, '#C0392B', tc='white', fs=7.5, bold=True)
box(ax, 0.79, y, 0.24, bh, val, LEAF4, tc=H, fs=8)
# Insertions
box(ax, 0.5, 0.41, 0.60, 0.055, 'TENDON INSERTION TYPES', L1, fs=10, bold=True)
arr(ax, 0.5, 0.383, 0.28, 0.32)
arr(ax, 0.5, 0.383, 0.72, 0.32)
box(ax, 0.28, 0.295, 0.45, 0.055,
'Periosteal Diaphyseal Insertion', '#1B5E20', fs=9.5, bold=True)
box(ax, 0.72, 0.295, 0.45, 0.055,
'Chondral Apophyseal Insertion', '#4A148C', fs=9.5, bold=True)
peri_zones = [
'Zone 1: Dense collagen fibers (tendon)',
'Zone 2: Fibrocartilage (uncalcified)',
'Zone 3: Mineralized fibrocartilage',
'Zone 4: Lamellar bone\n(Sharpey\'s fibers anchor here)',
]
for i, z in enumerate(peri_zones):
y = 0.23 - i*0.058
box(ax, 0.28, y, 0.45, 0.052, z, LEAF3 if i%2==0 else '#D0F0D8', tc=H, fs=8)
box(ax, 0.72, 0.23, 0.45, 0.052,
'Cartilage cells in non-mineralized\nfibrocartilage zone act as springs', LEAF, tc=H, fs=8)
box(ax, 0.72, 0.17, 0.45, 0.052,
'"Stretch protection" principle:\nresists transverse shortening on contraction', '#EAD0F0', tc=H, fs=8)
box(ax, 0.72, 0.11, 0.45, 0.052,
'Taut spring mechanism absorbs\nhigh tensile/compressive loads', LEAF4, tc=H, fs=8)
ax.text(0.5, 0.025, 'Muscle Fasciae: Collagenous weblike lattice — bears loads in any direction,\n'
'maintains shape, allows muscles to glide past each other with minimal friction',
ha='center', fontsize=8, color='#333333', multialignment='center',
bbox=dict(boxstyle='round,pad=0.3', facecolor='#F0F7FB', edgecolor=L1, lw=1))
ax.text(0.5, 0.005, 'Source: THIEME Atlas of Anatomy — Sections 5.3–5.4',
ha='center', fontsize=7.5, color='#888888')
pdf.savefig(fig, bbox_inches='tight')
plt.close()
# ══════════════════════════════════════════════════════════════════════════════
# CHART 8 — Summary Master Classification
# ══════════════════════════════════════════════════════════════════════════════
def chart8(pdf):
fig, ax = plt.subplots(figsize=(11, 8.5))
ax.set_xlim(0,1); ax.set_ylim(0,1); ax.axis('off')
fig.patch.set_facecolor('#F8FAFC')
ax.text(0.5, 0.965, 'Chart 8 — Master Classification Summary',
ha='center', va='top', fontsize=14, fontweight='bold', color=HEADER)
ax.text(0.5, 0.933, 'All classification schemes from the THIEME Atlas muscle chapter',
ha='center', va='top', fontsize=9, color='#555555')
rows = [
('Control', 'Voluntary (skeletal)', 'Involuntary (cardiac, smooth)', L1, '#8B3A8B'),
('Histology', 'Striated', 'Non-striated', '#27AE60','#C0392B'),
('Fiber Type', 'Type I (slow, oxidative)','Type II (fast, glycolytic/mixed)',LEAF2, LEAF),
('Function', 'Postural (red)', 'Phasic/movement (white)', LEAF3, LEAF4),
('Architecture', 'Non-pennate (parallel)', 'Pennate (uni/bi/multi)', '#5BAED4','#F5A623'),
('Action Role', 'Agonist / Synergist', 'Antagonist / Fixator', '#9C27B0','#795548'),
('Lever Type', 'One-arm lever', 'Two-arm lever', '#1565C0','#37474F'),
('Tendon Type', 'Traction (tensile)', 'Pressure (compressive)', '#2E7D52','#8B3A3A'),
('Insertion', 'Periosteal diaphyseal', 'Chondral apophyseal', '#1B3A6B','#4A148C'),
]
header_y = 0.875
box(ax, 0.12, header_y, 0.20, 0.048, 'CLASSIFICATION\nBASIS', HEADER, fs=8.5, bold=True)
box(ax, 0.45, header_y, 0.38, 0.048, 'TYPE / CATEGORY A', L1, fs=8.5, bold=True)
box(ax, 0.82, header_y, 0.34, 0.048, 'TYPE / CATEGORY B', '#8B3A8B', fs=8.5, bold=True)
bh = 0.065
for i, (basis, catA, catB, cA, cB) in enumerate(rows):
y = 0.815 - i * (bh + 0.004)
bg = '#F9F9F9' if i%2==0 else '#FFFFFF'
# row background
rect = plt.Rectangle((0.01, y-bh/2), 0.98, bh,
facecolor=bg, edgecolor='#DDDDDD', lw=0.5)
ax.add_patch(rect)
box(ax, 0.12, y, 0.20, bh-0.006, basis, '#34495E', tc='white', fs=8.5, bold=True)
box(ax, 0.45, y, 0.38, bh-0.006, catA, cA, tc=H if cA in [LEAF2,LEAF,LEAF3,LEAF4,'#F5A623'] else 'white', fs=8)
box(ax, 0.82, y, 0.34, bh-0.006, catB, cB, tc=H if cB in [LEAF2,LEAF,LEAF3,LEAF4,'#F5A623'] else 'white', fs=8)
ax.text(0.5, 0.025,
'THIEME Atlas of Anatomy — General Anatomy and Musculoskeletal System (ISBN 9781626237186)',
ha='center', fontsize=8, color='#555555',
bbox=dict(boxstyle='round,pad=0.3', facecolor='#EBF5FB', edgecolor=L1, lw=1))
pdf.savefig(fig, bbox_inches='tight')
plt.close()
# ══════════════════════════════════════════════════════════════════════════════
# MAIN — assemble PDF
# ══════════════════════════════════════════════════════════════════════════════
out_path = '/home/daytona/workspace/thieme-flowcharts/THIEME_Muscle_Flowcharts.pdf'
with PdfPages(out_path) as pdf:
title_page(pdf)
chart1(pdf)
chart2(pdf)
chart3(pdf)
chart4(pdf)
chart5(pdf)
chart6(pdf)
chart7(pdf)
chart8(pdf)
print(f'Done! Saved to {out_path}')
python3 /home/daytona/workspace/thieme-flowcharts/make_charts.py 2>&1
ls -lh /home/daytona/workspace/thieme-flowcharts/THIEME_Muscle_Flowcharts.pdf
THIEME Muscle Flowcharts
PDF Document · PDF
| Chart | Topic |
|---|---|
| Title page | Cover with table of contents |
| Chart 1 | Muscle Tissue Types — Skeletal vs Cardiac vs Smooth (comparison grid) |
| Chart 2 | Fiber Type Classification — Type I, Type IIA, Type IIB (properties, metabolism, examples) |
| Chart 3 | Architectural Classification — Non-pennate vs Pennate (Uni/Bi/Multi) |
| Chart 4 | Histological Organization — Epimysium → Perimysium → Endomysium → Fiber → Myofibril, L/T systems |
| Chart 5 | Motor Units — Large (Type I) vs Small (Type II), Henneman's Size Principle |
| Chart 6 | Muscle Function & Biomechanics — Postural/Phasic, Lever types, Agonist/Synergist/Antagonist/Fixator |
| Chart 7 | Tendons & Insertions — Traction vs Pressure tendons, Periosteal vs Chondral insertion zones |
| Chart 8 | Master Summary — All 9 classification schemes in one reference table |