Murmur sounds cvs

| Type | Timing | Shape | Key Causes |
|---|---|---|---|
| Early systolic | Starts at S1, ends well before S2 | Decrescendo | Acute MR (papillary rupture, chordal rupture), muscular VSD, TR with normal PA pressure |
| Mid-systolic (ejection) | After S1, ends before S2 | Crescendo-decrescendo (diamond) | Aortic stenosis, pulmonic stenosis, HCM, aortic sclerosis, high-output states |
| Holosystolic (pansystolic) | Spans entire systole, S1 to S2 | Plateau (constant) | Chronic MR, TR, VSD |
| Late systolic | Starts mid-to-late systole | Often crescendo | Mitral valve prolapse (after click), papillary muscle dysfunction |
| Type | Timing | Shape | Key Causes |
|---|---|---|---|
| Early diastolic (decrescendo) | Begins immediately after S2 | Decrescendo (blowing, high-pitched) | Aortic regurgitation, pulmonary regurgitation |
| Mid-diastolic | After S2 with brief gap | Rumbling, low-pitched (use bell) | Mitral stenosis, tricuspid stenosis, Austin Flint murmur |
| Presystolic | Just before S1 | Crescendo | Mitral stenosis (sinus rhythm only), tricuspid stenosis |
| Cause | Description |
|---|---|
| Patent Ductus Arteriosus (PDA) | Classic "machinery murmur" - peaks around S2, continuous throughout |
| Arteriovenous fistula | Continuous |
| Venous hum | Heard at neck/clavicle, disappears with neck vein compression |
| Cervical bruit | Over carotid stenosis |
| Grade | Description |
|---|---|
| I/VI | Very soft; heard only with great effort |
| II/VI | Soft but easily heard |
| III/VI | Loud; no thrill |
| IV/VI | Loud; accompanied by a palpable thrill |
| V/VI | Heard with the edge of stethoscope on chest |
| VI/VI | Heard with stethoscope off the chest |
| Valve | Abnormality | Murmur Timing |
|---|---|---|
| Aortic / Pulmonary | Stenosis | Systolic |
| Aortic / Pulmonary | Regurgitation | Diastolic |
| Mitral / Tricuspid | Stenosis | Diastolic |
| Mitral / Tricuspid | Regurgitation | Systolic |

| Murmur | Best heard | Radiation |
|---|---|---|
| Aortic stenosis | 2nd RICS (aortic area) | Carotids, neck |
| Pulmonic stenosis | 2nd LICS | Left shoulder/neck |
| Mitral regurgitation | Apex | Left axilla |
| Tricuspid regurgitation | Lower left sternal border | None / right side |
| VSD | 3rd-4th LICS | Left sternal border |
| HCM | Lower left sternal border / apex | Both carotids (but decreases with Valsalva release) |
| Murmur | Quality |
|---|---|
| Aortic regurgitation | Blowing, high-pitched decrescendo diastolic |
| Mitral stenosis | Rumbling, low-pitched mid-diastolic (use bell) |
| Aortic stenosis | Harsh, rough crescendo-decrescendo |
| PDA | Machinery continuous murmur |
| Mitral prolapse | Click followed by late systolic murmur |
| Innocent (flow) murmur | Soft, vibratory, midsystolic; common in children |
Create a quick reference PDF of murmur timing, grading, and bedside maneuvers
mkdir -p /home/daytona/workspace/murmur-pdf
~/murmur-pdf/create_murmur_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm, cm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether
)
from reportlab.lib.colors import HexColor
OUTPUT = "/home/daytona/workspace/murmur-pdf/Heart_Murmurs_Quick_Reference.pdf"
# ── Colour palette (medical deep teal / crimson accent) ──────────────────────
C_HEADER = HexColor("#1A3A4A") # dark teal – page header bar
C_SEC = HexColor("#1E6E8A") # section heading blue
C_ACCENT = HexColor("#C0392B") # crimson accent
C_SYS = HexColor("#D4EFFA") # light blue – systolic rows
C_DIA = HexColor("#FAD7D4") # light pink – diastolic rows
C_CON = HexColor("#D4FAD7") # light green – continuous rows
C_TBLHDR = HexColor("#1A3A4A") # table header bg
C_ALT = HexColor("#F4F8FB") # alternating row
C_GRADE_HDR = HexColor("#2C3E50")
C_MANV_HDR = HexColor("#17455A")
WHITE = colors.white
BLACK = colors.black
PAGE_W, PAGE_H = A4
MARGIN = 1.5 * cm
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
leftMargin=MARGIN, rightMargin=MARGIN,
topMargin=1.8*cm, bottomMargin=1.8*cm,
title="Heart Murmurs Quick Reference",
author="Orris Medical"
)
styles = getSampleStyleSheet()
def S(name, **kw):
return ParagraphStyle(name, parent=styles["Normal"], **kw)
# Custom styles
TITLE_STYLE = S("MyTitle", fontSize=22, textColor=WHITE,
fontName="Helvetica-Bold", alignment=TA_CENTER, leading=28)
SUBTITLE_STYLE = S("MySub", fontSize=11, textColor=HexColor("#B0D4E8"),
fontName="Helvetica", alignment=TA_CENTER, leading=15)
SEC_STYLE = S("MySec", fontSize=13, textColor=WHITE,
fontName="Helvetica-Bold", alignment=TA_LEFT, leading=17,
spaceBefore=6, spaceAfter=4)
BODY = S("MyBody", fontSize=9, leading=13, textColor=BLACK)
SMALL = S("MySmall", fontSize=8, leading=11, textColor=HexColor("#333333"))
BOLD_CELL = S("BoldCell", fontSize=8.5, fontName="Helvetica-Bold",
leading=11, textColor=BLACK)
ITALIC_CELL = S("ItalicCell", fontSize=8, fontName="Helvetica-Oblique",
leading=11, textColor=HexColor("#444444"))
NOTE_STYLE = S("MyNote", fontSize=8, textColor=HexColor("#555555"),
fontName="Helvetica-Oblique", leading=11)
FOOTER_STYLE = S("Footer", fontSize=7.5, textColor=HexColor("#888888"),
alignment=TA_CENTER)
# ── Helper: section banner ────────────────────────────────────────────────────
def section_banner(title, bg=C_SEC):
tbl = Table([[Paragraph(title, SEC_STYLE)]], colWidths=[PAGE_W - 2*MARGIN])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("ROUNDEDCORNERS", [4]),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
return tbl
# ── Helper: generic styled table ─────────────────────────────────────────────
def make_table(headers, rows, col_widths, row_colors=None):
"""row_colors: list same length as rows, each a hex string or None"""
header_row = [Paragraph(f"<b>{h}</b>", S("TH", fontSize=9,
textColor=WHITE, fontName="Helvetica-Bold", leading=12))
for h in headers]
data = [header_row]
for r in rows:
data.append([Paragraph(str(cell), SMALL) for cell in r])
tbl = Table(data, colWidths=col_widths, repeatRows=1)
ts = [
("BACKGROUND", (0, 0), (-1, 0), C_TBLHDR),
("TEXTCOLOR", (0, 0), (-1, 0), WHITE),
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
("GRID", (0, 0), (-1,-1), 0.4, HexColor("#CCCCCC")),
("ROWBACKGROUNDS",(0, 1), (-1,-1), [WHITE, C_ALT]),
("TOPPADDING", (0, 0), (-1,-1), 4),
("BOTTOMPADDING",(0, 0), (-1,-1), 4),
("LEFTPADDING", (0, 0), (-1,-1), 6),
("RIGHTPADDING", (0, 0), (-1,-1), 6),
("VALIGN", (0, 0), (-1,-1), "TOP"),
]
if row_colors:
for i, rc in enumerate(row_colors, start=1):
if rc:
ts.append(("BACKGROUND", (0, i), (-1, i), rc))
tbl.setStyle(TableStyle(ts))
return tbl
# ════════════════════════════════════════════════════════════════════════════
# BUILD CONTENT
# ════════════════════════════════════════════════════════════════════════════
story = []
# ── TITLE BLOCK ──────────────────────────────────────────────────────────────
title_tbl = Table(
[[Paragraph("HEART MURMURS", TITLE_STYLE)],
[Paragraph("Quick Reference Card · CVS Auscultation", SUBTITLE_STYLE)]],
colWidths=[PAGE_W - 2*MARGIN]
)
title_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_HEADER),
("TOPPADDING", (0,0), (-1,-1), 12),
("BOTTOMPADDING", (0,0), (-1,-1), 10),
("LEFTPADDING", (0,0), (-1,-1), 12),
("ROUNDEDCORNERS",[6]),
]))
story.append(title_tbl)
story.append(Spacer(1, 10))
# ── SECTION 1 – MURMUR TIMING ────────────────────────────────────────────────
story.append(section_banner("1. MURMUR TIMING"))
story.append(Spacer(1, 5))
story.append(Paragraph(
"The <b>first and most important</b> step in identifying any murmur is establishing "
"its timing within the cardiac cycle relative to S1 and S2.",
BODY))
story.append(Spacer(1, 6))
# 1a Systolic
story.append(Paragraph("<b>A. Systolic Murmurs</b> (S1 → S2)", BODY))
story.append(Spacer(1, 3))
sys_headers = ["Sub-type", "Onset / End", "Shape", "Key Causes"]
sys_rows = [
["Early Systolic",
"Begins at S1; ends well before S2",
"Decrescendo",
"Acute MR (papillary / chordal rupture); muscular VSD; TR with normal PA pressure"],
["Mid-Systolic\n(Ejection)",
"Starts after S1 (after IVCT); ends before S2",
"Crescendo-decrescendo (diamond)",
"Aortic stenosis; pulmonic stenosis; HCM; aortic sclerosis; high-output states (anaemia, pregnancy, thyrotoxicosis)"],
["Holosystolic\n(Pansystolic)",
"S1 to S2 – spans all of systole",
"Plateau (constant)",
"Chronic MR; tricuspid regurgitation; VSD (restrictive)"],
["Late Systolic",
"Mid-to-late systole; ends at S2",
"Crescendo (often preceded by click)",
"Mitral valve prolapse; papillary muscle dysfunction"],
]
sys_colors = [C_SYS, C_SYS, C_SYS, C_SYS]
story.append(make_table(sys_headers, sys_rows,
[3.2*cm, 4.2*cm, 3.5*cm, 6.5*cm], row_colors=sys_colors))
story.append(Spacer(1, 6))
# 1b Diastolic
story.append(Paragraph("<b>B. Diastolic Murmurs</b> (S2 → S1) – Almost always pathological", BODY))
story.append(Spacer(1, 3))
dia_headers = ["Sub-type", "Onset / End", "Quality", "Key Causes"]
dia_rows = [
["Early Diastolic",
"Immediately after S2; decrescendo",
"Blowing, high-pitched\n(use diaphragm)",
"Aortic regurgitation; pulmonary regurgitation (Graham Steell)"],
["Mid-Diastolic",
"After brief gap post-S2",
"Rumbling, low-pitched\n(use BELL)",
"Mitral stenosis (follows OS); tricuspid stenosis; Austin Flint murmur"],
["Presystolic",
"Just before S1; ends at S1",
"Crescendo rumble",
"Mitral stenosis (sinus rhythm only); tricuspid stenosis"],
]
dia_colors = [C_DIA, C_DIA, C_DIA]
story.append(make_table(dia_headers, dia_rows,
[3.2*cm, 4.2*cm, 3.5*cm, 6.5*cm], row_colors=dia_colors))
story.append(Spacer(1, 6))
# 1c Continuous
story.append(Paragraph("<b>C. Continuous Murmurs</b> (systole + diastole)", BODY))
story.append(Spacer(1, 3))
con_headers = ["Cause", "Character", "Notes"]
con_rows = [
["Patent Ductus Arteriosus (PDA)",
"Machinery murmur – peaks around S2; heard continuously",
"2nd LICS; louder in systole and around S2"],
["Arteriovenous fistula",
"Continuous bruit",
"At site of fistula"],
["Venous hum",
"Continuous, low humming",
"At neck/clavicle; disappears with neck vein compression – INNOCENT"],
["Cervical bruit (carotid stenosis)",
"Systolic > diastolic",
"Heard at neck; obliterates with stethoscope pressure"],
]
con_colors = [C_CON]*4
story.append(make_table(con_headers, con_rows,
[4.5*cm, 5.5*cm, 7.4*cm], row_colors=con_colors))
story.append(Spacer(1, 8))
# ── SECTION 2 – VALVE TIMING RULE ───────────────────────────────────────────
story.append(section_banner("2. VALVE TIMING RULE (Memory Aid)", C_ACCENT))
story.append(Spacer(1, 5))
vt_headers = ["Valve", "Abnormality", "Murmur Timing", "Mnemonic"]
vt_rows = [
["Aortic / Pulmonary", "Stenosis", "Systolic", "SAS – Systolic Aortic Stenosis"],
["Aortic / Pulmonary", "Regurgitation", "Diastolic", "ARD – Aortic Regurgitation = Diastolic"],
["Mitral / Tricuspid", "Stenosis", "Diastolic", "MSD – Mitral Stenosis = Diastolic"],
["Mitral / Tricuspid", "Regurgitation", "Systolic", "MRS – Mitral Regurgitation = Systolic"],
]
story.append(make_table(vt_headers, vt_rows,
[4.5*cm, 4*cm, 3.5*cm, 5.4*cm]))
story.append(Spacer(1, 6))
story.append(Paragraph(
"<i>Rule: Stenosis of a semilunar valve = systolic (blocked outflow); "
"Regurgitation of an AV valve = systolic (backward during high-pressure systole). "
"Everything flips for the other group.</i>", NOTE_STYLE))
story.append(Spacer(1, 8))
# ── SECTION 3 – GRADING (LEVINE SCALE) ──────────────────────────────────────
story.append(section_banner("3. GRADING OF INTENSITY — Levine Scale (I – VI)"))
story.append(Spacer(1, 5))
grade_headers = ["Grade", "Description", "Thrill?", "Clinical Significance"]
grade_rows = [
["I / VI", "Very soft; heard only with deliberate effort", "No", "Borderline clinical significance; often innocent"],
["II / VI", "Soft but easily audible", "No", "Common; may be innocent or pathological"],
["III / VI", "Moderately loud", "No", "Usually pathological; echocardiography warranted"],
["IV / VI", "Loud", "YES", "Structural heart disease very likely"],
["V / VI", "Very loud; heard with stethoscope edge on chest","YES","Significant structural pathology"],
["VI / VI", "Heard with stethoscope off the chest", "YES", "Severe structural pathology"],
]
rc = [C_ALT, WHITE, C_SYS, HexColor("#FDEBD0"), C_DIA, HexColor("#FADBD8")]
story.append(make_table(grade_headers, grade_rows,
[2*cm, 6.5*cm, 2.2*cm, 6.7*cm], row_colors=rc))
story.append(Spacer(1, 5))
story.append(Paragraph(
"<b>Rule of thumb:</b> Grade <b>I–II</b> midsystolic in asymptomatic young patients = likely innocent. "
"Grade <b>≥ III</b> systolic (especially holosystolic or late systolic), "
"or <b>any diastolic / continuous</b> murmur = echocardiography indicated.", BODY))
story.append(Spacer(1, 8))
# ── SECTION 4 – LOCATION & RADIATION ────────────────────────────────────────
story.append(section_banner("4. LOCATION & RADIATION"))
story.append(Spacer(1, 5))
loc_headers = ["Murmur", "Best Heard At", "Radiates To", "Key Feature"]
loc_rows = [
["Aortic Stenosis", "2nd RICS (aortic area)", "Carotids, neck", "Slow-rising pulse; ejection click (mild AS)"],
["Pulmonic Stenosis", "2nd LICS", "Left shoulder / neck", "Wide split S2; RV heave"],
["Mitral Regurgitation", "Apex (mitral area)", "Left axilla", "S3 often present; anterior jet = LSB radiation"],
["Tricuspid Regurgitation","Lower LSB (4th LICS)", "Right side; no radiation", "Increases with inspiration (Carvallo's sign)"],
["VSD", "3rd–4th LICS", "Entire precordium", "Thrill at LSB; louder = smaller defect"],
["Mitral Stenosis", "Apex (left lateral position)", "Minimal", "Rumbling; opening snap; loud S1"],
["Aortic Regurgitation", "3rd LICS (Erb's point)", "Apex", "Austin Flint murmur; Corrigan's pulse"],
["PDA", "2nd LICS infraclavicular", "Left shoulder", "Continuous 'machinery' murmur"],
["HCM", "Lower LSB / apex", "Carotids (variable)", "Increases with Valsalva / standing; decreases with squatting"],
]
story.append(make_table(loc_headers, loc_rows,
[3.8*cm, 4*cm, 3.8*cm, 5.8*cm]))
story.append(Spacer(1, 8))
# ── PAGE BREAK before bedside maneuvers ──────────────────────────────────────
from reportlab.platypus import PageBreak
story.append(PageBreak())
# ── SECTION 5 – BEDSIDE MANEUVERS ────────────────────────────────────────────
story.append(section_banner("5. BEDSIDE MANEUVERS & THEIR EFFECTS", C_MANV_HDR))
story.append(Spacer(1, 5))
story.append(Paragraph(
"Maneuvers alter <b>preload</b>, <b>afterload</b>, or <b>contractility</b>, "
"changing murmur intensity or timing in predictable ways. "
"Key principle: most murmurs <i>increase</i> with greater volume/flow, "
"except <b>HCM</b> and <b>MVP</b> which behave paradoxically.",
BODY))
story.append(Spacer(1, 6))
man_headers = ["Maneuver", "Preload", "Afterload", "HCM", "MVP (click timing)", "AS / MR / VSD"]
man_rows = [
["Valsalva (strain phase)", "Decreases", "Decreases",
"LOUDER (obstruction worse)", "Click moves EARLIER (louder murmur, longer)",
"Softer"],
["Valsalva release\n(post-strain)",
"Increases", "Increases",
"Softer", "Click moves LATER (shorter murmur)",
"Louder (transient)"],
["Standing (from squat)",
"Decreases", "Decreases",
"LOUDER", "Click earlier; murmur louder",
"Softer"],
["Squatting (from stand)",
"Increases", "Increases",
"Softer", "Click later; murmur softer/shorter",
"LOUDER"],
["Passive leg raise",
"Increases", "–",
"Softer", "Click later; murmur softer",
"Louder"],
["Isometric handgrip\n(sustained)",
"–", "Increases (SVR up)",
"Softer", "Click later; murmur softer",
"MR, VSD, AR louder; AS softer"],
["Amyl nitrite\n(vasodilator)",
"Decreases (pooling)", "Decreases",
"LOUDER", "Click earlier; murmur louder",
"AS louder; AR softer; MR softer"],
["Inspiration",
"Increases (right-sided)", "–",
"Variable", "Variable",
"Right-sided murmurs LOUDER (Carvallo's); left-sided unchanged"],
["Expiration",
"–", "–",
"Variable", "Variable",
"Left-sided murmurs slightly louder; aortic click louder"],
]
story.append(make_table(man_headers, man_rows,
[3.2*cm, 2*cm, 2*cm, 3.2*cm, 4*cm, 3*cm]))
story.append(Spacer(1, 8))
# ── SECTION 6 – MANEUVER QUICK MEMORY ───────────────────────────────────────
story.append(section_banner("6. QUICK MEMORY: MANEUVER EFFECTS", C_ACCENT))
story.append(Spacer(1, 5))
mem_data = [
[Paragraph("<b>Decreases preload</b>\n(Standing, Valsalva strain, Amyl nitrite)", SMALL),
Paragraph(
"HCM: <b>LOUDER</b> (LV outflow tract narrows)\n"
"MVP: click moves EARLIER, murmur longer\n"
"Most others: SOFTER (less flow)", SMALL)],
[Paragraph("<b>Increases preload</b>\n(Squatting, Passive leg raise, Post-Valsalva release)", SMALL),
Paragraph(
"HCM: <b>SOFTER</b> (better LV filling, less obstruction)\n"
"MVP: click moves LATER, murmur shorter\n"
"Most others: LOUDER", SMALL)],
[Paragraph("<b>Increases afterload</b>\n(Isometric handgrip, Squatting)", SMALL),
Paragraph(
"MR, VSD, AR: LOUDER (more pressure gradient)\n"
"AS: SOFTER (relative)\n"
"HCM: SOFTER (LV does not need to obstruct as hard)", SMALL)],
[Paragraph("<b>Inspiration</b>", SMALL),
Paragraph(
"Right-sided murmurs LOUDER (TR, PS, TS)\n"
"Carvallo's sign: TR murmur increases with inspiration\n"
"S3/S4 from right side: louder on inspiration", SMALL)],
]
mem_tbl = Table(mem_data, colWidths=[6*cm, 11.4*cm])
mem_tbl.setStyle(TableStyle([
("BACKGROUND", (0, 0), (0, -1), HexColor("#EAF4FB")),
("BACKGROUND", (1, 0), (1, -1), WHITE),
("ROWBACKGROUNDS",(0, 0), (-1,-1), [HexColor("#EAF4FB"), HexColor("#FDF6F0"),
HexColor("#F0FBF0"), HexColor("#FBF0F0")]),
("GRID", (0, 0), (-1,-1), 0.4, HexColor("#CCCCCC")),
("VALIGN", (0, 0), (-1,-1), "TOP"),
("TOPPADDING", (0, 0), (-1,-1), 5),
("BOTTOMPADDING", (0, 0), (-1,-1), 5),
("LEFTPADDING", (0, 0), (-1,-1), 7),
("RIGHTPADDING", (0, 0), (-1,-1), 7),
]))
story.append(mem_tbl)
story.append(Spacer(1, 8))
# ── SECTION 7 – INNOCENT vs PATHOLOGICAL ─────────────────────────────────────
story.append(section_banner("7. INNOCENT vs PATHOLOGICAL MURMURS"))
story.append(Spacer(1, 5))
ip_headers = ["Feature", "Innocent Murmur", "Pathological Murmur"]
ip_rows = [
["Timing", "Mid-systolic only", "Holosystolic, late systolic, diastolic, or continuous"],
["Grade", "I–II / VI", "Often III / VI or louder"],
["Thrill", "Absent", "May be present (grade IV+)"],
["Quality", "Soft, vibratory (Still's murmur)", "Harsh, blowing, or rumbling"],
["Radiation", "Minimal / none", "Often radiates (axilla, neck, etc.)"],
["S2", "Normal split", "May be abnormal (fixed split, absent, etc.)"],
["Associated Sx","None – asymptomatic", "Dyspnoea, syncope, chest pain, cyanosis"],
["Response", "Decreases with standing / Valsalva", "Variable; persists or worsens"],
["Echocardiography","Not required if typical features","Indicated (any diastolic/continuous; grade ≥ III systolic)"],
]
story.append(make_table(ip_headers, ip_rows,
[4*cm, 5.5*cm, 7.9*cm]))
story.append(Spacer(1, 8))
# ── SECTION 8 – SPECIAL MURMUR CHARACTERS ────────────────────────────────────
story.append(section_banner("8. CHARACTERISTIC MURMUR DESCRIPTIONS"))
story.append(Spacer(1, 5))
char_headers = ["Murmur", "Classic Description", "Key Additional Sign"]
char_rows = [
["Aortic Stenosis", "Harsh, rough crescendo-decrescendo ejection murmur; may sound musical at apex (Gallavardin)", "Slow-rising carotid pulse; systolic thrill at 2nd RICS"],
["Aortic Regurgitation", "Soft, blowing, high-pitched decrescendo diastolic (Erb's point); sometimes audible unaided", "Corrigan's (water-hammer) pulse; Austin Flint mid-diastolic rumble"],
["Mitral Stenosis", "Low-pitched, rumbling mid-diastolic; loud S1; opening snap (OS) after S2", "OS-S2 interval inversely proportional to severity; presystolic accentuation in SR"],
["Mitral Regurgitation", "Holosystolic plateau murmur; best at apex; radiates to axilla", "S3 gallop; displaced hyperdynamic apex"],
["Mitral Valve Prolapse", "Mid-systolic click followed by late systolic murmur (crescendo to S2)", "Click moves earlier and murmur lengthens with standing / Valsalva"],
["PDA", "'Machinery' continuous murmur; peaks around S2; heard under left clavicle", "Bounding peripheral pulses; wide pulse pressure"],
["VSD (restrictive)", "Loud (grade IV–V) holosystolic murmur at LSB; thrill usually present", "Louder murmur paradoxically = smaller, more restrictive defect"],
["HCM", "Harsh mid-systolic ejection at LSB/apex; does NOT radiate well to neck", "Dynamic obstruction; increases with Valsalva / standing"],
["TR", "Holosystolic at lower LSB; softer than MR", "Carvallo's sign (louder with inspiration); prominent v wave in JVP"],
["Graham Steell", "Early diastolic decrescendo at pulmonary area", "Pulmonary regurgitation due to pulmonary hypertension"],
["Austin Flint", "Mid-diastolic rumble at apex (mimics MS)", "Seen in severe AR; no opening snap; S1 not loud"],
]
story.append(make_table(char_headers, char_rows,
[4*cm, 6.8*cm, 6.6*cm]))
story.append(Spacer(1, 6))
# ── FOOTER NOTE ──────────────────────────────────────────────────────────────
story.append(HRFlowable(width="100%", thickness=0.5, color=HexColor("#AAAAAA")))
story.append(Spacer(1, 4))
story.append(Paragraph(
"Sources: Harrison's Principles of Internal Medicine 22nd Ed. (2025) · "
"Fuster & Hurst's The Heart 15th Ed. · Ganong's Review of Medical Physiology 26th Ed. "
"| Orris Medical Quick Reference · For clinical use — always correlate with full patient assessment.",
FOOTER_STYLE))
# ── BUILD ─────────────────────────────────────────────────────────────────────
doc.build(story)
print("PDF created:", OUTPUT)
cd /home/daytona/workspace/murmur-pdf && python create_murmur_pdf.py 2>&1
ls -lh /home/daytona/workspace/murmur-pdf/Heart_Murmurs_Quick_Reference.pdf
Heart Murmurs Quick Reference
PDF Document · PDF