Let's say it have 0 lnowledge about heart murmurs. I wanna find out murmurs clinically and wanna answer question about murmurs in my mbbs exam. Let's think ur self as my professor and teach me like a 10 year old kid. Don't use complex language ,use simple language and group by group teach me. Make a complete word document
mkdir -p /tmp/workspace/heart-murmurs && ls /tmp/workspace/heart-murmurs/
~/heart-murmurs/create_murmur_doc.py
from docx import Document
from docx.shared import Pt, Inches, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.oxml.ns import qn
from docx.oxml import OxmlElement
doc = Document()
# ββ Page margins ββββββββββββββββββββββββββββββββββββββββββββββ
for section in doc.sections:
section.top_margin = Inches(1.0)
section.bottom_margin = Inches(1.0)
section.left_margin = Inches(1.2)
section.right_margin = Inches(1.2)
# ββ Default Normal style βββββββββββββββββββββββββββββββββββββββ
normal = doc.styles["Normal"]
normal.font.name = "Calibri"
normal.font.size = Pt(11)
# ββ Helper: set heading colour βββββββββββββββββββββββββββββββββ
def set_heading_color(para, r, g, b):
for run in para.runs:
run.font.color.rgb = RGBColor(r, g, b)
def add_heading(text, level, r=0, g=70, b=127):
p = doc.add_heading(text, level=level)
set_heading_color(p, r, g, b)
return p
def add_body(text):
p = doc.add_paragraph(text)
p.style = doc.styles["Normal"]
return p
def add_bullet(text, bold_part=None):
p = doc.add_paragraph(style="List Bullet")
p.paragraph_format.left_indent = Inches(0.3)
if bold_part and text.startswith(bold_part):
run1 = p.add_run(bold_part)
run1.bold = True
run1.font.size = Pt(11)
rest = text[len(bold_part):]
run2 = p.add_run(rest)
run2.font.size = Pt(11)
else:
run = p.add_run(text)
run.font.size = Pt(11)
return p
def add_note(text):
"""Adds a highlighted tip/note paragraph."""
p = doc.add_paragraph()
p.paragraph_format.left_indent = Inches(0.3)
p.paragraph_format.right_indent = Inches(0.3)
run = p.add_run("π " + text)
run.font.size = Pt(10.5)
run.font.color.rgb = RGBColor(0x1A, 0x53, 0x76)
run.bold = True
return p
def add_table_row(table, col1, col2, col3="", col4="", header=False):
row = table.add_row()
cells = row.cells
data = [col1, col2, col3, col4]
for i, cell in enumerate(cells):
cell.text = data[i] if i < len(data) else ""
for run in cell.paragraphs[0].runs:
run.font.size = Pt(10)
if header:
run.bold = True
run.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
if header:
shading = OxmlElement("w:shd")
shading.set(qn("w:val"), "clear")
shading.set(qn("w:color"), "auto")
shading.set(qn("w:fill"), "00467F")
cell._tc.get_or_add_tcPr().append(shading)
return row
def add_shaded_table_row(table, col1, col2, col3="", col4="", shade="D9E8F5"):
row = table.add_row()
cells = row.cells
data = [col1, col2, col3, col4]
for i, cell in enumerate(cells):
cell.text = data[i] if i < len(data) else ""
for run in cell.paragraphs[0].runs:
run.font.size = Pt(10)
if shade:
shading = OxmlElement("w:shd")
shading.set(qn("w:val"), "clear")
shading.set(qn("w:color"), "auto")
shading.set(qn("w:fill"), shade)
cell._tc.get_or_add_tcPr().append(shading)
return row
def page_break():
doc.add_page_break()
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# COVER / TITLE
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
title_para = doc.add_paragraph()
title_para.alignment = WD_ALIGN_PARAGRAPH.CENTER
run = title_para.add_run("β€οΈ Heart Murmurs")
run.bold = True
run.font.size = Pt(28)
run.font.color.rgb = RGBColor(0xC0, 0x00, 0x00)
subtitle = doc.add_paragraph()
subtitle.alignment = WD_ALIGN_PARAGRAPH.CENTER
r2 = subtitle.add_run("A Complete, Simple-Language Guide for MBBS Students")
r2.font.size = Pt(14)
r2.font.color.rgb = RGBColor(0x00, 0x46, 0x7F)
r2.bold = True
subtitle2 = doc.add_paragraph()
subtitle2.alignment = WD_ALIGN_PARAGRAPH.CENTER
r3 = subtitle2.add_run("Taught like a 10-year-old would understand π")
r3.font.size = Pt(12)
r3.italic = True
r3.font.color.rgb = RGBColor(0x44, 0x44, 0x44)
doc.add_paragraph()
doc.add_paragraph()
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SECTION 1 β WHAT IS A HEART MURMUR?
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
add_heading("SECTION 1 β What Is a Heart Murmur? π€", level=1)
add_body(
"Imagine water flowing through a garden hose. When water flows smoothly, it is silent. "
"But when the hose is pinched, bent, or water shoots through a tiny hole β you hear a "
"WHOOSH or SWISH sound. That is exactly what happens in the heart!"
)
doc.add_paragraph()
add_body(
"A HEART MURMUR is an extra sound you hear between the normal 'LUB-DUB' of the heart. "
"Instead of silence between the heartbeats, there is a swishing, whooshing, or rumbling noise. "
"This happens because blood is flowing in a turbulent (rough, noisy) way."
)
doc.add_paragraph()
add_heading("Why does turbulence happen?", level=2)
add_bullet("Blood flows too fast through a normal valve (like in fever, anaemia, pregnancy)")
add_bullet("Blood is pushed through a valve that is too narrow (stenosis)")
add_bullet("Blood leaks backwards through a valve that does not close properly (regurgitation/incompetence)")
add_bullet("Blood flows through an abnormal hole between heart chambers (e.g., VSD, ASD)")
doc.add_paragraph()
add_note(
"EXAM TIP: A murmur is NOT always a disease! Some murmurs are innocent/physiological "
"(like in children and pregnant women) and some are pathological (due to heart disease)."
)
page_break()
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SECTION 2 β THE NORMAL HEARTBEAT FIRST
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
add_heading("SECTION 2 β Understand the Normal Heart Sounds First π₯", level=1)
add_body(
"Before we can find abnormal sounds, you MUST know the normal ones. "
"Think of the heart as a drum that beats in a rhythm."
)
doc.add_paragraph()
add_heading("The Two Normal Sounds", level=2)
add_bullet("S1 (First Heart Sound) β The 'LUB' sound. Happens when the mitral and tricuspid valves CLOSE. This marks the START of systole (when the heart squeezes and pumps blood out).")
add_bullet("S2 (Second Heart Sound) β The 'DUB' sound. Happens when the aortic and pulmonary valves CLOSE. This marks the END of systole and START of diastole (when the heart relaxes and fills).")
doc.add_paragraph()
add_body("So a normal heartbeat sounds like: LUB .... DUB .... LUB .... DUB")
doc.add_paragraph()
add_heading("What is Systole and Diastole?", level=2)
add_bullet("SYSTOLE = Heart squeezing = the short gap between S1 and S2 = LUB...DUB")
add_bullet("DIASTOLE = Heart relaxing = the longer gap between S2 and next S1 = DUB......LUB")
doc.add_paragraph()
add_note(
"Memory trick: SYSTOLE is SHORT (the short pause between LUB and DUB). "
"DIASTOLE is LONG (the longer pause between DUB and next LUB). "
"Easy way to feel this: put your finger on your carotid (neck) pulse. "
"The pulse beat happens just after S1 (LUB)."
)
page_break()
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SECTION 3 β HOW TO DESCRIBE A MURMUR (MBBS EXAM FORMULA)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
add_heading("SECTION 3 β How to Describe Any Murmur (Exam Formula) π", level=1)
add_body(
"In your MBBS exam, when you find a murmur, describe it using these 8 features. "
"Think of it as filling in a form for every murmur you hear."
)
doc.add_paragraph()
# Table of features
t = doc.add_table(rows=1, cols=3)
t.style = "Table Grid"
t.columns[0].width = Inches(1.2)
t.columns[1].width = Inches(2.2)
t.columns[2].width = Inches(2.8)
add_table_row(t, "Feature", "What to Ask?", "Possible Answers / Examples", header=True)
add_shaded_table_row(t, "1. TIMING", "When in the cycle?", "Systolic / Diastolic / Continuous", shade="D9E8F5")
add_shaded_table_row(t, "2. DURATION", "How long?", "Early / Mid / Late / Holo (Pan) = throughout", shade="EAF4FF")
add_shaded_table_row(t, "3. INTENSITY", "How loud? (Grade 1β6)", "See grading table below", shade="D9E8F5")
add_shaded_table_row(t, "4. QUALITY", "What does it sound like?", "Harsh / Blowing / Rumbling / Musical", shade="EAF4FF")
add_shaded_table_row(t, "5. PITCH", "High or Low?", "High-pitched / Low-pitched", shade="D9E8F5")
add_shaded_table_row(t, "6. SHAPE", "How does loudness change?", "Crescendo / Decrescendo / Crescendo-Decrescendo / Plateau (uniform)", shade="EAF4FF")
add_shaded_table_row(t, "7. LOCATION", "Where is it loudest?", "Apex / Aortic area / Pulmonary area / Left sternal border", shade="D9E8F5")
add_shaded_table_row(t, "8. RADIATION", "Where does it spread to?", "Axilla / Neck / Back / Jaw", shade="EAF4FF")
doc.add_paragraph()
add_note("EXAM ANSWER FORMULA: 'There is a [Grade X/6] [systolic/diastolic] [harsh/blowing/rumbling] murmur, best heard at [location], radiating to [area].'")
page_break()
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SECTION 4 β GRADING (LEVINE SCALE)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
add_heading("SECTION 4 β How Loud Is the Murmur? The Grading Scale π", level=1)
add_body(
"We grade murmur loudness from 1 to 6. This is called the Levine Scale. "
"Think of it like a music volume knob β 1 is barely audible, 6 is so loud you don't even need a stethoscope!"
)
doc.add_paragraph()
tg = doc.add_table(rows=1, cols=3)
tg.style = "Table Grid"
tg.columns[0].width = Inches(0.8)
tg.columns[1].width = Inches(2.5)
tg.columns[2].width = Inches(2.9)
add_table_row(tg, "Grade", "What You Hear", "Simple Memory Aid", header=True)
add_shaded_table_row(tg, "1/6", "Very faint β only with careful listening in a quiet room", "π Almost nothing", shade="D9E8F5")
add_shaded_table_row(tg, "2/6", "Faint but easily heard once you focus", "π Quiet whisper", shade="EAF4FF")
add_shaded_table_row(tg, "3/6", "Moderately loud β clear, NO thrill felt by hand", "π Normal speech volume β NO buzz on chest", shade="D9E8F5")
add_shaded_table_row(tg, "4/6", "Loud + you feel a THRILL (buzzing vibration under your fingers)", "π Loud + THRILL present", shade="EAF4FF")
add_shaded_table_row(tg, "5/6", "Very loud β heard with only the EDGE of stethoscope touching skin", "π’ Stethoscope barely touching", shade="D9E8F5")
add_shaded_table_row(tg, "6/6", "Loudest β heard WITHOUT stethoscope touching chest at all!", "π£ Stethoscope OFF the chest!", shade="EAF4FF")
doc.add_paragraph()
add_note(
"EXAM TIP: A thrill (buzzing vibration you feel with your palm) appears at Grade 4 and above. "
"Grades 3 and above usually mean important structural heart disease. "
"Grades 1β2 are often innocent/functional murmurs."
)
page_break()
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SECTION 5 β AUSCULTATION AREAS
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
add_heading("SECTION 5 β Where to Listen? The 4 Magic Spots on the Chest π©Ί", level=1)
add_body(
"You place your stethoscope in 4 key areas on the chest. Each area is closest to a valve, "
"so you hear that valve's sounds the best there. Remember: valve sounds do NOT come from where the valve physically is β "
"sound travels in the direction of blood flow!"
)
doc.add_paragraph()
ta = doc.add_table(rows=1, cols=4)
ta.style = "Table Grid"
ta.columns[0].width = Inches(1.5)
ta.columns[1].width = Inches(1.4)
ta.columns[2].width = Inches(1.3)
ta.columns[3].width = Inches(1.6)
add_table_row(ta, "Area Name", "Location on Chest", "Valve Heard", "Radiation", header=True)
add_shaded_table_row(ta, "Aortic Area", "2nd ICS*, Right sternal border", "Aortic Valve", "To neck/jaw", shade="D9E8F5")
add_shaded_table_row(ta, "Pulmonary Area", "2nd ICS, Left sternal border", "Pulmonary Valve", "To left shoulder", shade="EAF4FF")
add_shaded_table_row(ta, "Tricuspid Area", "4th/5th ICS, Left sternal border (LLSB)", "Tricuspid Valve", "To epigastrium", shade="D9E8F5")
add_shaded_table_row(ta, "Mitral Area (Apex)", "5th ICS, Midclavicular line", "Mitral Valve", "To left axilla", shade="EAF4FF")
doc.add_paragraph()
add_body("* ICS = Intercostal Space = the gap between two ribs")
doc.add_paragraph()
add_note(
"Memory trick for positions: 'All Patients Take Medicine' β "
"Aortic (2nd R), Pulmonary (2nd L), Tricuspid (4th L), Mitral (5th MCL). "
"Start at the top right and go in a Z-shape."
)
page_break()
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SECTION 6 β TYPES OF MURMURS (THE BIG THREE GROUPS)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
add_heading("SECTION 6 β Types of Murmurs (3 Big Groups) ποΈ", level=1)
add_body(
"ALL murmurs fall into ONE of 3 timing groups. If you can figure out the timing, "
"you have already solved HALF of the question!"
)
doc.add_paragraph()
add_heading("GROUP A β Systolic Murmurs (during LUB...DUB)", level=2)
add_body(
"These occur during systole β when the heart is squeezing. You hear them BETWEEN S1 and S2. "
"Pattern: S1 [whoosh] S2 (noise is in the short pause)"
)
add_bullet("Can be INNOCENT (harmless) or PATHOLOGICAL (due to disease)")
add_bullet("Further divided into: Ejection Systolic Murmur (ESM) and Pansystolic/Holosystolic Murmur")
doc.add_paragraph()
add_heading("GROUP B β Diastolic Murmurs (during DUB......LUB)", level=2)
add_body(
"These occur during diastole β when the heart is filling. You hear them BETWEEN S2 and the next S1. "
"Pattern: S2 [rumble or blow] S1 (noise is in the long pause)"
)
add_bullet("ALWAYS pathological β diastolic murmurs ALWAYS mean heart disease!")
add_bullet("Further divided into: Early Diastolic, Mid-Diastolic, and Presystolic (Late Diastolic)")
doc.add_paragraph()
add_heading("GROUP C β Continuous Murmurs (throughout the cycle)", level=2)
add_body(
"These run through BOTH systole AND diastole without stopping β they continue through S2. "
"Caused by blood flowing continuously between two structures (usually arteries or from great vessels)."
)
add_bullet("Best example: Patent Ductus Arteriosus (PDA) β 'Machinery murmur'")
doc.add_paragraph()
add_note(
"GOLDEN EXAM RULE: If a student says 'diastolic murmur = harmless,' "
"that is WRONG. Diastolic murmurs are ALWAYS significant. Only some systolic murmurs are innocent."
)
page_break()
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SECTION 7 β SYSTOLIC MURMURS IN DETAIL
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
add_heading("SECTION 7 β Systolic Murmurs in Detail π¬", level=1)
# 7A β Ejection Systolic
add_heading("7A. Ejection Systolic Murmur (ESM) β Diamond Shaped", level=2)
add_body(
"Shape: Crescendo-decrescendo (gets louder then softer = like a diamond β). "
"Timing: Starts AFTER S1, ends BEFORE S2. There is a small gap after S1 before it begins."
)
doc.add_paragraph()
te = doc.add_table(rows=1, cols=4)
te.style = "Table Grid"
te.columns[0].width = Inches(1.8)
te.columns[1].width = Inches(1.2)
te.columns[2].width = Inches(1.6)
te.columns[3].width = Inches(1.6)
add_table_row(te, "Disease", "Grade", "Best Heard", "Radiates To", header=True)
add_shaded_table_row(te, "Aortic Stenosis (AS)", "3β4/6", "2nd ICS Right (Aortic area)", "Neck, jaw (Gallavardin effect β apex)", shade="D9E8F5")
add_shaded_table_row(te, "Pulmonary Stenosis (PS)", "2β4/6", "2nd ICS Left (Pulmonary area)", "Left shoulder / back", shade="EAF4FF")
add_shaded_table_row(te, "HOCM (Hypertrophic Cardiomyopathy)", "3β4/6", "Lower left sternal border", "Does NOT radiate to neck", shade="D9E8F5")
add_shaded_table_row(te, "Innocent/Flow Murmur", "1β2/6", "Pulmonary area or apex", "Does not radiate", shade="EAF4FF")
doc.add_paragraph()
# 7B β Pansystolic
add_heading("7B. Pansystolic (Holosystolic) Murmur β Flat / Plateau Shaped", level=2)
add_body(
"Shape: Plateau (stays equally loud the WHOLE of systole = flat line). "
"Timing: Starts WITH S1, ends WITH S2. It occupies ALL of systole β you cannot hear S1 or S2 clearly. "
"Caused by: a constant pressure difference between two chambers throughout systole."
)
doc.add_paragraph()
tp = doc.add_table(rows=1, cols=4)
tp.style = "Table Grid"
tp.columns[0].width = Inches(1.8)
tp.columns[1].width = Inches(1.0)
tp.columns[2].width = Inches(1.8)
tp.columns[3].width = Inches(1.6)
add_table_row(tp, "Disease", "Quality", "Best Heard", "Radiates To", header=True)
add_shaded_table_row(tp, "Mitral Regurgitation (MR)", "Blowing", "Apex (Mitral area)", "Left axilla (armpit)", shade="D9E8F5")
add_shaded_table_row(tp, "Tricuspid Regurgitation (TR)", "Blowing", "LLSB (Tricuspid area)", "Epigastrium; β with inspiration", shade="EAF4FF")
add_shaded_table_row(tp, "VSD (Ventricular Septal Defect)", "Harsh", "LLSB (3rdβ4th ICS left)", "All over precordium (thrill common)", shade="D9E8F5")
doc.add_paragraph()
add_note(
"Memory trick β MAPS: Mitral regurgitation β Axilla; Pulmonary Stenosis β Shoulder; "
"Aortic Stenosis β Neck. These are the classic radiations to remember for exams."
)
page_break()
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SECTION 8 β DIASTOLIC MURMURS IN DETAIL
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
add_heading("SECTION 8 β Diastolic Murmurs in Detail (Always Pathological!) π¨", level=1)
add_body("Repeat after me: ALL diastolic murmurs = disease. There are NO innocent diastolic murmurs!")
doc.add_paragraph()
# 8A β Early Diastolic
add_heading("8A. Early Diastolic Murmur (EDM) β Decrescendo / Blowing", level=2)
add_body(
"Timing: Starts immediately AFTER S2, then gets softer as diastole goes on. "
"Pattern: S1 ... S2 [blow gets softer...] S1. "
"Caused by: Valve that does not close completely β blood leaks BACK into the ventricle."
)
add_bullet("Aortic Regurgitation (AR): High-pitched, blowing, decrescendo. Best at 3rd ICS Left sternal border. Heard best in EXPIRATION, leaning forward. Pitcured as: 'bbbbbbb...' fading.")
add_bullet("Pulmonary Regurgitation (PR): Same character. Best at 2nd ICS Left. Increases with inspiration (right-sided). Graham-Steell murmur = PR due to pulmonary hypertension.")
doc.add_paragraph()
# 8B β Mid Diastolic
add_heading("8B. Mid-Diastolic Murmur (MDM) β Rumbling / Low-pitched", level=2)
add_body(
"Timing: Starts after a delay from S2 (there is a gap, then the rumble begins). "
"Caused by: Narrowed AV valve obstructing blood flow into the ventricle during filling. "
"Quality: Low-pitched RUMBLE β use the BELL of the stethoscope with light pressure."
)
add_bullet("Mitral Stenosis (MS): Classic MDM. Heard at APEX. Low-pitched rumble. Preceded by an Opening Snap (OS). The shorter the gap between S2 and OS, the MORE severe the stenosis.")
add_bullet("Tricuspid Stenosis (TS): Same but at LLSB. Increases with inspiration (right-sided).")
add_bullet("Austin-Flint Murmur: Mid-diastolic rumble at apex in SEVERE AR β caused by regurgitant jet hitting the mitral leaflet. Looks like MS but there is no Opening Snap.")
doc.add_paragraph()
# 8C β Presystolic
add_heading("8C. Presystolic Murmur β Crescendo (Late Diastolic)", level=2)
add_body(
"Timing: Occurs just BEFORE S1 β the very end of diastole. "
"It is actually the LATE part of a mid-diastolic murmur that gets louder just before systole, "
"because the atrium contracts and pushes more blood through the still-narrow mitral valve."
)
add_bullet("Mitral Stenosis in sinus rhythm: Classic presystolic accentuation. The rumble gets louder just before S1.")
add_bullet("IMPORTANT: This presystolic accentuation is LOST in atrial fibrillation (AF) β because atria stop contracting properly in AF!")
doc.add_paragraph()
add_note(
"EXAM TRAP: Mitral stenosis has an Opening Snap (OS) + Mid-diastolic rumble + Presystolic accentuation. "
"If the patient has AF, the presystolic component disappears. Examiners LOVE to ask this!"
)
page_break()
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SECTION 9 β CONTINUOUS MURMUR
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
add_heading("SECTION 9 β Continuous Murmurs π΅", level=1)
add_body(
"A continuous murmur runs through both systole AND diastole without stopping. "
"It does NOT stop at S2 β it just keeps going. This is different from 'to-and-fro' murmurs "
"(which are two separate murmurs, one systolic and one diastolic, with a break between them)."
)
doc.add_paragraph()
add_heading("Patent Ductus Arteriosus (PDA) β The 'Machinery Murmur'", level=2)
add_body(
"This is the most famous continuous murmur. PDA is a channel between the aorta and pulmonary artery "
"that fails to close after birth. Blood continuously shunts from the aorta (high pressure) to the pulmonary "
"artery (low pressure) β so it flows ALL the time, in BOTH systole and diastole."
)
add_bullet("Character: Loud, rough, 'machinery-like' β like the noise of a machine running")
add_bullet("Best heard: 2nd ICS, left infraclavicular area (under left collarbone)")
add_bullet("Peaks at S2: Gets loudest around S2 then gradually fades in diastole")
add_bullet("Age: Usually found in neonates or young children (and infants born prematurely)")
doc.add_paragraph()
add_note(
"Do NOT confuse Continuous murmur with To-and-Fro murmur. "
"To-and-fro = two separate murmurs (e.g., AS + AR together). "
"Continuous = ONE murmur going through S2 without a break. "
"The key test: Can you hear S2 clearly? In continuous murmur = S2 is 'buried' inside the murmur."
)
page_break()
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SECTION 10 β THE BIG MURMUR TABLE (EXAM MASTER SHEET)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
add_heading("SECTION 10 β Master Exam Table: All Murmurs at a Glance π", level=1)
add_body("This is your MBBS exam cheat sheet. Learn every row β examiners love these details!")
doc.add_paragraph()
tm = doc.add_table(rows=1, cols=6)
tm.style = "Table Grid"
tm.columns[0].width = Inches(1.2)
tm.columns[1].width = Inches(0.9)
tm.columns[2].width = Inches(0.9)
tm.columns[3].width = Inches(0.8)
tm.columns[4].width = Inches(1.0)
tm.columns[5].width = Inches(1.5)
add_table_row(tm, "Disease", "Timing", "Quality", "Best Heard", "Radiates To", "Special Feature", header=True)
# Systolic
add_shaded_table_row(tm, "Aortic Stenosis (AS)", "ESM (Systolic)", "Harsh, rough", "2nd R ICS", "Neck / carotids", "Gallavardin: murmur sounds musical at apex", shade="FFE8CC")
add_shaded_table_row(tm, "Pulmonary Stenosis (PS)", "ESM (Systolic)", "Harsh", "2nd L ICS", "Left shoulder", "Wide split S2; ejection click before murmur", shade="FFF5E8")
add_shaded_table_row(tm, "HOCM", "ESM (Systolic)", "Harsh", "LLSB", "Does NOT go to neck", "β with Valsalva / standing; β with squatting", shade="FFE8CC")
add_shaded_table_row(tm, "Mitral Regurgitation (MR)", "Pansystolic", "Blowing", "Apex", "Left axilla", "S1 soft; S3 may be present", shade="FFF5E8")
add_shaded_table_row(tm, "Tricuspid Regurgitation (TR)", "Pansystolic", "Blowing", "LLSB", "Epigastrium", "Increases on INSPIRATION (Carvallo's sign)", shade="FFE8CC")
add_shaded_table_row(tm, "VSD", "Pansystolic", "Harsh", "LLSB (3β4 ICS)", "All over precordium", "Loud thrill; paradox: smaller hole = louder murmur", shade="FFF5E8")
# Diastolic
add_shaded_table_row(tm, "Aortic Regurgitation (AR)", "Early Diastolic", "High-pitched blowing", "3rd L ICS (LSB)", "To apex", "β leaning forward + expiration; Austin-Flint murmur at apex", shade="D9EAF5")
add_shaded_table_row(tm, "Pulmonary Regurgitation (PR)", "Early Diastolic", "Blowing", "2nd L ICS", "Left sternal border", "Graham-Steell murmur if pulm. HTN present", shade="E8F4FF")
add_shaded_table_row(tm, "Mitral Stenosis (MS)", "Mid Diastolic", "Low rumble", "Apex (bell)", "None", "OS after S2; presystolic accentuation (lost in AF)", shade="D9EAF5")
add_shaded_table_row(tm, "Tricuspid Stenosis (TS)", "Mid Diastolic", "Low rumble", "LLSB (bell)", "None", "Increases on inspiration; OS present", shade="E8F4FF")
# Continuous
add_shaded_table_row(tm, "PDA", "Continuous", "Machinery", "2nd L ICS infraclavicular", "None", "Peaks at S2; S2 buried in murmur; common in preterm", shade="E8FFE8")
doc.add_paragraph()
page_break()
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SECTION 11 β BEDSIDE MANEUVERS
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
add_heading("SECTION 11 β Clever Tricks to Change the Murmur (Bedside Maneuvers) π―", level=1)
add_body(
"When you do certain physical maneuvers, the murmur changes. By knowing HOW it changes, "
"you can figure out WHICH murmur it is. This is called Dynamic Auscultation."
)
doc.add_paragraph()
add_heading("The Two Most Important Maneuvers", level=2)
add_body("Think of it this way: When you decrease blood going to the heart β heart has less to pump β ventricle becomes smaller. When you increase blood to heart β it becomes fuller.")
doc.add_paragraph()
add_heading("1. Valsalva Maneuver (bear down / strain as if constipated)", level=3)
add_body("This DECREASES venous return β heart gets less blood β left ventricle becomes SMALLER.")
add_bullet("HOCM murmur: Gets LOUDER (obstruction gets worse when ventricle is small)")
add_bullet("MVP click: Moves earlier; murmur gets longer")
add_bullet("Most other murmurs: Get SOFTER")
doc.add_paragraph()
add_heading("2. Squatting (sudden squat from standing)", level=3)
add_body("This INCREASES venous return β heart gets more blood β ventricle becomes LARGER.")
add_bullet("HOCM murmur: Gets SOFTER (ventricle now bigger, obstruction less)")
add_bullet("Most other murmurs: Get LOUDER")
doc.add_paragraph()
add_heading("3. Inspiration (breathing in deeply)", level=3)
add_body("Inspiration increases venous return to the RIGHT side of the heart.")
add_bullet("RIGHT-sided murmurs (TR, TS, PR, PS): Get LOUDER on inspiration")
add_bullet("LEFT-sided murmurs (MR, MS, AS, AR): Stay same or get slightly softer")
add_bullet("This is called Carvallo's Sign for tricuspid regurgitation")
doc.add_paragraph()
add_heading("4. Handgrip (squeeze a fist firmly for 20 seconds)", level=3)
add_body("Increases systemic vascular resistance (SVR) β increases afterload.")
add_bullet("MR, VSD murmurs: Get LOUDER (more resistance β more backflow/shunt)")
add_bullet("AS, HOCM murmurs: Get SOFTER or unchanged")
add_bullet("AR diastolic murmur: Gets LOUDER")
doc.add_paragraph()
# Mini summary table of maneuvers
tmv = doc.add_table(rows=1, cols=4)
tmv.style = "Table Grid"
tmv.columns[0].width = Inches(1.5)
tmv.columns[1].width = Inches(1.2)
tmv.columns[2].width = Inches(1.2)
tmv.columns[3].width = Inches(2.3)
add_table_row(tmv, "Maneuver", "HOCM", "AS / MR / VSD", "Key Rule", header=True)
add_shaded_table_row(tmv, "Valsalva", "β LOUDER", "β Softer", "Valsalva makes HOCM louder (less blood)", shade="D9E8F5")
add_shaded_table_row(tmv, "Squatting", "β Softer", "β Louder", "Squat makes HOCM softer (more blood)", shade="EAF4FF")
add_shaded_table_row(tmv, "Inspiration", "No change", "Right-sided β", "Inspiration = right side louder", shade="D9E8F5")
add_shaded_table_row(tmv, "Handgrip", "β Softer", "MR/VSD β; AS β", "Grip = more afterload = more regurg", shade="EAF4FF")
doc.add_paragraph()
add_note(
"HOCM EXAM KEY: HOCM is the OPPOSITE of everyone else. "
"Everything that decreases heart filling β HOCM louder. "
"Everything that increases heart filling β HOCM softer. "
"Remember: HOCM hates a full heart!"
)
page_break()
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SECTION 12 β INNOCENT vs PATHOLOGICAL MURMURS
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
add_heading("SECTION 12 β Innocent vs. Pathological Murmurs πΆ vs β οΈ", level=1)
add_body(
"Not every murmur means heart disease! Innocent murmurs (also called physiological or functional) "
"are harmless sounds caused by faster-than-normal blood flow through a perfectly normal heart."
)
doc.add_paragraph()
add_heading("When Does Innocent Murmur Occur?", level=2)
add_bullet("Children and teenagers (very common β up to 80% of children may have it at some point!)")
add_bullet("Pregnancy (blood volume increases by 40β50% β faster flow β murmur)")
add_bullet("Anaemia (less thick blood flows faster β more turbulence)")
add_bullet("Fever or hyperthyroidism (increased cardiac output β faster flow)")
doc.add_paragraph()
add_heading("Features of an Innocent Murmur (5 S's)", level=2)
add_bullet("Short β Only in early or mid systole (NEVER diastolic)")
add_bullet("Soft β Grade 1 or 2/6 maximum")
add_bullet("Systolic β Always systolic (never diastolic or continuous)")
add_bullet("Simple β No other abnormal heart sounds")
add_bullet("Still's murmur β A vibratory, musical mid-systolic murmur in children (most common innocent murmur)")
doc.add_paragraph()
add_heading("Red Flags β When a Murmur is Likely Pathological", level=2)
add_bullet("ANY diastolic murmur")
add_bullet("Grade 3/6 or louder systolic murmur")
add_bullet("Systolic murmur with a THRILL (grade 4+)")
add_bullet("Murmur accompanied by symptoms: chest pain, fainting, breathlessness, palpitations")
add_bullet("Holosystolic or late systolic murmur")
add_bullet("Abnormal S1 or S2")
add_bullet("Any murmur in a patient with fever + recent sore throat (think Rheumatic fever!)")
doc.add_paragraph()
add_note(
"QUICK EXAM RULE: Soft, early-to-mid systolic, grade 1-2, no radiation, no symptoms, "
"child or pregnant = likely innocent. Diastolic + any grade = always send for echo!"
)
page_break()
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SECTION 13 β APPROACH IN CLINICAL/VIVA EXAM
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
add_heading("SECTION 13 β How to Approach a Murmur in Your Clinical Exam π₯", level=1)
add_body("Follow this step-by-step approach in your clinical examination and viva. Say it OUT LOUD to your examiner β they want to see your systematic thinking!")
doc.add_paragraph()
steps = [
("Step 1", "Confirm heartbeat timing", "Put your RIGHT hand on the patient's carotid pulse while listening. The pulse beat = S1 (LUB). Now you know what is systole and what is diastole."),
("Step 2", "Listen in all 4 areas", "Aortic β Pulmonary β Tricuspid (LLSB) β Mitral (Apex). Use DIAPHRAGM for high-pitched sounds. Use BELL for low-pitched sounds (like MS rumble)."),
("Step 3", "Time the murmur", "Is it between S1-S2 (systolic)? Or between S2-S1 (diastolic)? Or continuous?"),
("Step 4", "Describe the murmur", "State: Grade, Quality, Best location, Radiation"),
("Step 5", "Do a maneuver", "Ask patient to breathe in deeply (right-sided?). Ask them to squat (HOCM?). Lean forward + expire (AR?)"),
("Step 6", "Look for associated signs", "Check JVP, peripheral pulses, blood pressure in both arms, signs of heart failure, clubbing, cyanosis, signs of infective endocarditis."),
("Step 7", "Come to a diagnosis", "Use all findings together to name the murmur and likely cause."),
]
for step_title, step_sub, step_text in steps:
p = doc.add_paragraph()
r1 = p.add_run(f"{step_title}: {step_sub} β ")
r1.bold = True
r1.font.size = Pt(11)
r1.font.color.rgb = RGBColor(0x00, 0x46, 0x7F)
r2 = p.add_run(step_text)
r2.font.size = Pt(11)
doc.add_paragraph()
add_note(
"VIVA GOLDEN PHRASE: Start with β 'On auscultation, I hear a grade [X]/6 [systolic/diastolic] "
"[quality] murmur, best heard at [location], radiating to [area], which [increases/decreases] "
"with [maneuver]. This is most consistent with [DIAGNOSIS].'"
)
page_break()
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SECTION 14 β QUICK MEMORY AIDS & MNEMONICS
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
add_heading("SECTION 14 β Memory Aids and Mnemonics π§ ", level=1)
add_heading("Auscultation Areas β 'All Patients Take Medicine'", level=2)
add_bullet("A = Aortic β 2nd right ICS")
add_bullet("P = Pulmonary β 2nd left ICS")
add_bullet("T = Tricuspid β 4th/5th ICS left sternal border")
add_bullet("M = Mitral β 5th ICS midclavicular line (APEX)")
doc.add_paragraph()
add_heading("Valves That Close for S1 and S2 β 'M TAP'", level=2)
add_bullet("S1 = Mitral + Tricuspid close (M T)")
add_bullet("S2 = Aortic + Pulmonary close (A P)")
add_bullet("So: M T closes first (S1), then A P closes (S2) = M-T-A-P = MT AP")
doc.add_paragraph()
add_heading("Diastolic Murmurs β 'PRAMS'", level=2)
add_bullet("P = Pulmonary regurgitation (Graham-Steell)")
add_bullet("R = Rheumatic fever β Mitral Stenosis (most common cause of MS)")
add_bullet("A = Aortic Regurgitation (early diastolic blow)")
add_bullet("M = Mitral Stenosis (mid-diastolic rumble)")
add_bullet("S = Stenosis = any stenosis of AV valves β diastolic")
doc.add_paragraph()
add_heading("HOCM vs Others in Maneuvers β 'HOCM is the REBEL'", level=2)
add_body("When everyone else's murmur gets louder with more blood, HOCM's murmur gets SOFTER. HOCM rebels against every rule β it gets louder when the heart is EMPTY (Valsalva, standing, dehydration).")
doc.add_paragraph()
add_heading("Murmur Radiation Summary", level=2)
add_bullet("AS β Neck (like the aorta heading UP to the head)")
add_bullet("MR β Left Axilla (mitral regurgitant jet goes into left atrium = leftward = armpit)")
add_bullet("VSD β All over precordium")
add_bullet("PS β Left shoulder / back")
add_bullet("TR β Epigastrium, increases on inspiration")
doc.add_paragraph()
page_break()
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SECTION 15 β COMMON EXAM QUESTIONS & ANSWERS
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
add_heading("SECTION 15 β Frequently Asked MBBS Exam Questions π", level=1)
qas = [
("Q1", "What is a thrill?",
"A thrill is a vibration you FEEL with your palm or fingers on the chest wall. It is the tactile equivalent of a loud murmur (Grade 4 and above). It feels like a purring cat or a running engine under your hand."),
("Q2", "What is an Opening Snap (OS)?",
"In Mitral Stenosis, the stiff mitral leaflets snap open in early diastole, producing a high-pitched click β the Opening Snap. It comes just AFTER S2. The shorter the S2-OS interval, the MORE SEVERE the stenosis (because high left atrial pressure opens the valve sooner)."),
("Q3", "What is the Austin-Flint murmur?",
"In severe Aortic Regurgitation, the regurgitant jet of blood hits the anterior mitral leaflet and causes it to vibrate, creating a mid-diastolic rumble that sounds like Mitral Stenosis. The key difference: no Opening Snap in Austin-Flint. It goes AWAY when AR is treated."),
("Q4", "What is Carvallo's Sign?",
"The murmur of Tricuspid Regurgitation increases in intensity on INSPIRATION. This is called Carvallo's Sign. Inspiration β more venous return to right heart β more blood regurgitates through tricuspid β louder murmur."),
("Q5", "What is Graham-Steell murmur?",
"An early diastolic murmur of Pulmonary Regurgitation due to PULMONARY HYPERTENSION (usually from severe Mitral Stenosis). The high pulmonary pressure damages the pulmonary valve over time β it leaks β early diastolic blowing murmur at left 2nd ICS."),
("Q6", "What happens to murmurs in AF (Atrial Fibrillation)?",
"In AF, the atria quiver instead of contracting properly. So: the Presystolic Accentuation of Mitral Stenosis DISAPPEARS (no atrial contraction = no presystolic push of blood through the valve). The RR intervals also vary, making the diastolic filling time different with each beat."),
("Q7", "What is a Gallavardin effect?",
"In Aortic Stenosis, the harsh systolic murmur heard at the aortic area may sound much higher-pitched and 'musical' at the apex. This is the Gallavardin effect β it can be mistaken for Mitral Regurgitation. Remember: the murmur at the apex sounds different from the murmur at the aortic area, but they are the same murmur!"),
("Q8", "Differentiate Continuous murmur from To-and-Fro murmur.",
"Continuous murmur: ONE murmur that starts in systole, goes through S2 (without stopping), and continues into diastole. S2 is buried inside it. Example: PDA. To-and-Fro murmur: TWO separate murmurs β one systolic (e.g., AS) + one diastolic (e.g., AR) β with a brief gap at S2. Example: AS + AR together."),
]
for qnum, question, answer in qas:
p_q = doc.add_paragraph()
r_qnum = p_q.add_run(f"{qnum}: ")
r_qnum.bold = True
r_qnum.font.color.rgb = RGBColor(0xC0, 0x00, 0x00)
r_qnum.font.size = Pt(11)
r_qques = p_q.add_run(question)
r_qques.bold = True
r_qques.font.size = Pt(11)
p_a = doc.add_paragraph()
p_a.paragraph_format.left_indent = Inches(0.3)
r_ans = p_a.add_run("Answer: " + answer)
r_ans.font.size = Pt(11)
r_ans.font.color.rgb = RGBColor(0x1A, 0x1A, 0x1A)
doc.add_paragraph()
page_break()
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SECTION 16 β QUICK REVISION CARDS
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
add_heading("SECTION 16 β Quick Revision (Night Before Exam) π", level=1)
add_body("Read these bullet points the night before your exam:")
doc.add_paragraph()
cards = [
"Murmur = turbulent blood flow = extra whooshing sound between heartbeats",
"S1 (LUB) = mitral + tricuspid close = start of systole | S2 (DUB) = aortic + pulmonary close = end of systole",
"Systolic murmur = between S1 and S2 (short pause). Diastolic = between S2 and S1 (long pause)",
"ALL diastolic murmurs are pathological. Some systolic murmurs are innocent",
"Grading: 1=barely heard, 2=faint, 3=moderate no thrill, 4=loud with THRILL, 5=edge of stethoscope, 6=off chest",
"ESM (ejection systolic) = diamond shaped = AS, PS, HOCM, Innocent flow",
"Pansystolic = flat shape all of systole = MR, TR, VSD",
"Early diastolic blow = AR or PR",
"Mid-diastolic rumble with OS = Mitral Stenosis (bell, apex). Presystolic accentuation lost in AF",
"Continuous machinery = PDA",
"HOCM: louder with Valsalva/standing (small LV), softer with squat (big LV)",
"Inspiration = louder right-sided murmurs (Carvallo's = TR)",
"AS radiates to neck | MR to axilla | VSD all over precordium",
"OS to S2 gap: SHORT = SEVERE MS",
"Austin-Flint = AR mimicking MS (no OS, no thrill, no calcified valve on echo)",
"Graham-Steell = PR from pulmonary hypertension (often due to severe MS)",
"Gallavardin = AS murmur sounds musical/higher at apex = mimics MR",
"Carvallo's Sign = TR louder on inspiration",
"Still's murmur = vibratory musical innocent murmur in children (most common innocent)",
"New murmur post-MI = echo urgently (papillary rupture / VSR)",
]
for card in cards:
add_bullet(card)
doc.add_paragraph()
doc.add_paragraph()
end_para = doc.add_paragraph()
end_para.alignment = WD_ALIGN_PARAGRAPH.CENTER
end_run = end_para.add_run("β
You are now ready to ace your Heart Murmurs exam!\n Good luck, Doctor! π©Ί")
end_run.bold = True
end_run.font.size = Pt(14)
end_run.font.color.rgb = RGBColor(0x00, 0x70, 0x00)
# ββ Save ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
output_path = "/tmp/workspace/heart-murmurs/Heart_Murmurs_Complete_Guide.docx"
doc.save(output_path)
print(f"Document saved: {output_path}")
cd /tmp/workspace/heart-murmurs && python3 create_murmur_doc.py 2>&1
~/heart-murmurs/create_murmur_doc.py
Successfully replaced 1 instance(s) of the string in '/tmp/workspace/heart-murmurs/create_murmur_doc.py'
~/heart-murmurs/create_murmur_doc.py
Successfully replaced 1 instance(s) of the string in '/tmp/workspace/heart-murmurs/create_murmur_doc.py'
cd /tmp/workspace/heart-murmurs && python3 create_murmur_doc.py 2>&1
ls -lh /tmp/workspace/heart-murmurs/Heart_Murmurs_Complete_Guide.docx && python3 -c " from docx import Document doc = Document('/tmp/workspace/heart-murmurs/Heart_Murmurs_Complete_Guide.docx') headings = [p.text for p in doc.paragraphs if p.style.name.startswith('Heading')] print(f'Total paragraphs: {len(doc.paragraphs)}') print(f'Total tables: {len(doc.tables)}') print('HEADINGS:') for h in headings: print(' -', h) "
Heart Murmurs Complete Guide
Word Document Β· DOCX
| Section | What You Learn |
|---|---|
| Section 1 | What is a murmur? (garden hose analogy - dead simple) |
| Section 2 | Normal heart sounds - LUB-DUB explained |
| Section 3 | The 8-feature formula to describe ANY murmur in exams |
| Section 4 | Levine Grading Scale (1-6) with easy memory aids |
| Section 5 | 4 auscultation spots + "All Patients Take Medicine" trick |
| Section 6 | The 3 big groups: Systolic / Diastolic / Continuous |
| Section 7 | Systolic murmurs: ESM (diamond shape) vs Pansystolic (flat) |
| Section 8 | Diastolic murmurs: Early / Mid / Presystolic - all pathological! |
| Section 9 | Continuous murmur - PDA (the machinery murmur) |
| Section 10 | Master Table: All 11 murmurs - timing, quality, location, radiation, special features |
| Section 11 | Bedside maneuvers - Valsalva, Squat, Inspiration, Handgrip |
| Section 12 | Innocent vs pathological murmurs - 5 S's, red flags |
| Section 13 | Step-by-step clinical exam approach + viva golden phrase |
| Section 14 | Mnemonics - MAPS, MT AP, PRAMS, HOCM is the REBEL |
| Section 15 | 8 classic MBBS exam questions with full answers |
| Section 16 | Night-before-exam revision - 20 bullet points |
Create a summary PDF of just the master murmur table for quick pocket reference
~/heart-murmurs/create_pocket_pdf.py
from reportlab.lib.pagesizes import A4, landscape
from reportlab.lib import colors
from reportlab.lib.units import cm, mm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.platypus import (
SimpleDocTemplate, Table, TableStyle, Paragraph,
Spacer, HRFlowable
)
from reportlab.lib.colors import HexColor
# ββ Output path βββββββββββββββββββββββββββββββββββββββββββββββ
OUTPUT = "/tmp/workspace/heart-murmurs/Murmur_Pocket_Reference.pdf"
# ββ Colour palette ββββββββββββββββββββββββββββββββββββββββββββ
NAVY = HexColor("#003366")
SKY_HEADER = HexColor("#00467F")
WHITE = colors.white
LIGHT_GREY = HexColor("#F2F2F2")
# Row group colours
SYS_DARK = HexColor("#FFF0DC") # warm orange-tinted for systolic ESM
SYS_LIGHT = HexColor("#FFFAEF")
PAN_DARK = HexColor("#FFE4F0") # pink for pansystolic
PAN_LIGHT = HexColor("#FFF0F7")
DIAS_DARK = HexColor("#DDF0FF") # blue for diastolic
DIAS_LIGHT = HexColor("#EEF7FF")
CONT_ROW = HexColor("#DFFFDF") # green for continuous
# Section label colours (left side mini-header)
SYS_LABEL = HexColor("#C75000")
DIAS_LABEL = HexColor("#0055AA")
CONT_LABEL = HexColor("#007700")
# ββ Page setup (landscape A4) βββββββββββββββββββββββββββββββββ
doc = SimpleDocTemplate(
OUTPUT,
pagesize=landscape(A4),
leftMargin=1.2*cm,
rightMargin=1.2*cm,
topMargin=1.4*cm,
bottomMargin=1.4*cm,
title="Heart Murmur Pocket Reference",
author="Orris Medical Education",
)
styles = getSampleStyleSheet()
def ps(text, size=8, bold=False, color=colors.black, align=TA_LEFT, leading=10):
style = ParagraphStyle(
"custom",
fontName="Helvetica-Bold" if bold else "Helvetica",
fontSize=size,
textColor=color,
alignment=align,
leading=leading,
spaceAfter=0,
spaceBefore=0,
)
return Paragraph(text, style)
# ββ Build content βββββββββββββββββββββββββββββββββββββββββββββ
story = []
# Title
story.append(Paragraph(
"<font color='#003366'><b>β€ Heart Murmur β Master Pocket Reference</b></font>",
ParagraphStyle("title", fontName="Helvetica-Bold", fontSize=17,
textColor=NAVY, alignment=TA_CENTER, spaceAfter=2)
))
story.append(Paragraph(
"For MBBS Clinical Exam & Quick Bedside Revision | Source: Harrison's Principles of Internal Medicine 22E",
ParagraphStyle("sub", fontName="Helvetica", fontSize=8,
textColor=HexColor("#555555"), alignment=TA_CENTER, spaceAfter=6)
))
story.append(HRFlowable(width="100%", thickness=1.5, color=NAVY, spaceAfter=6))
# ββ MAIN TABLE ββββββββββββββββββββββββββββββββββββββββββββββββ
# Column widths (landscape A4 usable ~27 cm)
COL_W = [3.5*cm, 2.8*cm, 2.4*cm, 2.5*cm, 2.4*cm, 2.8*cm, 2.4*cm, 7.6*cm]
# Header row
header = [
ps("DISEASE", 8, bold=True, color=WHITE, align=TA_CENTER),
ps("TIMING", 8, bold=True, color=WHITE, align=TA_CENTER),
ps("SHAPE", 8, bold=True, color=WHITE, align=TA_CENTER),
ps("QUALITY", 8, bold=True, color=WHITE, align=TA_CENTER),
ps("BEST HEARD", 8, bold=True, color=WHITE, align=TA_CENTER),
ps("RADIATION", 8, bold=True, color=WHITE, align=TA_CENTER),
ps("PITCH", 8, bold=True, color=WHITE, align=TA_CENTER),
ps("SPECIAL FEATURES / EXAM PEARLS", 8, bold=True, color=WHITE, align=TA_CENTER),
]
# Data rows [disease, timing, shape, quality, best_heard, radiation, pitch, pearls]
rows_data = [
# ββ SYSTOLIC ESM ββββββββββββββββββββββββββββββββββββββββββ
[
ps("Aortic Stenosis\n(AS)", 8, bold=True),
ps("Ejection Systolic\n(ESM)", 8),
ps("Crescendo-\nDecrescendo\nβ Diamond", 8),
ps("Harsh, rough,\ncoarse", 8),
ps("2nd ICS\nRight sternal\nborder", 8),
ps("Neck / carotids\n(both sides)", 8),
ps("Medium-\nhigh", 8),
ps("β’ Gallavardin effect: murmur sounds musical / higher-pitched at apex β can mimic MR\n"
"β’ Ejection click may precede murmur in bicuspid AoV\n"
"β’ Slow rising (pulsus parvus et tardus) carotid pulse\n"
"β’ Softer with handgrip; louder with amyl nitrite", 7.5),
],
[
ps("Pulmonary Stenosis\n(PS)", 8, bold=True),
ps("Ejection Systolic\n(ESM)", 8),
ps("Crescendo-\nDecrescendo\nβ Diamond", 8),
ps("Harsh", 8),
ps("2nd ICS\nLeft sternal\nborder", 8),
ps("Left shoulder\n/ left back", 8),
ps("Medium", 8),
ps("β’ Pulmonary ejection click precedes murmur (only click that decreases on inspiration)\n"
"β’ Wide split S2; P2 soft or absent\n"
"β’ Right ventricular heave\n"
"β’ Louder on inspiration (right-sided)", 7.5),
],
[
ps("HOCM\n(Hypertrophic\nCardiomyopathy)", 8, bold=True),
ps("Ejection Systolic\n(ESM)", 8),
ps("Crescendo-\nDecrescendo\nβ Diamond", 8),
ps("Harsh", 8),
ps("Lower left\nsternal border\n(LLSB)", 8),
ps("Does NOT\nradiate to neck\n(key difference\nfrom AS)", 8),
ps("Medium", 8),
ps("β’ REBEL rule: LOUDER with Valsalva & standing (less blood in LV)\n"
"β’ SOFTER with squatting & handgrip (more blood fills LV)\n"
"β’ Bisferiens pulse; double apical impulse\n"
"β’ Family history of sudden cardiac death", 7.5),
],
[
ps("Innocent / Flow\nMurmur", 8, bold=True),
ps("Ejection Systolic\n(ESM) β early\nor mid only", 8),
ps("Crescendo-\nDecrescendo\nβ Diamond", 8),
ps("Soft, musical\n(vibratory =\nStill's)", 8),
ps("Pulmonary area\nor apex", 8),
ps("No radiation", 8),
ps("Low-med", 8),
ps("β’ Grade 1β2/6 MAXIMUM β no thrill\n"
"β’ Common in children, pregnancy, anaemia, fever\n"
"β’ Still's murmur: vibratory, musical β most common innocent murmur in children\n"
"β’ No other abnormal heart sounds; normal S1 & S2", 7.5),
],
# ββ PANSYSTOLIC βββββββββββββββββββββββββββββββββββββββββββ
[
ps("Mitral Regurgitation\n(MR)", 8, bold=True),
ps("Pansystolic\n(Holosystolic)", 8),
ps("Plateau\n(flat) β¬β¬\nthroughout", 8),
ps("Blowing", 8),
ps("Apex\n(mitral area)\n5th ICS MCL", 8),
ps("LEFT AXILLA\n(armpit)", 8),
ps("High", 8),
ps("β’ S1 is SOFT (valve does not close well)\n"
"β’ S3 may be present in severe MR\n"
"β’ Louder with handgrip (more afterload = more regurgitation)\n"
"β’ Acute MR (papillary rupture post-MI): early decrescendo, not pansystolic", 7.5),
],
[
ps("Tricuspid Regurgitation\n(TR)", 8, bold=True),
ps("Pansystolic\n(Holosystolic)", 8),
ps("Plateau\n(flat) β¬β¬", 8),
ps("Blowing", 8),
ps("LLSB\n(4thβ5th ICS\nleft border)", 8),
ps("Epigastrium\n/ right side", 8),
ps("High", 8),
ps("β’ CARVALLO'S SIGN: murmur increases on INSPIRATION (right-sided)\n"
"β’ Pulsatile liver, elevated JVP with prominent v-wave\n"
"β’ Causes: rheumatic, pulmonary HTN, infective endocarditis (IV drug use)", 7.5),
],
[
ps("VSD\n(Ventricular Septal\nDefect)", 8, bold=True),
ps("Pansystolic\n(Holosystolic)", 8),
ps("Plateau\n(flat) β¬β¬", 8),
ps("Harsh", 8),
ps("LLSB\n3rdβ4th ICS\nleft border", 8),
ps("All over\nprecordium", 8),
ps("High", 8),
ps("β’ Thrill common at LLSB (grade 4+)\n"
"β’ PARADOX: Smaller hole = LOUDER murmur (higher velocity jet)\n"
"β’ Large VSD may be silent (Eisenmenger: equalised pressures)\n"
"β’ Louder with handgrip; softer with amyl nitrite", 7.5),
],
# ββ DIASTOLIC βββββββββββββββββββββββββββββββββββββββββββββ
[
ps("Aortic Regurgitation\n(AR)", 8, bold=True),
ps("Early Diastolic\n(starts just after S2)", 8),
ps("Decrescendo\n(fades away β)", 8),
ps("Blowing", 8),
ps("3rd ICS\nLeft sternal\nborder (Erb's)", 8),
ps("To apex\n(Austin-Flint\nat apex)", 8),
ps("HIGH\npitched", 8),
ps("β’ Best heard: leaning FORWARD + end EXPIRATION\n"
"β’ Austin-Flint murmur: mid-diastolic rumble at apex in severe AR (mimics MS but NO opening snap)\n"
"β’ Corrigan's (water-hammer) pulse; wide pulse pressure; De Musset's sign\n"
"β’ Graham-Steell β AR: Graham-Steell is PR from pulm HTN", 7.5),
],
[
ps("Pulmonary Regurgitation\n(PR) / Graham-Steell", 8, bold=True),
ps("Early Diastolic", 8),
ps("Decrescendo\n(fades away β)", 8),
ps("Blowing", 8),
ps("2nd ICS\nLeft sternal\nborder", 8),
ps("Along left\nsternal\nborder", 8),
ps("HIGH\npitched", 8),
ps("β’ Graham-Steell murmur = PR from PULMONARY HYPERTENSION (usually due to severe MS)\n"
"β’ Increases on INSPIRATION (right-sided)\n"
"β’ Look for signs of pulmonary HTN: loud P2, right ventricular heave", 7.5),
],
[
ps("Mitral Stenosis\n(MS)", 8, bold=True),
ps("Mid-Diastolic\n+ Presystolic\naccentuation", 8),
ps("Rumble + pre-\nsystolic crescendo\n(if sinus rhythm)", 8),
ps("Low-pitched\nRumble", 8),
ps("APEX\n(use BELL,\nlight pressure!)", 8),
ps("No radiation", 8),
ps("LOW\npitched\n(use BELL)", 8),
ps("β’ OPENING SNAP (OS) after S2: shorter S2-OS gap = MORE severe MS\n"
"β’ Presystolic accentuation = LOST in AF (no atrial contraction)\n"
"β’ Loud S1 (tapping apex), loud P2 if pulm HTN\n"
"β’ Cause: almost always RHEUMATIC fever\n"
"β’ Position: left lateral decubitus to hear the rumble best", 7.5),
],
[
ps("Tricuspid Stenosis\n(TS)", 8, bold=True),
ps("Mid-Diastolic", 8),
ps("Rumble", 8),
ps("Low-pitched\nRumble", 8),
ps("LLSB\n(use BELL)", 8),
ps("No radiation", 8),
ps("LOW\npitched", 8),
ps("β’ Opening snap present (like MS)\n"
"β’ Increases on INSPIRATION (right-sided β distinguishes from MS)\n"
"β’ Rare; usually coexists with MS in rheumatic disease", 7.5),
],
# ββ CONTINUOUS ββββββββββββββββββββββββββββββββββββββββββββ
[
ps("PDA\n(Patent Ductus\nArteriosus)", 8, bold=True),
ps("CONTINUOUS\n(systole AND\ndiastole)", 8),
ps("Peaks at S2\nthen fades\nin diastole", 8),
ps("Machinery\n(rough,\nrolling)", 8),
ps("2nd ICS Left\ninfraclavicular\n(below left\ncollarbone)", 8),
ps("No specific\nradiation", 8),
ps("Medium", 8),
ps("β’ S2 is BURIED inside the murmur (key feature)\n"
"β’ NOT a to-and-fro: no break between systolic and diastolic components\n"
"β’ Common in PREMATURE neonates; also rubella syndrome\n"
"β’ Bounding pulse; wide pulse pressure\n"
"β’ Treatment: indomethacin (closes PDA) or surgical ligation", 7.5),
],
]
# Assemble table data
table_data = [header] + rows_data
# ββ TableStyle ββββββββββββββββββββββββββββββββββββββββββββββββ
# Row index ranges:
# 0 = header
# 1-4 = systolic ESM (rows 1,2,3,4)
# 5-7 = pansystolic (rows 5,6,7)
# 8-11 = diastolic (rows 8,9,10,11)
# 12 = continuous (row 12)
style = TableStyle([
# Global grid
("GRID", (0,0), (-1,-1), 0.4, HexColor("#AAAAAA")),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING",(0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 4),
("RIGHTPADDING", (0,0), (-1,-1), 4),
("ROWBACKGROUNDS", (0,0), (-1,-1), [colors.white]),
# Header
("BACKGROUND", (0,0), (-1,0), SKY_HEADER),
("LINEBELOW", (0,0), (-1,0), 1.5, NAVY),
("ALIGN", (0,0), (-1,0), "CENTER"),
# Systolic ESM rows (1β4) alternating
("BACKGROUND", (0,1), (-1,1), SYS_DARK),
("BACKGROUND", (0,2), (-1,2), SYS_LIGHT),
("BACKGROUND", (0,3), (-1,3), SYS_DARK),
("BACKGROUND", (0,4), (-1,4), SYS_LIGHT),
# Pansystolic rows (5β7) alternating pink
("BACKGROUND", (0,5), (-1,5), PAN_DARK),
("BACKGROUND", (0,6), (-1,6), PAN_LIGHT),
("BACKGROUND", (0,7), (-1,7), PAN_DARK),
# Diastolic rows (8β11) alternating blue
("BACKGROUND", (0,8), (-1,8), DIAS_DARK),
("BACKGROUND", (0,9), (-1,9), DIAS_LIGHT),
("BACKGROUND", (0,10), (-1,10), DIAS_DARK),
("BACKGROUND", (0,11), (-1,11), DIAS_LIGHT),
# Continuous row (12) green
("BACKGROUND", (0,12), (-1,12), CONT_ROW),
# Bold left column (disease names)
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("FONTSIZE", (0,1), (0,-1), 8),
# Section separator lines
("LINEABOVE", (0,1), (-1,1), 1.5, SYS_LABEL), # before ESM
("LINEABOVE", (0,5), (-1,5), 1.5, HexColor("#AA2200")), # before pansystolic
("LINEABOVE", (0,8), (-1,8), 1.5, DIAS_LABEL), # before diastolic
("LINEABOVE", (0,12), (-1,12), 1.5, CONT_LABEL), # before continuous
])
tbl = Table(table_data, colWidths=COL_W, repeatRows=1)
tbl.setStyle(style)
story.append(tbl)
story.append(Spacer(1, 6))
story.append(HRFlowable(width="100%", thickness=0.8, color=HexColor("#AAAAAA"), spaceAfter=4))
# ββ LEGEND ββββββββββββββββββββββββββββββββββββββββββββββββββββ
legend_data = [[
ps("COLOUR KEY:", 7.5, bold=True),
ps("β Orange rows = Ejection Systolic (ESM)", 7.5, color=HexColor("#C75000")),
ps("β Pink rows = Pansystolic", 7.5, color=HexColor("#AA0055")),
ps("β Blue rows = Diastolic", 7.5, color=HexColor("#0055AA")),
ps("β Green row = Continuous", 7.5, color=HexColor("#007700")),
]]
legend_tbl = Table(legend_data, colWidths=[2.5*cm, 5.5*cm, 4.5*cm, 4.5*cm, 4.0*cm])
legend_tbl.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("GRID", (0,0), (-1,-1), 0, colors.white),
("LEFTPADDING", (0,0), (-1,-1), 4),
("RIGHTPADDING", (0,0), (-1,-1), 4),
]))
story.append(legend_tbl)
story.append(Spacer(1, 4))
story.append(HRFlowable(width="100%", thickness=0.8, color=HexColor("#AAAAAA"), spaceAfter=4))
# ββ QUICK MNEMONICS STRIP βββββββββββββββββββββββββββββββββββββ
mnemo_items = [
("Auscultation Areas", "All Patients Take Medicine β Aortic (2R), Pulmonary (2L), Tricuspid (4L), Mitral (Apex)"),
("Grading Thrill", "Thrill = Grade 4+ | Grade 3+ = likely pathological"),
("HOCM Rule", "LOUDER: Valsalva / Standing | SOFTER: Squatting / Handgrip"),
("Inspiration Rule", "Right-sided murmurs louder on inspiration (Carvallo's = TR)"),
("OS-S2 gap", "Shorter gap β MORE severe MS"),
("Diastolic = Always Disease", "No innocent diastolic murmurs β always send for echo!"),
("AR position", "Lean forward + end-expiration to hear AR best"),
("PDA vs To-and-Fro", "PDA: S2 buried in murmur | To-and-fro: gap at S2 (e.g. AS+AR)"),
]
mnemo_data = []
row = []
for i, (title, text) in enumerate(mnemo_items):
cell_content = ps(f"<b>{title}:</b> {text}", 7)
row.append(cell_content)
if len(row) == 4:
mnemo_data.append(row)
row = []
if row:
while len(row) < 4:
row.append(ps(""))
mnemo_data.append(row)
mnemo_tbl = Table(mnemo_data, colWidths=[7.0*cm, 7.0*cm, 7.0*cm, 6.8*cm])
mnemo_tbl.setStyle(TableStyle([
("GRID", (0,0), (-1,-1), 0.3, HexColor("#CCCCCC")),
("BACKGROUND", (0,0), (-1,-1), HexColor("#F7F7FF")),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING",(0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
]))
story.append(mnemo_tbl)
story.append(Spacer(1, 5))
story.append(Paragraph(
"Source: Harrison's Principles of Internal Medicine 22E (2025) | Braunwald's Heart Disease | Goldman-Cecil Medicine | Prepared by Orris Medical Education",
ParagraphStyle("footer", fontName="Helvetica", fontSize=6.5,
textColor=HexColor("#888888"), alignment=TA_CENTER)
))
# ββ Build PDF βββββββββββββββββββββββββββββββββββββββββββββββββ
doc.build(story)
print(f"PDF saved: {OUTPUT}")
cd /tmp/workspace/heart-murmurs && python3 create_pocket_pdf.py 2>&1
ls -lh /tmp/workspace/heart-murmurs/Murmur_Pocket_Reference.pdf && python3 -c " from pypdf import PdfReader r = PdfReader('/tmp/workspace/heart-murmurs/Murmur_Pocket_Reference.pdf') print(f'Pages: {len(r.pages)}') print(f'Page size: {r.pages[0].mediabox}') "
Murmur Pocket Reference
PDF Document Β· PDF
| Column | What it tells you |
|---|---|
| Disease | Name + abbreviation |
| Timing | ESM / Pansystolic / Early Diastolic / Mid-Diastolic / Continuous |
| Shape | Diamond / Plateau / Decrescendo / Rumble |
| Quality | Harsh / Blowing / Rumbling / Machinery |
| Best Heard | Exact location with ICS |
| Radiation | Where it spreads |
| Pitch | High / Low (tells you which part of stethoscope to use) |
| Exam Pearls | 3-4 high-yield points per murmur |