Systemic circulation, pulmonary circulation, coronary circulation, portal circulation, cardiac cycle pdf on these topics with diagrams

Reading File
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Loading Image
Loading Image
Loading Image
Reading File
Finding Sources
Loading Image
Loading Image
Loading Image
Reading File
Loading Image
Loading Image
Reading File
Running Command

mkdir -p /home/daytona/workspace/circulation-pdf && ls /home/daytona/workspace/

Writing File

~/circulation-pdf/build_pdf.py

#!/usr/bin/env python3
"""
Build a comprehensive PDF on the five circulatory topics with diagrams.
Uses reportlab for layout.
"""

import requests
from io import BytesIO
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, Image, Table, TableStyle,
    PageBreak, HRFlowable, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import BaseDocTemplate, Frame, PageTemplate

OUTPUT = "/home/daytona/workspace/circulation-pdf/Circulatory_System_Notes.pdf"

# ── Image helper ─────────────────────────────────────────────────────────────
def fetch_img(url, width_cm=14, max_height_cm=10):
    try:
        r = requests.get(url, timeout=15)
        r.raise_for_status()
        bio = BytesIO(r.content)
        img = Image(bio)
        # preserve aspect ratio
        iw, ih = img.imageWidth, img.imageHeight
        target_w = width_cm * cm
        scale = target_w / iw
        target_h = ih * scale
        max_h = max_height_cm * cm
        if target_h > max_h:
            scale = max_h / ih
            target_w = iw * scale
            target_h = max_h
        img.drawWidth = target_w
        img.drawHeight = target_h
        return img
    except Exception as e:
        print(f"  [WARN] Could not load image {url}: {e}")
        return None

# ── Styles ────────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()

cover_title = ParagraphStyle(
    'CoverTitle', parent=styles['Title'],
    fontSize=28, leading=36, textColor=colors.HexColor('#1a3a6b'),
    spaceAfter=10, alignment=TA_CENTER
)
cover_sub = ParagraphStyle(
    'CoverSub', parent=styles['Normal'],
    fontSize=14, leading=20, textColor=colors.HexColor('#3a6bbf'),
    alignment=TA_CENTER, spaceAfter=6
)
chapter_h = ParagraphStyle(
    'ChapterH', parent=styles['Heading1'],
    fontSize=20, leading=26, textColor=colors.white,
    backColor=colors.HexColor('#1a3a6b'),
    spaceAfter=12, spaceBefore=6,
    leftIndent=-10, rightIndent=-10,
    borderPad=8
)
section_h = ParagraphStyle(
    'SectionH', parent=styles['Heading2'],
    fontSize=14, leading=18, textColor=colors.HexColor('#1a3a6b'),
    spaceBefore=12, spaceAfter=6,
    borderPad=4
)
subsec_h = ParagraphStyle(
    'SubSecH', parent=styles['Heading3'],
    fontSize=12, leading=16, textColor=colors.HexColor('#2c5f8a'),
    spaceBefore=8, spaceAfter=4
)
body = ParagraphStyle(
    'Body', parent=styles['Normal'],
    fontSize=10.5, leading=16, alignment=TA_JUSTIFY,
    spaceAfter=6
)
caption_style = ParagraphStyle(
    'Caption', parent=styles['Italic'],
    fontSize=9, leading=12, alignment=TA_CENTER,
    textColor=colors.HexColor('#555555'), spaceAfter=10, spaceBefore=4
)
bullet_style = ParagraphStyle(
    'Bullet', parent=styles['Normal'],
    fontSize=10.5, leading=16, leftIndent=18, bulletIndent=6,
    spaceAfter=4
)
key_box = ParagraphStyle(
    'KeyBox', parent=styles['Normal'],
    fontSize=10, leading=15,
    backColor=colors.HexColor('#eef4fb'),
    borderColor=colors.HexColor('#1a3a6b'),
    borderWidth=1, borderPad=8,
    leftIndent=8, rightIndent=8,
    spaceAfter=10
)

def bullet(txt): return Paragraph(f"<bullet>&bull;</bullet> {txt}", bullet_style)
def sp(n=1): return Spacer(1, n * 5 * mm)
def hr(): return HRFlowable(width="100%", thickness=1, color=colors.HexColor('#b0c4de'), spaceAfter=6)

# ── Image URLs ────────────────────────────────────────────────────────────────
IMGS = {
    "coronary_arteries":   "https://cdn.orris.care/cdss_images/ac6830385a91a83dabcbfa8d3ec65be871229ce66ddfc1a0ca8e48681cb8318e.png",
    "coronary_flow":       "https://cdn.orris.care/cdss_images/a0dba02f0054fbc99b67f215cad609188f2363b985d52e4204b00f427ac01a5b.png",
    "portal_hypertension": "https://cdn.orris.care/cdss_images/5709fed9166602432d944297dd6053972286b2132aa67c300f4c8b14ea030632.png",
    "cardiac_cycle":       "https://cdn.orris.care/cdss_images/5379713ae38b7760f16c6d3143e59fb2744f746ac41304bb94abcda6a828d458.png",
    "cardiac_cycle2":      "https://cdn.orris.care/cdss_images/ba750661390817b04e5354394b2ca1a49e6b35a9231a934377c61cc7e2cc992e.png",
    "systemic_pressure":   "https://cdn.orris.care/cdss_images/d07a2494731097461a2e719ad465bfeed46ae500d343f0fd627ec4f5c22c931c.png",
    "pulmonary_anatomy":   "https://cdn.orris.care/cdss_images/b8b834803b017326b8292c3ec3d70d74fcd87ea119f633f262ca44f6a1e36b2c.png",
    "epicardial_vessels":  "https://cdn.orris.care/cdss_images/1410e335ab78a1d0439069cd0531a1323dcdd17d4f06b5dffb1b843173fd6bef.png",
}

print("Downloading images...")
downloaded = {}
for k, url in IMGS.items():
    img = fetch_img(url)
    if img:
        downloaded[k] = img
        print(f"  OK: {k}")
    else:
        print(f"  FAIL: {k}")

# ── Pressure table ────────────────────────────────────────────────────────────
pressure_data = [
    ["Location", "Mean Pressure (mm Hg)"],
    ["SYSTEMIC", ""],
    ["Aorta", "100"],
    ["Large arteries", "100 (systolic 120 / diastolic 80)"],
    ["Arterioles", "50"],
    ["Capillaries", "20"],
    ["Vena cava", "4"],
    ["Right atrium", "0-2"],
    ["PULMONARY", ""],
    ["Pulmonary artery", "15 (systolic 25 / diastolic 8)"],
    ["Capillaries", "10"],
    ["Pulmonary vein", "8"],
    ["Left atrium", "2-5"],
]
pressure_table = Table(pressure_data, colWidths=[8*cm, 8*cm])
pressure_table.setStyle(TableStyle([
    ('BACKGROUND', (0,0), (-1,0), colors.HexColor('#1a3a6b')),
    ('TEXTCOLOR',  (0,0), (-1,0), colors.white),
    ('BACKGROUND', (0,1), (-1,1), colors.HexColor('#2c5f8a')),
    ('TEXTCOLOR',  (0,1), (-1,1), colors.white),
    ('BACKGROUND', (0,8), (-1,8), colors.HexColor('#2c5f8a')),
    ('TEXTCOLOR',  (0,8), (-1,8), colors.white),
    ('FONTNAME',   (0,0), (-1,0), 'Helvetica-Bold'),
    ('FONTNAME',   (0,1), (-1,1), 'Helvetica-Bold'),
    ('FONTNAME',   (0,8), (-1,8), 'Helvetica-Bold'),
    ('FONTSIZE',   (0,0), (-1,-1), 9),
    ('ROWBACKGROUNDS', (0,2), (-1,7), [colors.HexColor('#f5f8fd'), colors.white]),
    ('ROWBACKGROUNDS', (0,9), (-1,-1), [colors.HexColor('#f5f8fd'), colors.white]),
    ('ALIGN',      (1,0), (1,-1), 'CENTER'),
    ('GRID',       (0,0), (-1,-1), 0.5, colors.HexColor('#b0c4de')),
    ('VALIGN',     (0,0), (-1,-1), 'MIDDLE'),
    ('TOPPADDING', (0,0), (-1,-1), 5),
    ('BOTTOMPADDING', (0,0), (-1,-1), 5),
]))

# Cardiac cycle events table
cc_data = [
    ["Phase", "Major Events", "ECG", "Valves", "Heart Sounds"],
    ["A - Atrial Systole", "Atria contract; final ventricular filling", "P wave / PR interval", "-", "S4 (if present)"],
    ["B - Isovolumetric\nVentricular Contraction", "Ventricles contract; pressure rises; all valves closed", "QRS complex", "Mitral closes", "S1"],
    ["C - Rapid Ventricular\nEjection", "Max pressure; blood ejected; LV volume falls", "ST segment", "Aortic opens", "-"],
    ["D - Reduced Ventricular\nEjection", "Slower ejection; LV volume at minimum", "T wave", "-", "-"],
    ["E - Isovolumetric\nVentricular Relaxation", "Ventricles relax; all valves closed", "-", "Aortic closes", "S2"],
    ["F - Rapid Ventricular\nFilling", "Passive filling from atria", "-", "Mitral opens", "S3 (if present)"],
    ["G - Reduced Filling\n(Diastasis)", "Final slow filling phase", "-", "-", "-"],
]
cc_table = Table(cc_data, colWidths=[3.2*cm, 4.5*cm, 2.5*cm, 2.8*cm, 3*cm])
cc_table.setStyle(TableStyle([
    ('BACKGROUND', (0,0), (-1,0), colors.HexColor('#1a3a6b')),
    ('TEXTCOLOR',  (0,0), (-1,0), colors.white),
    ('FONTNAME',   (0,0), (-1,0), 'Helvetica-Bold'),
    ('FONTSIZE',   (0,0), (-1,-1), 8),
    ('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.HexColor('#f5f8fd'), colors.white]),
    ('GRID',       (0,0), (-1,-1), 0.5, colors.HexColor('#b0c4de')),
    ('VALIGN',     (0,0), (-1,-1), 'MIDDLE'),
    ('TOPPADDING', (0,0), (-1,-1), 4),
    ('BOTTOMPADDING', (0,0), (-1,-1), 4),
    ('WORDWRAP',   (0,0), (-1,-1), True),
]))

# ── Build story ───────────────────────────────────────────────────────────────
story = []

# === COVER PAGE ===
story.append(sp(8))
story.append(Paragraph("Circulatory System", cover_title))
story.append(Paragraph("A Comprehensive Study Guide", cover_sub))
story.append(sp(2))
story.append(hr())
story.append(sp(1))
topics = [
    "1. Systemic Circulation",
    "2. Pulmonary Circulation",
    "3. Coronary Circulation",
    "4. Portal Circulation",
    "5. Cardiac Cycle",
]
for t in topics:
    story.append(Paragraph(t, ParagraphStyle('toc', parent=styles['Normal'],
        fontSize=14, leading=22, alignment=TA_CENTER,
        textColor=colors.HexColor('#1a3a6b'), spaceAfter=4)))
story.append(sp(2))
story.append(hr())
story.append(sp(1))
story.append(Paragraph("Sources: Costanzo Physiology 7e | Guyton & Hall Medical Physiology | Murray & Nadel's Respiratory Medicine | Sleisenger & Fordtran's GI & Liver Disease | Ganong's Review of Medical Physiology", 
    ParagraphStyle('src', parent=styles['Normal'], fontSize=8, alignment=TA_CENTER, textColor=colors.grey)))
story.append(PageBreak())

# ═══════════════════════════════════════════════════════════
# 1. SYSTEMIC CIRCULATION
# ═══════════════════════════════════════════════════════════
story.append(Paragraph("1. Systemic Circulation", chapter_h))
story.append(sp())

story.append(Paragraph("Overview", section_h))
story.append(Paragraph(
    "The systemic circulation carries oxygenated blood from the left ventricle to all body tissues and returns deoxygenated blood to the right atrium. It is a high-pressure, high-resistance circuit compared to the pulmonary circulation. The driving force is the pressure difference created by left ventricular contraction.",
    body))

story.append(Paragraph("Blood Flow Pathway", section_h))
items = [
    "Left ventricle contracts → blood enters the <b>aorta</b> at ~100 mm Hg mean pressure",
    "Aorta branches into large arteries → arterioles (major resistance vessels)",
    "Arterioles → capillaries (site of gas/nutrient/waste exchange), pressure ~20 mm Hg",
    "Capillaries → venules → veins → vena cava, pressure falls to ~4 mm Hg",
    "Inferior and superior vena cava return blood to the <b>right atrium</b> (0-2 mm Hg)",
]
for it in items: story.append(bullet(it))
story.append(sp())

story.append(Paragraph("Pressure Gradient Across the Systemic Circuit", section_h))
story.append(Paragraph(
    "Blood flow requires a pressure gradient. The largest pressure drop occurs across the arterioles (from ~100 mm Hg to ~20 mm Hg), making arterioles the primary site of vascular resistance and the main regulators of blood flow distribution.",
    body))
story.append(sp())
story.append(pressure_table)
story.append(Paragraph("Table 1. Normal pressures in the systemic and pulmonary circulations. (Costanzo Physiology 7e)", caption_style))

story.append(Paragraph("Arterial Pressure", section_h))
story.append(Paragraph(
    "Arterial pressure oscillates with each cardiac cycle, reflecting the pulsatile activity of the heart (ejection during systole, rest during diastole). Key pressure values in the systemic arteries:", body))
items2 = [
    "<b>Systolic pressure:</b> highest arterial pressure during ventricular ejection (~120 mm Hg)",
    "<b>Diastolic pressure:</b> lowest arterial pressure during ventricular relaxation (~80 mm Hg)",
    "<b>Pulse pressure:</b> systolic minus diastolic (~40 mm Hg); reflects stroke volume",
    "<b>Mean arterial pressure (MAP):</b> diastolic + 1/3 pulse pressure ≈ 93 mm Hg; the effective driving pressure",
    "<b>Dicrotic notch (incisura):</b> brief pressure dip in the aortic pressure trace caused by aortic valve closure",
]
for it in items2: story.append(bullet(it))
story.append(sp())

if 'systemic_pressure' in downloaded:
    story.append(downloaded['systemic_pressure'])
    story.append(Paragraph("Fig. 1. Systemic arterial pressure during the cardiac cycle showing systolic, diastolic, and mean pressures. (Costanzo Physiology 7e)", caption_style))

story.append(Paragraph("Veins and Venous Return", section_h))
story.append(Paragraph(
    "Veins are highly compliant and act as blood reservoirs (unstressed volume). At low pressure they contain ~60-70% of total blood volume. The heart's venous return determines end-diastolic volume and, via the Frank-Starling mechanism, cardiac output. Venous compliance decreases during venoconstriction, shifting blood to the arterial side and raising arterial pressure.",
    body))

story.append(Paragraph("Regulation", section_h))
items3 = [
    "<b>Local autoregulation:</b> metabolic vasodilators (CO2, H+, adenosine, hypoxia) match blood flow to tissue demand",
    "<b>Sympathetic nervous system:</b> alpha-1 receptors cause vasoconstriction; beta-2 receptors cause vasodilation (mainly in skeletal muscle via epinephrine)",
    "<b>Hormonal:</b> angiotensin II (vasoconstriction), ANP (vasodilation), vasopressin (vasoconstriction)",
    "<b>Endothelial factors:</b> nitric oxide (NO) - vasodilation; endothelin-1 - vasoconstriction",
]
for it in items3: story.append(bullet(it))

story.append(PageBreak())

# ═══════════════════════════════════════════════════════════
# 2. PULMONARY CIRCULATION
# ═══════════════════════════════════════════════════════════
story.append(Paragraph("2. Pulmonary Circulation", chapter_h))
story.append(sp())

story.append(Paragraph("Overview", section_h))
story.append(Paragraph(
    "The pulmonary circulation is a low-pressure, low-resistance circuit that carries deoxygenated blood from the right ventricle to the lungs for gas exchange and returns oxygenated blood to the left atrium. Total pulmonary vascular resistance is approximately one-sixth that of the systemic circulation.",
    body))

story.append(Paragraph("Anatomical Course", section_h))
items_p = [
    "Right ventricle → <b>pulmonary trunk</b> → right and left pulmonary arteries",
    "Pulmonary arteries enter each lung at the <b>hilum</b> in a connective tissue sheath adjacent to the main bronchus",
    "Pulmonary arteries branch alongside each airway generation down to the <b>respiratory bronchiole</b>",
    "At the terminal respiratory unit, arteries branch into <b>capillaries</b> surrounding alveoli (surface area 50-70 m²)",
    "Pulmonary veins are peripherally located - they follow Miller's dictum of being as far from airways as possible",
    "Pulmonary veins → left atrium → left ventricle (completes the circuit)",
]
for it in items_p: story.append(bullet(it))
story.append(sp())

if 'pulmonary_anatomy' in downloaded:
    story.append(downloaded['pulmonary_anatomy'])
    story.append(Paragraph("Fig. 2. Anatomy of terminal respiratory units. PA = pulmonary artery; PV = pulmonary vein; TB = terminal bronchiole; RB = respiratory bronchiole; AD = alveolar duct; A = alveoli. (Murray & Nadel's Textbook of Respiratory Medicine)", caption_style))

story.append(Paragraph("Pressures", section_h))
items_pp = [
    "<b>Pulmonary artery:</b> systolic 25 / diastolic 8 / mean 15 mm Hg (much lower than systemic)",
    "<b>Pulmonary capillaries:</b> ~10 mm Hg",
    "<b>Left atrium (wedge pressure):</b> 2-5 mm Hg",
    "Driving pressure for pulmonary blood flow: ~10 mm Hg (vs ~98 mm Hg in the systemic circuit)",
]
for it in items_pp: story.append(bullet(it))
story.append(sp())

story.append(Paragraph("Unique Features of the Pulmonary Circulation", section_h))
story.append(Paragraph(
    "<b>Hypoxic vasoconstriction:</b> Unlike all other vascular beds, hypoxia causes <i>vasoconstriction</i> in the pulmonary circulation (opposite to systemic). This is a critical homeostatic mechanism: poorly ventilated alveolar units (low PO2) cause local arteriolar constriction, diverting blood flow away from non-ventilated areas toward well-ventilated areas, optimising ventilation-perfusion (V/Q) matching.",
    body))
story.append(sp())

quant_data = [
    ["Vessel Class", "Volume (mL)", "Surface Area (m²)"],
    ["Arteries (>500 μm)", "68", "0.4"],
    ["Arterioles (13-500 μm)", "18", "1.0"],
    ["Capillaries (~10 μm)", "60-200", "50-70"],
    ["Venules (13-500 μm)", "13", "1.2"],
]
qt = Table(quant_data, colWidths=[7*cm, 4*cm, 4*cm])
qt.setStyle(TableStyle([
    ('BACKGROUND', (0,0), (-1,0), colors.HexColor('#1a3a6b')),
    ('TEXTCOLOR',  (0,0), (-1,0), colors.white),
    ('FONTNAME',   (0,0), (-1,0), 'Helvetica-Bold'),
    ('FONTSIZE',   (0,0), (-1,-1), 9),
    ('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.HexColor('#f5f8fd'), colors.white]),
    ('GRID',       (0,0), (-1,-1), 0.5, colors.HexColor('#b0c4de')),
    ('ALIGN',      (1,0), (-1,-1), 'CENTER'),
    ('TOPPADDING', (0,0), (-1,-1), 5),
    ('BOTTOMPADDING', (0,0), (-1,-1), 5),
]))
story.append(qt)
story.append(Paragraph("Table 2. Quantitative data on intrapulmonary blood vessels in humans. (Murray & Nadel's Respiratory Medicine)", caption_style))

story.append(Paragraph("Clinical Relevance", section_h))
items_pc = [
    "<b>Pulmonary hypertension:</b> mean PAP > 20 mm Hg at rest; leads to right ventricular hypertrophy and failure",
    "<b>Pulmonary oedema:</b> elevated pulmonary capillary pressure (>~18 mm Hg) forces fluid into interstitium",
    "<b>Pulmonary embolism:</b> obstruction of pulmonary vessels elevates pulmonary resistance acutely",
    "<b>V/Q mismatch:</b> regional differences in ventilation and perfusion are the most common cause of hypoxaemia",
]
for it in items_pc: story.append(bullet(it))

story.append(PageBreak())

# ═══════════════════════════════════════════════════════════
# 3. CORONARY CIRCULATION
# ═══════════════════════════════════════════════════════════
story.append(Paragraph("3. Coronary Circulation", chapter_h))
story.append(sp())

story.append(Paragraph("Clinical Significance", section_h))
story.append(Paragraph(
    "Approximately one-third of all deaths in industrialized countries result from coronary artery disease, making coronary physiology one of the most important topics in medicine. The heart extracts ~70-75% of delivered oxygen at rest (compared to ~25% in most tissues), leaving almost no oxygen reserve - any increase in demand must be met by increased blood flow.",
    body))

story.append(Paragraph("Anatomical Supply", section_h))
if 'coronary_arteries' in downloaded:
    story.append(downloaded['coronary_arteries'])
    story.append(Paragraph("Fig. 3. Coronary arteries of the heart showing the left coronary artery (with left anterior descending and circumflex branches) and the right coronary artery. (Guyton & Hall Medical Physiology)", caption_style))

items_ca = [
    "<b>Left coronary artery (LCA):</b> supplies the anterior and left lateral portions of the left ventricle",
    "<b>Left anterior descending (LAD):</b> supplies the anterior LV wall and interventricular septum",
    "<b>Left circumflex:</b> supplies the lateral and posterior LV wall",
    "<b>Right coronary artery (RCA):</b> supplies the right ventricle and the posterior LV (in ~80-90% of people - right dominant)",
    "<b>Venous drainage:</b> ~75% drains through the <i>coronary sinus</i> into the right atrium; remainder through anterior cardiac veins and thebesian veins",
]
for it in items_ca: story.append(bullet(it))
story.append(sp())

story.append(Paragraph("Normal Coronary Blood Flow", section_h))
story.append(Paragraph(
    "Resting coronary blood flow averages ~70 mL/min/100 g of heart weight, or approximately 225 mL/min total, representing 4-5% of cardiac output. During strenuous exercise, coronary flow increases 3-4 fold to meet the 6-9 fold increase in cardiac work.",
    body))

story.append(Paragraph("Phasic Changes During the Cardiac Cycle", section_h))
story.append(Paragraph(
    "The coronary circulation has a unique and paradoxical relationship with the cardiac cycle: left ventricular coronary capillary blood flow is <i>reduced during systole</i> because intramyocardial compression obstructs intramuscular vessels. Most coronary flow occurs during <b>diastole</b>. This is why tachycardia (which shortens diastole) can be dangerous in the context of coronary artery disease.",
    body))

if 'coronary_flow' in downloaded:
    story.append(downloaded['coronary_flow'])
    story.append(Paragraph("Fig. 4. Phasic coronary blood flow during the cardiac cycle. Flow in the left ventricle falls during systole due to myocardial compression and peaks during diastole. (Guyton & Hall Medical Physiology)", caption_style))

story.append(Paragraph("Control of Coronary Blood Flow", section_h))
items_cc = [
    "<b>Local metabolism (primary controller):</b> increased myocardial work → increased O2 consumption → hypoxia + adenosine release → coronary arteriolar vasodilation (active hyperemia)",
    "<b>Adenosine:</b> most important local metabolite; released when ATP is degraded; powerful vasodilator",
    "<b>Hypoxia:</b> direct vasodilatory effect on coronary smooth muscle",
    "<b>Mechanical compression:</b> systolic compression reduces flow; reactive hyperemia occurs in diastole",
    "<b>Sympathetic innervation:</b> plays only a minor role; alpha-1 vasoconstriction is overridden by metabolic vasodilation during exercise",
    "<b>Autoregulation:</b> coronary flow remains constant over a wide range of perfusion pressures (60-140 mm Hg)",
]
for it in items_cc: story.append(bullet(it))
story.append(sp())

story.append(Paragraph("Epicardial vs. Subendocardial Flow", section_h))
story.append(Paragraph(
    "The subendocardium is most susceptible to ischemia because: (1) it is exposed to the highest intramyocardial wall tension during systole, (2) the subendocardial vessels cannot dilate as much as epicardial vessels, and (3) perfusion pressure driving subendocardial flow is lower due to ventricular wall tension during diastole. This explains why ST-segment depression (subendocardial ischemia) is more common than ST elevation in demand ischemia.",
    body))

if 'epicardial_vessels' in downloaded:
    story.append(downloaded['epicardial_vessels'])
    story.append(Paragraph("Fig. 5. Diagram of epicardial, intramuscular, and subendocardial coronary vasculature. (Guyton & Hall Medical Physiology)", caption_style))

story.append(PageBreak())

# ═══════════════════════════════════════════════════════════
# 4. PORTAL CIRCULATION
# ═══════════════════════════════════════════════════════════
story.append(Paragraph("4. Portal Circulation", chapter_h))
story.append(sp())

story.append(Paragraph("Overview", section_h))
story.append(Paragraph(
    "The portal circulation (portal venous system) is a specialized circuit that carries nutrient-rich capillary blood from the gastrointestinal tract, spleen, pancreas, and gallbladder to the liver before returning to the systemic venous circulation. It is the only portal system in the body where blood passes through two capillary beds in series.",
    body))

story.append(Paragraph("Anatomical Course", section_h))
items_portal = [
    "Capillaries of GI tract, spleen, pancreas, gallbladder drain into the <b>portal vein</b>",
    "Portal vein formed by confluence of the <b>splenic vein + superior mesenteric vein</b> (behind the neck of the pancreas)",
    "<b>Inferior mesenteric vein</b> usually drains into the splenic vein",
    "<b>Left gastric vein (coronary vein)</b> drains at the confluence of splenic and superior mesenteric veins",
    "Portal vein is ~7.5 cm long; the uppermost 5 cm receives no tributaries",
    "Portal vein divides at the liver hilum into <b>left and right portal vein branches</b>",
    "Portal venules → <b>hepatic sinusoids</b> → hepatic veins → inferior vena cava",
    "<b>Umbilical vein</b> drains into the left portal vein; <b>cystic vein</b> drains into the right portal vein",
]
for it in items_portal: story.append(bullet(it))
story.append(sp())

story.append(Paragraph("Dual Blood Supply of the Liver", section_h))
story.append(Paragraph(
    "The liver receives a dual blood supply - unique in the body:",
    body))
dual_data = [
    ["Source", "Proportion", "Oxygen Content", "Pressure"],
    ["Portal vein", "~75% of total flow", "Partially deoxygenated\n(nutrient-rich)", "Low (~10-12 mm Hg)"],
    ["Hepatic artery\n(from celiac trunk)", "~25% of total flow", "Fully oxygenated", "High (arterial)"],
]
dt = Table(dual_data, colWidths=[4.5*cm, 4*cm, 5*cm, 3.5*cm])
dt.setStyle(TableStyle([
    ('BACKGROUND', (0,0), (-1,0), colors.HexColor('#1a3a6b')),
    ('TEXTCOLOR',  (0,0), (-1,0), colors.white),
    ('FONTNAME',   (0,0), (-1,0), 'Helvetica-Bold'),
    ('FONTSIZE',   (0,0), (-1,-1), 9),
    ('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.HexColor('#f5f8fd'), colors.white]),
    ('GRID',       (0,0), (-1,-1), 0.5, colors.HexColor('#b0c4de')),
    ('ALIGN',      (0,0), (-1,-1), 'CENTER'),
    ('VALIGN',     (0,0), (-1,-1), 'MIDDLE'),
    ('TOPPADDING', (0,0), (-1,-1), 5),
    ('BOTTOMPADDING', (0,0), (-1,-1), 5),
]))
story.append(dt)
story.append(Paragraph("Table 3. Dual hepatic blood supply.", caption_style))
story.append(sp())

story.append(Paragraph("Hepatic Sinusoids", section_h))
items_sin = [
    "Highly permeable vascular channels where portal and arterial blood converge",
    "Lack a basement membrane; endothelial cells contain <b>fenestrae</b> (pores)",
    "Facilitates transport of macromolecules to hepatocytes",
    "<b>Space of Disse:</b> perisinusoidal space between endothelium and hepatocytes",
    "<b>Hepatic stellate cells (HSCs):</b> in space of Disse; quiescent = vitamin A storage; activated = contractile (sinusoidal pericytes in cirrhosis)",
    "<b>Kupffer cells:</b> sinusoidal macrophages; regulate vascular homeostasis via cytokines",
]
for it in items_sin: story.append(bullet(it))
story.append(sp())

story.append(Paragraph("Hepatic Arterial Buffer Response", section_h))
story.append(Paragraph(
    "An autoregulatory mechanism maintains total hepatic blood flow at a constant level. When portal venous flow decreases (e.g., portal vein thrombosis), hepatic arterial inflow increases compensatorily. Similarly, after hepatic artery occlusion, portal venous inflow increases. The liver can accommodate large post-prandial increases in portal flow without substantially increasing portal pressure.",
    body))

story.append(Paragraph("Portal Hypertension", section_h))
story.append(Paragraph(
    "Portal hypertension (portal pressure > 10-12 mm Hg) arises from: ΔP = Flow × Resistance. In clinical practice, both increased resistance (usually from cirrhosis) AND increased portal flow (hyperdynamic state) contribute. Key consequences:",
    body))
items_ph = [
    "<b>Oesophageal varices:</b> portosystemic collateral vessels form at the gastroesophageal junction; risk of life-threatening haemorrhage",
    "<b>Splenomegaly:</b> from splenic venous congestion",
    "<b>Ascites:</b> portal hypertension + hypoalbuminaemia + sodium retention",
    "<b>Caput medusae:</b> dilated periumbilical veins (recanalized umbilical vein)",
    "<b>Hyperdynamic circulation:</b> splanchnic vasodilation mediated by excess NO production",
]
for it in items_ph: story.append(bullet(it))
story.append(sp())

if 'portal_hypertension' in downloaded:
    story.append(downloaded['portal_hypertension'])
    story.append(Paragraph("Fig. 6. Vascular disturbances in portal hypertension and therapeutic interventions. Shows hepatic circulation (constriction via decreased NO / increased ET-1), splanchnic circulation (dilatation via increased NO), and collateral circulation with varices. (Sleisenger & Fordtran's GI & Liver Disease)", caption_style))

story.append(PageBreak())

# ═══════════════════════════════════════════════════════════
# 5. CARDIAC CYCLE
# ═══════════════════════════════════════════════════════════
story.append(Paragraph("5. Cardiac Cycle", chapter_h))
story.append(sp())

story.append(Paragraph("Overview", section_h))
story.append(Paragraph(
    "The cardiac cycle encompasses all mechanical and electrical events that occur during one complete heartbeat. At a normal resting heart rate of ~75 bpm, each cycle lasts approximately 0.8 seconds (0.3 s systole + 0.5 s diastole). The cycle is divided into seven distinct phases (A through G).",
    body))

story.append(Paragraph("The Seven Phases of the Cardiac Cycle", section_h))
story.append(cc_table)
story.append(Paragraph("Table 4. Events of the cardiac cycle. (Costanzo Physiology 7e)", caption_style))
story.append(sp())

story.append(Paragraph("Detailed Phase Descriptions", section_h))

phases = [
    ("A - Atrial Systole", 
     "Triggered by the P wave (atrial depolarisation). The atria contract, increasing atrial pressure and completing ventricular filling. The mitral valve is open; blood flows from the left atrium into the left ventricle. This 'atrial kick' contributes ~15-20% of final ventricular filling. S4 may be heard if the ventricle is stiff."),
    ("B - Isovolumetric Ventricular Contraction (IVC)",
     "Begins with the QRS complex. Ventricular pressure rises rapidly as the ventricle contracts. When ventricular pressure exceeds atrial pressure, the mitral valve closes (S1 - first heart sound). All valves are closed. Volume remains constant (isovolumetric) while pressure rises steeply."),
    ("C - Rapid Ventricular Ejection",
     "When ventricular pressure exceeds aortic pressure (~80 mm Hg), the aortic valve opens. Blood is rapidly ejected; ~70% of stroke volume is ejected in this phase. Ventricular volume falls sharply. Aortic pressure rises to its maximum (~120 mm Hg systolic)."),
    ("D - Reduced Ventricular Ejection",
     "Ventricular muscle begins to repolarise (T wave). Ejection continues at a slower rate. Ventricular pressure starts to fall even as blood is still flowing into the aorta (aorta still above ventricular pressure). Ventricular volume reaches its minimum (end-systolic volume, ESV ~65-70 mL)."),
    ("E - Isovolumetric Ventricular Relaxation (IVR)",
     "Ventricular pressure falls below aortic pressure; the aortic valve closes (S2 - second heart sound; dicrotic notch on aortic pressure curve). Both valves are again closed; volume remains constant while pressure falls to very low levels."),
    ("F - Rapid Ventricular Filling",
     "When ventricular pressure falls below atrial pressure, the mitral valve opens. Blood that has been pooling in the atria rapidly fills the relaxed ventricle (passive filling). Ventricular volume increases rapidly. A third heart sound (S3) may occur due to sudden deceleration of blood against the ventricular wall."),
    ("G - Reduced Ventricular Filling (Diastasis)",
     "The final slow-filling phase as atrial and ventricular pressures equilibrate. This is the longest phase and is most affected by increases in heart rate (tachycardia shortens or eliminates diastasis, reducing end-diastolic volume and stroke volume via the Frank-Starling mechanism)."),
]
for title, desc in phases:
    story.append(Paragraph(f"<b>{title}</b>", subsec_h))
    story.append(Paragraph(desc, body))

story.append(sp())
story.append(Paragraph("Cardiac Cycle Diagram (Costanzo Physiology 7e)", section_h))
if 'cardiac_cycle' in downloaded:
    img = downloaded['cardiac_cycle']
    img.drawWidth = 10 * cm
    img.drawHeight = 18 * cm
    story.append(img)
    story.append(Paragraph("Fig. 7. The complete cardiac cycle. Phases A-G are shown with simultaneous tracings of left ventricular pressure, aortic pressure, left atrial pressure, ventricular volume, venous pulse, and ECG. (Costanzo Physiology 7e)", caption_style))
story.append(sp())

story.append(Paragraph("Cardiac Cycle Diagram (Ganong's Review of Medical Physiology)", section_h))
if 'cardiac_cycle2' in downloaded:
    img2 = downloaded['cardiac_cycle2']
    img2.drawWidth = 14 * cm
    img2.drawHeight = 18 * cm
    story.append(img2)
    story.append(Paragraph("Fig. 8. Events of the cardiac cycle showing ECG, heart sounds, aortic pressure, left ventricular pressure, left atrial pressure, ventricular volume, jugular venous pressure, and pulmonary arterial pressure. (Ganong's Review of Medical Physiology 26e)", caption_style))

story.append(Paragraph("Heart Sounds", section_h))
hs_data = [
    ["Sound", "Timing", "Cause", "Associations"],
    ["S1 (lub)", "Start of systole (isovolumetric contraction)", "Closure of mitral + tricuspid valves", "Normal; louder in mitral stenosis, tachycardia"],
    ["S2 (dub)", "End of systole (start of diastole)", "Closure of aortic + pulmonary valves", "Normal; splitting widens on inspiration"],
    ["S3 (Ken-)", "Early diastole (rapid filling)", "Rapid deceleration of blood into ventricle", "Normal in young; pathological in HF (gallop rhythm)"],
    ["S4 (-tucky)", "Late diastole (atrial systole)", "Atrial contraction against stiff ventricle", "Pathological; hypertension, LVH, diastolic dysfunction"],
]
hst = Table(hs_data, colWidths=[2.5*cm, 4*cm, 5*cm, 5.5*cm])
hst.setStyle(TableStyle([
    ('BACKGROUND', (0,0), (-1,0), colors.HexColor('#1a3a6b')),
    ('TEXTCOLOR',  (0,0), (-1,0), colors.white),
    ('FONTNAME',   (0,0), (-1,0), 'Helvetica-Bold'),
    ('FONTSIZE',   (0,0), (-1,-1), 8),
    ('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.HexColor('#f5f8fd'), colors.white]),
    ('GRID',       (0,0), (-1,-1), 0.5, colors.HexColor('#b0c4de')),
    ('VALIGN',     (0,0), (-1,-1), 'MIDDLE'),
    ('TOPPADDING', (0,0), (-1,-1), 5),
    ('BOTTOMPADDING', (0,0), (-1,-1), 5),
    ('WORDWRAP',   (0,0), (-1,-1), True),
]))
story.append(hst)
story.append(Paragraph("Table 5. Heart sounds in relation to the cardiac cycle.", caption_style))
story.append(sp())

story.append(Paragraph("Key Relationships", section_h))
items_key = [
    "<b>End-diastolic volume (EDV):</b> ~130-135 mL; the preload; determined by venous return",
    "<b>End-systolic volume (ESV):</b> ~65-70 mL; the afterload-dependent residual volume",
    "<b>Stroke volume (SV):</b> EDV - ESV = ~65-70 mL per beat",
    "<b>Ejection fraction (EF):</b> SV/EDV × 100 = ~55-65%; a key measure of LV systolic function",
    "<b>Cardiac output (CO):</b> SV × heart rate = ~5 L/min at rest",
    "<b>Frank-Starling law:</b> increased EDV → increased stretch → increased force of contraction → increased SV",
    "<b>Effect of tachycardia:</b> diastole (especially diastasis phase G) is shortened; EDV decreases → SV may fall",
]
for it in items_key: story.append(bullet(it))

# Final page - Summary comparison
story.append(PageBreak())
story.append(Paragraph("Summary: Comparison of Circulations", chapter_h))
story.append(sp())

comp_data = [
    ["Parameter", "Systemic", "Pulmonary", "Coronary", "Portal"],
    ["Driving chamber", "Left ventricle", "Right ventricle", "Aortic root", "Mesenteric capillaries"],
    ["Receiving structure", "Right atrium", "Left atrium", "Coronary sinus / RA", "Hepatic sinusoids → IVC"],
    ["Mean driving pressure", "~100 mm Hg", "~15 mm Hg", "~100 mm Hg (aortic)", "~10-12 mm Hg"],
    ["Resistance", "High", "Low (1/6 of systemic)", "Moderate; varies with\ncardiac cycle phase", "Low-moderate"],
    ["O2 content", "Oxygenated (leaving heart)", "Deoxygenated (leaving heart)", "Oxygenated from aorta", "Partially deoxygenated;\nnutrient-rich"],
    ["Key regulation", "Sympathetic + local metabolites", "Hypoxic vasoconstriction", "Local metabolism;\nautoregulation; adenosine", "Hepatic arterial\nbuffer response"],
    ["Primary function", "Deliver O2/nutrients to all tissues", "Gas exchange in lungs", "Nourish myocardium", "First-pass metabolism;\ndetoxification"],
    ["Flow timing peculiarity", "Continuous; pulsatile", "Continuous; pulsatile", "Mainly diastolic (LV side)", "Post-prandial surge"],
]
comp_table = Table(comp_data, colWidths=[3.5*cm, 3.7*cm, 3.7*cm, 3.7*cm, 3.7*cm])
comp_table.setStyle(TableStyle([
    ('BACKGROUND', (0,0), (-1,0), colors.HexColor('#1a3a6b')),
    ('TEXTCOLOR',  (0,0), (-1,0), colors.white),
    ('FONTNAME',   (0,0), (-1,0), 'Helvetica-Bold'),
    ('BACKGROUND', (0,0), (0,-1), colors.HexColor('#2c5f8a')),
    ('TEXTCOLOR',  (0,1), (0,-1), colors.white),
    ('FONTNAME',   (0,1), (0,-1), 'Helvetica-Bold'),
    ('FONTSIZE',   (0,0), (-1,-1), 8),
    ('ROWBACKGROUNDS', (1,1), (-1,-1), [colors.HexColor('#f5f8fd'), colors.white]),
    ('GRID',       (0,0), (-1,-1), 0.5, colors.HexColor('#b0c4de')),
    ('VALIGN',     (0,0), (-1,-1), 'MIDDLE'),
    ('TOPPADDING', (0,0), (-1,-1), 5),
    ('BOTTOMPADDING', (0,0), (-1,-1), 5),
    ('WORDWRAP',   (0,0), (-1,-1), True),
]))
story.append(comp_table)
story.append(Paragraph("Table 6. Comparative overview of the four major circulatory systems.", caption_style))

story.append(sp(2))
story.append(hr())
story.append(Paragraph(
    "<i>Sources: Costanzo Physiology 7th Edition | Guyton & Hall Textbook of Medical Physiology | "
    "Murray & Nadel's Textbook of Respiratory Medicine | Sleisenger & Fordtran's GI and Liver Disease | "
    "Ganong's Review of Medical Physiology 26e | Morgan & Mikhail's Clinical Anesthesiology 7e</i>",
    ParagraphStyle('refs', parent=styles['Normal'], fontSize=8, alignment=TA_CENTER, textColor=colors.grey, leading=12)
))

# ── Build PDF ─────────────────────────────────────────────────────────────────
print("\nBuilding PDF...")
doc = SimpleDocTemplate(
    OUTPUT,
    pagesize=A4,
    rightMargin=2*cm, leftMargin=2*cm,
    topMargin=2*cm, bottomMargin=2*cm,
    title="Circulatory System - Comprehensive Study Guide",
    author="Orris Medical Library"
)
doc.build(story)
print(f"PDF saved to: {OUTPUT}")
Running Command

cd /home/daytona/workspace/circulation-pdf && python build_pdf.py 2>&1

Running Command

ls -lh /home/daytona/workspace/circulation-pdf/Circulatory_System_Notes.pdf

Your PDF is ready! Here is your download link:

Circulatory System Notes

PDF Document · PDF


What's Inside the PDF (5.1 MB)

The PDF is a comprehensive, fully illustrated study guide covering all five topics. Here is a summary of each section:

1. Systemic Circulation

  • Full blood flow pathway: left ventricle → aorta → arterioles → capillaries → veins → right atrium
  • Pressure table covering every segment (aorta 100 mm Hg down to right atrium 0-2 mm Hg)
  • Diagram of systemic arterial pressure showing systolic (120), diastolic (80), mean, and pulse pressure
  • Regulation: local metabolites, sympathetic system, hormonal, and endothelial factors

2. Pulmonary Circulation

  • Low-pressure circuit: right ventricle → pulmonary artery (mean 15 mm Hg) → alveolar capillaries → left atrium
  • Microscopy image of pulmonary artery/vein anatomy at the terminal respiratory unit
  • Quantitative table of intrapulmonary vessel volumes and surface areas
  • Unique feature: hypoxic vasoconstriction (opposite of all other beds) for V/Q matching
  • Clinical notes on pulmonary hypertension, oedema, embolism

3. Coronary Circulation

  • Labeled coronary artery diagram (LCA, LAD, circumflex, RCA)
  • Coronary blood flow graph showing the paradoxical drop during systole and peak during diastole
  • Epicardial vs. subendocardial vulnerability diagram
  • Control mechanisms: adenosine, hypoxia, autoregulation, sympathetic (minor role)

4. Portal Circulation

  • Full anatomical pathway: GI capillaries → portal vein → hepatic sinusoids → IVC
  • Dual hepatic blood supply table (portal vein 75% vs hepatic artery 25%)
  • Hepatic sinusoid structure: fenestrae, space of Disse, stellate cells, Kupffer cells
  • Hepatic arterial buffer response
  • Portal hypertension diagram with all vascular disturbances and therapeutic sites

5. Cardiac Cycle

  • 7-phase events table (A through G) with ECG correlation, valve events, and heart sounds
  • Complete Wiggers-style cardiac cycle diagram (Costanzo + Ganong versions) with LV pressure, aortic pressure, atrial pressure, ventricular volume, venous pulse, and ECG
  • Heart sounds table (S1-S4) with causes and clinical associations
  • Key values: EDV ~130 mL, ESV ~65 mL, SV ~65 mL, EF ~55-65%, CO ~5 L/min

Final Page

  • Summary comparison table: all four circulations side-by-side (driving pressure, resistance, O2 content, regulation, primary function)
Sources: Costanzo Physiology 7e | Guyton & Hall Medical Physiology | Murray & Nadel's Respiratory Medicine | Sleisenger & Fordtran's GI & Liver Disease | Ganong's Review of Medical Physiology 26e
This is a shared conversation. Sign in to Orris to start your own chat.