Can you teach me ecg

Asking for Preferences
Reading File
Finding Sources
Finding Sources
Finding Sources
Reading File
Finding Sources
Finding Sources
Reading File
Finding Sources
Finding Sources
Reading File
Reading File
Reading File
Loading Image
Loading Image
Reading File
I have everything needed for a thorough guide. Here is the full ECG interpretation framework for a practicing clinician.

ECG Interpretation: A Systematic Approach

Accurate ECG reading requires a fixed, reproducible sequence. As Harrison's puts it: "Many mistakes in ECG interpretation are errors of omission. Therefore, a systematic approach is essential." - Harrison's Principles of Internal Medicine 22E, p. 1919
Use this 14-step framework every single time.

Step 0 - Technical Check (Before You Read Anything)

  • Calibration: Standard is 10 mm = 1 mV and 25 mm/s sweep speed. Confirm the calibration box is present.
  • Lead placement: Reversed limb leads (most commonly L/R arm swap) produce bizarre axis and pseudo-infarct patterns. Look for P wave inversion in I with an upright P in aVR - that is the telltale sign.
  • Artifacts: Muscle tremor, loose leads, or patient movement can simulate AF or VT. If something looks dramatic and the patient seems fine, suspect artifact first.

Step 1 - The ECG Waveforms (Anatomy of a Beat)

ECG waveforms and intervals from Harrison's
WaveformRepresentsNormal
P waveAtrial depolarizationUpright in I, II; inverted in aVR
PR intervalAV conduction (SA node → bundle of His)120-200 ms (3-5 small squares)
QRSVentricular depolarization≤110 ms (≤2.5 small squares)
ST segmentIsoelectric plateau between depol. and repol.At baseline (J point)
T waveVentricular repolarizationConcordant with QRS direction
QT intervalTotal ventricular electrical cycleRate-dependent (QTc ≤440 ms men, ≤460 ms women)
U wavePurkinje repolarization (or M-cell)Small, same direction as T wave
Paper grid: Each small square = 40 ms (0.04 s) horizontally; each large square = 200 ms (0.20 s).

Step 2 - Rate

Rapid method (regular rhythm): 300 ÷ number of large squares between R waves.
  • 1 large square = 300 bpm
  • 2 = 150, 3 = 100, 4 = 75, 5 = 60, 6 = 50
For irregular rhythms: Count R waves in a 10-second strip × 6.
Normal: 60-100 bpm. Bradycardia <60, tachycardia >100.

Step 3 - Rhythm

Ask three questions:
  1. Is there a P wave before every QRS?
  2. Is there a QRS after every P wave?
  3. Are the R-R intervals regular?
This immediately classifies the rhythm into:
PatternLikely Diagnosis
Regular, P before QRS, normal rateSinus rhythm
Regular, P before QRS, rate >100Sinus tachycardia
Irregularly irregular, no distinct P wavesAtrial fibrillation
"Sawtooth" baseline at 300 bpm, QRS every 2nd or 3rd waveAtrial flutter
No P waves, wide bizarre QRS, rate 100-250Ventricular tachycardia
P waves present, rate <60Sinus bradycardia or block

Step 4 - PR Interval (AV Conduction)

Normal: 120-200 ms (3-5 small squares).
FindingInterpretation
PR >200 ms (constant)1st degree AV block
PR progressively lengthens → dropped QRS2nd degree AV block, Mobitz I (Wenckebach)
Sudden dropped QRS, PR constant2nd degree AV block, Mobitz II (more dangerous)
P waves and QRS completely dissociatedComplete (3rd degree) AV block
PR <120 ms with delta wavePre-excitation (WPW)

Step 5 - QRS Duration and Morphology

Normal: ≤110 ms (≤2.5 small squares).
Wide QRS (>120 ms) means delayed ventricular conduction:
PatternDiagnosis
Wide QRS + rSR' ("M" pattern) in V1, deep S in V5/V6Right bundle branch block (RBBB)
Wide QRS + broad notched R in V5/V6, no septal q, QS in V1Left bundle branch block (LBBB)
Wide QRS + short PR + slurred upstroke (delta wave)WPW / pre-excitation
Wide QRS + no P wavesVT until proven otherwise
For fascicular blocks: QRS is narrow (<120 ms) but the axis shifts markedly - left axis deviation (< -45°) = left anterior fascicular block; right axis deviation (>+110°) = left posterior fascicular block.

Step 6 - QRS Axis

The axis tells you the net direction of ventricular depolarization in the frontal plane.
Quick method: Look at leads I and aVF.
Lead ILead aVFAxis
PositivePositiveNormal (0° to +90°)
PositiveNegativeLeft axis deviation (LAD)
NegativePositiveRight axis deviation (RAD)
NegativeNegativeExtreme ("northwest") axis
Normal range: -30° to +100°. LAD <-30°, RAD >+100°.
Causes of LAD: LVH, left anterior fascicular block, inferior MI, LBBB. Causes of RAD: RVH, lateral MI, RBBB, left posterior fascicular block, PE, normal variant in young/thin patients.

Step 7 - Ventricular Depolarization (Precordial Leads)

Ventricular depolarization vectors - Harrison's
Depolarization has two phases:
  1. Phase 1 - Septum depolarizes left to right → small r in V1, small q in V6
  2. Phase 2 - LV dominates, vector points left/posterior → deep S in V1, tall R in V5/V6
Normal R-wave progression: R wave grows from V1 to V5, transition at V3/V4.
Poor R-wave progression (R wave fails to grow V1→V4): suggests anterior MI, LBBB, or COPD.

Step 8 - P Waves

  • Normal P: upright in I, II, aVF; inverted in aVR; biphasic in V1 (terminal negative portion)
  • Tall, peaked P >2.5 mm in II: Right atrial enlargement ("P pulmonale")
  • Broad, notched P >120 ms: Left atrial enlargement ("P mitrale")
  • Inverted P in II / retrograde P: Junctional rhythm or ectopic atrial focus
  • No visible P waves: AF, hyperkalemia (if combined with wide QRS)

Step 9 - QRS Voltages

Low voltage (QRS amplitude <5 mm in all limb leads or <10 mm in all precordial leads):
  • Pericardial effusion, cardiac tamponade (especially with electrical alternans)
  • Hypothyroidism, COPD, obesity, amyloidosis
High voltage:
  • LVH - Sokolov-Lyon criteria: S in V1 + R in V5 or V6 >35 mm; or R in aVL >11 mm
  • RVH - Dominant R in V1 (R >S), right axis deviation, ST depression V1-V3

Step 10 - ST Segment

This is where you find ischemia, injury, and infarction.

ST Elevation (STE)

Measure at the J point. Significant thresholds (from Washington Manual):
  • ≥1 mm in 2 contiguous leads (most leads)
  • ≥2 mm in V1-V3 in men ≥40 years (≥2.5 mm in men <40)
  • ≥1.5 mm in V1-V3 in women
  • ≥0.5 mm in posterior (V7-V9) or right-sided leads (V3R/V4R)
STE localization = culprit artery:
TerritoryLeadsArtery
Anterior/septalV1-V4LAD (proximal)
LateralI, aVL, V5-V6LCx
InferiorII, III, aVFRCA (usually)
PosteriorTall R + ST depression V1-V3 → check V7-V9LCx (often "silent")
Right ventricleV1, V3R-V4RProximal RCA
Reciprocal ST depression in the opposite territory increases specificity for acute MI.

ST Depression

  • Horizontal or downsloping: subendocardial ischemia (NSTEMI/UA)
  • Upsloping: less specific, can be normal variant
  • Diffuse STE + saddle-shaped + PR depression: pericarditis (not ischemia)

Sgarbossa Criteria (STEMI in LBBB or paced rhythm)

When LBBB is present, normal ST-T should be discordant with QRS. Ischemia is suspected when:
  1. STE ≥1 mm concordant with QRS (same direction as QRS) - most specific
  2. STD ≥1 mm in V1-V3 - concordant depression
  3. STE ≥5 mm discordant (opposite to QRS) - less specific

Step 11 - T Waves

  • Normally concordant with QRS (upright where QRS is positive)
  • Tall, peaked "hyperacute" T waves: earliest sign of STEMI (minutes after occlusion)
  • T-wave inversion: ischemia, RVH strain, LVH strain, post-tachycardia, CNS events
  • Diffuse T-wave inversion: Wellens syndrome (critical proximal LAD stenosis) - biphasic or deeply inverted T in V2-V3 in a pain-free patient. Do not stress-test these patients.
  • Tall peaked T waves: hyperkalemia (early sign, then widens QRS, then sine wave)

Step 12 - QT Interval

The QT interval shortens with faster heart rates. Always use a corrected QT (QTc).
Most common formula: Bazett's - QTc = QT / √RR (in seconds)
Normal QTc: ≤440 ms (men), ≤460 ms (women). Prolonged if >500 ms - significant risk of torsades de pointes.
Causes of long QT: Drugs (antiarrhythmics, antipsychotics, antibiotics like azithromycin), electrolyte abnormalities (↓K, ↓Mg, ↓Ca), congenital LQTS, hypothyroidism, hypothermia.
Short QT (<340 ms): hypercalcemia, digoxin toxicity, short QT syndrome.

Step 13 - U Waves

  • A small positive deflection after the T wave, best seen in V2-V3
  • Prominent U waves: hypokalemia (classic), bradycardia, LVH
  • Inverted U waves: myocardial ischemia (often overlooked)

Step 14 - Compare with Prior ECGs

This is not optional. A "new" LBBB, new Q waves, new axis deviation, or subtle ST change is far more informative than any isolated finding. Always ask for prior tracings.

Quick Summary Card

1.  Technical quality (calibration, lead placement, artifacts)
2.  Rate (300 ÷ large squares for regular; count × 6 for irregular)
3.  Rhythm (P before QRS? QRS after P? Regular R-R?)
4.  PR interval (120-200 ms; long = AV block; short+delta = WPW)
5.  QRS width (≤110 ms; wide = BBB, VT, WPW, metabolic)
6.  Axis (Leads I and aVF; normal -30° to +100°)
7.  R-wave progression (small in V1, growing to V5)
8.  P-wave morphology (tall = RAE; broad/notched = LAE)
9.  QRS voltages (low = effusion/hypothyroid; high = LVH/RVH)
10. ST segments (elevation = injury; depression = ischemia)
11. T waves (hyperacute = early STEMI; deep inv. = Wellens/ischemia)
12. QTc (>500 ms = risk of TdP)
13. U waves (prominent = hypokalemia)
14. Compare with prior ECGs

Common Pitfalls

PitfallTip
Calling AF when it's artifactCheck pulse, look for one clean lead with clear P waves
Missing posterior STEMIST depression V1-V3 + tall R = flip the ECG, think posterior; get V7-V9
Calling LVH strain "ischemia"Strain pattern: downsloping ST depression + asymmetric T inversion in lateral leads, no reciprocal changes
Over-reading computerized interpretationComputer has ~50-60% accuracy for complex findings; always review yourself (Harrison's notes computers still have "major limitations")
Missing RV infarction in inferior MIAny inferior STEMI → get right-sided leads; RV infarction changes management (fluids, not nitrates)
Ignoring electrolytes when QRS is wideHyperkalemia widens QRS and can look like VT or BBB

Want me to go deeper into any specific area - arrhythmias, ischemia localization, hypertrophy criteria, or electrolyte changes? I can also walk through example ECG cases.

Create a printable ECG quick reference PDF for your pocket

Reading File
Running Command

mkdir -p /home/daytona/workspace/ecg-reference && ls /home/daytona/workspace/ecg…

Writing File

~/ecg-reference/make_ecg_pdf.py

#!/usr/bin/env python3
"""
ECG Pocket Reference Card - printable A5 (half-sheet) PDF
Uses reportlab only.
"""

from reportlab.lib.pagesizes import A5
from reportlab.lib import colors
from reportlab.lib.units import mm
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_CENTER
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    HRFlowable, KeepTogether
)
from reportlab.lib.colors import HexColor, white, black

OUTPUT = "/home/daytona/workspace/ecg-reference/ECG_Pocket_Reference.pdf"

# ── Colour palette ──────────────────────────────────────────────────────────
C_NAVY   = HexColor("#0D2B55")
C_RED    = HexColor("#C0392B")
C_BLUE   = HexColor("#2471A3")
C_TEAL   = HexColor("#148F77")
C_ORANGE = HexColor("#D35400")
C_LTGRAY = HexColor("#F2F4F7")
C_MIDGRAY= HexColor("#BDC3C7")
C_WHITE  = white
C_BLACK  = black

# ── Page setup ────────────────────────────────────────────────────────────
W, H = A5   # 148 x 210 mm
MARGIN = 8 * mm

doc = SimpleDocTemplate(
    OUTPUT,
    pagesize=A5,
    leftMargin=MARGIN,
    rightMargin=MARGIN,
    topMargin=MARGIN,
    bottomMargin=MARGIN,
    title="ECG Pocket Reference",
    author="Orris Clinical Tools",
)

# ── Styles ────────────────────────────────────────────────────────────────
def style(name, parent=None, **kw):
    base = ParagraphStyle(name, **kw)
    return base

S_TITLE = style("title",
    fontSize=13, leading=16, textColor=C_WHITE,
    fontName="Helvetica-Bold", alignment=TA_CENTER)

S_SECTION = style("section",
    fontSize=7.5, leading=9, textColor=C_WHITE,
    fontName="Helvetica-Bold", alignment=TA_LEFT)

S_BODY = style("body",
    fontSize=6.5, leading=8.5, textColor=C_BLACK,
    fontName="Helvetica", alignment=TA_LEFT)

S_BOLD = style("bold",
    fontSize=6.5, leading=8.5, textColor=C_BLACK,
    fontName="Helvetica-Bold", alignment=TA_LEFT)

S_SMALL = style("small",
    fontSize=5.8, leading=7.5, textColor=HexColor("#555555"),
    fontName="Helvetica", alignment=TA_LEFT)

S_WARN = style("warn",
    fontSize=6.5, leading=8.5, textColor=C_RED,
    fontName="Helvetica-Bold", alignment=TA_LEFT)

S_FOOTER = style("footer",
    fontSize=5.5, leading=7, textColor=HexColor("#888888"),
    fontName="Helvetica", alignment=TA_CENTER)

# ── Helper: section header ────────────────────────────────────────────────
def sec_hdr(text, color=C_NAVY):
    return Table(
        [[Paragraph(text, S_SECTION)]],
        colWidths=[W - 2*MARGIN],
        rowHeights=[10*mm],
        style=TableStyle([
            ("BACKGROUND", (0,0), (-1,-1), color),
            ("VALIGN",     (0,0), (-1,-1), "MIDDLE"),
            ("LEFTPADDING",(0,0), (-1,-1), 4),
            ("TOPPADDING", (0,0), (-1,-1), 1),
            ("BOTTOMPADDING",(0,0),(-1,-1),1),
            ("ROUNDEDCORNERS", [2]),
        ])
    )

# ── Helper: 2-col table ───────────────────────────────────────────────────
def two_col(rows, col1=55*mm, col2=None, hdr_color=C_NAVY):
    if col2 is None:
        col2 = W - 2*MARGIN - col1
    style_cmds = [
        ("FONTSIZE",    (0,0), (-1,-1), 6.3),
        ("LEADING",     (0,0), (-1,-1), 8),
        ("FONTNAME",    (0,0), (-1,0),  "Helvetica-Bold"),
        ("BACKGROUND",  (0,0), (-1,0),  C_LTGRAY),
        ("TEXTCOLOR",   (0,0), (-1,0),  C_NAVY),
        ("GRID",        (0,0), (-1,-1), 0.3, C_MIDGRAY),
        ("VALIGN",      (0,0), (-1,-1), "TOP"),
        ("LEFTPADDING", (0,0), (-1,-1), 3),
        ("RIGHTPADDING",(0,0), (-1,-1), 3),
        ("TOPPADDING",  (0,0), (-1,-1), 2),
        ("BOTTOMPADDING",(0,0),(-1,-1), 2),
        ("ROWBACKGROUNDS",(0,1),(-1,-1),[C_WHITE, C_LTGRAY]),
    ]
    tbl_rows = []
    for r in rows:
        tbl_rows.append([Paragraph(str(r[0]), S_BOLD if r is rows[0] else S_BODY),
                         Paragraph(str(r[1]), S_BOLD if r is rows[0] else S_BODY)])
    return Table(tbl_rows, colWidths=[col1, col2], style=TableStyle(style_cmds))

def three_col(rows, widths=None):
    if widths is None:
        total = W - 2*MARGIN
        widths = [total*0.30, total*0.35, total*0.35]
    style_cmds = [
        ("FONTSIZE",     (0,0), (-1,-1), 6.0),
        ("LEADING",      (0,0), (-1,-1), 7.5),
        ("FONTNAME",     (0,0), (-1,0),  "Helvetica-Bold"),
        ("BACKGROUND",   (0,0), (-1,0),  C_LTGRAY),
        ("TEXTCOLOR",    (0,0), (-1,0),  C_NAVY),
        ("GRID",         (0,0), (-1,-1), 0.3, C_MIDGRAY),
        ("VALIGN",       (0,0), (-1,-1), "TOP"),
        ("LEFTPADDING",  (0,0), (-1,-1), 3),
        ("RIGHTPADDING", (0,0), (-1,-1), 3),
        ("TOPPADDING",   (0,0), (-1,-1), 2),
        ("BOTTOMPADDING",(0,0), (-1,-1), 2),
        ("ROWBACKGROUNDS",(0,1),(-1,-1), [C_WHITE, C_LTGRAY]),
    ]
    tbl_rows = [[Paragraph(str(c), S_BODY) for c in r] for r in rows]
    return Table(tbl_rows, colWidths=widths, style=TableStyle(style_cmds))

def sp(h=2):
    return Spacer(1, h*mm)

# ══════════════════════════════════════════════════════════════════════════
# BUILD CONTENT
# ══════════════════════════════════════════════════════════════════════════
story = []

# ── TITLE BANNER ─────────────────────────────────────────────────────────
title_tbl = Table(
    [[Paragraph("ECG QUICK REFERENCE", S_TITLE),
      Paragraph("Pocket Card", S_SECTION)]],
    colWidths=[W - 2*MARGIN - 28*mm, 28*mm],
    rowHeights=[12*mm],
    style=TableStyle([
        ("BACKGROUND",  (0,0), (-1,-1), C_NAVY),
        ("VALIGN",      (0,0), (-1,-1), "MIDDLE"),
        ("LEFTPADDING", (0,0), (0,0),   6),
        ("RIGHTPADDING",(1,0), (1,0),   4),
        ("TOPPADDING",  (0,0), (-1,-1), 2),
    ])
)
story.append(title_tbl)
story.append(sp(2))

# ── 1. WAVEFORMS & INTERVALS ─────────────────────────────────────────────
story.append(sec_hdr("1  WAVEFORMS & INTERVALS"))
story.append(sp(1))
w_rows = [
    ["Waveform / Interval", "Normal value & represents"],
    ["P wave",       "Atrial depolarisation. Upright I, II; inverted aVR"],
    ["PR interval",  "120-200 ms (3-5 sm sq). AV conduction time"],
    ["QRS",          "≤110 ms (≤2.5 sm sq). Ventricular depolarisation"],
    ["QT interval",  "Rate-corrected (QTc): ≤440 ms ♂ / ≤460 ms ♀"],
    ["ST segment",   "Isoelectric. Junction = J point"],
    ["T wave",       "Ventricular repolarisation. Concordant with QRS"],
    ["U wave",       "Small, after T. Prominent → hypokalaemia"],
]
story.append(two_col(w_rows, col1=32*mm))
story.append(sp(1))
story.append(Paragraph(
    "<b>Paper speed 25 mm/s:</b>  1 small sq = 40 ms  |  1 large sq = 200 ms  |  "
    "1 mV = 10 mm (standard calibration)", S_SMALL))
story.append(sp(2))

# ── 2. RATE & RHYTHM ─────────────────────────────────────────────────────
story.append(sec_hdr("2  RATE & RHYTHM", C_BLUE))
story.append(sp(1))

rate_rows = [
    ["Large sq between R-R", "Rate (bpm)"],
    ["1", "300"], ["2", "150"], ["3", "100"],
    ["4", "75"],  ["5", "60"],  ["6", "50"],
]
rhythm_rows = [
    ["Pattern", "Likely diagnosis"],
    ["Regular, P before QRS",          "Sinus rhythm/tachy/brady"],
    ["Irregularly irregular, no P",    "Atrial fibrillation"],
    ["Sawtooth 300 bpm, 2:1 or 3:1",   "Atrial flutter"],
    ["Wide QRS, no P, 100-250 bpm",    "Ventricular tachycardia"],
    ["P-QRS dissociation",             "Complete (3°) AV block"],
]

total = W - 2*MARGIN
left_w = total * 0.36
right_w = total - left_w - 3*mm

rate_tbl = two_col(rate_rows, col1=26*mm, col2=18*mm)
rhythm_tbl = two_col(rhythm_rows, col1=42*mm)

combo = Table(
    [[rate_tbl, Spacer(3*mm,1), rhythm_tbl]],
    colWidths=[44*mm, 3*mm, right_w],
    style=TableStyle([("VALIGN",(0,0),(-1,-1),"TOP")])
)
story.append(combo)
story.append(sp(2))

# ── 3. INTERVALS AT A GLANCE ─────────────────────────────────────────────
story.append(sec_hdr("3  KEY INTERVALS — ABNORMALITIES", C_TEAL))
story.append(sp(1))
int_rows = [
    ["Interval", "If short", "If long"],
    ["PR",    "< 120 ms → WPW (+ delta wave)",
               "> 200 ms → 1° AV block\nProgressive ↑→ drop = Mobitz I\nSudden drop (PR const) = Mobitz II"],
    ["QRS",   "N/A",
               "> 120 ms → BBB, WPW, VT, hyperkalaemia"],
    ["QTc",   "< 340 ms → hypercalcaemia, digoxin, short QT syndrome",
               "> 500 ms → TdP risk; drugs, ↓K/Mg/Ca, LQTS"],
]
story.append(three_col(int_rows, widths=[20*mm, 50*mm, 62*mm]))
story.append(sp(2))

# ── 4. QRS AXIS ──────────────────────────────────────────────────────────
story.append(sec_hdr("4  QRS AXIS  (normal −30° to +100°)", C_NAVY))
story.append(sp(1))
ax_rows = [
    ["Lead I", "Lead aVF", "Axis", "Causes"],
    ["↑ +ve", "↑ +ve", "Normal",           "—"],
    ["↑ +ve", "↓ −ve", "LAD (<−30°)",      "LVH, LAFB, inferior MI, LBBB"],
    ["↓ −ve", "↑ +ve", "RAD (>+100°)",     "RVH, lateral MI, RBBB, PE, LPFB"],
    ["↓ −ve", "↓ −ve", "Extreme (NW axis)","VT, hyperkalaemia, lead reversal"],
]
story.append(three_col(ax_rows, widths=[18*mm, 18*mm, 30*mm, 66*mm]))
story.append(sp(2))

# ── 5. BUNDLE BRANCH BLOCKS ──────────────────────────────────────────────
story.append(sec_hdr("5  BUNDLE BRANCH BLOCKS  (QRS > 120 ms)", C_ORANGE))
story.append(sp(1))
bbb_rows = [
    ["BBB", "V1", "V5/V6", "Memory aid"],
    ["RBBB", "rSR' (rabbit ears)", "Wide S wave",
             "WiLLiaM MaRRoW → RBBB = V1 W, V6 M"],
    ["LBBB", "QS or rS", "Broad notched R, no septal q",
             "WiLLiaM MaRRoW → LBBB = V1 M, V6 W"],
]
story.append(three_col(bbb_rows, widths=[16*mm, 36*mm, 36*mm, 44*mm]))
story.append(sp(1))
story.append(Paragraph(
    "<b>T waves discordant with QRS</b> in BBB = secondary change (normal). "
    "T waves concordant = suspect primary ischaemia.", S_SMALL))
story.append(sp(2))

# ── 6. ST SEGMENT ────────────────────────────────────────────────────────
story.append(sec_hdr("6  ST SEGMENT — ISCHAEMIA / INFARCTION", C_RED))
story.append(sp(1))

# STE thresholds
ste_rows = [
    ["Lead group", "STE threshold (at J point)", "Artery"],
    ["V1-V3 (men ≥40)",     "≥ 2 mm",       "LAD"],
    ["V1-V3 (men <40)",     "≥ 2.5 mm",     "LAD"],
    ["V1-V3 (women)",       "≥ 1.5 mm",     "LAD/LCx"],
    ["All other leads",     "≥ 1 mm in 2 contiguous leads", "Territory-specific"],
    ["V7-V9 (posterior)",   "≥ 0.5 mm",     "LCx (often silent)"],
    ["V3R-V4R (RV)",        "≥ 0.5 mm (men <30: ≥1 mm)", "Proximal RCA"],
]
story.append(three_col(ste_rows, widths=[38*mm, 52*mm, 42*mm]))
story.append(sp(1))

# Territory table
terr_rows = [
    ["Territory", "Leads", "Culprit artery"],
    ["Anterior/Septal",  "V1-V4",          "LAD (proximal)"],
    ["Lateral",          "I, aVL, V5-V6",  "LCx or LAD diagonal"],
    ["Inferior",         "II, III, aVF",   "RCA (80%) / LCx (20%)"],
    ["Posterior",        "ST↓ V1-V3 + tall R → check V7-V9", "LCx"],
    ["Right ventricle",  "V1, V3R-V4R",    "Proximal RCA"],
]
story.append(three_col(terr_rows, widths=[30*mm, 52*mm, 50*mm]))
story.append(sp(1))
story.append(Paragraph(
    "<b>Sgarbossa (STEMI in LBBB/paced):</b>  "
    "(1) STE ≥1 mm concordant with QRS  |  "
    "(2) STD ≥1 mm in V1-V3  |  "
    "(3) STE ≥5 mm discordant with QRS", S_SMALL))
story.append(sp(1))
story.append(Paragraph(
    "<b>Pericarditis:</b>  Diffuse saddle-shaped STE + PR depression — no reciprocal changes, no Q waves.", S_SMALL))
story.append(sp(2))

# ── 7. T WAVES ───────────────────────────────────────────────────────────
story.append(sec_hdr("7  T WAVES", C_TEAL))
story.append(sp(1))
tw_rows = [
    ["Finding", "Significance"],
    ["Tall, peaked (hyperacute)",     "Earliest STEMI sign (minutes after occlusion)"],
    ["Deep symmetric inversion V2-V3","Wellens syndrome — critical LAD stenosis (do NOT stress test!)"],
    ["Diffuse T inversion",           "Ischaemia, PE, myocarditis, CNS injury"],
    ["T inversion V1-V3 + RBBB",     "May indicate RV strain or anterior ischaemia"],
    ["Peaked T + wide QRS",          "Hyperkalaemia — check electrolytes urgently"],
]
story.append(two_col(tw_rows, col1=52*mm))
story.append(sp(2))

# ── 8. HYPERTROPHY ───────────────────────────────────────────────────────
story.append(sec_hdr("8  HYPERTROPHY", C_BLUE))
story.append(sp(1))
hyp_rows = [
    ["Diagnosis", "Criterion"],
    ["LVH (Sokolov-Lyon)", "S(V1) + R(V5 or V6) > 35 mm  OR  R(aVL) > 11 mm"],
    ["LVH strain pattern",  "Downsloping ST↓ + asymmetric T inversion in I, aVL, V5-V6"],
    ["RVH",                  "Dominant R in V1 (R > S) + RAD + ST↓/T-inv V1-V3"],
    ["RAE (P pulmonale)",    "Tall, peaked P > 2.5 mm in II"],
    ["LAE (P mitrale)",      "Broad, notched P > 120 ms (bifid P in II, −ve terminal V1)"],
]
story.append(two_col(hyp_rows, col1=40*mm))
story.append(sp(2))

# ── 9. AV BLOCKS ─────────────────────────────────────────────────────────
story.append(sec_hdr("9  AV BLOCKS", C_NAVY))
story.append(sp(1))
avb_rows = [
    ["Degree", "ECG finding", "Action"],
    ["1°",         "PR > 200 ms, all P→QRS conducted",          "Monitor; usually benign"],
    ["2° Mobitz I","PR lengthens → dropped QRS (Wenckebach)",   "Usually nodal; monitor"],
    ["2° Mobitz II","Constant PR, sudden dropped QRS",           "High-risk → pacing consult"],
    ["2:1 block",   "Every other P blocked",                    "Can't distinguish M1/M2 → treat as M2"],
    ["3° (complete)","P & QRS dissociated, escape rhythm",      "Urgent pacing"],
]
story.append(three_col(avb_rows, widths=[25*mm, 65*mm, 42*mm]))
story.append(sp(2))

# ── 10. ELECTROLYTES ─────────────────────────────────────────────────────
story.append(sec_hdr("10  ELECTROLYTE CHANGES", C_ORANGE))
story.append(sp(1))
elec_rows = [
    ["Electrolyte", "Low", "High"],
    ["Potassium (K)",
     "Flat/inverted T, prominent U, ST↓, U > T in same lead",
     "Peaked T → wide QRS → sine wave → VF/asystole"],
    ["Calcium (Ca)",
     "Long QTc (prolonged ST), ↑ TdP risk",
     "Short QTc, short ST segment, J-wave (Osborn)"],
    ["Magnesium (Mg)",
     "Long QTc, TdP. Often with ↓K",
     "Bradycardia, PR/QRS prolongation"],
]
story.append(three_col(elec_rows, widths=[26*mm, 60*mm, 46*mm]))
story.append(sp(2))

# ── 11. QUICK-LOOK PITFALLS ──────────────────────────────────────────────
story.append(sec_hdr("11  COMMON PITFALLS", C_RED))
story.append(sp(1))
pit_rows = [
    ["Pitfall", "How to avoid"],
    ["Calling AF when it's artifact",          "Check pulse; find one lead with clear P waves"],
    ["Missing posterior STEMI",                "ST↓ V1-V3 → get V7-V9; tall R in V1/V2 = posterior Q"],
    ["LVH strain called ischaemia",            "Strain: downsloping ST↓, asymmetric T-inv, no reciprocal STE"],
    ["RV infarction missed in inferior MI",    "Any inferior STEMI → get V3R/V4R; give fluids not nitrates"],
    ["Trusting computer read uncritically",    "Computer accuracy ~50-60% for complex patterns; always review"],
    ["Ignoring electrolytes in wide QRS",      "Wide QRS + no P + peaked T → consider hyperkalaemia"],
    ["Lead reversal",                          "P inverted in I + upright aVR = L/R arm reversal"],
]
story.append(two_col(pit_rows, col1=50*mm))
story.append(sp(2))

# ── 12. SYSTEMATIC CHECKLIST ─────────────────────────────────────────────
story.append(sec_hdr("12  SYSTEMATIC CHECKLIST", C_TEAL))
story.append(sp(1))

checklist_text = (
    "<b>□ 1 Technical</b> — calibration, leads, artifacts    "
    "<b>□ 2 Rate</b> — 300 ÷ large squares (regular); count×6 (irregular)<br/>"
    "<b>□ 3 Rhythm</b> — P before QRS? QRS after P? Regular R-R?    "
    "<b>□ 4 PR</b> — 120-200 ms; progressive lengthening? dropped beats?<br/>"
    "<b>□ 5 QRS width</b> — ≤110 ms; if wide → BBB, VT, WPW, toxin    "
    "<b>□ 6 Axis</b> — I + aVF; LAD/RAD?<br/>"
    "<b>□ 7 R-wave progression</b> — grows V1→V5, transition V3/V4    "
    "<b>□ 8 P-wave morphology</b> — tall = RAE; broad/notched = LAE<br/>"
    "<b>□ 9 Voltages</b> — high (LVH/RVH) or low (effusion, hypothyroid, amyloid)?    "
    "<b>□ 10 ST segments</b> — elevation/depression; territory?<br/>"
    "<b>□ 11 T waves</b> — hyperacute? Wellens? Peaked (K)?    "
    "<b>□ 12 QTc</b> — >500 ms → TdP risk<br/>"
    "<b>□ 13 U waves</b> — prominent → ↓K    "
    "<b>□ 14 Compare prior ECG</b> — new changes are the most important finding"
)
story.append(Paragraph(checklist_text, S_BODY))
story.append(sp(3))

# ── FOOTER ───────────────────────────────────────────────────────────────
story.append(HRFlowable(width="100%", thickness=0.5, color=C_MIDGRAY))
story.append(sp(1))
story.append(Paragraph(
    "ECG Pocket Reference  |  Based on Harrison's Principles 22E, Washington Manual, Braunwald's Heart Disease  |  "
    "For clinical decision-making always correlate with history, examination, and prior tracings.",
    S_FOOTER))

# ── BUILD ─────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF written to: {OUTPUT}")
Running Command

cd /home/daytona/workspace/ecg-reference && python3 make_ecg_pdf.py 2>&1

Editing File

~/ecg-reference/make_ecg_pdf.py

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/ecg-reference/make_ecg_pdf.py'
Running Command

cd /home/daytona/workspace/ecg-reference && python3 make_ecg_pdf.py 2>&1

Running Command

ls -lh /home/daytona/workspace/ecg-reference/ECG_Pocket_Reference.pdf

Your ECG pocket reference card is ready:

ECG Pocket Reference

PDF Document · PDF

What's inside (A5 format - fits in a white coat pocket):
SectionContents
1. Waveforms & IntervalsP, PR, QRS, QT, ST, T, U - normal values
2. Rate & Rhythm300-rule table + rhythm pattern recognition
3. Key IntervalsShort/long PR, QRS, QTc with causes
4. QRS AxisI + aVF quick method, causes of LAD/RAD
5. Bundle Branch BlocksRBBB vs LBBB morphology + WiLLiaM MaRRoW
6. ST SegmentSTEMI thresholds by lead, territory-artery table, Sgarbossa, pericarditis
7. T WavesHyperacute, Wellens, hyperkalaemia
8. HypertrophySokolov-Lyon, strain, RVH, P-wave changes
9. AV BlocksAll degrees with action needed
10. ElectrolytesK, Ca, Mg - high and low ECG changes
11. Pitfalls7 common mistakes with how to avoid them
12. Systematic Checklist14-step checkbox you can run on every tracing
Print tip: Print at A5 size (or set your printer to "fit to page" on A4/letter, then cut in half). For a laminated card, print two copies back-to-back on A5.
This is a shared conversation. Sign in to Orris to start your own chat.