I want to prepare for neet ss for general medicine group how to use marrow and which standard textbook and what content to read make a 2 month timetable
NEET SS General Medicine group syllabus 2025 2026 preparation strategy
Marrow NEET SS preparation how to use platform strategy
https://www.doctutorials.com/neet-ss/neet-ss-syllabus
| Subject | Textbook | What to Read |
|---|---|---|
| General Medicine (Foundation) | Harrison's Principles of Internal Medicine (21st Ed) | Do NOT read cover to cover. Read only high-yield chapters - see topic list below |
| Cardiology | Braunwald's Heart Disease | ACS, HF, Valvular, Arrhythmia chapters; ACC/AHA guideline summaries |
| Nephrology | Brenner & Rector's The Kidney | CKD, Glomerulonephritis, AKI, Electrolytes |
| Neurology | Adams & Victor's Principles of Neurology | Stroke, Epilepsy, Dementia, Neuro-critical care |
| Endocrinology | Williams Textbook of Endocrinology | Diabetes, Thyroid, Adrenal, Pituitary |
| Gastroenterology | Sleisenger & Fordtran's GI Disease | IBD, Cirrhosis, GI bleed, Hepatitis |
| Haematology | Williams Hematology | Anaemias, MDS, Lymphoma, Leukemias, Clotting disorders |
| Rheumatology | Harrison's + Kelley & Firestein's Textbook of Rheumatology | SLE, RA, Vasculitis, Crystal arthropathy |
| Infectious Diseases | Harrison's (Infective chapters) + Mandell's Principles | Tropical infections, HIV, Sepsis, Antimicrobials |
Key rule: Do NOT read entire textbooks. Use Marrow to identify high-yield topics, then read only those chapters from the textbook.
| Day | Morning (3h) | Afternoon (2h) | Evening (2h) |
|---|---|---|---|
| Day 1 | Marrow: ACS lectures | Harrison's ACS chapter (key pages) | QBank: ACS (30 Qs) |
| Day 2 | Marrow: Heart Failure | Braunwald's HF chapter - GDMT | QBank: HF + review wrongs |
| Day 3 | Marrow: Valvular disease | Valvular disease notes + guidelines | QBank: Valvular (25 Qs) |
| Day 4 | Marrow: Arrhythmias | AF algorithm, channelopathies | QBank: Arrhythmias |
| Day 5 | Marrow: Cardiomyopathies + Pericardial | Harrison's chapters | QBank: Cardiomyopathy |
| Day 6 | Marrow: HTN + Dyslipidaemia | ACC/AHA guidelines summary | QBank: HTN + Lipids |
| Day 7 | Cardiology Full Subject Test (Marrow) | Review all wrong answers | Weak topic re-read |
| Day | Focus |
|---|---|
| Day 8-9 | AKI + CKD (Marrow lectures + Brenner's key chapters + 50 Qs) |
| Day 10 | Glomerulonephritis (KDIGO 2021 classification, treatment) |
| Day 11 | Electrolyte disorders - Na, K disorders completely |
| Day 12 | Ca, Mg, Phosphate disorders + RTA |
| Day 13 | Dialysis, Transplant basics + Marrow QBank Nephrology |
| Day 14 | Nephrology subject test + revision of wrongs |
| Day | Focus |
|---|---|
| Day 15-16 | Stroke (thrombolysis, thrombectomy, secondary prevention) + Adams' key chapters |
| Day 17 | Epilepsy - drug selection table, status epilepticus |
| Day 18 | CNS infections + Dementia syndromes |
| Day 19 | Movement disorders, Parkinson's, Huntington |
| Day 20 | GBS, MG, NMO, MS |
| Day 21 | Neurology subject test + revision |
| Day | Focus |
|---|---|
| Day 22-23 | Diabetes complete (ADA 2025 - drug algorithms, DKA, HHS) |
| Day 24 | Thyroid + Adrenal |
| Day 25 | Pituitary + MEN + Carcinoid |
| Day 26 | Endocrinology QBank (50 Qs) + subject test |
| Day 27-28 | Anaemias + MDS + Aplastic anaemia |
| Day 29-30 | Lymphoma + Leukaemia + Coagulation disorders |
| Day 31 | Haematology subject test + revision |
| Day | Focus |
|---|---|
| Day 32-33 | Hepatology: Cirrhosis complications, Viral hepatitis (full) |
| Day 34 | IBD + GI Bleed + Pancreatitis |
| Day 35 | NAFLD, Autoimmune liver, PBC/PSC + GI QBank |
| Day 36 | Infectious Diseases: HIV, TB, Malaria, Typhoid |
| Day 37 | ID: Sepsis, IE, Fungal, Antimicrobials |
| Day 38-39 | Rheumatology: SLE, RA, Vasculitis, Crystal arthropathies + QBank |
| Day | Focus |
|---|---|
| Day 40-41 | Rapid revision: Cardiology + Nephrology (use Marrow notes, not textbooks) |
| Day 42-43 | Rapid revision: Neurology + Endocrinology |
| Day 44 | Rapid revision: GI/Hepatology + ID |
| Day 45 | Rapid revision: Haematology + Rheumatology |
| Day 46-47 | Marrow Mock Test 1 (Full Length) - Analysis + Weak Area identification |
| Day | Focus |
|---|---|
| Day 48-50 | Weak subject deep dive (from mock analysis) |
| Day 51 | Recent advances: 2023-2025 landmark trials (EMPEROR, CREDENCE, DAPA, ANNEXA-4, etc.) |
| Day 52 | Recent guidelines update: ADA 2025, ACC/AHA, KDIGO, AASLD |
| Day 53-54 | Mock Test 2 + Analysis |
| Day | Focus |
|---|---|
| Day 55-56 | High-yield only revision - use Marrow's "Important" tags and flashcards |
| Day 57 | Mock Test 3 |
| Day 58 | Analysis + Cardiology + Nephrology rapid fire |
| Day 59 | Neurology + Endocrinology rapid fire |
| Day 60-61 | GI + ID + Haem + Rheum rapid fire |
| Day 62 | Mock Test 4 + Final review of wrong answers |
| Day 63 | Rest. Revise only self-made short notes. |
6:00 - 7:00 AM → Previous day's QBank wrong answer review
7:00 - 9:00 AM → Marrow video lectures (new topic)
9:00 - 10:00 AM → Textbook chapter (selective - 15-20 pages max)
10:00 - 12:00 PM → Marrow QBank (30-40 Qs, topic-wise)
12:00 - 1:00 PM → Break + food
1:00 - 3:00 PM → Second topic lectures OR revision
3:00 - 4:00 PM → QBank for second topic
4:00 - 5:00 PM → Notes compilation (short, point-based)
5:00 - 6:00 PM → Break / exercise
6:00 - 8:00 PM → Weak area OR guidelines/recent advances reading
Generate a quick reference PDF for high-yield topics by subject (cards format)
ls -la /home/daytona/workspace/ 2>/dev/null && mkdir -p /home/daytona/workspace/neet-ss-guide
~/neet-ss-guide/generate_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether, PageBreak
)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_CENTER
from reportlab.platypus import Frame, PageTemplate
from reportlab.pdfgen import canvas as pdfcanvas
OUTPUT = "/home/daytona/workspace/neet-ss-guide/NEET_SS_Medicine_Quick_Reference.pdf"
# ── Color Palette ──────────────────────────────────────────────────────────────
C_HEADER = colors.HexColor("#1A3C5E") # deep navy
C_SUBHDR = colors.HexColor("#2E6DA4") # medium blue
C_ACCENT = colors.HexColor("#E8F4FD") # light blue fill
C_WARN = colors.HexColor("#FFF3CD") # amber fill
C_RED_DARK = colors.HexColor("#C0392B") # alert red
C_GREEN = colors.HexColor("#1A6B3C") # dark green
C_GRAY_LT = colors.HexColor("#F5F5F5")
C_BORDER = colors.HexColor("#B0C4DE")
C_TEXT = colors.HexColor("#1A1A1A")
C_MUTED = colors.HexColor("#555555")
C_TAG_BG = colors.HexColor("#D6EAF8")
# ── Styles ─────────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
def S(name, **kw):
return ParagraphStyle(name, **kw)
TITLE_STYLE = S("DocTitle",
fontSize=26, textColor=colors.white, alignment=TA_CENTER,
fontName="Helvetica-Bold", leading=32, spaceAfter=4)
SUBTITLE_STYLE = S("DocSub",
fontSize=12, textColor=colors.HexColor("#AEDAF0"), alignment=TA_CENTER,
fontName="Helvetica", leading=16)
SEC_TITLE = S("SecTitle",
fontSize=15, textColor=colors.white, fontName="Helvetica-Bold",
leading=20, alignment=TA_LEFT, spaceAfter=0, spaceBefore=0)
CARD_HEADING = S("CardHead",
fontSize=11, textColor=C_HEADER, fontName="Helvetica-Bold",
leading=15, spaceAfter=3)
CARD_BODY = S("CardBody",
fontSize=8.5, textColor=C_TEXT, fontName="Helvetica",
leading=13, spaceAfter=2)
CARD_BULLET = S("CardBullet",
fontSize=8.5, textColor=C_TEXT, fontName="Helvetica",
leading=12, leftIndent=10, spaceAfter=1)
CARD_KEY = S("CardKey",
fontSize=8, textColor=C_GREEN, fontName="Helvetica-Bold",
leading=11, leftIndent=10)
CARD_ALERT = S("CardAlert",
fontSize=8, textColor=C_RED_DARK, fontName="Helvetica-Bold",
leading=11, leftIndent=10)
LABEL_STYLE = S("Label",
fontSize=7, textColor=colors.white, fontName="Helvetica-Bold",
leading=9, alignment=TA_CENTER)
PAGE_W, PAGE_H = A4
MARGIN = 14 * mm
# ── Helper: section header banner ─────────────────────────────────────────────
def section_banner(title, emoji_color):
data = [[Paragraph(f" {title}", SEC_TITLE)]]
t = Table(data, colWidths=[PAGE_W - 2*MARGIN])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), emoji_color),
("ROWBACKGROUNDS", (0,0), (-1,-1), [emoji_color]),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING",(0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 10),
("ROUNDEDCORNERS", [4]),
]))
return t
# ── Helper: card ──────────────────────────────────────────────────────────────
def card(title, items, bg=C_ACCENT, width=None):
"""items = list of (type, text) where type in: 'bullet','key','alert','body'"""
if width is None:
width = PAGE_W - 2*MARGIN
rows = [[Paragraph(title, CARD_HEADING)]]
for typ, txt in items:
if typ == "bullet":
rows.append([Paragraph(f"• {txt}", CARD_BULLET)])
elif typ == "key":
rows.append([Paragraph(f"★ {txt}", CARD_KEY)])
elif typ == "alert":
rows.append([Paragraph(f"! {txt}", CARD_ALERT)])
else:
rows.append([Paragraph(txt, CARD_BODY)])
t = Table(rows, colWidths=[width])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("BACKGROUND", (0,0), (-1,0), C_TAG_BG),
("BOX", (0,0), (-1,-1), 0.5, C_BORDER),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("ROUNDEDCORNERS", [4]),
]))
return t
# ── Helper: two-column layout ─────────────────────────────────────────────────
def two_col(left_items, right_items, spacer=4*mm):
col_w = (PAGE_W - 2*MARGIN - spacer) / 2
left_col = [card(t, i, width=col_w) for (t,i) in left_items]
right_col = [card(t, i, width=col_w) for (t,i) in right_items]
# interleave with small spacers
def col_flowables(cards):
out = []
for c in cards:
out.append(c)
out.append(Spacer(1, 3*mm))
return out
lf = col_flowables(left_col)
rf = col_flowables(right_col)
data = [[lf, rf]]
t = Table(data, colWidths=[col_w, col_w])
t.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "TOP"),
("LEFTPADDING", (0,0), (-1,-1), 0),
("RIGHTPADDING", (0,0), (-1,-1), 0),
("TOPPADDING", (0,0), (-1,-1), 0),
("BOTTOMPADDING",(0,0), (-1,-1), 0),
("COLPADDING", (0,0), (-1,-1), spacer/2),
]))
return t
# ── Cover page canvas callback ─────────────────────────────────────────────────
def cover_bg(canvas, doc):
canvas.saveState()
# gradient-ish background using two rects
canvas.setFillColor(C_HEADER)
canvas.rect(0, 0, PAGE_W, PAGE_H, fill=1, stroke=0)
canvas.setFillColor(C_SUBHDR)
canvas.rect(0, PAGE_H*0.35, PAGE_W, PAGE_H*0.65, fill=1, stroke=0)
# accent bar
canvas.setFillColor(colors.HexColor("#F39C12"))
canvas.rect(0, PAGE_H*0.35 - 4, PAGE_W, 8, fill=1, stroke=0)
canvas.restoreState()
def normal_page(canvas, doc):
canvas.saveState()
# Header strip
canvas.setFillColor(C_HEADER)
canvas.rect(0, PAGE_H - 10*mm, PAGE_W, 10*mm, fill=1, stroke=0)
canvas.setFont("Helvetica-Bold", 7)
canvas.setFillColor(colors.white)
canvas.drawString(MARGIN, PAGE_H - 6*mm, "NEET SS | General Medicine Group | Quick Reference Cards")
# Footer
canvas.setFillColor(C_HEADER)
canvas.rect(0, 0, PAGE_W, 8*mm, fill=1, stroke=0)
canvas.setFont("Helvetica", 7)
canvas.setFillColor(colors.white)
canvas.drawString(MARGIN, 3*mm, "For exam preparation use only | Always verify with latest guidelines")
canvas.drawRightString(PAGE_W - MARGIN, 3*mm, f"Page {doc.page}")
canvas.restoreState()
# ═══════════════════════════════════════════════════════════════════════════════
# CONTENT DATA
# ═══════════════════════════════════════════════════════════════════════════════
def build_story():
story = []
sp = lambda h=4: Spacer(1, h*mm)
# ── COVER ──────────────────────────────────────────────────────────────────
story.append(sp(55))
story.append(Paragraph("NEET SS", TITLE_STYLE))
story.append(Paragraph("General Medicine Group", TITLE_STYLE))
story.append(sp(3))
story.append(Paragraph("High-Yield Quick Reference Cards", SUBTITLE_STYLE))
story.append(sp(2))
story.append(Paragraph("Cardiology • Nephrology • Neurology • Endocrinology", SUBTITLE_STYLE))
story.append(Paragraph("Gastroenterology • Haematology • Infectious Diseases • Rheumatology", SUBTITLE_STYLE))
story.append(sp(8))
# cover info box
cover_data = [
[Paragraph("How to Use This Document", S("ch", fontSize=10, textColor=C_HEADER, fontName="Helvetica-Bold", leading=14))],
[Paragraph("★ Each card = one high-yield topic. Review card AFTER watching Marrow lecture.", CARD_BULLET)],
[Paragraph("★ Highlighted items (★) = exam favorites / guideline numbers.", CARD_BULLET)],
[Paragraph("! Alert items (!) = common traps and negative markers.", CARD_BULLET)],
[Paragraph("★ Use as a last-week rapid revision tool - not a replacement for full study.", CARD_BULLET)],
]
ct = Table(cover_data, colWidths=[140*mm])
ct.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), colors.HexColor("#EBF5FB")),
("BACKGROUND", (0,0), (-1,0), colors.HexColor("#D6EAF8")),
("BOX", (0,0), (-1,-1), 1, C_BORDER),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
story.append(ct)
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════
# 1. CARDIOLOGY
# ══════════════════════════════════════════════════════════════════════════
story.append(section_banner("CARDIOLOGY (~20% of paper)", colors.HexColor("#1A3C5E")))
story.append(sp(3))
left = [
("ACS - STEMI Management", [
("key", "Reperfusion: PCI within 90 min (door-to-balloon) if PCI-capable hospital"),
("key", "Fibrinolysis if PCI delay >120 min; within 12h of onset"),
("bullet", "Antiplatelet: Aspirin 325 mg STAT + Ticagrelor 180 mg (preferred) or Clopidogrel"),
("bullet", "Anticoagulation: UFH / Enoxaparin / Fondaparinux (avoid fondaparinux with PCI)"),
("bullet", "STEMI equivalent: New LBBB, Posterior MI (ST depression V1-V3)"),
("alert", "! Do NOT delay PCI for ECHO, troponins, or loading dose if already on antiplatelet"),
("key", "Door-to-needle (fibrinolysis): within 30 min"),
]),
("Heart Failure - GDMT (HFrEF)", [
("key", "4 pillars: ACEi/ARB/ARNI + BB + MRA + SGLT2i"),
("key", "ARNI (Sacubitril/Valsartan): superior to ACEi (PARADIGM-HF)"),
("key", "SGLT2i: Dapagliflozin (DAPA-HF) + Empagliflozin (EMPEROR) - reduce HF hospitalization"),
("bullet", "BB: Carvedilol / Bisoprolol / Metoprolol succinate ONLY"),
("bullet", "MRA: Spironolactone (EF <35%, NYHA II-IV, eGFR >30, K <5.0)"),
("bullet", "ICD: EF <35% on GDMT for >3 months, NYHA II-III"),
("alert", "! HFpEF: SGLT2i shown benefit; ACEi/BB NOT proven to reduce mortality"),
]),
]
right = [
("ACS - NSTEMI/UA Management", [
("key", "Risk stratify: TIMI score, GRACE score"),
("key", "Early invasive (<24h): High risk (dynamic ST change, elevated troponin, GRACE >140)"),
("bullet", "Anticoagulation: Fondaparinux preferred (unless PCI planned, then UFH/bivalirudin)"),
("bullet", "Antiplatelet: Aspirin + Ticagrelor (preferred over Clopidogrel - PLATO trial)"),
("bullet", "Avoid GP IIb/IIIa routinely; use only as bailout during PCI"),
("alert", "! Morphine in ACS may decrease P2Y12 absorption - use cautiously"),
]),
("Atrial Fibrillation", [
("key", "Rate control target: <110 bpm (RACE II) in stable AF"),
("key", "Rhythm control: preferred in younger, symptomatic, AF <1yr (EAST-AFNET 4)"),
("bullet", "Rate control drugs: BB > CCB (diltiazem/verapamil) > Digoxin"),
("bullet", "Anticoagulation: CHA2DS2-VASc >=2 (men) / >=3 (women) -> OAC"),
("key", "DOACs preferred over warfarin (AF + non-valvular)"),
("bullet", "Valvular AF (rheumatic MS, mechanical valve): Warfarin only"),
("alert", "! CHADS2VASc 0 (men): no anticoagulation needed"),
]),
]
story.append(two_col(left, right))
story.append(sp(3))
left2 = [
("Valvular Heart Disease - Intervention Criteria", [
("key", "Severe AS: AVA <1 cm2, mean gradient >40 mmHg, Vmax >4 m/s"),
("key", "Indications for AVR: Symptomatic severe AS (angina/syncope/dyspnea) OR EF <50%"),
("key", "TAVI vs SAVR: TAVI preferred in high/intermediate/low surgical risk (PARTNER 3)"),
("bullet", "Severe MR: Surgery when EF <60% OR LVESD >40 mm"),
("bullet", "Severe MS: MVA <1.5 cm2; PBMC if anatomy favorable (Wilkins score <=8)"),
("bullet", "AR: Surgery when EF <50% or LVESD >50 mm"),
("alert", "! Penicillin prophylaxis for RHD: 10 yrs or until age 40 (severe MR: lifelong)"),
]),
("Hypertension - Key Numbers", [
("key", "Target BP <130/80 mmHg in most patients (ACC/AHA 2017)"),
("key", "CKD + Albuminuria: ACEi or ARB first-line"),
("bullet", "Diabetes: <130/80 mmHg; ACEi/ARB preferred"),
("bullet", "HF: ACEi/ARB + BB; target <130/80"),
("bullet", "Resistant HTN: Add MRA (spironolactone) as 4th agent"),
("key", "Hypertensive crisis: IV labetalol / nicardipine / clevidipine"),
("alert", "! Lower BP by max 25% in first hour in hypertensive emergency"),
]),
]
right2 = [
("Cardiomyopathies - Key Points", [
("key", "HCM: Asymmetric septal hypertrophy; SAM of MV; dynamic LVOT obstruction"),
("key", "HCM management: BB / Verapamil; Mavacamten (new - myosin inhibitor)"),
("bullet", "ICD in HCM: Septal thickness >=30mm, family h/o SCD, NSVT, EF <50%, unexplained syncope"),
("bullet", "Dilated CM: GDMT same as HFrEF; rule out reversible causes (alcohol, thyroid)"),
("bullet", "ARVC: Epsilon wave, T-wave inversion V1-V3; risk of SCD in athletes"),
("alert", "! HCM + AF: Anticoagulate regardless of CHA2DS2-VASc score"),
]),
("Landmark Trials - Cardiology", [
("key", "PARADIGM-HF: Sacubitril/Valsartan vs Enalapril - 20% RRR in CV death/HF hosp"),
("key", "DAPA-HF: Dapagliflozin - 26% RRR HF events (includes non-diabetics)"),
("key", "EMPEROR-Reduced: Empagliflozin - similar benefit in HFrEF"),
("key", "PLATO: Ticagrelor > Clopidogrel in ACS (all subtypes)"),
("key", "PARTNER 3: TAVI non-inferior to SAVR at low surgical risk at 2 years"),
("key", "EAST-AFNET 4: Early rhythm control reduces CV outcomes vs rate control"),
("key", "RACE II: Lenient rate control (<110) non-inferior to strict (<80) in AF"),
]),
]
story.append(two_col(left2, right2))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════
# 2. NEPHROLOGY
# ══════════════════════════════════════════════════════════════════════════
story.append(section_banner("NEPHROLOGY (~15% of paper)", colors.HexColor("#1A5276")))
story.append(sp(3))
left = [
("CKD - Staging & Management", [
("key", "KDIGO staging: G1-G5 (GFR) + A1-A3 (albuminuria) -> risk matrix"),
("key", "Slow progression: ACEi/ARB (especially if proteinuria >0.3g/day)"),
("key", "SGLT2i (Dapagliflozin - DAPA-CKD; Canagliflozin - CREDENCE) - all CKD with albuminuria"),
("key", "Target BP <130/80; target HbA1c <7% in diabetic CKD"),
("bullet", "Anaemia in CKD: ESA if Hb <10; iron before ESA if ferritin <500"),
("bullet", "CKD-MBD: Phosphate restriction, active Vit D; avoid Ca-based binders if high Ca"),
("alert", "! Finerenone (MRA) - FIDELIO-DKD trial: reduces CKD progression in DKD"),
]),
("Glomerulonephritis - KDIGO 2021", [
("key", "IgA Nephropathy: Proteinuria >1g/day - ACEi/ARB; >2g/day consider steroids (TESTING trial)"),
("key", "MN (Membranous): Anti-PLA2R antibody (70%); Cyclophosphamide+Steroids or Rituximab"),
("bullet", "Minimal Change Disease: Steroids 1mg/kg; Cyclophosphamide for frequent relapse"),
("bullet", "FSGS: High-dose steroids; Cyclosporine/Tacrolimus if steroid-resistant"),
("bullet", "Lupus Nephritis Class III/IV: MMF or Cyclophosphamide + Steroids"),
("key", "LN Class V (membranous): MMF + steroids; Belimumab/Voclosporin as add-on"),
("alert", "! RPGN: Pauci-immune (ANCA) - IV methylprednisolone + Cyclophosphamide/Rituximab"),
]),
]
right = [
("AKI - KDIGO Criteria & Management", [
("key", "AKI Stage 1: Cr +0.3 mg/dL in 48h OR x1.5 baseline; UO <0.5 mL/kg/h for 6h"),
("key", "AKI Stage 3 OR oliguria/anuria: consider RRT"),
("bullet", "RRT Indications: AEIOU - Acidosis (pH<7.1), Electrolytes (K>6.5), Intoxication, Overload, Uraemia"),
("bullet", "Contrast nephropathy prevention: IV NS pre/post; N-acetylcysteine (debated)"),
("bullet", "Hepatorenal Syndrome: Terlipressin + Albumin (Type 1 HRS - acute)"),
("alert", "! Do NOT use NSAID, aminoglycosides, contrast in CKD eGFR <30"),
]),
("Electrolyte Disorders", [
("key", "Hyponatremia: SIADH - fluid restriction; severe symptomatic - 3% NaCl (1-2 ml/kg/h)"),
("key", "Correct Na no faster than 8-10 mEq/L per 24h (risk: osmotic demyelination)"),
("bullet", "SIADH diagnosis: serum Na <135, serum Osm <275, urine Osm >100, urine Na >40"),
("key", "Hyperkalemia >6.5 or ECG changes: IV Calcium gluconate FIRST (cardiac protection)"),
("bullet", "Then: Insulin+Glucose, Salbutamol, Bicarb, dialysis"),
("bullet", "Hypercalcemia: IV saline + Furosemide; Bisphosphonates (Zoledronic acid) for malignancy"),
("alert", "! Hypokalaemia + Hypomagnesaemia: Replace Mg first (K replacement will fail)"),
]),
]
story.append(two_col(left, right))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════
# 3. NEUROLOGY
# ══════════════════════════════════════════════════════════════════════════
story.append(section_banner("NEUROLOGY (~15% of paper)", colors.HexColor("#1B4F72")))
story.append(sp(3))
left = [
("Acute Ischemic Stroke", [
("key", "IV Alteplase (tPA): within 4.5 hours of onset; dose 0.9 mg/kg (max 90mg)"),
("key", "Thrombectomy: within 24h if large vessel occlusion + salvageable penumbra (DAWN/DEFUSE-3)"),
("bullet", "BP target before tPA: <185/110 mmHg"),
("bullet", "BP after tPA: maintain <180/105 for 24h"),
("bullet", "Antiplatelet: Aspirin 325 mg within 24-48h (not within 24h of tPA)"),
("key", "Dual antiplatelet (Aspirin + Clopidogrel): minor stroke/TIA for 21 days (POINT/CHANCE)"),
("alert", "! tPA contraindications: Recent surgery <14d, BP >185/110 uncontrolled, INR >1.7, platelets <100k"),
]),
("Epilepsy - Drug Selection", [
("key", "Focal seizures: Carbamazepine / Levetiracetam / Lamotrigine"),
("key", "Generalised (absence): Ethosuximide (first-line), Valproate, Lamotrigine"),
("key", "Generalised tonic-clonic: Valproate (most effective), Levetiracetam, Lamotrigine"),
("alert", "! Valproate: AVOID in women of childbearing age (teratogenic - neural tube defects)"),
("bullet", "Status Epilepticus: Lorazepam -> Phenytoin/Levetiracetam -> Phenobarb -> Propofol/Midazolam"),
("bullet", "Refractory SE: Ketamine, Isoflurane (4th line)"),
("key", "Drug-induced seizures: Isoniazid -> give Pyridoxine (B6)"),
]),
]
right = [
("Meningitis - Empirical Treatment", [
("key", "Bacterial meningitis: Ceftriaxone 2g IV q12h + Vancomycin + Dexamethasone"),
("key", "Dexamethasone: 0.15 mg/kg q6h x4 days - start BEFORE or with first antibiotic dose"),
("bullet", "Add Ampicillin if age >50, immunocompromised (Listeria coverage)"),
("bullet", "HSV encephalitis: IV Acyclovir 10 mg/kg q8h x14-21 days"),
("bullet", "Cryptococcal meningitis (HIV): Amphotericin B + Flucytosine induction, then Fluconazole"),
("alert", "! LP contraindicated if papilledema, focal neuro signs - do CT first"),
("key", "CSF in bacterial: high protein (>45), low glucose (<45, CSF:serum <0.4), neutrophils"),
]),
("Neurodegenerative Diseases", [
("key", "Parkinson's: Dopaminergic deficit substantia nigra; Lewy bodies (alpha-synuclein)"),
("key", "Parkinson's treatment: Levodopa+Carbidopa (most effective); MAO-B inhibitors (early/mild)"),
("bullet", "Motor complications (on-off): Add COMT inhibitor (Entacapone) or dopamine agonist"),
("bullet", "Dementia with Lewy Bodies: Parkinsonism + Dementia + Visual hallucinations + REM sleep disorder"),
("alert", "! DLB: Antipsychotics CONTRAINDICATED (neuroleptic hypersensitivity - fatal)"),
("bullet", "Alzheimer's: AChE inhibitors (Donepezil, Rivastigmine) + Memantine (moderate-severe)"),
("key", "FTD: Behavioral variant - frontal/temporal atrophy; No proven disease-modifying therapy"),
]),
]
story.append(two_col(left, right))
story.append(sp(3))
left2 = [
("GBS, MG, NMO - Highlights", [
("key", "GBS: Ascending paralysis post-infection (Campylobacter most common); Albumin-cytologic dissociation"),
("key", "GBS treatment: IVIG or Plasmapheresis (equal efficacy); NOT steroids"),
("bullet", "MG: Fatigable weakness, ptosis, diplopia; AChR Ab (85%), anti-MuSK (10%)"),
("bullet", "MG crisis treatment: Plasmapheresis / IVIG + Neostigmine; ventilatory support"),
("key", "NMO (Devic): Anti-AQP4 antibody; optic neuritis + transverse myelitis; area postrema lesions"),
("bullet", "NMO prevention: Rituximab / Eculizumab / Inebilizumab"),
("alert", "! NMO vs MS: NMO - long spinal cord lesion (>3 segments), responds poorly to MS drugs"),
]),
]
right2 = [
("Stroke - Secondary Prevention", [
("key", "Cardioembolic (AF): Anticoagulation (DOAC) - start 2-14 days after stroke"),
("key", "Atherosclerotic stroke: Antiplatelet; Statin (LDL <70 mg/dL); BP control"),
("bullet", "PFO closure: Consider if cryptogenic stroke age <60 (CLOSE, REDUCE, RESPECT trials)"),
("bullet", "Carotid stenosis: CEA if 70-99% symptomatic; beneficial if >50% with high surgical risk"),
("bullet", "ICH management: BP target SBP <140 mmHg within 1h (INTERACT 2)"),
("alert", "! Anticoagulation reversal in ICH: Idarucizumab for Dabigatran; Andexanet for Factor Xa inhibitors"),
]),
]
story.append(two_col(left2, right2))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════
# 4. ENDOCRINOLOGY
# ══════════════════════════════════════════════════════════════════════════
story.append(section_banner("ENDOCRINOLOGY (~12% of paper)", colors.HexColor("#1A5276")))
story.append(sp(3))
left = [
("Diabetes - ADA 2025 Highlights", [
("key", "HbA1c targets: <7% general; <8% elderly/frail/limited life expectancy"),
("key", "1st line: Metformin STILL preferred; but consider SGLT2i/GLP1-RA if ASCVD/HF/CKD"),
("key", "SGLT2i: preferred if CKD (eGFR>20), HFrEF, established ASCVD"),
("key", "GLP-1 RA: preferred if weight loss needed, ASCVD, MAFLD"),
("bullet", "DKA: pH<7.3, HCO3<15, glucose>250, ketonemia"),
("bullet", "DKA insulin: Start only after K >=3.5 mEq/L"),
("alert", "! SGLT2i: pause 3-5 days before surgery (risk euglycemic DKA)"),
("key", "HHS: glucose >600, Osm >320, minimal ketones, no acidosis; slower correction"),
]),
("Thyroid Disorders", [
("key", "Graves' disease: TSH low, T3/T4 high, TSH-R Ab positive, diffuse goiter, eye signs"),
("key", "Definitive treatment: Radioiodine (most common in USA) or Surgery"),
("bullet", "Antithyroid drugs: Carbimazole / PTU; PTU preferred in pregnancy 1st trimester"),
("bullet", "Thyroid storm: Propylthiouracil + SSKI + Propranolol + Steroids + Supportive"),
("key", "Hypothyroidism in pregnancy: Target TSH <2.5 mIU/L (1st trimester); increase LT4 dose by 30% on conception"),
("bullet", "Sick euthyroid syndrome: Low T3 (most sensitive), normal/low T4, normal TSH - do NOT treat"),
("alert", "! Amiodarone: Causes both hypo and hyperthyroidism; contains 37% iodine"),
]),
]
right = [
("Adrenal Disorders", [
("key", "Cushing's workup: 24h UFC -> low-dose DST -> if +ve, high-dose DST/ACTH levels"),
("key", "ACTH-dependent Cushing's: pituitary (Cushing's disease) vs ectopic ACTH (small cell lung)"),
("bullet", "Addison's disease: Primary adrenal insufficiency; raised ACTH, low cortisol, hyperkalemia, hyponatremia"),
("key", "Addisonian crisis: IV Hydrocortisone 100mg q8h + IV saline; do NOT wait for test results"),
("key", "Conn's syndrome (Primary Hyperaldosteronism): HTN + hypokalemia + metabolic alkalosis; Aldosterone:Renin ratio >30"),
("bullet", "Phaeochromocytoma workup: 24h urine metanephrines (best); Alpha-block FIRST before surgery"),
("alert", "! Phaeo surgery: Alpha-blockade (phenoxybenzamine) BEFORE beta-blockade (never BB first)"),
]),
("Pituitary & SIADH vs DI", [
("key", "SIADH: Serum Na <135, Serum Osm <275, Urine Osm >100, Urine Na >40, euvolemic"),
("key", "SIADH causes: CNS disease, pulmonary (SCLC), drugs (SSRIs, Carbamazepine, Cyclophosphamide)"),
("bullet", "Central DI: Low ADH; responds to Desmopressin; Urine Osm rises after DDAVP"),
("bullet", "Nephrogenic DI: ADH normal/high; no response to DDAVP; treat with thiazides, NSAIDs"),
("key", "Water deprivation test distinguishes DI from psychogenic polydipsia"),
("bullet", "MEN 1: Pituitary + Parathyroid + Pancreas (3 P's)"),
("bullet", "MEN 2A: Phaeo + Medullary thyroid Ca + Hyperparathyroidism; RET mutation"),
("alert", "! MEN 2B: Phaeo + Medullary thyroid Ca + Marfanoid + Mucosal neuromas; most aggressive"),
]),
]
story.append(two_col(left, right))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════
# 5. GASTROENTEROLOGY & HEPATOLOGY
# ══════════════════════════════════════════════════════════════════════════
story.append(section_banner("GASTROENTEROLOGY & HEPATOLOGY (~12% of paper)", colors.HexColor("#0E6655")))
story.append(sp(3))
left = [
("Cirrhosis - Complication Management", [
("key", "SBP diagnosis: Ascitic PMN >=250 cells/mm3; treat even without culture"),
("key", "SBP treatment: Cefotaxime 2g IV q8h x5 days + IV Albumin (1.5g/kg day1, 1g/kg day3)"),
("key", "SBP prophylaxis: Norfloxacin if Protein <1.5g/dL OR prior SBP OR hepatic failure"),
("bullet", "Hepatic Encephalopathy: Lactulose (first-line) + Rifaximin (add-on/prevention)"),
("key", "HRS Type 1 (acute, rapid): Terlipressin + Albumin (CONFIRM trial)"),
("bullet", "Variceal bleed: Octreotide/Terlipressin + Ceftriaxone + Endoscopy within 12h"),
("alert", "! TIPS: Consider if 2nd variceal bleed or refractory ascites; CONTRAINDICATED if encephalopathy"),
]),
("Viral Hepatitis", [
("key", "HBV treatment: HBeAg+ with ALT elevated >2x ULN or HBV DNA >20,000 IU/mL"),
("key", "HBV drugs: Tenofovir (TDF/TAF) preferred; Entecavir alternative"),
("key", "HBsAg clearance = functional cure (goal of treatment)"),
("bullet", "HCV: Pan-genotypic regimen: Sofosbuvir/Velpatasvir x12 weeks; SVR = cure"),
("bullet", "HBV reactivation: Risk with rituximab, steroids, anti-TNF; prophylaxis with Entecavir"),
("key", "HDV coinfection: Worsens HBV; Peginterferon alfa + Bulevirtide (new drug)"),
("alert", "! HCV in pregnancy: No approved DAA; screen and treat postpartum"),
]),
]
right = [
("IBD - Crohn's vs UC", [
("body", "<b>Crohn's Disease:</b> Skip lesions, transmural, any GI tract, non-caseating granulomas"),
("body", "<b>Ulcerative Colitis:</b> Continuous, mucosa only, starts rectum, no granulomas"),
("key", "Mild-moderate UC: Mesalazine (5-ASA) first-line"),
("key", "Moderate-severe: Steroids for induction; Biologics (infliximab, vedolizumab) for maintenance"),
("bullet", "Biologics in IBD: Anti-TNF (Infliximab, Adalimumab), Anti-integrin (Vedolizumab), Anti-IL12/23 (Ustekinumab)"),
("bullet", "Surgery indications in UC: Toxic megacolon, dysplasia/cancer, refractory disease"),
("alert", "! Toxic megacolon: Colon >6cm; IV steroids + bowel rest; surgery if no improvement in 48-72h"),
]),
("Autoimmune Liver Diseases", [
("key", "AIH: ANA/SMA positive (Type 1), Anti-LKM1 (Type 2); elevated IgG; interface hepatitis on biopsy"),
("key", "AIH treatment: Prednisolone + Azathioprine; remission in >80%"),
("key", "PBC: AMA positive (>95%); cholestatic LFTs; Ursodeoxycholic acid slows progression"),
("key", "PSC: p-ANCA; beaded bile ducts on MRCP; associated with IBD (UC >70%); no proven medical therapy"),
("bullet", "PSC: Cholangiocarcinoma risk 0.5-1.5%/year; colonoscopy annually (IBD surveillance)"),
("alert", "! PSC + new biliary stricture = rule out cholangiocarcinoma (CA 19-9, ERCP brushings)"),
("bullet", "Overlap syndrome (AIH + PBC): Treat AIH component with steroids"),
]),
]
story.append(two_col(left, right))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════
# 6. HAEMATOLOGY
# ══════════════════════════════════════════════════════════════════════════
story.append(section_banner("HAEMATOLOGY (~10% of paper)", colors.HexColor("#6C3483")))
story.append(sp(3))
left = [
("Anaemias - Diagnostic Algorithm", [
("key", "MCV <80 (Microcytic): Iron deficiency, Thalassemia, Sideroblastic, ACD"),
("key", "Iron deficiency: Low serum iron, LOW ferritin, HIGH TIBC"),
("key", "ACD (chronic disease): Low serum iron, HIGH ferritin, LOW TIBC - key differentiator"),
("key", "MCV 80-100 (Normocytic): ACD, Haemolytic, Aplastic, renal failure"),
("key", "MCV >100 (Macrocytic): B12/Folate deficiency, Hypothyroid, Drugs (Hydroxyurea, MTX), MDS"),
("bullet", "B12 deficiency: Subacute combined degeneration (dorsal + lateral columns)"),
("alert", "! Treat B12 deficiency BEFORE folate replacement (risk of precipitating SACD)"),
]),
("Leukaemia - Markers & Treatment", [
("key", "CML: BCR-ABL1 (Philadelphia chromosome t(9;22)); treat with Imatinib (1st-line TKI)"),
("key", "CML blast crisis: Add intensive chemotherapy; Allogeneic SCT"),
("bullet", "AML: t(15;17) = APL - treat with ATRA + Arsenic trioxide (NOT standard chemo)"),
("key", "APL (M3) emergency: Bleeding + DIC; ATRA must be started IMMEDIATELY (diagnosis even suspected)"),
("bullet", "ALL: Philadelphia+ ALL: TKI + chemotherapy + CNS prophylaxis; Allo-SCT"),
("key", "CLL: Asymptomatic - watch and wait; symptomatic - BTK inhibitor (Ibrutinib) or Venetoclax+Obinutuzumab"),
("alert", "! CLL + autoimmune haemolytic anaemia: Treat with steroids first, not chemotherapy"),
]),
]
right = [
("Lymphoma - Key Facts", [
("key", "Hodgkin's Lymphoma: Reed-Sternberg cells (CD15+, CD30+); excellent prognosis"),
("bullet", "HL staging: Ann Arbor I-IV; B symptoms (fever, night sweats, weight loss >10%)"),
("key", "HL treatment: ABVD (Doxorubicin, Bleomycin, Vinblastine, Dacarbazine) - early stage"),
("bullet", "NHL: Most common = DLBCL (aggressive); Follicular lymphoma (indolent, CD10+, BCL2+, t(14;18))"),
("key", "DLBCL treatment: R-CHOP (Rituximab + CHOP chemotherapy)"),
("bullet", "Burkitt's: t(8;14), c-MYC; jaw tumor (endemic); aggressive, highly curable with intensive chemo"),
("alert", "! Tumour Lysis Syndrome: Aggressive lymphoma/leukemia post-chemo; Allopurinol/Rasburicase prophylaxis"),
]),
("Coagulation Disorders", [
("key", "DVT/PE: DOAC (Rivaroxaban / Apixaban) preferred for treatment (3-6 months)"),
("key", "Provoked PE: 3 months; Unprovoked / cancer-related: 6 months or indefinitely"),
("bullet", "Heparin-induced Thrombocytopenia (HIT): Platelet fall >50% on day 5-10 of heparin; 4T score"),
("key", "HIT management: STOP all heparin; start Argatroban or Fondaparinux (NOT warfarin initially)"),
("key", "TTP: Pentad (Microangiopathic haemolysis, thrombocytopenia, fever, renal, neuro); ADAMTS13 <10%"),
("bullet", "TTP treatment: Plasma exchange (DAILY) + steroids + Caplacizumab (new)"),
("alert", "! DIC: Treat underlying cause FIRST; give FFP, platelets, cryoprecipitate for active bleeding"),
]),
]
story.append(two_col(left, right))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════
# 7. INFECTIOUS DISEASES
# ══════════════════════════════════════════════════════════════════════════
story.append(section_banner("INFECTIOUS DISEASES (~8% of paper)", colors.HexColor("#7D6608")))
story.append(sp(3))
left = [
("HIV Management", [
("key", "ART initiation: ALL patients regardless of CD4 count (INSIGHT START trial)"),
("key", "Preferred 1st-line: TDF/FTC/DTG (Tenofovir + Emtricitabine + Dolutegravir)"),
("bullet", "OI prophylaxis: PCP <200 CD4 (TMP-SMX); MAC <50 CD4 (Azithromycin); Toxoplasma <100 (TMP-SMX)"),
("bullet", "Cryptococcal prophylaxis: Fluconazole if CD4 <100"),
("key", "Immune Reconstitution Syndrome (IRIS): Paradoxical worsening after ART start; treat with steroids"),
("alert", "! Abacavir: Test HLA-B*5701 before use (hypersensitivity risk)"),
("alert", "! Efavirenz: Avoid in pregnancy 1st trimester (teratogenic) - use DTG instead"),
]),
("Sepsis - Surviving Sepsis 2021", [
("key", "Sepsis-3 definition: Life-threatening organ dysfunction (SOFA +2) due to infection"),
("key", "Septic shock: Sepsis + vasopressors to maintain MAP >=65 + lactate >2 mmol/L"),
("key", "Hour-1 bundle: Blood cultures -> antibiotics within 1h -> IV fluids 30mL/kg if hypotension/lactate >4"),
("bullet", "Vasopressor of choice: Noradrenaline (norepinephrine) first-line"),
("bullet", "Add Vasopressin if NE dose >0.25 mcg/kg/min (steroid-sparing effect)"),
("key", "IV Hydrocortisone 200mg/day: if septic shock not responding to fluids + vasopressors"),
("alert", "! Do NOT delay antibiotics for cultures - each hour delay increases mortality by ~7%"),
]),
]
right = [
("Infective Endocarditis", [
("key", "Duke Criteria: 2 major OR 1 major + 3 minor OR 5 minor = definite IE"),
("key", "Major criteria: Positive blood culture (2 sets) + Echo evidence (vegetation/abscess/dehiscence)"),
("bullet", "Common organisms: S. aureus (acute, IV drug use), Streptococcus viridans (subacute, dental), HACEK (culture-negative)"),
("key", "Empirical treatment (native valve): Flucloxacillin + Gentamicin (MRSA risk: add Vancomycin)"),
("bullet", "Surgery indications: Heart failure, abscess/fistula, recurrent embolism, persistent bacteremia"),
("alert", "! New AV block in aortic valve IE = perivalvular extension/abscess; surgical emergency"),
]),
("Tuberculosis & Malaria", [
("key", "TB DOTS: RHEZ x2m (Rifampicin, INH, Ethambutol, Pyrazinamide) then RH x4m"),
("key", "Drug-resistant TB: MDR-TB (resistant R+H) - Bedaquiline-based regimen 6-9 months"),
("bullet", "TB meningitis: Steroids (Dexamethasone) reduce mortality; treat 12 months"),
("key", "Falciparum malaria: Artemisinin-based combination therapy (ACT) - Artesunate + partner drug"),
("key", "Severe malaria: IV Artesunate (preferred over Quinine in adults)"),
("bullet", "Vivax/Ovale: Chloroquine + Primaquine (radical cure of liver hypnozoites); check G6PD first"),
("alert", "! Check G6PD before Primaquine (causes haemolysis in G6PD deficiency)"),
]),
]
story.append(two_col(left, right))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════
# 8. RHEUMATOLOGY
# ══════════════════════════════════════════════════════════════════════════
story.append(section_banner("RHEUMATOLOGY (~5% of paper)", colors.HexColor("#922B21")))
story.append(sp(3))
left = [
("SLE - ACR/EULAR 2019 Criteria", [
("key", "Entry criterion: ANA >=1:80 (highly sensitive, 98%)"),
("key", "Scoring domains: Constitutional, haematological, neuropsychiatric, mucocutaneous, serosal, musculoskeletal, renal, immunological"),
("key", "Score >=10 = SLE (with positive ANA as entry)"),
("bullet", "Lupus nephritis class III/IV (proliferative): MMF or IV Cyclophosphamide + steroids"),
("key", "New add-on therapies: Belimumab (B-lymphocyte stimulator blocker), Voclosporin (calcineurin inhibitor for LN)"),
("bullet", "Hydroxychloroquine: ALL SLE patients (reduces flares, thrombosis, mortality)"),
("alert", "! Anti-dsDNA: Best for monitoring disease activity; Anti-Sm: Most specific for SLE"),
]),
("Rheumatoid Arthritis", [
("key", "ACR/EULAR 2010 criteria: Joints + Serology (RF/anti-CCP) + Acute phase reactants + Duration >=6wks; score >=6"),
("key", "Anti-CCP: Most specific for RA (95%); also predicts erosive disease"),
("key", "Treat to target: DAS28 < 2.6 (remission) or <3.2 (low disease activity)"),
("bullet", "First-line DMARD: Methotrexate (MTX) - gold standard; add folic acid"),
("key", "Biologic add-on if MTX fails: Anti-TNF (Adalimumab/Etanercept) OR JAK inhibitors (Baricitinib/Tofacitinib)"),
("alert", "! Felty's syndrome: RA + Splenomegaly + Neutropenia; increased infection risk"),
]),
]
right = [
("Vasculitides - Classification", [
("key", "Large vessel: Takayasu (young women, aorta), Giant Cell Arteritis (>50yr, temporal artery, ESR>50)"),
("key", "GCA treatment: Prednisolone 1mg/kg/day; Tocilizumab as steroid-sparing agent"),
("bullet", "Medium vessel: PAN (ANCA negative, HBV-associated), Kawasaki (children)"),
("key", "Small vessel ANCA+: GPA (c-ANCA/PR3), MPA (p-ANCA/MPO), EGPA (Eosinophilic, asthma, p-ANCA)"),
("key", "ANCA vasculitis treatment: Cyclophosphamide + steroids (induction); Rituximab equivalent (RAVE trial)"),
("bullet", "Maintenance: Azathioprine or Rituximab for 18-24 months"),
("alert", "! GCA: Temporal artery biopsy - do NOT delay steroids for biopsy result (start if high suspicion)"),
]),
("Crystal Arthropathies", [
("key", "Gout: Urate crystals (negatively birefringent, needle-shaped) in synovial fluid"),
("key", "Acute gout: NSAIDs (first-line) OR Colchicine OR Steroids"),
("key", "Urate-lowering therapy: Start AFTER acute attack resolves; target SUA <6 mg/dL"),
("bullet", "Allopurinol: Check HLA-B*5801 in Han Chinese/Thai (SJS risk)"),
("bullet", "Febuxostat: Alternative to Allopurinol; avoid in CVD (CARES trial mortality signal)"),
("bullet", "CPPD (pseudogout): Calcium pyrophosphate crystals (positively birefringent, rhomboid)"),
("alert", "! Renal impairment: Reduce Colchicine dose; avoid NSAIDs; Allopurinol dose adjustment per eGFR"),
]),
]
story.append(two_col(left, right))
story.append(sp(4))
# ── Final tips card ────────────────────────────────────────────────────────
tips_data = [
[Paragraph("EXAM STRATEGY REMINDERS", S("ts", fontSize=10, textColor=C_HEADER,
fontName="Helvetica-Bold", leading=14))],
[Paragraph("★ Guidelines > Old textbook editions - ACC/AHA 2023, ADA 2025, KDIGO 2021, AASLD, ACR/EULAR 2019 are heavily tested.", CARD_KEY)],
[Paragraph("★ Landmark trials: Know the trial name, drug, and RESULT (not just that it was 'positive').", CARD_KEY)],
[Paragraph("! First-line vs preferred vs contraindicated: These 3 categories produce ~40% of MCQ options.", CARD_ALERT)],
[Paragraph("★ Diagnostic criteria numbers: Learn exact thresholds (CD4 counts, SOFA score, Duke criteria, SLE score, etc.).", CARD_KEY)],
[Paragraph("! Negative markers: Know what NOT to give (NSAIDs in CKD, antipsychotics in DLB, BB before alpha-block in phaeo, etc.).", CARD_ALERT)],
[Paragraph("★ Marrow QBank: Use 'High Yield' + 'Repeat questions' filter in the final 3 weeks. Aim for 75%+ accuracy before exam.", CARD_KEY)],
]
tips_t = Table(tips_data, colWidths=[PAGE_W - 2*MARGIN])
tips_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), colors.HexColor("#EBF5FB")),
("BACKGROUND", (0,0), (-1,0), colors.HexColor("#D6EAF8")),
("BOX", (0,0), (-1,-1), 1, C_BORDER),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
story.append(tips_t)
return story
# ═══════════════════════════════════════════════════════════════════════════════
# BUILD
# ═══════════════════════════════════════════════════════════════════════════════
def build():
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
leftMargin=MARGIN, rightMargin=MARGIN,
topMargin=16*mm, bottomMargin=14*mm,
title="NEET SS General Medicine Quick Reference",
author="Orris",
)
story = build_story()
# Page templates
frame_cover = Frame(0, 0, PAGE_W, PAGE_H, id='cover')
frame_normal = Frame(MARGIN, 10*mm, PAGE_W - 2*MARGIN, PAGE_H - 20*mm, id='normal')
doc.build(
story,
onFirstPage=cover_bg,
onLaterPages=normal_page,
)
print(f"PDF saved to: {OUTPUT}")
build()
cd /home/daytona/workspace/neet-ss-guide && python generate_pdf.py 2>&1
ls -lh /home/daytona/workspace/neet-ss-guide/NEET_SS_Medicine_Quick_Reference.pdf
NEET SS Medicine Quick Reference
PDF Document · PDF
| Section | Color | Content |
|---|---|---|
| Cardiology | Deep Navy | ACS, HF-GDMT, Valvular, AF, Cardiomyopathies, Landmark Trials |
| Nephrology | Dark Blue | CKD staging, GN-KDIGO 2021, AKI, Electrolytes |
| Neurology | Medium Blue | Stroke (tPA/thrombectomy), Epilepsy, Meningitis, GBS/MG/NMO |
| Endocrinology | Steel Blue | ADA 2025 Diabetes, Thyroid, Adrenal, MEN syndromes, DI vs SIADH |
| Gastroenterology | Dark Green | Cirrhosis complications, Viral hepatitis, IBD, Autoimmune liver |
| Haematology | Purple | Anaemia algorithm, Leukaemia markers, Lymphoma, Coagulation |
| Infectious Diseases | Amber | HIV-ART, Sepsis bundles, IE-Duke criteria, TB, Malaria |
| Rheumatology | Dark Red | SLE 2019 criteria, RA treat-to-target, Vasculitis, Crystal arthropathies |
Create a 60-day countdown study tracker (Excel/PDF) to monitor daily progress through the timetable
~/neet-ss-guide/build_tracker.py
"""
NEET SS General Medicine - 60-Day Countdown Study Tracker
Sheets:
1. Dashboard - countdown, overall progress, subject-wise progress bars
2. Daily Tracker - day-by-day log (date, subject, topics, Marrow Qs, mock score, status)
3. Subject Progress - per-subject completion and accuracy
4. Mock Test Log - mock test scores and analysis
5. Weak Topics - running list of weak areas flagged during study
"""
import openpyxl
from openpyxl import Workbook
from openpyxl.styles import (
Font, PatternFill, Alignment, Border, Side, GradientFill
)
from openpyxl.utils import get_column_letter
from openpyxl.chart import BarChart, Reference, LineChart
from openpyxl.chart.series import DataPoint
from openpyxl.formatting.rule import ColorScaleRule, DataBarRule, FormulaRule, CellIsRule
from openpyxl.worksheet.datavalidation import DataValidation
from datetime import date, timedelta
import copy
wb = Workbook()
# ── Palette ────────────────────────────────────────────────────────────────────
NAVY = "1A3C5E"
BLUE = "2E6DA4"
LIGHT_BLUE = "D6EAF8"
SKY = "EBF5FB"
GREEN = "1A6B3C"
LIGHT_GRN = "D5F5E3"
AMBER = "F39C12"
AMBER_LT = "FEF9E7"
RED = "C0392B"
RED_LT = "FADBD8"
PURPLE = "6C3483"
PURPLE_LT = "E8DAEF"
TEAL = "0E6655"
TEAL_LT = "D1F2EB"
WHITE = "FFFFFF"
GRAY = "F2F3F4"
GRAY_MID = "BDC3C7"
GRAY_DARK = "717D7E"
GOLD = "D4AC0D"
def fill(hex_color):
return PatternFill("solid", fgColor=hex_color)
def font(bold=False, size=11, color="1A1A1A", italic=False, name="Arial"):
return Font(name=name, bold=bold, size=size, color=color, italic=italic)
def border(style="thin", color="BDC3C7"):
s = Side(style=style, color=color)
return Border(left=s, right=s, top=s, bottom=s)
def thick_border():
tk = Side(style="medium", color=NAVY)
return Border(left=tk, right=tk, top=tk, bottom=tk)
def align(h="left", v="center", wrap=False):
return Alignment(horizontal=h, vertical=v, wrap_text=wrap)
def write(ws, row, col, value, fnt=None, fl=None, aln=None, brd=None):
c = ws.cell(row=row, column=col, value=value)
if fnt: c.font = fnt
if fl: c.fill = fl
if aln: c.alignment = aln
if brd: c.border = brd
return c
START_DATE = date(2026, 6, 27)
# 60-day timetable (day, week, subject, topics, textbook_ref)
TIMETABLE = []
week_plans = [
# Week 1: Cardiology
[(1,1,"Cardiology","ACS - STEMI Management, Thrombolysis, PCI protocols","Harrison's + Braunwald Ch 56-57"),
(2,1,"Cardiology","ACS - NSTEMI/UA, Risk Stratification, Antiplatelets","Braunwald Ch 56-57"),
(3,1,"Cardiology","Heart Failure - GDMT, HFrEF vs HFpEF, Device therapy","Braunwald Ch 58"),
(4,1,"Cardiology","Valvular Heart Disease - AS, MR, MS, AR + intervention criteria","Braunwald Ch 67"),
(5,1,"Cardiology","Arrhythmias - AF management, SVT, VT, Channelopathies","Braunwald Ch 65-66"),
(6,1,"Cardiology","Cardiomyopathies, Pericardial disease, HTN + Dyslipidaemia","Braunwald Ch 69-70"),
(7,1,"Cardiology - REVISION","Cardiology Full Subject Test + Review of wrong answers","Full chapter review"),],
# Week 2: Nephrology
[(8,2,"Nephrology","AKI - KDIGO criteria, causes, management, RRT indications","Harrison's Ch 306-307"),
(9,2,"Nephrology","CKD - Staging, progression, SGLT2i in CKD (CREDENCE/DAPA-CKD)","Brenner Ch 57"),
(10,2,"Nephrology","Glomerulonephritis - KDIGO 2021, IgAN, MN, MCD, FSGS","Brenner Ch 30-31"),
(11,2,"Nephrology","Sodium disorders - Hypo/Hypernatraemia, SIADH algorithm","Harrison's Ch 55"),
(12,2,"Nephrology","Potassium, Calcium, Magnesium disorders + Acid-base","Harrison's Ch 55"),
(13,2,"Nephrology","Dialysis modalities, Transplant basics, Renal tubular acidosis","Brenner Ch 63"),
(14,2,"Nephrology - REVISION","Nephrology Subject Test + Review all wrongs","Full chapter review"),],
# Week 3: Neurology
[(15,3,"Neurology","Stroke - tPA criteria, thrombectomy window, NIHSS","Adams Ch 34"),
(16,3,"Neurology","Stroke secondary prevention, PFO closure, ICH management","Adams Ch 34"),
(17,3,"Neurology","Epilepsy - drug selection table, Status Epilepticus protocol","Adams Ch 16"),
(18,3,"Neurology","CNS Infections - Bacterial meningitis, HSV encephalitis, Crypto","Adams Ch 32"),
(19,3,"Neurology","Dementia syndromes - AD, DLB, FTD, Vascular; Movement disorders","Adams Ch 39-40"),
(20,3,"Neurology","GBS, Myasthenia Gravis, NMO, MS","Adams Ch 46-47"),
(21,3,"Neurology - REVISION","Neurology Subject Test + Review","Full chapter review"),],
# Week 4: Endocrinology + Haematology
[(22,4,"Endocrinology","Diabetes - ADA 2025, Drug selection algorithms, SGLT2i/GLP1-RA","Williams Ch 33"),
(23,4,"Endocrinology","DKA, HHS management; Hypoglycaemia unawareness","Harrison's Ch 417"),
(24,4,"Endocrinology","Thyroid - Graves', Hashimoto, thyroid storm, hypothyroid in pregnancy","Williams Ch 11-12"),
(25,4,"Endocrinology","Adrenal - Cushing's, Addison's, Conn's, Phaeochromocytoma","Williams Ch 15-16"),
(26,4,"Endocrinology","Pituitary - DI vs SIADH, MEN syndromes, Carcinoid; Endocrinology QBank","Williams Ch 9"),
(27,4,"Haematology","Anaemias - Iron deficiency, ACD, B12/Folate, Haemolytic","Williams Haem Ch 11-15"),
(28,4,"Haematology","MDS, Aplastic Anaemia - diagnostic criteria, treatment","Williams Haem Ch 35"),],
# Week 5 continuation
[(29,5,"Haematology","Leukaemias - AML (APL), CML, ALL, CLL; targeted therapy markers","Williams Haem Ch 87-92"),
(30,5,"Haematology","Lymphoma - Hodgkin's vs NHL, staging, chemotherapy regimens","Williams Haem Ch 103"),
(31,5,"Haematology","Coagulation - DVT/PE (DOACs), HIT, TTP/HUS, DIC","Williams Haem Ch 129"),
(32,5,"Gastroenterology","Cirrhosis complications - SBP, HRS, HE, Variceal bleed","Sleisenger Ch 74-76"),
(33,5,"Gastroenterology","Viral hepatitis - HBV treatment, HCV DAA regimens, HBV reactivation","Sleisenger Ch 80"),
(34,5,"Gastroenterology","IBD - CD vs UC, biologic agents, surgical indications","Sleisenger Ch 116"),
(35,5,"Gastroenterology","NAFLD/NASH, Autoimmune hepatitis, PBC/PSC + GI bleed","Sleisenger Ch 87"),],
# Week 6: Infectious Diseases + Rheumatology
[(36,6,"Infectious Diseases","HIV - ART initiation, OI prophylaxis, IRIS, drug interactions","Mandell Ch 121"),
(37,6,"Infectious Diseases","Sepsis - Surviving Sepsis 2021 bundle, vasopressors, corticosteroids","Harrison's Ch 297"),
(38,6,"Infectious Diseases","Infective Endocarditis - Duke criteria, treatment, surgery indications","Mandell Ch 80"),
(39,6,"Infectious Diseases","TB - DOTS regimen, MDR-TB, TB meningitis","Mandell Ch 251"),
(40,6,"Infectious Diseases","Malaria, Typhoid, Fungal infections, Antimicrobials stewardship","Mandell Ch 259"),
(41,6,"Rheumatology","SLE - ACR/EULAR 2019 criteria, LN treatment, Belimumab","Kelley Ch 78"),
(42,6,"Rheumatology","RA - treat-to-target, DMARDs, Biologics, JAK inhibitors","Kelley Ch 70"),],
# Week 7: Revision Phase 1
[(43,7,"REVISION","Cardiology rapid revision - Marrow notes, no new reading","Marrow flashcards"),
(44,7,"REVISION","Nephrology rapid revision + Electrolytes","Marrow flashcards"),
(45,7,"REVISION","Neurology rapid revision","Marrow flashcards"),
(46,7,"REVISION","Endocrinology rapid revision","Marrow flashcards"),
(47,7,"REVISION","GI/Hepatology + ID rapid revision","Marrow flashcards"),
(48,7,"REVISION","Haematology + Rheumatology rapid revision","Marrow flashcards"),
(49,7,"MOCK TEST 1","Full-length Mock Test 1 (Marrow) + Analysis","Marrow platform"),],
# Week 8: Targeted weak areas + advances
[(50,8,"WEAK AREAS","Weak subject 1 targeted revision (from Mock 1 analysis)","Textbook + Marrow"),
(51,8,"WEAK AREAS","Weak subject 2 targeted revision","Textbook + Marrow"),
(52,8,"WEAK AREAS","Weak subject 3 targeted revision","Textbook + Marrow"),
(53,8,"RECENT ADVANCES","2023-2025 Landmark Trials: EMPEROR, CREDENCE, DAPA-HF/CKD, ANNEXA-4","Marrow + UpToDate"),
(54,8,"RECENT ADVANCES","Guidelines update: ADA 2025, ACC/AHA, KDIGO 2021, AASLD","Guideline documents"),
(55,8,"MOCK TEST 2","Full-length Mock Test 2 + Detailed Analysis","Marrow platform"),
(56,8,"MOCK TEST 2","Mock 2 analysis - subject-wise accuracy, flag weak Qs","Marrow platform"),],
# Week 9: Final revision
[(57,9,"FINAL REVISION","High-yield only - Marrow 'Important' tags, Cardiology + Nephrology","Marrow"),
(58,9,"MOCK TEST 3","Full-length Mock Test 3","Marrow platform"),
(59,9,"FINAL REVISION","Neurology + Endocrinology rapid fire","Marrow notes"),
(60,9,"MOCK TEST 4","Full-length Mock Test 4 + Final review of wrong answers","Marrow platform"),],
]
for wk in week_plans:
for entry in wk:
TIMETABLE.append(entry)
SUBJECTS = [
"Cardiology","Nephrology","Neurology","Endocrinology",
"Gastroenterology","Haematology","Infectious Diseases","Rheumatology",
"REVISION","MOCK TEST","RECENT ADVANCES","WEAK AREAS","FINAL REVISION"
]
SUBJECT_COLORS = {
"Cardiology": (NAVY, LIGHT_BLUE),
"Nephrology": ("1A5276", "D6EAF8"),
"Neurology": ("1B4F72", "D6EAF8"),
"Endocrinology": ("0E6655", "D1F2EB"),
"Gastroenterology": ("145A32", "D5F5E3"),
"Haematology": (PURPLE, PURPLE_LT),
"Infectious Diseases": ("7D6608", "FCF3CF"),
"Rheumatology": ("922B21", "FADBD8"),
"REVISION": ("1A6B3C", "D5F5E3"),
"MOCK TEST": ("B7950B", "FEF9E7"),
"RECENT ADVANCES": ("6C3483", "E8DAEF"),
"WEAK AREAS": ("C0392B", "FADBD8"),
"FINAL REVISION": ("1B2631", "EAECEE"),
}
# ══════════════════════════════════════════════════════════════════════════════
# SHEET 1: DASHBOARD
# ══════════════════════════════════════════════════════════════════════════════
ws_dash = wb.active
ws_dash.title = "Dashboard"
ws_dash.sheet_properties.tabColor = NAVY
ws_dash.freeze_panes = None
# column widths
for col, w in [(1,3),(2,22),(3,14),(4,14),(5,14),(6,14),(7,14),(8,3)]:
ws_dash.column_dimensions[get_column_letter(col)].width = w
# row heights
for r in range(1, 80):
ws_dash.row_dimensions[r].height = 18
# ── Title Banner ──────────────────────────────────────────────────────────────
ws_dash.merge_cells("B1:G1")
ws_dash.row_dimensions[1].height = 10
ws_dash.merge_cells("B2:G2")
c = ws_dash["B2"]
c.value = "NEET SS | General Medicine Group"
c.font = Font(name="Arial", bold=True, size=20, color=WHITE)
c.fill = fill(NAVY)
c.alignment = align("center")
ws_dash.row_dimensions[2].height = 38
ws_dash.merge_cells("B3:G3")
c = ws_dash["B3"]
c.value = "60-Day Study Countdown Tracker • June 27 – August 25, 2026"
c.font = Font(name="Arial", size=11, color=WHITE, italic=True)
c.fill = fill(BLUE)
c.alignment = align("center")
ws_dash.row_dimensions[3].height = 22
for row in range(1,4):
for col in range(1,9):
ws_dash.cell(row=row, column=col).fill = fill(NAVY if row < 4 else WHITE)
# ── Countdown box ─────────────────────────────────────────────────────────────
ws_dash.row_dimensions[5].height = 16
ws_dash.row_dimensions[6].height = 40
ws_dash.row_dimensions[7].height = 22
ws_dash.row_dimensions[8].height = 16
ws_dash.row_dimensions[9].height = 30
ws_dash.row_dimensions[10].height = 30
ws_dash.merge_cells("B5:D5")
c = ws_dash["B5"]
c.value = "DAYS REMAINING"
c.font = font(bold=True, size=9, color=GRAY_DARK)
c.alignment = align("center")
ws_dash.merge_cells("B6:D6")
c = ws_dash["B6"]
c.value = '=MAX(0,DATE(2026,8,25)-TODAY())'
c.font = Font(name="Arial", bold=True, size=32, color=RED)
c.fill = fill(RED_LT)
c.alignment = align("center")
c.border = border("medium", RED)
ws_dash.merge_cells("B7:D7")
c = ws_dash["B7"]
c.value = "days until exam (target: Aug 25, 2026)"
c.font = font(size=8, color=GRAY_DARK, italic=True)
c.alignment = align("center")
ws_dash.merge_cells("E5:G5")
c = ws_dash["E5"]
c.value = "OVERALL COMPLETION"
c.font = font(bold=True, size=9, color=GRAY_DARK)
c.alignment = align("center")
ws_dash.merge_cells("E6:G6")
c = ws_dash["E6"]
c.value = "=IFERROR(COUNTIF('Daily Tracker'!H2:H61,\"Done\")/60,0)"
c.number_format = "0.0%"
c.font = Font(name="Arial", bold=True, size=32, color=GREEN)
c.fill = fill(LIGHT_GRN)
c.alignment = align("center")
c.border = border("medium", GREEN)
ws_dash.merge_cells("E7:G7")
c = ws_dash["E7"]
c.value = "of 60 days completed"
c.font = font(size=8, color=GRAY_DARK, italic=True)
c.alignment = align("center")
# ── Stats row ─────────────────────────────────────────────────────────────────
ws_dash.row_dimensions[9].height = 20
ws_dash.row_dimensions[10].height = 30
ws_dash.row_dimensions[11].height = 18
def stat_box(ws, row, col_start, col_end, label, formula, num_fmt, fc, bc):
ws.merge_cells(start_row=row, start_column=col_start, end_row=row, end_column=col_end)
c = ws.cell(row=row, column=col_start, value=label)
c.font = font(bold=True, size=8, color=GRAY_DARK)
c.alignment = align("center")
ws.merge_cells(start_row=row+1, start_column=col_start, end_row=row+1, end_column=col_end)
c2 = ws.cell(row=row+1, column=col_start, value=formula)
c2.font = Font(name="Arial", bold=True, size=18, color=fc)
c2.fill = fill(bc)
c2.alignment = align("center")
c2.number_format = num_fmt
return c2
stat_box(ws_dash, 9, 2, 3, "DONE DAYS", '=COUNTIF(\'Daily Tracker\'!H2:H61,"Done")', "0", GREEN, LIGHT_GRN)
stat_box(ws_dash, 9, 4, 5, "SKIPPED", '=COUNTIF(\'Daily Tracker\'!H2:H61,"Skipped")', "0", RED, RED_LT)
stat_box(ws_dash, 9, 6, 7, "TOTAL Qs ATTEMPTED", '=IFERROR(SUM(\'Daily Tracker\'!F2:F61),0)', "#,##0", BLUE, LIGHT_BLUE)
# ── Subject progress table ────────────────────────────────────────────────────
ws_dash.row_dimensions[13].height = 20
ws_dash.merge_cells("B13:G13")
c = ws_dash["B13"]
c.value = "SUBJECT-WISE PROGRESS"
c.font = font(bold=True, size=11, color=WHITE)
c.fill = fill(NAVY)
c.alignment = align("center")
headers = ["Subject", "Planned Days", "Done", "Avg Marrow Qs/Day", "Completion %", "Status"]
col_widths = [22, 14, 8, 18, 14, 12]
for i, (h, cw) in enumerate(zip(headers, col_widths)):
c = ws_dash.cell(row=14, column=i+2, value=h)
c.font = font(bold=True, size=9, color=WHITE)
c.fill = fill(BLUE)
c.alignment = align("center")
ws_dash.row_dimensions[14].height = 20
MAIN_SUBJECTS = [
("Cardiology", 7, NAVY, LIGHT_BLUE),
("Nephrology", 7, "1A5276", "D6EAF8"),
("Neurology", 7, "1B4F72", "D6EAF8"),
("Endocrinology", 5, "0E6655", "D1F2EB"),
("Haematology", 5, PURPLE, PURPLE_LT),
("Gastroenterology", 5, "145A32", "D5F5E3"),
("Infectious Diseases",5, "7D6608", "FCF3CF"),
("Rheumatology", 3, "922B21", "FADBD8"),
("REVISION", 6, "1A6B3C", "D5F5E3"),
("MOCK TEST", 4, "B7950B", "FEF9E7"),
("Recent Adv/Weak", 3, "6C3483", "E8DAEF"),
]
for i, (subj, planned, fc, bc) in enumerate(MAIN_SUBJECTS):
r = 15 + i
ws_dash.row_dimensions[r].height = 22
# Subject name
c = ws_dash.cell(row=r, column=2, value=subj)
c.font = Font(name="Arial", bold=True, size=9, color=fc)
c.fill = fill(bc)
c.alignment = align("left")
# Planned days
c = ws_dash.cell(row=r, column=3, value=planned)
c.font = font(size=9)
c.alignment = align("center")
# Done formula - count from Daily Tracker where subject matches and status=Done
done_formula = f'=COUNTIFS(\'Daily Tracker\'!D2:D61,B{r},\'Daily Tracker\'!H2:H61,"Done")'
c = ws_dash.cell(row=r, column=4, value=done_formula)
c.font = font(size=9, color=GREEN)
c.alignment = align("center")
# Avg Qs
avg_q = f'=IFERROR(AVERAGEIFS(\'Daily Tracker\'!F2:F61,\'Daily Tracker\'!D2:D61,B{r},\'Daily Tracker\'!H2:H61,"Done"),0)'
c = ws_dash.cell(row=r, column=5, value=avg_q)
c.font = font(size=9)
c.number_format = "0.0"
c.alignment = align("center")
# Completion %
pct = f'=IFERROR(D{r}/C{r},0)'
c = ws_dash.cell(row=r, column=6, value=pct)
c.font = font(size=9, bold=True)
c.number_format = "0%"
c.alignment = align("center")
# Status
status_formula = f'=IF(F{r}>=1,"Complete",IF(F{r}>0,"In Progress","Not Started"))'
c = ws_dash.cell(row=r, column=7, value=status_formula)
c.font = font(size=8)
c.alignment = align("center")
# Conditional formatting for completion %
from openpyxl.formatting.rule import ColorScaleRule
ws_dash.conditional_formatting.add(
f"F15:F{15+len(MAIN_SUBJECTS)-1}",
ColorScaleRule(
start_type="num", start_value=0, start_color="FADBD8",
mid_type="num", mid_value=0.5, mid_color="FEF9E7",
end_type="num", end_value=1, end_color="D5F5E3"
)
)
# ── Mock test summary ─────────────────────────────────────────────────────────
mr = 15 + len(MAIN_SUBJECTS) + 2
ws_dash.row_dimensions[mr].height = 20
ws_dash.merge_cells(f"B{mr}:G{mr}")
c = ws_dash.cell(row=mr, column=2, value="MOCK TEST SCORES (from Mock Test Log sheet)")
c.font = font(bold=True, size=11, color=WHITE)
c.fill = fill("B7950B")
c.alignment = align("center")
for i, (label, col) in enumerate([("Mock 1", "C"), ("Mock 2", "D"), ("Mock 3", "E"), ("Mock 4", "F")]):
rr = mr + 1
ws_dash.row_dimensions[rr].height = 22
c = ws_dash.cell(row=rr, column=2+i*1+1-1+1, value=label)
mock_headers = ["Mock", "Date", "Score /200", "Correct %", "Rank (est.)", "Key Weak Area"]
for j, h in enumerate(mock_headers):
c = ws_dash.cell(row=mr+1, column=j+2, value=h)
c.font = font(bold=True, size=8, color=WHITE)
c.fill = fill(AMBER)
c.alignment = align("center")
ws_dash.row_dimensions[mr+1].height = 18
for k in range(1,5):
r = mr+1+k
ws_dash.row_dimensions[r].height = 20
ws_dash.cell(row=r, column=2, value=f"Mock {k}").font = font(bold=True, size=9)
ws_dash.cell(row=r, column=3, value=f"='Mock Test Log'!B{k+1}").font = font(size=9)
ws_dash.cell(row=r, column=4, value=f"='Mock Test Log'!C{k+1}").number_format = "0/200"
ws_dash.cell(row=r, column=4).font = Font(name="Arial", bold=True, size=11, color=NAVY)
ws_dash.cell(row=r, column=5, value=f"=IFERROR('Mock Test Log'!C{k+1}/200,\"-\")")
ws_dash.cell(row=r, column=5).number_format = "0.0%"
ws_dash.cell(row=r, column=6, value=f"='Mock Test Log'!E{k+1}").font = font(size=9)
ws_dash.cell(row=r, column=7, value=f"='Mock Test Log'!F{k+1}").font = font(size=8, color=RED)
# ── Motivational footer ───────────────────────────────────────────────────────
fr = mr + 7
ws_dash.row_dimensions[fr].height = 8
ws_dash.row_dimensions[fr+1].height = 24
ws_dash.merge_cells(f"B{fr+1}:G{fr+1}")
c = ws_dash.cell(row=fr+1, column=2, value='="Day "&(61-MAX(0,DATE(2026,8,25)-TODAY()))&" of 60 | "&TEXT(COUNTIF(\'Daily Tracker\'!H2:H61,"Done")/60,"0.0%")&" complete | "&MAX(0,DATE(2026,8,25)-TODAY())&" days to go — Keep going!"')
c.font = Font(name="Arial", italic=True, size=9, color=GRAY_DARK)
c.alignment = align("center")
c.fill = fill(GRAY)
# ══════════════════════════════════════════════════════════════════════════════
# SHEET 2: DAILY TRACKER
# ══════════════════════════════════════════════════════════════════════════════
ws_daily = wb.create_sheet("Daily Tracker")
ws_daily.sheet_properties.tabColor = GREEN
# Freeze header row
ws_daily.freeze_panes = "A2"
# Column widths
col_widths_daily = [5, 8, 12, 22, 44, 12, 12, 12, 22, 30]
for i, w in enumerate(col_widths_daily, 1):
ws_daily.column_dimensions[get_column_letter(i)].width = w
# Header
headers_daily = ["#", "Date", "Week", "Subject", "Topics Planned", "Marrow Qs Planned", "Marrow Qs Done", "Status", "Mock Score (if any)", "Notes / Weak Points Flagged"]
header_colors = [GRAY_DARK, NAVY, NAVY, NAVY, NAVY, BLUE, BLUE, GREEN, AMBER, PURPLE]
ws_daily.row_dimensions[1].height = 28
for j, (h, hc) in enumerate(zip(headers_daily, header_colors), 1):
c = ws_daily.cell(row=1, column=j, value=h)
c.font = Font(name="Arial", bold=True, size=9, color=WHITE)
c.fill = fill(hc)
c.alignment = align("center", wrap=True)
c.border = border("medium", WHITE)
# Data validation for Status
dv_status = DataValidation(type="list", formula1='"Done,In Progress,Skipped,Holiday"', allow_blank=True)
dv_status.error = "Please select: Done, In Progress, Skipped, or Holiday"
dv_status.errorTitle = "Invalid Input"
dv_status.prompt = "Select status"
dv_status.promptTitle = "Status"
ws_daily.add_data_validation(dv_status)
dv_status.sqref = "H2:H61"
# Data rows
for idx, entry in enumerate(TIMETABLE):
day_num, week_num, subject, topics, textbook = entry
r = idx + 2
d = START_DATE + timedelta(days=idx)
ws_daily.row_dimensions[r].height = 22
# Get subject color
sc = SUBJECT_COLORS.get(subject, (GRAY_DARK, GRAY))
dark_c, light_c = sc
# determine planned Qs
if "MOCK TEST" in subject:
planned_qs = 200
elif "REVISION" in subject or "FINAL REVISION" in subject:
planned_qs = 50
elif "RECENT ADVANCES" in subject or "WEAK AREAS" in subject:
planned_qs = 40
else:
planned_qs = 35
row_data = [
day_num,
d.strftime("%d %b %Y"),
f"Week {week_num}",
subject,
topics,
planned_qs,
"", # Marrow Qs Done - user fills
"", # Status - user fills
"", # Mock score - user fills
"", # Notes - user fills
]
for j, val in enumerate(row_data, 1):
c = ws_daily.cell(row=r, column=j, value=val)
c.font = font(size=9)
c.alignment = align("left" if j in [4,5,10] else "center", wrap=(j in [5,10]))
c.border = border("thin", "D5D8DC")
if j == 1: # day number
c.font = Font(name="Arial", bold=True, size=10, color=WHITE)
c.fill = fill(dark_c)
c.alignment = align("center")
elif j == 4: # subject
c.font = Font(name="Arial", bold=True, size=9, color=dark_c)
c.fill = fill(light_c)
elif j == 5: # topics
c.font = font(size=8, color="2C3E50")
c.alignment = align("left", wrap=True)
elif j == 6: # planned qs
c.font = font(size=9, color=BLUE, bold=True)
c.alignment = align("center")
elif j == 2: # date
c.font = Font(name="Arial", bold=True, size=9, color=NAVY)
# Conditional formatting for Status column
ws_daily.conditional_formatting.add("H2:H61",
CellIsRule(operator="equal", formula=['"Done"'],
fill=fill(LIGHT_GRN), font=Font(name="Arial", bold=True, size=9, color=GREEN)))
ws_daily.conditional_formatting.add("H2:H61",
CellIsRule(operator="equal", formula=['"Skipped"'],
fill=fill(RED_LT), font=Font(name="Arial", bold=True, size=9, color=RED)))
ws_daily.conditional_formatting.add("H2:H61",
CellIsRule(operator="equal", formula=['"In Progress"'],
fill=fill(AMBER_LT), font=Font(name="Arial", bold=True, size=9, color=AMBER)))
ws_daily.conditional_formatting.add("H2:H61",
CellIsRule(operator="equal", formula=['"Holiday"'],
fill=fill(GRAY), font=Font(name="Arial", size=9, color=GRAY_DARK)))
# Conditional formatting for Marrow Qs Done vs Planned (column G vs F)
ws_daily.conditional_formatting.add("G2:G61",
ColorScaleRule(
start_type="num", start_value=0, start_color="FADBD8",
mid_type="percentile", mid_value=50, mid_color="FEF9E7",
end_type="num", end_value=200, end_color="D5F5E3"
)
)
# ══════════════════════════════════════════════════════════════════════════════
# SHEET 3: SUBJECT PROGRESS
# ══════════════════════════════════════════════════════════════════════════════
ws_subj = wb.create_sheet("Subject Progress")
ws_subj.sheet_properties.tabColor = BLUE
ws_subj.freeze_panes = "A2"
subj_cols = [5, 22, 14, 14, 14, 18, 18, 22]
for i, w in enumerate(subj_cols, 1):
ws_subj.column_dimensions[get_column_letter(i)].width = w
ws_subj.row_dimensions[1].height = 10
ws_subj.merge_cells("A2:H2")
c = ws_subj["A2"]
c.value = "SUBJECT-WISE COMPLETION & ACCURACY TRACKER"
c.font = Font(name="Arial", bold=True, size=14, color=WHITE)
c.fill = fill(NAVY)
c.alignment = align("center")
ws_subj.row_dimensions[2].height = 32
headers_subj = ["", "Subject", "Total Days", "Days Done", "% Complete", "Total Qs Done", "Avg Accuracy %", "Target Topics"]
for j, h in enumerate(headers_subj, 1):
c = ws_subj.cell(row=3, column=j, value=h)
c.font = font(bold=True, size=9, color=WHITE)
c.fill = fill(BLUE)
c.alignment = align("center")
ws_subj.row_dimensions[3].height = 22
SUBJ_DETAIL = [
("Cardiology", 7, "ACS, HF-GDMT, Valvular, AF, Cardiomyopathies, HTN, Landmark Trials"),
("Nephrology", 7, "AKI, CKD, Glomerulonephritis, Electrolytes, RTA, Transplant"),
("Neurology", 7, "Stroke, Epilepsy, Meningitis, Dementia, Movement, GBS/MG/NMO"),
("Endocrinology", 5, "Diabetes (ADA 2025), Thyroid, Adrenal, Pituitary, MEN"),
("Haematology", 5, "Anaemias, MDS, Aplastic, Leukaemias, Lymphoma, Coagulation"),
("Gastroenterology", 5, "Cirrhosis, Viral Hepatitis, IBD, Autoimmune liver, NAFLD"),
("Infectious Diseases",5, "HIV-ART, Sepsis, IE, TB, Malaria, Antimicrobials"),
("Rheumatology", 3, "SLE, RA, Vasculitis, Crystal arthropathies"),
]
for i, (subj, days, targets) in enumerate(SUBJ_DETAIL):
r = 4 + i
dark_c, light_c = SUBJECT_COLORS[subj]
ws_subj.row_dimensions[r].height = 28
# color swatch
c = ws_subj.cell(row=r, column=1)
c.fill = fill(dark_c)
# subject
c = ws_subj.cell(row=r, column=2, value=subj)
c.font = Font(name="Arial", bold=True, size=10, color=dark_c)
c.fill = fill(light_c)
c.alignment = align("left")
# total days
c = ws_subj.cell(row=r, column=3, value=days)
c.font = font(size=9, bold=True)
c.alignment = align("center")
# days done (from daily tracker)
done_f = f'=COUNTIFS(\'Daily Tracker\'!D2:D61,B{r},\'Daily Tracker\'!H2:H61,"Done")'
c = ws_subj.cell(row=r, column=4, value=done_f)
c.font = font(size=10, bold=True, color=GREEN)
c.alignment = align("center")
# % complete
c = ws_subj.cell(row=r, column=5, value=f"=IFERROR(D{r}/C{r},0)")
c.font = font(size=10, bold=True)
c.number_format = "0%"
c.alignment = align("center")
# total Qs done
qs_f = f'=IFERROR(SUMIFS(\'Daily Tracker\'!G2:G61,\'Daily Tracker\'!D2:D61,B{r}),0)'
c = ws_subj.cell(row=r, column=6, value=qs_f)
c.font = font(size=9)
c.number_format = "#,##0"
c.alignment = align("center")
# accuracy % (user can fill in)
c = ws_subj.cell(row=r, column=7, value="")
c.number_format = "0.0%"
c.alignment = align("center")
c.fill = fill(AMBER_LT)
c.font = font(size=9, color=AMBER)
# target topics
c = ws_subj.cell(row=r, column=8, value=targets)
c.font = font(size=8, color=GRAY_DARK, italic=True)
c.alignment = align("left", wrap=True)
for col in range(1, 9):
ws_subj.cell(row=r, column=col).border = border("thin")
# Color scale on % complete
ws_subj.conditional_formatting.add(
f"E4:E{4+len(SUBJ_DETAIL)-1}",
ColorScaleRule(
start_type="num", start_value=0, start_color="FADBD8",
mid_type="num", mid_value=0.5, mid_color="FEF9E7",
end_type="num", end_value=1, end_color="D5F5E3"
)
)
# Accuracy input instructions
ws_subj.merge_cells(f"A{4+len(SUBJ_DETAIL)+2}:H{4+len(SUBJ_DETAIL)+2}")
c = ws_subj.cell(row=4+len(SUBJ_DETAIL)+2, column=1,
value=" INSTRUCTIONS: Fill in 'Avg Accuracy %' (column G) manually after each subject's QBank session. Target: >70% before moving on.")
c.font = font(size=9, color=GRAY_DARK, italic=True)
c.fill = fill(AMBER_LT)
# ══════════════════════════════════════════════════════════════════════════════
# SHEET 4: MOCK TEST LOG
# ══════════════════════════════════════════════════════════════════════════════
ws_mock = wb.create_sheet("Mock Test Log")
ws_mock.sheet_properties.tabColor = AMBER
mock_col_widths = [5, 14, 14, 16, 16, 22, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 30]
for i, w in enumerate(mock_col_widths, 1):
ws_mock.column_dimensions[get_column_letter(i)].width = w
ws_mock.row_dimensions[1].height = 10
ws_mock.merge_cells("A2:R2")
c = ws_mock["A2"]
c.value = "MOCK TEST LOG & SUBJECT-WISE ANALYSIS"
c.font = Font(name="Arial", bold=True, size=14, color=WHITE)
c.fill = fill("B7950B")
c.alignment = align("center")
ws_mock.row_dimensions[2].height = 32
mock_headers = [
"", "Date", "Score /200", "% Correct", "Est. Rank",
"Weakest Subject", "Time Taken (min)", "Cardiology %",
"Nephrology %", "Neurology %", "Endocrinology %", "GI/Hepatology %",
"Haematology %", "Infect. Dis. %", "Rheumatology %", "Avg Accuracy %",
"Better than Mock?", "Action Plan"
]
ws_mock.row_dimensions[3].height = 30
for j, h in enumerate(mock_headers, 1):
c = ws_mock.cell(row=3, column=j, value=h)
c.font = font(bold=True, size=8, color=WHITE)
c.fill = fill("B7950B")
c.alignment = align("center", wrap=True)
for k in range(1, 5):
r = 3 + k
ws_mock.row_dimensions[r].height = 35
# Mock number swatch
c = ws_mock.cell(row=r, column=1)
c.value = k
c.font = Font(name="Arial", bold=True, size=14, color=WHITE)
c.fill = fill(NAVY)
c.alignment = align("center")
# Mock label row
ws_mock.cell(row=r, column=2, value="").number_format = "DD MMM YYYY"
ws_mock.cell(row=r, column=3, value="").number_format = "0"
# % correct
c = ws_mock.cell(row=r, column=4, value=f"=IFERROR(C{r}/200,\"\")")
c.number_format = "0.0%"
c.font = Font(name="Arial", bold=True, size=12, color=NAVY)
# Better than previous mock
if k > 1:
c = ws_mock.cell(row=r, column=17, value=f'=IF(C{r}="","",IF(C{r}>C{r-1},"YES ▲","NO ▼"))')
c.font = font(size=10, bold=True)
# Format all cells
for j in range(1, 19):
cc = ws_mock.cell(row=r, column=j)
cc.border = border("thin")
cc.alignment = align("center", wrap=(j==18))
if j in range(8, 16): # subject accuracy cells
cc.fill = fill(LIGHT_BLUE)
cc.number_format = "0%"
# Colour scale on score
ws_mock.conditional_formatting.add("C4:C7",
ColorScaleRule(
start_type="num", start_value=100, start_color="FADBD8",
mid_type="num", mid_value=140, mid_color="FEF9E7",
end_type="num", end_value=180, end_color="D5F5E3"
)
)
# Target score box
ws_mock.row_dimensions[10].height = 20
ws_mock.merge_cells("B10:F10")
c = ws_mock["B10"]
c.value = "TARGET: Score > 140/200 (70%) by Mock 2 | > 160/200 (80%) by Mock 4"
c.font = font(bold=True, size=10, color=NAVY)
c.fill = fill(LIGHT_BLUE)
c.alignment = align("center")
# Best score tracker
ws_mock.row_dimensions[12].height = 20
ws_mock.merge_cells("B12:D12")
ws_mock.cell(row=12, column=2, value="Best Score So Far:").font = font(bold=True, size=10)
c = ws_mock.cell(row=12, column=3, value="=IFERROR(MAX(C4:C7),\"-\")")
c.font = Font(name="Arial", bold=True, size=16, color=GREEN)
c.fill = fill(LIGHT_GRN)
c.alignment = align("center")
ws_mock.merge_cells("E12:G12")
ws_mock.cell(row=12, column=5, value="Improvement (Mock4-Mock1):").font = font(bold=True, size=10)
c = ws_mock.cell(row=12, column=6, value="=IFERROR(C7-C4,\"-\")")
c.font = Font(name="Arial", bold=True, size=16, color=BLUE)
c.alignment = align("center")
# ══════════════════════════════════════════════════════════════════════════════
# SHEET 5: WEAK TOPICS LOG
# ══════════════════════════════════════════════════════════════════════════════
ws_weak = wb.create_sheet("Weak Topics Log")
ws_weak.sheet_properties.tabColor = RED
weak_col_widths = [5, 8, 22, 40, 16, 14, 30, 20]
for i, w in enumerate(weak_col_widths, 1):
ws_weak.column_dimensions[get_column_letter(i)].width = w
ws_weak.row_dimensions[1].height = 10
ws_weak.merge_cells("A2:H2")
c = ws_weak["A2"]
c.value = "WEAK TOPICS TRACKER — Log every topic you get wrong more than twice"
c.font = Font(name="Arial", bold=True, size=13, color=WHITE)
c.fill = fill(RED)
c.alignment = align("center")
ws_weak.row_dimensions[2].height = 30
weak_headers = ["#", "Date Flagged", "Subject", "Weak Topic / Concept", "Times Wrong",
"Priority", "Revision Action", "Resolved (date)"]
weak_hcols = [GRAY_DARK, RED, RED, RED, RED, RED, PURPLE, GREEN]
ws_weak.row_dimensions[3].height = 22
for j, (h, hc) in enumerate(zip(weak_headers, weak_hcols), 1):
c = ws_weak.cell(row=3, column=j, value=h)
c.font = font(bold=True, size=9, color=WHITE)
c.fill = fill(hc)
c.alignment = align("center", wrap=True)
# Data validation for Priority
dv_priority = DataValidation(type="list", formula1='"High,Medium,Low"', allow_blank=True)
ws_weak.add_data_validation(dv_priority)
dv_priority.sqref = "F4:F53"
# Pre-fill some common weak areas as examples
example_weak = [
("Cardiology", "HFpEF treatment vs HFrEF differences", 0, "High", "Re-watch Marrow lecture on HF"),
("Nephrology", "SIADH vs DI vs Cerebral salt wasting", 0, "High", "Draw comparison table"),
("Neurology", "tPA contraindications complete list", 0, "High", "Flashcard all contraindications"),
("Haematology", "HIT - 4T score calculation", 0, "Medium", "Practice scoring with cases"),
("Endocrinology", "MEN syndrome components", 0, "Medium", "Mnemonics + Marrow QBank"),
]
for i, (subj, topic, times, priority, action) in enumerate(example_weak):
r = 4 + i
ws_weak.row_dimensions[r].height = 22
ws_weak.cell(row=r, column=1, value=i+1).font = font(bold=True, size=9, color=GRAY_DARK)
ws_weak.cell(row=r, column=2, value="").number_format = "DD MMM YYYY"
ws_weak.cell(row=r, column=3, value=subj).font = Font(name="Arial", bold=True, size=9, color=SUBJECT_COLORS[subj][0])
ws_weak.cell(row=r, column=3).fill = fill(SUBJECT_COLORS[subj][1])
ws_weak.cell(row=r, column=4, value=topic).font = font(size=9)
ws_weak.cell(row=r, column=5, value=times).font = font(size=9)
ws_weak.cell(row=r, column=5).alignment = align("center")
ws_weak.cell(row=r, column=6, value=priority).font = font(bold=True, size=9, color=RED if priority=="High" else AMBER)
ws_weak.cell(row=r, column=7, value=action).font = font(size=8, italic=True)
for col in range(1,9):
ws_weak.cell(row=r, column=col).border = border("thin")
# Add 30 more blank rows
for i in range(5, 35):
r = 4 + i
ws_weak.row_dimensions[r].height = 20
ws_weak.cell(row=r, column=1, value=i+1).font = font(size=8, color=GRAY_DARK)
for col in range(2,9):
ws_weak.cell(row=r, column=col).border = border("thin", "E8E8E8")
ws_weak.cell(row=r, column=col).fill = fill(GRAY)
ws_weak.conditional_formatting.add("E4:E40",
ColorScaleRule(
start_type="num", start_value=0, start_color="FFFFFF",
end_type="num", end_value=5, end_color="E74C3C"
)
)
ws_weak.conditional_formatting.add("F4:F40",
CellIsRule(operator="equal", formula=['"High"'],
fill=fill(RED_LT), font=Font(name="Arial", bold=True, size=9, color=RED)))
# ══════════════════════════════════════════════════════════════════════════════
# SHEET 6: TIMETABLE OVERVIEW
# ══════════════════════════════════════════════════════════════════════════════
ws_tt = wb.create_sheet("Timetable Overview")
ws_tt.sheet_properties.tabColor = PURPLE
tt_col_widths = [5, 10, 12, 12, 24, 18, 22, 14]
for i, w in enumerate(tt_col_widths, 1):
ws_tt.column_dimensions[get_column_letter(i)].width = w
ws_tt.merge_cells("A1:H1")
c = ws_tt["A1"]
c.value = "2-MONTH STUDY TIMETABLE OVERVIEW | June 27 – August 25, 2026"
c.font = Font(name="Arial", bold=True, size=14, color=WHITE)
c.fill = fill(NAVY)
c.alignment = align("center")
ws_tt.row_dimensions[1].height = 32
tt_headers = ["Day", "Date", "Week", "Phase", "Subject", "Topics", "Textbook Reference", "Planned Qs"]
for j, h in enumerate(tt_headers, 1):
c = ws_tt.cell(row=2, column=j, value=h)
c.font = font(bold=True, size=9, color=WHITE)
c.fill = fill(NAVY)
c.alignment = align("center", wrap=True)
ws_tt.row_dimensions[2].height = 22
ws_tt.freeze_panes = "A3"
PHASE_MAP = {
1: "Deep Study", 2: "Deep Study", 3: "Deep Study", 4: "Deep Study",
5: "Deep Study", 6: "Deep Study",
7: "Revision 1", 8: "Targeted + Mocks", 9: "Final Sprint"
}
for idx, entry in enumerate(TIMETABLE):
day_num, week_num, subject, topics, textbook = entry
r = idx + 3
d = START_DATE + timedelta(days=idx)
dark_c, light_c = SUBJECT_COLORS.get(subject, (GRAY_DARK, GRAY))
ws_tt.row_dimensions[r].height = 22
phase = PHASE_MAP.get(week_num, "Final Sprint")
if "MOCK TEST" in subject:
planned_qs = 200
elif "REVISION" in subject or "FINAL REVISION" in subject:
planned_qs = 50
elif "RECENT ADVANCES" in subject or "WEAK AREAS" in subject:
planned_qs = 40
else:
planned_qs = 35
vals = [day_num, d.strftime("%d %b"), f"Week {week_num}", phase, subject, topics, textbook, planned_qs]
for j, val in enumerate(vals, 1):
c = ws_tt.cell(row=r, column=j, value=val)
c.font = font(size=9)
c.border = border("thin", "D5D8DC")
c.alignment = align("left" if j in [5,6,7] else "center", wrap=(j in [6,7]))
if j == 1:
c.font = Font(name="Arial", bold=True, size=10, color=WHITE)
c.fill = fill(dark_c)
c.alignment = align("center")
elif j == 5:
c.font = Font(name="Arial", bold=True, size=9, color=dark_c)
c.fill = fill(light_c)
elif j == 6:
c.font = font(size=8, color="2C3E50")
elif j == 7:
c.font = font(size=7.5, color=GRAY_DARK, italic=True)
# ══════════════════════════════════════════════════════════════════════════════
# FINAL POLISH - set Dashboard as active sheet
# ══════════════════════════════════════════════════════════════════════════════
wb.active = ws_dash
# Print settings
for ws in [ws_dash, ws_daily, ws_subj, ws_mock, ws_weak, ws_tt]:
ws.print_title_rows = "1:1"
ws.page_setup.orientation = "landscape"
ws.page_setup.fitToPage = True
ws.page_setup.fitToWidth = 1
OUTPUT = "/home/daytona/workspace/neet-ss-guide/NEET_SS_60Day_Study_Tracker.xlsx"
wb.save(OUTPUT)
print(f"Saved: {OUTPUT}")
cd /home/daytona/workspace/neet-ss-guide && python build_tracker.py 2>&1
~/neet-ss-guide/build_tracker.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/neet-ss-guide/build_tracker.py'
cd /home/daytona/workspace/neet-ss-guide && python build_tracker.py 2>&1
python3 -c " import openpyxl wb = openpyxl.Workbook() ws = wb.active ws['A1'] = 'test' wb.save('/tmp/test_xlsx.xlsx') print('tmp write OK') import shutil shutil.copy('/tmp/test_xlsx.xlsx', '/home/daytona/workspace/neet-ss-guide/test.xlsx') print('copy OK') " 2>&1
python3 -c " import shutil, os shutil.copy2('/tmp/test_xlsx.xlsx', '/home/daytona/workspace/neet-ss-guide/test.xlsx') print('copy2 OK') " 2>&1 # Also check if existing xlsx files exist in workspace from previous sessions ls -la /home/daytona/workspace/neet-ss-guide/ 2>&1
~/neet-ss-guide/build_tracker.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/neet-ss-guide/build_tracker.py'
~/neet-ss-guide/build_tracker.py
Error: String not found in file: 'OUTPUT = "/home/daytona/workspace/neet-ss-guide/NEET_SS_60Day_Study_Tracker.xlsx"'
cd /home/daytona/workspace/neet-ss-guide && python build_tracker.py 2>&1
ls -lh /home/daytona/workspace/neet-ss-guide/NEET_SS_60Day_Study_Tracker.xlsx
NEET SS 60Day Study Tracker
Spreadsheet · XLSX
Can you make a pdf of chapters to read from harrison and braunwalds for cardiology for this week
~/neet-ss-guide/build_cardio_reading.py
"""
NEET SS – Week 1 Cardiology Reading Guide
Chapters to read from Harrison's 22E and Braunwald's Heart Disease
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether, PageBreak
)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_RIGHT
PAGE_W, PAGE_H = A4
MARGIN = 14 * mm
# ── Palette ────────────────────────────────────────────────────────────────────
C_NAVY = colors.HexColor("#1A3C5E")
C_BLUE = colors.HexColor("#2E6DA4")
C_SKY = colors.HexColor("#D6EAF8")
C_SKYLT = colors.HexColor("#EBF5FB")
C_RED = colors.HexColor("#C0392B")
C_REDLT = colors.HexColor("#FADBD8")
C_GREEN = colors.HexColor("#1A6B3C")
C_GREENLT = colors.HexColor("#D5F5E3")
C_AMBER = colors.HexColor("#F39C12")
C_AMBERLT = colors.HexColor("#FEF9E7")
C_PURPLE = colors.HexColor("#6C3483")
C_PURPLT = colors.HexColor("#E8DAEF")
C_GRAY = colors.HexColor("#F5F5F5")
C_GRAYMD = colors.HexColor("#BDC3C7")
C_TEXT = colors.HexColor("#1A1A1A")
C_MUTED = colors.HexColor("#555555")
C_BRAUNW = colors.HexColor("#7D0A0A") # deep red for Braunwald
C_HARRIS = colors.HexColor("#0A3D6B") # deep blue for Harrison
def S(name, **kw):
return ParagraphStyle(name, **kw)
TITLE_ST = S("T1", fontSize=22, fontName="Helvetica-Bold",
textColor=colors.white, alignment=TA_CENTER, leading=28)
SUB_ST = S("T2", fontSize=11, fontName="Helvetica",
textColor=colors.HexColor("#AEDAF0"), alignment=TA_CENTER, leading=16)
SEC_ST = S("Sec", fontSize=13, fontName="Helvetica-Bold",
textColor=colors.white, alignment=TA_LEFT, leading=18)
BOOK_ST = S("Book", fontSize=10, fontName="Helvetica-Bold",
textColor=colors.white, alignment=TA_LEFT, leading=14)
CH_HEAD = S("ChH", fontSize=10, fontName="Helvetica-Bold",
textColor=C_NAVY, alignment=TA_LEFT, leading=14)
CH_BODY = S("ChB", fontSize=8.5, fontName="Helvetica",
textColor=C_TEXT, alignment=TA_LEFT, leading=12)
BULLET = S("Bul", fontSize=8.5, fontName="Helvetica",
textColor=C_TEXT, leading=12, leftIndent=10)
KEY_ST = S("Key", fontSize=8, fontName="Helvetica-Bold",
textColor=C_GREEN, leading=11, leftIndent=10)
ALERT_ST = S("Alt", fontSize=8, fontName="Helvetica-Bold",
textColor=C_RED, leading=11, leftIndent=10)
TIP_ST = S("Tip", fontSize=8, fontName="Helvetica",
textColor=C_MUTED, leading=11, italic=True)
PG_HDR = S("PgH", fontSize=7, fontName="Helvetica-Bold",
textColor=colors.white, leading=10)
LABEL_ST = S("Lbl", fontSize=7.5, fontName="Helvetica-Bold",
textColor=colors.white, alignment=TA_CENTER, leading=10)
DAY_ST = S("Day", fontSize=9, fontName="Helvetica-Bold",
textColor=C_NAVY, alignment=TA_CENTER, leading=12)
DAY_SUB = S("DSub", fontSize=8, fontName="Helvetica",
textColor=C_MUTED, alignment=TA_CENTER, leading=11)
def fill_table(data, col_widths, styles_list):
t = Table(data, colWidths=col_widths)
t.setStyle(TableStyle(styles_list))
return t
def sp(h=3):
return Spacer(1, h * mm)
def hr(color=C_GRAYMD, thickness=0.5):
return HRFlowable(width="100%", thickness=thickness, color=color, spaceAfter=2)
# ── Page callbacks ─────────────────────────────────────────────────────────────
def cover_bg(c, doc):
c.saveState()
c.setFillColor(C_NAVY)
c.rect(0, 0, PAGE_W, PAGE_H, fill=1, stroke=0)
c.setFillColor(C_BLUE)
c.rect(0, PAGE_H * 0.38, PAGE_W, PAGE_H * 0.62, fill=1, stroke=0)
c.setFillColor(C_AMBER)
c.rect(0, PAGE_H * 0.38 - 4, PAGE_W, 8, fill=1, stroke=0)
c.restoreState()
def page_header_footer(c, doc):
c.saveState()
# header
c.setFillColor(C_NAVY)
c.rect(0, PAGE_H - 10 * mm, PAGE_W, 10 * mm, fill=1, stroke=0)
c.setFont("Helvetica-Bold", 7)
c.setFillColor(colors.white)
c.drawString(MARGIN, PAGE_H - 6 * mm,
"NEET SS | Week 1 Cardiology | Harrison's 22E + Braunwald's Heart Disease")
c.setFont("Helvetica", 7)
c.drawRightString(PAGE_W - MARGIN, PAGE_H - 6 * mm, f"Page {doc.page}")
# footer
c.setFillColor(C_NAVY)
c.rect(0, 0, PAGE_W, 8 * mm, fill=1, stroke=0)
c.setFont("Helvetica", 7)
c.setFillColor(colors.white)
c.drawString(MARGIN, 3 * mm, "Study reading guide only | Prioritize ★ sections")
c.drawRightString(PAGE_W - MARGIN, 3 * mm, "June 27 – July 3, 2026")
c.restoreState()
# ══════════════════════════════════════════════════════════════════════════════
# CONTENT
# ══════════════════════════════════════════════════════════════════════════════
def section_banner(title, bg_color):
data = [[Paragraph(f" {title}", SEC_ST)]]
t = Table(data, colWidths=[PAGE_W - 2 * MARGIN])
t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), bg_color),
("TOPPADDING", (0, 0), (-1, -1), 8),
("BOTTOMPADDING", (0, 0), (-1, -1), 8),
("LEFTPADDING", (0, 0), (-1, -1), 12),
]))
return t
def book_banner(title, subtitle, bg_color):
data = [
[Paragraph(title, BOOK_ST)],
[Paragraph(subtitle, S("BS2", fontSize=8, fontName="Helvetica",
textColor=colors.HexColor("#FFCCCC") if "Braunwald" in title
else colors.HexColor("#AEDAF0"), leading=11))],
]
t = Table(data, colWidths=[PAGE_W - 2 * MARGIN])
t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), bg_color),
("TOPPADDING", (0, 0), (-1, -1), 6),
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 12),
]))
return t
def chapter_card(ch_num, ch_title, pages, day_label, priority,
sections, tips, width=None, book="harrison"):
if width is None:
width = PAGE_W - 2 * MARGIN
bg = C_SKYLT if book == "harrison" else colors.HexColor("#FDF2F2")
hdr_bg = C_SKY if book == "harrison" else colors.HexColor("#F5C6C6")
bdr_color = C_BLUE if book == "harrison" else C_BRAUNW
rows = []
# Chapter header row
col_w1 = 16 * mm
col_w2 = width - col_w1 - 28 * mm
col_w3 = 28 * mm
# Priority badge color
pri_colors = {
"MUST READ": (C_RED, C_REDLT),
"HIGH YIELD": (C_GREEN, C_GREENLT),
"SKIM": (C_AMBER, C_AMBERLT),
"REFERENCE": (colors.HexColor("#7D6608"), colors.HexColor("#FEF9E7")),
}
p_fg, p_bg = pri_colors.get(priority, (C_NAVY, C_SKY))
hdr_data = [
[
Paragraph(f"Ch {ch_num}", S("CN", fontSize=14, fontName="Helvetica-Bold",
textColor=C_HARRIS if book=="harrison" else C_BRAUNW,
alignment=TA_CENTER, leading=18)),
Paragraph(f"<b>{ch_title}</b><br/>"
f"<font size='8' color='#555555'>Pages {pages}</font>",
S("CT", fontSize=9.5, fontName="Helvetica-Bold",
textColor=C_TEXT, leading=13)),
Paragraph(priority, S("PR", fontSize=7.5, fontName="Helvetica-Bold",
textColor=p_fg, alignment=TA_CENTER, leading=11)),
]
]
hdr_t = Table(hdr_data, colWidths=[col_w1, col_w2, col_w3])
hdr_t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), hdr_bg),
("BACKGROUND", (2, 0), (2, 0), p_bg),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
("TOPPADDING", (0, 0), (-1, -1), 7),
("BOTTOMPADDING", (0, 0), (-1, -1), 7),
("LEFTPADDING", (0, 0), (-1, -1), 8),
("RIGHTPADDING", (0, 0), (-1, -1), 6),
("BOX", (0, 0), (-1, -1), 1, bdr_color),
]))
# Day label badge
day_data = [[
Paragraph(f"📅 {day_label}", S("DL", fontSize=8, fontName="Helvetica-Bold",
textColor=C_NAVY if book=="harrison" else C_BRAUNW,
leading=11)),
]]
day_t = Table(day_data, colWidths=[width])
day_t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), bg),
("TOPPADDING", (0, 0), (-1, -1), 3),
("BOTTOMPADDING", (0, 0), (-1, -1), 2),
("LEFTPADDING", (0, 0), (-1, -1), 10),
]))
# Sections to read
sec_rows = []
for sec_title, sec_notes, must in sections:
icon = "★" if must else "•"
fc = C_GREEN if must else C_TEXT
sec_rows.append([
Paragraph(f"<font color='#{C_GREEN.hexval()[2:] if must else '555555'}'>{icon}</font> "
f"<b>{sec_title}</b>",
S("SR", fontSize=8.5, fontName="Helvetica-Bold" if must else "Helvetica",
textColor=fc, leading=12, leftIndent=8)),
Paragraph(sec_notes, S("SN", fontSize=7.5, fontName="Helvetica",
textColor=C_MUTED, leading=11, italic=True)),
])
if sec_rows:
sec_col_w = [width * 0.48, width * 0.52]
sec_t = Table(sec_rows, colWidths=sec_col_w)
sec_t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), bg),
("TOPPADDING", (0, 0), (-1, -1), 3),
("BOTTOMPADDING", (0, 0), (-1, -1), 3),
("LEFTPADDING", (0, 0), (-1, -1), 8),
("RIGHTPADDING", (0, 0), (-1, -1), 6),
("LINEBELOW", (0, 0), (-1, -2), 0.3, C_GRAYMD),
("BOX", (0, 0), (-1, -1), 0.5, bdr_color),
]))
else:
sec_t = None
# Tips/exam focus row
if tips:
tip_data = [[
Paragraph(f"<b>Exam Focus:</b> {tips}",
S("TipRow", fontSize=7.5, fontName="Helvetica",
textColor=C_MUTED, leading=11, leftIndent=8)),
]]
tip_t = Table(tip_data, colWidths=[width])
tip_t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), C_AMBERLT),
("TOPPADDING", (0, 0), (-1, -1), 4),
("BOTTOMPADDING", (0, 0), (-1, -1), 4),
("LEFTPADDING", (0, 0), (-1, -1), 10),
("BOX", (0, 0), (-1, -1), 0.5, C_AMBER),
]))
else:
tip_t = None
parts = [hdr_t, day_t]
if sec_t:
parts.append(sec_t)
if tip_t:
parts.append(tip_t)
outer_data = [[p] for p in parts]
outer = Table(outer_data, colWidths=[width])
outer.setStyle(TableStyle([
("TOPPADDING", (0, 0), (-1, -1), 0),
("BOTTOMPADDING", (0, 0), (-1, -1), 0),
("LEFTPADDING", (0, 0), (-1, -1), 0),
("RIGHTPADDING", (0, 0), (-1, -1), 0),
("BOX", (0, 0), (-1, -1), 1.5, bdr_color),
]))
return outer
# ══════════════════════════════════════════════════════════════════════════════
# STORY
# ══════════════════════════════════════════════════════════════════════════════
def build_story():
story = []
# ── Cover ──────────────────────────────────────────────────────────────────
story.append(sp(50))
story.append(Paragraph("NEET SS · Week 1 Reading Guide", TITLE_ST))
story.append(sp(2))
story.append(Paragraph("CARDIOLOGY", S("T3", fontSize=28, fontName="Helvetica-Bold",
textColor=C_AMBER, alignment=TA_CENTER, leading=34)))
story.append(sp(3))
story.append(Paragraph("Harrison's Principles of Internal Medicine 22E + Braunwald's Heart Disease",
SUB_ST))
story.append(sp(1))
story.append(Paragraph("June 27 – July 3, 2026 | Day 1 – Day 7", SUB_ST))
story.append(sp(10))
# cover legend box
legend_data = [
[Paragraph("<b>How to Use This Guide</b>",
S("LH", fontSize=10, fontName="Helvetica-Bold",
textColor=C_NAVY, leading=14))],
[Paragraph("★ <b>Starred sections</b> = MUST READ for NEET SS. These are directly exam-tested.",
BULLET)],
[Paragraph("• <b>Bullet sections</b> = Read if time permits; helps conceptual understanding.",
BULLET)],
[Paragraph("<b>Exam Focus</b> boxes (amber) = Specific facts, numbers, and criteria to memorise.",
BULLET)],
[Paragraph("<b>Priority labels:</b> MUST READ > HIGH YIELD > SKIM > REFERENCE",
BULLET)],
[Paragraph("Workflow: Marrow lecture first → then read the marked sections → attempt QBank.",
BULLET)],
[Paragraph("<b>Harrison's 22E</b> (2025) chapters listed with page ranges from actual book.",
S("LN", fontSize=8, fontName="Helvetica", textColor=C_MUTED,
leading=11, italic=True))],
[Paragraph("<b>Braunwald's Heart Disease</b> chapters listed with page ranges from actual book.",
S("LN2", fontSize=8, fontName="Helvetica", textColor=C_MUTED,
leading=11, italic=True))],
]
leg_t = Table(legend_data, colWidths=[130 * mm])
leg_t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), C_SKYLT),
("BACKGROUND", (0, 0), (0, 0), C_SKY),
("BOX", (0, 0), (-1, -1), 1, C_BLUE),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING", (0, 0), (-1, -1), 4),
("LEFTPADDING", (0, 0), (-1, -1), 12),
]))
story.append(leg_t)
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════
# WEEK OVERVIEW TABLE
# ══════════════════════════════════════════════════════════════════════════
story.append(section_banner("WEEK 1 OVERVIEW — Cardiology (Day 1–7)", C_NAVY))
story.append(sp(3))
overview_hdr = [["Day", "Date", "Topic", "Harrison's Chapter", "Braunwald's Chapter", "Marrow Qs"]]
overview_rows = [
["1", "27 Jun", "ACS – STEMI Management", "Ch 286 (pp 1823-1842)", "Ch 59 (pp 1058-1118)", "30 Qs"],
["2", "28 Jun", "ACS – NSTEMI/UA & Antiplatelets", "Ch 285 (pp 1808-1822)", "Ch 58 (pp 1011-1057)", "30 Qs"],
["3", "29 Jun", "Heart Failure (HFrEF & HFpEF)", "Ch 279 (pp 1732-1757)", "Ch 52-53 (pp 799-889)", "30 Qs"],
["4", "30 Jun", "Valvular Heart Disease", "Ch 282 (pp 1775-1799)", "Ch 75-78 (pp 1385-1519)", "25 Qs"],
["5", "1 Jul", "Arrhythmias – AF, SVT, VT", "Ch 280-281 (pp 1758-1774)", "Ch 64-66 (pp 1199-1302)", "30 Qs"],
["6", "2 Jul", "Cardiomyopathies & Pericardial", "Ch 283-284 (pp 1800-1808)", "Ch 71-72 (pp 1303-1380)", "25 Qs"],
["7", "3 Jul", "REVISION – Full Cardiology Test", "All above chapters (review notes)", "All above chapters", "Mock: 50 Qs"],
]
all_rows = overview_hdr + overview_rows
col_ws = [10*mm, 14*mm, 44*mm, 40*mm, 42*mm, 18*mm]
ov_t = Table(all_rows, colWidths=col_ws)
ov_t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), C_NAVY),
("TEXTCOLOR", (0, 0), (-1, 0), colors.white),
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
("FONTSIZE", (0, 0), (-1, 0), 8),
("BACKGROUND", (0, 1), (-1, 1), colors.HexColor("#EAF4FB")),
("BACKGROUND", (0, 2), (-1, 2), colors.HexColor("#FDF2F2")),
("BACKGROUND", (0, 3), (-1, 3), colors.HexColor("#EAF4FB")),
("BACKGROUND", (0, 4), (-1, 4), colors.HexColor("#FDF2F2")),
("BACKGROUND", (0, 5), (-1, 5), colors.HexColor("#EAF4FB")),
("BACKGROUND", (0, 6), (-1, 6), colors.HexColor("#FDF2F2")),
("BACKGROUND", (0, 7), (-1, 7), colors.HexColor("#D5F5E3")),
("FONTNAME", (0, 1), (-1, -1), "Helvetica"),
("FONTSIZE", (0, 1), (-1, -1), 8),
("ALIGN", (0, 0), (-1, -1), "CENTER"),
("ALIGN", (2, 0), (2, -1), "LEFT"),
("ALIGN", (3, 0), (4, -1), "LEFT"),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
("ROWBACKGROUNDS", (0, 0), (-1, -1), None),
("GRID", (0, 0), (-1, -1), 0.5, C_GRAYMD),
("TOPPADDING", (0, 0), (-1, -1), 6),
("BOTTOMPADDING", (0, 0), (-1, -1), 6),
("LEFTPADDING", (0, 0), (-1, -1), 6),
("FONTNAME", (0, 7), (-1, 7), "Helvetica-Bold"),
("TEXTCOLOR", (0, 7), (-1, 7), C_GREEN),
]))
story.append(ov_t)
story.append(sp(4))
# Reading load summary
summary_data = [[
Paragraph("Total pages to read this week:", S("SL", fontSize=9, fontName="Helvetica-Bold",
textColor=C_NAVY, leading=12)),
Paragraph("<b>Harrison's 22E:</b> ~120 pages (selective sections only)<br/>"
"<b>Braunwald's:</b> ~180 pages (starred sections only)<br/>"
"<b>Total Marrow Qs:</b> ~200 Qs over 7 days",
S("SB", fontSize=8.5, fontName="Helvetica", textColor=C_TEXT, leading=13)),
Paragraph("<b>Strategy reminder:</b><br/>Watch Marrow lecture → Read starred sections → Do QBank on SAME day.",
S("SS", fontSize=8, fontName="Helvetica", textColor=C_MUTED, leading=12, italic=True)),
]]
sum_t = Table(summary_data, colWidths=[40*mm, 70*mm, 57*mm])
sum_t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), C_AMBERLT),
("BOX", (0, 0), (-1, -1), 1, C_AMBER),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("TOPPADDING", (0, 0), (-1, -1), 8),
("BOTTOMPADDING", (0, 0), (-1, -1), 8),
("LEFTPADDING", (0, 0), (-1, -1), 8),
]))
story.append(sum_t)
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════
# HARRISON'S 22E SECTION
# ══════════════════════════════════════════════════════════════════════════
story.append(book_banner(
"Harrison's Principles of Internal Medicine 22E (2025 Edition)",
"McGraw Hill Medical | ISBN 978-1-26-597706-1 | Chapters from Part 9: Disorders of the Cardiovascular System",
C_HARRIS
))
story.append(sp(3))
# ── Day 1 & 2: ACS ──────────────────────────────────────────────────────
story.append(section_banner("Days 1–2: Acute Coronary Syndromes", C_BLUE))
story.append(sp(2))
cards_acs = [
chapter_card(
ch_num="285",
ch_title="Non-ST-Elevation Acute Coronary Syndrome",
pages="pp 1808–1822",
day_label="Day 2 (June 28)",
priority="MUST READ",
sections=[
("Pathophysiology of ACS", "Plaque rupture, thrombus, vasospasm", True),
("Clinical Presentation", "Typical vs atypical symptoms, Killip classification", True),
("Diagnosis: Biomarkers", "Troponin kinetics, high-sensitivity assay cutoffs", True),
("Risk Stratification: TIMI & GRACE scores", "Score components, threshold for invasive strategy", True),
("Antiplatelet Therapy", "Aspirin + P2Y12 inhibitors; Ticagrelor vs Clopidogrel (PLATO trial)", True),
("Anticoagulation: Fondaparinux vs UFH vs LMWH", "When to choose each; avoid fondaparinux if PCI planned", True),
("Invasive vs Conservative Strategy (Fig 285-4)", "Timing thresholds: <24h, <72h criteria", True),
("GP IIb/IIIa inhibitors", "Role now limited to bailout PCI only", False),
("Secondary Prevention", "Statin targets, ACEi, BB post-ACS", False),
],
tips="TIMI score thresholds, door-to-balloon times, Ticagrelor advantages over Clopidogrel (PLATO), Fondaparinux avoidance with PCI – all are frequent MCQ triggers.",
book="harrison"
),
chapter_card(
ch_num="286",
ch_title="ST-Elevation Myocardial Infarction (STEMI)",
pages="pp 1823–1842",
day_label="Day 1 (June 27)",
priority="MUST READ",
sections=[
("Pathophysiology & ECG Localisation", "Territory → artery mapping; posterior MI = V1-V3 changes", True),
("Reperfusion: Primary PCI", "Door-to-balloon <90 min; <120 min if transfer needed", True),
("Reperfusion: Fibrinolysis", "When to use (PCI unavailable, onset <12h); D2N <30 min", True),
("Antithrombotic in STEMI", "Aspirin + Ticagrelor; UFH/Bivalirudin with PCI; avoid Fondaparinux", True),
("Cardiogenic Shock Management", "Intra-aortic balloon pump; ECMO indications", True),
("STEMI Complications", "Mechanical: VSD, MR, free wall rupture; arrhythmic: VF, AVB", True),
("Post-MI Management", "GDMT initiation: BB, ACEi, statin, antiplatelet duration", True),
("Right Ventricular Infarction", "ST elevation V4R; avoid nitrates/diuretics; fluid load", True),
("Reperfusion Injury", "No-reflow, microvascular obstruction", False),
],
tips="Door-to-balloon 90 min (direct) / 120 min (transfer). Fibrinolysis 30 min D2N. Contraindications to tPA (all 10 absolute). RV infarct: avoid nitrates – most tested STEMI pitfall.",
book="harrison"
),
]
for card in cards_acs:
story.append(KeepTogether([card, sp(3)]))
story.append(PageBreak())
# ── Day 3: Heart Failure ─────────────────────────────────────────────────
story.append(section_banner("Day 3: Heart Failure", C_BLUE))
story.append(sp(2))
hf_card = chapter_card(
ch_num="279",
ch_title="Heart Failure and Cor Pulmonale",
pages="pp 1732–1757",
day_label="Day 3 (June 29)",
priority="MUST READ",
sections=[
("HFrEF vs HFpEF vs HFmrEF: Definitions", "EF cutoffs, pathophysiology differences", True),
("GDMT for HFrEF – 4 Pillars", "ACEi/ARB/ARNI + BB + MRA + SGLT2i; each pillar's trial", True),
("ARNI (Sacubitril/Valsartan)", "PARADIGM-HF: 20% RRR vs Enalapril; when to switch", True),
("SGLT2i in HF", "DAPA-HF (Dapagliflozin), EMPEROR (Empagliflozin); non-diabetic benefit", True),
("Device Therapy: ICD & CRT", "Criteria: EF <35%, NYHA II-III, >3 months GDMT; LBBB for CRT", True),
("Acute Decompensated HF Management", "IV diuretics, vasodilators, ultrafiltration indications", True),
("HFpEF Management", "SGLT2i (EMPEROR-Preserved); MRA; volume management", True),
("Cor Pulmonale", "Causes, ECG, management of right HF", False),
("Haemodynamic Profiles: Warm/Dry, Wet/Cold", "4 profiles and treatment approach per profile", False),
("Biomarkers: BNP & NT-proBNP", "Cutoffs, causes of false elevation (obesity lowers BNP)", False),
],
tips="GDMT 4-drug regimen for HFrEF, trial names (PARADIGM, DAPA-HF, EMPEROR), ICD criteria (EF <35% + 3 months GDMT), HFpEF vs HFrEF mortality trial data – all high-frequency MCQ content.",
book="harrison"
)
story.append(hf_card)
story.append(sp(3))
story.append(PageBreak())
# ── Day 4: Valvular ──────────────────────────────────────────────────────
story.append(section_banner("Day 4: Valvular Heart Disease", C_BLUE))
story.append(sp(2))
valv_card = chapter_card(
ch_num="282",
ch_title="Valvular Heart Disease",
pages="pp 1775–1799",
day_label="Day 4 (June 30)",
priority="MUST READ",
sections=[
("Aortic Stenosis: Severity Criteria", "Severe: AVA <1 cm², mean gradient >40 mmHg, Vmax >4 m/s", True),
("AS: Surgical vs TAVI Decision", "PARTNER 3: TAVI equivalent to SAVR in low risk at 2yr; STS score", True),
("AS: Paradoxical Low-Flow Low-Gradient", "Normal EF + low gradient + low AVA: dobutamine stress echo", True),
("Mitral Regurgitation: Indications for Surgery", "EF <60% OR LVESD >40 mm; earlier if repairable", True),
("Mitral Stenosis: Wilkins Score & PBMC", "MVA <1.5 cm²; PBMC if Wilkins ≤8; avoid if LA thrombus", True),
("Aortic Regurgitation: Surgical Timing", "EF <50% OR LVESD >50 mm (or >25 mm/m²)", True),
("RHD & Penicillin Prophylaxis Duration", "10yr or age 40 (whichever longer); severe MR: lifelong", True),
("Infective Endocarditis Prophylaxis", "Only for prosthetic valves, prior IE, unrepaired CHD", False),
("Prosthetic Valve Anticoagulation", "Mechanical: warfarin; bioprosthetic: aspirin ± anticoag 3m", False),
],
tips="Severity thresholds for all 4 valves, intervention timing criteria, PARTNER 3 trial results, Wilkins score cutoff for PBMC, penicillin prophylaxis durations – all memorisable and directly tested.",
book="harrison"
)
story.append(valv_card)
story.append(sp(3))
story.append(PageBreak())
# ── Day 5: Arrhythmias ───────────────────────────────────────────────────
story.append(section_banner("Day 5: Cardiac Arrhythmias", C_BLUE))
story.append(sp(2))
arrh_cards = [
chapter_card(
ch_num="280",
ch_title="Principles of Electrophysiology",
pages="pp 1758–1764",
day_label="Day 5 (July 1)",
priority="SKIM",
sections=[
("Normal Conduction System", "SA node → AV node → His-Purkinje; refractory periods", False),
("Action Potential Phases", "Phase 0-4 for different cell types; drug targets", False),
("Mechanisms of Arrhythmia", "Reentry, automaticity, triggered activity", True),
],
tips="Read selectively – reentry mechanisms and action potential phases are MCQ-tested.",
book="harrison"
),
chapter_card(
ch_num="281",
ch_title="Diagnosis & Treatment of Cardiac Arrhythmias",
pages="pp 1765–1800 (Key sections only)",
day_label="Day 5 (July 1)",
priority="MUST READ",
sections=[
("Atrial Fibrillation: Classification", "Paroxysmal/Persistent/Long-standing/Permanent definitions", True),
("AF: Rate vs Rhythm Control", "EAST-AFNET 4: early rhythm control superior; RACE II: lenient rate OK", True),
("AF: Rate Control Drugs", "BB > non-DHP CCB (diltiazem/verapamil) > Digoxin (last resort)", True),
("AF: Rhythm Control Drugs", "Flecainide (no structural disease), Amiodarone, Dronedarone", True),
("AF: Anticoagulation – CHA₂DS₂-VASc", "Score ≥2 men / ≥3 women → OAC; DOACs > Warfarin", True),
("Valvular AF", "Rheumatic MS / mechanical valve → Warfarin ONLY (no DOAC)", True),
("AF Ablation: Pulmonary Vein Isolation", "Indication: symptomatic, drug-refractory; cure rates", True),
("SVT: AVNRT vs AVRT", "Vagal manoeuvres → Adenosine → Ablation (90%+ cure rate)", True),
("VT: Sustained vs Non-Sustained", "ICD indications; VT storm management", True),
("Channelopathies: Long QT, Brugada, CPVT", "Triggers, ECG pattern, treatment – high yield", True),
("Torsades de Pointes", "QTc >500, stop offending drug, IV MgSO₄, overdrive pacing", True),
],
tips="CHA₂DS₂-VASc score by heart (all 8 components), DOAC contraindications (valvular AF), Brugada ECG pattern, Long QT drugs to avoid, Adenosine dose (6mg then 12mg) – all classic MCQ material.",
book="harrison"
),
]
for card in arrh_cards:
story.append(KeepTogether([card, sp(3)]))
story.append(PageBreak())
# ── Day 6: Cardiomyopathies + Pericardial ──────────────────────────────
story.append(section_banner("Day 6: Cardiomyopathies & Pericardial Disease", C_BLUE))
story.append(sp(2))
cmp_cards = [
chapter_card(
ch_num="283",
ch_title="Cardiomyopathy and Myocarditis",
pages="pp 1800–1805",
day_label="Day 6 (July 2)",
priority="HIGH YIELD",
sections=[
("HCM: Pathophysiology & LVOT Obstruction", "Asymmetric septal hypertrophy, SAM, dynamic gradient", True),
("HCM: ECG and Echo Findings", "LVH, septal Q waves, septal thickness ≥15 mm", True),
("HCM: SCD Risk Stratification", "5 risk factors: thickness ≥30mm, NSVT, family h/o SCD, abnormal BP response, unexplained syncope", True),
("HCM: Management", "BB/Verapamil; Mavacamten (myosin inhibitor); ICD; septal ablation", True),
("Dilated CM: Causes & Management", "Alcohol, viral, thyroid, peripartum; GDMT same as HFrEF", True),
("ARVC: ECG & Risk", "Epsilon wave, T-wave V1-V3 inversion; sudden death in athletes", True),
("Restrictive CM: vs Constrictive Pericarditis", "Key differentiating features on echo/catheter", True),
("Myocarditis", "Viral (Parvovirus B19, Coxsackie), giant cell myocarditis; biopsy Dallas criteria", False),
],
tips="HCM SCD risk factors (all 5), Mavacamten mechanism, HCM+AF → anticoagulate regardless of CHA₂DS₂-VASc. ARVC epsilon wave location. DCM causes (reversible ones are exam favourites).",
book="harrison"
),
chapter_card(
ch_num="284",
ch_title="Pericardial Disease",
pages="pp 1805–1808",
day_label="Day 6 (July 2)",
priority="HIGH YIELD",
sections=[
("Acute Pericarditis: Diagnosis & Treatment", "2/4 diagnostic criteria; NSAIDs + Colchicine (COPE trial)", True),
("Pericardial Tamponade: Beck's Triad", "Hypotension + JVP raised + muffled heart sounds", True),
("Tamponade: ECG & Echo Findings", "Electrical alternans; RA/RV collapse; pulsus paradoxus >10", True),
("Tamponade vs Constrictive Pericarditis", "Pulsus paradoxus, Kussmaul's sign, square root sign on catheter", True),
("Constrictive Pericarditis", "Post-TB / post-radiation; pericardiectomy definitive", True),
("Pericarditis in Systemic Disease", "SLE, uraemia (uraemic pericarditis – dialysis indication), drug-induced", False),
],
tips="Beck's triad, pulsus paradoxus definition and measurement, Kussmaul's sign (raised JVP on inspiration – only in constrictive pericarditis, NOT tamponade), Colchicine halves recurrence – all tested.",
book="harrison"
),
]
for card in cmp_cards:
story.append(KeepTogether([card, sp(3)]))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════
# BRAUNWALD'S SECTION
# ══════════════════════════════════════════════════════════════════════════
story.append(book_banner(
"Braunwald's Heart Disease: A Textbook of Cardiovascular Medicine",
"Elsevier | ISBN 978-0-323-72219-3 | 12th Edition | Use for deeper clinical detail on exam-heavy topics",
C_BRAUNW
))
story.append(sp(3))
# Important note on Braunwald approach
braunw_note = [[
Paragraph(
"<b>Reading strategy for Braunwald's:</b> This is a reference text (~3000 pages). "
"Do NOT read full chapters. Use Braunwald's only for the specific sub-sections listed below, "
"after completing the equivalent Harrison's chapter. Focus on guidelines tables, "
"management algorithms, and landmark trial summaries embedded in each chapter.",
S("BN", fontSize=8.5, fontName="Helvetica", textColor=C_TEXT, leading=13)
)
]]
bn_t = Table(braunw_note, colWidths=[PAGE_W - 2 * MARGIN])
bn_t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), colors.HexColor("#FFF5F5")),
("BOX", (0, 0), (-1, -1), 1, C_BRAUNW),
("TOPPADDING", (0, 0), (-1, -1), 8),
("BOTTOMPADDING", (0, 0), (-1, -1), 8),
("LEFTPADDING", (0, 0), (-1, -1), 12),
]))
story.append(bn_t)
story.append(sp(3))
# Braunwald ACS chapters
story.append(section_banner("Days 1–2: ACS (Braunwald's)", C_BRAUNW))
story.append(sp(2))
braw_acs_cards = [
chapter_card(
ch_num="58",
ch_title="Non-ST-Elevation Acute Coronary Syndrome",
pages="pp 1011–1057",
day_label="Day 2 (June 28) — After Harrison's Ch 285",
priority="HIGH YIELD",
sections=[
("Pathophysiology of Plaque Instability", "Thin-cap fibroatheroma, OCT findings, vulnerable plaque", False),
("Risk Stratification Tables (Tables 58-1 to 58-4)", "TIMI, GRACE, HEART scores – full scoring tables", True),
("Figure 58-5: Antithrombotic Algorithm", "Fondaparinux vs enoxaparin vs UFH decision flowchart", True),
("P2Y12 Inhibitor Comparison Table", "Ticagrelor vs Prasugrel vs Clopidogrel head-to-head", True),
("Timing of Invasive Strategy (Fig 58-7)", "Immediate/Early/Deferred strategies with criteria", True),
("PLATO Trial Summary (Box 58-3)", "Ticagrelor 20% RRR over Clopidogrel; bleeding risk nuance", True),
("Post-Discharge DAPT Duration", "12 months standard; 30 months in high ischaemic risk (DAPT trial)", False),
],
tips="Braunwald has better algorithm figures than Harrison's for ACS antithrombotic choices. Study Fig 58-5 and 58-7 carefully.",
book="braunwald"
),
chapter_card(
ch_num="59",
ch_title="ST-Elevation Myocardial Infarction",
pages="pp 1058–1118",
day_label="Day 1 (June 27) — After Harrison's Ch 286",
priority="MUST READ",
sections=[
("Figure 59-2: Reperfusion Decision Algorithm", "PCI vs fibrinolysis decision tree with time thresholds", True),
("Table 59-3: STEMI Antithrombotic Regimens", "Full drug regimens for PCI vs fibrinolysis scenarios", True),
("Fibrinolytic Contraindications Table (Table 59-4)", "All absolute + relative contraindications – memorise", True),
("Figure 59-6: Mechanical Complications", "VSD, MR, free wall rupture – timing, echo findings, treatment", True),
("Cardiogenic Shock Protocol (Fig 59-8)", "Haemodynamic support options: IABP, Impella, ECMO", True),
("Table 59-7: Post-MI Drug Dosing", "Exact doses for aspirin, BB, ACEi, statin", False),
("STREAM Trial (Box 59-2)", "Fibrinolysis vs primary PCI in rural settings – landmark", True),
("RV Infarction Section", "V4R lead, clinical triad, avoid vasodilators, fluid load", True),
],
tips="Table 59-3 and Fig 59-2 are exam-quality content. Mechanical complication timing post-STEMI (VSD days 3-5, free wall rupture days 1-3) is a classic MCQ area.",
book="braunwald"
),
]
for card in braw_acs_cards:
story.append(KeepTogether([card, sp(3)]))
story.append(PageBreak())
# Braunwald HF
story.append(section_banner("Day 3: Heart Failure (Braunwald's)", C_BRAUNW))
story.append(sp(2))
braw_hf_cards = [
chapter_card(
ch_num="52",
ch_title="Pathophysiology of Heart Failure",
pages="pp 799–835",
day_label="Day 3 (June 29) — Concept building only",
priority="SKIM",
sections=[
("Neurohormonal Activation in HF", "RAAS, sympathetic, natriuretic peptide axes", True),
("Cardiac Remodelling", "Eccentric vs concentric hypertrophy; reverse remodelling with GDMT", True),
("Haemodynamic Profiles", "Forrester classification: Warm/Cold × Wet/Dry", True),
],
tips="Read only the summary sections and figures. This chapter provides the 'why' behind GDMT – useful for clinical reasoning questions.",
book="braunwald"
),
chapter_card(
ch_num="53",
ch_title="Management of Heart Failure (HFrEF and HFpEF)",
pages="pp 836–889",
day_label="Day 3 (June 29) — Core reading",
priority="MUST READ",
sections=[
("Figure 53-1: GDMT Algorithm", "Step-by-step initiation and titration of 4-drug therapy", True),
("Table 53-2: Evidence Summary for GDMT Drugs", "Trial names, drug classes, NNT/ARR – comprehensive", True),
("ARNI: Sacubitril/Valsartan (Box 53-3)", "PARADIGM-HF full results; switching from ACEi (36h washout)", True),
("SGLT2i Evidence Tables", "DAPA-HF + EMPEROR-Reduced results; combined analysis", True),
("ICD/CRT Criteria Table (Table 53-7)", "All indication criteria with NYHA class thresholds", True),
("Diuretic Therapy in ADHF", "IV furosemide dosing, resistance, ultrafiltration", True),
("HFpEF Management (Section 53.4)", "EMPEROR-Preserved: Empagliflozin benefits; TOPCAT: Spiro limited benefit", True),
("Cardiorenal Syndrome", "Types 1-5; worsening renal function in ADHF management", False),
("Advanced HF: LVAD & Transplant", "Bridge-to-transplant, destination therapy; listing criteria", False),
],
tips="Best single reference for complete GDMT evidence. Fig 53-1 algorithm is exam-quality. SGLT2i evidence in non-diabetics tested repeatedly.",
book="braunwald"
),
]
for card in braw_hf_cards:
story.append(KeepTogether([card, sp(3)]))
story.append(PageBreak())
# Braunwald Valvular, Arrhythmias, CMP
story.append(section_banner("Days 4–6: Valvular, Arrhythmias, CMP (Braunwald's)", C_BRAUNW))
story.append(sp(2))
braw_rest = [
chapter_card(
ch_num="75–78",
ch_title="Valvular Heart Disease (AS, MR, MS, AR)",
pages="pp 1385–1519",
day_label="Day 4 (June 30) — Read starred sections only",
priority="HIGH YIELD",
sections=[
("AS: Figure 75-3 – Natural History", "Classic triad onset: Angina →3yr; Syncope →2yr; Dyspnea →1yr", True),
("AS: Table 75-4 – Intervention Criteria (AHA 2021)", "All indication classes I, IIa, IIb tabulated", True),
("AS: TAVI Landmark Trials Summary Box", "PARTNER 1/2/3, EVOLUT – low/intermediate/high risk results", True),
("MR: Table 76-2 – Surgical Timing", "EF and LVESD thresholds for primary vs secondary MR", True),
("MS: Wilkins Score Table (Table 77-3)", "All 4 components scored 1-4; total ≤8 for PBMC", True),
("AR: Management Algorithm (Fig 78-4)", "Medical vs surgical decision based on EF + symptoms", True),
("Anticoagulation in VHD: Table 79-1", "Full anticoagulation guidance for different valve conditions", True),
],
tips="The tables in Braunwald's valvular chapters are the best single source for intervention criteria. AHA guideline tables (2021) reproduced in full – study them directly.",
book="braunwald"
),
chapter_card(
ch_num="64–66",
ch_title="Atrial Fibrillation, SVT, and Ventricular Arrhythmias",
pages="pp 1199–1302",
day_label="Day 5 (July 1) — After Harrison's Ch 281",
priority="HIGH YIELD",
sections=[
("AF: Table 64-1 – CHA₂DS₂-VASc Scoring", "Full table with risk categories and DOAC initiation thresholds", True),
("AF: Table 64-3 – Rate Control Drug Dosing", "IV and oral doses, contraindications for each agent", True),
("AF: Figure 64-7 – Rhythm Control Decision", "When to choose rhythm control; EAST-AFNET 4 incorporated", True),
("AF: Catheter Ablation Outcomes", "Success rates, complications, patient selection", True),
("AVNRT vs AVRT: Electrophysiologic Mechanism", "Dual AV nodal pathways; accessory pathway features", False),
("VT: Sustained Monomorphic VT Algorithm", "Haemodynamically stable vs unstable management", True),
("Channelopathies: Table 65-8", "Long QT subtypes, triggers (LQT1: exercise, LQT2: sounds, LQT3: sleep)", True),
("Brugada Syndrome Diagnostic Criteria", "Type 1 ECG pattern; fever-induced unmasking; ICD criteria", True),
],
tips="Braunwald's channelopathy tables are the best reference for LQT subtypes and Brugada. Table 65-8 alone covers multiple exam questions.",
book="braunwald"
),
chapter_card(
ch_num="71–72",
ch_title="Hypertrophic Cardiomyopathy & Pericardial Diseases",
pages="pp 1303–1380",
day_label="Day 6 (July 2) — After Harrison's Chs 283-284",
priority="HIGH YIELD",
sections=[
("HCM: Table 71-2 – SCD Risk Stratification", "AHA 2020 risk calculator factors; 5-year risk threshold for ICD", True),
("HCM: Figure 71-5 – Medical vs Invasive Algorithm", "Mavacamten, disopyramide, septal myectomy, alcohol ablation", True),
("HCM: Mavacamten (Box 71-3)", "EXPLORER-HCM trial results; cardiac myosin inhibitor mechanism", True),
("HCM+AF: Anticoagulation Recommendation", "All HCM+AF anticoagulate regardless of CHA₂DS₂-VASc score", True),
("Constrictive vs Restrictive: Table 72-4", "Side-by-side comparison of haemodynamics, echo, catheter findings", True),
("Pericarditis: ESC 2015 Guidelines Table", "Aspirin + Colchicine (COPE/ICAP trials); steroid avoidance", True),
("Tamponade: Figure 72-8 – Management", "Pericardiocentesis technique; drainage volume; recurrence", True),
],
tips="HCM risk factors (all 5 from AHA 2020), Mavacamten mechanism (EXPLORER-HCM), constrictive vs restrictive comparison table, and pericarditis guideline-based treatment are all direct exam targets.",
book="braunwald"
),
]
for card in braw_rest:
story.append(KeepTogether([card, sp(3)]))
story.append(PageBreak())
# ── Day 7 Revision Page ───────────────────────────────────────────────────
story.append(section_banner("Day 7 (July 3) — Revision & Full Cardiology Test", C_GREEN))
story.append(sp(3))
rev_data = [
[Paragraph("Day 7 Checklist", S("RH", fontSize=12, fontName="Helvetica-Bold",
textColor=C_GREEN, leading=16))],
[Paragraph("□ Re-read ALL starred (★) sections from Harrison's – do not re-read Braunwald's today", BULLET)],
[Paragraph("□ Review your wrong answers from Days 1-6 QBank sessions (Marrow 'Incorrect' filter)", BULLET)],
[Paragraph("□ Attempt the Marrow Cardiology Full Subject Test (50 Qs)", BULLET)],
[Paragraph("□ For every wrong answer: note chapter + page reference and add to Weak Topics Log", BULLET)],
[Paragraph("□ Review these specific numbers (no textbook needed):", BULLET)],
[Paragraph(" ACS: D2B 90/120 min, D2N 30 min, Ticagrelor loading 180mg, tPA 0.9mg/kg max 90mg", KEY_ST)],
[Paragraph(" HF: EF <35% ICD threshold, SGLT2i in non-diabetics, ARNI 36h washout from ACEi", KEY_ST)],
[Paragraph(" Valvular: AS AVA <1cm², TAVI PARTNER 3, MS Wilkins ≤8 for PBMC, MR EF <60%", KEY_ST)],
[Paragraph(" AF: CHA₂DS₂-VASc ≥2/≥3, lenient rate <110 (RACE II), EAST-AFNET 4 rhythm control", KEY_ST)],
[Paragraph(" HCM: 5 SCD risk factors, Mavacamten, HCM+AF → anticoagulate always", KEY_ST)],
[Paragraph(" Pericarditis: Colchicine halves recurrence, Beck's triad, Kussmaul's = constrictive ONLY", KEY_ST)],
[Paragraph("□ Target accuracy on Day 7 test: >65% (acceptable) | >75% (excellent)", ALERT_ST)],
]
rev_t = Table(rev_data, colWidths=[PAGE_W - 2 * MARGIN])
rev_t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), C_GREENLT),
("BACKGROUND", (0, 0), (0, 0), C_GREEN),
("TEXTCOLOR", (0, 0), (0, 0), colors.white),
("BOX", (0, 0), (-1, -1), 1.5, C_GREEN),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING", (0, 0), (-1, -1), 4),
("LEFTPADDING", (0, 0), (-1, -1), 12),
]))
story.append(rev_t)
story.append(sp(5))
# Landmark trials summary
story.append(section_banner("Landmark Cardiology Trials – Week 1 Quick Reference", C_NAVY))
story.append(sp(3))
trials = [
["PARADIGM-HF", "Sacubitril/Valsartan vs Enalapril in HFrEF", "20% RRR in CV death + HF hosp"],
["DAPA-HF", "Dapagliflozin in HFrEF (incl. non-diabetics)", "26% RRR in HF events vs placebo"],
["EMPEROR-Red", "Empagliflozin in HFrEF", "25% RRR in CV death + HF hosp"],
["EMPEROR-Pres","Empagliflozin in HFpEF", "21% RRR HF events; first proven benefit in HFpEF"],
["PLATO", "Ticagrelor vs Clopidogrel in ACS", "Ticagrelor: 20% RRR in CV death/MI/stroke, more bleeding"],
["PARTNER 3", "TAVI vs SAVR in low-surgical-risk AS", "TAVI non-inferior at 2yr; trend to superiority"],
["EAST-AFNET 4","Early rhythm control vs rate control in AF", "Rhythm control superior: 21% RRR in CV outcomes"],
["RACE II", "Lenient (<110) vs strict (<80) rate in AF", "Lenient rate control non-inferior; less drug burden"],
["EXPLORER-HCM","Mavacamten vs placebo in obstructive HCM", "Mavacamten: 27% improved functional class"],
["CREDENCE", "Canagliflozin in DKD", "30% RRR in kidney failure/CV death (also relevant HF-renal)"],
["STREAM", "Fibrinolysis vs PCI in rural STEMI", "Pharmaco-invasive strategy non-inferior if PCI unavailable"],
["DANAMI-3 DEFER","Deferred stenting in STEMI", "No benefit to routine deferred stenting vs immediate PCI"],
]
trial_hdr = [["Trial", "Question", "Key Result"]]
t_data = trial_hdr + trials
trial_t = Table(t_data, colWidths=[32*mm, 72*mm, 63*mm])
trial_t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), C_NAVY),
("TEXTCOLOR", (0, 0), (-1, 0), colors.white),
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
("FONTSIZE", (0, 0), (-1, -1), 8),
("FONTNAME", (0, 1), (0, -1), "Helvetica-Bold"),
("TEXTCOLOR", (0, 1), (0, -1), C_NAVY),
("GRID", (0, 0), (-1, -1), 0.5, C_GRAYMD),
("ROWBACKGROUNDS", (0, 1), (-1, -1), [C_GRAY, colors.white]),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 6),
("TEXTCOLOR", (2, 1), (2, -1), C_GREEN),
("FONTNAME", (2, 1), (2, -1), "Helvetica-Bold"),
]))
story.append(trial_t)
return story
# ── Build ──────────────────────────────────────────────────────────────────────
TMP = "/tmp/NEET_SS_Cardiology_Reading_Guide.pdf"
DEST = "/home/daytona/workspace/neet-ss-guide/NEET_SS_Cardiology_Reading_Guide.pdf"
doc = SimpleDocTemplate(
TMP,
pagesize=A4,
leftMargin=MARGIN, rightMargin=MARGIN,
topMargin=16 * mm, bottomMargin=12 * mm,
title="NEET SS Week 1 Cardiology Reading Guide",
author="Orris",
)
story = build_story()
doc.build(story, onFirstPage=cover_bg, onLaterPages=page_header_footer)
with open(TMP, "rb") as src, open(DEST, "wb") as dst:
dst.write(src.read())
print(f"Saved: {DEST}")
cd /home/daytona/workspace/neet-ss-guide && python build_cardio_reading.py 2>&1
~/neet-ss-guide/build_cardio_reading.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/neet-ss-guide/build_cardio_reading.py'
cd /home/daytona/workspace/neet-ss-guide && python build_cardio_reading.py 2>&1
ls -lh /home/daytona/workspace/neet-ss-guide/NEET_SS_Cardiology_Reading_Guide.pdf
NEET SS Cardiology Reading Guide
PDF Document · PDF
| Chapter | Topic | Day | Pages |
|---|---|---|---|
| Ch 286 | STEMI | Day 1 | pp 1823–1842 |
| Ch 285 | NSTEMI/UA | Day 2 | pp 1808–1822 |
| Ch 279 | Heart Failure | Day 3 | pp 1732–1757 |
| Ch 282 | Valvular Disease | Day 4 | pp 1775–1799 |
| Ch 280–281 | Arrhythmias | Day 5 | pp 1758–1800 |
| Ch 283–284 | Cardiomyopathies + Pericardial | Day 6 | pp 1800–1808 |
| Chapter | Topic | Pages |
|---|---|---|
| Ch 59 | STEMI | pp 1058–1118 |
| Ch 58 | NSTEMI | pp 1011–1057 |
| Ch 52–53 | Heart Failure | pp 799–889 |
| Ch 75–78 | Valvular Disease | pp 1385–1519 |
| Ch 64–66 | Arrhythmias | pp 1199–1302 |
| Ch 71–72 | HCM + Pericardial | pp 1303–1380 |
Can you optimize the chapters so that there is no repetition of content and less waste of time and construct pdf again?
~/neet-ss-guide/build_cardio_optimized.py
"""
NEET SS Week 1 Cardiology – Optimized, Non-Redundant Reading Guide
Strategy:
- Harrison's = primary source for clinical reasoning + diagnosis + management overview
- Braunwald's = supplementary ONLY for: algorithm figures, guideline tables, trial summaries
- Overlap eliminated topic-by-topic
- Each topic gets ONE reading block (not two separate ones that repeat content)
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether, PageBreak
)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_CENTER
PAGE_W, PAGE_H = A4
MARGIN = 14 * mm
COL_W = PAGE_W - 2 * MARGIN
# ── Palette ───────────────────────────────────────────────────────────────────
C_NAVY = colors.HexColor("#1A3C5E")
C_BLUE = colors.HexColor("#2E6DA4")
C_SKY = colors.HexColor("#D6EAF8")
C_SKYLT = colors.HexColor("#EBF5FB")
C_RED = colors.HexColor("#C0392B")
C_REDLT = colors.HexColor("#FADBD8")
C_GREEN = colors.HexColor("#1A6B3C")
C_GREENLT = colors.HexColor("#D5F5E3")
C_AMBER = colors.HexColor("#F39C12")
C_AMBERLT = colors.HexColor("#FEF9E7")
C_GRAY = colors.HexColor("#F2F3F4")
C_GRAYMD = colors.HexColor("#BDC3C7")
C_TEXT = colors.HexColor("#1A1A1A")
C_MUTED = colors.HexColor("#5D6D7E")
C_HARRIS = colors.HexColor("#0A3D6B")
C_BRAUNW = colors.HexColor("#7D0A0A")
C_PURPLE = colors.HexColor("#6C3483")
C_OVERLAP = colors.HexColor("#FF6B35") # orange = overlap eliminated
# ── Style factory ─────────────────────────────────────────────────────────────
def S(name, **kw):
return ParagraphStyle(name, **kw)
TITLE_ST = S("T1", fontSize=22, fontName="Helvetica-Bold", textColor=colors.white,
alignment=TA_CENTER, leading=28)
AMBER_ST = S("T2", fontSize=26, fontName="Helvetica-Bold", textColor=C_AMBER,
alignment=TA_CENTER, leading=32)
SUB_ST = S("T3", fontSize=10, fontName="Helvetica", textColor=colors.HexColor("#AEDAF0"),
alignment=TA_CENTER, leading=15, italic=True)
SEC_ST = S("Sec", fontSize=12, fontName="Helvetica-Bold", textColor=colors.white,
alignment=TA_LEFT, leading=16)
BODY_ST = S("Bd", fontSize=8.5, fontName="Helvetica", textColor=C_TEXT, leading=12)
BOLD_ST = S("Bo", fontSize=8.5, fontName="Helvetica-Bold", textColor=C_TEXT, leading=12)
KEY_ST = S("Key", fontSize=8, fontName="Helvetica-Bold", textColor=C_GREEN,
leading=11, leftIndent=8)
ALERT_ST = S("Alt", fontSize=8, fontName="Helvetica-Bold", textColor=C_RED,
leading=11, leftIndent=8)
MUTED_ST = S("Mu", fontSize=7.5, fontName="Helvetica", textColor=C_MUTED,
leading=11, italic=True)
LABEL_ST = S("Lb", fontSize=7.5, fontName="Helvetica-Bold", textColor=colors.white,
alignment=TA_CENTER, leading=10)
H_TAG_ST = S("HT", fontSize=7, fontName="Helvetica-Bold", textColor=C_HARRIS,
alignment=TA_CENTER, leading=9)
B_TAG_ST = S("BT", fontSize=7, fontName="Helvetica-Bold", textColor=C_BRAUNW,
alignment=TA_CENTER, leading=9)
def sp(h=3):
return Spacer(1, h * mm)
def banner(text, bg):
t = Table([[Paragraph(f" {text}", SEC_ST)]], colWidths=[COL_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), bg),
("TOPPADDING", (0,0),(-1,-1), 7),
("BOTTOMPADDING",(0,0),(-1,-1), 7),
("LEFTPADDING", (0,0),(-1,-1), 10),
]))
return t
def page_hdr_ftr(c, doc):
c.saveState()
c.setFillColor(C_NAVY)
c.rect(0, PAGE_H - 10*mm, PAGE_W, 10*mm, fill=1, stroke=0)
c.setFont("Helvetica-Bold", 7)
c.setFillColor(colors.white)
c.drawString(MARGIN, PAGE_H - 6*mm,
"NEET SS | Week 1 Cardiology | Optimized Reading Guide (Non-Redundant)")
c.setFont("Helvetica", 7)
c.drawRightString(PAGE_W - MARGIN, PAGE_H - 6*mm, f"Page {doc.page}")
c.setFillColor(C_NAVY)
c.rect(0, 0, PAGE_W, 8*mm, fill=1, stroke=0)
c.setFont("Helvetica", 7)
c.setFillColor(colors.white)
c.drawString(MARGIN, 3*mm, "Harrison's = clinical overview | Braunwald's = algorithm tables + trial data only")
c.drawRightString(PAGE_W - MARGIN, 3*mm, "June 27 – July 3, 2026")
c.restoreState()
def cover_bg(c, doc):
c.saveState()
c.setFillColor(C_NAVY)
c.rect(0, 0, PAGE_W, PAGE_H, fill=1, stroke=0)
c.setFillColor(C_BLUE)
c.rect(0, PAGE_H*0.38, PAGE_W, PAGE_H*0.62, fill=1, stroke=0)
c.setFillColor(C_AMBER)
c.rect(0, PAGE_H*0.38-4, PAGE_W, 8, fill=1, stroke=0)
c.restoreState()
# ══════════════════════════════════════════════════════════════════════════════
# CORE COMPONENT: The Optimized Topic Block
# Each topic = ONE block with:
# - Primary source to read (Harrison OR Braunwald, whichever is better)
# - Supplementary source: specific tables/figures ONLY (no re-reading content)
# - Eliminated overlap listed explicitly so student knows what to skip
# ══════════════════════════════════════════════════════════════════════════════
def topic_block(day, date_str, topic, time_est,
primary_book, primary_ch, primary_pages, primary_sections,
supp_book, supp_ch, supp_pages, supp_items,
overlap_skip,
exam_focus,
marrow_qs):
"""
primary_sections: list of (text, is_key_bool)
supp_items: list of (item_name, what_to_extract) – specific tables/figs only
overlap_skip: list of strings describing what NOT to read (duplicate content)
exam_focus: string of key facts/numbers
"""
w = COL_W
pri_is_H = "Harrison" in primary_book
pri_color = C_HARRIS if pri_is_H else C_BRAUNW
pri_bg = C_SKYLT if pri_is_H else colors.HexColor("#FEF0F0")
sup_color = C_HARRIS if "Harrison" in supp_book else C_BRAUNW
sup_bg = C_SKYLT if "Harrison" in supp_book else colors.HexColor("#FEF0F0")
rows = []
# ── Row 1: Day header ────────────────────────────────────────────────────
day_row = Table([[
Paragraph(f"Day {day} · {date_str}", S("DR", fontSize=9, fontName="Helvetica-Bold",
textColor=colors.white, leading=12)),
Paragraph(f"⏱ {time_est}", S("TE", fontSize=8, fontName="Helvetica",
textColor=colors.HexColor("#AEDAF0"), leading=12, alignment=TA_CENTER)),
Paragraph(f"QBank: {marrow_qs} Qs", S("QB", fontSize=8, fontName="Helvetica-Bold",
textColor=C_AMBER, leading=12, alignment=TA_CENTER)),
]], colWidths=[w*0.55, w*0.25, w*0.20])
day_row.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_NAVY),
("TOPPADDING", (0,0),(-1,-1), 6),
("BOTTOMPADDING",(0,0),(-1,-1), 6),
("LEFTPADDING", (0,0),(-1,-1), 10),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]))
# ── Row 2: Topic title ───────────────────────────────────────────────────
topic_row = Table([[
Paragraph(topic, S("TR", fontSize=11, fontName="Helvetica-Bold",
textColor=C_NAVY, leading=15)),
]], colWidths=[w])
topic_row.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_SKY),
("TOPPADDING", (0,0),(-1,-1), 7),
("BOTTOMPADDING",(0,0),(-1,-1), 6),
("LEFTPADDING", (0,0),(-1,-1), 10),
("BOX", (0,0),(-1,-1), 1, C_BLUE),
]))
# ── Row 3: Two-column layout ─────────────────────────────────────────────
# Left = primary source, Right = supplement
half = (w - 2*mm) / 2
# Primary source column
pri_content = []
pri_content.append(Table([[
Paragraph("PRIMARY READ", LABEL_ST),
Paragraph(primary_book.replace("Harrison's Principles of Internal Medicine 22E","Harrison's 22E"),
S("PB", fontSize=7.5, fontName="Helvetica-Bold", textColor=colors.white, leading=10)),
]], colWidths=[20*mm, half - 22*mm]))
pri_content[-1].setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), pri_color),
("BACKGROUND", (0,0),(0,0), colors.HexColor("#0D2B45") if pri_is_H else colors.HexColor("#5C0808")),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
("TOPPADDING", (0,0),(-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 6),
]))
pri_content.append(Table([[
Paragraph(f"<b>{primary_ch}</b> · {primary_pages}",
S("PC", fontSize=9, fontName="Helvetica-Bold", textColor=pri_color, leading=13)),
]], colWidths=[half]))
pri_content[-1].setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), pri_bg),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 8),
("BOX", (0,0),(-1,-1), 0.5, pri_color),
]))
# Sections list
sec_rows = []
for sec_text, is_key in primary_sections:
icon = "★" if is_key else "→"
fc = C_GREEN if is_key else C_MUTED
sec_rows.append([
Paragraph(f"<font color='#{(C_GREEN if is_key else C_MUTED).hexval()[2:]}'>{icon}</font> {sec_text}",
S("SecR", fontSize=8, fontName="Helvetica-Bold" if is_key else "Helvetica",
textColor=C_TEXT if is_key else C_MUTED, leading=12, leftIndent=4)),
])
if sec_rows:
sec_t = Table(sec_rows, colWidths=[half])
sec_t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), pri_bg),
("TOPPADDING", (0,0),(-1,-1), 3),
("BOTTOMPADDING",(0,0),(-1,-1), 3),
("LEFTPADDING", (0,0),(-1,-1), 8),
("LINEBELOW", (0,0),(-1,-2), 0.3, C_GRAYMD),
("BOX", (0,0),(-1,-1), 0.5, pri_color),
]))
pri_content.append(sec_t)
# Supplement column
sup_content = []
sup_content.append(Table([[
Paragraph("SUPPLEMENT ONLY", LABEL_ST),
Paragraph(supp_book.replace("Braunwald's Heart Disease: A Textbook of Cardiovascular Medicine","Braunwald's HD")
.replace("Harrison's Principles of Internal Medicine 22E","Harrison's 22E"),
S("SB2", fontSize=7.5, fontName="Helvetica-Bold", textColor=colors.white, leading=10)),
]], colWidths=[24*mm, half - 26*mm]))
sup_content[-1].setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), sup_color),
("BACKGROUND", (0,0),(0,0), colors.HexColor("#0D2B45") if "Harrison" in supp_book
else colors.HexColor("#5C0808")),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
("TOPPADDING", (0,0),(-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 6),
]))
sup_content.append(Table([[
Paragraph(f"<b>{supp_ch}</b> · {supp_pages} <font size='7' color='#C0392B'>(tables/figs only)</font>",
S("SC2", fontSize=8.5, fontName="Helvetica-Bold", textColor=sup_color, leading=13)),
]], colWidths=[half]))
sup_content[-1].setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), sup_bg),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 8),
("BOX", (0,0),(-1,-1), 0.5, sup_color),
]))
sup_rows = []
for item_name, extract in supp_items:
sup_rows.append([
Paragraph(f"<b>→ {item_name}:</b>",
S("IR", fontSize=7.5, fontName="Helvetica-Bold", textColor=sup_color, leading=11, leftIndent=4)),
Paragraph(extract,
S("IE", fontSize=7.5, fontName="Helvetica", textColor=C_MUTED, leading=11, italic=True)),
])
if sup_rows:
sup_t = Table(sup_rows, colWidths=[half*0.4, half*0.6])
sup_t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), sup_bg),
("TOPPADDING", (0,0),(-1,-1), 3),
("BOTTOMPADDING",(0,0),(-1,-1), 3),
("LEFTPADDING", (0,0),(-1,-1), 8),
("LINEBELOW", (0,0),(-1,-2), 0.3, C_GRAYMD),
("BOX", (0,0),(-1,-1), 0.5, sup_color),
]))
sup_content.append(sup_t)
# Two-column table
pri_data = [[p] for p in pri_content]
sup_data = [[p] for p in sup_content]
pri_col = Table(pri_data, colWidths=[half])
pri_col.setStyle(TableStyle([
("TOPPADDING", (0,0),(-1,-1), 0),
("BOTTOMPADDING",(0,0),(-1,-1), 0),
("LEFTPADDING", (0,0),(-1,-1), 0),
("RIGHTPADDING", (0,0),(-1,-1), 0),
]))
sup_col = Table(sup_data, colWidths=[half])
sup_col.setStyle(TableStyle([
("TOPPADDING", (0,0),(-1,-1), 0),
("BOTTOMPADDING",(0,0),(-1,-1), 0),
("LEFTPADDING", (0,0),(-1,-1), 0),
("RIGHTPADDING", (0,0),(-1,-1), 0),
]))
two_col = Table([[pri_col, sup_col]], colWidths=[half, half])
two_col.setStyle(TableStyle([
("VALIGN", (0,0),(-1,-1), "TOP"),
("TOPPADDING", (0,0),(-1,-1), 0),
("BOTTOMPADDING",(0,0),(-1,-1), 0),
("LEFTPADDING", (0,0),(-1,-1), 0),
("RIGHTPADDING", (0,0),(-1,-1), 1),
("COLPADDING", (0,0),(-1,-1), 1),
]))
# ── Row 4: Overlap skip (what NOT to read) ───────────────────────────────
if overlap_skip:
skip_text = " <b>SKIP (already covered):</b> " + " · ".join(overlap_skip)
skip_row = Table([[
Paragraph(skip_text, S("SR2", fontSize=7.5, fontName="Helvetica",
textColor=C_OVERLAP, leading=11)),
]], colWidths=[w])
skip_row.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), colors.HexColor("#FFF5EE")),
("TOPPADDING", (0,0),(-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 8),
("BOX", (0,0),(-1,-1), 0.5, C_OVERLAP),
]))
else:
skip_row = None
# ── Row 5: Exam focus ────────────────────────────────────────────────────
exam_row = Table([[
Paragraph("★ EXAM FOCUS:", S("EH", fontSize=8, fontName="Helvetica-Bold",
textColor=C_NAVY, leading=11)),
Paragraph(exam_focus, S("EB", fontSize=7.5, fontName="Helvetica",
textColor=C_TEXT, leading=11)),
]], colWidths=[22*mm, w - 22*mm])
exam_row.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_AMBERLT),
("BACKGROUND", (0,0),(0,0), colors.HexColor("#FDE8B3")),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 8),
("BOX", (0,0),(-1,-1), 0.8, C_AMBER),
("VALIGN", (0,0),(-1,-1), "TOP"),
]))
# ── Assemble outer wrapper ────────────────────────────────────────────────
inner = [day_row, topic_row, two_col]
if skip_row:
inner.append(skip_row)
inner.append(exam_row)
outer_data = [[p] for p in inner]
outer = Table(outer_data, colWidths=[w])
outer.setStyle(TableStyle([
("TOPPADDING", (0,0),(-1,-1), 0),
("BOTTOMPADDING",(0,0),(-1,-1), 0),
("LEFTPADDING", (0,0),(-1,-1), 0),
("RIGHTPADDING", (0,0),(-1,-1), 0),
("BOX", (0,0),(-1,-1), 1.5, C_BLUE),
]))
return outer
# ══════════════════════════════════════════════════════════════════════════════
# CONTENT DEFINITIONS
# ══════════════════════════════════════════════════════════════════════════════
TOPICS = [
# ── Day 1: STEMI ──────────────────────────────────────────────────────────
dict(
day=1, date_str="Saturday, June 27",
topic="STEMI – ST-Elevation Myocardial Infarction",
time_est="3.5 h total",
primary_book="Harrison's Principles of Internal Medicine 22E",
primary_ch="Ch 286",
primary_pages="pp 1823–1842 (~19 pages)",
primary_sections=[
("Pathophysiology & ECG localisation (territory → artery map)", True),
("Reperfusion: Primary PCI – door-to-balloon 90/120 min thresholds", True),
("Reperfusion: Fibrinolysis – door-to-needle 30 min; absolute contraindications", True),
("Antithrombotic regimen: Aspirin + Ticagrelor + UFH/Bivalirudin", True),
("RV Infarction: V4R lead, avoid nitrates/diuretics, fluid load", True),
("Mechanical complications: VSD, MR, free wall rupture – timing", True),
("Post-MI GDMT initiation (BB, ACEi, statin, DAPT duration)", True),
("Cardiogenic shock: haemodynamic support overview", False),
],
supp_book="Braunwald's Heart Disease: A Textbook of Cardiovascular Medicine",
supp_ch="Ch 59",
supp_pages="pp 1058–1118",
supp_items=[
("Fig 59-2", "Reperfusion decision tree – PCI vs fibrinolysis with time nodes"),
("Table 59-3", "Full antithrombotic regimens for PCI vs fibrinolysis scenarios"),
("Table 59-4", "Complete fibrinolytic contraindications list – memorise"),
("Fig 59-6", "Mechanical complication diagrams (VSD, papillary rupture, free wall)"),
("Box 59-2 (STREAM)", "Pharmaco-invasive vs PCI in rural STEMI"),
],
overlap_skip=[
"Braunwald Ch 59 pathophysiology text (same as Harrison's)",
"Braunwald Ch 59 ECG section (covered in Harrison's)",
"Braunwald post-MI drug list (covered in Harrison's)",
],
exam_focus="D2B <90 min (direct), <120 min (transfer). D2N <30 min. Fibrinolysis: tPA 0.9 mg/kg max 90mg. RV infarct: avoid nitrates. Posterior MI: ST depression V1–V3. New LBBB = STEMI equivalent.",
marrow_qs="30",
),
# ── Day 2: NSTEMI ─────────────────────────────────────────────────────────
dict(
day=2, date_str="Sunday, June 28",
topic="NSTEMI / Unstable Angina – Non-ST-Elevation ACS",
time_est="3 h total",
primary_book="Harrison's Principles of Internal Medicine 22E",
primary_ch="Ch 285",
primary_pages="pp 1808–1822 (~14 pages)",
primary_sections=[
("Clinical presentation, Killip class, differential diagnosis", True),
("Troponin kinetics – high-sensitivity assay 0/1h or 0/3h protocols", True),
("TIMI score (0–7) and GRACE score – risk stratification thresholds", True),
("Antiplatelet: Aspirin 325mg + Ticagrelor 180mg (PLATO trial result)", True),
("Anticoagulation: Fondaparinux preferred (avoid if PCI) vs UFH/enoxaparin", True),
("Invasive vs conservative strategy – timing criteria (<2h, <24h, <72h)", True),
("Secondary prevention: statin (LDL <70), ACEi, BB, DAPT 12 months", True),
("GP IIb/IIIa inhibitors – now limited to bailout PCI only", False),
],
supp_book="Braunwald's Heart Disease: A Textbook of Cardiovascular Medicine",
supp_ch="Ch 58",
supp_pages="pp 1011–1057",
supp_items=[
("Fig 58-5", "Antithrombotic algorithm – Fondaparinux vs enoxaparin vs UFH decision"),
("Fig 58-7", "Invasive strategy timing flowchart (immediate/early/deferred)"),
("Table 58-3 (PLATO)", "Ticagrelor vs Clopidogrel outcomes head-to-head data"),
("Table 58-4 (P2Y12)", "Ticagrelor vs Prasugrel vs Clopidogrel comparison table"),
],
overlap_skip=[
"Braunwald Ch 58 clinical presentation (same as Harrison's)",
"Braunwald Ch 58 pathophysiology text (covered Day 1 as it's largely shared)",
"Braunwald Ch 58 secondary prevention section (Harrison's covers this)",
],
exam_focus="Ticagrelor > Clopidogrel (PLATO: 20% RRR). Fondaparinux: avoid if PCI planned (use UFH/bivalirudin). GRACE >140 or TIMI ≥3 = early invasive strategy. Morphine decreases P2Y12 drug absorption.",
marrow_qs="30",
),
# ── Day 3: Heart Failure ─────────────────────────────────────────────────
dict(
day=3, date_str="Monday, June 29",
topic="Heart Failure – HFrEF, HFpEF & Acute Decompensation",
time_est="4 h total",
primary_book="Harrison's Principles of Internal Medicine 22E",
primary_ch="Ch 279",
primary_pages="pp 1732–1757 (~25 pages)",
primary_sections=[
("HFrEF (<40%) vs HFmrEF (40-49%) vs HFpEF (≥50%) definitions + pathophysiology", True),
("GDMT Pillar 1: ACEi/ARB – ramipril/enalapril; switch to ARNI if tolerating", True),
("GDMT Pillar 2: ARNI (Sacubitril/Valsartan) – PARADIGM-HF: 20% RRR; 36h washout from ACEi", True),
("GDMT Pillar 3: BB – carvedilol/bisoprolol/metoprolol succinate ONLY (NOT atenolol)", True),
("GDMT Pillar 4: MRA – spironolactone (eGFR >30, K <5.0); RALES/EMPHASIS trials", True),
("GDMT Pillar 5: SGLT2i – dapagliflozin (DAPA-HF), empagliflozin (EMPEROR-Reduced); non-diabetics benefit", True),
("Device therapy: ICD (EF <35%, NYHA II-III, ≥3 months GDMT), CRT (LBBB + EF <35%)", True),
("Acute decompensated HF: IV furosemide, vasodilators, BiPAP; Forrester profile approach", True),
("HFpEF management: SGLT2i (EMPEROR-Preserved), diuretics; no survival benefit from ACEi/BB", True),
("BNP/NT-proBNP: cutoffs, causes of falsely low (obesity) and falsely high (renal failure)", False),
],
supp_book="Braunwald's Heart Disease: A Textbook of Cardiovascular Medicine",
supp_ch="Ch 53",
supp_pages="pp 836–889",
supp_items=[
("Fig 53-1", "Step-by-step GDMT initiation and titration algorithm – best single figure"),
("Table 53-2", "All GDMT drugs: trial name, dose, NNT/ARR – comprehensive evidence table"),
("Table 53-7", "ICD/CRT criteria with all NYHA class thresholds tabulated"),
("Box 53-3", "ARNI: PARADIGM-HF full NNT data + switching protocol details"),
],
overlap_skip=[
"Braunwald Ch 52 (pathophysiology) – read only Forrester table + neurohormonal summary box",
"Braunwald Ch 53 text sections – all management narrative covered by Harrison's Ch 279",
"Braunwald Ch 53 diuretic pharmacology section – not exam-tested at this level",
],
exam_focus="5-drug GDMT (ACEi/ARNI + BB + MRA + SGLT2i + now Vericiguat/Ivabradine optional). ARNI 36h washout from ACEi. SGLT2i benefit in non-diabetics. ICD EF <35% + 3 months GDMT. HFpEF: SGLT2i is only proven agent. EMPEROR-Preserved: empagliflozin.",
marrow_qs="30",
),
# ── Day 4: Valvular ──────────────────────────────────────────────────────
dict(
day=4, date_str="Tuesday, June 30",
topic="Valvular Heart Disease – AS, MR, MS, AR",
time_est="3.5 h total",
primary_book="Harrison's Principles of Internal Medicine 22E",
primary_ch="Ch 282",
primary_pages="pp 1775–1799 (~24 pages)",
primary_sections=[
("AS severity: AVA <1 cm², mean gradient >40 mmHg, Vmax >4 m/s", True),
("AS intervention criteria – class I: symptomatic severe OR EF <50% + severe AS", True),
("TAVI vs SAVR: PARTNER 3 (low risk), PARTNER 2 (intermediate), PARTNER 1 (high risk)", True),
("Paradoxical low-flow low-gradient AS: normal EF + low gradient + low AVA → dobutamine echo", True),
("MR (primary): surgery if EF <60% OR LVESD >40 mm; repair preferred over replacement", True),
("MS: MVA <1.5 cm²; PBMC if Wilkins ≤8, no LA thrombus, no moderate+ MR", True),
("AR: surgery if symptomatic OR EF <50% OR LVESD >50 mm (or >25 mm/m²)", True),
("RHD penicillin prophylaxis: 10 yr or until age 40 (whichever longer); severe MR: lifelong", True),
("Prosthetic valve anticoagulation: mechanical → warfarin; bioprosthetic → aspirin ±3 months anticoag", False),
("IE prophylaxis: limited to prosthetic valves, prior IE, unrepaired cyanotic CHD", False),
],
supp_book="Braunwald's Heart Disease: A Textbook of Cardiovascular Medicine",
supp_ch="Ch 75–78",
supp_pages="pp 1385–1519",
supp_items=[
("Table 75-4 (AS)", "AHA 2021 intervention indications by class – all criteria tabulated"),
("AS Natural Hx Fig", "Classic triad onset: Angina 3yr → Syncope 2yr → Dyspnea 1yr"),
("PARTNER Trial Box", "PARTNER 1/2/3 + EVOLUT results summary by surgical risk tier"),
("Table 76-2 (MR)", "Primary vs secondary MR surgical timing thresholds"),
("Table 77-3 (MS)", "Wilkins score: all 4 components scored 1-4 (memorise)"),
("Fig 78-4 (AR)", "AR management decision flowchart – EF + LVESD thresholds"),
],
overlap_skip=[
"Braunwald narrative sections for each valve (Harrison's covers all clinical content)",
"Braunwald Ch 79 anticoagulation chapter – Harrison's has adequate summary",
],
exam_focus="AS: AVA <1, gradient >40, Vmax >4. MR surgery: EF <60% or LVESD >40. MS PBMC: Wilkins ≤8. AR surgery: EF <50% or LVESD >50. PARTNER 3: TAVI = SAVR at low risk. Prophylaxis: penicillin 10yr or age 40.",
marrow_qs="25",
),
# ── Day 5: Arrhythmias ───────────────────────────────────────────────────
dict(
day=5, date_str="Wednesday, July 1",
topic="Cardiac Arrhythmias – AF, SVT, VT, Channelopathies",
time_est="4 h total",
primary_book="Harrison's Principles of Internal Medicine 22E",
primary_ch="Ch 281 (+ Ch 280 skim)",
primary_pages="pp 1765–1800 (~35 pages, starred sections only)",
primary_sections=[
("AF classification: paroxysmal/persistent/long-standing/permanent definitions", True),
("AF rate control: BB > diltiazem/verapamil > digoxin; lenient <110 (RACE II)", True),
("AF rhythm control: EAST-AFNET 4 – early rhythm control superior at 5 yr", True),
("AF rhythm control drugs: Flecainide (no structural), Amiodarone, Dronedarone", True),
("AF anticoagulation: CHA₂DS₂-VASc ≥2 (men)/≥3 (women) → OAC; DOACs > warfarin", True),
("Valvular AF (rheumatic MS, mechanical valve): warfarin ONLY – no DOACs", True),
("AF ablation: pulmonary vein isolation – success ~70%; repeat procedures common", True),
("AVNRT vs AVRT: mechanism, Adenosine 6mg→12mg, ablation 95% cure", True),
("VT: haemodynamically stable vs unstable management; ICD indications", True),
("Long QT: subtypes 1/2/3, triggers (LQT1 exercise, LQT2 sounds, LQT3 sleep), drugs to avoid", True),
("Brugada syndrome: Type 1 ECG (coved pattern V1-V3), fever trigger, ICD", True),
("Torsades de Pointes: QTc >500, IV MgSO₄ 2g, stop offending drug, overdrive pacing", True),
("Ch 280 mechanisms: only reentry + triggered activity paragraphs", False),
],
supp_book="Braunwald's Heart Disease: A Textbook of Cardiovascular Medicine",
supp_ch="Ch 64–65",
supp_pages="pp 1199–1302",
supp_items=[
("Table 64-1", "CHA₂DS₂-VASc full scoring table – 8 components + point values"),
("Table 64-3", "Rate control drug IV + oral doses, contraindications"),
("Fig 64-7", "Rhythm control decision incorporating EAST-AFNET 4 evidence"),
("Table 65-8", "Channelopathy comparison: LQT1/2/3 + Brugada – triggers + Rx"),
],
overlap_skip=[
"Braunwald Ch 64 AF text narrative (identical content to Harrison's Ch 281)",
"Braunwald Ch 65 VT/SVT clinical text (covered fully in Harrison's)",
"Braunwald EP mechanisms chapter (too detailed; Ch 280 skim is sufficient)",
],
exam_focus="CHA₂DS₂-VASc (8 components, ≥2 men). Valvular AF → warfarin only. RACE II lenient <110. EAST-AFNET 4: rhythm control superior. LQT1=exercise, LQT2=auditory, LQT3=sleep. Brugada: coved V1-V3. Torsades: IV MgSO₄ first.",
marrow_qs="30",
),
# ── Day 6: CMP + Pericardial ─────────────────────────────────────────────
dict(
day=6, date_str="Thursday, July 2",
topic="Cardiomyopathies & Pericardial Disease",
time_est="3 h total",
primary_book="Harrison's Principles of Internal Medicine 22E",
primary_ch="Ch 283–284",
primary_pages="pp 1800–1808 (~8 pages, all sections)",
primary_sections=[
("HCM: SAM, dynamic LVOT gradient, septal hypertrophy ≥15 mm", True),
("HCM SCD risk (AHA 2020): septum ≥30mm, NSVT, family hx SCD, unexplained syncope, abnormal BP response", True),
("HCM management: BB/verapamil → Mavacamten (EXPLORER-HCM) → septal ablation/myectomy", True),
("HCM + AF: anticoagulate regardless of CHA₂DS₂-VASc (all patients)", True),
("DCM: causes (alcohol, thyroid, viral, peripartum, drug-induced) – manage reversible", True),
("ARVC: epsilon wave, T-wave inversion V1-V3, fatty infiltration; SCD in athletes", True),
("Restrictive CM vs Constrictive pericarditis: key differentiating features", True),
("Acute pericarditis: 2/4 criteria, NSAIDs + Colchicine (COPE trial – halves recurrence)", True),
("Tamponade: Beck's triad, pulsus paradoxus >10, electrical alternans, RA collapse on echo", True),
("Constrictive pericarditis: Kussmaul's sign (NOT in tamponade), equalization pressures, square root sign", True),
("Uraemic pericarditis: dialysis indication even without haemodynamic compromise", True),
],
supp_book="Braunwald's Heart Disease: A Textbook of Cardiovascular Medicine",
supp_ch="Ch 71–72",
supp_pages="pp 1303–1380",
supp_items=[
("Table 71-2 (HCM SCD)", "AHA 2020 risk calculator – 5 factors + 5-year ICD threshold"),
("Fig 71-5 (HCM Rx)", "Medical (Mavacamten/disopyramide) vs invasive algorithm"),
("Box 71-3 Mavacamten", "EXPLORER-HCM: mechanism + 27% improvement in functional class"),
("Table 72-4", "Constrictive vs Restrictive CM: side-by-side echo + catheter data"),
("ESC 2015 Box", "Pericarditis evidence table: Aspirin + Colchicine; steroid avoidance"),
],
overlap_skip=[
"Braunwald DCM/ARVC text (Harrison's is sufficient for NEET SS level)",
"Braunwald Ch 72 tamponade narrative (Harrison's covers clinical adequately)",
"Braunwald Ch 73 RCM chapter (too detailed; only restrictive vs constrictive table needed)",
],
exam_focus="HCM+AF → always anticoagulate. Mavacamten: cardiac myosin inhibitor. SCD risk ≥30mm septum. Kussmaul's sign: ONLY constrictive pericarditis (NOT tamponade). Uraemic pericarditis → dialysis. COPE trial: colchicine halves pericarditis recurrence.",
marrow_qs="25",
),
]
# ══════════════════════════════════════════════════════════════════════════════
# STORY BUILD
# ══════════════════════════════════════════════════════════════════════════════
def build_story():
story = []
# ── Cover ──────────────────────────────────────────────────────────────────
story.append(sp(48))
story.append(Paragraph("NEET SS · Week 1 · Optimized Reading Guide", TITLE_ST))
story.append(sp(2))
story.append(Paragraph("CARDIOLOGY", AMBER_ST))
story.append(sp(3))
story.append(Paragraph("Harrison's 22E + Braunwald's Heart Disease – Non-Redundant", SUB_ST))
story.append(Paragraph("June 27 – July 3, 2026 · Day 1 – Day 6 · Day 7 = Full Subject Test", SUB_ST))
story.append(sp(8))
# Cover principle box
principles = [
[Paragraph("Optimization Principles", S("PP", fontSize=11, fontName="Helvetica-Bold",
textColor=C_NAVY, leading=14))],
[Paragraph("<b>1. One primary source per topic.</b> Harrison's 22E is your primary read for all topics. "
"Braunwald's is supplementary – specific tables and figures only.",
S("P1", fontSize=9, fontName="Helvetica", textColor=C_TEXT, leading=13))],
[Paragraph("<b>2. Overlap explicitly listed.</b> Each topic block shows exactly what to SKIP in Braunwald's "
"to avoid re-reading the same content.", S("P2", fontSize=9, fontName="Helvetica",
textColor=C_TEXT, leading=13))],
[Paragraph("<b>3. Braunwald's used only for 3 things:</b> Algorithm figures (better drawn), "
"Guideline tables (more complete), Landmark trial summaries (concise boxes).",
S("P3", fontSize=9, fontName="Helvetica", textColor=C_TEXT, leading=13))],
[Paragraph("<b>4. Estimated time per day already deducted for overlap.</b> Each block shows net "
"reading time after skipping redundant sections.",
S("P4", fontSize=9, fontName="Helvetica", textColor=C_TEXT, leading=13))],
[Paragraph("★ = Must read for NEET SS → = Read if time permits "
"<font color='#FF6B35'>■ Orange = skip (overlap eliminated)</font>",
S("P5", fontSize=8.5, fontName="Helvetica-Bold", textColor=C_NAVY, leading=12))],
]
pt = Table(principles, colWidths=[130*mm])
pt.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_SKYLT),
("BACKGROUND", (0,0),(0,0), C_SKY),
("BOX", (0,0),(-1,-1), 1.5, C_BLUE),
("TOPPADDING", (0,0),(-1,-1), 6),
("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 14),
]))
story.append(pt)
story.append(PageBreak())
# ── Time saving summary ───────────────────────────────────────────────────
story.append(banner("TIME SAVINGS vs Non-Optimized Reading", C_NAVY))
story.append(sp(3))
savings_data = [
["Topic", "Old approach (both books full)", "Optimized approach", "Time saved"],
["STEMI", "Harrison's 19pg + Braunwald Ch59 60pg = 79pg", "Harrison's 19pg + Braunwald 5 items (figs/tables)", "~2.5 hours"],
["NSTEMI", "Harrison's 14pg + Braunwald Ch58 47pg = 61pg", "Harrison's 14pg + Braunwald 4 items", "~2 hours"],
["Heart Failure", "Harrison's 25pg + Braunwald Ch52+53 90pg = 115pg", "Harrison's 25pg + Braunwald 4 tables/figs", "~3.5 hours"],
["Valvular", "Harrison's 24pg + Braunwald Ch75-78 135pg = 159pg", "Harrison's 24pg + Braunwald 6 tables", "~4 hours"],
["Arrhythmias", "Harrison's 35pg + Braunwald Ch64-65 104pg = 139pg", "Harrison's 35pg + Braunwald 4 tables/figs", "~3.5 hours"],
["CMP+Pericardial", "Harrison's 8pg + Braunwald Ch71-72 78pg = 86pg", "Harrison's 8pg + Braunwald 5 tables/figs", "~2.5 hours"],
["TOTAL", "~639 pages over 7 days", "~125 pages + targeted supplementing", "~18 hours saved"],
]
sv_t = Table(savings_data, colWidths=[28*mm, 67*mm, 60*mm, 22*mm])
sv_t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), C_NAVY),
("TEXTCOLOR", (0,0),(-1,0), colors.white),
("FONTNAME", (0,0),(-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0),(-1,-1), 8),
("FONTNAME", (0,1),(-1,-1), "Helvetica"),
("GRID", (0,0),(-1,-1), 0.5, C_GRAYMD),
("ROWBACKGROUNDS", (0,1),(-1,-2), [C_GRAY, colors.white]),
("BACKGROUND", (0,-1),(-1,-1), C_GREENLT),
("FONTNAME", (0,-1),(-1,-1), "Helvetica-Bold"),
("TEXTCOLOR", (0,-1),(-1,-1), C_GREEN),
("TEXTCOLOR", (3,1),(3,-1), C_RED),
("FONTNAME", (3,1),(3,-1), "Helvetica-Bold"),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 6),
]))
story.append(sv_t)
story.append(sp(4))
# Week overview bar
story.append(banner("WEEK 1 DAILY OVERVIEW", C_BLUE))
story.append(sp(3))
ov_data = [["Day", "Date", "Topic", "Primary (Harrison's)", "Supplement (Braunwald's)", "Qs"]]
ov_rows = [
["1", "27 Jun", "STEMI", "Ch 286 pp 1823–1842", "Ch 59: Fig 59-2, Table 59-3, Table 59-4", "30"],
["2", "28 Jun", "NSTEMI/UA", "Ch 285 pp 1808–1822", "Ch 58: Fig 58-5, 58-7, Table 58-3", "30"],
["3", "29 Jun", "Heart Failure", "Ch 279 pp 1732–1757", "Ch 53: Fig 53-1, Table 53-2, 53-7", "30"],
["4", "30 Jun", "Valvular VHD", "Ch 282 pp 1775–1799", "Ch 75-78: Table 75-4, 76-2, 77-3", "25"],
["5", "1 Jul", "Arrhythmias", "Ch 281 pp 1765–1800", "Ch 64-65: Table 64-1, 64-3, 65-8", "30"],
["6", "2 Jul", "CMP + Pericardial", "Ch 283-284 pp 1800–1808", "Ch 71-72: Table 71-2, 72-4", "25"],
["7", "3 Jul", "REVISION", "Review starred sections + wrong Qs only", "No new Braunwald", "50"],
]
all_ov = ov_data + ov_rows
ov_t = Table(all_ov, colWidths=[9*mm, 14*mm, 30*mm, 42*mm, 58*mm, 10*mm])
ov_t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), C_NAVY),
("TEXTCOLOR", (0,0),(-1,0), colors.white),
("FONTNAME", (0,0),(-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0),(-1,-1), 8),
("FONTNAME", (0,1),(-1,-1), "Helvetica"),
("GRID", (0,0),(-1,-1), 0.5, C_GRAYMD),
("ROWBACKGROUNDS", (0,1),(-1,-2), [C_SKYLT, colors.white]),
("BACKGROUND", (0,-1),(-1,-1), C_GREENLT),
("FONTNAME", (0,-1),(-1,-1), "Helvetica-Bold"),
("TEXTCOLOR", (0,-1),(-1,-1), C_GREEN),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 5),
]))
story.append(ov_t)
story.append(PageBreak())
# ── Topic blocks ──────────────────────────────────────────────────────────
for td in TOPICS:
blk = topic_block(**td)
story.append(KeepTogether([blk, sp(4)]))
story.append(PageBreak())
# ── Day 7 Revision Page ───────────────────────────────────────────────────
story.append(banner("Day 7 (July 3) — Full Cardiology Subject Test + Revision", C_GREEN))
story.append(sp(3))
rev_items = [
("DO", "Re-read ONLY starred ★ sections from Harrison's Ch 279–286 (your notes, not full chapters)"),
("DO", "Attempt Marrow Cardiology Subject Test (50 Qs) as if exam conditions"),
("DO", "For every wrong answer: note Harrison's chapter + page in Weak Topics Log"),
("DO", "Re-read Braunwald figures/tables for any topic where you scored <50% accuracy"),
("NUMBERS", "D2B 90/120 min · D2N 30 min · tPA 0.9mg/kg max 90mg · RV infarct avoid nitrates"),
("NUMBERS", "GDMT 5-drug · ARNI 36h washout · ICD EF <35% + 3 months · HFpEF: SGLT2i only"),
("NUMBERS", "AS AVA <1 · MR EF <60% LVESD >40 · MS Wilkins ≤8 · AR EF <50% LVESD >50"),
("NUMBERS", "CHA₂DS₂-VASc ≥2/≥3 · Valvular AF warfarin only · RACE II <110 · EAST-AFNET 4 rhythm"),
("NUMBERS", "HCM SCD: septum ≥30mm · Mavacamten EXPLORER-HCM · Kussmaul = constrictive ONLY"),
("SKIP", "Do NOT open Braunwald today – no new reading in revision sessions"),
("TARGET", "Target: >65% (acceptable) | >75% (excellent) on Day 7 test"),
]
rev_rows = []
for tag, text in rev_items:
if tag == "DO":
icon_col = Paragraph("✓", S("IC", fontSize=11, fontName="Helvetica-Bold",
textColor=C_GREEN, alignment=TA_CENTER, leading=14))
bg = C_GREENLT
elif tag == "NUMBERS":
icon_col = Paragraph("★", S("IC2", fontSize=11, fontName="Helvetica-Bold",
textColor=C_AMBER, alignment=TA_CENTER, leading=14))
bg = C_AMBERLT
elif tag == "SKIP":
icon_col = Paragraph("✗", S("IC3", fontSize=11, fontName="Helvetica-Bold",
textColor=C_RED, alignment=TA_CENTER, leading=14))
bg = C_REDLT
else:
icon_col = Paragraph("→", S("IC4", fontSize=11, fontName="Helvetica-Bold",
textColor=C_BLUE, alignment=TA_CENTER, leading=14))
bg = C_SKY
rev_rows.append([
icon_col,
Paragraph(text, S("RT", fontSize=8.5, fontName="Helvetica", textColor=C_TEXT, leading=12)),
])
rev_t = Table(rev_rows, colWidths=[10*mm, COL_W - 10*mm])
rev_t.setStyle(TableStyle([
("ROWBACKGROUNDS", (0,0),(-1,-1), [C_GREENLT, C_GREENLT, C_GREENLT, C_GREENLT,
C_AMBERLT, C_AMBERLT, C_AMBERLT, C_AMBERLT,
C_AMBERLT, C_REDLT, C_SKYLT]),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
("TOPPADDING", (0,0),(-1,-1), 6),
("BOTTOMPADDING",(0,0),(-1,-1), 6),
("LEFTPADDING", (0,0),(-1,-1), 8),
("BOX", (0,0),(-1,-1), 1.5, C_GREEN),
("GRID", (0,0),(-1,-1), 0.3, C_GRAYMD),
]))
story.append(rev_t)
story.append(sp(5))
# ── Landmark Trials ───────────────────────────────────────────────────────
story.append(banner("Landmark Trials – Cardiology Quick Reference", C_NAVY))
story.append(sp(3))
trials = [
["Trial", "Drug / Comparison", "Population", "Key Result (memorise)"],
["PARADIGM-HF", "Sacubitril/Valsartan vs Enalapril", "HFrEF EF <40%", "20% RRR CV death/HF hosp"],
["DAPA-HF", "Dapagliflozin vs placebo", "HFrEF (incl. non-DM)", "26% RRR HF events; 18% CV death"],
["EMPEROR-Red", "Empagliflozin vs placebo", "HFrEF (incl. non-DM)", "25% RRR CV death/HF hosp"],
["EMPEROR-Pres", "Empagliflozin vs placebo", "HFpEF EF ≥40%", "21% RRR; first proven HFpEF benefit"],
["PLATO", "Ticagrelor vs Clopidogrel", "ACS all types", "20% RRR CV death/MI/stroke; more bleeding"],
["PARTNER 3", "TAVI vs SAVR", "Severe AS low surgical risk", "TAVI non-inferior at 2yr; trend superior"],
["EAST-AFNET 4", "Early rhythm control vs rate", "AF ≤1yr, CV risk factors", "21% RRR CV outcomes at 5yr"],
["RACE II", "Lenient (<110) vs strict (<80)", "Permanent AF", "Lenient non-inferior; fewer drug side effects"],
["EXPLORER-HCM", "Mavacamten vs placebo", "Obstructive HCM", "27% improved functional class; LVOT relief"],
["COPE/ICAP", "Colchicine vs placebo", "Acute/recurrent pericarditis", "Halves recurrence rate at 18 months"],
["STREAM", "Pharmaco-invasive vs PCI", "STEMI, PCI delay >60 min", "Non-inferior outcomes; viable rural strategy"],
["DAPA-CKD", "Dapagliflozin", "CKD + proteinuria (incl. non-DM)", "39% RRR kidney failure/CV death"],
]
tt = Table(trials, colWidths=[28*mm, 48*mm, 46*mm, 45*mm])
tt.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), C_NAVY),
("TEXTCOLOR", (0,0),(-1,0), colors.white),
("FONTNAME", (0,0),(-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0),(-1,-1), 8),
("FONTNAME", (0,1),(0,-1), "Helvetica-Bold"),
("TEXTCOLOR", (0,1),(0,-1), C_NAVY),
("TEXTCOLOR", (3,1),(3,-1), C_GREEN),
("FONTNAME", (3,1),(3,-1), "Helvetica-Bold"),
("GRID", (0,0),(-1,-1), 0.5, C_GRAYMD),
("ROWBACKGROUNDS", (0,1),(-1,-1), [C_GRAY, colors.white]),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 6),
]))
story.append(tt)
return story
# ── Build PDF ──────────────────────────────────────────────────────────────────
TMP = "/tmp/NEET_SS_Cardiology_Optimized.pdf"
DEST = "/home/daytona/workspace/neet-ss-guide/NEET_SS_Cardiology_Optimized.pdf"
doc = SimpleDocTemplate(
TMP, pagesize=A4,
leftMargin=MARGIN, rightMargin=MARGIN,
topMargin=16*mm, bottomMargin=12*mm,
title="NEET SS Week 1 Cardiology – Optimized Reading Guide",
author="Orris",
)
story = build_story()
doc.build(story, onFirstPage=cover_bg, onLaterPages=page_hdr_ftr)
with open(TMP, "rb") as src, open(DEST, "wb") as dst:
dst.write(src.read())
print(f"Saved: {DEST}")
cd /home/daytona/workspace/neet-ss-guide && python build_cardio_optimized.py 2>&1
ls -lh /home/daytona/workspace/neet-ss-guide/NEET_SS_Cardiology_Optimized.pdf
NEET SS Cardiology Optimized
PDF Document · PDF
| Book | Role | What to actually read |
|---|---|---|
| Harrison's 22E | Primary source for ALL topics | Full starred sections - clinical reasoning, management overview, diagnostic criteria |
| Braunwald's | Supplement ONLY | 3–6 specific items per topic: algorithm figures, AHA guideline tables, landmark trial summary boxes |
| Old approach | Optimized | |
|---|---|---|
| Total pages | ~639 pages | ~125 pages |
| Time estimate | Impossible in 7 days | 3–4 hours/day (realistic) |
| Time saved | - | ~18 hours |
Make a comparison flashcard PDF of all 7 cardiac topics in one page (for last-day revision)
~/neet-ss-guide/build_flashcard.py
"""
NEET SS Cardiology – 7-Topic Comparison Flashcard (Single A3 Landscape Page)
Dense, last-day revision format. All 7 topics in a grid.
"""
from reportlab.lib.pagesizes import A3, landscape
from reportlab.lib import colors
from reportlab.lib.units import mm
from reportlab.platypus import (
SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer
)
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.pdfgen import canvas as pdfcanvas
PAGE_W, PAGE_H = landscape(A3)
MARGIN = 8 * mm
# ── Palette ───────────────────────────────────────────────────────────────────
C = {
"navy": colors.HexColor("#0D2137"),
"blue": colors.HexColor("#1A5276"),
"sky": colors.HexColor("#D6EAF8"),
"skylt": colors.HexColor("#EBF5FB"),
"green": colors.HexColor("#145A32"),
"greenlt": colors.HexColor("#D5F5E3"),
"amber": colors.HexColor("#B7770D"),
"amberlt": colors.HexColor("#FEF9E7"),
"red": colors.HexColor("#922B21"),
"redlt": colors.HexColor("#FADBD8"),
"purple": colors.HexColor("#6C3483"),
"purplt": colors.HexColor("#E8DAEF"),
"teal": colors.HexColor("#0E6655"),
"teallt": colors.HexColor("#D1F2EB"),
"brown": colors.HexColor("#784212"),
"brownlt": colors.HexColor("#FDEBD0"),
"gray": colors.HexColor("#F2F3F4"),
"graymd": colors.HexColor("#AEB6BF"),
"white": colors.white,
"black": colors.HexColor("#0A0A0A"),
"muted": colors.HexColor("#5D6D7E"),
}
def S(name, sz=7, bold=False, color="black", italic=False, align=TA_LEFT, leading=None):
return ParagraphStyle(
name,
fontSize=sz,
fontName="Helvetica-Bold" if bold else ("Helvetica-Oblique" if italic else "Helvetica"),
textColor=C[color] if isinstance(color, str) else color,
alignment=align,
leading=leading or (sz + 2),
spaceAfter=0, spaceBefore=0,
)
def P(text, sz=7, bold=False, color="black", italic=False, align=TA_LEFT):
return Paragraph(text, S("_", sz=sz, bold=bold, color=color,
italic=italic, align=align, leading=sz+1.5))
def cell(content, bg="white", pad=2):
"""Wrap content list into a mini-table cell with background."""
rows = [[item] for item in content]
t = Table(rows, colWidths=[None])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C[bg] if isinstance(bg,str) else bg),
("TOPPADDING", (0,0),(-1,-1), pad),
("BOTTOMPADDING", (0,0),(-1,-1), pad),
("LEFTPADDING", (0,0),(-1,-1), pad),
("RIGHTPADDING", (0,0),(-1,-1), pad),
("VALIGN", (0,0),(-1,-1), "TOP"),
]))
return t
def hdr(text, bg_key, text_color="white", sz=8):
return P(f"<b>{text}</b>", sz=sz, bold=True,
color=text_color if isinstance(text_color,str) else text_color,
align=TA_CENTER)
# ── Row builder helpers ────────────────────────────────────────────────────────
def kv(key, val, ksz=6.5, vsz=6.5, kbold=True, vbold=False, vcolor="black"):
return P(f"<b>{key}</b> {val}", sz=vsz, color=vcolor)
def star(text, sz=6.5):
return P(f"<font color='#145A32'>★</font> {text}", sz=sz)
def bang(text, sz=6.5):
return P(f"<font color='#922B21'>!</font> {text}", sz=sz)
def dot(text, sz=6.5):
return P(f"• {text}", sz=sz)
# ══════════════════════════════════════════════════════════════════════════════
# FLASHCARD DATA – each topic = dict of row_label → list of Paragraphs
# 7 topics across columns, rows = comparison dimensions
# ══════════════════════════════════════════════════════════════════════════════
# Row labels (left spine)
ROWS = [
"KEY NUMBERS",
"1st LINE Rx",
"LANDMARK TRIALS",
"TRAPS / DON'T",
"ECG / ECHO",
"DRUG DETAILS",
"SURGERY / DEVICE",
]
TOPICS = [
{
"title": "STEMI",
"color": "navy",
"light": "skylt",
"KEY NUMBERS": [
star("D2B: <b>90 min</b> (direct PCI)"),
star("D2B: <b>120 min</b> (transfer PCI)"),
star("D2N: <b>30 min</b> fibrinolysis"),
star("tPA dose: <b>0.9 mg/kg</b>, max <b>90 mg</b>"),
dot("PCI window: <b>12 h</b> from onset"),
dot("Lysis window: <b>12 h</b> from onset"),
],
"1st LINE Rx": [
star("Aspirin 325 mg + <b>Ticagrelor 180 mg</b>"),
star("Primary PCI if available"),
star("UFH or Bivalirudin with PCI"),
bang("Fondaparinux: AVOID with PCI"),
dot("Fibrinolysis if PCI delay >120 min"),
dot("Oxygen only if SpO₂ <90%"),
],
"LANDMARK TRIALS": [
star("<b>PLATO:</b> Ticagrelor > Clopidogrel (20% RRR)"),
star("<b>STREAM:</b> Pharmaco-invasive = PCI in rural STEMI"),
dot("DANAMI-3 DEFER: deferred stenting no benefit"),
],
"TRAPS / DON'T": [
bang("RV infarct: <b>NO nitrates, NO diuretics</b>"),
bang("RV infarct: fluid load (500 mL NS bolus)"),
bang("New LBBB = STEMI equivalent → treat same"),
bang("Posterior MI: ST dep V1-V3 = STEMI equivalent"),
],
"ECG / ECHO": [
star("Territory map: V1-V4 = LAD, II/III/aVF = RCA, I/aVL = LCx"),
star("RV infarct: ST elevation <b>V4R</b>"),
dot("Mechanical complication echo: VSD, MR, tamponade"),
],
"DRUG DETAILS": [
star("Ticagrelor: 180 mg load → 90 mg BD"),
star("Prasugrel: better than Clopi for PCI STEMI"),
bang("Prasugrel: <b>avoid</b> if prior stroke/TIA, age >75, wt <60 kg"),
dot("Clopidogrel: 600 mg load if Ticagrelor unavailable"),
],
"SURGERY / DEVICE": [
star("IABP: cardiogenic shock (not proven mortality benefit)"),
star("Impella/Axella: haemodynamic support in shock"),
dot("CABG: if anatomy unfavourable for PCI"),
dot("DAPT duration: 12 months standard post-STEMI"),
],
},
{
"title": "NSTEMI / UA",
"color": "blue",
"light": "skylt",
"KEY NUMBERS": [
star("TIMI ≥3 = high risk → early invasive"),
star("GRACE >140 = early invasive <24h"),
star("Immediate (<2h): electrical instability, refractory ischaemia"),
dot("Early invasive: <24h (high risk)"),
dot("Deferred: <72h (low-intermediate risk)"),
],
"1st LINE Rx": [
star("Aspirin + <b>Ticagrelor</b> (preferred over Clopi)"),
star("<b>Fondaparinux</b> preferred anticoagulation"),
bang("Fondaparinux + PCI: add UFH bolus (anti-Xa coverage)"),
dot("Conservative: Fondaparinux + ASA + Ticagrelor"),
],
"LANDMARK TRIALS": [
star("<b>PLATO:</b> Ticagrelor 20% RRR vs Clopidogrel in ACS"),
star("<b>OASIS-5:</b> Fondaparinux = enoxaparin, less bleeding"),
dot("TIMACS: early (<24h) vs delayed (>36h) – early better in high risk"),
],
"TRAPS / DON'T": [
bang("Morphine ↓ P2Y12 absorption – use cautiously"),
bang("GP IIb/IIIa: NOT routine; <b>bailout PCI only</b>"),
bang("Prasugrel: do NOT load before angiography (anatomy unknown)"),
],
"ECG / ECHO": [
star("Dynamic ST changes = high risk (>0.5mm)"),
star("T-wave inversion: Wellens' pattern = proximal LAD lesion"),
dot("Echo: wall motion abnormality, EF assessment"),
],
"DRUG DETAILS": [
star("Ticagrelor: 180 mg load → 90 mg BD"),
star("Enoxaparin: 1 mg/kg SC BD; reduce to 1 mg/kg OD if CrCl <30"),
dot("UFH: 60 U/kg bolus, 12 U/kg/h infusion, target aPTT 50-70"),
],
"SURGERY / DEVICE": [
star("PCI: drug-eluting stent preferred"),
dot("CABG: multivessel disease, LM disease, diabetics"),
dot("DAPT post-PCI: 12 months (1 month minimum if bleeding risk)"),
],
},
{
"title": "HEART FAILURE",
"color": "teal",
"light": "teallt",
"KEY NUMBERS": [
star("HFrEF: EF <40% | HFmrEF: 40-49% | HFpEF: ≥50%"),
star("ICD: EF <35%, NYHA II-III, ≥3 months GDMT"),
star("CRT: EF <35% + LBBB + QRS ≥150 ms"),
dot("ARNI: 36h washout from ACEi before switching"),
dot("MRA: only if eGFR >30 and K <5.0 mEq/L"),
],
"1st LINE Rx": [
star("<b>5-drug GDMT:</b> ARNI + BB + MRA + SGLT2i (+ diuretic prn)"),
star("BB: <b>carvedilol / bisoprolol / metoprolol succinate ONLY</b>"),
star("SGLT2i: dapagliflozin 10mg or empagliflozin 10mg"),
bang("HFpEF: ACEi/BB NOT proven mortality benefit"),
dot("HFpEF: SGLT2i (EMPEROR-Preserved) only proven drug"),
],
"LANDMARK TRIALS": [
star("<b>PARADIGM-HF:</b> Sacubitril/Valsartan 20% RRR vs Enalapril"),
star("<b>DAPA-HF:</b> Dapagliflozin 26% RRR (incl. non-diabetics)"),
star("<b>EMPEROR-Red:</b> Empagliflozin 25% RRR (incl. non-DM)"),
star("<b>EMPEROR-Pres:</b> Empagliflozin 21% RRR in HFpEF"),
],
"TRAPS / DON'T": [
bang("BB: <b>atenolol NOT proven</b> in HF (use only 3 above)"),
bang("Start BB only when STABLE (not in acute decompensation)"),
bang("MRA + ACEi: monitor K closely; stop if K >5.5 or eGFR <30"),
bang("Thiazides alone: NOT for HF oedema – use loop diuretics"),
],
"ECG / ECHO": [
star("Echo: EF, wall motion, diastolic parameters (E/A, E/e')"),
dot("HFpEF: preserved EF + diastolic dysfunction Grade II+"),
dot("BNP >100, NT-proBNP >300 (acute); higher cutoffs for HFpEF"),
bang("BNP falsely LOW in obesity; falsely HIGH in renal failure"),
],
"DRUG DETAILS": [
star("Sacubitril/Valsartan: start 49/51mg BD → titrate to 97/103mg"),
dot("Spironolactone 25mg OD (RALES); Eplerenone 25mg (EMPHASIS)"),
dot("Ivabradine: if sinus rhythm + HR ≥70 + EF <35% on max BB"),
],
"SURGERY / DEVICE": [
star("ICD: primary prevention EF <35%, NYHA II-III, ≥3mo GDMT"),
star("CRT-D: EF <35%, LBBB, QRS ≥150ms, NYHA III-IV"),
dot("LVAD: bridge-to-transplant or destination therapy"),
dot("Transplant: NYHA IV despite GDMT; age <70"),
],
},
{
"title": "VALVULAR HD",
"color": "brown",
"light": "brownlt",
"KEY NUMBERS": [
star("<b>AS severe:</b> AVA <1 cm², gradient >40 mmHg, Vmax >4 m/s"),
star("<b>MR surgery:</b> EF <60% OR LVESD >40 mm"),
star("<b>MS:</b> MVA <1.5 cm²; PBMC if Wilkins ≤8"),
star("<b>AR surgery:</b> EF <50% OR LVESD >50 mm"),
dot("Prophylaxis: penicillin 10yr or age 40; severe MR: lifelong"),
],
"1st LINE Rx": [
star("Symptomatic severe AS → <b>AVR (surgery or TAVI)</b>"),
star("MS: PBMC if Wilkins ≤8, no LA thrombus, no mod+ MR"),
star("RHD: Benzathine Penicillin G 1.2 MU IM every 4 weeks"),
dot("Asymptomatic severe AS with EF <50%: intervention"),
dot("AR: vasodilators (ACEi/nifedipine) if symptomatic, not surgical candidate"),
],
"LANDMARK TRIALS": [
star("<b>PARTNER 3:</b> TAVI non-inferior to SAVR at low surgical risk"),
star("<b>PARTNER 2:</b> TAVI non-inferior at intermediate risk"),
dot("EVOLUT Low Risk: similar results to PARTNER 3"),
],
"TRAPS / DON'T": [
bang("AS: <b>NO vasodilators</b> (nitrates, ACEi) – hypotension risk"),
bang("PBMC: <b>NOT</b> if LA thrombus present"),
bang("Paradoxical low-flow low-gradient AS: need dobutamine stress echo"),
bang("Valvular AF (rheumatic MS): warfarin only – NO DOACs"),
],
"ECG / ECHO": [
star("AS: slow-rising carotid pulse (pulsus parvus et tardus)"),
star("MS: opening snap, loud S1, rumbling mid-diastolic murmur"),
star("AR: wide pulse pressure, Corrigan's pulse, de Musset's sign"),
dot("MR: holosystolic murmur, S3 gallop in severe acute MR"),
],
"DRUG DETAILS": [
star("Warfarin: mechanical valve (target INR 2.5-3.5 MVR; 2-3 AVR)"),
dot("Bioprosthetic valve: aspirin 75mg + anticoag 3 months"),
dot("IE prophylaxis: Amoxicillin 2g PO 1h before dental procedure"),
],
"SURGERY / DEVICE": [
star("TAVI: PARTNER 3 shows non-inferior to SAVR at low risk"),
star("SAVR: preferred if concurrent CABG needed; bicuspid valve"),
star("MR repair > replacement if anatomy suitable (lower mortality)"),
dot("Wilkins components: mobility, thickening, calcification, subvalvular"),
],
},
{
"title": "ARRHYTHMIAS",
"color": "purple",
"light": "purplt",
"KEY NUMBERS": [
star("CHA₂DS₂-VASc ≥2 (men) / ≥3 (women) → OAC"),
star("Lenient rate control target: <b><110 bpm</b> (RACE II)"),
star("QTc prolonged: >450ms (men), >470ms (women), danger >500ms"),
dot("Torsades: IV MgSO₄ 2g over 15 min"),
dot("Brugada: fever can unmask; check Na channel blockers"),
],
"1st LINE Rx": [
star("AF rate control: <b>BB > diltiazem/verapamil > digoxin</b>"),
star("AF anticoag: <b>DOAC preferred</b> (non-valvular AF)"),
star("Valvular AF: <b>warfarin ONLY</b> – no DOACs"),
dot("SVT: vagal → Adenosine 6mg IV (if no response: 12mg)"),
dot("VF/pulseless VT: <b>CPR + defibrillation immediately</b>"),
],
"LANDMARK TRIALS": [
star("<b>EAST-AFNET 4:</b> early rhythm control 21% RRR CV outcomes"),
star("<b>RACE II:</b> lenient rate <110 non-inferior to strict <80"),
star("<b>AFFIRM:</b> rate ≈ rhythm in older AF patients"),
dot("RE-LY/ROCKET/ARISTOTLE: DOACs non-inferior to warfarin in AF"),
],
"TRAPS / DON'T": [
bang("Valvular AF (rheumatic MS / mechanical valve): <b>NO DOACs</b>"),
bang("WPW + AF: <b>NO adenosine, NO digoxin, NO verapamil</b>"),
bang("Flecainide: <b>NOT</b> if structural heart disease"),
bang("Amiodarone: check TFTs, LFTs, PFTs every 6 months"),
],
"ECG / ECHO": [
star("AF: irregularly irregular, no P waves, fibrillatory baseline"),
star("Brugada type 1: coved ST ≥2mm V1-V3 + RBBB morphology"),
star("LQT: corrected QTc >450 (men) or >470 (women)"),
dot("AVNRT: narrow QRS, pseudo-R' in V1, P in QRS or just after"),
],
"DRUG DETAILS": [
star("Amiodarone: 200mg TDS 4wks → 200mg BD 4wks → 200mg OD"),
star("Ticagrelor: reversal with idarucizumab – NO, that's dabigatran"),
dot("Dabigatran reversal: <b>Idarucizumab</b>"),
dot("Factor Xa inhibitor reversal: <b>Andexanet alfa</b>"),
],
"SURGERY / DEVICE": [
star("AF ablation: pulmonary vein isolation; ~70% cure rate at 1yr"),
star("SVT ablation: 95%+ cure; preferred over lifelong drugs"),
dot("ICD: sustained VT or aborted SCD"),
dot("Pacemaker: complete heart block, sick sinus syndrome symptomatic"),
],
},
{
"title": "CARDIOMYOPATHY",
"color": "red",
"light": "redlt",
"KEY NUMBERS": [
star("HCM ICD: septum ≥30mm, NSVT, fam hx SCD, syncope, ↓BP response to exercise"),
star("HCM: LVOT obstruction if gradient ≥30 mmHg (haemodynamically significant ≥50)"),
star("DCM: EF <40%, dilated LV; EF <35% = ICD criterion"),
dot("ARVC: diagnosis by Task Force criteria (major + minor)"),
],
"1st LINE Rx": [
star("HCM obstructive: BB (metoprolol/atenolol) or verapamil"),
star("HCM refractory: <b>Mavacamten</b> (EXPLORER-HCM)"),
star("DCM: GDMT (same as HFrEF – 5-drug regimen)"),
dot("ARVC: BB; ICD if high risk; avoid strenuous exercise"),
],
"LANDMARK TRIALS": [
star("<b>EXPLORER-HCM:</b> Mavacamten 27% functional class improvement"),
dot("MAVA-LTE: sustained benefit of Mavacamten at 5yr"),
],
"TRAPS / DON'T": [
bang("HCM + AF: <b>anticoagulate regardless of CHA₂DS₂-VASc</b>"),
bang("HCM: <b>NO digoxin, NO nitrates, NO diuretics</b> (worsens obstruction)"),
bang("HCM: DHP calcium channel blockers CONTRAINDICATED"),
bang("ARVC: stop competitive sports – risk of SCD with exercise"),
],
"ECG / ECHO": [
star("HCM: LVH, septal Q waves leads I/aVL/V5-V6, giant T-wave inversion"),
star("ARVC: epsilon wave (terminal notch) after QRS in V1-V3"),
star("DCM: LBBB pattern common; dilated LV, global hypokinesis"),
dot("HCM echo: SAM of anterior MV leaflet, LVOT gradient on Doppler"),
],
"DRUG DETAILS": [
star("Mavacamten: allosteric cardiac myosin inhibitor; reversible"),
star("Disopyramide: negative inotrope → reduces LVOT gradient (add to BB)"),
dot("Avoid high-dose diuretics in HCM – reduces preload → ↑ obstruction"),
],
"SURGERY / DEVICE": [
star("Septal myectomy (Morrow procedure): gold standard for refractory HCM"),
star("Alcohol septal ablation: alternative to surgery (older/comorbid patients)"),
dot("ICD: primary prevention if ≥1 AHA risk factor for SCD"),
dot("Heart transplant: end-stage DCM or restrictive CM"),
],
},
{
"title": "PERICARDIAL Dz",
"color": "green",
"light": "greenlt",
"KEY NUMBERS": [
star("Pericarditis diagnosis: <b>2 of 4</b> criteria"),
star("Tamponade pulsus paradoxus: >10 mmHg drop in SBP on inspiration"),
star("Colchicine halves recurrence (COPE trial: 0.5mg BD x3 months)"),
dot("Constrictive: equalisation of diastolic pressures (±5 mmHg)"),
dot("Tamponade drainage: drain if >20mm echo-free space or haemodynamic compromise"),
],
"1st LINE Rx": [
star("Acute pericarditis: <b>NSAIDs + Colchicine</b> (both, not either)"),
star("Pericarditis 4 criteria: <i>pleuritic chest pain, friction rub, ST elevation, pericardial effusion</i>"),
star("Tamponade: <b>pericardiocentesis</b> (subxiphoid approach)"),
dot("Constrictive: pericardiectomy (only definitive treatment)"),
dot("Uraemic pericarditis: <b>dialysis</b> even without haemodynamic compromise"),
],
"LANDMARK TRIALS": [
star("<b>COPE trial:</b> Colchicine + NSAIDs vs NSAIDs alone → halved recurrence"),
star("<b>ICAP trial:</b> Colchicine in first episode → 38% ↓ recurrence at 18 months"),
dot("CORP/CORP-2: Colchicine prevents recurrent pericarditis"),
],
"TRAPS / DON'T": [
bang("Tamponade: <b>Kussmaul's sign ABSENT</b> (present in constrictive only)"),
bang("Constrictive: <b>Kussmaul's sign PRESENT</b> (JVP rises on inspiration)"),
bang("Pericarditis: <b>avoid steroids</b> (increases recurrence – COPE data)"),
bang("Tamponade: <b>AVOID diuretics/vasodilators</b> – will precipitate collapse"),
],
"ECG / ECHO": [
star("Pericarditis ECG: diffuse saddle-shaped ST elevation + PR depression"),
star("Tamponade ECG: <b>electrical alternans</b> + sinus tachycardia"),
star("Echo: RA collapse in early diastole, RV collapse in late diastole"),
dot("Constrictive: septal bounce, inspiratory shift, preserved tissue Doppler"),
],
"DRUG DETAILS": [
star("Colchicine: 0.5mg BD (>70kg) or 0.5mg OD (<70kg) x 3 months"),
dot("NSAIDs: Aspirin 750mg TDS (preferred in post-MI pericarditis) or ibuprofen 600mg TDS"),
bang("Anticoagulants: use cautiously in pericarditis – risk of haemorrhagic tamponade"),
],
"SURGERY / DEVICE": [
star("Pericardiocentesis: <b>echo-guided, subxiphoid approach</b>"),
star("Pericardiectomy: for constrictive pericarditis (mortality 5-10%)"),
dot("Surgical drainage: recurrent tamponade, purulent pericarditis, malignancy"),
],
},
]
# ══════════════════════════════════════════════════════════════════════════════
# BUILD THE SINGLE-PAGE TABLE
# ══════════════════════════════════════════════════════════════════════════════
def build_page():
N = len(TOPICS) # 7
ROW_LBL_W = 18 * mm
available_w = PAGE_W - 2 * MARGIN - ROW_LBL_W
col_w = available_w / N # equal width per topic
# ── Build the grid data structure ─────────────────────────────────────────
# grid[row][col] = reportlab flowable or list
# Row 0 = topic headers
# Rows 1..7 = content rows
# Header row
header_row = [P("TOPIC", sz=7, bold=True, color="white", align=TA_CENTER)]
for td in TOPICS:
header_row.append(P(td["title"], sz=8, bold=True, color="white", align=TA_CENTER))
# Content rows
all_rows = [header_row]
for ri, row_label in enumerate(ROWS):
row = [P(row_label, sz=6.5, bold=True, color="white", align=TA_CENTER)]
for td in TOPICS:
items = td.get(row_label, [dot("—")])
# wrap in a mini inner table
inner_rows = [[item] for item in items]
inner_t = Table(inner_rows, colWidths=[col_w - 3])
inner_t.setStyle(TableStyle([
("TOPPADDING", (0,0),(-1,-1), 1.2),
("BOTTOMPADDING", (0,0),(-1,-1), 1.2),
("LEFTPADDING", (0,0),(-1,-1), 2),
("RIGHTPADDING", (0,0),(-1,-1), 1),
("VALIGN", (0,0),(-1,-1), "TOP"),
]))
row.append(inner_t)
all_rows.append(row)
# Column widths
col_widths = [ROW_LBL_W] + [col_w] * N
# Row heights – header taller, content rows equal
usable_h = PAGE_H - 2 * MARGIN - 12 * mm # 12mm for title bar
hdr_h = 9 * mm
content_h = (usable_h - hdr_h) / len(ROWS)
row_heights = [hdr_h] + [content_h] * len(ROWS)
# Build main table
main_t = Table(all_rows, colWidths=col_widths, rowHeights=row_heights)
# ── Styles ────────────────────────────────────────────────────────────────
style_cmds = [
# Global
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 2),
("BOTTOMPADDING",(0,0), (-1,-1), 2),
("LEFTPADDING", (0,0), (-1,-1), 2),
("RIGHTPADDING", (0,0), (-1,-1), 2),
# Grid lines
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#AEB6BF")),
("BOX", (0,0), (-1,-1), 1.5, colors.HexColor("#0D2137")),
# Row label spine (col 0) – dark navy
("BACKGROUND", (0,0), (0,-1), C["navy"]),
("ALIGN", (0,0), (0,-1), "CENTER"),
("VALIGN", (0,1), (0,-1), "MIDDLE"),
# Header row (row 0)
("BACKGROUND", (0,0), (-1,0), C["navy"]),
("ALIGN", (0,0), (-1,0), "CENTER"),
("VALIGN", (0,0), (-1,0), "MIDDLE"),
# Thick separators between topics
("LINEAFTER", (0,0), (-1,-1), 1.0, colors.HexColor("#5D6D7E")),
]
# Per-topic column backgrounds (alternating light colors)
row_bg_map = {
"KEY NUMBERS": [C["skylt"], C["skylt"], C["teallt"], C["brownlt"], C["purplt"], C["redlt"], C["greenlt"]],
"1st LINE Rx": [C["sky"], C["sky"], colors.HexColor("#C8EAF5"), C["brownlt"], C["purplt"], C["redlt"], C["greenlt"]],
"LANDMARK TRIALS": [colors.HexColor("#E8F4FB"), colors.HexColor("#E8F4FB"), colors.HexColor("#D1ECF0"), colors.HexColor("#FDEBD0"), colors.HexColor("#E8DAEF"), colors.HexColor("#FADBD8"), colors.HexColor("#D5F5E3")],
"TRAPS / DON'T": [colors.HexColor("#FFF0F0")] * 7,
"ECG / ECHO": [colors.HexColor("#F0F3FA")] * 7,
"DRUG DETAILS": [colors.HexColor("#FFFDE7")] * 7,
"SURGERY / DEVICE": [colors.HexColor("#F0FFF4")] * 7,
}
for ri, row_label in enumerate(ROWS):
actual_row = ri + 1 # row 0 = header
bgs = row_bg_map.get(row_label, [C["gray"]] * 7)
for ci, bg in enumerate(bgs):
style_cmds.append(("BACKGROUND", (ci+1, actual_row), (ci+1, actual_row), bg))
# Topic header colors
topic_header_colors = [C["navy"], C["blue"], C["teal"], C["brown"],
C["purple"], C["red"], C["green"]]
for ci, tc in enumerate(topic_header_colors):
style_cmds.append(("BACKGROUND", (ci+1, 0), (ci+1, 0), tc))
main_t.setStyle(TableStyle(style_cmds))
return main_t
# ══════════════════════════════════════════════════════════════════════════════
# DRAW
# ══════════════════════════════════════════════════════════════════════════════
TMP = "/tmp/NEET_SS_Cardiology_Flashcards.pdf"
DEST = "/home/daytona/workspace/neet-ss-guide/NEET_SS_Cardiology_Flashcards.pdf"
c = pdfcanvas.Canvas(TMP, pagesize=landscape(A3))
w, h = landscape(A3)
# Background
c.setFillColor(C["navy"])
c.rect(0, 0, w, h, fill=1, stroke=0)
# Title bar
c.setFillColor(C["navy"])
c.rect(0, h - 12*mm, w, 12*mm, fill=1, stroke=0)
c.setFillColor(colors.HexColor("#F39C12"))
c.rect(0, h - 13*mm, w, 1.5, fill=1, stroke=0)
c.setFont("Helvetica-Bold", 11)
c.setFillColor(colors.white)
c.drawString(MARGIN, h - 8.5*mm,
"NEET SS · General Medicine · CARDIOLOGY — 7-Topic Comparison Flashcard · Last-Day Rapid Revision")
c.setFont("Helvetica", 8)
c.setFillColor(colors.HexColor("#AEDAF0"))
c.drawRightString(w - MARGIN, h - 8.5*mm,
"★ = must know | ! = trap | • = good to know | Week 1 · Day 1–6 content")
# Footer
c.setFillColor(C["navy"])
c.rect(0, 0, w, 5*mm, fill=1, stroke=0)
c.setFont("Helvetica", 6.5)
c.setFillColor(colors.HexColor("#AEDAF0"))
c.drawCentredString(w/2, 1.8*mm,
"Harrison's 22E · Braunwald's Heart Disease · Marrow NEET SS Medicine | June 27 – July 3, 2026")
# Draw the table using platypus in a canvas frame
from reportlab.platypus import Frame
table_h = h - 2*MARGIN - 12*mm - 5*mm # below title, above footer
table_w = w - 2*MARGIN
frame = Frame(MARGIN, 5*mm + MARGIN/2, table_w, table_h,
leftPadding=0, rightPadding=0, topPadding=0, bottomPadding=0)
main_table = build_page()
frame.addFromList([main_table], c)
c.showPage()
c.save()
with open(TMP, "rb") as src, open(DEST, "wb") as dst:
dst.write(src.read())
print(f"Saved: {DEST}")
cd /home/daytona/workspace/neet-ss-guide && python build_flashcard.py 2>&1
ls -lh /home/daytona/workspace/neet-ss-guide/NEET_SS_Cardiology_Flashcards.pdf
~/neet-ss-guide/build_flashcard.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/neet-ss-guide/build_flashcard.py'
~/neet-ss-guide/build_flashcard.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/neet-ss-guide/build_flashcard.py'
cd /home/daytona/workspace/neet-ss-guide && python build_flashcard.py 2>&1
ls -lh /home/daytona/workspace/neet-ss-guide/NEET_SS_Cardiology_Flashcards.pdf
NEET SS Cardiology Flashcards
PDF Document · PDF
| STEMI | NSTEMI/UA | Heart Failure | Valvular HD | Arrhythmias | Cardiomyopathy | Pericardial | |
|---|---|---|---|---|---|---|---|
| Key Numbers | D2B 90/120 min | TIMI/GRACE scores | EF cutoffs, ICD EF <35% | AS AVA <1, MR EF <60% | CHA₂DS₂-VASc ≥2/3 | HCM septum ≥30mm | 2-of-4 criteria |
| 1st Line Rx | Aspirin + Ticagrelor + PCI | Fondaparinux + Ticagrelor | 5-drug GDMT | AVR/TAVI, PBMC | BB > CCB > Digoxin | BB + Mavacamten | NSAIDs + Colchicine |
| Landmark Trials | PLATO, STREAM | PLATO, OASIS-5 | PARADIGM, DAPA, EMPEROR | PARTNER 3 | EAST-AFNET 4, RACE II | EXPLORER-HCM | COPE/ICAP |
| Traps / Don't | No nitrates in RV infarct | No GP IIb/IIIa routine | Atenolol NOT proven in HF | No vasodilators in AS | No DOACs in valvular AF | No digoxin in HCM | No steroids |
| ECG / Echo | V4R for RV, territory map | Wellens' pattern | E/A, E/e', BNP traps | AS: pulsus parvus | AF: irregular, no P-wave | SAM, epsilon wave | Saddle ST, electrical alternans |
| Drug Details | Ticagrelor 180mg load | Enoxaparin dosing | ARNI 36h washout | Warfarin for mechanical | Amiodarone dosing | Mavacamten mechanism | Colchicine 0.5mg BD |
| Surgery / Device | IABP/Impella in shock | DES, CABG criteria | ICD/CRT criteria | TAVI vs SAVR | PVI ablation, ICD | Myectomy vs ablation | Pericardiocentesis |
Can you provide braunwald and harrison orignal Pdf/link to download?