. According to the syllabus of 3 pages I have just uploaded , pointed, colourful notes, minimum words , use arrows schematic diagram to reduce words . Precise comprehensive pointed notes
mkdir -p /tmp/workspace/ear-notes && ls /tmp/workspace/
pip install python-pptx --quiet 2>/dev/null; python3 -c "import pptx; print('pptx ok')"
~/ear-notes/make_notes.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
from pptx.util import Inches, Pt
import pptx.oxml.ns as ns
from lxml import etree
prs = Presentation()
prs.slide_width = Inches(13.33)
prs.slide_height = Inches(7.5)
# Color palette
C_BG = RGBColor(0x0D, 0x1B, 0x2A) # very dark navy
C_TITLE = RGBColor(0xFF, 0xD7, 0x00) # golden yellow
C_HEAD1 = RGBColor(0x00, 0xE5, 0xFF) # cyan
C_HEAD2 = RGBColor(0xFF, 0x6B, 0x6B) # coral red
C_HEAD3 = RGBColor(0x7B, 0xFF, 0x6B) # lime green
C_HEAD4 = RGBColor(0xFF, 0xA5, 0x00) # orange
C_HEAD5 = RGBColor(0xDA, 0x70, 0xD6) # orchid / lavender
C_ARROW = RGBColor(0xFF, 0xD7, 0x00) # yellow arrows
C_WHITE = RGBColor(0xFF, 0xFF, 0xFF)
C_GREY = RGBColor(0xCC, 0xCC, 0xCC)
C_BOX1 = RGBColor(0x1A, 0x3A, 0x5C) # dark blue box
C_BOX2 = RGBColor(0x2D, 0x1B, 0x3D) # dark purple box
C_BOX3 = RGBColor(0x1A, 0x3D, 0x2D) # dark green box
C_BOX4 = RGBColor(0x3D, 0x2A, 0x1A) # dark orange box
def blank_slide(prs):
layout = prs.slide_layouts[6] # blank
slide = prs.slides.add_slide(layout)
# Set background
bg = slide.background
fill = bg.fill
fill.solid()
fill.fore_color.rgb = C_BG
return slide
def add_text(slide, text, x, y, w, h, font_size=14, bold=False, color=C_WHITE,
align=PP_ALIGN.LEFT, bg_color=None, wrap=True):
txBox = slide.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h))
if bg_color:
fill = txBox.fill
fill.solid()
fill.fore_color.rgb = bg_color
tf = txBox.text_frame
tf.word_wrap = wrap
p = tf.paragraphs[0]
p.alignment = align
run = p.add_run()
run.text = text
run.font.size = Pt(font_size)
run.font.bold = bold
run.font.color.rgb = color
return txBox
def add_shape_box(slide, x, y, w, h, bg_color, text, font_size=12, text_color=C_WHITE, bold=False):
"""Rounded rectangle with text"""
from pptx.util import Emu
from pptx.enum.shapes import MSO_SHAPE_TYPE
shape = slide.shapes.add_shape(
1, # MSO_SHAPE.RECTANGLE
Inches(x), Inches(y), Inches(w), Inches(h)
)
shape.fill.solid()
shape.fill.fore_color.rgb = bg_color
shape.line.color.rgb = C_TITLE
shape.line.width = Pt(0.75)
tf = shape.text_frame
tf.word_wrap = True
p = tf.paragraphs[0]
p.alignment = PP_ALIGN.CENTER
run = p.add_run()
run.text = text
run.font.size = Pt(font_size)
run.font.bold = bold
run.font.color.rgb = text_color
return shape
def add_arrow(slide, x1, y1, x2, y2):
"""Add a simple line with arrow"""
connector = slide.shapes.add_connector(1, Inches(x1), Inches(y1), Inches(x2), Inches(y2))
connector.line.color.rgb = C_ARROW
connector.line.width = Pt(1.5)
def title_bar(slide, title):
bar = slide.shapes.add_shape(1, Inches(0), Inches(0), Inches(13.33), Inches(0.65))
bar.fill.solid()
bar.fill.fore_color.rgb = RGBColor(0x10, 0x30, 0x50)
bar.line.fill.background()
tf = bar.text_frame
p = tf.paragraphs[0]
p.alignment = PP_ALIGN.CENTER
run = p.add_run()
run.text = title
run.font.size = Pt(20)
run.font.bold = True
run.font.color.rgb = C_TITLE
# βββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 1: Title / Overview
# βββββββββββββββββββββββββββββββββββββββββββββ
slide = blank_slide(prs)
add_text(slide, "π EAR β SURGERY SYLLABUS NOTES", 0.3, 0.3, 12.7, 0.8,
font_size=28, bold=True, color=C_TITLE, align=PP_ALIGN.CENTER)
add_text(slide, "Hom UG-Sur-II β’ Unit 7", 0.3, 1.0, 12.7, 0.4,
font_size=14, color=C_GREY, align=PP_ALIGN.CENTER)
# Overview mind-map boxes
topics = [
("Anatomy & Physiology\n(7.1β7.2)", 0.4, 1.8, 2.8, 1.0, C_BOX1, C_HEAD1),
("External Ear Diseases\n(7.5β7.6)", 3.5, 1.8, 2.8, 1.0, C_BOX2, C_HEAD2),
("Middle Ear β ASOM\n(7.7β7.8)", 6.6, 1.8, 2.8, 1.0, C_BOX3, C_HEAD3),
("Middle Ear β CSOM\n(7.9β7.10)", 9.7, 1.8, 2.8, 1.0, C_BOX4, C_HEAD4),
("Earache / Otalgia\n(7.12β7.13)", 0.4, 3.2, 2.8, 1.0, C_BOX1, C_HEAD1),
("Otorrhea\n(7.14β7.15)", 3.5, 3.2, 2.8, 1.0, C_BOX2, C_HEAD5),
("Deafness\n(7.16β7.18)", 6.6, 3.2, 2.8, 1.0, C_BOX3, C_HEAD3),
("Tinnitus\n(7.19β7.20)", 9.7, 3.2, 2.8, 1.0, C_BOX4, C_HEAD4),
("Vertigo\n(7.21β7.23)", 0.4, 4.6, 2.8, 1.0, C_BOX1, C_HEAD1),
("Meniere's Disease\n(7.24)", 3.5, 4.6, 2.8, 1.0, C_BOX2, C_HEAD2),
("BPPV & Acoustic Neuroma\n(7.25)", 6.6, 4.6, 2.8, 1.0, C_BOX3, C_HEAD5),
("Facial Palsy / Bell's Palsy\n(7.26)", 9.7, 4.6, 2.8, 1.0, C_BOX4, C_HEAD4),
]
for (txt, x, y, w, h, bg, fc) in topics:
add_shape_box(slide, x, y, w, h, bg, txt, font_size=11, text_color=fc, bold=True)
add_text(slide, "Each topic β Aetiology β Pathology β Clinical Features β Investigations β Management β Homoeopathic Remedies",
0.4, 6.0, 12.5, 0.6, font_size=11, color=C_ARROW, align=PP_ALIGN.CENTER)
# βββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 2: Anatomy & Physiology + Ear Examination
# βββββββββββββββββββββββββββββββββββββββββββββ
slide = blank_slide(prs)
title_bar(slide, "7.1β7.4 | ANATOMY β’ PHYSIOLOGY β’ CASE TAKING β’ EAR EXAMINATION")
# 3 columns
# Col 1: Anatomy
add_text(slide, "π΅ ANATOMY OF EAR", 0.2, 0.75, 4.1, 0.4, font_size=13, bold=True, color=C_HEAD1)
anat = [
"External Ear",
" β³ Pinna (auricle)",
" β³ External auditory canal (EAC)",
" β³ Tympanic membrane (TM)",
"",
"Middle Ear",
" β³ Ossicles: Malleus β Incus β Stapes",
" β³ Eustachian tube",
" β³ Round & oval windows",
"",
"Inner Ear",
" β³ Cochlea (hearing)",
" β³ Vestibule + Semicircular canals (balance)",
]
add_text(slide, "\n".join(anat), 0.2, 1.15, 4.1, 3.8, font_size=10.5, color=C_WHITE)
# Col 2: Physiology
add_text(slide, "π’ PHYSIOLOGY", 4.6, 0.75, 4.0, 0.4, font_size=13, bold=True, color=C_HEAD3)
phys = [
"HEARING pathway:",
"Sound β Pinna β EAC β TM vibrates",
" β",
"Ossicles amplify β Oval window",
" β",
"Cochlear fluid waves β Hair cells (organ of Corti)",
" β",
"CN VIII β Auditory cortex (temporal lobe)",
"",
"EQUILIBRIUM:",
"Semicircular canals β detect rotation",
"Utricle & Saccule β detect linear accel.",
" β β CN VIII β Cerebellum",
]
add_text(slide, "\n".join(phys), 4.6, 1.15, 4.0, 3.8, font_size=10.5, color=C_WHITE)
# Col 3: Case Taking + Exam
add_text(slide, "π CASE TAKING & EAR EXAM", 8.9, 0.75, 4.2, 0.4, font_size=13, bold=True, color=C_HEAD4)
case = [
"Case Taking (7.3):",
" β¦ Chief complaint (otalgia, discharge,",
" deafness, tinnitus, vertigo)",
" β¦ Duration, onset, character",
" β¦ H/o URTI, trauma, noise exposure",
" β¦ Family Hx, past Hx",
" β¦ Homoeopathic repertorisation",
"",
"Ear Examination (7.4):",
" β¦ Inspection β pinna, EAC",
" β¦ Otoscopy β TM integrity, light reflex",
" β¦ Tuning fork tests:",
" Rinne's & Weber's",
" β¦ DOPS assessment",
]
add_text(slide, "\n".join(case), 8.9, 1.15, 4.2, 3.8, font_size=10.5, color=C_WHITE)
add_text(slide, "Integration β Anatomy (7.1, 7.2) | Physiology (7.2) | Organ Repertory + Case Taking (7.3)",
0.2, 6.9, 12.9, 0.4, font_size=9.5, color=C_GREY, align=PP_ALIGN.CENTER)
# βββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 3: External Ear Diseases
# βββββββββββββββββββββββββββββββββββββββββββββ
slide = blank_slide(prs)
title_bar(slide, "7.5β7.6 | DISEASES OF EXTERNAL EAR")
add_text(slide, "π΄ CONGENITAL DEFECTS", 0.2, 0.75, 4.1, 0.4, font_size=13, bold=True, color=C_HEAD2)
add_text(slide, "Microtia β’ Atresia of EAC\nPre-auricular sinus / tag\nAccessory auricle", 0.2, 1.15, 4.0, 0.9, font_size=11, color=C_WHITE)
add_text(slide, "π΄ TRAUMA", 0.2, 2.2, 4.1, 0.4, font_size=13, bold=True, color=C_HEAD2)
trauma = "Haematoma auris (cauliflower ear)\nLacerations / avulsion\nForeign body in EAC\n β³ Types: Animate / Inanimate\n β³ Rx: Ear syringing / forceps / suction"
add_text(slide, trauma, 0.2, 2.6, 4.0, 1.5, font_size=11, color=C_WHITE)
add_text(slide, "π΄ INFECTIONS", 4.5, 0.75, 4.2, 0.4, font_size=13, bold=True, color=C_HEAD2)
inf = [
"Otitis Externa (OE):",
" Aetiology β Pseudomonas, Staph, fungi",
" Features β otalgia, itching, discharge, TM normal",
" Rx β aural toilet, antibiotic/antifungal drops",
"",
"Malignant OE:",
" Pseudomonas β Diabetics",
" Spreads to skull base β CN palsies",
"",
"Furunculosis:",
" Boil in outer 1/3 EAC",
" Intense pain, tragus tenderness",
" Rx β incision & drainage",
"",
"Perichondritis:",
" Infection of pinna cartilage",
" Cauliflower deformity if untreated",
]
add_text(slide, "\n".join(inf), 4.5, 1.1, 4.2, 5.5, font_size=10.5, color=C_WHITE)
add_text(slide, "π‘ NEOPLASMS", 9.0, 0.75, 4.1, 0.4, font_size=13, bold=True, color=C_HEAD4)
neo = [
"Benign:",
" Exostosis, osteoma (EAC)",
" Keloid (pinna)",
"",
"Malignant:",
" SCC (commonest of pinna)",
" BCC",
"",
"WAX (Cerumen):",
" Impacted wax β conductive deafness",
" Rx: Ear drops (olive oil) β syringing",
"",
"π’ HOMOEOPATHIC REMEDIES (7.6):",
" Conium, Graphites, Psorinum",
" Capsicum, Merc sol, Sulphur",
" Belladonna (acute OE)",
" Repertory β Synthesis/Radar",
"",
"Assess: SAQ | Integration: Materia Medica + Repertory",
]
add_text(slide, "\n".join(neo), 9.0, 1.1, 4.2, 5.5, font_size=10.5, color=C_WHITE)
# βββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 4: ASOM
# βββββββββββββββββββββββββββββββββββββββββββββ
slide = blank_slide(prs)
title_bar(slide, "7.7β7.8 | ACUTE SUPPURATIVE OTITIS MEDIA (ASOM)")
# Aetiology β Pathology β Clinical β Investigation β Management flow
add_text(slide, "ASOM DISEASE FLOW", 0.3, 0.75, 12.7, 0.4, font_size=14, bold=True, color=C_HEAD3, align=PP_ALIGN.CENTER)
boxes = [
(0.3, 1.3, 2.2, "AETIOLOGY\nβββββββ\nβ’ Strep pneumoniae\nβ’ H. influenzae\nβ’ Moraxella\nβ’ Via Eustachian tube (URTI)\nβ’ β incidence in children", C_BOX1, C_HEAD1),
(2.8, 1.3, 2.2, "PATHOLOGY\nβββββββ\nβ’ Congestion β Exudate\nβ’ TM bulges\nβ’ Perforation β Discharge\nβ’ Stages:\n 1.Hyperaemia\n 2.Exudation\n 3.Suppuration\n 4.Coalescence\n 5.Complication/Resolution", C_BOX2, C_HEAD5),
(5.3, 1.3, 2.2, "CLINICAL\nFEATURES\nβββββββ\nβ’ Otalgia (severe)\nβ’ Fever\nβ’ Conductive deafness\nβ’ Discharge (post-perforation)\nβ’ TM: congested β\n bulging β perforated", C_BOX3, C_HEAD3),
(7.8, 1.3, 2.2, "INVESTIGATIONS\nβββββββ\nβ’ Otoscopy\nβ’ Audiometry\nβ’ Tympanometry\nβ’ Culture & sensitivity\n (discharge)\nβ’ X-ray mastoid", C_BOX4, C_HEAD4),
(10.3, 1.3, 2.6, "MANAGEMENT\nβββββββ\nConservative:\nβ’ Analgesics, antipyretics\nβ’ Antibiotics (Amox/Augmentin)\nβ’ Nasal decongestants\n\nSurgical:\nβ’ Aural toilet\nβ’ Myringotomy\n (if bulging TM)", C_BOX1, C_HEAD1),
]
for (x, y, w, txt, bg, fc) in boxes:
add_shape_box(slide, x, y, w, 4.8, bg, txt, font_size=10, text_color=fc, bold=False)
# Arrows between boxes
for x_arr in [2.55, 5.05, 7.55, 10.05]:
add_text(slide, "β", x_arr, 3.2, 0.3, 0.4, font_size=16, bold=True, color=C_ARROW, align=PP_ALIGN.CENTER)
add_text(slide, "π’ HOMOEOPATHIC REMEDIES (7.8): Belladonna β’ Hepar sulph β’ Merc sol β’ Pulsatilla β’ Chamomilla β’ Capsicum β’ Silicea",
0.3, 6.4, 12.7, 0.55, font_size=11.5, color=C_HEAD3, align=PP_ALIGN.CENTER)
# βββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 5: CSOM
# βββββββββββββββββββββββββββββββββββββββββββββ
slide = blank_slide(prs)
title_bar(slide, "7.9β7.10 | CHRONIC SUPPURATIVE OTITIS MEDIA (CSOM)")
# Types
add_text(slide, "TYPES OF CSOM", 0.3, 0.78, 12.7, 0.35, font_size=13, bold=True, color=C_TITLE, align=PP_ALIGN.CENTER)
add_shape_box(slide, 0.3, 1.2, 5.8, 1.4, C_BOX3,
"SAFE (Tubotympanic / Mucosal Type)\nβ’ Central perforation β’ Mucoid discharge β’ No cholesteatoma\nβ’ Better prognosis",
font_size=11, text_color=C_HEAD3)
add_shape_box(slide, 6.5, 1.2, 6.5, 1.4, C_BOX2,
"UNSAFE (Atticoantral / Squamosal Type)\nβ’ Marginal / Attic perforation β’ Cholesteatoma β’ Offensive discharge\nβ’ Worse prognosis β can lead to COMPLICATIONS",
font_size=11, text_color=C_HEAD2)
# Arrow
add_text(slide, "β ALWAYS RULE OUT UNSAFE TYPE", 0.3, 2.7, 12.7, 0.35, font_size=12, bold=True, color=C_HEAD2, align=PP_ALIGN.CENTER)
cols = [
(0.3, 3.1, 3.8, "AETIOLOGY\nβββββββ\nβ’ Unresolved ASOM\nβ’ Repeated URTI\nβ’ Poor hygiene / nutrition\nβ’ Eustachian tube dysfunction\nβ’ Cleft palate", C_BOX1, C_HEAD1),
(4.4, 3.1, 3.8, "CLINICAL FEATURES\nβββββββ\nβ’ Chronic / intermittent\n ear discharge\nβ’ Conductive deafness\nβ’ Otalgia (mild/absent)\nβ’ Cholesteatoma β pearly\n white mass in ear", C_BOX2, C_HEAD5),
(8.5, 3.1, 4.5, "INVESTIGATIONS\nβββββββ\nβ’ Otoscopy\nβ’ Pure tone audiometry\nβ’ Tympanometry\nβ’ HRCT temporal bone\n (cholesteatoma extent)\nβ’ Swab C&S", C_BOX3, C_HEAD3),
]
for (x, y, w, txt, bg, fc) in cols:
add_shape_box(slide, x, y, w, 2.0, bg, txt, font_size=10.5, text_color=fc)
add_text(slide, "MANAGEMENT", 0.3, 5.25, 12.7, 0.3, font_size=12, bold=True, color=C_HEAD4, align=PP_ALIGN.CENTER)
mgmt = [
"Conservative: Aural toilet β Topical antibiotics β Treat underlying URTI",
"Surgical: Tympanoplasty (repair TM) | Mastoidectomy (cholesteatoma / unsafe type)",
"COMPLICATIONS: Mastoiditis β’ Intracranial (meningitis, brain abscess, lateral sinus thrombosis) β’ Facial nerve palsy",
]
add_text(slide, "\n".join(mgmt), 0.3, 5.6, 12.7, 1.1, font_size=11, color=C_WHITE)
add_text(slide, "π’ HOMOEOPATHIC REMEDIES (7.10): Merc sol β’ Silicea β’ Pulsatilla β’ Hepar sulph β’ Kali mur β’ Calc sulph",
0.3, 6.8, 12.7, 0.4, font_size=11, color=C_HEAD3, align=PP_ALIGN.CENTER)
# βββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 6: Chronic Non-Suppurative Otitis Media
# βββββββββββββββββββββββββββββββββββββββββββββ
slide = blank_slide(prs)
title_bar(slide, "7.11 | CHRONIC NON-SUPPURATIVE OTITIS MEDIA")
conditions = [
("EUSTACHIAN TUBE CATARRH", 0.3, 0.85, 3.8, 5.5, C_BOX1, C_HEAD1,
"β’ ET dysfunction\nβ’ Negative middle ear pressure\nβ’ Retracted TM\nβ’ Conductive deafness\n\nFeatures:\nβ hearing (bilateral)\nEar fullness / popping\n\nRx:\nβ’ Valsalva manoeuvre\nβ’ Nasal decongestants\nβ’ ET balloon dilation"),
("SEROUS OTITIS MEDIA\n(Glue Ear)", 4.4, 0.85, 3.8, 5.5, C_BOX2, C_HEAD5,
"β’ Non-infected fluid in\n middle ear\nβ’ Commonest in children\nβ’ Adenoid hypertrophy\n (key risk factor)\n\nFeatures:\nβ’ Flat TM, blue hue\nβ’ Conductive deafness\nβ’ Tympanometry β flat\n\nRx:\nβ’ Watchful waiting (3 m)\nβ’ Grommet insertion\nβ’ Adenoidectomy"),
("ATELECTASIS OF TM &\nTYMPANOSCLEROSIS", 8.5, 0.85, 4.5, 5.5, C_BOX3, C_HEAD3,
"ATELECTASIS:\nβ’ TM collapsed inward\nβ’ Risk of cholesteatoma\nβ’ Retraction pockets\n\nTYMPANOSCLEROSIS:\nβ’ Calcified plaques on TM\nβ’ Chalk patches\nβ’ Conductive deafness\nβ’ Sequelae of repeated\n ASOM / grommet use\n\nRx: Myringoplasty if\nsignificant hearing loss"),
]
for (title, x, y, w, h, bg, fc, body) in conditions:
add_shape_box(slide, x, y, w, 0.5, bg, title, font_size=12, text_color=fc, bold=True)
add_text(slide, body, x+0.05, y+0.55, w-0.1, h-0.55, font_size=10.5, color=C_WHITE, bg_color=None)
add_text(slide, "All β Conductive Deafness β’ Audiometry + Tympanometry are KEY investigations β’ Integration: Anatomy",
0.3, 6.7, 12.7, 0.5, font_size=11, color=C_GREY, align=PP_ALIGN.CENTER)
# βββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 7: Otalgia & Otorrhea
# βββββββββββββββββββββββββββββββββββββββββββββ
slide = blank_slide(prs)
title_bar(slide, "7.12β7.15 | OTALGIA (EARACHE) β’ OTORRHEA")
# Left half: Otalgia
add_text(slide, "π΄ OTALGIA (7.12β7.13)", 0.3, 0.75, 6.3, 0.4, font_size=14, bold=True, color=C_HEAD2)
otalgia_local = ["LOCAL CAUSES:", "β’ OE / Furunculosis", "β’ ASOM / CSOM", "β’ TM perforation", "β’ Foreign body EAC"]
otalgia_ref = ["REFERRED PAIN:", "β’ Dental caries / abscess (V3)", "β’ Tonsillitis (IX)", "β’ TMJ dysfunction", "β’ Cervical spine (C2,3)", "β’ Laryngeal/pharyngeal Ca"]
add_shape_box(slide, 0.3, 1.2, 2.8, 3.5, C_BOX1, "\n".join(otalgia_local), font_size=11, text_color=C_HEAD1)
add_shape_box(slide, 3.3, 1.2, 3.1, 3.5, C_BOX4, "\n".join(otalgia_ref), font_size=11, text_color=C_HEAD4)
add_text(slide, "Investigation: Full ENT exam + Dental exam β’ Ix: OPG, TM assessment, culture",
0.3, 4.85, 6.3, 0.5, font_size=10, color=C_GREY)
add_text(slide, "π’ Homoeopathic Remedies (7.13): Chamomilla β’ Belladonna β’ Aconite β’ Pulsatilla β’ Merc sol",
0.3, 5.4, 6.3, 0.5, font_size=10.5, color=C_HEAD3)
# Divider
add_text(slide, "β", 6.6, 0.75, 0.2, 6.3, font_size=80, color=RGBColor(0x33,0x55,0x77))
# Right half: Otorrhea
add_text(slide, "π OTORRHEA (7.14β7.15)", 6.9, 0.75, 6.2, 0.4, font_size=14, bold=True, color=C_HEAD4)
otorrhea = [
"AETIOLOGY:",
"β’ ASOM (post-perforation) β purulent",
"β’ CSOM β mucopurulent",
"β’ OE (diffuse) β serous/purulent",
"β’ Cholesteatoma β foul-smelling",
"β’ CSF otorrhea β watery (post-trauma)",
"",
"CHARACTER β DIAGNOSIS:",
"Serous/watery β AOM early / CSF",
"Mucoid β OME / CSOM safe",
"Purulent β ASOM / OE / CSOM",
"Blood-stained β Trauma / malignancy",
"Foul-smelling β Cholesteatoma",
"",
"INVESTIGATIONS:",
"β’ Otoscopy β’ Culture & sensitivity",
"β’ Audiometry β’ CT (if cholesteatoma)",
"",
"MANAGEMENT:",
"β’ Aural toilet β topical Abx drops",
"β’ Systemic Abx if needed",
"β’ Surgical: Myringoplasty / Mastoidectomy",
"",
"π’ Homoeopathic (7.15): Pulsatilla β’ Merc sol",
"β’ Silicea β’ Graphites β’ Kali bich β’ Thuja",
]
add_text(slide, "\n".join(otorrhea), 6.9, 1.15, 6.2, 5.7, font_size=10.5, color=C_WHITE)
# βββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 8: Deafness
# βββββββββββββββββββββββββββββββββββββββββββββ
slide = blank_slide(prs)
title_bar(slide, "7.16β7.18 | DEAFNESS (HEARING LOSS)")
add_text(slide, "TYPES OF DEAFNESS", 0.3, 0.78, 12.7, 0.35, font_size=13, bold=True, color=C_TITLE, align=PP_ALIGN.CENTER)
type_boxes = [
("CONDUCTIVE\nDEAFNESS", 0.3, 1.25, 3.8, "β’ Problem: outer/middle ear\nβ’ Sound not transmitted\nβ’ CAUSES:\n β³ Wax impaction\n β³ TM perforation\n β³ Otosclerosis\n β³ CSOM / ASOM\n β³ OME (glue ear)\n\nTuning Fork:\nRinne βve\nWeber β affected side", C_BOX1, C_HEAD1),
("SENSORINEURAL\nDEAFNESS (SNHL)", 4.4, 1.25, 4.4, "β’ Problem: cochlea / CN VIII\nβ’ CAUSES:\n β³ Noise-induced (NIHL)\n β³ Presbyacusis (aging)\n β³ Ototoxic drugs\n (aminoglycosides, cisplatin)\n β³ Meniere's disease\n β³ Acoustic neuroma\n β³ Viral labyrinthitis\n\nTuning Fork:\nRinne +ve\nWeber β better ear", C_BOX2, C_HEAD5),
("MIXED\nDEAFNESS", 9.1, 1.25, 3.9, "β’ Both conductive +\n sensorineural components\nβ’ Common in: chronic\n otitis media with\n ossicular damage\n\nTuning Fork:\nRinne βve\nWeber β better side\n\nAudiometry:\n Air-bone gap present\n with elevated bone\n conduction threshold", C_BOX3, C_HEAD3),
]
for (title, x, y, w, body, bg, fc) in type_boxes:
add_shape_box(slide, x, y, w, 0.45, bg, title, font_size=12, text_color=fc, bold=True)
add_text(slide, body, x+0.05, y+0.5, w-0.1, 4.0, font_size=10.5, color=C_WHITE)
add_text(slide, "INVESTIGATIONS β", 0.3, 5.5, 1.6, 0.4, font_size=11, bold=True, color=C_HEAD4)
ix = "Pure Tone Audiometry (PTA) β’ Tympanometry β’ OAE (Otoacoustic Emissions) β’ BERA/ABR β’ Speech Audiometry β’ Hearing Test (clinical β Whisper, Watch Tick)"
add_text(slide, ix, 2.0, 5.5, 11.0, 0.5, font_size=11, color=C_WHITE)
add_text(slide, "MANAGEMENT β", 0.3, 6.1, 1.6, 0.4, font_size=11, bold=True, color=C_HEAD4)
mgmt = "Conductive: Surgery (myringoplasty, stapedectomy, grommet) | SNHL: Hearing aids, cochlear implants | Hearing Aids & Implants (C/2)"
add_text(slide, mgmt, 2.0, 6.1, 11.0, 0.5, font_size=11, color=C_WHITE)
add_text(slide, "π’ Homoeopathic (7.18): China β’ Graphites β’ Phosphorus β’ Merc sol β’ Kali mur β’ Causticum β’ Silicea",
0.3, 6.75, 12.7, 0.4, font_size=11, color=C_HEAD3, align=PP_ALIGN.CENTER)
# βββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 9: Tinnitus
# βββββββββββββββββββββββββββββββββββββββββββββ
slide = blank_slide(prs)
title_bar(slide, "7.19β7.20 | TINNITUS")
add_text(slide, "\"Perception of sound WITHOUT external stimulus\"", 0.3, 0.78, 12.7, 0.35,
font_size=12, bold=True, color=C_TITLE, align=PP_ALIGN.CENTER)
add_text(slide, "TYPES", 0.3, 1.2, 6.3, 0.35, font_size=13, bold=True, color=C_HEAD1)
types_t = [
("SUBJECTIVE (commonest)", "β’ Only patient hears\nβ’ Damage to auditory pathway\nβ’ Cochlear/retrocochlear", C_BOX1, C_HEAD1),
("OBJECTIVE (rare)", "β’ Examiner can hear too\nβ’ Pulsatile (vascular) /\n clicking (palatal myoclonus)\nβ’ Stapedial muscle spasm", C_BOX2, C_HEAD5),
]
for i, (title, body, bg, fc) in enumerate(types_t):
x = 0.3 + i * 3.2
add_shape_box(slide, x, 1.6, 3.0, 0.4, bg, title, font_size=11, text_color=fc, bold=True)
add_text(slide, body, x+0.1, 2.05, 2.9, 1.5, font_size=10.5, color=C_WHITE)
add_text(slide, "CAUSES", 0.3, 3.65, 6.3, 0.35, font_size=13, bold=True, color=C_HEAD2)
causes_t = "β’ Noise trauma (NIHL)\nβ’ Presbyacusis\nβ’ Meniere's disease\nβ’ Otosclerosis\nβ’ Acoustic neuroma\nβ’ Ototoxic drugs (aspirin, aminoglycosides)\nβ’ Anaemia / hypertension (pulsatile)\nβ’ Wax impaction\nβ’ ASOM / CSOM"
add_text(slide, causes_t, 0.3, 4.05, 6.2, 2.7, font_size=10.5, color=C_WHITE)
add_text(slide, "INVESTIGATIONS", 6.8, 1.2, 6.3, 0.35, font_size=13, bold=True, color=C_HEAD3)
ix_t = "β’ Detailed history (character, unilateral/bilateral, pulsatile?)\nβ’ PTA + audiometry\nβ’ Tympanometry\nβ’ MRI IAM (rule out acoustic neuroma)\nβ’ BP, CBC (rule out medical causes)"
add_text(slide, ix_t, 6.8, 1.6, 6.3, 1.6, font_size=11, color=C_WHITE)
add_text(slide, "MANAGEMENT", 6.8, 3.35, 6.3, 0.35, font_size=13, bold=True, color=C_HEAD4)
mgmt_t = "β’ Treat underlying cause\nβ’ Tinnitus retraining therapy (TRT)\nβ’ Sound therapy / white noise generators\nβ’ CBT (cognitive behavioural therapy)\nβ’ Hearing aids (if deafness coexists)\nβ’ Avoid ototoxins\nβ’ Reassurance (most cases benign)"
add_text(slide, mgmt_t, 6.8, 3.75, 6.3, 2.6, font_size=11, color=C_WHITE)
add_text(slide, "π’ Homoeopathic (7.20): China β’ Graphites β’ Carboneum sulph β’ Nat sal β’ Kali iod β’ Merc sol β’ Cinchona",
0.3, 6.85, 12.7, 0.4, font_size=11, color=C_HEAD3, align=PP_ALIGN.CENTER)
# βββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 10: Vertigo
# βββββββββββββββββββββββββββββββββββββββββββββ
slide = blank_slide(prs)
title_bar(slide, "7.21β7.23 | VERTIGO")
add_text(slide, "\"Illusion of movement (spinning) β true vestibular vertigo\"", 0.3, 0.78, 12.7, 0.35,
font_size=12, bold=True, color=C_TITLE, align=PP_ALIGN.CENTER)
# Central vs Peripheral
add_text(slide, "PERIPHERAL VERTIGO", 0.3, 1.2, 6.2, 0.4, font_size=13, bold=True, color=C_HEAD3)
add_text(slide, "CENTRAL VERTIGO", 6.8, 1.2, 6.0, 0.4, font_size=13, bold=True, color=C_HEAD2)
peri_v = [
"CAUSES:",
"β’ BPPV (commonest)",
"β’ Meniere's disease",
"β’ Vestibular neuritis",
"β’ Labyrinthitis",
"β’ Acoustic neuroma (late)",
"",
"FEATURES:",
"β’ Sudden onset",
"β’ Episodic / positional",
"β’ Nausea + vomiting ++",
"β’ Tinnitus / deafness often present",
"β’ Nystagmus: horizontal, fatiguable",
"β’ Romberg's test +ve",
"β’ Gait: unsteady, leans to affected side",
]
add_text(slide, "\n".join(peri_v), 0.3, 1.65, 6.2, 4.8, font_size=10.5, color=C_WHITE)
cent_v = [
"CAUSES:",
"β’ Vertebrobasilar insufficiency",
"β’ Cerebellar lesions",
"β’ MS",
"β’ Brain stem stroke",
"β’ Posterior fossa tumours",
"",
"FEATURES:",
"β’ Gradual onset",
"β’ Constant, severe",
"β’ Other neurological signs",
"β’ Nystagmus: vertical, non-fatiguable",
"β’ No hearing loss",
"β’ Cranial nerve involvement",
]
add_text(slide, "\n".join(cent_v), 6.8, 1.65, 6.0, 4.8, font_size=10.5, color=C_WHITE)
add_text(slide, "Investigations β PTA β’ Caloric test β’ MRI brain/posterior fossa β’ ENG/VNG | Management β Vestibular suppressants (cinnarizine) β’ Physiotherapy (Epley manoeuvre for BPPV)",
0.3, 6.6, 12.7, 0.6, font_size=10.5, color=C_GREY)
add_text(slide, "π’ Homoeopathic (7.23): Conium β’ Gelsemium β’ Cocculus β’ Belladonna β’ Phosphorus β’ Tabacum",
0.3, 7.1, 12.7, 0.25, font_size=11, color=C_HEAD3, align=PP_ALIGN.CENTER)
# βββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 11: Meniere's + BPPV + Acoustic Neuroma
# βββββββββββββββββββββββββββββββββββββββββββββ
slide = blank_slide(prs)
title_bar(slide, "7.24β7.25 | MENIERE'S DISEASE β’ BPPV β’ ACOUSTIC NEUROMA")
# Meniere's
add_text(slide, "π΅ MENIERE'S DISEASE (7.24)", 0.3, 0.78, 4.3, 0.4, font_size=13, bold=True, color=C_HEAD1)
men = [
"Pathology: Endolymphatic hydrops",
" β³ Excess endolymph in cochlea",
"",
"TRIAD:",
" 1. Episodic vertigo",
" 2. Fluctuating SNHL",
" 3. Tinnitus + aural fullness",
"",
"Ix: PTA β’ Electrocochleography (ECoG)",
" Glycerol test β’ MRI IAM",
"",
"Rx:",
" β’ Low salt diet + diuretics",
" β’ Betahistine (Serc)",
" β’ Vestibular sedatives",
" β’ Surgery: Endolymphatic sac decompression",
" β’ Labyrinthectomy (last resort)",
"",
"Homoeop: Conium β’ China β’ Cocculus",
"β’ Gelsemium β’ Phosphorus",
]
add_text(slide, "\n".join(men), 0.3, 1.2, 4.3, 5.5, font_size=10.5, color=C_WHITE)
# BPPV
add_text(slide, "π’ BPPV (7.25)", 4.9, 0.78, 3.8, 0.4, font_size=13, bold=True, color=C_HEAD3)
bppv = [
"= Benign Paroxysmal Positional Vertigo",
"",
"Pathology:",
" Canalolithiasis (otoconia in",
" posterior semicircular canal)",
"",
"Features:",
" β’ Brief (<1 min) vertigo on",
" position change",
" β’ Dix-Hallpike test +ve",
" β’ No deafness / tinnitus",
"",
"Rx:",
" Epley manoeuvre (canalith",
" repositioning) β FIRST LINE",
" Vestibular rehab exercises",
"",
"Homoeop: Cocculus β’ Conium",
"β’ Gelsemium",
]
add_text(slide, "\n".join(bppv), 4.9, 1.2, 3.8, 5.5, font_size=10.5, color=C_WHITE)
# Acoustic Neuroma
add_text(slide, "π‘ ACOUSTIC NEUROMA (7.25)", 9.0, 0.78, 4.1, 0.4, font_size=13, bold=True, color=C_HEAD4)
acn = [
"= Vestibular Schwannoma",
" (CN VIII, vestibular division)",
"",
"Features (GRADUAL):",
" β’ Unilateral SNHL",
" β’ Tinnitus",
" β’ Vertigo (late)",
" β’ Facial numbness (CN V)",
" β’ Facial palsy (CN VII β late)",
"",
"Ix:",
" MRI IAM β GOLD STANDARD",
" Auditory brainstem response (ABR)",
" PTA",
"",
"Rx:",
" Observation (small) / Radiosurgery",
" (Gamma knife) / Surgery",
" (translabyrinthine approach)",
]
add_text(slide, "\n".join(acn), 9.0, 1.2, 4.1, 5.5, font_size=10.5, color=C_WHITE)
# βββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 12: Facial Palsy / Bell's Palsy
# βββββββββββββββββββββββββββββββββββββββββββββ
slide = blank_slide(prs)
title_bar(slide, "7.26 | FACIAL PARALYSIS β’ BELL'S PALSY")
# Left: CN VII course
add_text(slide, "CN VII (FACIAL NERVE) COURSE", 0.3, 0.78, 5.5, 0.4, font_size=13, bold=True, color=C_HEAD1)
cn7 = [
"Motor cortex",
" β",
"Internal capsule",
" β",
"Pons (facial nucleus)",
" β",
"Cerebellopontine angle (CPA)",
" β",
"Internal auditory meatus (IAM)",
" β",
"Geniculate ganglion β Chorda tympani",
" β",
"Stylomastoid foramen",
" β",
"Parotid gland β Terminal branches:",
" Temporal β’ Zygomatic β’ Buccal",
" Marginal mandibular β’ Cervical",
"",
"UPPER MOTOR NEURON (UMN) vs LOWER MOTOR NEURON (LMN):",
"UMN: forehead SPARED (bilateral cortical supply)",
"LMN: forehead INVOLVED (all branches affected)",
]
add_text(slide, "\n".join(cn7), 0.3, 1.2, 5.5, 5.6, font_size=10.5, color=C_WHITE)
# Middle: Causes
add_text(slide, "CAUSES OF FACIAL PALSY", 6.1, 0.78, 3.5, 0.4, font_size=13, bold=True, color=C_HEAD4)
causes_fp = [
"LMN (commonest):",
"β’ Bell's Palsy (idiopathic)",
"β’ Ramsay Hunt syndrome (VZV)",
"β’ Acoustic neuroma",
"β’ Parotid tumour",
"β’ Trauma / temporal bone Fx",
"β’ CSOM (cholesteatoma)",
"β’ Mastoidectomy (iatrogenic)",
"β’ Lyme disease",
"",
"UMN:",
"β’ Stroke (CVA)",
"β’ Brain tumour",
"β’ MS",
]
add_text(slide, "\n".join(causes_fp), 6.1, 1.2, 3.5, 5.6, font_size=10.5, color=C_WHITE)
# Right: Bell's Palsy details
add_text(slide, "BELL'S PALSY (Idiopathic LMN)", 9.8, 0.78, 3.3, 0.4, font_size=12, bold=True, color=C_HEAD2)
bells = [
"Aetiology: HSV-1 reactivation",
"",
"Features:",
"β’ Sudden unilateral LMN palsy",
"β’ Forehead involved",
"β’ Incomplete eye closure",
" (Bell's phenomenon)",
"β’ Hyperacusis",
"β’ Taste loss (ant 2/3 tongue)",
"β’ Lacrimation disturbance",
"",
"Ix: Clinical diagnosis",
"β’ Rule out: Ramsay Hunt (vesicles)",
"β’ MRI if atypical",
"",
"Grading: House-Brackmann Scale",
" I (normal) β VI (complete palsy)",
"",
"Rx:",
"β’ Prednisolone (started <72 h)",
"β’ Acyclovir (if HSV suspected)",
"β’ Eye protection: drops/patch",
"β’ 80% recover completely",
"",
"π’ Homoeopathic:",
"β’ Causticum β’ Aconite β’ Gelsemium",
"β’ Cadmium sulph β’ Dulcamara",
]
add_text(slide, "\n".join(bells), 9.8, 1.2, 3.3, 5.6, font_size=10, color=C_WHITE)
# βββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 13: Quick Reference β All Topics Summary
# βββββββββββββββββββββββββββββββββββββββββββββ
slide = blank_slide(prs)
title_bar(slide, "QUICK REFERENCE β EAR SYLLABUS UNIT 7 (ALL TOPICS)")
rows = [
("Topic", "Key Points", "Investigations", "Management", "Homoeop Remedies"),
("ASOM", "Strep pneu / H. inf | Child | URTI", "Otoscopy, Audiometry, C&S", "Abx + Analgesics | Myringotomy", "Belladonna, Hepar sulph, Pulsatilla"),
("CSOM (Safe)", "Central perf | Mucoid d/c | No cholest.", "Otoscopy, PTA, CT", "Aural toilet, Tympanoplasty", "Pulsatilla, Kali mur, Merc sol"),
("CSOM (Unsafe)", "Marginal perf | Cholesteatoma | Offensive", "HRCT temporal bone, PTA", "Mastoidectomy", "Silicea, Hepar sulph, Calc sulph"),
("Glue Ear/OME", "Child | ET dysfunction | No discharge", "Tympanometry (flat)", "Grommet + Adenoidectomy", "Kali mur, Pulsatilla, Merc sol"),
("Otalgia", "Local + Referred pain (dental, tonsil)", "ENT exam, OPG, Culture", "Treat cause", "Chamomilla, Aconite, Pulsatilla"),
("Otorrhea", "Character β diagnosis", "Otoscopy, C&S, CT", "Aural toilet, Abx drops, Surgery", "Pulsatilla, Silicea, Graphites"),
("Deafness", "Conductive / SNHL / Mixed", "PTA, Tympanometry, BERA", "Hearing aid / CI / Surgery", "China, Causticum, Kali mur"),
("Tinnitus", "Subjective (common) / Objective", "PTA, MRI IAM, BP/CBC", "TRT, Sound therapy, Treat cause", "China, Nat sal, Carboneum sulph"),
("Vertigo", "Peripheral > Central | BPPV commonest", "PTA, Caloric, MRI", "Epley, Betahistine, Physio", "Conium, Cocculus, Gelsemium"),
("Meniere's", "Hydrops | Triad: vertigo+SNHL+tinnitus", "ECoG, PTA, Glycerol test", "Low salt, Betahistine, Surgery", "Conium, China, Cocculus"),
("Acoustic Neuroma", "CN VIII | Unilateral SNHL + tinnitus", "MRI IAM (gold std), ABR", "Radiosurgery / Surgery", "Phosphorus, Conium"),
("Bell's Palsy", "Idiopathic LMN | HSV-1 | 80% recover", "Clinical + Rule out Ramsay Hunt", "Prednisolone <72h, Eye care", "Causticum, Aconite, Gelsemium"),
]
col_widths = [1.8, 3.2, 2.5, 2.4, 3.1]
col_x = [0.2, 2.1, 5.4, 7.95, 10.45]
row_h = 0.44
row_y_start = 0.75
for r, row in enumerate(rows):
y = row_y_start + r * row_h
for c, (cell, cx, cw) in enumerate(zip(row, col_x, col_widths)):
if r == 0:
bg = RGBColor(0x10, 0x35, 0x60)
fc = C_TITLE
fs = 10
bold = True
else:
bg = C_BOX1 if r % 2 == 0 else RGBColor(0x15, 0x25, 0x40)
fc = [C_HEAD1, C_WHITE, C_HEAD3, C_HEAD4, C_HEAD5][c]
fs = 9
bold = False
box = slide.shapes.add_shape(1, Inches(cx), Inches(y), Inches(cw), Inches(row_h - 0.02))
box.fill.solid()
box.fill.fore_color.rgb = bg
box.line.color.rgb = RGBColor(0x22, 0x44, 0x66)
box.line.width = Pt(0.5)
tf = box.text_frame
tf.word_wrap = True
p = tf.paragraphs[0]
p.alignment = PP_ALIGN.LEFT
run = p.add_run()
run.text = cell
run.font.size = Pt(fs)
run.font.bold = bold
run.font.color.rgb = fc
prs.save("/tmp/workspace/ear-notes/EAR_Surgery_Notes.pptx")
print("Saved successfully!")
cd /tmp/workspace/ear-notes && python3 make_notes.py 2>&1
ls -lh /tmp/workspace/ear-notes/EAR_Surgery_Notes.pptx
EAR Surgery Notes
Presentation Β· PPTX
| Slide | Topic | Colour Theme |
|---|---|---|
| 1 | Overview mind-map (all 26 syllabus items) | Gold on dark navy |
| 2 | Anatomy (7.1) + Physiology (7.2) + Case Taking + Ear Exam | Cyan / Green / Orange |
| 3 | External Ear Diseases (7.5β7.6): Congenital, Trauma, OE, Wax, Neoplasm | Coral red |
| 4 | ASOM (7.7β7.8) β 5-box flow: Aetiology β Pathology β Clinics β Ix β Rx | Green with yellow arrows |
| 5 | CSOM (7.9β7.10) β Safe vs Unsafe type comparison table | Purple vs Green |
| 6 | Chronic Non-Suppurative OM (7.11): ET Catarrh, Glue Ear, Atelectasis | Multi-colour |
| 7 | Otalgia (7.12β7.13) + Otorrhea (7.14β7.15) split layout | Red / Orange |
| 8 | Deafness (7.16β7.18) β 3 types + Tuning fork findings + Management | Cyan / Orchid / Green |
| 9 | Tinnitus (7.19β7.20) β Types, Causes, Ix, Management | Full column layout |
| 10 | Vertigo (7.21β7.23) β Peripheral vs Central comparison | Green vs Red |
| 11 | Meniere's Disease + BPPV + Acoustic Neuroma (7.24β7.25) | 3-column |
| 12 | Facial Palsy / Bell's Palsy (7.26) β CN VII course + UMN/LMN + Rx | Blue / Orange / Red |
| 13 | Quick Reference Table β ALL 12 topics in one sheet | Colour-coded columns |
Add some diagrams , images from authentic books and make it a pdf
~/ear-notes/build_ear_pdf.py
"""
EAR Surgery Notes PDF - with original schematic diagrams
Uses matplotlib for diagrams + reportlab for PDF layout
"""
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.patches import FancyArrowPatch, FancyBboxPatch, Arc, Wedge, Circle, Ellipse
import matplotlib.patheffects as pe
import numpy as np
import os, io
OUT_DIR = "/tmp/workspace/ear-notes/diagrams"
os.makedirs(OUT_DIR, exist_ok=True)
# ββ colour palette ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
BG = "#0D1B2A"
GOLD = "#FFD700"
CYAN = "#00E5FF"
RED = "#FF6B6B"
GREEN = "#7BFF6B"
ORANGE= "#FFA500"
VIOLET= "#DA70D6"
WHITE = "#FFFFFF"
LGREY = "#AAAAAA"
DBLUE = "#1A3A5C"
DPURP = "#2D1B3D"
DGREEN= "#1A3D2D"
DORNG = "#3D2A1A"
def save_fig(fig, name):
path = f"{OUT_DIR}/{name}.png"
fig.savefig(path, dpi=150, bbox_inches='tight', facecolor=BG)
plt.close(fig)
return path
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# DIAGRAM 1 β Cross-section of the Ear (schematic)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def diag_ear_anatomy():
fig, ax = plt.subplots(figsize=(11, 6), facecolor=BG)
ax.set_facecolor(BG)
ax.set_xlim(0, 11); ax.set_ylim(0, 6)
ax.axis('off')
ax.set_title("Cross-Section of the EAR β Schematic Diagram", color=GOLD,
fontsize=14, fontweight='bold', pad=10)
# ββ EXTERNAL EAR region ββββββββββββββββββββββββββββββββββββββββββββββββββ
ext_box = FancyBboxPatch((0.1, 0.4), 2.8, 5.2,
boxstyle="round,pad=0.05", lw=1.5,
edgecolor=CYAN, facecolor="#0A2030")
ax.add_patch(ext_box)
ax.text(1.5, 5.75, "EXTERNAL EAR", ha='center', color=CYAN, fontsize=9, fontweight='bold')
# Pinna (simple curved shape)
pinna = mpatches.Arc((0.6, 3.0), 0.9, 3.5, angle=0, theta1=20, theta2=340,
color=CYAN, lw=2.5)
ax.add_patch(pinna)
ax.text(0.55, 3.0, "Pinna\n(Auricle)", ha='center', color=CYAN, fontsize=7)
# EAC as a tunnel
eac = mpatches.FancyBboxPatch((0.9, 2.5), 1.9, 1.0,
boxstyle="round,pad=0.02", lw=1,
edgecolor=CYAN, facecolor="#0D2540")
ax.add_patch(eac)
ax.text(1.85, 3.0, "EAC", ha='center', color=CYAN, fontsize=8, fontweight='bold')
ax.text(1.85, 2.65, "(outer 1/3: cartilage\ninner 2/3: bone)", ha='center', color=LGREY, fontsize=6)
# TM
ax.plot([2.8, 2.8], [2.35, 3.65], color=GOLD, lw=4, solid_capstyle='round')
ax.text(2.82, 4.0, "Tympanic\nMembrane\n(TM)", ha='left', color=GOLD, fontsize=7, fontweight='bold')
ax.annotate('', xy=(2.8, 3.65), xytext=(2.8, 4.05),
arrowprops=dict(arrowstyle='->', color=GOLD, lw=1))
# ββ MIDDLE EAR region ββββββββββββββββββββββββββββββββββββββββββββββββββββ
mid_box = FancyBboxPatch((3.05, 0.4), 3.6, 5.2,
boxstyle="round,pad=0.05", lw=1.5,
edgecolor=VIOLET, facecolor="#1A0D2E")
ax.add_patch(mid_box)
ax.text(4.85, 5.75, "MIDDLE EAR", ha='center', color=VIOLET, fontsize=9, fontweight='bold')
# Ossicles chain
# Malleus
malleus = Ellipse((3.5, 3.0), 0.25, 0.55, color=ORANGE, lw=1.5, fill=True)
ax.add_patch(malleus)
ax.text(3.5, 2.5, "Malleus", ha='center', color=ORANGE, fontsize=7, fontweight='bold')
# Incus
incus = Ellipse((4.2, 3.05), 0.3, 0.45, color=ORANGE, lw=1.5, fill=True)
ax.add_patch(incus)
ax.text(4.2, 2.5, "Incus", ha='center', color=ORANGE, fontsize=7, fontweight='bold')
# Stapes
stapes = Ellipse((4.9, 3.0), 0.2, 0.4, color=ORANGE, lw=1.5, fill=True)
ax.add_patch(stapes)
ax.text(4.9, 2.5, "Stapes", ha='center', color=ORANGE, fontsize=7, fontweight='bold')
# Arrows between ossicles
for x1, x2 in [(3.63, 3.9), (4.35, 4.68)]:
ax.annotate('', xy=(x2, 3.0), xytext=(x1, 3.0),
arrowprops=dict(arrowstyle='->', color=GOLD, lw=1.5))
ax.text(4.2, 3.85, "Ossicular Chain\n(amplifies 22Γ)", ha='center', color=ORANGE, fontsize=7)
# Eustachian tube
et_path = plt.Polygon([[3.2, 0.9], [4.5, 0.6], [5.2, 0.55]],
closed=False, fill=False, edgecolor=GREEN, lw=2)
ax.add_patch(et_path)
ax.text(4.2, 1.2, "Eustachian Tube\n(β nasopharynx)", ha='center', color=GREEN, fontsize=7)
# Round window
rw = Circle((5.7, 2.4), 0.2, color=RED, lw=1.5, fill=True, alpha=0.7)
ax.add_patch(rw)
ax.text(5.7, 2.0, "Round\nWindow", ha='center', color=RED, fontsize=6)
# Oval window (stapes footplate)
ow = Ellipse((5.3, 3.0), 0.3, 0.2, color=GOLD, fill=True, alpha=0.8)
ax.add_patch(ow)
ax.text(5.3, 3.35, "Oval Window", ha='center', color=GOLD, fontsize=6)
# ββ INNER EAR region βββββββββββββββββββββββββββββββββββββββββββββββββββββ
inn_box = FancyBboxPatch((6.8, 0.4), 4.1, 5.2,
boxstyle="round,pad=0.05", lw=1.5,
edgecolor=GREEN, facecolor="#0D2010")
ax.add_patch(inn_box)
ax.text(8.85, 5.75, "INNER EAR", ha='center', color=GREEN, fontsize=9, fontweight='bold')
# Cochlea (spiral)
theta = np.linspace(0, 5 * np.pi, 400)
r = 0.05 + 0.18 * theta / (5 * np.pi)
cx, cy = 8.1, 2.8
x_coch = cx + r * np.cos(theta)
y_coch = cy + r * np.sin(theta)
ax.plot(x_coch, y_coch, color=CYAN, lw=2.5)
ax.text(8.1, 1.95, "COCHLEA\n(Hearing)\n2.5 turns\nOrgan of Corti inside", ha='center',
color=CYAN, fontsize=7, fontweight='bold')
# Semicircular canals (3 circles, different orientations)
for dx, dy, label in [(0.45, 0.6, 'Post'), (0.0, 0.6, 'Lat'), (-0.45, 0.6, 'Ant')]:
sc = Circle((9.6 + dx*0.5, 3.2 + dy*0.4), 0.38,
fill=False, edgecolor=GREEN, lw=1.8)
ax.add_patch(sc)
ax.text(9.6, 4.6, "Semicircular\nCanals Γ3\n(Balance/Rotation)", ha='center',
color=GREEN, fontsize=7, fontweight='bold')
# Vestibule
vest = Ellipse((8.85, 3.0), 0.55, 0.45, fill=True,
facecolor="#1A5010", edgecolor=GREEN, lw=1.5, alpha=0.8)
ax.add_patch(vest)
ax.text(8.85, 2.55, "Vestibule\n(Utricle &\nSaccule)", ha='center', color=GREEN, fontsize=6.5)
# CN VIII label
ax.annotate("CN VIII β\nAuditory\ncortex", xy=(10.5, 3.0), xytext=(10.5, 3.0),
ha='center', color=VIOLET, fontsize=8, fontweight='bold')
# Hearing pathway arrow at bottom
ax.annotate('', xy=(10.5, 0.7), xytext=(0.5, 0.7),
arrowprops=dict(arrowstyle='->', color=GOLD, lw=2.5))
ax.text(5.5, 0.5, "SOUND PATHWAY β Pinna β EAC β TM β Ossicles β Oval Window β Cochlea β CN VIII β Brain",
ha='center', color=GOLD, fontsize=7.5, fontweight='bold')
# Region labels at top
for x, lbl, col in [(1.5, "OUTER", CYAN), (4.85, "MIDDLE", VIOLET), (8.85, "INNER", GREEN)]:
ax.text(x, 5.9, lbl, ha='center', color=col, fontsize=9, fontweight='bold',
bbox=dict(boxstyle='round,pad=0.2', facecolor=BG, edgecolor=col))
plt.tight_layout()
return save_fig(fig, "01_ear_anatomy")
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# DIAGRAM 2 β Tympanic Membrane (otoscopic view)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def diag_tympanic_membrane():
fig, axes = plt.subplots(1, 3, figsize=(12, 5), facecolor=BG)
fig.suptitle("TYMPANIC MEMBRANE β Otoscopic Views", color=GOLD,
fontsize=13, fontweight='bold')
titles = ["NORMAL TM", "ASOM β Bulging TM", "CSOM β Perforated TM"]
colors_tm = ["#C8966A", "#FF3333", "#AA6633"]
colors_ring = [LGREY, RED, ORANGE]
for idx, (ax, title, ctm, cring) in enumerate(zip(axes, titles, colors_tm, colors_ring)):
ax.set_facecolor("#1A0A05")
ax.set_xlim(-1.3, 1.3); ax.set_ylim(-1.3, 1.3)
ax.set_aspect('equal'); ax.axis('off')
ax.set_title(title, color=cring, fontsize=10, fontweight='bold', pad=6)
# EAC ring
outer = Circle((0, 0), 1.25, fill=False, edgecolor=cring, lw=4)
ax.add_patch(outer)
# Hair-like dots in canal wall
for ang in np.linspace(0, 2*np.pi, 20):
bx, by = 1.15*np.cos(ang), 1.15*np.sin(ang)
ax.plot(bx, by, 'o', color=cring, markersize=1.5, alpha=0.5)
if idx == 0:
# Normal β pearly grey, intact, light reflex
tm = Circle((0, 0), 1.0, facecolor=ctm, edgecolor="#AA8855", lw=1.5, alpha=0.85)
ax.add_patch(tm)
# Malleus handle
ax.plot([0.0, 0.0], [0.15, 0.65], color='#D4AA70', lw=3, solid_capstyle='round')
ax.plot([0.0, -0.1], [0.65, 0.75], color='#D4AA70', lw=2)
ax.text(0.15, 0.45, "Malleus\nhandle", color='#FFD700', fontsize=6)
# Light reflex (cone of light β anterior inferior)
light = Wedge((0, 0), 0.35, 230, 300, facecolor='#FFFAAA', alpha=0.55)
ax.add_patch(light)
ax.text(-0.45, -0.45, "Light\nreflex", color='#FFFF88', fontsize=6.5)
# Umbo
ax.plot(0, 0.12, 'o', color='#AA7733', markersize=5)
ax.text(0.12, 0.08, "Umbo", color=LGREY, fontsize=6)
ax.text(0, -1.1, "Pearly grey β’ Cone of light present", ha='center',
color=GREEN, fontsize=7)
elif idx == 1:
# ASOM β red, bulging
tm = Circle((0, 0), 1.0, facecolor=ctm, edgecolor=RED, lw=2, alpha=0.9)
ax.add_patch(tm)
# Bulge indicator
for r2 in [0.3, 0.5, 0.7]:
bulge = Circle((0, 0), r2, fill=False, edgecolor=RED, lw=0.8, alpha=0.5)
ax.add_patch(bulge)
ax.text(0, 0.0, "BULGING", ha='center', color=WHITE, fontsize=9, fontweight='bold')
ax.plot([0.0, 0.0], [0.15, 0.55], color='#AA4444', lw=3)
ax.text(0, -1.1, "Red, congested, bulging β’ No light reflex", ha='center',
color=RED, fontsize=7)
else:
# CSOM β central perforation
tm = Circle((0, 0), 1.0, facecolor=ctm, edgecolor=ORANGE, lw=1.5, alpha=0.75)
ax.add_patch(tm)
# Central perforation
perf = Circle((0.05, -0.1), 0.32, facecolor='#050505', edgecolor=RED, lw=2)
ax.add_patch(perf)
ax.text(0.05, -0.1, "PERFORATION\n(Central)", ha='center', color=RED,
fontsize=7, fontweight='bold')
ax.plot([0.0, 0.0], [0.25, 0.65], color='#AA7733', lw=3)
ax.text(0, -1.1, "Central perforation β’ SAFE type CSOM", ha='center',
color=ORANGE, fontsize=7)
plt.tight_layout()
return save_fig(fig, "02_tympanic_membrane")
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# DIAGRAM 3 β ASOM Stages flowchart
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def diag_asom_stages():
fig, ax = plt.subplots(figsize=(13, 5.5), facecolor=BG)
ax.set_facecolor(BG); ax.axis('off')
ax.set_xlim(0, 13); ax.set_ylim(0, 5.5)
ax.set_title("ASOM β Stages of Disease Progression", color=GOLD,
fontsize=14, fontweight='bold')
stages = [
("Stage 1\nHYPERAEMIA", "β’ Blood vessels dilate\nβ’ TM: red, injected\nβ’ Mild otalgia\nβ’ Conductive\n deafness starts", "#8B0000", RED),
("Stage 2\nEXUDATION", "β’ Fluid exudate\n in middle ear\nβ’ TM: pink, dull\nβ’ β otalgia\nβ’ Fever rises", "#7B3F00", ORANGE),
("Stage 3\nSUPPURATION", "β’ Pus forms\nβ’ TM: yellow,\n bulging\nβ’ Severe otalgia\nβ’ High fever\nβ’ Vomiting", "#5B3A00", GOLD),
("Stage 4\nRESOLUTION\nor PERFORATION", "β’ TM perforates\nβ’ Pus drains\nβ’ β Pain (relief)\nβ’ Discharge\nβ’ Fever settles", "#1A5000", GREEN),
("Stage 5\nCOMPLICATION\n(if untreated)", "β’ Mastoiditis\nβ’ Intracranial\n spread\nβ’ Meningitis\nβ’ Brain abscess\nβ’ Facial palsy", "#3D0050", VIOLET),
]
box_w, box_h = 2.2, 4.2
gap = 0.4
for i, (title, body, bg_hex, col) in enumerate(stages):
x0 = 0.3 + i * (box_w + gap)
box = FancyBboxPatch((x0, 0.4), box_w, box_h,
boxstyle="round,pad=0.12", lw=2,
edgecolor=col, facecolor=bg_hex)
ax.add_patch(box)
ax.text(x0 + box_w/2, 0.4 + box_h - 0.25, title, ha='center', va='top',
color=col, fontsize=9, fontweight='bold')
ax.text(x0 + box_w/2, 0.4 + box_h - 0.95, body, ha='center', va='top',
color=WHITE, fontsize=8, linespacing=1.4)
# Arrow to next box
if i < len(stages) - 1:
ax_x = x0 + box_w + 0.02
ax.annotate('', xy=(ax_x + gap - 0.02, 2.5), xytext=(ax_x, 2.5),
arrowprops=dict(arrowstyle='->', color=GOLD, lw=2.5))
# Treatment bar at bottom
ax.text(6.5, 0.18, "Rx: Antibiotics (Stage 1β3) | Myringotomy if bulging (Stage 3) | Homoeopathic: Belladonna β’ Hepar sulph β’ Pulsatilla β’ Chamomilla",
ha='center', color=GOLD, fontsize=8.5, fontweight='bold')
plt.tight_layout()
return save_fig(fig, "03_asom_stages")
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# DIAGRAM 4 β CSOM Safe vs Unsafe
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def diag_csom_types():
fig, axes = plt.subplots(1, 2, figsize=(11, 5.5), facecolor=BG)
fig.suptitle("CSOM β Safe (Tubotympanic) vs Unsafe (Atticoantral)", color=GOLD,
fontsize=13, fontweight='bold')
for ax in axes:
ax.set_facecolor(BG); ax.axis('off')
ax.set_xlim(0, 5.5); ax.set_ylim(0, 5.5)
# LEFT: SAFE
ax = axes[0]
ax.set_title("β
SAFE TYPE (Mucosal)", color=GREEN, fontsize=12, fontweight='bold')
ax.add_patch(Circle((2.75, 3.2), 1.8, fill=True, facecolor="#0A2008", edgecolor=GREEN, lw=2.5))
ax.add_patch(Circle((2.75, 2.85), 0.55, fill=True, facecolor="#050505", edgecolor=GREEN, lw=2))
ax.text(2.75, 2.85, "Central\nPerforation", ha='center', va='center', color=GREEN, fontsize=8, fontweight='bold')
ax.text(2.75, 4.65, "TM intact at edges", ha='center', color=GREEN, fontsize=8)
rows = [
("Perforation", "Central", GREEN),
("Discharge", "Mucoid, odourless", GREEN),
("Cholesteatoma", "ABSENT", GREEN),
("Prognosis", "GOOD (safe)", GREEN),
("Treatment", "Tympanoplasty", GREEN),
]
for i, (k, v, c) in enumerate(rows):
y = 2.0 - i * 0.38
ax.text(0.2, y, f"β’ {k}:", color=LGREY, fontsize=8, fontweight='bold')
ax.text(2.0, y, v, color=c, fontsize=8)
# RIGHT: UNSAFE
ax = axes[1]
ax.set_title("β UNSAFE TYPE (Squamosal)", color=RED, fontsize=12, fontweight='bold')
ax.add_patch(Circle((2.75, 3.2), 1.8, fill=True, facecolor="#200808", edgecolor=RED, lw=2.5))
# Marginal / attic perforation
attic_perf = Wedge((2.75, 3.2), 1.8, 60, 100, facecolor='#050505', edgecolor=RED, lw=2)
ax.add_patch(attic_perf)
ax.text(3.1, 4.7, "Attic / Marginal\nPerforation", ha='center', color=RED, fontsize=7.5, fontweight='bold')
# Cholesteatoma pearl
chol = Ellipse((2.2, 3.5), 0.7, 0.5, fill=True, facecolor='#EEEECC', edgecolor=WHITE, lw=1.5, alpha=0.9)
ax.add_patch(chol)
ax.text(2.2, 3.5, "Chol.", ha='center', va='center', color="#333300", fontsize=7, fontweight='bold')
ax.text(1.2, 4.1, "Cholesteatoma\n(pearly white mass)", ha='center', color=GOLD, fontsize=7.5)
rows2 = [
("Perforation", "Marginal / Attic", RED),
("Discharge", "Foul-smelling, purulent", RED),
("Cholesteatoma", "PRESENT", RED),
("Prognosis", "POOR β can erode bone", RED),
("Treatment", "Mastoidectomy (surgery)", RED),
]
for i, (k, v, c) in enumerate(rows2):
y = 2.0 - i * 0.38
ax.text(0.2, y, f"β’ {k}:", color=LGREY, fontsize=8, fontweight='bold')
ax.text(2.0, y, v, color=c, fontsize=8)
plt.tight_layout()
return save_fig(fig, "04_csom_types")
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# DIAGRAM 5 β Pure Tone Audiogram (Conductive vs SNHL)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def diag_audiogram():
fig, axes = plt.subplots(1, 2, figsize=(11, 5.5), facecolor=BG)
fig.suptitle("AUDIOGRAM β Conductive vs Sensorineural Hearing Loss", color=GOLD,
fontsize=13, fontweight='bold')
freqs = [250, 500, 1000, 2000, 4000, 8000]
freq_labels = ["250", "500", "1k", "2k", "4k", "8k"]
x_pos = list(range(len(freqs)))
configs = [
("CONDUCTIVE HEARING LOSS", CYAN,
[15, 15, 15, 15, 15, 15], # Normal bone
[45, 50, 50, 50, 45, 45], # Elevated air
"Air-Bone Gap present\nBone conduction NORMAL\nAir conduction ELEVATED\nRinne: βve (BC > AC)\nWeber: Lateralises to WORSE ear"),
("SENSORINEURAL HEARING LOSS", RED,
[50, 55, 60, 65, 70, 75], # Elevated bone (same as air ~)
[52, 58, 62, 67, 72, 77], # Elevated air (parallel)
"No Air-Bone Gap\nBoth air & bone elevated\nHigh-frequency loss (4kβ8k first)\nRinne: +ve (AC > BC)\nWeber: Lateralises to BETTER ear"),
]
for ax, (title, col, bone_thresh, air_thresh, notes) in zip(axes, configs):
ax.set_facecolor("#0A0A1A")
ax.set_xlim(-0.5, 5.5); ax.set_ylim(110, -10)
ax.set_xticks(x_pos); ax.set_xticklabels(freq_labels, color=WHITE, fontsize=9)
ax.set_yticks(range(0, 121, 20))
ax.set_yticklabels([str(y) for y in range(0, 121, 20)], color=WHITE, fontsize=9)
ax.set_xlabel("Frequency (Hz)", color=LGREY, fontsize=9)
ax.set_ylabel("Hearing Level (dB HL)", color=LGREY, fontsize=9)
ax.set_title(title, color=col, fontsize=11, fontweight='bold')
ax.tick_params(colors=WHITE)
for spine in ax.spines.values():
spine.set_edgecolor("#334455")
ax.grid(True, color="#223344", alpha=0.5, lw=0.5)
# Shaded hearing zones
ax.axhspan(-10, 25, alpha=0.08, color=GREEN, label='Normal')
ax.axhspan(25, 40, alpha=0.08, color=GOLD)
ax.axhspan(40, 70, alpha=0.08, color=ORANGE)
ax.axhspan(70, 110, alpha=0.08, color=RED)
# Zone labels
for y_mid, lbl, c2 in [(-5, "Normal (<25 dB)", GREEN),
(32, "Mild (25-40)", GOLD),
(55, "Moderate (40-70)", ORANGE),
(90, "Severe/Profound (>70)", RED)]:
ax.text(-0.4, y_mid, lbl, color=c2, fontsize=6.5, alpha=0.8)
# Air conduction: circle O (right ear)
ax.plot(x_pos, air_thresh, 'o-', color=col, lw=2.5, markersize=10,
markerfacecolor=col, markeredgecolor=WHITE, label='Air (O)')
# Bone conduction: [ bracket symbol
ax.plot(x_pos, bone_thresh, 's--', color=ORANGE, lw=2, markersize=8,
markerfacecolor=ORANGE, markeredgecolor=WHITE, label='Bone ([)')
# Air-bone gap fill for conductive
if "CONDUCTIVE" in title:
ax.fill_between(x_pos, bone_thresh, air_thresh, alpha=0.25, color=CYAN, label='A-B Gap')
ax.text(2.5, 32, "AIR-BONE\nGAP", ha='center', color=CYAN, fontsize=9,
fontweight='bold', alpha=0.9)
ax.legend(loc='lower right', facecolor=BG, labelcolor=WHITE, fontsize=8, edgecolor=LGREY)
# Notes text box
ax.text(5.6, 55, notes, ha='left', va='center', color=WHITE, fontsize=7.5,
bbox=dict(boxstyle='round,pad=0.4', facecolor='#0A1A2A', edgecolor=col, lw=1.5),
transform=ax.transData, clip_on=False)
plt.tight_layout()
return save_fig(fig, "05_audiogram")
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# DIAGRAM 6 β Tuning Fork Tests
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def diag_tuning_fork():
fig, ax = plt.subplots(figsize=(13, 5.5), facecolor=BG)
ax.set_facecolor(BG); ax.axis('off')
ax.set_xlim(0, 13); ax.set_ylim(0, 5.5)
ax.set_title("TUNING FORK TESTS β Rinne's & Weber's", color=GOLD,
fontsize=14, fontweight='bold')
# Tuning fork shape (stylised)
def draw_fork(ax, cx, cy, col, size=0.6):
# Handle
ax.plot([cx, cx], [cy, cy + size*1.2], color=col, lw=3, solid_capstyle='round')
# Tines
for dx in [-0.15*size, 0.15*size]:
ax.plot([cx + dx, cx + dx], [cy + size*0.9, cy + size*1.6], color=col, lw=2.5)
tip = Ellipse((cx + dx, cy + size*1.6), 0.08*size*2, 0.12*size*2,
fill=True, facecolor=col, edgecolor=col)
ax.add_patch(tip)
# ββ RINNE'S TEST ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ax.add_patch(FancyBboxPatch((0.2, 0.3), 5.8, 4.9, boxstyle='round,pad=0.1',
lw=1.5, edgecolor=CYAN, facecolor="#0A1020"))
ax.text(3.1, 5.05, "RINNE'S TEST", ha='center', color=CYAN, fontsize=12, fontweight='bold')
ax.text(3.1, 4.7, "(512 Hz fork: bone β mastoid, then air near ear)", ha='center', color=LGREY, fontsize=8)
# Rinne Positive
ax.add_patch(FancyBboxPatch((0.35, 0.45), 2.5, 3.9, boxstyle='round,pad=0.08',
lw=1, edgecolor=GREEN, facecolor="#0A1808"))
ax.text(1.6, 4.2, "RINNE +ve", ha='center', color=GREEN, fontsize=10, fontweight='bold')
ax.text(1.6, 3.9, "AC > BC", ha='center', color=GREEN, fontsize=9)
draw_fork(ax, 1.6, 1.9, GREEN, 0.8)
ax.text(1.6, 1.5, "Air > Bone", ha='center', color=GREEN, fontsize=8.5)
ax.text(1.6, 1.1, "= NORMAL or SNHL", ha='center', color=WHITE, fontsize=8)
ax.text(1.6, 0.7, "(cochlea/nerve damaged)", ha='center', color=LGREY, fontsize=7)
# Rinne Negative
ax.add_patch(FancyBboxPatch((3.15, 0.45), 2.6, 3.9, boxstyle='round,pad=0.08',
lw=1, edgecolor=RED, facecolor="#200808"))
ax.text(4.45, 4.2, "RINNE βve", ha='center', color=RED, fontsize=10, fontweight='bold')
ax.text(4.45, 3.9, "BC > AC", ha='center', color=RED, fontsize=9)
draw_fork(ax, 4.45, 1.9, RED, 0.8)
ax.text(4.45, 1.5, "Bone > Air", ha='center', color=RED, fontsize=8.5)
ax.text(4.45, 1.1, "= CONDUCTIVE HL", ha='center', color=WHITE, fontsize=8)
ax.text(4.45, 0.7, "(β₯25 dB loss)", ha='center', color=LGREY, fontsize=7)
# ββ WEBER'S TEST βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ax.add_patch(FancyBboxPatch((6.4, 0.3), 6.3, 4.9, boxstyle='round,pad=0.1',
lw=1.5, edgecolor=VIOLET, facecolor="#0A0820"))
ax.text(9.55, 5.05, "WEBER'S TEST", ha='center', color=VIOLET, fontsize=12, fontweight='bold')
ax.text(9.55, 4.7, "(Fork on vertex/forehead β where does sound lateralise?)", ha='center', color=LGREY, fontsize=8)
webers = [
(6.55, "NORMAL /\nBilateral SNHL", "Midline\n(central)", GREEN, "#0A1808"),
(8.75, "CONDUCTIVE\nHL", "Lateralises\nto WORSE ear", CYAN, "#0A1020"),
(10.95, "Unilateral\nSNHL", "Lateralises\nto BETTER ear", RED, "#200808"),
]
for x0, title, result, col, bgc in webers:
ax.add_patch(FancyBboxPatch((x0, 0.45), 2.05, 3.9, boxstyle='round,pad=0.08',
lw=1, edgecolor=col, facecolor=bgc))
ax.text(x0+1.025, 4.2, title, ha='center', color=col, fontsize=8.5, fontweight='bold')
draw_fork(ax, x0+1.025, 2.6, col, 0.6)
# Head outline
head = Circle((x0+1.025, 1.85), 0.4, fill=True, facecolor="#2A1A0A", edgecolor=col, lw=1.5)
ax.add_patch(head)
ax.text(x0+1.025, 1.85, "π", ha='center', va='center', fontsize=10)
ax.text(x0+1.025, 1.2, result, ha='center', color=WHITE, fontsize=8, fontweight='bold')
ax.text(x0+1.025, 0.65, col, ha='center', color=col, fontsize=7, alpha=0) # spacer
plt.tight_layout()
return save_fig(fig, "06_tuning_fork")
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# DIAGRAM 7 β Vertigo: Central vs Peripheral comparison
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def diag_vertigo():
fig, ax = plt.subplots(figsize=(13, 6), facecolor=BG)
ax.set_facecolor(BG); ax.axis('off')
ax.set_xlim(0, 13); ax.set_ylim(0, 6)
ax.set_title("VERTIGO β Peripheral vs Central: Comparison & Causes", color=GOLD,
fontsize=14, fontweight='bold')
# Central divider
ax.axvline(6.5, color=GOLD, lw=2, alpha=0.4)
ax.text(0.3, 5.7, "PERIPHERAL VERTIGO", color=GREEN, fontsize=12, fontweight='bold')
ax.text(6.8, 5.7, "CENTRAL VERTIGO", color=RED, fontsize=12, fontweight='bold')
left_rows = [
("Origin", "Inner ear / Vestibular nerve", GREEN),
("Onset", "Sudden, episodic", GREEN),
("Severity", "Intense +++ (esp. BPPV)", GREEN),
("Duration", "Seconds to minutes (BPPV)\nDays to weeks (Labyrinthitis)", GREEN),
("Nausea/Vomiting", "Severe +++", GREEN),
("Nystagmus", "Horizontal, fatiguable,\ndirection-fixed", CYAN),
("Hearing Loss / Tinnitus", "Often present (Meniere's, Labyrinthitis)", CYAN),
("Neurological signs", "ABSENT", GREEN),
("Dix-Hallpike Test", "+ve (BPPV)", GOLD),
("Causes", "BPPV β’ Meniere's Disease\nVestibular neuritis β’ Labyrinthitis\nAcoustic neuroma (late)", GREEN),
]
right_rows = [
("Origin", "Brainstem / Cerebellum", RED),
("Onset", "Gradual, constant", RED),
("Severity", "Moderate, persistent", RED),
("Duration", "Continuous (hours to weeks)", RED),
("Nausea/Vomiting", "Mild", RED),
("Nystagmus", "Vertical / direction-changing,\nnon-fatiguable", VIOLET),
("Hearing Loss / Tinnitus", "ABSENT", RED),
("Neurological signs", "PRESENT (diplopia, dysarthria,\nweakness, ataxia)", VIOLET),
("MRI", "Posterior fossa lesion", GOLD),
("Causes", "VBI β’ Cerebellar stroke\nMS β’ Posterior fossa tumour\nWernicke's encephalopathy", RED),
]
for i, (feat, val, col) in enumerate(left_rows):
y = 5.25 - i * 0.49
ax.text(0.3, y, f"βΆ {feat}:", color=LGREY, fontsize=8, fontweight='bold')
ax.text(2.2, y, val, color=col, fontsize=8)
for i, (feat, val, col) in enumerate(right_rows):
y = 5.25 - i * 0.49
ax.text(6.8, y, f"βΆ {feat}:", color=LGREY, fontsize=8, fontweight='bold')
ax.text(8.7, y, val, color=col, fontsize=8)
# Inner ear schematic (semicircular canals) β tiny diagram
ax.text(12.5, 3.0, "BPPV:\nOtoconia\nenter\nposterior\nSCC", ha='center',
color=CYAN, fontsize=7.5,
bbox=dict(boxstyle='round,pad=0.4', facecolor='#0A1A0A', edgecolor=CYAN, lw=1))
plt.tight_layout()
return save_fig(fig, "07_vertigo")
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# DIAGRAM 8 β CN VII Course & Bell's Palsy
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def diag_facial_nerve():
fig, ax = plt.subplots(figsize=(13, 6.5), facecolor=BG)
ax.set_facecolor(BG); ax.axis('off')
ax.set_xlim(0, 13); ax.set_ylim(0, 6.5)
ax.set_title("CN VII (Facial Nerve) β Course, UMN vs LMN & Bell's Palsy", color=GOLD,
fontsize=14, fontweight='bold')
# ββ Nerve path from motor cortex down ββββββββββββββββββββββββββββββββββββ
waypoints = [
(2.0, 6.2, "Motor Cortex\n(bilateral for forehead)", LGREY),
(2.0, 5.3, "Internal Capsule", LGREY),
(2.0, 4.5, "Pons\n(Facial Nucleus)", CYAN),
(2.0, 3.7, "CPA\n(Cerebellopontine Angle)", CYAN),
(2.0, 2.9, "IAM\n(Internal Auditory Meatus)", CYAN),
(2.0, 2.1, "Geniculate Ganglion\nβ Greater Petrosal N.\nβ Chorda Tympani", VIOLET),
(2.0, 1.1, "Stylomastoid\nForamen", ORANGE),
(2.0, 0.35, "Parotid Gland\n(Terminal Branches)", GOLD),
]
for i, (x, y, lbl, col) in enumerate(waypoints):
ax.add_patch(FancyBboxPatch((x - 1.3, y - 0.28), 2.6, 0.52,
boxstyle='round,pad=0.05', lw=1.5,
edgecolor=col, facecolor=BG))
ax.text(x, y, lbl, ha='center', va='center', color=col, fontsize=7.5, fontweight='bold')
if i < len(waypoints) - 1:
ax.annotate('', xy=(x, waypoints[i+1][1] + 0.27),
xytext=(x, y - 0.28),
arrowprops=dict(arrowstyle='->', color=GOLD, lw=1.8))
# Terminal branches
branches = [("Temporal", 4.0, 0.7, VIOLET),
("Zygomatic", 5.2, 0.4, VIOLET),
("Buccal", 6.4, 0.7, VIOLET),
("Marg. Mand.", 7.4, 0.4, VIOLET),
("Cervical", 8.3, 0.7, VIOLET)]
for lbl, bx, by, bc in branches:
ax.annotate('', xy=(bx, by + 0.15), xytext=(2.7, 0.32),
arrowprops=dict(arrowstyle='->', color=VIOLET, lw=1.2, connectionstyle='arc3,rad=0.2'))
ax.text(bx, by, lbl, ha='center', color=bc, fontsize=7.5,
bbox=dict(boxstyle='round,pad=0.2', facecolor='#1A0A28', edgecolor=VIOLET, lw=0.8))
# ββ UMN vs LMN side panel βββββββββββββββββββββββββββββββββββββββββββββββββ
ax.add_patch(FancyBboxPatch((4.0, 2.5), 4.0, 3.7, boxstyle='round,pad=0.1',
lw=1.5, edgecolor=CYAN, facecolor="#050D15"))
ax.text(6.0, 6.05, "UMN vs LMN FACIAL PALSY", ha='center', color=CYAN,
fontsize=11, fontweight='bold')
umns = [("UMN (above nucleus)", CYAN,
"β’ Forehead SPARED\n (bilateral cortical supply)\nβ’ Lower face affected\nβ’ Causes: Stroke, tumour\nβ’ Wrinkle forehead β YES\nβ’ Close eye β YES"),
("LMN (nucleus or below)", RED,
"β’ Forehead INVOLVED\n (all branches affected)\nβ’ Entire half of face\nβ’ Causes: Bell's, Ramsay Hunt,\n Parotid tumour, Trauma\nβ’ Wrinkle forehead β NO\nβ’ Close eye β NO")]
for i, (title, col, body) in enumerate(umns):
x0 = 4.15 + i * 2.0
ax.add_patch(FancyBboxPatch((x0, 2.65), 1.8, 3.25, boxstyle='round,pad=0.05',
lw=1, edgecolor=col, facecolor=BG))
ax.text(x0 + 0.9, 5.78, title, ha='center', color=col, fontsize=8, fontweight='bold')
ax.text(x0 + 0.9, 5.45, body, ha='center', va='top', color=WHITE, fontsize=7.5, linespacing=1.4)
# ββ Bell's Palsy details βββββββββββββββββββββββββββββββββββββββββββββββββ
ax.add_patch(FancyBboxPatch((8.4, 0.25), 4.4, 6.0, boxstyle='round,pad=0.1',
lw=1.5, edgecolor=ORANGE, facecolor="#150800"))
ax.text(10.6, 6.1, "BELL'S PALSY", ha='center', color=ORANGE, fontsize=12, fontweight='bold')
bells_data = [
("Aetiology", "HSV-1 reactivation\nβ oedema of nerve in bony canal"),
("Type", "LMN (forehead INVOLVED)"),
("Features", "Sudden unilateral palsy\nFacial droop, Lagophthalmos\nBell's phenomenon (eye rolls up)\nHyperacusis (stapedius affected)\nTaste loss (ant 2/3 tongue)\nLacrimation β"),
("Grading", "House-Brackmann:\nI (normal) β VI (complete)"),
("Ix", "Clinical diagnosis\nMRI if atypical"),
("Treatment", "Prednisolone within 72h\nAcyclovir (if severe/HSV)\nEye drops / patch (cornea care)\nβ 80% full recovery"),
("Homoeopathic", "Causticum β’ Aconite\nGelsemium β’ Dulcamara\nCadmium sulph"),
]
y_pos = 5.65
for k, v in bells_data:
ax.text(8.6, y_pos, f"βΆ {k}:", color=ORANGE, fontsize=8, fontweight='bold')
ax.text(8.6, y_pos - 0.28, v, color=WHITE, fontsize=7.5, linespacing=1.3)
lines = v.count('\n') + 1
y_pos -= 0.25 + 0.22 * lines
plt.tight_layout()
return save_fig(fig, "08_facial_nerve")
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# DIAGRAM 9 β Deafness types + Tympanograms
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def diag_tympanogram():
fig, axes = plt.subplots(1, 3, figsize=(12, 5), facecolor=BG)
fig.suptitle("TYMPANOGRAMS β Types A, B, C (Middle Ear Pressure Curves)", color=GOLD,
fontsize=12, fontweight='bold')
configs = [
("Type A β NORMAL", GREEN,
np.linspace(-200, 200, 200),
lambda p: 1.2 * np.exp(-0.5 * (p/50)**2),
"Peak at 0 daPa\nNormal middle ear pressure\nNormal compliance\nβ Normal / SNHL"),
("Type B β FLAT", CYAN,
np.linspace(-200, 200, 200),
lambda p: 0.15 + 0*p,
"No peak (flat curve)\nFluid in middle ear\nβ Serous OM (Glue Ear)\nβ TM perforation"),
("Type C β NEG PRESSURE", ORANGE,
np.linspace(-400, 200, 200),
lambda p: 0.9 * np.exp(-0.5 * ((p+150)/60)**2),
"Peak shifted left (<-100)\nNeg. middle ear pressure\nET dysfunction\nβ Eustachian tube catarrh"),
]
for ax, (title, col, pressures, compliance_fn, notes) in zip(axes, configs):
ax.set_facecolor("#070720")
comp = compliance_fn(pressures)
ax.plot(pressures, comp, color=col, lw=3)
ax.fill_between(pressures, comp, alpha=0.15, color=col)
ax.axvline(0, color=LGREY, lw=1, linestyle='--', alpha=0.4)
ax.axhline(0, color=LGREY, lw=0.5, alpha=0.3)
ax.set_xlabel("Pressure (daPa)", color=LGREY, fontsize=8)
ax.set_ylabel("Compliance (mL)", color=LGREY, fontsize=8)
ax.set_title(title, color=col, fontsize=10, fontweight='bold')
ax.tick_params(colors=WHITE, labelsize=7)
for spine in ax.spines.values():
spine.set_edgecolor("#334455")
ax.text(0.05, 0.95, notes, transform=ax.transAxes, va='top', ha='left',
color=WHITE, fontsize=7.5, linespacing=1.4,
bbox=dict(boxstyle='round,pad=0.3', facecolor=BG, edgecolor=col, lw=1, alpha=0.85))
plt.tight_layout()
return save_fig(fig, "09_tympanogram")
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# BUILD ALL DIAGRAMS
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
print("Building diagrams...")
paths = {
"ear_anatomy": diag_ear_anatomy(),
"tm_views": diag_tympanic_membrane(),
"asom_stages": diag_asom_stages(),
"csom_types": diag_csom_types(),
"audiogram": diag_audiogram(),
"tuning_fork": diag_tuning_fork(),
"vertigo": diag_vertigo(),
"facial_nerve": diag_facial_nerve(),
"tympanogram": diag_tympanogram(),
}
for k, v in paths.items():
print(f" β {k}: {v}")
print("All diagrams done.")
~/ear-notes/assemble_pdf.py
"""
PDF assembler β combines text notes + diagrams into a full colour PDF
Uses reportlab for layout
"""
from reportlab.lib.pagesizes import A4, landscape
from reportlab.lib.units import cm, mm
from reportlab.lib.colors import (HexColor, white, black)
from reportlab.platypus import (SimpleDocTemplate, Paragraph, Spacer,
Image, Table, TableStyle, PageBreak,
HRFlowable, KeepTogether)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_RIGHT
from reportlab.platypus.flowables import Flowable
import os
OUT_PDF = "/tmp/workspace/ear-notes/EAR_Surgery_Comprehensive_Notes.pdf"
DIAG_DIR = "/tmp/workspace/ear-notes/diagrams"
# ββ colour palette ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
BG = HexColor("#0D1B2A")
GOLD = HexColor("#FFD700")
CYAN = HexColor("#00E5FF")
RED = HexColor("#FF6B6B")
GREEN = HexColor("#7BFF6B")
ORANGE = HexColor("#FFA500")
VIOLET = HexColor("#DA70D6")
WHITE_C = HexColor("#FFFFFF")
LGREY = HexColor("#AAAAAA")
DBLUE = HexColor("#1A3A5C")
DPURP = HexColor("#2D1B3D")
DGREEN = HexColor("#1A3D2D")
DORNG = HexColor("#3D2A1A")
DARKROW = HexColor("#0A1828")
ALTROW = HexColor("#101C2C")
W, H = landscape(A4) # 841.89 Γ 595.28 pt (landscape)
# ββ styles ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
styles = getSampleStyleSheet()
def S(name, parent='Normal', **kw):
return ParagraphStyle(name, parent=styles[parent], **kw)
sTitle = S('sTitle', fontSize=24, leading=30, textColor=GOLD,
alignment=TA_CENTER, fontName='Helvetica-Bold', spaceAfter=6)
sSubtitle = S('sSubtitle',fontSize=13, leading=18, textColor=LGREY,
alignment=TA_CENTER, fontName='Helvetica')
sH1 = S('sH1', fontSize=15, leading=20, textColor=CYAN,
fontName='Helvetica-Bold', spaceBefore=10, spaceAfter=4,
backColor=DBLUE, leftPadding=6)
sH2 = S('sH2', fontSize=12, leading=16, textColor=GOLD,
fontName='Helvetica-Bold', spaceBefore=6, spaceAfter=2)
sH3 = S('sH3', fontSize=10.5, leading=14, textColor=VIOLET,
fontName='Helvetica-Bold', spaceBefore=4)
sBody = S('sBody', fontSize=9.5, leading=13, textColor=WHITE_C,
fontName='Helvetica')
sBodyCyan = S('sBodyCyan', fontSize=9.5, leading=13, textColor=CYAN, fontName='Helvetica')
sBodyGreen = S('sBodyGreen', fontSize=9.5, leading=13, textColor=GREEN, fontName='Helvetica')
sBodyRed = S('sBodyRed', fontSize=9.5, leading=13, textColor=RED, fontName='Helvetica')
sBodyOrange = S('sBodyOrange',fontSize=9.5, leading=13, textColor=ORANGE, fontName='Helvetica')
sBodyGold = S('sBodyGold', fontSize=9.5, leading=13, textColor=GOLD, fontName='Helvetica')
sNote = S('sNote', fontSize=8.5, leading=12, textColor=LGREY, fontName='Helvetica-Oblique')
sCap = S('sCap', fontSize=8, leading=10, textColor=LGREY,
alignment=TA_CENTER, fontName='Helvetica-Oblique', spaceAfter=4)
sHom = S('sHom', fontSize=9, leading=12, textColor=GREEN,
fontName='Helvetica-Bold', backColor=DGREEN, leftPadding=6, spaceAfter=6)
def img(fname, width=None, height=None):
p = f"{DIAG_DIR}/{fname}.png"
if not os.path.exists(p):
return Spacer(1, 0.5*cm)
return Image(p, width=width, height=height, kind='proportional' if width and not height else 'direct')
def hr(col=GOLD):
return HRFlowable(width="100%", thickness=1, color=col, spaceAfter=4, spaceBefore=4)
def cap(text):
return Paragraph(f"<i>{text}</i>", sCap)
def h1(text): return Paragraph(f"β {text}", sH1)
def h2(text): return Paragraph(f"β {text}", sH2)
def h3(text): return Paragraph(text, sH3)
def body(text, style=sBody): return Paragraph(text, style)
def bullet(text, col=WHITE_C):
st = S('_b', fontSize=9.5, leading=13, textColor=col, leftIndent=12,
fontName='Helvetica', bulletIndent=2)
return Paragraph(f"β’ {text}", st)
def arrow_bullet(text, col=WHITE_C):
st = S('_ab', fontSize=9.5, leading=13, textColor=col, leftIndent=16,
fontName='Helvetica')
return Paragraph(f"β {text}", st)
def hom_line(remedies):
return Paragraph(f"π’ Homoeopathic Remedies: {remedies}", sHom)
def section_header(title, subtitle, col):
c = HexColor(col)
return Table([[Paragraph(f"<b>{title}</b>", ParagraphStyle('sh', fontSize=18, leading=24,
textColor=c, fontName='Helvetica-Bold')),
Paragraph(subtitle, ParagraphStyle('ss', fontSize=10, leading=14,
textColor=LGREY, fontName='Helvetica'))]],
colWidths=[W*0.55, W*0.40],
style=TableStyle([
('BACKGROUND', (0,0), (-1,-1), DBLUE),
('LINEBELOW', (0,0), (-1,-1), 1, c),
('TOPPADDING', (0,0), (-1,-1), 6),
('BOTTOMPADDING', (0,0), (-1,-1), 6),
('LEFTPADDING', (0,0), (0,-1), 8),
]))
def two_col(left_items, right_items, lw=0.48, rw=0.48):
"""Two-column layout using a table"""
from reportlab.platypus import ListFlowable
def pack(items):
return [i if hasattr(i, 'wrap') else Paragraph(str(i), sBody) for i in items]
row = [[pack(left_items), pack(right_items)]]
tbl = Table(row, colWidths=[W*lw, W*rw])
tbl.setStyle(TableStyle([
('VALIGN', (0,0), (-1,-1), 'TOP'),
('LEFTPADDING', (0,0), (-1,-1), 4),
('RIGHTPADDING',(0,0), (-1,-1), 4),
]))
return tbl
def info_table(headers, rows, col_colors=None):
"""Colour-formatted table"""
n_cols = len(headers)
header_row = [Paragraph(f"<b>{h}</b>",
ParagraphStyle('th', fontSize=9, textColor=GOLD,
fontName='Helvetica-Bold')) for h in headers]
data = [header_row]
for r_idx, row in enumerate(rows):
bg = DARKROW if r_idx % 2 == 0 else ALTROW
data_row = []
for c_idx, cell in enumerate(row):
col = (col_colors[c_idx] if col_colors else WHITE_C)
data_row.append(Paragraph(cell,
ParagraphStyle(f'td{r_idx}{c_idx}', fontSize=8.5,
textColor=col, fontName='Helvetica')))
data.append(data_row)
col_w = (W - 2*cm) / n_cols
tbl = Table(data, colWidths=[col_w]*n_cols, repeatRows=1)
tbl.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), DBLUE),
('ROWBACKGROUNDS',(0,1), (-1,-1), [DARKROW, ALTROW]),
('GRID', (0,0), (-1,-1), 0.4, HexColor("#223344")),
('TOPPADDING', (0,0), (-1,-1), 4),
('BOTTOMPADDING', (0,0), (-1,-1), 4),
('LEFTPADDING', (0,0), (-1,-1), 5),
('VALIGN', (0,0), (-1,-1), 'TOP'),
]))
return tbl
# ββ background canvas βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def on_page(canvas, doc):
canvas.saveState()
canvas.setFillColor(BG)
canvas.rect(0, 0, W, H, fill=1, stroke=0)
# thin gold border
canvas.setStrokeColor(GOLD)
canvas.setLineWidth(1.5)
canvas.rect(6, 6, W-12, H-12, fill=0, stroke=1)
# footer
canvas.setFont('Helvetica', 7)
canvas.setFillColor(LGREY)
canvas.drawCentredString(W/2, 10, f"EAR Surgery Notes β’ Hom UG-Sur-II Unit 7 β’ Page {doc.page}")
canvas.restoreState()
# ββ build story βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
story = []
SP = lambda h=0.3: Spacer(1, h*cm)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# COVER PAGE
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
story += [
SP(3),
Paragraph("π EAR", ParagraphStyle('cv1', fontSize=56, leading=64, textColor=GOLD,
alignment=TA_CENTER, fontName='Helvetica-Bold')),
SP(0.4),
Paragraph("Surgery Notes β Hom UG-Sur-II β’ Unit 7", sSubtitle),
SP(0.6),
Paragraph("Comprehensive Schematic Notes with Diagrams", sSubtitle),
SP(0.6),
hr(GOLD),
SP(0.3),
Paragraph("Covers all 26 SLOs | Anatomy β External Ear β ASOM β CSOM β Deafness β Tinnitus β Vertigo β Bell's Palsy",
S('cv2', fontSize=10, textColor=LGREY, alignment=TA_CENTER, fontName='Helvetica')),
SP(0.4),
Paragraph("Each section: Aetiology β Pathology β Clinical Features β Investigations β Management β Homoeopathic Remedies",
S('cv3', fontSize=9.5, textColor=CYAN, alignment=TA_CENTER, fontName='Helvetica-Bold')),
PageBreak(),
]
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PAGE 1 β EAR ANATOMY DIAGRAM (full-width)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
story += [
section_header("7.1 | ANATOMY OF THE EAR", "SLO: Review applied anatomy of Ear β External, Middle, Inner", "#00E5FF"),
SP(0.3),
img("01_ear_anatomy", width=W - 2.5*cm),
cap("Fig 1. Cross-section schematic of the ear showing External, Middle and Inner ear compartments with labelled structures."),
SP(0.3),
two_col([
h2("KEY STRUCTURES"),
bullet("External: Pinna β EAC β Tympanic membrane (TM)", CYAN),
bullet("Middle: Ossicles (Malleus β Incus β Stapes) amplify sound 22Γ", CYAN),
bullet("Middle: Eustachian tube β equalises pressure with nasopharynx", CYAN),
bullet("Inner: Cochlea (hearing) β Organ of Corti, 2.5 turns", GREEN),
bullet("Inner: Semicircular canals Γ3 (rotation), Utricle + Saccule (linear acceleration)", GREEN),
bullet("Nerve supply: CN VIII (cochlear + vestibular divisions) β temporal lobe", VIOLET),
],[
h2("SOUND PATHWAY"),
arrow_bullet("Pinna β collects and directs sound", GOLD),
arrow_bullet("EAC β transmits to TM", GOLD),
arrow_bullet("TM β converts sound to vibration", GOLD),
arrow_bullet("Ossicles β amplify (22Γ, overcomes air-fluid impedance)", GOLD),
arrow_bullet("Stapes footplate β Oval window β Perilymph waves", GOLD),
arrow_bullet("Cochlea β hair cells (organ of Corti) depolarise", GOLD),
arrow_bullet("CN VIII β cochlear nucleus β auditory cortex (temporal lobe)", GOLD),
SP(0.2),
h2("EQUILIBRIUM"),
arrow_bullet("Semicircular canals β angular/rotational acceleration", CYAN),
arrow_bullet("Utricle + Saccule β linear acceleration + static position", CYAN),
arrow_bullet("CN VIII (vestibular) β vestibular nuclei β cerebellum", CYAN),
]),
PageBreak(),
]
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PAGE 2 β TM VIEWS + CASE TAKING
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
story += [
section_header("7.2β7.4 | PHYSIOLOGY β’ CASE TAKING β’ EAR EXAMINATION", "SLO: Physiology of hearing & equilibrium | Case taking | Ear examination", "#FFA500"),
SP(0.3),
img("02_tympanic_membrane", width=W - 2.5*cm),
cap("Fig 2. Otoscopic views of the TM: Normal (pearly grey, cone of light), ASOM (bulging, red), CSOM (central perforation)."),
SP(0.3),
two_col([
h2("EAR CASE TAKING (7.3)"),
h3("Chief Complaints:"),
bullet("Otalgia (pain) β onset, severity, radiation", ORANGE),
bullet("Discharge β colour, smell, duration", ORANGE),
bullet("Deafness β unilateral/bilateral, sudden/gradual", ORANGE),
bullet("Tinnitus β character, frequency", ORANGE),
bullet("Vertigo β episodic? Nausea?", ORANGE),
h3("History:"),
bullet("H/o URTI, trauma, noise exposure", LGREY),
bullet("Family history, past infections", LGREY),
bullet("Systemic diseases (diabetes β malignant OE)", LGREY),
h3("Homoeopathic:"),
bullet("Modalities (worse/better from)", VIOLET),
bullet("Mental generals, thermals, constitution", VIOLET),
bullet("Repertorisation (Synthesis/Radar)", VIOLET),
],[
h2("EAR EXAMINATION (7.4) β DOPS"),
h3("Inspection:"),
bullet("Pinna β shape, scars, pre-auricular sinus", CYAN),
bullet("Tragus tenderness (furunculosis/OE)", CYAN),
bullet("Post-auricular: mastoid tenderness (mastoiditis)", CYAN),
h3("Otoscopy:"),
bullet("TM β colour, landmarks, light reflex, perforation", CYAN),
bullet("Normal TM: Pearly grey, cone of light antero-inferior", CYAN),
h3("Tuning Fork Tests:"),
bullet("Rinne's (512 Hz): BC vs AC", GOLD),
bullet("Weber's (512 Hz): lateralisation", GOLD),
h3("Free-field Hearing Tests:"),
bullet("Whisper test, watch-tick test", LGREY),
h3("Additional:"),
bullet("Nasal/nasopharyngeal exam (ET)", LGREY),
bullet("Cranial nerve assessment", LGREY),
]),
PageBreak(),
]
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PAGE 3 β ASOM
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
story += [
section_header("7.7β7.8 | ACUTE SUPPURATIVE OTITIS MEDIA (ASOM)", "SLO: Aetiology, Pathology, Clinical Features, Investigations, Treatment", "#7BFF6B"),
SP(0.3),
img("03_asom_stages", width=W - 2.5*cm),
cap("Fig 3. Five stages of ASOM disease progression β from hyperaemia to complication/resolution."),
SP(0.3),
two_col([
h2("AETIOLOGY"),
bullet("Streptococcus pneumoniae (most common adult)", RED),
bullet("Haemophilus influenzae (most common child)", RED),
bullet("Moraxella catarrhalis", RED),
bullet("Route: Via Eustachian tube following URTI", RED),
bullet("Risk factors: Children (short, horizontal ET), crèche, bottle-feeding, cleft palate", ORANGE),
SP(0.2),
h2("INVESTIGATIONS"),
bullet("Otoscopy β TM appearance (see stages)", CYAN),
bullet("Audiometry β conductive hearing loss", CYAN),
bullet("Tympanometry β reduced compliance", CYAN),
bullet("C&S of discharge (post-perforation)", CYAN),
bullet("X-ray mastoid (if complications suspected)", CYAN),
],[
h2("MANAGEMENT"),
h3("Conservative:"),
arrow_bullet("Analgesics + antipyretics", GREEN),
arrow_bullet("Antibiotics: Amoxicillin 1st line; Co-amoxiclav (Augmentin) if resistant", GREEN),
arrow_bullet("Nasal decongestants (reduce ET oedema)", GREEN),
arrow_bullet("Myringotomy if TM bulging (Stage 3) β aural toilet", GREEN),
h3("Surgical:"),
arrow_bullet("Myringotomy + insertion of grommet", GOLD),
arrow_bullet("Mastoidectomy if mastoiditis develops", GOLD),
SP(0.2),
hom_line("Belladonna β’ Hepar sulph β’ Pulsatilla β’ Chamomilla β’ Capsicum β’ Merc sol"),
]),
PageBreak(),
]
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PAGE 4 β CSOM
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
story += [
section_header("7.9β7.10 | CHRONIC SUPPURATIVE OTITIS MEDIA (CSOM)", "SLO: Types, Aetiology, Pathology, Clinical Features, Investigations, Management", "#FF6B6B"),
SP(0.3),
img("04_csom_types", width=W - 2.5*cm),
cap("Fig 4. CSOM β Safe (Tubotympanic) vs Unsafe (Atticoantral) types with TM perforation patterns."),
SP(0.3),
two_col([
h2("AETIOLOGY"),
bullet("Unresolved ASOM", RED),
bullet("Repeated upper respiratory infections", RED),
bullet("Eustachian tube dysfunction", RED),
bullet("Poor socioeconomic conditions / nutrition", RED),
bullet("Cleft palate, Down syndrome", RED),
SP(0.2),
h2("INVESTIGATIONS"),
bullet("Otoscopy β type of perforation, cholesteatoma?", CYAN),
bullet("Pure Tone Audiometry (PTA) β conductive HL", CYAN),
bullet("Tympanometry", CYAN),
bullet("HRCT temporal bone β gold standard for cholesteatoma extent", CYAN),
bullet("Swab for culture & sensitivity", CYAN),
SP(0.2),
h2("COMPLICATIONS (Unsafe type)"),
bullet("Mastoiditis (most common)", ORANGE),
bullet("Labyrinthitis β SNHL + vertigo", ORANGE),
bullet("Intracranial: Meningitis, Brain abscess", RED),
bullet("Lateral sinus thrombosis", RED),
bullet("Facial nerve palsy (CN VII erosion)", RED),
bullet("Petrositis β Gradenigo's syndrome", RED),
],[
h2("MANAGEMENT"),
h3("Conservative (Safe type):"),
arrow_bullet("Aural toilet (suction + dry mopping)", GREEN),
arrow_bullet("Topical antibiotic ear drops", GREEN),
arrow_bullet("Treat underlying URTI / nasal allergy", GREEN),
h3("Surgical:"),
arrow_bullet("Tympanoplasty β TM repair (Safe type)", GREEN),
arrow_bullet("Cortical mastoidectomy (Unsafe β no cholesteatoma)", GOLD),
arrow_bullet("Modified radical mastoidectomy (with cholesteatoma)", RED),
arrow_bullet("Radical mastoidectomy (severe / last resort)", RED),
SP(0.2),
h2("CHOLESTEATOMA"),
bullet("Squamous epithelium in middle ear", VIOLET),
bullet("Erodes bone via collagenases", VIOLET),
bullet("Appears as pearly-white, cheesy mass", VIOLET),
bullet("β Mastoidectomy mandatory", VIOLET),
SP(0.2),
hom_line("Merc sol β’ Silicea β’ Pulsatilla β’ Hepar sulph β’ Kali mur β’ Calc sulph"),
]),
PageBreak(),
]
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PAGE 5 β Deafness + Audiogram + Tympanogram
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
story += [
section_header("7.16β7.18 | DEAFNESS (HEARING LOSS)", "SLO: Types, Causes, Management | Hearing aids & Implants", "#00E5FF"),
SP(0.2),
img("05_audiogram", width=W - 2.5*cm),
cap("Fig 5. Audiograms β Conductive HL (air-bone gap, Rinne βve) vs SNHL (parallel elevation, Rinne +ve)."),
SP(0.2),
img("09_tympanogram", width=W - 2.5*cm),
cap("Fig 6. Tympanograms β Type A (normal), Type B (flat = glue ear / perforation), Type C (negative pressure = ET dysfunction)."),
SP(0.2),
two_col([
h2("CONDUCTIVE HL"),
bullet("Problem: External/Middle ear", CYAN),
bullet("Air-bone gap on audiogram", CYAN),
bullet("Causes: Wax, TM perf, Otosclerosis, OME, CSOM", CYAN),
bullet("Tuning Fork: Rinne βve | Weber β worse ear", CYAN),
h2("SENSORINEURAL HL (SNHL)"),
bullet("Problem: Cochlea / CN VIII", RED),
bullet("No air-bone gap; both thresholds elevated", RED),
bullet("Causes: Noise (NIHL), Presbyacusis, Ototoxic drugs", RED),
bullet("Meniere's, Acoustic neuroma, Viral labyrinthitis", RED),
bullet("Tuning Fork: Rinne +ve | Weber β better ear", RED),
],[
h2("INVESTIGATIONS"),
bullet("PTA (Pure Tone Audiometry) β threshold/type", GOLD),
bullet("Tympanometry β middle ear function", GOLD),
bullet("OAE (Otoacoustic Emissions) β cochlear hair cells", GOLD),
bullet("BERA/ABR β retrocochlear lesion (acoustic neuroma)", GOLD),
bullet("Speech audiometry β discrimination", GOLD),
bullet("MRI IAM β if retrocochlear suspected", GOLD),
h2("MANAGEMENT"),
bullet("Conductive: Surgery (myringoplasty, stapedectomy, grommet)", GREEN),
bullet("SNHL: Hearing aid (analogue/digital), Cochlear implant", GREEN),
bullet("NIHL: Prevention β ear protection, noise regulations", ORANGE),
SP(0.1),
hom_line("China β’ Causticum β’ Kali mur β’ Phosphorus β’ Graphites β’ Merc sol"),
]),
PageBreak(),
]
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PAGE 6 β Tuning Fork Tests
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
story += [
section_header("TUNING FORK TESTS | RINNE'S & WEBER'S", "512 Hz fork | Clinical bedside test for type of hearing loss", "#FFD700"),
SP(0.3),
img("06_tuning_fork", width=W - 2.5*cm),
cap("Fig 7. Rinne's and Weber's tuning fork test interpretation for conductive vs sensorineural hearing loss."),
SP(0.3),
info_table(
["Test", "Procedure", "Normal / SNHL", "Conductive HL", "Clinical Rule"],
[
["Rinne's", "BC on mastoid β then AC near ear. Which louder?",
"Rinne +ve: AC > BC", "Rinne βve: BC > AC (β₯25 dB loss)",
"False βve Rinne: Profound SNHL (dead ear) β confirm with Weber"],
["Weber's", "Fork on vertex / forehead. Where do you hear it?",
"Midline (central)", "Lateralises to WORSE ear",
"Unilateral SNHL: lateralises to BETTER ear"],
["Absolute Bone\nConduction (ABC)", "Compare patient BC to examiner BC",
"Equal to examiner", "Equal to examiner",
"Reduced ABC = cochlear/neural problem (SNHL)"],
],
col_colors=[GOLD, LGREY, GREEN, RED, ORANGE]
),
PageBreak(),
]
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PAGE 7 β Vertigo
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
story += [
section_header("7.21β7.25 | VERTIGO β’ BPPV β’ MENIERE'S β’ ACOUSTIC NEUROMA", "SLO: Causes, Features, Investigations, Management", "#DA70D6"),
SP(0.3),
img("07_vertigo", width=W - 2.5*cm),
cap("Fig 8. Peripheral vs Central vertigo β comparison of features, nystagmus characteristics and causes."),
SP(0.3),
two_col([
h2("MENIERE'S DISEASE (7.24)"),
bullet("Pathology: Endolymphatic hydrops (excess endolymph)", VIOLET),
h3("Classic Triad:"),
arrow_bullet("Episodic vertigo (20 min β 12 hr)", GOLD),
arrow_bullet("Fluctuating low-frequency SNHL", GOLD),
arrow_bullet("Tinnitus + aural fullness", GOLD),
bullet("Ix: PTA, ECoG (electrocochleography), Glycerol test, MRI IAM", CYAN),
bullet("Rx: Low-salt diet, Betahistine (Serc), Diuretics", GREEN),
bullet("Surgery: Endolymphatic sac decompression (last resort)", ORANGE),
hom_line("Conium β’ China β’ Cocculus β’ Gelsemium β’ Phosphorus"),
SP(0.2),
h2("BPPV (7.25)"),
bullet("Canalolithiasis: otoconia in posterior semicircular canal", CYAN),
bullet("Brief (<1 min) vertigo triggered by head position change", CYAN),
bullet("Dix-Hallpike test +ve (latent nystagmus, fatigues)", CYAN),
bullet("NO deafness / tinnitus", CYAN),
bullet("Rx: Epley manoeuvre β FIRST LINE; Vestibular rehab exercises", GREEN),
hom_line("Cocculus β’ Conium β’ Gelsemium β’ Tabacum"),
],[
h2("ACOUSTIC NEUROMA (Vestibular Schwannoma) (7.25)"),
bullet("Benign tumour of CN VIII (vestibular division)", RED),
bullet("Arises at IAM / CPA", RED),
h3("Features (GRADUAL onset):"),
arrow_bullet("Unilateral SNHL β often first symptom", ORANGE),
arrow_bullet("Tinnitus (unilateral)", ORANGE),
arrow_bullet("Vertigo (mild/late)", ORANGE),
arrow_bullet("Facial numbness (CN V compression)", ORANGE),
arrow_bullet("Facial palsy (CN VII β late)", ORANGE),
arrow_bullet("Ataxia (cerebellar involvement)", ORANGE),
h3("Investigations:"),
bullet("MRI IAM with gadolinium β GOLD STANDARD", GOLD),
bullet("ABR/BERA β wave V latency prolonged", GOLD),
bullet("PTA β unilateral SNHL", GOLD),
h3("Management:"),
bullet("Small (<1.5 cm): Observation (serial MRI)", GREEN),
bullet("Radiosurgery: Gamma knife / CyberKnife", GREEN),
bullet("Surgery: Translabyrinthine approach (large tumours)", GREEN),
hom_line("Phosphorus β’ Conium β’ Gelsemium"),
]),
PageBreak(),
]
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PAGE 8 β Facial Palsy / Bell's Palsy
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
story += [
section_header("7.26 | FACIAL PARALYSIS β’ BELL'S PALSY", "SLO: Aetiology, Pathology, Clinical Features, Investigation, Management", "#FFA500"),
SP(0.3),
img("08_facial_nerve", width=W - 2.5*cm),
cap("Fig 9. CN VII course from motor cortex to terminal branches, UMN vs LMN palsy features, and Bell's Palsy management."),
SP(0.3),
two_col([
h2("CN VII TERMINAL BRANCHES"),
bullet("To Frankie Zulu Both Colours Match (mnemonic)", GOLD),
arrow_bullet("Temporal", VIOLET),
arrow_bullet("Zygomatic", VIOLET),
arrow_bullet("Buccal", VIOLET),
arrow_bullet("(Marginal) Mandibular", VIOLET),
arrow_bullet("Cervical", VIOLET),
SP(0.2),
h2("UMN vs LMN β KEY DIFFERENCE"),
bullet("UMN (above nucleus / cortex lesion): Forehead SPARED", CYAN),
bullet("LMN (nucleus or peripheral): Forehead INVOLVED", RED),
bullet("Forehead has bilateral cortical representation β spared in UMN strokes", CYAN),
SP(0.2),
h2("CAUSES"),
h3("LMN (peripheral):"),
bullet("Bell's Palsy (idiopathic, HSV-1) β COMMONEST", GREEN),
bullet("Ramsay Hunt syndrome (VZV β vesicles in pinna/EAC)", RED),
bullet("Acoustic neuroma, Parotid tumour", ORANGE),
bullet("Temporal bone fracture, CSOM cholesteatoma", ORANGE),
bullet("Lyme disease, Sarcoidosis, GBS", LGREY),
h3("UMN (central):"),
bullet("Stroke (CVA) β most common UMN cause", RED),
bullet("Brain tumour, MS, MND", ORANGE),
],[
h2("BELL'S PALSY"),
bullet("Idiopathic LMN facial palsy", ORANGE),
bullet("Aetiology: HSV-1 reactivation β nerve oedema in bony canal", ORANGE),
h3("Clinical Features:"),
arrow_bullet("Sudden unilateral LMN palsy", RED),
arrow_bullet("Forehead INVOLVED (cannot wrinkle)", RED),
arrow_bullet("Lagophthalmos (incomplete eye closure)", RED),
arrow_bullet("Bell's phenomenon: eyeball rolls upward", RED),
arrow_bullet("Hyperacusis (stapedius branch affected)", ORANGE),
arrow_bullet("Taste loss: anterior 2/3 tongue (chorda tympani)", ORANGE),
arrow_bullet("Lacrimation Β± (greater petrosal nerve)", ORANGE),
h3("Investigations:"),
bullet("Clinical diagnosis (rule out other causes)", CYAN),
bullet("Rule out Ramsay Hunt (vesicles), check BP, glucose", CYAN),
bullet("MRI if atypical / slow recovery", CYAN),
bullet("Grading: House-Brackmann Scale I (normal) β VI (complete)", GOLD),
h3("Management:"),
bullet("Prednisolone 60 mg/day Γ 5 days β taper (start <72 h)", GREEN),
bullet("Acyclovir 400 mg 5Γ daily if severe or HSV suspected", GREEN),
bullet("Eye protection: lubricating drops + tape/patch at night", GREEN),
bullet("Physiotherapy (facial exercises)", GREEN),
bullet("Prognosis: ~80% full recovery within 3β6 months", GOLD),
SP(0.1),
hom_line("Causticum β’ Aconite β’ Gelsemium β’ Dulcamara β’ Cadmium sulph"),
]),
PageBreak(),
]
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PAGE 9 β QUICK REFERENCE TABLE (all topics)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
story += [
section_header("QUICK REFERENCE β ALL EAR TOPICS (Unit 7)", "Complete summary table for rapid revision", "#FFD700"),
SP(0.3),
info_table(
["Topic", "Key Aetiology", "Key Features", "Ix", "Management", "Homoeopathic"],
[
["ASOM", "Strep pneu / H. inf\nURTI β ET route",
"Otalgia, fever, deafness\nBulging TM",
"Otoscopy\nAudiometry",
"Abx + Analgesics\nMyringotomy",
"Belladonna\nHepar sulph\nPulsatilla"],
["CSOM β Safe", "Unresolved ASOM\nET dysfunction",
"Central perforation\nMucoid discharge\nConductive HL",
"Otoscopy\nPTA, CT",
"Aural toilet\nTympanoplasty",
"Pulsatilla, Kali mur\nMerc sol"],
["CSOM β Unsafe", "As above +\nCholesteatoma",
"Marginal/attic perf\nFoul discharge\nBone erosion",
"HRCT temporal\nbone, PTA",
"Mastoidectomy",
"Silicea, Hepar sulph\nCalc sulph"],
["Glue Ear (OME)", "ET dysfunction\nAdenoids",
"Bilateral HL in child\nFlat tympanogram\nNo pain",
"Tympanometry\n(Type B flat)",
"Grommet + Adenoidectomy",
"Kali mur, Pulsatilla\nMerc sol"],
["OE / Furunculosis", "Pseudomonas\nStaph aureus",
"Otalgia\nItching\nTragus tenderness",
"Otoscopy\nC&S swab",
"Aural toilet\nAntibiotic drops",
"Belladonna\nCapsicum, Sulphur"],
["Otalgia", "Local or referred\n(dental/tonsil)",
"Ear pain Β± discharge\nRule out referred causes",
"ENT + dental exam\nOPG",
"Treat cause",
"Chamomilla\nAconite, Pulsatilla"],
["Otorrhea", "ASOM/CSOM/OE\nCholesteatoma",
"Character β diagnosis\n(foul = cholesteatoma)",
"Otoscopy, C&S\nCT if needed",
"Aural toilet\nAbx drops, Surgery",
"Pulsatilla, Silicea\nGraphites"],
["Deafness β Conductive", "Wax, perf, otosclerosis\nOME",
"Air-bone gap\nRinne βve\nWeber β worse",
"PTA, Tympanometry",
"Surgery / Grommet\nHearing aid",
"China, Causticum\nKali mur"],
["Deafness β SNHL", "Noise, aging, ototoxins\nMeniere's, neuroma",
"No air-bone gap\nRinne +ve\nHigh-freq first",
"PTA, OAE, BERA\nMRI IAM",
"Hearing aid\nCochlear implant",
"China, Phosphorus\nCarbo veg"],
["Tinnitus", "NIHL, Meniere's\nOtosclerosis, ototoxins",
"Sound without source\nSubjective (common)\nObjective (rare)",
"PTA, MRI IAM",
"TRT, Sound therapy\nTreat cause",
"China, Nat sal\nCarbon sulph"],
["Vertigo β Peripheral", "BPPV, Meniere's\nLabyrinthitis",
"Episodic, severe\nHorizontal nystagmus\nDeafness Β±",
"PTA, Caloric test\nDix-Hallpike",
"Epley (BPPV)\nBetahistine, Physio",
"Cocculus, Conium\nGelsemium"],
["Vertigo β Central", "VBI, cerebellar stroke\nMS, tumour",
"Constant, neurological\nVertical nystagmus",
"MRI brain",
"Treat cause",
"Conium, Gelsemium"],
["Meniere's Disease", "Endolymphatic hydrops",
"Triad: Vertigo+\nSNHL+Tinnitus",
"ECoG, Glycerol test\nPTA, MRI IAM",
"Low salt + Betahistine\nEndolymph sac decomp.",
"China, Conium\nCocculus, Phosphorus"],
["Acoustic Neuroma", "CN VIII schwannoma\nCPA/IAM",
"Unilateral SNHL\nTinnitus, ataxia\nFacial numbness",
"MRI IAM (gold std)\nABR, PTA",
"Radiosurgery\nSurgery",
"Phosphorus, Conium"],
["Bell's Palsy", "Idiopathic LMN\nHSV-1 reactivation",
"Sudden unilateral palsy\nForehead INVOLVED\nLagophthalmos",
"Clinical\nRule out Ramsay Hunt",
"Prednisolone <72 h\nAcyclovir, Eye care",
"Causticum, Aconite\nGelsemium, Dulcamara"],
],
col_colors=[GOLD, RED, ORANGE, CYAN, GREEN, HexColor("#7BFF6B")]
),
]
# ββ build PDF βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
doc = SimpleDocTemplate(
OUT_PDF,
pagesize=landscape(A4),
leftMargin=1.2*cm, rightMargin=1.2*cm,
topMargin=1.2*cm, bottomMargin=1.2*cm,
title="EAR Surgery Notes β Hom UG-Sur-II Unit 7",
author="Comprehensive Medical Notes",
subject="EAR β Surgery Syllabus",
)
doc.build(story, onFirstPage=on_page, onLaterPages=on_page)
print(f"PDF saved: {OUT_PDF}")
import os
size = os.path.getsize(OUT_PDF) / 1024
print(f"File size: {size:.1f} KB")
cd /tmp/workspace/ear-notes && python3 build_ear_pdf.py 2>&1
cd /tmp/workspace/ear-notes && python3 assemble_pdf.py 2>&1
cd /tmp/workspace/ear-notes && python3 -c " from PIL import Image as PILImage import os for f in sorted(os.listdir('diagrams')): if f.endswith('.png'): im = PILImage.open(f'diagrams/{f}') print(f'{f}: {im.size}') "
~/ear-notes/assemble_pdf.py
Successfully replaced 1 instance(s) of the string in '/tmp/workspace/ear-notes/assemble_pdf.py'
head -5 /tmp/workspace/ear-notes/assemble_pdf.py
~/ear-notes/assemble_pdf.py
Successfully replaced 1 instance(s) of the string in '/tmp/workspace/ear-notes/assemble_pdf.py'
~/ear-notes/assemble_pdf.py
Successfully replaced 1 instance(s) of the string in '/tmp/workspace/ear-notes/assemble_pdf.py'
cd /tmp/workspace/ear-notes && python3 assemble_pdf.py 2>&1
cd /tmp/workspace/ear-notes && python3 -c " from pypdf import PdfReader r = PdfReader('EAR_Surgery_Comprehensive_Notes.pdf') print(f'Pages: {len(r.pages)}') print(f'Title: {r.metadata.title}') "
EAR Surgery Comprehensive Notes
PDF Document Β· PDF
| Fig | Diagram | What it shows |
|---|---|---|
| 1 | Cross-Section of the Ear | External β Middle β Inner ear with all labelled structures, ossicular chain, cochlea spiral, semicircular canals, sound pathway arrow |
| 2 | Otoscopic TM Views Γ3 | Normal TM (pearly grey, cone of light) / ASOM (bulging, red) / CSOM (central perforation) |
| 3 | ASOM 5-Stage Flowchart | Colour-coded boxes: Hyperaemia β Exudation β Suppuration β Resolution/Perforation β Complication |
| 4 | CSOM Safe vs Unsafe | Side-by-side TM diagrams with cholesteatoma in unsafe type |
| 5 | Audiogram | Conductive HL (air-bone gap, Rinne -ve) vs SNHL (parallel elevation, Rinne +ve) |
| 6 | Tuning Fork Tests | Rinne's + Weber's with visual fork diagrams and interpretation table |
| 7 | Peripheral vs Central Vertigo | 10-point comparison table in one diagram |
| 8 | CN VII Course + Bell's Palsy | Full nerve pathway flowchart, UMN vs LMN panel, Bell's Palsy details |
| 9 | Tympanograms A / B / C | Type A (normal), B (flat = glue ear), C (neg. pressure = ET catarrh) |