Give me a pdf that would be enough to diagnose and ecg correctly with its treatment don't generate boring pdf make it colourful with animations and don't miss any concepts I know some what ecg please help me to be better add some more details and more detailed easy and simple explanation keep details vast and include treatment too bro and keep colour radiant and add cartoonisitc and animated images generate more attractive pdf this is best this details should be there but add more with modification I mentioned plz help me out with it and at end of every page introduce a footer of my name mihir and give page number with a boundary it should be attractive create a pdf of it

Reading File
Running Command

mkdir -p /tmp/workspace/ecg-pdf && ls /tmp/workspace/

Give me a pdf that would be enough to diagnose and ecg correctly with its treatment don't generate boring pdf make it colourful with animations and don't miss any concepts I know some what ecg please help me to be better add some more details and more detailed easy and simple explanation keep details vast and include treatment too bro and keep colour radiant and add cartoonisitc and animated images generate more attractive pdf this is best this details should be there but add more with modification I mentioned plz help me out with it and at end of every page introduce a footer of my name mihir and give page number with a boundary it should be attractive create a pdf of it

Reading File
Running Command

mkdir -p /tmp/workspace/ecg-pdf && echo "Ready"

Why so much time

Running Command

cat << 'PYEOF' > /tmp/workspace/ecg-pdf/build_ecg.py from reportlab.lib.pagesizes import A4 from reportlab.lib import colors from reportlab.lib.units import mm, cm from reportlab.platypus import (SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, PageBreak, HRFlowable) from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY from reportlab.platypus.flowables import Flowable from reportlab.pdfgen import canvas from reportlab.graphics.shapes import Drawing, Rect, Circle, Ellipse, Line, Polygon, String, Path from reportlab.graphics import renderPDF import math, os OUTPUT = "/tmp/workspace/ecg-pdf/ECG_MasterGuide_Mihir.pdf" W, H = A4 # 595 x 842 pts # ── Colour palette ────────────────────────────────────────────────────────── C_BG = colors.HexColor("#0D1B2A") # deep navy C_CARD1 = colors.HexColor("#1A2E4A") C_CARD2 = colors.HexColor("#112233") C_ACCENT1 = colors.HexColor("#FF6B6B") # coral red C_ACCENT2 = colors.HexColor("#FFD93D") # sunny yellow C_ACCENT3 = colors.HexColor("#6BCB77") # mint green C_ACCENT4 = colors.HexColor("#4D96FF") # electric blue C_ACCENT5 = colors.HexColor("#FF922B") # orange C_ACCENT6 = colors.HexColor("#CC5DE8") # purple C_WHITE = colors.white C_LTGRAY = colors.HexColor("#C8D6E5") C_GOLD = colors.HexColor("#FFD700") C_PINK = colors.HexColor("#FF69B4") C_CYAN = colors.HexColor("#00D4FF") C_LIME = colors.HexColor("#AAFF00") # ── Page background + border + footer drawn on every page ─────────────────── def on_page(canv, doc): canv.saveState() # full-page gradient background simulation canv.setFillColor(C_BG) canv.rect(0, 0, W, H, fill=1, stroke=0) # decorative corner squares sz = 18 for x, y in [(0,0),(W-sz,0),(0,H-sz),(W-sz,H-sz)]: canv.setFillColor(C_ACCENT2) canv.rect(x, y, sz, sz, fill=1, stroke=0) # outer rainbow border (4 nested rectangles) border_cols = [C_ACCENT4, C_ACCENT3, C_ACCENT1, C_ACCENT2] for i, bc in enumerate(border_cols): off = 6 + i*4 canv.setStrokeColor(bc) canv.setLineWidth(2.5 - i*0.4) canv.roundRect(off, off, W-2*off, H-2*off, 12-i*2, fill=0, stroke=1) # heartbeat line across the top canv.setStrokeColor(C_ACCENT1) canv.setLineWidth(2) p = canv.beginPath() segs = [(0,H-28),(60,H-28),(70,H-8),(80,H-48),(90,H-8),(100,H-28),(W,H-28)] p.moveTo(*segs[0]) for pt in segs[1:]: p.lineTo(*pt) canv.drawPath(p) # ── FOOTER ── footer_y = 20 canv.setFillColor(C_ACCENT2) canv.roundRect(30, footer_y-4, W-60, 22, 6, fill=1, stroke=0) canv.setFillColor(C_BG) canv.setFont("Helvetica-Bold", 9) canv.drawCentredString(W/2, footer_y+4, f"✦ MIHIR ✦ ECG MasterGuide ✦ Page {doc.page} ✦") canv.restoreState() # ── Helper Flowables ──────────────────────────────────────────────────────── class ColorBox(Flowable): """A coloured rounded-rect box drawn behind some text – used as section dividers.""" def __init__(self, text, bg=C_ACCENT4, fg=C_WHITE, font="Helvetica-Bold", fsize=14, radius=10, pad=8, width=None): super().__init__() self.text = text self.bg = bg self.fg = fg self.font = font self.fsize = fsize self.radius= radius self.pad = pad self._w = width or (W - 100) self.height= fsize + 2*pad + 4 def wrap(self, aW, aH): return (self._w, self.height) def draw(self): c = self.canv c.setFillColor(self.bg) c.roundRect(0, 0, self._w, self.height, self.radius, fill=1, stroke=0) c.setFillColor(self.fg) c.setFont(self.font, self.fsize) c.drawCentredString(self._w/2, self.pad+2, self.text) class ECGWave(Flowable): """Draws a realistic cartoon ECG trace with labelled waves.""" def __init__(self, width=460, height=130): super().__init__() self._w = width self._h = height def wrap(self, aW, aH): return (self._w, self._h) def draw(self): c = self.canv w, h = self._w, self._h baseline = h * 0.42 # grid c.setStrokeColor(colors.HexColor("#1A4A2A")) c.setLineWidth(0.4) for gx in range(0, int(w)+1, 20): c.line(gx, 0, gx, h*0.85) for gy in range(0, int(h*0.85)+1, 20): c.line(0, gy, w, gy) # bold grid every 100px c.setStrokeColor(colors.HexColor("#2A7A4A")) c.setLineWidth(0.8) for gx in range(0, int(w)+1, 100): c.line(gx, 0, gx, h*0.85) # ECG waveform points (two beats) def beat(ox): return [ (ox+0, baseline), # start (ox+20, baseline), # flat (ox+28, baseline+8), # P wave up (ox+36, baseline+8), (ox+40, baseline), # P down (ox+55, baseline), # PR flat (ox+58, baseline-5), # Q dip (ox+62, baseline+55), # R peak (ox+66, baseline-12), # S dip (ox+72, baseline), # back to base (ox+80, baseline), (ox+88, baseline+6), # T wave (ox+100, baseline+18), (ox+112, baseline+6), (ox+120, baseline), (ox+150, baseline), # TP flat ] pts1 = beat(10) pts2 = beat(10+150) all_pts = pts1 + pts2[1:] c.setStrokeColor(C_ACCENT3) c.setLineWidth(2.5) p = c.beginPath() p.moveTo(*all_pts[0]) for pt in all_pts[1:]: p.lineTo(*pt) c.drawPath(p) # Labels c.setFont("Helvetica-Bold", 9) labels = [ (pts1[2][0]+2, pts1[2][1]+12, "P", C_ACCENT2), (pts1[7][0]-4, pts1[7][1]+6, "R", C_ACCENT1), (pts1[10][0], pts1[10][1]-14, "Q", C_CYAN), (pts1[11][0]-2, pts1[11][1]-14, "S", C_PINK), (pts1[14][0]+2, pts1[14][1]+20, "T", C_ACCENT3), (pts1[0][0]+2, pts1[0][1]-14, "PR int",C_LTGRAY), (pts1[8][0]+4, pts1[8][1]-14, "QRS", C_ACCENT5), (pts1[12][0]+2, pts1[12][1]+6, "ST", C_ACCENT4), ] for lx, ly, txt, col in labels: c.setFillColor(col) c.drawString(lx, ly, txt) # Baseline dashed c.setStrokeColor(C_LTGRAY) c.setDash(4, 3) c.setLineWidth(0.7) c.line(0, baseline, w, baseline) c.setDash() class HeartCartoon(Flowable): """Simple cartoon heart with face.""" def __init__(self, size=80): super().__init__() self.size = size def wrap(self, aW, aH): return (self.size, self.size) def draw(self): c = self.canv s = self.size cx, cy = s/2, s/2 - 4 # heart shape using bezier curves c.setFillColor(C_ACCENT1) c.setStrokeColor(colors.HexColor("#FF0000")) c.setLineWidth(2) p = c.beginPath() # left bump p.moveTo(cx, cy - s*0.15) p.curveTo(cx - s*0.05, cy + s*0.25, cx - s*0.45, cy + s*0.25, cx - s*0.45, cy) p.curveTo(cx - s*0.45, cy - s*0.25, cx, cy - s*0.4, cx, cy - s*0.15) # right bump p.moveTo(cx, cy - s*0.15) p.curveTo(cx + s*0.05, cy + s*0.25, cx + s*0.45, cy + s*0.25, cx + s*0.45, cy) p.curveTo(cx + s*0.45, cy - s*0.25, cx, cy - s*0.4, cx, cy - s*0.15) c.drawPath(p, fill=1, stroke=1) # face eyes c.setFillColor(C_WHITE) c.circle(cx - s*0.12, cy + s*0.05, s*0.06, fill=1, stroke=0) c.circle(cx + s*0.12, cy + s*0.05, s*0.06, fill=1, stroke=0) c.setFillColor(C_BG) c.circle(cx - s*0.10, cy + s*0.05, s*0.03, fill=1, stroke=0) c.circle(cx + s*0.10, cy + s*0.05, s*0.03, fill=1, stroke=0) # smile c.setStrokeColor(C_BG) c.setLineWidth(1.5) p2 = c.beginPath() p2.moveTo(cx - s*0.10, cy - s*0.04) p2.curveTo(cx - s*0.05, cy - s*0.12, cx + s*0.05, cy - s*0.12, cx + s*0.10, cy - s*0.04) c.drawPath(p2, fill=0, stroke=1) class RhythmStrip(Flowable): """Draws various cartoon rhythm strips labelled by type.""" RHYTHMS = { "Normal Sinus": "normal", "A-Fib": "afib", "V-Fib": "vfib", "V-Tach": "vtach", "Heart Block 3rd": "chb", "ST Elevation": "stemi", } def __init__(self, rtype="normal", width=420, height=70, label=""): super().__init__() self.rtype = rtype self._w = width self._h = height self.label = label def wrap(self, aW, aH): return (self._w, self._h) def draw(self): c = self.canv w, h = self._w, self._h bl = h * 0.5 # background c.setFillColor(colors.HexColor("#0A1F0A")) c.roundRect(0, 0, w, h, 6, fill=1, stroke=0) # grid c.setStrokeColor(colors.HexColor("#143D14")) c.setLineWidth(0.5) for gx in range(0, int(w), 15): c.line(gx, 4, gx, h-4) for gy in range(4, int(h), 15): c.line(0, gy, w, gy) c.setStrokeColor(C_ACCENT3) c.setLineWidth(2) if self.rtype == "normal": pts = [] for b in range(5): ox = b * 80 + 10 pts += [(ox, bl),(ox+10,bl),(ox+14,bl+7),(ox+18,bl), (ox+23,bl),(ox+25,bl-3),(ox+28,bl+28),(ox+31,bl-7), (ox+34,bl),(ox+40,bl+9),(ox+48,bl),(ox+55,bl)] elif self.rtype == "afib": import random; random.seed(42) pts = [(0, bl)] x = 0 while x < w: x += random.randint(3, 9) pts.append((x, bl + random.randint(-5, 5))) # occasional QRS for b in [60, 160, 255, 340]: pts += [(b, bl),(b+2, bl+25),(b+4, bl-8),(b+6, bl)] elif self.rtype == "vfib": import random; random.seed(7) pts = [(0, bl)] x = 0 while x < w: x += random.randint(2, 8) pts.append((x, bl + random.randint(-22, 22))) elif self.rtype == "vtach": pts = [] for b in range(8): ox = b * 52 pts += [(ox,bl),(ox+5,bl),(ox+8,bl+24),(ox+14,bl-10), (ox+18,bl),(ox+30,bl+8),(ox+38,bl+8),(ox+45,bl),(ox+52,bl)] elif self.rtype == "chb": # P waves march independently, wide QRS slow pts = [] for pp in range(12): ox = pp*35+5 pts += [(ox,bl),(ox+4,bl+6),(ox+8,bl)] c.setStrokeColor(C_ACCENT4) c.setLineWidth(2) p2 = c.beginPath() p2.moveTo(5, bl) for pp in range(12): ox = pp*35+5 p2.lineTo(ox, bl); p2.lineTo(ox+4,bl+6); p2.lineTo(ox+8,bl) c.drawPath(p2, stroke=1, fill=0) # slow QRS c.setStrokeColor(C_ACCENT1) pts = [] for b in range(3): ox = b*145+30 pts += [(ox,bl),(ox+5,bl-4),(ox+10,bl+32),(ox+16,bl-10),(ox+22,bl)] elif self.rtype == "stemi": pts = [] for b in range(4): ox = b*100+10 pts += [(ox,bl),(ox+10,bl),(ox+14,bl+7),(ox+18,bl), (ox+22,bl-3),(ox+26,bl+38),(ox+30,bl-8), (ox+34,bl+14),(ox+50,bl+14), # ST elevation (ox+55,bl+10),(ox+65,bl),(ox+75,bl)] if self.rtype not in ("chb",): p = c.beginPath() if pts: p.moveTo(*pts[0]) for pt in pts[1:]: p.lineTo(*pt) c.drawPath(p, stroke=1, fill=0) elif self.rtype == "chb": p = c.beginPath() if pts: p.moveTo(*pts[0]) for pt in pts[1:]: p.lineTo(*pt) c.setStrokeColor(C_ACCENT1) c.drawPath(p, stroke=1, fill=0) # label if self.label: c.setFillColor(C_ACCENT2) c.setFont("Helvetica-Bold", 8) c.drawString(6, h-14, self.label) class BulletBox(Flowable): """Coloured pill-shaped bullet row.""" def __init__(self, items, bg=C_CARD1, accent=C_ACCENT4, width=None, font_size=10): super().__init__() self.items = items self.bg = bg self.accent = accent self._w = width or (W - 100) self.fs = font_size self.lh = font_size + 8 self.height = len(items) * self.lh + 16 def wrap(self, aW, aH): return (self._w, self.height) def draw(self): c = self.canv c.setFillColor(self.bg) c.roundRect(0, 0, self._w, self.height, 10, fill=1, stroke=0) y = self.height - self.lh for item in self.items: # bullet circle c.setFillColor(self.accent) c.circle(14, y + self.fs*0.35, 5, fill=1, stroke=0) c.setFillColor(C_WHITE) c.setFont("Helvetica", self.fs) c.drawString(26, y, item) y -= self.lh # ── Paragraph styles ──────────────────────────────────────────────────────── styles = getSampleStyleSheet() def S(name, **kw): return ParagraphStyle(name, **kw) title_style = S("MyTitle", fontSize=32, textColor=C_ACCENT2, fontName="Helvetica-Bold", alignment=TA_CENTER, spaceAfter=6, leading=38) subtitle_style = S("MySub", fontSize=16, textColor=C_CYAN, fontName="Helvetica-BoldOblique", alignment=TA_CENTER, spaceAfter=4) h1 = S("H1", fontSize=18, textColor=C_ACCENT2, fontName="Helvetica-Bold", spaceBefore=10, spaceAfter=4, leading=22) h2 = S("H2", fontSize=14, textColor=C_CYAN, fontName="Helvetica-Bold", spaceBefore=6, spaceAfter=3, leading=18) h3 = S("H3", fontSize=12, textColor=C_ACCENT3, fontName="Helvetica-Bold", spaceBefore=4, spaceAfter=2) body = S("Body", fontSize=10, textColor=C_LTGRAY, fontName="Helvetica", spaceBefore=3, spaceAfter=3, leading=14, alignment=TA_JUSTIFY) emph = S("Emph", fontSize=10, textColor=C_ACCENT2, fontName="Helvetica-BoldOblique", spaceBefore=2, spaceAfter=2) small = S("Small", fontSize=8, textColor=C_LTGRAY, fontName="Helvetica", spaceBefore=1, spaceAfter=1) def H(txt, st=h1): return Paragraph(txt, st) def B(txt): return Paragraph(txt, body) def SP(n=6): return Spacer(1, n) def colored_table(data, col_widths, header_bg=C_ACCENT4): t = Table(data, colWidths=col_widths) style = TableStyle([ ("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), 10), ("ALIGN", (0,0), (-1,-1), "CENTER"), ("VALIGN", (0,0), (-1,-1), "MIDDLE"), ("ROWBACKGROUNDS", (0,1), (-1,-1), [C_CARD1, C_CARD2]), ("TEXTCOLOR", (0,1), (-1,-1), C_LTGRAY), ("FONTNAME", (0,1), (-1,-1), "Helvetica"), ("FONTSIZE", (0,1), (-1,-1), 9), ("GRID", (0,0), (-1,-1), 0.5, colors.HexColor("#2A4A6A")), ("ROUNDEDCORNERS", [6]), ("TOPPADDING", (0,0), (-1,-1), 5), ("BOTTOMPADDING",(0,0), (-1,-1), 5), ]) t.setStyle(style) return t # ── Build story ───────────────────────────────────────────────────────────── story = [] # ════════════════════════════════════════════════════════════════════════════ # PAGE 1 – COVER # ════════════════════════════════════════════════════════════════════════════ story += [ SP(40), HeartCartoon(size=110), SP(10), Paragraph("ECG MASTER GUIDE", title_style), Paragraph("Complete Diagnosis + Treatment Atlas", subtitle_style), SP(6), Paragraph("● Waves ● Intervals ● Rhythms ● Arrhythmias ● STEMI ● Blocks ● Treatment ●", S("cover_sub", fontSize=11, textColor=C_ACCENT3, fontName="Helvetica-BoldOblique", alignment=TA_CENTER)), SP(10), ECGWave(width=460, height=130), SP(12), ColorBox("📖 Made with ❤ for Mihir — Your Pocket ECG Bible 📖", bg=C_ACCENT1, fg=C_WHITE, fsize=12, radius=14), SP(8), Paragraph("Crafted to make you an ECG Expert ✦ Every concept, every arrhythmia, every treatment", S("foot2", fontSize=9, textColor=C_LTGRAY, alignment=TA_CENTER)), PageBreak(), ] # ════════════════════════════════════════════════════════════════════════════ # PAGE 2 – WHAT IS AN ECG? # ════════════════════════════════════════════════════════════════════════════ story += [ SP(8), ColorBox("⚡ CHAPTER 1 : WHAT IS AN ECG?", bg=C_ACCENT4, fsize=16), SP(8), H("What is an ECG (Electrocardiogram)?", h1), B("An ECG is a graphical recording of the electrical activity of the heart over time. " "Every time the heart beats, tiny electrical signals travel through the heart muscle. " "These signals can be detected by electrodes placed on the skin and plotted as waves " "on graph paper (or screen). Think of it as the heart's own <b>WhatsApp message</b> — " "it tells you what's happening inside!"), SP(6), H("Why is ECG So Important?", h2), BulletBox([ "Detect heart attacks (MI) within minutes", "Identify life-threatening arrhythmias (V-Fib, V-Tach)", "Diagnose heart blocks and conduction defects", "Assess drug toxicity (e.g., digoxin, quinidine)", "Monitor electrolyte imbalances (K+, Ca2+)", "Screen athletes and pre-op patients", "Evaluate pacemaker function", ], accent=C_ACCENT4), SP(8), H("The ECG Paper — Your Canvas", h2), B("Standard ECG paper runs at <b>25 mm/sec</b>. Each small square = 1 mm = 0.04 sec. " "Each large square = 5 mm = 0.2 sec. Voltage: 1 mV = 10 mm (10 small boxes) in amplitude."), SP(6), colored_table( [["Parameter", "Small Box", "Large Box", "Standard Value"], ["Time (width)", "0.04 sec", "0.2 sec", "25 mm/s paper speed"], ["Voltage (height)","0.1 mV", "0.5 mV", "1 mV = 10 mm"], ["Boxes per second","25 small", "5 large", "—"], ["Normal HR calc", "300/large sq","1500/small sq","60-100 bpm"]], [120, 90, 90, 140] ), SP(8), H("The 12-Lead System — 12 Views of the Heart", h2), B("Just like photographing a building from 12 angles, 12 leads give 12 different views " "of the same electrical event. They are grouped into:"), BulletBox([ "Limb leads: I, II, III (frontal plane — left/right/up/down)", "Augmented limb leads: aVR, aVL, aVF (augmented unipolar)", "Precordial (chest) leads: V1 to V6 (horizontal plane — front/back)", "Each lead 'looks' at a different wall of the heart", ], accent=C_ACCENT3), SP(6), colored_table( [["Lead Group", "Leads", "Wall Viewed", "Artery"], ["Inferior", "II, III, aVF", "Inferior wall", "RCA"], ["Lateral", "I, aVL, V5, V6", "Lateral wall", "LCx"], ["Anterior", "V1–V4", "Anterior wall", "LAD"], ["Septal", "V1, V2", "Septum", "LAD"], ["Right ventricular","V1, V4R", "Right ventricle", "RCA"], ["Posterior", "V7–V9 (reciprocal)","Posterior wall","LCx/RCA"]], [100, 110, 120, 110] ), PageBreak(), ] # ════════════════════════════════════════════════════════════════════════════ # PAGE 3 – WAVES, INTERVALS, SEGMENTS # ════════════════════════════════════════════════════════════════════════════ story += [ SP(8), ColorBox("🌊 CHAPTER 2 : WAVES, INTERVALS & SEGMENTS", bg=C_ACCENT3, fg=C_BG, fsize=16), SP(6), ECGWave(width=460, height=140), SP(6), H("The P Wave — Atrial Depolarisation", h2), BulletBox([ "Represents: SA node fires → both atria contract", "Normal: Upright in I, II, aVF; biphasic in V1", "Duration: < 0.12 sec (3 small boxes)", "Amplitude: < 2.5 mm in limb leads, < 1.5 mm in V1", "Absent P wave = AF, junctional rhythm, or SA block", "Tall peaked P (>2.5 mm) = P pulmonale (RA enlargement)", "Broad notched P = P mitrale (LA enlargement)", ], accent=C_ACCENT2), SP(6), H("The QRS Complex — Ventricular Depolarisation", h2), BulletBox([ "Q wave: First negative deflection — septal depolarisation", "R wave: First positive deflection — main ventricular depolarisation", "S wave: First negative deflection after R", "Normal QRS duration: 0.06–0.10 sec (< 3 small boxes)", "Wide QRS (>0.12 sec) = BBB, WPW, ventricular rhythm, hyperkalaemia", "Pathological Q: > 0.04 sec wide OR > 1/3 of R height = old MI", "Tall R in V1 = RVH, RBBB, posterior MI, WPW", ], accent=C_ACCENT1), SP(6), H("The T Wave — Ventricular Repolarisation", h2), BulletBox([ "Normally upright in I, II, V3–V6; inverted in aVR, V1 (normal)", "Tall peaked T = hyperkalaemia (early), hyperacute STEMI", "Inverted T = ischaemia, PE, hypertrophy, BBB, digoxin", "Flattened T = hypokalaemia, hypothyroidism, ischaemia", ], accent=C_ACCENT3), SP(6), H("The U Wave", h2), B("Small deflection after T wave. Best seen in V2–V3. Prominent U = hypokalaemia, " "bradycardia, hypothermia. Inverted U = ischaemia, LVH."), SP(6), colored_table( [["Interval/Segment","Duration (Normal)","What it measures", "Abnormal = "], ["PR interval", "0.12–0.20 sec", "AV node conduction", "Heart block / WPW"], ["QRS duration", "0.06–0.10 sec", "Ventricular depol.", "BBB / hyperkalaemia"], ["QT interval", "< 0.44 sec (men)", "Total ventricular act.", "Long QT syndrome"], ["QTc (Bazett)", "< 0.44 s", "Rate-corrected QT", "TdP risk"], ["ST segment", "Isoelectric", "Early repolarisation", "STEMI / NSTEMI"], ["PR segment", "Isoelectric", "AV node + Bundle", "Pericarditis (dep.)"]], [110, 100, 140, 120] ), PageBreak(), ] # ════════════════════════════════════════════════════════════════════════════ # PAGE 4 – SYSTEMATIC APPROACH # ════════════════════════════════════════════════════════════════════════════ story += [ SP(8), ColorBox("🔍 CHAPTER 3 : SYSTEMATIC ECG READING — STEP BY STEP", bg=C_ACCENT5, fg=C_WHITE, fsize=15), SP(6), H("The 8-Step Approach (Never Miss Anything!)", h1), B("Always read an ECG systematically. Never jump to conclusions. Follow these 8 steps every single time:"), SP(4), colored_table( [["Step", "What to Check", "How to do it", "Normal Value"], ["1", "Rate", "300 ÷ large boxes between R-R", "60–100 bpm"], ["2", "Rhythm", "Regular? P before every QRS?", "Regular sinus"], ["3", "Axis", "QRS in I & aVF — both positive?", "−30° to +90°"], ["4", "P wave", "Present, upright in II, uniform?", "< 0.12 s"], ["5", "PR interval", "Measure from P start to QRS start", "0.12–0.20 s"], ["6", "QRS complex", "Width, morphology, pathological Q?", "< 0.10 s"], ["7", "ST segment & T wave", "Elevation, depression, inversion?", "Isoelectric"], ["8", "QT interval", "QTc = QT ÷ √RR (Bazett formula)", "< 0.44 s"]], [30, 110, 200, 100] ), SP(8), H("STEP 1 — Heart Rate Calculation", h2), BulletBox([ "METHOD 1 (fast): 300 ÷ number of large squares between two R peaks", "METHOD 2 (accurate): 1500 ÷ number of small squares between R-R", "METHOD 3 (irregular rhythms): Count QRS in 6 sec strip × 10", "Bradycardia: HR < 60 bpm | Tachycardia: HR > 100 bpm", "Extreme brady < 40 bpm — think complete heart block, hypothermia", "Extreme tachy > 150 bpm — think SVT, VT, AF with rapid ventricular response", ], accent=C_ACCENT2), SP(6), H("STEP 3 — Cardiac Axis", h2), B("The axis tells us the overall direction of ventricular depolarisation."), colored_table( [["Axis", "Lead I", "Lead aVF", "Causes"], ["Normal (−30 to +90°)","Positive","Positive","Normal"], ["LAD (< −30°)", "Positive", "Negative", "LBBB, LAHB, inferior MI, LVH"], ["RAD (> +90°)", "Negative", "Positive", "RBBB, LPHB, RVH, PE, dextrocardia"], ["Extreme/NW axis","Negative", "Negative", "VT, severe RVH, pacing"]], [120, 70, 70, 200] ), SP(6), H("Quick Axis Mnemonic", h3), BulletBox([ "Both positive → NORMAL ✅", "Lead I positive + aVF negative → LEFT axis deviation (LAD) ⬅", "Lead I negative + aVF positive → RIGHT axis deviation (RAD) ➡", "Both negative → EXTREME axis (North-West) ⚠", ], accent=C_ACCENT6, bg=C_CARD2), PageBreak(), ] # ════════════════════════════════════════════════════════════════════════════ # PAGE 5 – RHYTHMS NORMAL + SINUS VARIATIONS # ════════════════════════════════════════════════════════════════════════════ story += [ SP(8), ColorBox("💓 CHAPTER 4 : SINUS RHYTHMS & BASIC ARRHYTHMIAS", bg=C_ACCENT6, fg=C_WHITE, fsize=15), SP(6), H("Normal Sinus Rhythm (NSR)", h2), RhythmStrip("normal", label="Normal Sinus Rhythm — Rate 60-100, Regular, P before every QRS"), SP(4), BulletBox([ "Rate: 60–100 bpm", "P wave: upright in II, inverted in aVR, before every QRS", "PR interval: 0.12–0.20 sec (constant)", "QRS: < 0.10 sec (narrow)", "Regular rhythm", ], accent=C_ACCENT3), SP(8), H("Sinus Bradycardia", h2), BulletBox([ "Rate < 60 bpm, otherwise normal morphology", "Causes: Athletes, vagal tone, hypothyroidism, hypothermia, beta-blockers, inferior MI", "Symptoms: Dizziness, syncope, fatigue", "Treatment: Asymptomatic → no treatment | Symptomatic → Atropine 0.5 mg IV, " "consider pacing if refractory", ], accent=C_CYAN), SP(6), H("Sinus Tachycardia", h2), BulletBox([ "Rate 100–150 bpm, normal P waves, regular", "Causes: Pain, fever, anaemia, PE, hypovolaemia, anxiety, thyrotoxicosis, heart failure", "ALWAYS treat the underlying cause — not the rate itself", "Treatment: Treat precipitant (fluids for shock, antipyretics for fever, etc.)", ], accent=C_ACCENT5), SP(6), H("Sinus Arrhythmia", h2), B("Rate varies with breathing — increases on inspiration, decreases on expiration. " "Normal in young patients and athletes. P wave morphology is normal. No treatment needed."), SP(6), H("Sinus Pause / Arrest", h2), BulletBox([ "Sudden absence of P waves — SA node fails to fire", "If pause > 3 sec → symptomatic, requires treatment", "Causes: Vagal stimulation, sick sinus syndrome, digoxin toxicity", "Treatment: Atropine, permanent pacemaker if recurrent", ], accent=C_ACCENT1), SP(6), H("Sick Sinus Syndrome (SSS)", h2), BulletBox([ "Also called Tachy-Brady syndrome", "Alternates between sinus tachycardia and profound bradycardia/arrest", "Causes: Fibrosis of SA node, ischaemia, cardiomyopathy", "Treatment: Permanent dual-chamber pacemaker (DDD) — DEFINITIVE treatment", ], accent=C_GOLD), PageBreak(), ] # ════════════════════════════════════════════════════════════════════════════ # PAGE 6 – ATRIAL ARRHYTHMIAS # ════════════════════════════════════════════════════════════════════════════ story += [ SP(8), ColorBox("🔴 CHAPTER 5 : ATRIAL ARRHYTHMIAS", bg=C_ACCENT1, fg=C_WHITE, fsize=15), SP(6), H("Premature Atrial Complex (PAC)", h2), BulletBox([ "Early P wave with different morphology (ectopic atrial focus)", "QRS usually narrow (< 0.10 sec), followed by incomplete compensatory pause", "Causes: Caffeine, alcohol, stress, electrolyte imbalance", "Treatment: Usually benign — reassure, avoid triggers", ], accent=C_ACCENT4), SP(6), H("Atrial Flutter", h2), BulletBox([ "Atrial rate 250–350 bpm, ventricular rate varies (2:1, 3:1, 4:1 block)", "CLASSIC: Sawtooth flutter waves (F waves) best seen in II, III, aVF", "Regular rhythm if fixed block (2:1 → HR ~150 bpm)", "Causes: Ischaemia, RHD, PE, post-cardiac surgery, thyrotoxicosis", "Treatment: Rate control (beta-blocker, CCB, digoxin) OR rhythm control " "(cardioversion, ablation). Anticoagulate if > 48 hrs", ], accent=C_ACCENT2), SP(6), H("Atrial Fibrillation (AF) — The MOST Common Arrhythmia", h2), RhythmStrip("afib", label="ATRIAL FIBRILLATION — Irregularly irregular, no P waves, chaotic baseline"), SP(4), BulletBox([ "No discernible P waves — replaced by irregular chaotic f waves", "Irregularly IRREGULAR ventricular rhythm (key diagnostic feature!)", "Atrial rate 350–600 bpm, ventricular rate variable", "Causes: HTN, IHD, mitral valve disease, thyrotoxicosis, alcohol (holiday heart), PE", "CHADSVASC score for stroke risk stratification", ], accent=C_ACCENT1), SP(4), H("AF Treatment", h2), colored_table( [["Goal", "Drug / Method", "Notes"], ["Rate Control", "Beta-blockers (metoprolol, bisoprolol)","Target HR < 110 bpm at rest"], ["Rate Control", "CCBs (diltiazem, verapamil)", "Avoid in HF with low EF"], ["Rate Control", "Digoxin", "Useful in HF, sedentary"], ["Rhythm Control", "Electrical cardioversion (DCCV)", "Synchronised 200J biphasic"], ["Rhythm Control", "Flecainide / Propafenone", "Pill-in-pocket (no struct. disease)"], ["Rhythm Control", "Amiodarone", "AF + heart failure or LVH"], ["Anticoagulation", "DOACs (Apixaban, Rivaroxaban)", "CHA2DS2-VASc ≥ 2 in men, ≥ 3 women"], ["Anticoagulation", "Warfarin (target INR 2–3)", "Valvular AF, CKD, mechanical valve"], ["Ablation", "Pulmonary vein isolation (PVI)", "Symptomatic paroxysmal AF"]], [100, 170, 170] ), SP(6), H("SVT — Supraventricular Tachycardia", h2), BulletBox([ "Narrow complex tachycardia, rate 150–250 bpm, regular", "Sudden onset & offset (paroxysmal)", "P waves hidden in or after QRS", "Types: AVNRT (most common), AVRT (WPW), Atrial Tachycardia", "TREATMENT: Vagal manoeuvres → Adenosine 6 mg IV (then 12 mg) → " "Verapamil/Beta-blocker → DCCV if haemodynamically unstable", ], accent=C_ACCENT6), PageBreak(), ] # ════════════════════════════════════════════════════════════════════════════ # PAGE 7 – VENTRICULAR ARRHYTHMIAS # ════════════════════════════════════════════════════════════════════════════ story += [ SP(8), ColorBox("⚠ CHAPTER 6 : VENTRICULAR ARRHYTHMIAS — CRITICAL!", bg=C_ACCENT1, fg=C_WHITE, fsize=15), SP(6), H("PVCs — Premature Ventricular Complexes", h2), BulletBox([ "Early, WIDE (>0.12 sec), bizarre QRS — no preceding P wave", "Full compensatory pause follows", "Uniform PVCs = same focus | Multiform = multiple foci (worse)", "Bigeminy: every other beat is PVC | Trigeminy: every 3rd beat", "Couplet: 2 PVCs in a row | Triplet: 3 = non-sustained VT", "Causes: IHD, hypokalaemia, hypoxia, caffeine, stimulants, cardiomyopathy", "Treatment: Benign in normal hearts. Treat if symptomatic: Beta-blockers. " "Ablation if very frequent (>10000/day).", ], accent=C_ACCENT5), SP(6), H("Ventricular Tachycardia (VT)", h2), RhythmStrip("vtach", label="VENTRICULAR TACHYCARDIA — Wide QRS, rate 120-250, may lose pulse"), SP(4), BulletBox([ "≥ 3 consecutive PVCs at rate > 100 bpm", "Wide QRS (>0.12 sec), bizarre morphology", "AV dissociation (P waves march independently) — pathognomonic!", "Capture beats + fusion beats confirm VT", "Monomorphic VT: uniform QRS — usually ischaemic scar", "Polymorphic VT: changing QRS — ischaemia, long QT, Brugada", "Sustained VT (> 30 sec) = EMERGENCY", ], accent=C_ACCENT1), SP(4), H("VT Treatment", h2), colored_table( [["Situation", "Treatment", "Notes"], ["Pulseless VT", "Immediate defibrillation 200J", "CPR between shocks"], ["VT with pulse (unstable)","Synchronised DCCV 100-200J", "Sedate first if possible"], ["VT with pulse (stable)","Amiodarone 300mg IV over 20-60min","Can also try Lidocaine"], ["Post-resuscitation", "IV amiodarone infusion", "1mg/min for 6hrs, then 0.5mg/min"], ["Recurrent VT", "ICD implantation", "Gold standard for secondary prevention"], ["Structural heart disease","Beta-blocker + ICD", "Reduce SCD risk"]], [150, 160, 150] ), SP(6), H("Ventricular Fibrillation (VF) — CARDIAC ARREST", h2), RhythmStrip("vfib", label="VENTRICULAR FIBRILLATION — Chaotic, NO recognisable QRS — DEFIB NOW!"), SP(4), BulletBox([ "CHAOTIC, irregular fibrillatory waves — NO organised QRS complexes", "No cardiac output — patient is pulseless and unconscious", "IMMEDIATELY life-threatening — death within minutes without treatment", "Causes: Acute MI, cardiomyopathy, hypokalaemia, hypothermia, electrocution", "TREATMENT: CPR + DEFIBRILLATION 200J (biphasic) ASAP — Every second counts!", "Adrenaline 1 mg IV every 3-5 mins during CPR", "Amiodarone 300 mg IV after 3rd shock", "Continue ALS algorithm until ROSC or decision to stop", ], accent=C_ACCENT1), SP(6), H("Torsades de Pointes (TdP)", h2), BulletBox([ "Polymorphic VT where QRS 'twists' around the baseline", "Associated with LONG QT interval (QTc > 500 ms = high risk)", "Causes: Hypokalaemia, hypomagnesaemia, drugs (amiodarone, erythromycin, " "antipsychotics, methadone, quinolones), congenital LQTS", "TREATMENT: IV Magnesium sulphate 2g bolus — FIRST LINE!", "Remove offending drug | Correct electrolytes | Overdrive pacing", "NOT amiodarone (it prolongs QT further!)", ], accent=C_GOLD), PageBreak(), ] # ════════════════════════════════════════════════════════════════════════════ # PAGE 8 – HEART BLOCKS # ════════════════════════════════════════════════════════════════════════════ story += [ SP(8), ColorBox("🧱 CHAPTER 7 : HEART BLOCKS (AV BLOCKS)", bg=C_ACCENT2, fg=C_BG, fsize=15), SP(6), H("1st Degree AV Block", h2), BulletBox([ "PR interval > 0.20 sec (> 1 large box) — FIXED and prolonged", "Every P wave followed by QRS — just delayed", "Causes: Vagal tone, inferior MI, myocarditis, digoxin, beta-blockers", "Treatment: Usually NONE required — benign. Monitor.", ], accent=C_ACCENT3), SP(6), H("2nd Degree AV Block — Type 1 (Wenckebach / Mobitz I)", h2), BulletBox([ "PR interval PROGRESSIVELY LENGTHENS until a P wave is not conducted (QRS drops)", "Grouped beating pattern — 'group with pause'", "Ratio: 3:2, 4:3, 5:4 (3 P waves → 2 QRS complexes, etc.)", "Level of block: AV node (proximal) — generally benign", "Causes: Inferior MI (RCA), vagal tone, myocarditis, drugs", "Treatment: Usually none. Atropine if symptomatic. Monitor.", ], accent=C_CYAN), SP(6), H("2nd Degree AV Block — Type 2 (Mobitz II)", h2), BulletBox([ "PR interval CONSTANT — then P wave suddenly drops (QRS missing) WITHOUT warning", "Wide QRS often (infranodal block)", "More dangerous than Wenckebach — can progress to complete block suddenly!", "Level of block: Bundle of His or bundle branches", "Causes: Anterior MI (LAD), fibrosis, cardiac surgery", "Treatment: URGENT pacing — temporary then permanent pacemaker!", ], accent=C_ACCENT5), SP(6), H("3rd Degree (Complete) Heart Block", h2), RhythmStrip("chb", label="COMPLETE HEART BLOCK — P waves and QRS completely dissociated"), SP(4), BulletBox([ "COMPLETE AV dissociation — P waves and QRS complexes beat INDEPENDENTLY", "Atrial rate (P waves): 60–100 bpm | Ventricular rate (QRS): 20–40 bpm", "QRS: Wide if escape from ventricle; narrow if junctional escape", "Patient may have syncope (Stokes-Adams attacks), haemodynamic collapse", "Causes: Inferior MI (usually transient), anterior MI (usually permanent), " "Lyme disease, sarcoidosis, drugs", "Treatment: PERMANENT PACEMAKER — absolutely indicated!", "Temporary: Atropine (limited benefit) or transcutaneous/transvenous pacing", ], accent=C_ACCENT1), SP(6), colored_table( [["Block Type", "PR interval", "Dropped QRS?", "QRS width", "Treatment"], ["1st degree", "Fixed, > 0.20s", "No", "Narrow", "Monitor"], ["2nd Mobitz I","Progressive ↑", "Yes (periodic)", "Narrow", "Monitor/Atropine"], ["2nd Mobitz II","Fixed", "Yes (sudden)", "Wide", "Urgent pacing!"], ["3rd (CHB)", "AV dissociation","All P blocked", "Wide/narrow", "Permanent PM"]], [100, 120, 100, 80, 110] ), PageBreak(), ] # ════════════════════════════════════════════════════════════════════════════ # PAGE 9 – BUNDLE BRANCH BLOCKS # ════════════════════════════════════════════════════════════════════════════ story += [ SP(8), ColorBox("🌿 CHAPTER 8 : BUNDLE BRANCH BLOCKS (BBB)", bg=C_ACCENT3, fg=C_BG, fsize=15), SP(6), H("Understanding the Conduction System", h2), B("The normal sequence: SA node → AV node → Bundle of His → Left & Right bundle branches → " "Purkinje fibres → Ventricular myocardium. If a bundle branch is blocked, the " "impulse takes a slower, abnormal route — producing WIDE QRS with characteristic patterns."), SP(6), H("Right Bundle Branch Block (RBBB)", h2), BulletBox([ "QRS duration > 0.12 sec (complete RBBB) or 0.10–0.12 sec (incomplete)", "CLASSIC: RSR' pattern ('M' pattern / Rabbit ears) in V1", "Wide, slurred S wave in I, V5, V6", "T wave inversion in V1-V3 (secondary changes — normal in BBB)", "ST depression V1-V3 (secondary — do NOT diagnose ischaemia here)", "Causes: Normal variant, RBBB can be normal! Also PE, RVH, ASD, ischaemia", "Mnemonic: 'WiLLiaM MaRRoW' — RBBB = MaRRoW (M in V1, W in V6)", ], accent=C_ACCENT4), SP(6), H("Left Bundle Branch Block (LBBB)", h2), BulletBox([ "QRS > 0.12 sec, broad QS or rS in V1 (W pattern)", "Broad monophasic R wave in I, aVL, V5, V6 (M pattern)", "WILLIAM MaRRoW: LBBB = WiLLiaM (W in V1, M in V6)", "DO NOT diagnose ST changes or ischaemia in LBBB — changes are EXPECTED", "NEW LBBB + chest pain = treat as STEMI (Sgarbossa criteria can help)", "Causes: ALWAYS pathological! IHD, HTN, cardiomyopathy, aortic stenosis", "Sgarbossa criteria: Concordant ST elevation ≥ 1mm in ≥ 1 lead = positive", ], accent=C_ACCENT1), SP(6), colored_table( [["Feature", "RBBB", "LBBB"], ["V1 pattern", "RSR' (Rabbit ears / M)", "QS or rS (W shape)"], ["V6 pattern", "Wide S wave (W shape)", "Tall broad R (M shape)"], ["QRS width", "> 0.12 sec", "> 0.12 sec"], ["Pathological?","Not always", "ALWAYS assume"], ["Secondary ST", "ST dep, T inv V1-V3", "ST/T opposite to QRS"], ["Mnemonic", "MaRRoW", "WiLLiaM"]], [110, 190, 170] ), SP(6), H("Fascicular Blocks (Hemiblocks)", h2), BulletBox([ "LAHB (Left Anterior Hemiblock): LAD (axis < −45°), small Q in I, small R in III, " "QRS < 0.12 sec", "LPHB (Left Posterior Hemiblock): RAD (axis > +120°), small R in I, small Q in III", "Bifascicular block: RBBB + LAHB (most common) or RBBB + LPHB", "Trifascicular block: Bifascicular + 1st degree block → high risk → consider PM", ], accent=C_ACCENT6), PageBreak(), ] # ════════════════════════════════════════════════════════════════════════════ # PAGE 10 – MI / STEMI / NSTEMI # ════════════════════════════════════════════════════════════════════════════ story += [ SP(8), ColorBox("❤ CHAPTER 9 : MYOCARDIAL INFARCTION — STEMI & NSTEMI", bg=C_ACCENT1, fg=C_WHITE, fsize=14), SP(6), H("ECG Evolution of STEMI — The Timeline", h2), colored_table( [["Time", "ECG Changes", "What is Happening"], ["Minutes", "Tall peaked (hyperacute) T waves", "Acute ischaemia — earliest sign!"], ["0–6 hrs", "ST elevation > 1mm (limb) / 2mm (V)","Full thickness ischaemia"], ["6–24 hrs", "Q waves develop, ST still elevated", "Necrosis beginning"], ["24–72 hrs", "T wave inversion, Q waves deepen", "Evolving infarction"], ["Days–weeks", "ST returns to baseline, Q persists", "T waves may normalise"], ["Months–years", "Persistent Q waves only", "Scar — permanent marker of old MI"]], [80, 200, 180] ), SP(6), H("STEMI — ST Elevation Patterns by Territory", h2), RhythmStrip("stemi", label="STEMI — Massive ST elevation with hyperacute T waves"), SP(4), colored_table( [["Territory", "ST elevation leads", "Culprit artery", "Reciprocal changes"], ["Inferior", "II, III, aVF ≥ 2mm", "RCA (80%)", "I, aVL"], ["Anterior", "V1–V4 ≥ 2mm", "LAD", "None (II,III,aVF mild)"], ["Lateral", "I, aVL, V5, V6", "LCx", "V1, V2"], ["Extensive Ant.", "V1–V6 + I + aVL", "Proximal LAD", "II, III, aVF"], ["Posterior", "ST dep V1-V3 + tall R V1","LCx or RCA", "V1-V3 (reciprocal = STE)"], ["RV infarction", "V4R elevation ≥ 1mm", "Proximal RCA", "Inferior STE"]], [100, 130, 100, 130] ), SP(6), H("STEMI vs NSTEMI vs Unstable Angina", h2), colored_table( [["Feature", "STEMI", "NSTEMI", "Unstable Angina"], ["ECG", "STE ≥ 1-2mm OR LBBB", "ST dep / T inv / normal","Normal or ST dep"], ["Troponin", "Elevated", "Elevated", "Normal"], ["Mechanism", "Total occlusion", "Partial occlusion", "Partial/spasm"], ["Treatment", "Primary PCI < 90 min","Heparin + PCI < 72h", "Medical + PCI if high risk"]], [100, 140, 140, 140] ), SP(6), H("STEMI Treatment — TIME IS MUSCLE!", h2), BulletBox([ "IMMEDIATE: Aspirin 300mg + Ticagrelor 180mg (or Prasugrel/Clopidogrel)", "Oxygen only if SpO2 < 94% (avoid hyperoxia in uncomplicated MI)", "Morphine 2-5mg IV for pain (cautious — may reduce platelet inhibitor absorption)", "IV Heparin / LMWH (anticoagulation)", "PRIMARY PCI: Target door-to-balloon < 90 minutes — GOLD STANDARD", "Thrombolysis if PCI not available within 120 min (e.g. Tenecteplase/Streptokinase)", "Beta-blocker (oral) within 24 hrs if no contraindication", "ACE inhibitor within 24 hrs (especially anterior MI, LV dysfunction)", "Statin (high-dose atorvastatin 80mg) — start immediately", "Secondary prevention: DAPT for 12 months, long-term aspirin + statin", ], accent=C_ACCENT1), PageBreak(), ] # ════════════════════════════════════════════════════════════════════════════ # PAGE 11 – WPW, LONG QT, BRUGADA, PERICARDITIS # ════════════════════════════════════════════════════════════════════════════ story += [ SP(8), ColorBox("🌟 CHAPTER 10 : SPECIAL SYNDROMES & PATTERNS", bg=C_ACCENT6, fg=C_WHITE, fsize=15), SP(6), H("Wolff-Parkinson-White Syndrome (WPW)", h2), BulletBox([ "Accessory pathway (Bundle of Kent) bypasses AV node", "Triad: Short PR (< 0.12 sec) + Delta wave + Wide QRS", "Delta wave = slurred upstroke at start of QRS ('pre-excitation')", "Risk of AF → rapid conduction → VF → sudden death!", "NEVER use digoxin, verapamil, beta-blockers in WPW with AF — fatal!", "Acute SVT: IV Adenosine (if narrow complex) or cardioversion", "Definitive: Radiofrequency ablation of accessory pathway", ], accent=C_ACCENT2), SP(6), H("Long QT Syndrome (LQTS)", h2), BulletBox([ "QTc > 440 ms (men), > 460 ms (women) — risk of TdP", "QTc > 500 ms = HIGH risk of sudden cardiac death", "Congenital: Romano-Ward, Jervell-Lange-Nielsen syndromes", "Acquired: Drugs (see TdP section), hypokalaemia, hypomagnesaemia, hypothyroidism", "Drug mnemonics — ABCDE: Antibiotics (quinolones, macrolides), " "antipsychotics (haloperidol), antiemetics (domperidone), " "antiarrhythmics (amiodarone, sotalol), antidepressants (TCAs)", "Treatment: Remove offending drug, IV Mg2+, correct electrolytes, " "beta-blockers, ICD for high-risk congenital", ], accent=C_GOLD), SP(6), H("Brugada Syndrome", h2), BulletBox([ "Characteristic Type 1: Coved ST elevation (saddle-back) in V1-V2 + RBBB pattern", "Type 2 & 3: Saddle-back ST elevation (less diagnostic, may unmask with sodium channel blocker)", "Risk: VF and sudden cardiac death — especially young Asian males, at night", "Gene: SCN5A mutation (sodium channel)", "ECG may be dynamic — fever/drugs can unmask it", "Treatment: ICD implantation if symptomatic. Quinidine can reduce VT burden.", "Avoid Class IC drugs (flecainide), tricyclics, avoid fever", ], accent=C_ACCENT4), SP(6), H("Pericarditis — Saddle-Shaped ST Elevation", h2), BulletBox([ "Diffuse ST elevation in MULTIPLE leads (not territorial) — saddle-shaped", "PR DEPRESSION — classic and almost pathognomonic!", "Affects most leads simultaneously (unlike MI which is territorial)", "No reciprocal changes (unlike MI)", "Stages: Stage 1: ST elevation + PR depression | Stage 2: Normalise | " "Stage 3: T inversion | Stage 4: Normal", "Treatment: NSAIDs (ibuprofen 600mg TDS or aspirin) + Colchicine 0.5mg BD x 3 months", "Avoid exercise during acute phase | Corticosteroids if refractory", ], accent=C_CYAN), SP(6), H("Pulmonary Embolism (PE) — ECG Clues", h2), BulletBox([ "CLASSIC (but NOT pathognomonic): S1Q3T3 pattern", " → Deep S in Lead I + Q wave in Lead III + T inversion in Lead III", "Sinus tachycardia — MOST common finding in PE!", "Right heart strain: RAD, RBBB (complete or incomplete), RV strain pattern", "T wave inversion V1–V4 (right ventricular strain)", "New AF or atrial flutter", "Remember: Normal ECG does NOT exclude PE", ], accent=C_ACCENT5), PageBreak(), ] # ════════════════════════════════════════════════════════════════════════════ # PAGE 12 – ELECTROLYTES & DRUG EFFECTS # ════════════════════════════════════════════════════════════════════════════ story += [ SP(8), ColorBox("🧪 CHAPTER 11 : ELECTROLYTES & DRUG EFFECTS ON ECG", bg=C_ACCENT3, fg=C_BG, fsize=14), SP(6), H("Hyperkalaemia — The Silent Killer", h2), colored_table( [["Serum K+ (mmol/L)","ECG Change", "What to do"], ["5.5–6.0", "Tall, peaked, symmetrical T waves","Monitor closely"], ["6.0–7.0", "PR prolongation, QRS widening", "Start treatment"], ["7.0–8.0", "Loss of P waves, sine wave", "Urgent treatment"], ["> 8.0", "VF, asystole", "EMERGENCY"]], [120, 200, 140] ), SP(4), H("Hyperkalaemia Treatment", h2), BulletBox([ "1. Calcium gluconate 10ml 10% IV — membrane stabilisation (IMMEDIATE, within 5 min)", "2. IV Insulin + Dextrose (10 units actrapid + 50ml 50% dextrose) — shifts K+ into cells", "3. Salbutamol nebuliser 10-20mg — shifts K+ into cells", "4. Sodium bicarbonate 50-100mEq IV (if acidotic)", "5. Calcium resonium (oral/rectal) — removes K+ from body", "6. Dialysis — definitive if refractory or renal failure", ], accent=C_ACCENT1), SP(6), H("Hypokalaemia", h2), BulletBox([ "Flat/inverted T waves + Prominent U waves (appears as prolonged QT)", "U wave height > T wave height = significant hypokalaemia", "Can trigger TdP and VT", "Treatment: Oral/IV KCl replacement. IV K+ max 20 mmol/hr with monitoring.", ], accent=C_ACCENT2), SP(6), H("Hypercalcaemia vs Hypocalcaemia", h2), colored_table( [["Electrolyte", "ECG Change", "Mnemonic"], ["Hypercalcaemia", "Short QT interval", "High Ca = Short QT"], ["Hypocalcaemia", "Long QT interval", "Low Ca = Long QT"], ["Hypermagnesaemia","Prolonged PR, AV block", "↑ Mg = blocks conduction"], ["Hypomagnesaemia","TdP, VT, prolonged QT", "↓ Mg = arrhythmias"]], [130, 200, 130] ), SP(6), H("Digoxin Effects on ECG", h2), BulletBox([ "Therapeutic: 'Reverse tick' / Salvador Dali moustache — down-sloping ST depression", "Bradycardia and PR prolongation (therapeutic)", "Toxicity: AV blocks (any degree), atrial tachycardia with block", "Bidirectional VT = highly suggestive of digoxin toxicity", "Treatment of toxicity: Digibind (Fab fragments) — specific antidote", ], accent=C_GOLD), SP(6), H("Other Drug Effects", h2), colored_table( [["Drug", "ECG Effect", "Concern"], ["Tricyclic antidepressants","Wide QRS, RAD, QTc", "VT, TdP — treat with Na bicarb"], ["Amiodarone", "Prolonged QT, bradycardia", "TdP risk (long term)"], ["Beta-blockers", "Bradycardia, PR prolongation", "AV block in overdose"], ["Cocaine", "ST elevation, VT, VF", "Coronary spasm, direct cardiotox"], ["Hypothermia", "J (Osborn) waves, bradycardia", "VF at < 28°C"]], [120, 170, 170] ), PageBreak(), ] # ════════════════════════════════════════════════════════════════════════════ # PAGE 13 – HYPERTROPHY PATTERNS # ════════════════════════════════════════════════════════════════════════════ story += [ SP(8), ColorBox("📐 CHAPTER 12 : CHAMBER ENLARGEMENT & HYPERTROPHY", bg=C_ACCENT4, fg=C_WHITE, fsize=14), SP(6), H("Left Ventricular Hypertrophy (LVH)", h2), BulletBox([ "Sokolov-Lyon Criteria: S wave V1 + R wave V5 or V6 ≥ 35mm", "Cornell Criteria: R in aVL + S in V3 > 28mm (men), > 20mm (women)", "Voltage changes + Strain pattern (ST depression + T inversion in lateral leads)", "LAD, broad notched P wave, prolonged QRS", "Causes: HTN (most common), HCM, aortic stenosis, MR", ], accent=C_ACCENT1), SP(6), H("Right Ventricular Hypertrophy (RVH)", h2), BulletBox([ "Dominant R wave in V1 (R > S in V1)", "R wave in V1 + S wave in V5 or V6 ≥ 11mm", "Right axis deviation (RAD)", "ST depression + T inversion in V1–V3 (strain pattern)", "Causes: Pulmonary hypertension, COPD, PE, mitral stenosis, ASD, PS", ], accent=C_ACCENT4), SP(6), H("Left Atrial Enlargement (LAE) — P Mitrale", h2), BulletBox([ "P wave duration > 0.12 sec in limb leads", "Bifid (notched) P wave in II — M-shaped 'P mitrale'", "Biphasic P wave in V1 with deep negative component (> 1mm deep, > 1mm wide)", "Causes: Mitral stenosis, LVF, HTN", ], accent=C_ACCENT3), SP(6), H("Right Atrial Enlargement (RAE) — P Pulmonale", h2), BulletBox([ "Tall, peaked P wave in II > 2.5mm", "Positive P wave in V1 > 1.5mm", "P wave duration normal (< 0.12 sec)", "Causes: COPD, pulmonary hypertension, tricuspid stenosis", ], accent=C_CYAN), SP(6), H("Dextrocardia", h2), BulletBox([ "ECG: Global negative deflections in lead I (inverted P, QRS, T)", "Reverse R wave progression (decreasing R V1–V6)", "Confirmed by clinical exam and CXR", "Technical dextrocardia: Lead reversal — R arm/L arm swap gives same picture in lead I", "Distinguish: If leads reversed, V leads progress normally; true dextrocardia — reversed", ], accent=C_ACCENT6), SP(8), ColorBox("📋 QUICK REFERENCE SUMMARY TABLE", bg=C_ACCENT5, fg=C_WHITE, fsize=13), SP(6), colored_table( [["Condition", "Key ECG Finding", "First-line Treatment"], ["NSR", "Regular, 60-100, P before QRS", "None"], ["AF", "Irregularly irregular, no P waves", "Rate control + anticoagulation"], ["Atrial Flutter", "Sawtooth F waves, 2:1 block", "Rate control / cardioversion"], ["SVT", "Narrow tachy 150-250, regular", "Adenosine 6mg IV"], ["VT", "Wide QRS tachy, AV dissociation", "Amiodarone / Defibrillation"], ["VF", "Chaotic, no QRS", "Immediate defibrillation 200J"], ["TdP", "Polymorphic VT + long QT", "IV Magnesium 2g"], ["1st° AV Block", "PR > 0.20 sec", "Monitor"], ["2nd° Mobitz II", "Dropped QRS suddenly", "Urgent pacing"], ["3rd° CHB", "AV dissociation", "Permanent pacemaker"], ["RBBB", "RSR' in V1, wide S in V6", "Treat underlying cause"], ["LBBB", "W in V1, M in V6", "Treat underlying (always pathological)"], ["STEMI", "STE ≥ 1-2mm, evolving Q waves", "Primary PCI < 90 min"], ["NSTEMI", "ST dep / T inv / normal, Trop +", "Heparin + PCI < 72h"], ["Pericarditis", "Diffuse STE, PR depression", "NSAIDs + Colchicine"], ["WPW", "Short PR, delta wave", "Ablation"], ["Hyperkalaemia", "Peaked T → sine wave", "Ca gluconate + insulin/dextrose"], ["PE", "S1Q3T3, sinus tachy, RBBB", "Anticoagulation / thrombolysis"], ["LVH", "Sokolov ≥ 35mm + strain", "Treat HTN"], ["Brugada", "Coved STE V1-V2", "ICD"]], [130, 190, 150] ), PageBreak(), ] # ════════════════════════════════════════════════════════════════════════════ # PAGE 14 – CLINICAL PEARLS & MNEMONICS # ════════════════════════════════════════════════════════════════════════════ story += [ SP(8), ColorBox("💡 CHAPTER 13 : CLINICAL PEARLS, MNEMONICS & TIPS", bg=C_GOLD, fg=C_BG, fsize=15), SP(6), H("Essential Mnemonics", h1), BulletBox([ "WiLLiaM MaRRoW: LBBB = W in V1, M in V6 | RBBB = M in V1, W in V6", "AIVR: Rate 60-100 + wide QRS + no P = Accelerated Idioventricular Rhythm", "STEMI territories: I See LAD → Anterior (LAD) | I, aVL = Lateral (LCx) | II,III,F = Inferior (RCA)", "P wave absent: AF, junctional, SA block, ventricular rhythm", "DEAD: Delta wave, Every P has QRS, Axis check, Duration of QRS", "5 H's + 5 T's for reversible cardiac arrest causes: Hypoxia, Hypovolaemia, " "Hypo/Hyperkalaemia, Hypothermia, H+ acidosis / Tamponade, Tension pneumothorax, " "Thrombosis (PE/MI), Toxins", ], accent=C_ACCENT6, bg=C_CARD2), SP(6), H("Common Exam & Clinical Traps", h2), BulletBox([ "TRAP: SVT rate ~150 → always rule out Atrial Flutter with 2:1 block first!", "TRAP: Wide complex tachycardia = VT until proven otherwise (never assume SVT with aberrancy)", "TRAP: New LBBB + chest pain = STEMI equivalent — activate cath lab!", "TRAP: Normal ECG does NOT exclude MI (sensitivity ~55% for NSTEMI)", "TRAP: Hyperkalaemia can cause tall T waves like hyperacute MI — check U&E!", "TRAP: ST depression in V1-V3 may be posterior STEMI — do right-sided and posterior leads!", "TRAP: Digoxin causes 'reverse tick' depression — not ischaemia in isolation", "TRAP: Right lead reversal mimics dextrocardia", ], accent=C_ACCENT1, bg=C_CARD1), SP(6), H("Rate vs Rhythm vs Morphology", h2), BulletBox([ "First ask: Is the patient STABLE or UNSTABLE? (BP, GCS, perfusion)", "Unstable tachycardia of ANY type → synchronised DCCV", "Pulseless rhythm → CPR + Defibrillation (shockable: VF/VT) or Adrenaline (non-shockable)", "Narrow QRS tachy → probably supraventricular", "Wide QRS tachy → VT until proven otherwise", "Irregular rhythm → AF, flutter with variable block, multifocal atrial tachycardia, or PVCs", ], accent=C_ACCENT3, bg=C_CARD1), SP(6), H("Normal Variants — Don't Over-Diagnose!", h2), BulletBox([ "Early repolarisation: ST elevation in V2-V4 in young athletes — concave, benign", "Juvenile T wave inversion: T inversion V1-V3 in children/young women — normal", "Incomplete RBBB: QRS 0.10-0.12, RSR' in V1 — can be normal", "1st degree AV block in athletes: vagal tone — benign", "Sinus arrhythmia: HR varies with breathing — young patients — normal", "Voltage criteria for LVH in thin patients: may be normal", ], accent=C_ACCENT3, bg=C_CARD2), SP(6), ColorBox("🏆 You've Mastered ECG! Keep Practising — Mihir is Going to Be a Legend! 🏆", bg=C_ACCENT1, fg=C_WHITE, fsize=12, radius=14), SP(4), Paragraph("Review a real ECG every day ◆ Practice pattern recognition ◆ Correlate with clinical findings ◆ When in doubt — call for help", S("final", fontSize=9, textColor=C_LTGRAY, alignment=TA_CENTER)), ] # ── Build PDF ──────────────────────────────────────────────────────────────── doc = SimpleDocTemplate( OUTPUT, pagesize=A4, leftMargin=40, rightMargin=40, topMargin=50, bottomMargin=50, title="ECG Master Guide — Mihir", author="Mihir", subject="Complete ECG Diagnosis & Treatment" ) doc.build(story, onFirstPage=on_page, onLaterPages=on_page) print(f"PDF created: {OUTPUT}") PYEOF echo "Script written OK"

Running Command

mkdir -p /tmp/workspace/ecg-pdf && ls /tmp/workspace/ecg-pdf/

This is a shared conversation. Sign in to Orris to start your own chat.