~/pharmacology-notes/generate_notes.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether
)
from reportlab.lib.enums import TA_LEFT, TA_CENTER
from reportlab.platypus import PageBreak
OUTPUT = "/home/daytona/workspace/pharmacology-notes/Ephedrine_Phenylephrine_Notes.pdf"
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
leftMargin=2*cm, rightMargin=2*cm,
topMargin=2*cm, bottomMargin=2*cm
)
styles = getSampleStyleSheet()
# Custom styles
TITLE = ParagraphStyle("Title", parent=styles["Title"],
fontSize=20, textColor=colors.HexColor("#1a1a2e"), spaceAfter=6,
alignment=TA_CENTER, fontName="Helvetica-Bold")
SUBTITLE = ParagraphStyle("Subtitle", parent=styles["Normal"],
fontSize=11, textColor=colors.HexColor("#555555"),
spaceAfter=18, alignment=TA_CENTER, fontName="Helvetica-Oblique")
DRUG_HEADER = ParagraphStyle("DrugHeader",
fontSize=16, textColor=colors.white, fontName="Helvetica-Bold",
alignment=TA_LEFT, spaceAfter=0, spaceBefore=0,
leftIndent=8)
SECTION = ParagraphStyle("Section",
fontSize=11, textColor=colors.HexColor("#1a1a2e"), fontName="Helvetica-Bold",
spaceBefore=10, spaceAfter=4, leftIndent=0)
BODY = ParagraphStyle("Body", parent=styles["Normal"],
fontSize=9.5, leading=14, textColor=colors.HexColor("#222222"),
fontName="Helvetica", spaceAfter=3, leftIndent=8)
BULLET = ParagraphStyle("Bullet", parent=styles["Normal"],
fontSize=9.5, leading=14, textColor=colors.HexColor("#222222"),
fontName="Helvetica", spaceAfter=2, leftIndent=16, bulletIndent=8)
TABLE_HEADER = ParagraphStyle("TH", fontSize=9, fontName="Helvetica-Bold",
textColor=colors.white, alignment=TA_CENTER)
TABLE_CELL = ParagraphStyle("TC", fontSize=9, fontName="Helvetica",
textColor=colors.HexColor("#222222"), alignment=TA_LEFT, leading=12)
FOOTER_TEXT = ParagraphStyle("Footer", fontSize=8, textColor=colors.grey,
alignment=TA_CENTER, fontName="Helvetica-Oblique")
# ── Colours
EPHEDRINE_BG = colors.HexColor("#2e4057")
PHENYL_BG = colors.HexColor("#048a81")
SECTION_LINE = colors.HexColor("#cccccc")
TABLE_HDR_BG = colors.HexColor("#2e4057")
ALT_ROW = colors.HexColor("#f0f4f8")
def drug_header(name, subtitle):
data = [[Paragraph(name, DRUG_HEADER), Paragraph(subtitle, ParagraphStyle(
"Sub2", fontSize=10, textColor=colors.HexColor("#dddddd"),
fontName="Helvetica-Oblique", alignment=TA_LEFT))]]
bg = EPHEDRINE_BG if "Ephedrine" in name else PHENYL_BG
t = Table(data, colWidths=[9*cm, 8*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("ROWBACKGROUNDS", (0,0), (-1,-1), [bg]),
("TOPPADDING", (0,0), (-1,-1), 10),
("BOTTOMPADDING", (0,0), (-1,-1), 10),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("ROUNDEDCORNERS", (0,0), (-1,-1), [6,6,6,6]),
]))
return t
def section_title(text):
return [
Paragraph(f"▸ {text}", SECTION),
HRFlowable(width="100%", thickness=0.5, color=SECTION_LINE, spaceAfter=4),
]
def bullets(items):
return [Paragraph(f"• {item}", BULLET) for item in items]
def mini_table(headers, rows, col_widths=None):
if col_widths is None:
col_widths = [17*cm / len(headers)] * len(headers)
header_row = [Paragraph(h, TABLE_HEADER) for h in headers]
data = [header_row]
for i, row in enumerate(rows):
data.append([Paragraph(str(c), TABLE_CELL) for c in row])
t = Table(data, colWidths=col_widths, repeatRows=1)
ts = [
("BACKGROUND", (0,0), (-1,0), TABLE_HDR_BG),
("TEXTCOLOR", (0,0), (-1,0), colors.white),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,0), 9),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#cccccc")),
("VALIGN", (0,0), (-1,-1), "TOP"),
]
for i in range(1, len(data)):
if i % 2 == 0:
ts.append(("BACKGROUND", (0,i), (-1,i), ALT_ROW))
t.setStyle(TableStyle(ts))
return t
# ─────────────────────────────────────────────
# BUILD CONTENT
# ─────────────────────────────────────────────
story = []
# TITLE PAGE
story.append(Spacer(1, 1.5*cm))
story.append(Paragraph("Pharmacology Notes", TITLE))
story.append(Paragraph("Ephedrine & Phenylephrine — Mechanism, Pharmacokinetics, Indications, Adverse Effects, Dosing & Drug Interactions", SUBTITLE))
story.append(HRFlowable(width="100%", thickness=1.5, color=EPHEDRINE_BG, spaceAfter=6))
story.append(Paragraph("Sources: Morgan & Mikhail Clinical Anesthesiology 7e · Barash Clinical Anesthesia 9e · Goodman & Gilman 14e · Katzung 16e · Lippincott Illustrated Reviews Pharmacology", FOOTER_TEXT))
story.append(Spacer(1, 0.5*cm))
# ══════════════════════════════════════════════
# DRUG 1 — EPHEDRINE
# ══════════════════════════════════════════════
story.append(drug_header("1. Ephedrine", "Mixed-acting sympathomimetic · Noncatecholamine phenylisopropylamine"))
story.append(Spacer(1, 0.3*cm))
# MOA
story += section_title("Mechanism of Action")
story += bullets([
"Mixed-acting sympathomimetic: predominantly indirect, with direct component.",
"Indirect mechanism: endocytosis into adrenergic nerve terminals → displaces norepinephrine (NE) from synaptic vesicles → released NE activates postsynaptic α and β receptors.",
"Direct mechanism: directly stimulates α₁, α₂, β₁, and β₂ adrenoceptors.",
"Net receptor profile: α₁ + α₂ + β₁ + β₂ (all adrenoceptors).",
"Because it depends on presynaptic NE stores, drugs depleting NE (e.g., reserpine) or blocking uptake (e.g., cocaine) attenuate its effects.",
"Tachyphylaxis: rapid depletion of presynaptic NE stores with repeated dosing; ephedrine is released as a false neurotransmitter.",
"CNS penetrant — mild stimulant (unlike catecholamines).",
])
story.append(Spacer(1, 0.2*cm))
# PHARMACOKINETICS
story += section_title("Pharmacokinetics")
story.append(mini_table(
["Parameter", "Detail"],
[
["Route", "Oral (high bioavailability), IV, IM"],
["Onset (IV)", "~1 min"],
["Duration (IV bolus)", "10–60 min (longer than direct-acting catecholamines)"],
["Half-life", "3–6 hours"],
["Metabolism", "Minor hepatic; not metabolised by MAO or COMT (unlike catecholamines)"],
["Elimination", "Renal excretion — largely unchanged drug in urine"],
["CNS penetration", "Yes — crosses blood-brain barrier; mild CNS stimulant"],
],
col_widths=[5*cm, 12*cm]
))
story.append(Spacer(1, 0.2*cm))
# INDICATIONS
story += section_title("Indications")
story += bullets([
"Hypotension during anesthesia — preferred when accompanied by bradycardia.",
"Spinal / neuraxial anesthesia-induced hypotension (when heart rate is low or normal).",
"Bronchospasm / asthma — largely superseded by selective β₂ agonists.",
"Urinary incontinence (stress) — stimulates α receptors at bladder neck.",
"Nasal decongestant (oral / topical).",
"Narcolepsy / myasthenia gravis (historical use).",
"Intraoperative: vasopressor of choice when hypotension + bradycardia coexist.",
])
story.append(Spacer(1, 0.2*cm))
# ADVERSE EFFECTS
story += section_title("Adverse Effects")
story.append(mini_table(
["System", "Effect"],
[
["Cardiovascular", "Hypertension, tachycardia, palpitations, arrhythmias (β₁ stimulation)"],
["CNS", "Insomnia, anxiety, tremor, headache, CNS stimulation"],
["Genitourinary", "Urinary retention — especially in BPH patients (α receptor activation at bladder neck)"],
["Tachyphylaxis", "Rapid tolerance with repeated doses due to NE depletion from nerve terminals"],
["Metabolic", "Hyperglycaemia (β₂ effect on glycogenolysis)"],
["Obstetric concern", "Crosses placenta → fetal tachycardia and fetal acidosis (lower umbilical pH)"],
["Overdose", "Severe hypertension, arrhythmias, haemorrhagic stroke"],
["Regulatory", "FDA banned ephedra-containing dietary supplements (safety concerns, deaths reported)"],
],
col_widths=[4*cm, 13*cm]
))
story.append(Spacer(1, 0.2*cm))
# DOSING
story += section_title("Dosing (Clinical Anesthesia / Inpatient)")
story.append(mini_table(
["Route / Indication", "Dose"],
[
["IV bolus (anesthesia-induced hypotension)", "5–25 mg; titrate to effect"],
["IV infusion", "25–50 mg in 250 mL → titrate 5–25 mg/h"],
["IM", "25–50 mg"],
["Oral (decongestant)", "25–50 mg every 4 h (max 150 mg/day)"],
],
col_widths=[7*cm, 10*cm]
))
story.append(Spacer(1, 0.2*cm))
# DRUG INTERACTIONS
story += section_title("Drug Interactions")
story.append(mini_table(
["Drug / Class", "Interaction", "Clinical Consequence"],
[
["MAO inhibitors (phenelzine, tranylcypromine)",
"MAO normally breaks down displaced NE; MAOIs block this → massive NE accumulation",
"Severe hypertensive crisis; potentially fatal. Avoid — use direct-acting agents instead."],
["Tricyclic antidepressants (TCAs)",
"TCAs block NE reuptake transporter (NET) → augmented pressor response to released NE",
"Exaggerated hypertension; arrhythmias. Use with extreme caution; reduce dose."],
["β-blockers",
"Block β₁/β₂ effects of ephedrine → unopposed α stimulation",
"Paradoxical hypertension and bradycardia; reduced bronchodilation."],
["Volatile anaesthetics (halothane)",
"Sensitise myocardium to catecholamines",
"Increased arrhythmia risk — use cautiously."],
["Reserpine / α-methyldopa",
"Deplete presynaptic NE stores",
"Attenuated or absent response to ephedrine (loss of indirect action)."],
["Cocaine",
"Blocks NE reuptake transporter, preventing ephedrine uptake into nerve terminal",
"Reduced indirect effect; unpredictable pressor response."],
["Tocolytics (β-sympathomimetics, e.g., ritodrine)",
"Additive β stimulation",
"Increased risk of arrhythmias and cardiovascular instability — use cautiously in labour."],
["Oxytocin",
"Synergistic vasoconstriction in some vascular beds",
"Monitor blood pressure closely in obstetric patients."],
["Theophylline",
"Additive β₂ and CNS stimulation",
"Risk of arrhythmias and seizures."],
["Digoxin",
"Increased sympathetic tone may worsen digoxin-related arrhythmias",
"Cardiac monitoring required."],
],
col_widths=[4.5*cm, 6.5*cm, 6*cm]
))
story.append(Spacer(1, 0.4*cm))
# ══════════════════════════════════════════════
# DRUG 2 — PHENYLEPHRINE
# ══════════════════════════════════════════════
story.append(PageBreak())
story.append(drug_header("2. Phenylephrine", "Direct-acting selective α₁ agonist · Noncatecholamine"))
story.append(Spacer(1, 0.3*cm))
# MOA
story += section_title("Mechanism of Action")
story += bullets([
"Direct-acting, selective α₁ adrenoceptor agonist — does NOT depend on presynaptic NE stores.",
"Structural difference from epinephrine: lacks the 4-hydroxyl group on the phenyl ring → abolishes β-receptor activity.",
"Activates α₁ on vascular smooth muscle → Gq coupling → ↑ intracellular Ca²⁺ → actin-myosin shortening → vasoconstriction.",
"Constricts venous capacitance vessels, cutaneous, skeletal muscle, mesenteric, splenic, and renal vasculature → ↑ LV preload and afterload → ↑ arterial pressure.",
"Baroreceptor-mediated reflex bradycardia (vagal tone increases in response to ↑ BP).",
"NOT arrhythmogenic — no β-receptor stimulation of myocardium.",
"Pulmonary vasoconstriction → ↑ pulmonary artery pressures.",
])
story.append(Spacer(1, 0.2*cm))
# PHARMACOKINETICS
story += section_title("Pharmacokinetics")
story.append(mini_table(
["Parameter", "Detail"],
[
["Routes", "IV bolus, IV infusion, topical intranasal, ophthalmic, oral (decongestant — limited systemic absorption)"],
["Onset (IV)", "< 1 min"],
["Duration (IV bolus)", "~15 min"],
["Half-life (IV)", "~2–3 min (redistribution); terminal t½ ~2–3 h"],
["Metabolism", "Hepatic (MAO and COMT independent — not a catechol); also intestinal MAO"],
["Elimination", "Renal; metabolised to inactive glucuronide conjugates"],
["CNS penetration", "Minimal — does not cross BBB readily"],
],
col_widths=[5*cm, 12*cm]
))
story.append(Spacer(1, 0.2*cm))
# INDICATIONS
story += section_title("Indications")
story += bullets([
"Hypotension during anesthesia with normal or elevated heart rate (e.g., after vasodilating agents).",
"Spinal / neuraxial anesthesia-induced hypotension — preferred agent in obstetric (cesarean) spinal anesthesia; prophylactic infusion reduces nausea and physician interventions.",
"Paroxysmal supraventricular tachycardia (PSVT) — reflex vagal slowing can terminate SVT.",
"Nasal decongestant: topical spray or oral; has replaced pseudoephedrine in many OTC products.",
"Mydriasis: ophthalmic drops for pupil dilation during fundoscopy.",
"Hypotension in patients on PDE5 inhibitors (e.g., after sildenafil + nitrate interaction) — used as vasopressor of last resort.",
"Septic shock (as vasopressor when tachyarrhythmias preclude other agents).",
"Refractory hypotension in cases where β stimulation is undesirable (e.g., HOCM, aortic stenosis).",
])
story.append(Spacer(1, 0.2*cm))
# ADVERSE EFFECTS
story += section_title("Adverse Effects")
story.append(mini_table(
["System", "Effect"],
[
["Cardiovascular", "Reflex bradycardia (can be severe); increased pulmonary artery pressure"],
["Cardiac output", "May ↓ CO in patients with HFrEF — failing ventricle is afterload-sensitive"],
["Renal / splanchnic", "Renal and mesenteric vasoconstriction with high doses"],
["Tissue ischaemia", "Risk of peripheral ischaemia with prolonged infusion"],
["Hypertensive headache", "With large doses"],
["Ophthalmic", "Prolonged mydriasis; angle-closure glaucoma risk in predisposed patients"],
["Tachyphylaxis", "With infusions — mechanism: receptor desensitisation; requires dose titration upward"],
["Nasal rebound", "Rhinitis medicamentosa with prolonged topical use (> 3 days)"],
["Spinal additive", "As spinal adjuvant: associated with transient neurological symptoms (TNS)"],
],
col_widths=[4*cm, 13*cm]
))
story.append(Spacer(1, 0.2*cm))
# DOSING
story += section_title("Dosing (Clinical Anesthesia / Inpatient)")
story.append(mini_table(
["Route / Indication", "Dose"],
[
["IV bolus (adult anesthesia-induced hypotension)", "50–100 mcg (0.5–1 mcg/kg); repeat every 1–2 min PRN"],
["IV infusion (prophylaxis / treatment)", "25–100 mcg/min; titrate to target MAP"],
["Preparation", "Dilute 1% solution (10 mg/mL ampule) → 100 mcg/mL working solution"],
["Obstetric prophylactic infusion", "25–50 mcg/min; start at induction of spinal block"],
["Intranasal (decongestant)", "0.25–0.5% solution — 2–3 sprays per nostril every 4 h (max 3 days)"],
["Ophthalmic (mydriasis)", "2.5% or 10% solution — 1 drop; 10% avoided in elderly / infants"],
["SVT (historical)", "0.5–1 mg IV slow push — largely replaced by adenosine"],
],
col_widths=[7*cm, 10*cm]
))
story.append(Spacer(1, 0.2*cm))
# DRUG INTERACTIONS
story += section_title("Drug Interactions")
story.append(mini_table(
["Drug / Class", "Interaction", "Clinical Consequence"],
[
["MAO inhibitors",
"MAO is a minor metabolic pathway for phenylephrine; MAOIs prolong and intensify action",
"Exaggerated hypertension; use with caution and at reduced doses."],
["Tricyclic antidepressants",
"TCAs block NET → augmented response to direct α₁ stimulation",
"Severe hypertension with even small doses; reduce dose significantly."],
["β-blockers (non-selective)",
"Unopposed α stimulation when β-mediated vasodilation is blocked",
"Paradoxical hypertension and reflex bradycardia worsened."],
["PDE5 inhibitors (sildenafil, tadalafil)",
"PDE5 inhibitors cause profound vasodilation; phenylephrine used to counteract hypotension from PDE5i + nitrate interaction",
"Phenylephrine is vasopressor of choice in this setting; titrate carefully."],
["Oxytocin",
"Additive vasoconstrictive effects",
"Monitor BP closely in post-partum patients."],
["Guanethidine / reserpine",
"NE depletion has no effect on phenylephrine (direct-acting) — no attenuation",
"Unlike ephedrine, phenylephrine response is preserved."],
["Halogenated anaesthetics",
"Phenylephrine does not sensitise myocardium (no β effect) — advantage over ephedrine",
"Lower arrhythmia risk compared to ephedrine in volatile anaesthetic context."],
["Ergot alkaloids (ergometrine)",
"Additive vasoconstriction",
"Risk of severe peripheral and coronary vasospasm — avoid combination."],
["Atropine",
"Blocks reflex bradycardia caused by phenylephrine",
"Useful if bradycardia is problematic; heart rate may rise substantially."],
["α-blockers (prazosin, phentolamine)",
"Competitive antagonism at α₁ receptors",
"Attenuated or abolished vasoconstrictor response."],
],
col_widths=[4.5*cm, 6.5*cm, 6*cm]
))
story.append(Spacer(1, 0.4*cm))
# ══════════════════════════════════════════════
# QUICK COMPARISON TABLE
# ══════════════════════════════════════════════
story.append(PageBreak())
story.append(Paragraph("Quick Comparison Summary", ParagraphStyle("QC", fontSize=14,
textColor=colors.HexColor("#1a1a2e"), fontName="Helvetica-Bold",
spaceBefore=8, spaceAfter=10, alignment=TA_CENTER)))
story.append(mini_table(
["Feature", "Ephedrine", "Phenylephrine"],
[
["Class", "Noncatecholamine, phenylisopropylamine", "Noncatecholamine, synthetic"],
["Mechanism", "Mixed (indirect + direct)", "Direct only"],
["Receptor profile", "α₁, α₂, β₁, β₂ (all)", "α₁ only"],
["Depends on NE stores?", "Yes", "No"],
["Heart rate", "↑ (β₁)", "↓ (reflex bradycardia)"],
["Cardiac output", "↑", "↓ or unchanged"],
["SVR", "↑ (variable)", "↑↑ (primary effect)"],
["Arrhythmogenicity", "Yes (β₁ stimulation)", "No"],
["CNS effects", "Stimulant (insomnia, anxiety)", "Minimal"],
["Duration (IV)", "10–60 min", "~15 min"],
["Half-life", "3–6 h", "Short (2–3 min redistribution)"],
["Tachyphylaxis mechanism", "NE depletion from terminals", "Receptor desensitisation"],
["Preferred in bradycardia?", "Yes", "No (worsens it)"],
["Preferred in tachycardia?", "No", "Yes"],
["Obstetric spinal anesthesia", "Causes fetal acidosis — less preferred", "Preferred; better fetal pH"],
["Mydriasis", "Not used", "Yes (topical)"],
["Decongestant", "Yes (oral/topical)", "Yes (oral/topical; OTC)"],
["Key interaction", "MAOIs → hypertensive crisis (indirect mechanism)", "TCAs → exaggerated hypertension"],
],
col_widths=[5*cm, 6*cm, 6*cm]
))
story.append(Spacer(1, 0.6*cm))
story.append(HRFlowable(width="100%", thickness=0.5, color=colors.grey))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"References: Morgan & Mikhail's Clinical Anesthesiology 7e | Barash, Cullen & Stoelting's Clinical Anesthesia 9e | "
"Goodman & Gilman's Pharmacological Basis of Therapeutics 14e | Katzung's Basic and Clinical Pharmacology 16e | "
"Lippincott Illustrated Reviews: Pharmacology | Miller's Anesthesia 10e",
FOOTER_TEXT
))
# BUILD
doc.build(story)
print(f"PDF saved to: {OUTPUT}")