Prepare a ppt topic cardioembolic stroke with subheading etiology symptoms and signs relevant findings treatment
mkdir -p /tmp/workspace/cardioembolic-stroke && ls /tmp/workspace/
~/cardioembolic-stroke/build_ppt.py
from pptx import Presentation
from pptx.util import Inches, Pt, Emu
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.util import Inches, Pt
import copy
# ── Colour palette ────────────────────────────────────────────────────────────
DARK_NAVY = RGBColor(0x0D, 0x1B, 0x3E) # slide background / title bar
MID_BLUE = RGBColor(0x1A, 0x53, 0x8A) # accent bars
ACCENT_TEAL = RGBColor(0x00, 0x8C, 0x9A) # bullet icons / highlight
LIGHT_GREY = RGBColor(0xF4, 0xF6, 0xF8) # content area bg
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
TEXT_DARK = RGBColor(0x1E, 0x1E, 0x2E)
YELLOW_HL = RGBColor(0xFF, 0xD7, 0x00) # key stat highlight
prs = Presentation()
prs.slide_width = Inches(13.333)
prs.slide_height = Inches(7.5)
blank = prs.slide_layouts[6] # fully blank
# ── Helper utilities ──────────────────────────────────────────────────────────
def add_rect(slide, x, y, w, h, fill_rgb, alpha=None):
from pptx.util import Inches
shape = slide.shapes.add_shape(1, x, y, w, h) # MSO_SHAPE_TYPE.RECTANGLE = 1
shape.line.fill.background() # no border
shape.fill.solid()
shape.fill.fore_color.rgb = fill_rgb
return shape
def add_textbox(slide, x, y, w, h, text, font_size=18, bold=False,
color=WHITE, align=PP_ALIGN.LEFT, wrap=True,
italic=False, v_anchor=MSO_ANCHOR.TOP):
tb = slide.shapes.add_textbox(x, y, w, h)
tf = tb.text_frame
tf.word_wrap = wrap
tf.vertical_anchor = v_anchor
tf.margin_left = 0; tf.margin_right = 0
tf.margin_top = 0; tf.margin_bottom = 0
p = tf.paragraphs[0]
p.alignment = align
r = p.add_run()
r.text = text
r.font.size = Pt(font_size)
r.font.bold = bold
r.font.italic = italic
r.font.color.rgb = color
r.font.name = "Calibri"
return tb, tf
def add_slide_chrome(slide, title_text, subtitle_text=""):
"""Add the common top bar + title."""
# Full background
add_rect(slide, 0, 0, prs.slide_width, prs.slide_height, LIGHT_GREY)
# Top banner
add_rect(slide, 0, 0, prs.slide_width, Inches(1.15), DARK_NAVY)
# Left accent stripe
add_rect(slide, 0, Inches(1.15), Inches(0.07), prs.slide_height - Inches(1.15), ACCENT_TEAL)
# Title text
add_textbox(slide, Inches(0.2), Inches(0.12), Inches(12.5), Inches(0.75),
title_text, font_size=30, bold=True, color=WHITE, align=PP_ALIGN.LEFT)
if subtitle_text:
add_textbox(slide, Inches(0.2), Inches(0.72), Inches(12.5), Inches(0.36),
subtitle_text, font_size=14, bold=False, color=ACCENT_TEAL,
align=PP_ALIGN.LEFT)
# Bottom accent bar
add_rect(slide, 0, Inches(7.2), prs.slide_width, Inches(0.3), MID_BLUE)
add_textbox(slide, Inches(0.2), Inches(7.22), Inches(10), Inches(0.26),
"Sources: Harrison's Principles of Internal Medicine 22E | Fuster & Hurst's The Heart 15E | Frameworks for Internal Medicine",
font_size=8, color=WHITE, align=PP_ALIGN.LEFT)
def add_bullets(slide, x, y, w, h, items, font_size=16, color=TEXT_DARK,
bullet_color=ACCENT_TEAL, indent=0):
"""Add a bulleted list as stacked textboxes for easy formatting."""
from pptx.oxml.ns import qn
import lxml.etree as etree
tb = slide.shapes.add_textbox(x, y, w, h)
tf = tb.text_frame
tf.word_wrap = True
tf.margin_left = Inches(0.08)
tf.margin_top = Inches(0.05)
first = True
for item in items:
if first:
p = tf.paragraphs[0]
first = False
else:
p = tf.add_paragraph()
p.space_before = Pt(4)
p.space_after = Pt(2)
# bullet dot
run_dot = p.add_run()
run_dot.text = "● "
run_dot.font.size = Pt(font_size - 2)
run_dot.font.color.rgb = bullet_color
run_dot.font.name = "Calibri"
# text
run_txt = p.add_run()
run_txt.text = item
run_txt.font.size = Pt(font_size)
run_txt.font.color.rgb = color
run_txt.font.name = "Calibri"
return tb
def stat_box(slide, x, y, w, h, label, value, val_color=YELLOW_HL):
"""A highlighted stat card."""
add_rect(slide, x, y, w, h, MID_BLUE)
add_textbox(slide, x + Inches(0.1), y + Inches(0.05), w - Inches(0.2), Inches(0.45),
value, font_size=28, bold=True, color=val_color,
align=PP_ALIGN.CENTER, v_anchor=MSO_ANCHOR.MIDDLE)
add_textbox(slide, x + Inches(0.1), y + Inches(0.52), w - Inches(0.2), Inches(0.38),
label, font_size=12, bold=False, color=WHITE,
align=PP_ALIGN.CENTER, v_anchor=MSO_ANCHOR.MIDDLE)
# ═══════════════════════════════════════════════════════════════════════════════
# SLIDE 1 — Title Slide
# ═══════════════════════════════════════════════════════════════════════════════
s = prs.slides.add_slide(blank)
add_rect(s, 0, 0, prs.slide_width, prs.slide_height, DARK_NAVY)
# Decorative teal band
add_rect(s, 0, Inches(3.2), prs.slide_width, Inches(0.08), ACCENT_TEAL)
add_rect(s, 0, Inches(5.4), prs.slide_width, Inches(0.05), MID_BLUE)
add_textbox(s, Inches(1), Inches(1.3), Inches(11), Inches(1.2),
"CARDIOEMBOLIC STROKE",
font_size=48, bold=True, color=WHITE, align=PP_ALIGN.CENTER)
add_textbox(s, Inches(1), Inches(2.6), Inches(11), Inches(0.5),
"Etiology | Symptoms & Signs | Relevant Findings | Treatment",
font_size=20, bold=False, color=ACCENT_TEAL, align=PP_ALIGN.CENTER)
add_textbox(s, Inches(2), Inches(3.5), Inches(9), Inches(0.4),
"Cardioembolic stroke accounts for ~20–25% of all ischemic strokes",
font_size=16, italic=True, color=LIGHT_GREY, align=PP_ALIGN.CENTER)
# Stat boxes on title slide
stat_box(s, Inches(1.5), Inches(4.4), Inches(2.2), Inches(1.0), "of all ischemic strokes", "~20%")
stat_box(s, Inches(4.1), Inches(4.4), Inches(2.2), Inches(1.0), "annual stroke risk in AF", "~5%")
stat_box(s, Inches(6.7), Inches(4.4), Inches(2.2), Inches(1.0), "risk reduction with OAC", "~67%")
stat_box(s, Inches(9.3), Inches(4.4), Inches(2.2), Inches(1.0), "PFO in general population", "~15%")
add_rect(s, 0, Inches(7.2), prs.slide_width, Inches(0.3), MID_BLUE)
add_textbox(s, Inches(0.2), Inches(7.22), Inches(10), Inches(0.26),
"Sources: Harrison's 22E | Fuster & Hurst's The Heart 15E | Frameworks for Internal Medicine",
font_size=8, color=WHITE, align=PP_ALIGN.LEFT)
# ═══════════════════════════════════════════════════════════════════════════════
# SLIDE 2 — Overview & Pathophysiology
# ═══════════════════════════════════════════════════════════════════════════════
s = prs.slides.add_slide(blank)
add_slide_chrome(s, "Overview & Pathophysiology", "Mechanism of cardioembolic stroke")
# Left column
add_rect(s, Inches(0.15), Inches(1.25), Inches(6.2), Inches(5.75), WHITE)
add_textbox(s, Inches(0.25), Inches(1.35), Inches(6.0), Inches(0.4),
"Definition & Mechanism", font_size=16, bold=True, color=MID_BLUE)
bullets_l = [
"Cardioembolism: ~20% of all ischemic strokes",
"Thrombus forms on atrial/ventricular wall or left heart valves → detaches → embolises into arterial circulation",
"Thrombus may fragment/lyse quickly → TIA; prolonged occlusion → stroke",
"Embolic strokes: sudden onset with MAXIMUM neurologic deficit at onset",
"Petechial haemorrhages may follow reperfusion (distinguish from frank haemorrhagic transformation)",
"Most common lodgement sites: ICA, MCA, PCA, and their branches",
"Large embolus (3–4 mm) occludes MCA stem → large infarct (deep grey + white matter + cortex)",
"Multiple-territory infarction is a hallmark (unlike thrombotic strokes)"
]
add_bullets(s, Inches(0.2), Inches(1.8), Inches(6.1), Inches(5.0), bullets_l, font_size=14)
# Right column
add_rect(s, Inches(6.55), Inches(1.25), Inches(6.6), Inches(5.75), WHITE)
add_textbox(s, Inches(6.65), Inches(1.35), Inches(6.4), Inches(0.4),
"Embolism Mechanisms", font_size=16, bold=True, color=MID_BLUE)
mechanisms = [
("Cardioembolism", "Large cardiac output → brain; thrombus originates in heart chambers"),
("Artery-to-Artery", "Atherosclerotic plaque fragments travel downstream"),
("Paradoxical Embolism", "Venous thrombus crosses to arterial circulation via PFO or ASD"),
("Fat / Tumour Emboli", "Rare; fat (fractures), atrial myxoma, bacterial vegetations"),
]
ypos = Inches(1.85)
for title, desc in mechanisms:
add_rect(s, Inches(6.6), ypos, Inches(6.4), Inches(0.28), ACCENT_TEAL)
add_textbox(s, Inches(6.7), ypos, Inches(6.2), Inches(0.28),
title, font_size=13, bold=True, color=WHITE)
add_textbox(s, Inches(6.7), ypos + Inches(0.3), Inches(6.2), Inches(0.42),
desc, font_size=12, color=TEXT_DARK)
ypos += Inches(0.82)
# ═══════════════════════════════════════════════════════════════════════════════
# SLIDE 3 — Etiology
# ═══════════════════════════════════════════════════════════════════════════════
s = prs.slides.add_slide(blank)
add_slide_chrome(s, "Etiology", "Major cardiac sources of cerebral embolism")
# Two-column layout
# Col 1 — High risk
add_rect(s, Inches(0.15), Inches(1.25), Inches(6.0), Inches(5.75), WHITE)
add_rect(s, Inches(0.15), Inches(1.25), Inches(6.0), Inches(0.42), MID_BLUE)
add_textbox(s, Inches(0.25), Inches(1.27), Inches(5.8), Inches(0.38),
"HIGH RISK — Anticoagulation Standard of Care", font_size=13, bold=True, color=WHITE)
high_risk = [
"Non-rheumatic (non-valvular) atrial fibrillation — MOST COMMON cause overall",
"Atrial flutter",
"Left atrial / left atrial appendage thrombus",
"Left ventricular thrombus",
"Recent anterior MI (<4 weeks) with LV thrombus",
"Left ventricular assist device (LVAD)",
"Rheumatic mitral stenosis with AF / recurrent embolic events",
"Mechanical prosthetic valves (aortic or mitral)",
"Ischaemic cardiomyopathy with very low EF (<15%)",
]
add_bullets(s, Inches(0.2), Inches(1.75), Inches(5.9), Inches(5.0), high_risk, font_size=13)
# Col 2 — Moderate / other
add_rect(s, Inches(6.45), Inches(1.25), Inches(6.75), Inches(5.75), WHITE)
add_rect(s, Inches(6.45), Inches(1.25), Inches(6.75), Inches(0.42), ACCENT_TEAL)
add_textbox(s, Inches(6.55), Inches(1.27), Inches(6.55), Inches(0.38),
"MODERATE / SPECIAL RISK", font_size=13, bold=True, color=WHITE)
mod_risk = [
"Infective endocarditis (antibiotics; anticoagulation CONTRAINDICATED)",
"Non-bacterial thrombotic endocarditis (marantic) — especially with hypercoagulability",
"Papillary fibroelastoma (anticoag if surgery contraindicated)",
"Atrial myxoma (surgical resection — anticoag contraindicated)",
"Mitral valve prolapse (anticoag only if AF present; aspirin if cryptogenic TIA)",
"Bioprosthetic aortic/mitral valve — antiplatelet standard of care",
"Patent foramen ovale (PFO) — cryptogenic stroke, closure if causative",
"Aortic arch mobile atheroma — aspirin or OAC",
"Mitral annular calcification — aspirin unless AF (then OAC)",
"Paradoxical embolism via ASD / pulmonary AVM",
]
add_bullets(s, Inches(6.5), Inches(1.75), Inches(6.65), Inches(5.0), mod_risk, font_size=13)
# ═══════════════════════════════════════════════════════════════════════════════
# SLIDE 4 — Symptoms & Signs
# ═══════════════════════════════════════════════════════════════════════════════
s = prs.slides.add_slide(blank)
add_slide_chrome(s, "Symptoms & Signs", "Clinical presentation of cardioembolic stroke")
# Top banner note
add_rect(s, Inches(0.15), Inches(1.28), Inches(13.0), Inches(0.42), MID_BLUE)
add_textbox(s, Inches(0.3), Inches(1.3), Inches(12.7), Inches(0.38),
"KEY FEATURE: Sudden onset with maximum deficit at onset; may involve multiple vascular territories simultaneously",
font_size=13, bold=True, color=YELLOW_HL, align=PP_ALIGN.LEFT)
# Three columns: MCA, ICA/ACA, PCA/Posterior
col_w = Inches(4.15)
cols = [
{
"title": "MCA Territory",
"items": [
"Contralateral hemiplegia (face + arm > leg)",
"Contralateral hemisensory loss",
"Homonymous hemianopia",
"Aphasia (dominant hemisphere — Broca, Wernicke or global)",
"Neglect / anosognosia (non-dominant)",
"Gaze deviation towards infarct side",
"Dysarthria",
"Large MCA: impaired consciousness, cerebral oedema (malignant MCA syndrome)",
]
},
{
"title": "ICA / ACA Territory",
"items": [
"ICA occlusion: combined MCA + ACA territory deficits",
"Monocular blindness (amaurosis fugax) — ophthalmic artery",
"ACA: contralateral leg > arm weakness",
"ACA: abulia, personality change, urinary incontinence",
"Carotid terminus occlusion: large hemispheric infarct ± herniation",
]
},
{
"title": "Posterior / Vertebrobasilar",
"items": [
"PCA: contralateral hemianopia, visual agnosia, alexia",
"Basilar apex emboli: bilateral signs (hallmark), sudden coma",
"Weber syndrome (CN III palsy + contralateral hemiplegia)",
"Cerebellar infarct: ataxia, vertigo, nausea, vomiting",
"Lateral medullary (Wallenberg) syndrome",
"Diplopia, nystagmus, dysphagia, dysarthria",
"Top-of-basilar: hypersomnolence, pupillary abnormalities",
]
}
]
x = Inches(0.15)
for col in cols:
add_rect(s, x, Inches(1.78), col_w, Inches(5.3), WHITE)
add_rect(s, x, Inches(1.78), col_w, Inches(0.38), ACCENT_TEAL)
add_textbox(s, x + Inches(0.1), Inches(1.80), col_w - Inches(0.2), Inches(0.34),
col["title"], font_size=13, bold=True, color=WHITE)
add_bullets(s, x + Inches(0.05), Inches(2.2), col_w - Inches(0.1), Inches(4.8),
col["items"], font_size=12)
x += col_w + Inches(0.22)
# ═══════════════════════════════════════════════════════════════════════════════
# SLIDE 5 — Relevant Findings (Investigations)
# ═══════════════════════════════════════════════════════════════════════════════
s = prs.slides.add_slide(blank)
add_slide_chrome(s, "Relevant Findings & Investigations", "Diagnostic workup for cardioembolic stroke")
invest = [
{
"cat": "Neuroimaging",
"items": [
"CT brain (non-contrast): first-line — exclude haemorrhage; early ischaemia in <60% within 6 h",
"MRI DWI: most sensitive for acute infarct; shows restricted diffusion within minutes",
"Multiple cortical / subcortical infarcts in DIFFERENT vascular territories → strongly suggests embolism",
"Cortical 'wedge' infarcts or 'rosette' haemorrhagic transformation — embolic pattern",
"MRI FLAIR / GRE: identifies haemorrhagic transformation",
"CT/MR Angiography: identifies vessel occlusion (MCA, ICA, basilar)",
]
},
{
"cat": "Cardiac Investigations",
"items": [
"12-lead ECG: AF, flutter, recent MI (Q waves), LV hypertrophy",
"Prolonged cardiac monitoring (Holter 24–72 h or implantable loop recorder): detect paroxysmal AF",
"Transthoracic echocardiogram (TTE): LV thrombus, wall motion abnormality, valve disease, EF",
"Transesophageal echocardiogram (TEE): superior for LAA thrombus, PFO, aortic arch atheroma, vegetations",
"Bubble-contrast echo (agitated saline): detects right-to-left shunt (PFO/ASD)",
"Transcranial Doppler + bubble study: detect right-to-left shunt (microemboli)",
"Troponin / BNP: myocardial injury, heart failure",
]
},
{
"cat": "Laboratory & Other",
"items": [
"CBC, PT/INR, aPTT, glucose: baseline coagulation, exclude metabolic causes",
"Hypercoagulability screen (protein C/S, antiphospholipid antibodies) in young/cryptogenic stroke",
"CHA₂DS₂-VASc score: quantify stroke risk in AF to guide anticoagulation",
"Carotid duplex / CTA: exclude large-vessel atherosclerosis as alternative source",
"Blood cultures: if infective endocarditis suspected",
"ESR / CRP / ANA: vasculitis / inflammatory causes in young patients",
]
}
]
# Three rows
ypos = Inches(1.28)
for idx, inv in enumerate(invest):
add_rect(s, Inches(0.15), ypos, Inches(13.0), Inches(0.35), MID_BLUE if idx % 2 == 0 else ACCENT_TEAL)
add_textbox(s, Inches(0.3), ypos + Inches(0.03), Inches(12.7), Inches(0.30),
inv["cat"], font_size=14, bold=True, color=WHITE)
add_rect(s, Inches(0.15), ypos + Inches(0.35), Inches(13.0), Inches(1.5), WHITE)
add_bullets(s, Inches(0.25), ypos + Inches(0.38), Inches(12.7), Inches(1.4),
inv["items"], font_size=12)
ypos += Inches(1.95)
# ═══════════════════════════════════════════════════════════════════════════════
# SLIDE 6 — CHA₂DS₂-VASc Score
# ═══════════════════════════════════════════════════════════════════════════════
s = prs.slides.add_slide(blank)
add_slide_chrome(s, "CHA₂DS₂-VASc Score", "Stroke risk stratification in non-valvular atrial fibrillation")
# Table
headers = ["Risk Factor", "Points", "Recommendation"]
rows = [
("C — Congestive Heart Failure / LV dysfunction", "1", ""),
("H — Hypertension", "1", ""),
("A₂ — Age ≥ 75 years", "2", ""),
("D — Diabetes Mellitus", "1", ""),
("S₂ — Prior Stroke / TIA / thromboembolism", "2", ""),
("V — Vascular disease (MI, PAD, aortic plaque)", "1", ""),
("A — Age 65–74 years", "1", ""),
("Sc — Sex category (Female)", "1", ""),
]
recs = [
("Score 0", "No antithrombotic OR aspirin"),
("Score 1", "Aspirin OR oral anticoagulant (OAC)"),
("Score ≥ 2", "OAC (preferred DOAC over warfarin)"),
]
# Left: table
add_rect(s, Inches(0.15), Inches(1.28), Inches(7.5), Inches(5.72), WHITE)
add_rect(s, Inches(0.15), Inches(1.28), Inches(7.5), Inches(0.38), DARK_NAVY)
hx = Inches(0.2)
for h, hw in zip(headers, [Inches(4.5), Inches(0.9), Inches(1.8)]):
add_textbox(s, hx, Inches(1.3), hw, Inches(0.34), h, font_size=13, bold=True, color=WHITE)
hx += hw
yrow = Inches(1.7)
for i, (rf, pts, _) in enumerate(rows):
bg = LIGHT_GREY if i % 2 == 0 else WHITE
add_rect(s, Inches(0.15), yrow, Inches(7.5), Inches(0.52), bg)
add_textbox(s, Inches(0.25), yrow + Inches(0.05), Inches(4.4), Inches(0.44),
rf, font_size=12, color=TEXT_DARK)
add_textbox(s, Inches(4.75), yrow + Inches(0.05), Inches(0.85), Inches(0.44),
pts, font_size=14, bold=True, color=MID_BLUE, align=PP_ALIGN.CENTER)
yrow += Inches(0.53)
# Right: recommendations
add_rect(s, Inches(7.85), Inches(1.28), Inches(5.35), Inches(5.72), WHITE)
add_rect(s, Inches(7.85), Inches(1.28), Inches(5.35), Inches(0.38), ACCENT_TEAL)
add_textbox(s, Inches(7.95), Inches(1.30), Inches(5.15), Inches(0.34),
"Treatment Recommendations", font_size=14, bold=True, color=WHITE)
ypos2 = Inches(1.75)
for score, rec in recs:
add_rect(s, Inches(7.9), ypos2, Inches(5.2), Inches(0.85), MID_BLUE)
add_textbox(s, Inches(8.0), ypos2 + Inches(0.06), Inches(5.0), Inches(0.35),
score, font_size=14, bold=True, color=YELLOW_HL)
add_textbox(s, Inches(8.0), ypos2 + Inches(0.42), Inches(5.0), Inches(0.38),
rec, font_size=12, color=WHITE)
ypos2 += Inches(1.0)
# Max score note
add_textbox(s, Inches(7.9), ypos2 + Inches(0.3), Inches(5.15), Inches(0.4),
"Maximum score: 9\nFemale sex alone (score=1) does NOT mandate anticoagulation",
font_size=11, italic=True, color=MID_BLUE)
# ═══════════════════════════════════════════════════════════════════════════════
# SLIDE 7 — Treatment: Acute Management
# ═══════════════════════════════════════════════════════════════════════════════
s = prs.slides.add_slide(blank)
add_slide_chrome(s, "Treatment: Acute Management", "Immediate intervention in cardioembolic stroke")
boxes = [
{
"title": "1. IV Thrombolysis (tPA)",
"color": MID_BLUE,
"items": [
"Alteplase 0.9 mg/kg IV (max 90 mg) — 10% bolus, remainder over 60 min",
"Window: ≤4.5 hours from symptom onset (selected patients up to 9 h with imaging mismatch)",
"DO NOT delay for cardiac workup if within window",
"Haemorrhagic transformation risk is higher in cardioembolic stroke",
"Tenecteplase: emerging as equivalent alternative (single bolus)",
]
},
{
"title": "2. Mechanical Thrombectomy (EVT)",
"color": ACCENT_TEAL,
"items": [
"Indicated for LVO (large vessel occlusion: ICA, M1/M2 MCA, basilar)",
"Window: up to 24 h with perfusion imaging selection (DAWN / DEFUSE-3 criteria)",
"Stent-retriever or aspiration technique",
"Can be combined with IV tPA (drip-and-ship)",
"Cardioembolic clots: often red/fibrin-rich — may respond well to retrieval",
]
},
{
"title": "3. General Supportive Care",
"color": MID_BLUE,
"items": [
"Permissive hypertension: allow BP up to 220/120 mmHg (unless tPA given: <180/105)",
"Normoglycaemia: treat hypo/hyperglycaemia (glucose 140–180 mg/dL)",
"Supplemental O₂ only if SpO₂ <94%; avoid routine O₂",
"Fever management: paracetamol ± cooling (target normothermia)",
"DVT prophylaxis: pneumatic compression stockings acutely",
"Swallow assessment before oral intake",
"Stroke unit admission: reduces mortality and disability",
]
}
]
x = Inches(0.15)
bw = Inches(4.28)
for box in boxes:
add_rect(s, x, Inches(1.28), bw, Inches(5.72), WHITE)
add_rect(s, x, Inches(1.28), bw, Inches(0.4), box["color"])
add_textbox(s, x + Inches(0.1), Inches(1.30), bw - Inches(0.2), Inches(0.36),
box["title"], font_size=13, bold=True, color=WHITE)
add_bullets(s, x + Inches(0.05), Inches(1.73), bw - Inches(0.1), Inches(5.15),
box["items"], font_size=12)
x += bw + Inches(0.18)
# ═══════════════════════════════════════════════════════════════════════════════
# SLIDE 8 — Treatment: Secondary Prevention & Antithrombotic Therapy
# ═══════════════════════════════════════════════════════════════════════════════
s = prs.slides.add_slide(blank)
add_slide_chrome(s, "Treatment: Secondary Prevention", "Antithrombotic therapy & anticoagulation")
# Key messages banner
add_rect(s, Inches(0.15), Inches(1.28), Inches(13.0), Inches(0.4), DARK_NAVY)
add_textbox(s, Inches(0.3), Inches(1.30), Inches(12.7), Inches(0.36),
"OAC reduces recurrent stroke by ~67% in NVAF | DOACs preferred over VKA (warfarin) in most cases",
font_size=13, bold=True, color=YELLOW_HL, align=PP_ALIGN.LEFT)
# Two columns
add_rect(s, Inches(0.15), Inches(1.72), Inches(6.4), Inches(5.28), WHITE)
add_rect(s, Inches(0.15), Inches(1.72), Inches(6.4), Inches(0.38), MID_BLUE)
add_textbox(s, Inches(0.25), Inches(1.74), Inches(6.2), Inches(0.34),
"Direct Oral Anticoagulants (DOACs)", font_size=14, bold=True, color=WHITE)
doacs = [
"Dabigatran (thrombin inhibitor): 110 mg or 150 mg BD — non-inferior to warfarin; 150 mg BD superior; no INR monitoring",
"Apixaban 5 mg BD (factor Xa inhibitor): superior to warfarin (1.27% vs 1.6% endpoint); less major bleeding",
"Rivaroxaban 20 mg OD (factor Xa inhibitor): non-inferior to warfarin; less intracranial haemorrhage",
"Edoxaban 60 mg OD (factor Xa inhibitor): non-inferior to warfarin",
"Reversal agents: Idarucizumab (dabigatran); Andexanet alfa (apixaban, rivaroxaban)",
"DOACs require no routine INR monitoring; minimal dietary interaction",
"AVOID DOACs in: mechanical heart valves, moderate-severe rheumatic mitral stenosis",
]
add_bullets(s, Inches(0.2), Inches(2.14), Inches(6.3), Inches(4.75), doacs, font_size=12)
add_rect(s, Inches(6.75), Inches(1.72), Inches(6.4), Inches(5.28), WHITE)
add_rect(s, Inches(6.75), Inches(1.72), Inches(6.4), Inches(0.38), ACCENT_TEAL)
add_textbox(s, Inches(6.85), Inches(1.74), Inches(6.2), Inches(0.34),
"Vitamin K Antagonists & Special Situations", font_size=14, bold=True, color=WHITE)
vka = [
"Warfarin (VKA): INR 2–3 for NVAF; still gold standard for mechanical valves",
"Mechanical aortic valve (bileaflet): VKA INR 2.5–3.5",
"Mechanical mitral valve: VKA INR 3.0 (range 2.5–3.5)",
"Mechanical valve + AF / low EF: Aspirin + VKA INR 3.0",
"If OAC not tolerated (bleeding risk): Clopidogrel + Aspirin (ACTIVE-A — more effective than aspirin alone but ↑ bleeding)",
"LAA occlusion device (Watchman): non-inferior to DOACs in high bleeding-risk patients",
"Infective endocarditis: antibiotics; anticoagulation CONTRAINDICATED",
"Timing to restart OAC after stroke: typically 2–4 weeks (varies by infarct size & haemorrhagic transformation risk)",
]
add_bullets(s, Inches(6.8), Inches(2.14), Inches(6.3), Inches(4.75), vka, font_size=12)
# ═══════════════════════════════════════════════════════════════════════════════
# SLIDE 9 — Summary
# ═══════════════════════════════════════════════════════════════════════════════
s = prs.slides.add_slide(blank)
add_rect(s, 0, 0, prs.slide_width, prs.slide_height, DARK_NAVY)
add_rect(s, 0, Inches(1.1), prs.slide_width, Inches(0.06), ACCENT_TEAL)
add_rect(s, 0, Inches(6.5), prs.slide_width, Inches(0.06), MID_BLUE)
add_textbox(s, Inches(1), Inches(0.2), Inches(11), Inches(0.8),
"SUMMARY: CARDIOEMBOLIC STROKE",
font_size=34, bold=True, color=WHITE, align=PP_ALIGN.CENTER)
summary_items = [
("Incidence", "~20–25% of all ischaemic strokes; MOST COMMON embolic stroke type"),
("Onset", "Sudden, MAXIMAL deficit at onset; multiple territory involvement is hallmark"),
("Top Aetiology", "Non-valvular atrial fibrillation (AF) — annual stroke risk ~5%"),
("Other Sources", "LV thrombus, MI, prosthetic valves, endocarditis, PFO, cardiomyopathy"),
("Key Investigations", "MRI DWI + MRA, ECG (prolonged monitoring), TTE/TEE, bubble echo, CHA₂DS₂-VASc"),
("Acute Treatment", "IV tPA (≤4.5 h) and/or mechanical thrombectomy for LVO (up to 24 h)"),
("Secondary Prevention", "OAC (DOACs preferred) for AF: reduces recurrence by ~67%"),
("Special Cases", "Mechanical valves → warfarin; Infective endocarditis → antibiotics only"),
]
x_positions = [Inches(0.2), Inches(6.7)]
y_start = Inches(1.25)
for i, (key, val) in enumerate(summary_items):
col = i % 2
row = i // 2
xp = x_positions[col]
yp = y_start + row * Inches(1.22)
add_rect(s, xp, yp, Inches(6.2), Inches(1.1), MID_BLUE)
add_rect(s, xp, yp, Inches(1.8), Inches(1.1), ACCENT_TEAL)
add_textbox(s, xp + Inches(0.1), yp + Inches(0.2), Inches(1.6), Inches(0.65),
key, font_size=12, bold=True, color=WHITE, align=PP_ALIGN.CENTER,
v_anchor=MSO_ANCHOR.MIDDLE)
add_textbox(s, xp + Inches(1.9), yp + Inches(0.08), Inches(4.2), Inches(0.94),
val, font_size=12, color=WHITE, v_anchor=MSO_ANCHOR.MIDDLE)
add_rect(s, 0, Inches(7.2), prs.slide_width, Inches(0.3), MID_BLUE)
add_textbox(s, Inches(0.2), Inches(7.22), Inches(10), Inches(0.26),
"Sources: Harrison's Principles of Internal Medicine 22E | Fuster & Hurst's The Heart 15E | Frameworks for Internal Medicine",
font_size=8, color=WHITE, align=PP_ALIGN.LEFT)
# ── Save ──────────────────────────────────────────────────────────────────────
out_path = "/tmp/workspace/cardioembolic-stroke/Cardioembolic_Stroke.pptx"
prs.save(out_path)
print(f"Saved: {out_path}")
cd /tmp/workspace/cardioembolic-stroke && python build_ppt.py 2>&1
python3 -c " from pptx import Presentation prs = Presentation('/tmp/workspace/cardioembolic-stroke/Cardioembolic_Stroke.pptx') print(f'Slides: {len(prs.slides)}') for i, slide in enumerate(prs.slides, 1): texts = [s.text_frame.text.strip()[:60] for s in slide.shapes if s.has_text_frame and s.text_frame.text.strip()] print(f' Slide {i}: {texts[0] if texts else \"(empty)\"}') "
Cardioembolic Stroke
Presentation · PPTX
| # | Slide | Content |
|---|---|---|
| 1 | Title slide | Key stats: 20% of strokes, 5% annual AF risk, 67% OAC risk reduction, 15% PFO prevalence |
| 2 | Overview & Pathophysiology | Mechanism of clot formation, embolisation, infarct patterns, all 4 embolism types |
| 3 | Etiology | Two-column layout — High risk (AF, LV thrombus, MI, prosthetic valves) vs Moderate/Special risk (endocarditis, PFO, myxoma, MVP) |
| 4 | Symptoms & Signs | Three-column: MCA territory, ICA/ACA territory, Posterior/Vertebrobasilar — with "sudden maximal onset" highlighted |
| 5 | Relevant Findings | Neuroimaging (CT/MRI DWI), Cardiac investigations (ECG, Holter, TTE/TEE, bubble echo), Lab & other |
| 6 | CHA₂DS₂-VASc Score | Full scoring table + treatment thresholds for AF anticoagulation |
| 7 | Acute Treatment | IV tPA, Mechanical Thrombectomy, General supportive care (3 columns) |
| 8 | Secondary Prevention | DOACs (dabigatran, apixaban, rivaroxaban, edoxaban) vs VKA, reversal agents, special situations |
| 9 | Summary | 8-box grid recap of all key points |