make flow charts in pdf

Reading File
Browsing Directory

~/attachments/61540d64-392d-4807-93f8-09a7e822ebf6

Reading File
Running Command

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]) "

Running Command

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') "

Writing File

~/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}')
Running Command

python3 /home/daytona/workspace/thieme-flowcharts/make_charts.py 2>&1

Running Command

ls -lh /home/daytona/workspace/thieme-flowcharts/THIEME_Muscle_Flowcharts.pdf

Your PDF is ready with 9 pages of flowcharts:

THIEME Muscle Flowcharts

PDF Document · PDF

Here's what's inside each chart:
ChartTopic
Title pageCover with table of contents
Chart 1Muscle Tissue Types — Skeletal vs Cardiac vs Smooth (comparison grid)
Chart 2Fiber Type Classification — Type I, Type IIA, Type IIB (properties, metabolism, examples)
Chart 3Architectural Classification — Non-pennate vs Pennate (Uni/Bi/Multi)
Chart 4Histological Organization — Epimysium → Perimysium → Endomysium → Fiber → Myofibril, L/T systems
Chart 5Motor Units — Large (Type I) vs Small (Type II), Henneman's Size Principle
Chart 6Muscle Function & Biomechanics — Postural/Phasic, Lever types, Agonist/Synergist/Antagonist/Fixator
Chart 7Tendons & Insertions — Traction vs Pressure tendons, Periosteal vs Chondral insertion zones
Chart 8Master Summary — All 9 classification schemes in one reference table
This is a shared conversation. Sign in to Orris to start your own chat.