teach me the blood supply of heart, ecg leads and how it is affected in MI (with LOCALISATION)


| Dominance | PDA Origin | Frequency |
|---|---|---|
| Right dominant | RCA | ~85% |
| Left dominant | LCx | ~5% |
| Codominant | Both | ~10% |
| Structure | Artery |
|---|---|
| SA node | RCA (~60%), LCx (~40%) |
| AV node | RCA (dominant ~90%), LCx (left dominant) |
| Bundle of His | Dual: LAD septal perforators + AV nodal artery |
| Right bundle branch | LAD (septal perforators) |
| Left anterior fascicle | LAD (dual supply) |
| Left posterior fascicle | RCA + LAD (most protected - dual supply) |
| Lead | Positive Pole | Negative Pole | Looks at |
|---|---|---|---|
| I | Left arm | Right arm | Lateral |
| II | Left leg | Right arm | Inferior |
| III | Left leg | Left arm | Inferior |
| Lead | Positive Electrode | Looks at |
|---|---|---|
| aVR | Right arm | Cavity (normally negative) |
| aVL | Left arm | High lateral |
| aVF | Left foot | Inferior |
| Lead | Position | Looks at |
|---|---|---|
| V1 | 4th intercostal space, right sternal border | Septum/RV |
| V2 | 4th intercostal space, left sternal border | Septum/anterior |
| V3 | Between V2 and V4 | Anterior |
| V4 | 5th intercostal space, mid-clavicular line | Anterior/apex |
| V5 | Anterior axillary line (same level as V4) | Lateral |
| V6 | Mid-axillary line (same level as V4) | Lateral |
| Parameter | Normal |
|---|---|
| Heart rate | 50-100 bpm |
| P wave duration | < 120 ms |
| PR interval | 90-200 ms |
| QRS duration | 75-110 ms |
| QTc | M: 390-450 ms; F: 390-460 ms |
| QRS axis | -30° to +90° |
| Time | ECG change |
|---|---|
| Minutes | Tall, peaked "hyperacute" T waves (earliest sign) |
| Hours | ST elevation (injury current) |
| Hours-days | Q wave development (pathological necrosis) |
| Days | T wave inversion (evolving/reperfusion) |
| Weeks-months | ST normalises, Q waves may persist permanently |
| Infarct Location | Leads with Changes | Coronary Artery | Reciprocal Changes |
|---|---|---|---|
| Anterior | V1-V4 | LAD (mid-distal) | II, III, aVF |
| Septal | V1-V2 | LAD (septal perforators) | None specific |
| Anteroseptal | V1-V3 | LAD (proximal-mid) | Inferior leads |
| Anterolateral | V1-V6, I, aVL | LAD (proximal, before D1) | II, III, aVF |
| High lateral | I, aVL | LCx or D1 (diagonal) | III, aVF |
| Lateral | I, aVL, V5-V6 | LCx (OM1 or OM2) | II, III, aVF |
| Inferior | II, III, aVF | RCA (85%) or LCx (15%) | I, aVL |
| Right ventricular | V3R-V4R (V1 sometimes) | Proximal RCA | Anterior leads |
| Posterior | Tall R + ST depression V1-V3; ST elevation V7-V9 | RCA or LCx | (V1-V3 are reciprocal) |
| Left main / Multivessel | aVR elevation + widespread ST depression | Left main or proximal LAD | Global ST depression |

RCA (proximal) ─── Inferior + RV + AV node
→ II, III, aVF + V3R-V4R
→ Heart blocks, bradycardia
RCA (mid-distal) ── Inferior + posterior
→ II, III, aVF + reciprocal V1-V3
LAD (proximal) ─── Anteroseptal + lateral + septal
→ V1-V6, I, aVL
LAD (mid) ────── Anterior
→ V1-V4
LAD (diagonal) ── High lateral
→ I, aVL
LCx ────────── Lateral / High lateral / Posterior
→ I, aVL, V5-V6 (or V7-V9)
Left Main ───── Massive anterior + aVR elevation
→ Widespread ST depression + aVR ST↑
| Finding | Think of |
|---|---|
| STE V1-V4 | Anterior MI (LAD) |
| STE V1-V4 + I, aVL | Anterolateral MI (proximal LAD) |
| STE II, III, aVF | Inferior MI (RCA or LCx) |
| STE V3R-V4R (with inferior STE) | Right ventricular MI (proximal RCA) |
| STD V1-V3 + tall R | Posterior MI (RCA or LCx) |
| STE I, aVL only | High lateral MI (D1 or LCx) |
| STE aVR + diffuse STD | Left main / proximal LAD / multivessel |
| Biphasic/deep T V2-V3 (no STE) | Wellens syndrome (critical LAD stenosis) |
| STE V7-V9 | True posterior MI |
create a pdf of all this information
ls -la /home/daytona/workspace/ 2>/dev/null || echo "workspace not found"
mkdir -p /home/daytona/workspace/cardiac-mi && python3 -c "import reportlab; print('reportlab ok')" && python3 -c "import requests; print('requests ok')"
~/cardiac-mi/generate_pdf.py
import requests
import os
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, Table, TableStyle,
HRFlowable, Image, PageBreak, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus.flowables import Flowable
OUTPUT = "/home/daytona/workspace/cardiac-mi/Cardiac_BloodSupply_ECG_MI.pdf"
# ── colour palette ──────────────────────────────────────────────────────────
C_NAVY = colors.HexColor("#1a2e4a")
C_RED = colors.HexColor("#c0392b")
C_BLUE = colors.HexColor("#2980b9")
C_TEAL = colors.HexColor("#16a085")
C_ORANGE = colors.HexColor("#e67e22")
C_LGRAY = colors.HexColor("#f0f4f8")
C_MGRAY = colors.HexColor("#d5dce6")
C_WHITE = colors.white
C_BLACK = colors.black
# ── styles ──────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
def S(name, **kw):
return ParagraphStyle(name, **kw)
TITLE_STYLE = S("DocTitle",
fontName="Helvetica-Bold", fontSize=22, textColor=C_WHITE,
alignment=TA_CENTER, spaceAfter=4)
SUBTITLE_STYLE = S("DocSub",
fontName="Helvetica", fontSize=11, textColor=C_MGRAY,
alignment=TA_CENTER, spaceAfter=2)
H1 = S("H1",
fontName="Helvetica-Bold", fontSize=14, textColor=C_WHITE,
spaceBefore=14, spaceAfter=6, leading=18,
backColor=C_NAVY, borderPad=6,
leftIndent=0, rightIndent=0)
H2 = S("H2",
fontName="Helvetica-Bold", fontSize=11, textColor=C_NAVY,
spaceBefore=10, spaceAfter=4, leading=14,
borderPad=2)
H3 = S("H3",
fontName="Helvetica-Bold", fontSize=10, textColor=C_TEAL,
spaceBefore=8, spaceAfter=3, leading=13)
BODY = S("Body",
fontName="Helvetica", fontSize=9, textColor=C_BLACK,
spaceAfter=4, leading=13, alignment=TA_JUSTIFY)
BULLET = S("Bullet",
fontName="Helvetica", fontSize=9, textColor=C_BLACK,
spaceAfter=3, leading=12, leftIndent=14, bulletIndent=4)
NOTE = S("Note",
fontName="Helvetica-Oblique", fontSize=8, textColor=colors.HexColor("#555555"),
spaceAfter=3, leading=11, leftIndent=8)
CAPTION = S("Caption",
fontName="Helvetica-Oblique", fontSize=8, textColor=colors.HexColor("#444444"),
alignment=TA_CENTER, spaceAfter=6)
TABLE_HEADER = S("TH",
fontName="Helvetica-Bold", fontSize=8.5, textColor=C_WHITE, alignment=TA_CENTER)
TABLE_CELL = S("TC",
fontName="Helvetica", fontSize=8.5, textColor=C_BLACK, alignment=TA_LEFT, leading=11)
TABLE_CELL_C = S("TCC",
fontName="Helvetica", fontSize=8.5, textColor=C_BLACK, alignment=TA_CENTER, leading=11)
# ── helper: coloured section header ─────────────────────────────────────────
def section_header(text, bg=C_NAVY, fg=C_WHITE, size=13):
style = S(f"SH_{text[:10]}",
fontName="Helvetica-Bold", fontSize=size, textColor=fg,
backColor=bg, borderPad=7, spaceBefore=16, spaceAfter=8,
leading=size+4)
return Paragraph(text, style)
def subsection_header(text):
return Paragraph(text, H2)
def subsubsection(text):
return Paragraph(text, H3)
def body(text):
return Paragraph(text, BODY)
def bullet(text):
return Paragraph(f"• {text}", BULLET)
def note(text):
return Paragraph(f"<i>{text}</i>", NOTE)
def sp(h=4):
return Spacer(1, h)
def hr(color=C_MGRAY, thickness=0.5):
return HRFlowable(width="100%", thickness=thickness, color=color, spaceAfter=4, spaceBefore=4)
def make_table(data, col_widths, header_bg=C_NAVY, stripe=True):
"""Build a styled table. data[0] = header row."""
table = Table(data, colWidths=col_widths, repeatRows=1)
n_rows = len(data)
style_cmds = [
# header
("BACKGROUND", (0,0), (-1,0), header_bg),
("TEXTCOLOR", (0,0), (-1,0), C_WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,0), 8.5),
("ALIGN", (0,0), (-1,0), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("FONTNAME", (0,1), (-1,-1), "Helvetica"),
("FONTSIZE", (0,1), (-1,-1), 8.5),
("ROWBACKGROUND", (0,0), (-1,0), header_bg),
("GRID", (0,0), (-1,-1), 0.4, C_MGRAY),
("LEFTPADDING",(0,0), (-1,-1), 5),
("RIGHTPADDING",(0,0), (-1,-1), 5),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0), (-1,-1), 4),
]
if stripe:
for i in range(1, n_rows):
bg = C_LGRAY if i % 2 == 0 else C_WHITE
style_cmds.append(("BACKGROUND", (0,i), (-1,i), bg))
table.setStyle(TableStyle(style_cmds))
return table
# ── download images ──────────────────────────────────────────────────────────
IMG_URLS = {
"sternocostal": "https://cdn.orris.care/cdss_images/aa8a084fa66ce33c9f12579f7c800b3367a6abc81ef10f5ba7f2460306155ea3.png",
"diaphragmatic": "https://cdn.orris.care/cdss_images/92995cea1339ff3de4460a9e31b3a8f8a278645fead9eccfe57cf32d041ca93e.png",
"anterior_stemi": "https://cdn.orris.care/cdss_images/779f6d419b0a92f4ddbbf7533f11e2047e00de9f40fc28c7c6bccc9af32e5a5b.png",
}
img_paths = {}
for key, url in IMG_URLS.items():
try:
r = requests.get(url, timeout=15)
path = f"/home/daytona/workspace/cardiac-mi/{key}.png"
with open(path, "wb") as f:
f.write(r.content)
img_paths[key] = path
print(f"Downloaded {key}")
except Exception as e:
print(f"Failed {key}: {e}")
def img_flow(key, width, caption=""):
elems = []
if key in img_paths and os.path.exists(img_paths[key]):
try:
elems.append(Image(img_paths[key], width=width, kind="proportional"))
if caption:
elems.append(Paragraph(caption, CAPTION))
except Exception as e:
print(f"Image error {key}: {e}")
return elems
# ── cover page flowable ───────────────────────────────────────────────────────
class CoverPage(Flowable):
def __init__(self, w, h):
Flowable.__init__(self)
self.w = w
self.h = h
def draw(self):
c = self.canv
# Background gradient-like rectangles
c.setFillColor(C_NAVY)
c.rect(0, 0, self.w, self.h, fill=1, stroke=0)
c.setFillColor(colors.HexColor("#0d1f33"))
c.rect(0, 0, self.w, self.h*0.38, fill=1, stroke=0)
# Red accent bar
c.setFillColor(C_RED)
c.rect(0, self.h*0.38, self.w, 6, fill=1, stroke=0)
# Title
c.setFillColor(C_WHITE)
c.setFont("Helvetica-Bold", 26)
c.drawCentredString(self.w/2, self.h*0.72,
"Cardiac Blood Supply,")
c.drawCentredString(self.w/2, self.h*0.64,
"ECG Leads &")
c.drawCentredString(self.w/2, self.h*0.56,
"MI Localisation")
# Subtitle
c.setFillColor(C_MGRAY)
c.setFont("Helvetica", 12)
c.drawCentredString(self.w/2, self.h*0.47,
"A Comprehensive Clinical Reference")
# Red accent line
c.setStrokeColor(C_RED)
c.setLineWidth(2)
c.line(self.w*0.2, self.h*0.44, self.w*0.8, self.h*0.44)
# Sources
c.setFillColor(C_MGRAY)
c.setFont("Helvetica-Oblique", 9)
sources = ("Sources: Rosen's Emergency Medicine | Harrison's 22E | "
"Goldman-Cecil Medicine | Ganong's Physiology | Netter's Atlas")
c.drawCentredString(self.w/2, self.h*0.28, sources)
# Date
c.setFont("Helvetica", 9)
c.drawCentredString(self.w/2, self.h*0.23, "June 2026")
# ── BUILD DOCUMENT ────────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
leftMargin=1.8*cm, rightMargin=1.8*cm,
topMargin=1.8*cm, bottomMargin=1.8*cm,
title="Cardiac Blood Supply, ECG Leads & MI Localisation",
author="Orris Medical Reference"
)
W = A4[0] - 3.6*cm # usable width
story = []
# ── COVER ─────────────────────────────────────────────────────────────────────
story.append(CoverPage(A4[0], A4[1]))
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# PART 1 - BLOOD SUPPLY
# ════════════════════════════════════════════════════════════════════════════
story.append(section_header("PART 1 | BLOOD SUPPLY OF THE HEART", bg=C_NAVY))
story.append(body(
"The heart is supplied by <b>two coronary arteries</b> that arise from the aortic sinuses "
"(sinuses of Valsalva) just above the aortic valve cusps. Coronary flow occurs primarily "
"during <b>diastole</b> (unlike the rest of the body), because systolic contraction "
"compresses the intramyocardial vessels."
))
story.append(sp(6))
# Netter images side by side
story += img_flow("sternocostal", W*0.48,
"Fig 1A. Sternocostal (anterior) surface - Netter's Atlas of Human Anatomy")
story += img_flow("diaphragmatic", W*0.48,
"Fig 1B. Diaphragmatic (posterior) surface - Netter's Atlas of Human Anatomy")
story.append(sp(8))
# ── Left Coronary Artery
story.append(subsection_header("1.1 Left Coronary Artery (LCA)"))
story.append(body(
"Arises from the <b>left (posterior) aortic sinus</b>. The <b>left main trunk</b> is "
"1-2 cm long and divides into two main branches (occasionally three — trifurcation with "
"a <i>ramus intermedius</i>)."
))
story.append(sp(4))
story.append(subsubsection("LAD (Left Anterior Descending = Anterior Interventricular Artery)"))
lad_data = [
["Feature", "Detail"],
["Course", "Runs in the anterior interventricular groove toward the apex"],
["LV supply", "Anterior wall of the LV (main bulk)"],
["Septal supply", "Anterior 2/3 of interventricular septum (via septal perforators)"],
["RV supply", "Small branches to the anterior RV"],
["Apical supply", "Usually wraps around the apex"],
["Key branches", "Diagonal branches (D1, D2) → anterolateral LV wall; Septal perforators"],
["Clinical", "Called the 'widow maker' — proximal occlusion = massive anterior MI"],
]
story.append(make_table(lad_data, [W*0.28, W*0.72], header_bg=C_BLUE))
story.append(sp(8))
story.append(subsubsection("LCx (Left Circumflex)"))
lcx_data = [
["Feature", "Detail"],
["Course", "Runs in the LEFT atrioventricular (AV) groove"],
["Supply", "Left atrium, lateral and posterior wall of LV"],
["SA node", "Supplies SA node in ~40% of people"],
["Key branches", "Obtuse marginal (OM1, OM2) branches → lateral LV wall"],
["Dominant?", "Dominant in ~5% — gives rise to PDA in left dominant systems"],
]
story.append(make_table(lcx_data, [W*0.28, W*0.72], header_bg=C_TEAL))
story.append(sp(8))
# ── Right Coronary Artery
story.append(subsection_header("1.2 Right Coronary Artery (RCA)"))
story.append(body(
"Arises from the <b>right (anterior) aortic sinus</b>. Runs in the right AV groove, "
"then turns posteriorly to reach the crux of the heart."
))
rca_data = [
["Feature", "Detail"],
["Course", "Right AV groove → crux of heart (posterior)"],
["First branch", "SA nodal artery — supplies SA node in ~60% of people"],
["RV supply", "Multiple RV branches; acute marginal branch = free wall of RV"],
["AV node", "AV nodal artery in ~85-90% of right-dominant people"],
["Posterior septum", "Posterior 1/3 of interventricular septum"],
["PDA", "Posterior descending artery — inferior wall of LV (right dominant)"],
["Posterolateral", "Posterior left ventricular branches in right dominant systems"],
]
story.append(make_table(rca_data, [W*0.28, W*0.72], header_bg=C_RED))
story.append(sp(8))
# ── Dominance
story.append(subsection_header("1.3 Coronary Dominance"))
story.append(body(
"Dominance is defined by which vessel gives rise to the <b>Posterior Descending Artery (PDA)</b>."
))
dom_data = [
["Dominance", "PDA Origin", "Frequency", "AV Node Supply"],
["Right dominant", "RCA", "~85%", "RCA"],
["Left dominant", "LCx", "~5%", "LCx"],
["Codominant", "Both RCA + LCx", "~10%", "Variable"],
]
story.append(make_table(dom_data, [W*0.22, W*0.25, W*0.22, W*0.31], header_bg=C_NAVY))
story.append(sp(8))
# ── Venous drainage
story.append(subsection_header("1.4 Venous Drainage"))
vein_data = [
["Vein", "Course / Territory", "Drains Into"],
["Great cardiac vein", "Alongside LAD → anterior coronary sulcus", "Coronary sinus"],
["Middle cardiac vein", "Posterior interventricular groove", "Coronary sinus"],
["Small cardiac vein", "Right AV groove", "Coronary sinus"],
["Posterior vein of LV", "Posterior lateral LV", "Coronary sinus"],
["Thebesian veins", "Small myocardial sinusoids", "Directly into cardiac chambers"],
]
story.append(make_table(vein_data, [W*0.28, W*0.42, W*0.30], header_bg=C_NAVY))
story.append(sp(8))
# ── Conduction system supply
story.append(subsection_header("1.5 Conduction System Blood Supply"))
cond_data = [
["Structure", "Supplying Artery", "Clinical Pearl"],
["SA node", "RCA (~60%), LCx (~40%)", "Inferior MI (RCA) → sinus bradycardia"],
["AV node", "RCA (~90%), LCx in left dominant", "Inferior MI → heart blocks (reversible)"],
["Bundle of His", "LAD septal perforators + AV nodal artery", "Dual supply = protected"],
["Right bundle branch", "LAD (septal perforators)", "Anterior MI → new RBBB"],
["Left anterior fascicle", "LAD (anterior septal perforators)", "Anterior MI → LAFB"],
["Left posterior fascicle", "RCA + LAD (dual supply)", "Most protected fascicle"],
]
story.append(make_table(cond_data, [W*0.25, W*0.30, W*0.45], header_bg=C_NAVY))
story.append(note("Source: Tintinalli's Emergency Medicine; Harrison's Principles of Internal Medicine 22E"))
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# PART 2 - ECG LEADS
# ════════════════════════════════════════════════════════════════════════════
story.append(section_header("PART 2 | ECG LEADS", bg=C_TEAL))
story.append(body(
"The standard 12-lead ECG records <b>12 views</b> of the heart using <b>10 electrodes</b> "
"(4 limb + 6 chest). The right leg electrode serves as electrical ground. Leads are grouped "
"into <b>limb leads</b> (frontal plane) and <b>precordial leads</b> (transverse plane)."
))
story.append(sp(6))
story.append(subsection_header("2.1 Limb Leads (Frontal Plane)"))
story.append(subsubsection("Bipolar Leads"))
bipolar_data = [
["Lead", "Positive Pole", "Negative Pole", "Views"],
["Lead I", "Left arm", "Right arm", "Lateral wall"],
["Lead II", "Left leg", "Right arm", "Inferior wall (most useful for rhythm)"],
["Lead III", "Left leg", "Left arm", "Inferior wall"],
]
story.append(make_table(bipolar_data, [W*0.12, W*0.20, W*0.20, W*0.48], header_bg=C_TEAL))
story.append(sp(6))
story.append(subsubsection("Augmented Unipolar Leads"))
aug_data = [
["Lead", "Positive Electrode", "Views", "Normal Polarity"],
["aVR", "Right arm", "Cardiac cavity (aVR looks inward)", "Normally negative"],
["aVL", "Left arm", "High lateral wall", "Usually positive"],
["aVF", "Left foot", "Inferior wall", "Positive"],
]
story.append(make_table(aug_data, [W*0.12, W*0.22, W*0.30, W*0.36], header_bg=C_TEAL))
story.append(sp(8))
story.append(subsection_header("2.2 Precordial (Chest) Leads (Transverse Plane)"))
story.append(body(
"Unipolar leads comparing each chest electrode to the <b>Wilson central terminal</b> "
"(average of RA + LA + LL). Positioned on specific landmarks:"
))
pre_data = [
["Lead", "Position", "Views", "Key Feature"],
["V1", "4th ICS, right sternal border", "Septum / RV", "Dominant S wave normally"],
["V2", "4th ICS, left sternal border", "Septum / anterior", "Transition zone often here"],
["V3", "Between V2 and V4", "Anterior septum", "Transitional"],
["V4", "5th ICS, mid-clavicular line", "Anterior / apex", "R = S (transition)"],
["V5", "Anterior axillary line (V4 level)", "Lateral", "Dominant R wave normally"],
["V6", "Mid-axillary line (V4 level)", "Lateral", "Dominant R wave normally"],
]
story.append(make_table(pre_data, [W*0.08, W*0.30, W*0.22, W*0.40], header_bg=C_BLUE))
story.append(sp(6))
story.append(subsubsection("Additional / Extended Leads"))
ext_data = [
["Leads", "Position", "Purpose"],
["V3R, V4R", "Mirror image on right chest", "Right ventricular MI detection"],
["V7, V8, V9", "Posterior chest wall (left)", "True posterior MI (direct ST elevation)"],
["V4R", "Right 5th ICS mid-clavicular", "Most sensitive/specific for RV infarction"],
]
story.append(make_table(ext_data, [W*0.18, W*0.42, W*0.40], header_bg=C_BLUE))
story.append(sp(8))
story.append(subsection_header("2.3 Lead Grouping by Territory"))
terr_data = [
["Territory", "Leads", "Coronary Artery"],
["Inferior", "II, III, aVF", "RCA (85%), LCx (15%)"],
["Anterior / Septal", "V1, V2, V3, V4", "LAD"],
["Lateral", "I, aVL, V5, V6", "LCx (OM branches)"],
["High lateral", "I, aVL", "LCx or D1 (diagonal of LAD)"],
["Right ventricular", "V3R, V4R (right-sided)", "Proximal RCA"],
["Posterior", "V7, V8, V9 (reciprocal in V1-V3)", "RCA or LCx"],
]
story.append(make_table(terr_data, [W*0.22, W*0.32, W*0.46], header_bg=C_NAVY))
story.append(sp(8))
story.append(subsection_header("2.4 Normal ECG Intervals"))
norm_data = [
["Parameter", "Normal Range", "Notes"],
["Heart rate", "50-100 bpm", "< 50 = bradycardia, > 100 = tachycardia"],
["P wave duration", "< 120 ms (< 3 small boxes)", "Broader → atrial enlargement / conduction delay"],
["PR interval", "90-200 ms", "> 200 ms = 1st degree AV block"],
["QRS duration", "75-110 ms", "> 120 ms = bundle branch block"],
["QTc (male)", "390-450 ms", "Prolonged QTc = risk of Torsades"],
["QTc (female)", "390-460 ms", "Slightly longer than male"],
["QRS axis", "-30° to +90°", "< -30° = LAD; > +90° = RAD"],
]
story.append(make_table(norm_data, [W*0.22, W*0.28, W*0.50], header_bg=C_TEAL))
story.append(note("Source: Goldman-Cecil Medicine International Edition"))
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# PART 3 - MI ECG CHANGES AND LOCALISATION
# ════════════════════════════════════════════════════════════════════════════
story.append(section_header("PART 3 | ECG IN MYOCARDIAL INFARCTION", bg=C_RED))
story.append(sp(4))
story.append(subsection_header("3.1 Mechanism of ECG Changes in MI"))
story.append(body(
"Three electrical changes occur in infarcted myocardium. <b>All three produce ST elevation</b> "
"in leads overlying the infarct. Leads on the opposite side of the heart show <b>reciprocal "
"ST depression</b>."
))
mech_data = [
["Defect in Infarcted Cells", "Current Flow", "ECG Change (leads over infarct)"],
["Rapid repolarisation\n(K+ channels open early)", "Out of infarct → normal area", "ST segment elevation"],
["Decreased resting membrane potential\n(K+ loss — partial depolarisation at rest)", "Into infarct during diastole", "TQ depression → recorded as ST elevation"],
["Delayed depolarisation\n(slow Na+ influx)", "Out of infarct → normal area", "ST segment elevation"],
]
story.append(make_table(mech_data, [W*0.35, W*0.30, W*0.35], header_bg=C_RED))
story.append(note("Source: Ganong's Review of Medical Physiology 26th Edition, Table 29-3"))
story.append(sp(8))
story.append(subsection_header("3.2 Temporal ECG Sequence in STEMI"))
seq_data = [
["Time", "ECG Change", "Mechanism"],
["Minutes (0-30 min)", "Tall, peaked 'hyperacute' T waves", "Earliest ischaemia — increased T wave amplitude"],
["Hours (30 min – 6 h)", "ST elevation (injury current)", "Three mechanisms above; 'tombstone' morphology"],
["Hours to 24 h", "Q wave development begins", "Electrically silent necrotic zone"],
["Hours to days", "T wave inversion", "Repolarisation abnormality over infarct zone"],
["Days to weeks", "ST normalises", "Injury current resolves with scar formation"],
["Weeks to months", "Q waves may persist", "Permanent marker of prior infarction"],
]
story.append(make_table(seq_data, [W*0.25, W*0.33, W*0.42], header_bg=C_NAVY))
story.append(sp(6))
story.append(body(
"<b>Pathological Q wave criteria:</b> width ≥ 40 ms (1 small box) OR depth > 25% of the R wave amplitude. "
"Q waves may develop as early as 1 hour but most commonly appear at 8-12 hours."
))
story.append(sp(8))
story.append(subsection_header("3.3 STEMI Diagnostic Criteria"))
stemi_data = [
["Leads", "ST Elevation Threshold (J-point)", "Notes"],
["V2-V3 (men ≥ 40 years)", "≥ 2.0 mm", "Most common threshold used"],
["V2-V3 (men < 40 years)", "≥ 2.5 mm", "Higher threshold for young men"],
["V2-V3 (women)", "≥ 1.5 mm", "Lower threshold"],
["All other leads", "≥ 1.0 mm in 2 contiguous leads", "Standard threshold"],
["V7-V9 (posterior leads)", "≥ 0.5 mm", "Lower threshold for posterior leads"],
["V3R-V4R (RV leads)", "≥ 0.5 mm (≥ 1 mm in men < 30 y)", "Right ventricular MI"],
]
story.append(make_table(stemi_data, [W*0.32, W*0.30, W*0.38], header_bg=C_RED))
story.append(note("Source: Harrison's Principles of Internal Medicine 22E"))
story.append(PageBreak())
# ── THE BIG LOCALISATION TABLE
story.append(subsection_header("3.4 MI Localisation — Master Reference Table"))
loc_data = [
["Location", "ST Elevation Leads", "Coronary Artery", "Reciprocal Changes", "Special Features"],
["Septal", "V1, V2", "LAD (septal perforators)", "None specific", "LBBB/RBBB possible"],
["Anterior", "V1-V4", "LAD (mid)", "II, III, aVF", "R wave failure to progress"],
["Anteroseptal", "V1-V3", "LAD (proximal-mid)", "Inferior leads", "Common pattern"],
["Anterolateral", "V1-V6, I, aVL", "Proximal LAD (before D1)", "II, III, aVF", "Largest territory MI"],
["High lateral", "I, aVL", "D1 (diagonal) or LCx", "III, aVF", "May be subtle/small"],
["Lateral", "I, aVL, V5-V6", "LCx (OM1 or OM2)", "II, III, aVF", "Can be isolated or with inferior"],
["Inferior", "II, III, aVF", "RCA (85%), LCx (15%)", "I, aVL", "Always check V3R/V4R for RVI"],
["Right ventricular", "V3R-V4R (V1)", "Proximal RCA", "Anterior leads", "Triad: Hypotension+JVP↑+clear lungs"],
["Posterior", "V7-V9 (direct); V1-V3 reciprocal", "RCA or LCx", "V1-V3 (STD + tall R)", "R>S in V1 = posterior MI equivalent"],
["Left main/multivessel", "aVR + V1 (+ diffuse STD)", "Left main or proximal LAD", "Global ST depression", "aVR > V1 = LM; V1 > aVR = LAD"],
]
story.append(make_table(loc_data,
[W*0.16, W*0.18, W*0.18, W*0.18, W*0.30],
header_bg=C_NAVY))
story.append(sp(8))
# ── Territory-by-territory detail
story.append(subsection_header("3.5 Territory-by-Territory Detail"))
story.append(sp(4))
# ANTERIOR
story.append(subsubsection("Anterior STEMI (LAD)"))
story.append(body(
"ST elevation in <b>V1-V4</b>. Reciprocal depression in II, III, aVF. The LAD supplies "
"the anterior LV wall and the anterior 2/3 of the septum via septal perforators."
))
story.append(bullet("Proximal LAD occlusion (before D1): Anterolateral pattern — STE extends to I, aVL, V5-V6"))
story.append(bullet("Mid LAD: Classic anterior V1-V4 only"))
story.append(bullet("Distal LAD: May show only V3-V4 or apical changes"))
story.append(bullet("Look for new RBBB, LAFB — septal perforators supply the right bundle branch"))
story += img_flow("anterior_stemi", W*0.9,
"Fig 2. Anterior wall STEMI — ST elevation V1-V4. LAD 90% stenosis. "
"(Rosen's Emergency Medicine, Fig 64.6)")
story.append(sp(6))
# INFERIOR
story.append(subsubsection("Inferior STEMI (RCA or LCx)"))
story.append(body(
"ST elevation in <b>II, III, aVF</b>. Reciprocal depression in <b>I and aVL</b> "
"(absence of reciprocal changes should prompt reconsideration of the diagnosis)."
))
inf_tips = [
["Finding", "Implication"],
["III > II in ST elevation", "RCA occlusion more likely (right dominant)"],
["II > III in ST elevation", "LCx occlusion more likely (left dominant or codominant)"],
["ST elevation in V3R-V4R", "Right ventricular involvement — proximal RCA"],
["ST elevation V7-V9 also", "Inferoposterior MI — RCA or LCx"],
["Heart blocks (1°, 2° Mobitz I)", "AV nodal ischaemia from RCA — usually reversible"],
["Sinus bradycardia", "SA nodal ischaemia from RCA"],
]
story.append(make_table(inf_tips, [W*0.45, W*0.55], header_bg=C_ORANGE))
story.append(sp(6))
# RV MI
story.append(subsubsection("Right Ventricular MI"))
story.append(body(
"Always suspect in <b>inferior STEMI</b> — proximal RCA occlusion (before RV marginal branch). "
"Apply right-sided leads (V3R-V4R) to every patient with inferior STEMI."
))
story.append(bullet("ECG: STE in V3R-V4R (V4R most sensitive/specific)"))
story.append(bullet("Clinical triad: Hypotension + Elevated JVP + Clear lungs (no pulmonary oedema)"))
story.append(bullet("Kussmaul's sign may be present (JVP rises on inspiration)"))
story.append(bullet("AVOID nitrates and diuretics — RV is preload-dependent"))
story.append(bullet("Treatment: IV fluids, maintain RV preload, early reperfusion"))
story.append(sp(6))
# POSTERIOR
story.append(subsubsection("Posterior MI"))
story.append(body(
"No standard lead looks directly at the posterior wall — diagnosed by <b>reciprocal changes "
"in V1-V3</b>. Confirm with posterior leads V7-V9."
))
post_data = [
["Finding in V1-V3", "Meaning"],
["Horizontal ST depression", "Reciprocal to posterior ST elevation"],
["Tall, broad R wave (R > S in V1)", "Reciprocal to posterior Q wave"],
["Upright T waves", "Reciprocal to posterior T wave inversion"],
["ST elevation V7-V9 ≥ 0.5 mm", "Direct posterior MI confirmation"],
]
story.append(make_table(post_data, [W*0.45, W*0.55], header_bg=C_BLUE))
story.append(sp(6))
# HIGH LATERAL
story.append(subsubsection("High Lateral MI"))
story.append(body(
"ST elevation <b>only in I and aVL</b>, with reciprocal changes in III and aVF. "
"Caused by occlusion of the <b>first diagonal (D1) branch of LAD</b> or an <b>LCx</b> "
"OM branch. Often subtle — small territory, easy to miss."
))
story.append(sp(6))
# LEFT MAIN
story.append(subsubsection("Left Main / Proximal LAD / Multivessel Ischaemia"))
story.append(body(
"The most haemodynamically unstable STEMI equivalent. Pattern: "
"<b>ST elevation in aVR</b> (and often V1) with diffuse ST depression in multiple leads."
))
lm_data = [
["Pattern", "Likely Culprit"],
["aVR elevation > V1 elevation", "Left main coronary artery occlusion"],
["V1 elevation > aVR elevation", "Proximal LAD occlusion"],
["aVR + V1 elevation + diffuse STD", "Multivessel ischaemia or LMCA"],
["de Winter pattern (J-point depression + upsloping STD V1-V6 + prominent T waves + aVR elevation)", "Proximal LAD occlusion (STEMI equivalent)"],
]
story.append(make_table(lm_data, [W*0.45, W*0.55], header_bg=C_RED))
story.append(note(
"aVR > 0.5 mV STE: ~78% sensitive, ~83% specific for left main disease. "
"(Rosen's Emergency Medicine)"
))
story.append(PageBreak())
# ── SPECIAL PATTERNS
story.append(subsection_header("3.6 Special Patterns to Know"))
story.append(sp(4))
story.append(subsubsection("Wellens Syndrome (Critical LAD Stenosis — No STE)"))
story.append(body(
"Seen <b>between ischaemic episodes</b> — ECG changes present when patient is pain-free. "
"Represents >70% proximal LAD stenosis. <b>DO NOT stress test</b> — risk of massive MI."
))
wellens_data = [
["Type", "ECG Findings", "Risk"],
["Type A (25%)", "Biphasic T waves in V2-V3\n(positive then negative)", "High risk proximal LAD occlusion"],
["Type B (75%)", "Deep, symmetric T wave inversions in V2-V3", "High risk proximal LAD occlusion"],
]
story.append(make_table(wellens_data, [W*0.15, W*0.45, W*0.40], header_bg=C_ORANGE))
story.append(sp(6))
story.append(subsubsection("LBBB and STEMI (Sgarbossa Criteria)"))
story.append(body(
"New (or presumed new) LBBB in the setting of chest pain may represent STEMI — "
"however, LBBB itself alters the ST segments. The <b>Sgarbossa criteria</b> help "
"identify STEMI within LBBB:"
))
sgar_data = [
["Criterion", "Points", "Specificity"],
["ST elevation ≥ 1 mm concordant with QRS direction", "5 points", "High"],
["ST depression ≥ 1 mm in V1-V3 (concordant ST depression)", "3 points", "High"],
["ST elevation ≥ 5 mm discordant with QRS (excessive discordance)", "2 points", "Moderate"],
]
story.append(make_table(sgar_data, [W*0.55, W*0.15, W*0.30], header_bg=C_NAVY))
story.append(note("Score ≥ 3 points is sensitive and specific for STEMI in LBBB."))
story.append(sp(8))
# ── QUICK REFERENCE SUMMARY
story.append(section_header("QUICK REFERENCE SUMMARY", bg=C_NAVY, size=12))
story.append(sp(4))
story.append(subsection_header("Artery → Territory → ECG Leads at a Glance"))
qr_data = [
["Artery / Branch", "Territory Supplied", "ECG Leads Affected", "Watch For"],
["RCA (proximal)", "Inferior + RV + AV node", "II, III, aVF + V3R-V4R", "Heart block, RV failure"],
["RCA (mid-distal)", "Inferior + posterior", "II, III, aVF + V7-V9 (reciprocal V1-V3)", "Posterior involvement"],
["LAD (proximal)", "Anterior + lateral + septum", "V1-V6, I, aVL", "Largest MI, RBBB, LAFB"],
["LAD (mid)", "Anterior wall", "V1-V4", "Classic anterior STEMI"],
["D1 (diagonal)", "High lateral", "I, aVL", "Subtle — easy to miss"],
["LCx (OM branches)", "Lateral / posterior LV", "I, aVL, V5-V6 (or V7-V9)", "Posterior MI pattern"],
["Left main / proximal LAD", "Massive — all LV territories", "aVR + V1 elevation + diffuse STD", "Cardiogenic shock"],
]
story.append(make_table(qr_data,
[W*0.22, W*0.24, W*0.26, W*0.28],
header_bg=C_RED))
story.append(sp(10))
story.append(subsection_header("ECG Finding → Think of"))
ecg_dx_data = [
["ECG Finding", "Diagnosis / Territory"],
["STE V1-V4", "Anterior STEMI (LAD)"],
["STE V1-V4 + I, aVL", "Anterolateral STEMI (proximal LAD)"],
["STE II, III, aVF", "Inferior STEMI (RCA or LCx)"],
["STE II, III, aVF + V3R-V4R", "Inferior + Right Ventricular MI (proximal RCA)"],
["STD V1-V3 + tall R + upright T", "Posterior MI (reciprocal) — check V7-V9"],
["STE I, aVL only", "High lateral MI (D1 or LCx)"],
["STE aVR > V1 + diffuse STD", "Left main artery occlusion"],
["STE V1 > aVR + widespread changes", "Proximal LAD occlusion"],
["Biphasic/deep T V2-V3, pain-free", "Wellens syndrome — critical LAD stenosis"],
["Concordant STE in LBBB", "STEMI in LBBB (Sgarbossa criterion)"],
["STE V7-V9 ≥ 0.5 mm", "True posterior MI"],
["Hyperacute T waves (tall, peaked)", "Earliest STEMI sign (minutes after occlusion)"],
["STE + PR depression, all leads", "Pericarditis (not MI)"],
]
story.append(make_table(ecg_dx_data, [W*0.45, W*0.55], header_bg=C_NAVY))
story.append(sp(8))
story.append(note(
"Sources: Rosen's Emergency Medicine | Harrison's Principles of Internal Medicine 22E | "
"Goldman-Cecil Medicine International Edition | Ganong's Review of Medical Physiology 26th Ed | "
"Netter's Atlas of Human Anatomy | Tintinalli's Emergency Medicine"
))
# ── BUILD ─────────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF created: {OUTPUT}")
cd /home/daytona/workspace/cardiac-mi && python3 generate_pdf.py 2>&1
~/cardiac-mi/generate_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/cardiac-mi/generate_pdf.py'
~/cardiac-mi/generate_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/cardiac-mi/generate_pdf.py'
~/cardiac-mi/generate_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/cardiac-mi/generate_pdf.py'
~/cardiac-mi/generate_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/cardiac-mi/generate_pdf.py'
~/cardiac-mi/generate_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/cardiac-mi/generate_pdf.py'
~/cardiac-mi/generate_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/cardiac-mi/generate_pdf.py'
cd /home/daytona/workspace/cardiac-mi && python3 generate_pdf.py 2>&1
ls -lh /home/daytona/workspace/cardiac-mi/Cardiac_BloodSupply_ECG_MI.pdf
Cardiac BloodSupply ECG MI
PDF Document · PDF