Short notes on abnormal uterine bleeding from dc dutta
| Parameter | Normal Range |
|---|---|
| Cycle length | 24-38 days |
| Duration of flow | 4-8 days |
| Blood loss | 35-80 mL per cycle |
Heavy menstrual bleeding (HMB) = >80 mL per cycle. This leads to iron-deficiency anemia if recurrent.
| Old Term | Meaning |
|---|---|
| Menorrhagia | Regular cycle, excessive flow (>80 mL) or duration (>7 days) |
| Metrorrhagia | Irregular bleeding between periods |
| Menometrorrhagia | Irregular, excessive, and prolonged bleeding |
| Polymenorrhoea | Cycle interval <21 days |
| Oligomenorrhoea | Cycle interval >35 days |
| Intermenstrual bleeding (IMB) | Bleeding between regular menses |
| Postcoital bleeding (PCB) | Bleeding after intercourse |
| Postmenopausal bleeding (PMB) | Bleeding >1 year after last menses |
| Dysfunctional uterine bleeding (DUB) | Anovulatory or ovulatory AUB with no structural cause - term now replaced |
PALM = Structural causes
COEIN = Non-structural causes
| Letter | Cause | Key Features |
|---|---|---|
| P | Polyp (AUB-P) | Endometrial/endocervical overgrowth; sessile or pedunculated; mostly benign; up to 5% malignant transformation |
| A | Adenomyosis (AUB-A) | Endometrial glands in myometrium; bulky tender uterus; causes HMB + dysmenorrhoea |
| L | Leiomyoma (AUB-L) | Most common benign gynecologic tumor; submucosal type most likely to bleed; affects up to 70% of women by age 50 |
| M | Malignancy/Hyperplasia (AUB-M) | Must always be excluded; endometrial cancer in 90% presents with AUB |
| Letter | Cause | Key Features |
|---|---|---|
| C | Coagulopathy (AUB-C) | 5-20% of HMB cases; von Willebrand disease most common; bleeding since menarche is a red flag |
| O | Ovulatory dysfunction (AUB-O) | Most common cause in reproductive age; anovulation → no progesterone → unopposed estrogen → irregular endometrial shedding; causes include PCOS, thyroid disorders, hyperprolactinaemia, hypothalamic dysfunction, POI |
| E | Endometrial (AUB-E) | Primary endometrial disorder (e.g., defective local haemostasis); diagnosis of exclusion |
| I | Iatrogenic (AUB-I) | OCP breakthrough bleeding, anticoagulants, antipsychotics, IUD, tamoxifen |
| N | Not otherwise classified (AUB-N) | Rare causes - AV malformations, myometrial hypertrophy |
| Age Group | Common Causes |
|---|---|
| Infancy | Maternal estrogen withdrawal |
| Prepubertal | Vulvovaginitis, foreign body, precocious puberty, tumor |
| Adolescent | Anovulation, coagulopathy (von Willebrand), pregnancy, exogenous hormones |
| Reproductive | Pregnancy complications, anovulation, fibroids, polyps, thyroid disease |
| Perimenopausal | Anovulation, fibroids, polyps, thyroid dysfunction |
| Postmenopausal | Atrophy (most common), endometrial polyps, endometrial cancer |
"Abnormal uterine bleeding where no organic, systemic, or iatrogenic cause can be found" - a diagnosis of exclusion.
| Drug | Use |
|---|---|
| Combined oral contraceptives (COC) | Regulate cycle; reduce flow by 40-50% |
| Progestins (norethisterone, MPA) | Anovulatory AUB; luteal phase support |
| Levonorgestrel IUS (Mirena) | HMB - reduces flow by up to 90%; first-line for many |
| Tranexamic acid | Antifibrinolytic; reduces HMB by 40-50%; non-hormonal option |
| NSAIDs (mefenamic acid) | Reduces HMB and dysmenorrhoea via prostaglandin inhibition |
| GnRH agonists | Preoperative use to reduce fibroid size; temporary amenorrhoea |
| Danazol | Androgenic; reserved for resistant cases |
| Procedure | Indication |
|---|---|
| Endometrial ablation | HMB when family complete; destroys endometrium |
| Hysteroscopic polypectomy | Uterine polyps |
| Myomectomy | Symptomatic fibroids, fertility desired |
| Hysterectomy | Definitive; failed medical/conservative treatment, or malignancy |
Create a study guide PDF on PALM-COEIN classification
ls /home/daytona/workspace/ 2>/dev/null || echo "workspace empty or missing"
mkdir -p /home/daytona/workspace/palm-coein-guide && python3 -c "import reportla…
~/palm-coein-guide/generate_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm, mm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether, PageBreak
)
from reportlab.platypus.flowables import BalancedColumns
from reportlab.graphics.shapes import Drawing, Rect, String, Line
from reportlab.graphics import renderPDF
from reportlab.pdfbase import pdfmetrics
OUTPUT = "/home/daytona/workspace/palm-coein-guide/PALM_COEIN_Study_Guide.pdf"
# ---------- Colour palette ----------
TEAL = colors.HexColor("#0B6477")
TEAL_LIGHT = colors.HexColor("#14919B")
PALM_COL = colors.HexColor("#145369")
COEIN_COL = colors.HexColor("#0E7C86")
ACCENT = colors.HexColor("#E5F5F7")
GOLD = colors.HexColor("#D4A017")
RED_SOFT = colors.HexColor("#C0392B")
GREEN_SOFT = colors.HexColor("#1A7A4A")
WHITE = colors.white
BLACK = colors.HexColor("#1A1A2E")
GREY_LIGHT = colors.HexColor("#F4F8F9")
GREY_MID = colors.HexColor("#B0C4C8")
PAGE_BG = colors.white
W, H = A4
# ---------- Styles ----------
styles = getSampleStyleSheet()
def style(name, **kwargs):
s = ParagraphStyle(name, **kwargs)
return s
TITLE_STYLE = style("Title",
fontName="Helvetica-Bold", fontSize=26, textColor=WHITE,
alignment=TA_CENTER, leading=32, spaceAfter=4)
SUB_STYLE = style("Sub",
fontName="Helvetica", fontSize=12, textColor=colors.HexColor("#D0EEF2"),
alignment=TA_CENTER, leading=16)
SECTION_STYLE = style("Section",
fontName="Helvetica-Bold", fontSize=13, textColor=WHITE,
alignment=TA_CENTER, leading=18, spaceAfter=2)
BODY_STYLE = style("Body",
fontName="Helvetica", fontSize=9, textColor=BLACK,
leading=14, spaceAfter=3, leftIndent=4)
BODY_BOLD = style("BodyBold",
fontName="Helvetica-Bold", fontSize=9, textColor=BLACK,
leading=14, spaceAfter=2, leftIndent=4)
LABEL_STYLE = style("Label",
fontName="Helvetica-Bold", fontSize=10, textColor=TEAL,
leading=14, spaceAfter=2)
SMALL_STYLE = style("Small",
fontName="Helvetica", fontSize=8, textColor=colors.HexColor("#444444"),
leading=12, spaceAfter=2)
BULLET_STYLE = style("Bullet",
fontName="Helvetica", fontSize=9, textColor=BLACK,
leading=13, spaceAfter=2, leftIndent=12, bulletIndent=4,
bulletText="\u2022")
HEADING2 = style("Heading2",
fontName="Helvetica-Bold", fontSize=11, textColor=TEAL,
leading=16, spaceAfter=4, spaceBefore=8)
TABLE_HEADER = style("TH",
fontName="Helvetica-Bold", fontSize=9, textColor=WHITE,
alignment=TA_CENTER, leading=13)
TABLE_CELL = style("TC",
fontName="Helvetica", fontSize=8.5, textColor=BLACK,
leading=13, leftIndent=3)
TABLE_CELL_BOLD = style("TCB",
fontName="Helvetica-Bold", fontSize=8.5, textColor=BLACK,
leading=13, leftIndent=3)
NOTE_STYLE = style("Note",
fontName="Helvetica-Oblique", fontSize=8, textColor=colors.HexColor("#555555"),
leading=12, leftIndent=6, spaceAfter=2)
KEY_STYLE = style("Key",
fontName="Helvetica-Bold", fontSize=9, textColor=RED_SOFT,
leading=13, leftIndent=4, spaceAfter=2)
# ---------- Helper: coloured header bar ----------
def section_bar(text, bg=TEAL, width=W - 2*cm, height=22):
d = Drawing(width, height)
d.add(Rect(0, 0, width, height, fillColor=bg, strokeColor=None))
d.add(String(width/2, 5, text,
fontName="Helvetica-Bold", fontSize=12,
textAnchor="middle", fillColor=colors.white))
return d
def mini_bar(text, bg=TEAL_LIGHT, width=W - 2*cm, height=18):
d = Drawing(width, height)
d.add(Rect(0, 0, width, height, fillColor=bg, strokeColor=None))
d.add(String(8, 4, text,
fontName="Helvetica-Bold", fontSize=10,
textAnchor="start", fillColor=colors.white))
return d
# ---------- Letter badge ----------
def letter_badge(letter, sub, bg, size=44):
d = Drawing(size, size)
d.add(Rect(0, 0, size, size, rx=6, ry=6, fillColor=bg, strokeColor=None))
d.add(String(size/2, size*0.44, letter,
fontName="Helvetica-Bold", fontSize=24,
textAnchor="middle", fillColor=WHITE))
d.add(String(size/2, 3, sub,
fontName="Helvetica", fontSize=6.5,
textAnchor="middle", fillColor=colors.HexColor("#D0EEF2")))
return d
# ============================================================
# PAGE TEMPLATE with background & footer
# ============================================================
def on_page(canvas, doc):
canvas.saveState()
# subtle top band
canvas.setFillColor(TEAL)
canvas.rect(0, H - 8*mm, W, 8*mm, fill=1, stroke=0)
# footer
canvas.setFillColor(TEAL)
canvas.rect(0, 0, W, 7*mm, fill=1, stroke=0)
canvas.setFont("Helvetica", 7)
canvas.setFillColor(WHITE)
canvas.drawCentredString(W/2, 2.5*mm,
f"PALM-COEIN Classification | AUB Study Guide | Page {doc.page}")
canvas.restoreState()
# ============================================================
# BUILD DOCUMENT
# ============================================================
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
leftMargin=1*cm, rightMargin=1*cm,
topMargin=1.4*cm, bottomMargin=1.2*cm,
title="PALM-COEIN AUB Study Guide",
author="Orris Medical Education",
subject="Abnormal Uterine Bleeding Classification"
)
story = []
# ---- COVER SECTION ----
cover_data = Drawing(W - 2*cm, 110)
cover_data.add(Rect(0, 0, W - 2*cm, 110, rx=8, ry=8, fillColor=TEAL, strokeColor=None))
cover_data.add(String((W-2*cm)/2, 72, "PALM-COEIN",
fontName="Helvetica-Bold", fontSize=34,
textAnchor="middle", fillColor=WHITE))
cover_data.add(String((W-2*cm)/2, 50, "CLASSIFICATION OF ABNORMAL UTERINE BLEEDING",
fontName="Helvetica-Bold", fontSize=11,
textAnchor="middle", fillColor=colors.HexColor("#A8DDE4")))
cover_data.add(String((W-2*cm)/2, 30, "Complete Study Guide | FIGO 2011 | DC Dutta Gynaecology",
fontName="Helvetica", fontSize=9,
textAnchor="middle", fillColor=colors.HexColor("#D0EEF2")))
cover_data.add(String((W-2*cm)/2, 12, "Structural (PALM) + Non-Structural (COEIN) | Diagnosis | Management",
fontName="Helvetica-Oblique", fontSize=8.5,
textAnchor="middle", fillColor=colors.HexColor("#C0E8EE")))
story.append(cover_data)
story.append(Spacer(1, 8))
# ---- QUICK DEFINITION BOX ----
def_tbl = Table(
[[Paragraph(
"<b>Definition:</b> AUB is any uterine bleeding that is abnormal in <b>regularity, frequency, duration, or volume</b>, "
"unrelated to pregnancy. Replaces older terms: menorrhagia, metrorrhagia, menometrorrhagia, DUB.",
BODY_STYLE)]],
colWidths=[W - 2*cm]
)
def_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), ACCENT),
("BOX", (0,0), (-1,-1), 1, TEAL),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
]))
story.append(def_tbl)
story.append(Spacer(1, 6))
# ---- NORMAL MENSTRUAL PARAMETERS ----
story.append(mini_bar(" Normal Menstrual Parameters", bg=TEAL_LIGHT))
story.append(Spacer(1, 3))
param_data = [
[Paragraph("<b>Parameter</b>", TABLE_HEADER),
Paragraph("<b>Normal Range</b>", TABLE_HEADER),
Paragraph("<b>Abnormal if</b>", TABLE_HEADER)],
[Paragraph("Cycle Length", TABLE_CELL_BOLD),
Paragraph("24 - 38 days", TABLE_CELL),
Paragraph("<8 days (frequent) or >38 days (infrequent)", TABLE_CELL)],
[Paragraph("Duration of Flow", TABLE_CELL_BOLD),
Paragraph("4 - 8 days", TABLE_CELL),
Paragraph(">8 days (prolonged) or <4 days (shortened)", TABLE_CELL)],
[Paragraph("Volume / Blood Loss", TABLE_CELL_BOLD),
Paragraph("5 - 80 mL per cycle (mean 35 mL)", TABLE_CELL),
Paragraph(">80 mL = Heavy Menstrual Bleeding (HMB)", TABLE_CELL)],
[Paragraph("Regularity", TABLE_CELL_BOLD),
Paragraph("Regular (±2-20 days variation)", TABLE_CELL),
Paragraph("Irregular if variation >20 days", TABLE_CELL)],
]
param_tbl = Table(param_data, colWidths=[4.5*cm, 5*cm, 9*cm])
param_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), PALM_COL),
("BACKGROUND", (0,1), (-1,1), GREY_LIGHT),
("BACKGROUND", (0,2), (-1,2), WHITE),
("BACKGROUND", (0,3), (-1,3), GREY_LIGHT),
("BACKGROUND", (0,4), (-1,4), WHITE),
("BOX", (0,0), (-1,-1), 0.5, GREY_MID),
("INNERGRID", (0,0), (-1,-1), 0.3, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(param_tbl)
story.append(Spacer(1, 8))
# ====================================================
# THE PALM-COEIN ACRONYM VISUAL
# ====================================================
story.append(section_bar(" THE PALM-COEIN ACRONYM", bg=PALM_COL))
story.append(Spacer(1, 5))
acronym_data = [
[Paragraph("<b>STRUCTURAL CAUSES (PALM)</b>", TABLE_HEADER),
Paragraph("<b>NON-STRUCTURAL CAUSES (COEIN)</b>", TABLE_HEADER)],
[
Table([
[letter_badge("P","Polyp", TEAL), Paragraph("<b>P</b> — Polyp (AUB-P)", LABEL_STYLE)],
[letter_badge("A","Adenomyosis", TEAL), Paragraph("<b>A</b> — Adenomyosis (AUB-A)", LABEL_STYLE)],
[letter_badge("L","Leiomyoma", TEAL), Paragraph("<b>L</b> — Leiomyoma (AUB-L)", LABEL_STYLE)],
[letter_badge("M","Malignancy", TEAL), Paragraph("<b>M</b> — Malignancy/Hyperplasia (AUB-M)", LABEL_STYLE)],
], colWidths=[1.2*cm, 7.7*cm]),
Table([
[letter_badge("C","Coagulopathy", COEIN_COL), Paragraph("<b>C</b> — Coagulopathy (AUB-C)", LABEL_STYLE)],
[letter_badge("O","Ovulatory", COEIN_COL), Paragraph("<b>O</b> — Ovulatory Dysfunction (AUB-O)", LABEL_STYLE)],
[letter_badge("E","Endometrial", COEIN_COL), Paragraph("<b>E</b> — Endometrial (AUB-E)", LABEL_STYLE)],
[letter_badge("I","Iatrogenic", COEIN_COL), Paragraph("<b>I</b> — Iatrogenic (AUB-I)", LABEL_STYLE)],
[letter_badge("N","Not Classified", COEIN_COL), Paragraph("<b>N</b> — Not Otherwise Classified (AUB-N)", LABEL_STYLE)],
], colWidths=[1.2*cm, 7.7*cm]),
]
]
acronym_tbl = Table(acronym_data, colWidths=[(W-2*cm)/2, (W-2*cm)/2])
acronym_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), PALM_COL),
("BACKGROUND", (1,0), (1,0), COEIN_COL),
("BOX", (0,0), (-1,-1), 0.5, GREY_MID),
("INNERGRID", (0,0), (-1,-1), 0.3, GREY_MID),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
]))
story.append(acronym_tbl)
story.append(Spacer(1, 8))
# ====================================================
# PALM - DETAILED TABLE
# ====================================================
story.append(section_bar(" PALM — STRUCTURAL CAUSES (Diagnosed by Imaging / Histology)", bg=PALM_COL))
story.append(Spacer(1, 4))
palm_data = [
[Paragraph("<b>Category</b>", TABLE_HEADER),
Paragraph("<b>Definition</b>", TABLE_HEADER),
Paragraph("<b>Clinical Features</b>", TABLE_HEADER),
Paragraph("<b>Key Points</b>", TABLE_HEADER)],
[Paragraph("AUB-P\nPolyp", TABLE_CELL_BOLD),
Paragraph("Benign overgrowth of endometrial glands + stroma; sessile or pedunculated", TABLE_CELL),
Paragraph("IMB, PCB, heavy periods; often asymptomatic; diagnosed by TVS/hysteroscopy", TABLE_CELL),
Paragraph("Up to 5% malignant transformation\nAssociated with tamoxifen, obesity, PCOS", TABLE_CELL)],
[Paragraph("AUB-A\nAdenomyosis", TABLE_CELL_BOLD),
Paragraph("Endometrial glands & stroma within myometrium (>2.5 mm from basalis)", TABLE_CELL),
Paragraph("Bulky, tender, globular uterus; progressive dysmenorrhoea; HMB; secondary dysmenorrhoea", TABLE_CELL),
Paragraph("Definitive Dx: histology post-hysterectomy\nMRI best imaging modality", TABLE_CELL)],
[Paragraph("AUB-L\nLeiomyoma\n(Fibroids)", TABLE_CELL_BOLD),
Paragraph("Benign smooth muscle tumours from myometrium\nType 0-8 (FIGO fibroid classification)", TABLE_CELL),
Paragraph("Most common benign GU tumor (70% by age 50)\nSubmucosal (Type 0-2) → most likely to bleed", TABLE_CELL),
Paragraph("Predominantly in Black women\nRx: Mirena, GnRH agonist, myomectomy, UAE, hysterectomy", TABLE_CELL)],
[Paragraph("AUB-M\nMalignancy /\nHyperplasia", TABLE_CELL_BOLD),
Paragraph("Endometrial hyperplasia (simple/complex, with/without atypia) or carcinoma", TABLE_CELL),
Paragraph("90% of endometrial Ca presents with AUB/PMB\nRisk: obesity, PCOS, unopposed estrogen, Lynch syndrome", TABLE_CELL),
Paragraph("MUST EXCLUDE in women >45 or with risk factors\nEndometrial biopsy mandatory", TABLE_CELL)],
]
palm_tbl = Table(palm_data, colWidths=[2.3*cm, 4.8*cm, 5.5*cm, 5.9*cm])
palm_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), PALM_COL),
("BACKGROUND", (0,1), (-1,1), GREY_LIGHT),
("BACKGROUND", (0,2), (-1,2), WHITE),
("BACKGROUND", (0,3), (-1,3), GREY_LIGHT),
("BACKGROUND", (0,4), (-1,4), WHITE),
("BOX", (0,0), (-1,-1), 0.5, GREY_MID),
("INNERGRID", (0,0), (-1,-1), 0.3, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("TEXTCOLOR", (0,1), (0,-1), PALM_COL),
]))
story.append(palm_tbl)
story.append(Spacer(1, 8))
# ====================================================
# COEIN - DETAILED TABLE
# ====================================================
story.append(section_bar(" COEIN — NON-STRUCTURAL CAUSES (Medical / Hormonal)", bg=COEIN_COL))
story.append(Spacer(1, 4))
coein_data = [
[Paragraph("<b>Category</b>", TABLE_HEADER),
Paragraph("<b>Definition</b>", TABLE_HEADER),
Paragraph("<b>Clinical Features / Examples</b>", TABLE_HEADER),
Paragraph("<b>Key Points</b>", TABLE_HEADER)],
[Paragraph("AUB-C\nCoagulopathy", TABLE_CELL_BOLD),
Paragraph("Systemic disorder of haemostasis causing HMB", TABLE_CELL),
Paragraph("von Willebrand disease (most common)\nITP, haemophilia carrier, liver disease, anticoagulants", TABLE_CELL),
Paragraph("5-20% of HMB cases\nRed flag: HMB since menarche\nScreen: CBC, PT, aPTT, VWF Ag + activity", TABLE_CELL)],
[Paragraph("AUB-O\nOvulatory\nDysfunction", TABLE_CELL_BOLD),
Paragraph("Absent/abnormal ovulation → no progesterone → unopposed estrogen → irregular endometrial shedding", TABLE_CELL),
Paragraph("PCOS, hypothyroidism, hyperprolactinaemia\nHypothalamic dysfunction, POI, obesity\nCommon at extremes of reproductive life", TABLE_CELL),
Paragraph("Most common cause in reproductive age\nEstrogen breakthrough bleeding mechanism\nAmenorrhoea → acute heavy bleed pattern", TABLE_CELL)],
[Paragraph("AUB-E\nEndometrial", TABLE_CELL_BOLD),
Paragraph("Primary endometrial haemostatic defect despite normal ovulation and no structural pathology", TABLE_CELL),
Paragraph("Regular but heavy periods (HMB)\nAbnormal prostaglandin / fibrinolytic balance\nExcess PGE2 / prostacyclin (vasodilators)", TABLE_CELL),
Paragraph("Diagnosis of EXCLUSION\nNormal endometrial biopsy\nRx: tranexamic acid, NSAIDs", TABLE_CELL)],
[Paragraph("AUB-I\nIatrogenic", TABLE_CELL_BOLD),
Paragraph("Bleeding attributable to exogenous hormonal / pharmacological agents or devices", TABLE_CELL),
Paragraph("OCPs / Progestins: breakthrough bleeding\nAnticoagulants (warfarin, DOAC)\nAntipsychotics → hyperprolactinaemia\nCopper/LNG-IUD\nTamoxifen", TABLE_CELL),
Paragraph("Always take a thorough drug history\nChlamydia screen if irregular OCP bleeding\nAdjust/stop offending agent if possible", TABLE_CELL)],
[Paragraph("AUB-N\nNot Otherwise\nClassified", TABLE_CELL_BOLD),
Paragraph("Rare / poorly understood causes not fitting other categories", TABLE_CELL),
Paragraph("Arteriovenous malformations (AVM)\nMyometrial hypertrophy\nCervicitis, endometritis", TABLE_CELL),
Paragraph("Rare but important to consider\nAVM diagnosed on Doppler USS / MRI\nRx: uterine artery embolisation", TABLE_CELL)],
]
coein_tbl = Table(coein_data, colWidths=[2.3*cm, 4.5*cm, 5.7*cm, 6*cm])
coein_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), COEIN_COL),
("BACKGROUND", (0,1), (-1,1), GREY_LIGHT),
("BACKGROUND", (0,2), (-1,2), WHITE),
("BACKGROUND", (0,3), (-1,3), GREY_LIGHT),
("BACKGROUND", (0,4), (-1,4), WHITE),
("BACKGROUND", (0,5), (-1,5), GREY_LIGHT),
("BOX", (0,0), (-1,-1), 0.5, GREY_MID),
("INNERGRID", (0,0), (-1,-1), 0.3, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("TEXTCOLOR", (0,1), (0,-1), COEIN_COL),
]))
story.append(coein_tbl)
story.append(Spacer(1, 8))
# ====================================================
# CAUSES BY AGE + MECHANISM OF ANOVULATORY BLEEDING
# ====================================================
story.append(section_bar(" CAUSES BY AGE GROUP", bg=TEAL))
story.append(Spacer(1, 4))
age_data = [
[Paragraph("<b>Age Group</b>", TABLE_HEADER),
Paragraph("<b>Common Causes</b>", TABLE_HEADER),
Paragraph("<b>Priority Concern</b>", TABLE_HEADER)],
[Paragraph("Neonatal / Infancy", TABLE_CELL_BOLD),
Paragraph("Maternal estrogen withdrawal", TABLE_CELL),
Paragraph("Physiological; self-limiting", TABLE_CELL)],
[Paragraph("Prepubertal", TABLE_CELL_BOLD),
Paragraph("Vulvovaginitis, foreign body, precocious puberty, tumor", TABLE_CELL),
Paragraph("Rule out abuse / tumor", TABLE_CELL)],
[Paragraph("Adolescent", TABLE_CELL_BOLD),
Paragraph("Anovulation (most common), coagulopathy (vWD), pregnancy, exogenous hormones", TABLE_CELL),
Paragraph("HMB since menarche → screen coagulopathy", TABLE_CELL)],
[Paragraph("Reproductive Age", TABLE_CELL_BOLD),
Paragraph("Pregnancy, anovulation, fibroids, polyps, thyroid, PCOS, exogenous hormones", TABLE_CELL),
Paragraph("Always exclude pregnancy first", TABLE_CELL)],
[Paragraph("Perimenopausal", TABLE_CELL_BOLD),
Paragraph("Anovulation, fibroids, polyps, thyroid dysfunction", TABLE_CELL),
Paragraph("Endometrial biopsy if ≥45 yrs", TABLE_CELL)],
[Paragraph("Postmenopausal", TABLE_CELL_BOLD),
Paragraph("Atrophy (most common), polyps, HRT, endometrial cancer", TABLE_CELL),
Paragraph("ALL PMB = abnormal → biopsy if ET >4 mm", TABLE_CELL)],
]
age_tbl = Table(age_data, colWidths=[3.5*cm, 8*cm, 7*cm])
age_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), TEAL),
("ROWBACKGROUNDS", (0,1), (-1,-1), [GREY_LIGHT, WHITE]),
("BOX", (0,0), (-1,-1), 0.5, GREY_MID),
("INNERGRID", (0,0), (-1,-1), 0.3, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(age_tbl)
story.append(Spacer(1, 8))
# ====================================================
# MECHANISM OF ANOVULATORY DUB
# ====================================================
story.append(mini_bar(" Mechanism of Anovulatory Bleeding (AUB-O)", bg=TEAL))
story.append(Spacer(1, 4))
mech_data = [
[Paragraph(
"<b>No Ovulation</b> → <b>No Corpus Luteum</b> → <b>No Progesterone</b> → "
"<b>Unopposed Estrogen</b> → <b>Endometrial Proliferation</b> → "
"<b>Irregular / Fragile Shedding</b>",
style("Mech", fontName="Helvetica-Bold", fontSize=9, textColor=TEAL,
leading=16, alignment=TA_CENTER)
)]
]
mech_tbl = Table(mech_data, colWidths=[W - 2*cm])
mech_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), ACCENT),
("BOX", (0,0), (-1,-1), 1, TEAL_LIGHT),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 12),
("RIGHTPADDING", (0,0), (-1,-1), 12),
]))
story.append(mech_tbl)
story.append(Spacer(1, 4))
detail_mech = [
[Paragraph("Low estrogen levels:", BODY_BOLD),
Paragraph("Irregular prolonged spotting", BODY_STYLE)],
[Paragraph("High sustained estrogen:", BODY_BOLD),
Paragraph("Amenorrhoea followed by sudden, acute heavy bleeding", BODY_STYLE)],
[Paragraph("Ovulatory DUB (20%):", BODY_BOLD),
Paragraph("Normal cycles but excess PGE2/prostacyclin → impaired platelet plug → HMB", BODY_STYLE)],
]
dm_tbl = Table(detail_mech, colWidths=[5*cm, 13.5*cm])
dm_tbl.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 2),
("BOTTOMPADDING", (0,0), (-1,-1), 2),
]))
story.append(dm_tbl)
story.append(Spacer(1, 8))
# ====================================================
# PAGE 2 - INVESTIGATIONS & MANAGEMENT
# ====================================================
story.append(PageBreak())
story.append(section_bar(" INVESTIGATIONS — STEP-BY-STEP APPROACH", bg=PALM_COL))
story.append(Spacer(1, 5))
inv_data = [
[Paragraph("<b>Step</b>", TABLE_HEADER),
Paragraph("<b>Investigation</b>", TABLE_HEADER),
Paragraph("<b>Rationale</b>", TABLE_HEADER)],
[Paragraph("1 (Always First)", TABLE_CELL_BOLD),
Paragraph("Urine / serum beta-hCG (Pregnancy Test)", TABLE_CELL),
Paragraph("Exclude ectopic pregnancy, abortion, GTD before all else", TABLE_CELL)],
[Paragraph("2 (Haematology)", TABLE_CELL_BOLD),
Paragraph("CBC (Hb, platelets, WBC)", TABLE_CELL),
Paragraph("Detect anaemia from HMB; thrombocytopenia (ITP)", TABLE_CELL)],
[Paragraph("3 (Endocrine)", TABLE_CELL_BOLD),
Paragraph("TSH, Prolactin, LH/FSH, AMH (if indicated)", TABLE_CELL),
Paragraph("Thyroid dysfunction, hyperprolactinaemia, POI, PCOS evaluation", TABLE_CELL)],
[Paragraph("4 (Coagulation)", TABLE_CELL_BOLD),
Paragraph("PT, aPTT, VWF antigen + activity, Factor VIII, fibrinogen", TABLE_CELL),
Paragraph("If HMB since menarche, family Hx bleeding, easy bruising, epistaxis", TABLE_CELL)],
[Paragraph("5 (Infection)", TABLE_CELL_BOLD),
Paragraph("Cervical swab / NAAT for Chlamydia, gonorrhoea; Pap smear", TABLE_CELL),
Paragraph("Exclude cervicitis, endometritis, cervical cancer", TABLE_CELL)],
[Paragraph("6 (Imaging)", TABLE_CELL_BOLD),
Paragraph("Transvaginal USS (TVS) — first-line imaging", TABLE_CELL),
Paragraph("Assess endometrial thickness, fibroids, polyps, adnexa; ET >4 mm PMB → biopsy", TABLE_CELL)],
[Paragraph("7 (Specialised)", TABLE_CELL_BOLD),
Paragraph("Sonohysterography / Saline Infusion Sonography (SIS)", TABLE_CELL),
Paragraph("Best for intracavitary lesions (polyps, submucosal fibroids)", TABLE_CELL)],
[Paragraph("8 (Histology)", TABLE_CELL_BOLD),
Paragraph("Endometrial biopsy (Pipelle) / Hysteroscopy + D&C", TABLE_CELL),
Paragraph("Mandatory: age ≥45; <45 with obesity, PCOS, persistent AUB, Lynch syndrome risk", TABLE_CELL)],
[Paragraph("9 (Imaging Plus)", TABLE_CELL_BOLD),
Paragraph("MRI pelvis (if USS inconclusive)", TABLE_CELL),
Paragraph("Best for adenomyosis characterisation; fibroid mapping pre-surgery", TABLE_CELL)],
]
inv_tbl = Table(inv_data, colWidths=[3.2*cm, 6.5*cm, 8.8*cm])
inv_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), PALM_COL),
("ROWBACKGROUNDS", (0,1), (-1,-1), [GREY_LIGHT, WHITE]),
("BOX", (0,0), (-1,-1), 0.5, GREY_MID),
("INNERGRID", (0,0), (-1,-1), 0.3, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(inv_tbl)
story.append(Spacer(1, 8))
# ====================================================
# MANAGEMENT
# ====================================================
story.append(section_bar(" MANAGEMENT OF AUB", bg=COEIN_COL))
story.append(Spacer(1, 5))
# Medical
story.append(mini_bar(" Medical Treatment", bg=TEAL_LIGHT))
story.append(Spacer(1, 3))
med_data = [
[Paragraph("<b>Drug / Intervention</b>", TABLE_HEADER),
Paragraph("<b>Mechanism</b>", TABLE_HEADER),
Paragraph("<b>Efficacy / Notes</b>", TABLE_HEADER)],
[Paragraph("Levonorgestrel IUS (Mirena)", TABLE_CELL_BOLD),
Paragraph("Local progestin → endometrial atrophy", TABLE_CELL),
Paragraph("Reduces HMB by up to 90%; first-line for HMB; also contraception", TABLE_CELL)],
[Paragraph("Tranexamic Acid", TABLE_CELL_BOLD),
Paragraph("Antifibrinolytic → stabilises clot", TABLE_CELL),
Paragraph("Reduces HMB by 40-50%; non-hormonal; take during menses only", TABLE_CELL)],
[Paragraph("NSAIDs (Mefenamic acid, Ibuprofen)", TABLE_CELL_BOLD),
Paragraph("PG synthetase inhibitor → reduces PGE2/prostacyclin", TABLE_CELL),
Paragraph("Reduces HMB by 20-50%; also treats dysmenorrhoea", TABLE_CELL)],
[Paragraph("Combined OCP (COCP)", TABLE_CELL_BOLD),
Paragraph("Suppress HPO axis → regular withdrawal bleeds", TABLE_CELL),
Paragraph("Reduces HMB by 40-50%; regulates cycle; also contraception", TABLE_CELL)],
[Paragraph("Progestins (Norethisterone, MPA, Dydrogesterone)", TABLE_CELL_BOLD),
Paragraph("Oppose estrogen → stabilise endometrium", TABLE_CELL),
Paragraph("Oral: D5-D26 for anovulatory AUB; less effective than Mirena for HMB", TABLE_CELL)],
[Paragraph("GnRH Agonists (Leuprolide, Goserelin)", TABLE_CELL_BOLD),
Paragraph("Down-regulate HPO → hypo-oestrogenic state → amenorrhoea", TABLE_CELL),
Paragraph("Short-term (3-6 months); pre-op fibroid shrinkage; add-back HRT needed", TABLE_CELL)],
[Paragraph("Danazol", TABLE_CELL_BOLD),
Paragraph("Androgen; suppresses FSH/LH; androgenic endometrium", TABLE_CELL),
Paragraph("Effective but androgenic SE (acne, hirsutism); reserved for resistant cases", TABLE_CELL)],
]
med_tbl = Table(med_data, colWidths=[4.5*cm, 5.5*cm, 8.5*cm])
med_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), COEIN_COL),
("ROWBACKGROUNDS", (0,1), (-1,-1), [GREY_LIGHT, WHITE]),
("BOX", (0,0), (-1,-1), 0.5, GREY_MID),
("INNERGRID", (0,0), (-1,-1), 0.3, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(med_tbl)
story.append(Spacer(1, 6))
# Surgical
story.append(mini_bar(" Surgical Treatment", bg=TEAL))
story.append(Spacer(1, 3))
surg_data = [
[Paragraph("<b>Procedure</b>", TABLE_HEADER),
Paragraph("<b>Indication</b>", TABLE_HEADER),
Paragraph("<b>Notes</b>", TABLE_HEADER)],
[Paragraph("Endometrial Ablation", TABLE_CELL_BOLD),
Paragraph("HMB with failed medical Rx; family complete", TABLE_CELL),
Paragraph("Destroys endometrium; 80% amenorrhoea/hypomenorrhoea; day procedure", TABLE_CELL)],
[Paragraph("Hysteroscopic Polypectomy", TABLE_CELL_BOLD),
Paragraph("Endometrial / endocervical polyps", TABLE_CELL),
Paragraph("Outpatient; resectoscope; send polyp for histology", TABLE_CELL)],
[Paragraph("Myomectomy", TABLE_CELL_BOLD),
Paragraph("Symptomatic fibroids, fertility desired", TABLE_CELL),
Paragraph("Abdominal / laparoscopic / hysteroscopic (Type 0-2 fibroids)", TABLE_CELL)],
[Paragraph("Uterine Artery Embolisation (UAE)", TABLE_CELL_BOLD),
Paragraph("Symptomatic fibroids / AVM; uterus preservation desired", TABLE_CELL),
Paragraph("Interventional radiology; 85-90% symptom improvement", TABLE_CELL)],
[Paragraph("Hysterectomy", TABLE_CELL_BOLD),
Paragraph("Definitive; failed conservative Rx; malignancy", TABLE_CELL),
Paragraph("Total / subtotal; abdominal, laparoscopic or vaginal approach", TABLE_CELL)],
]
surg_tbl = Table(surg_data, colWidths=[4.5*cm, 5.5*cm, 8.5*cm])
surg_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), TEAL),
("ROWBACKGROUNDS", (0,1), (-1,-1), [GREY_LIGHT, WHITE]),
("BOX", (0,0), (-1,-1), 0.5, GREY_MID),
("INNERGRID", (0,0), (-1,-1), 0.3, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(surg_tbl)
story.append(Spacer(1, 8))
# ====================================================
# PAGE 3 - HIGH YIELD EXAM NOTES
# ====================================================
story.append(PageBreak())
story.append(section_bar(" HIGH-YIELD EXAM POINTS", bg=colors.HexColor("#8B0000")))
story.append(Spacer(1, 5))
# Two column layout
left_col = []
right_col = []
left_col.append(Paragraph("Classic DC Dutta exam facts:", HEADING2))
left_items = [
("DUB definition", "Abnormal uterine bleeding with NO organic, systemic, or iatrogenic cause — diagnosis of exclusion"),
("DUB most common type", "Anovulatory (80%); common at extremes of reproductive life"),
("Most common cause HMB", "Uterine fibroids (leiomyoma) in reproductive age"),
("Most common cause PMB", "Endometrial atrophy"),
("Most common coagulopathy", "von Willebrand Disease (5-20% of HMB)"),
("Estrogen breakthrough", "Low estrogen → irregular spotting; High estrogen → sudden heavy bleed"),
("Hormone in anovulatory DUB", "No progesterone; unopposed estrogen"),
("PALM-COEIN origin", "FIGO 2011; replaced all old terminology"),
("Term now abandoned", "DUB, menorrhagia, metrorrhagia, menometrorrhagia"),
("HMB definition", ">80 mL/cycle or soaking a pad/tampon every hour for 2+ consecutive hours"),
("Most effective medical Rx", "LNG-IUS (Mirena) — reduces flow up to 90%"),
("Best initial imaging", "Transvaginal Ultrasound (TVS)"),
("Biopsy mandatory in", "Women ≥45 yrs with AUB; ANY postmenopausal bleeding with ET >4 mm"),
]
for title, fact in left_items:
left_col.append(Table(
[[Paragraph(title, TABLE_CELL_BOLD), Paragraph(fact, TABLE_CELL)]],
colWidths=[4.5*cm, 5.5*cm]
))
right_col.append(Paragraph("Quick mnemonics & differentials:", HEADING2))
right_col.append(Table(
[[Paragraph(
"<b>PALM</b> = Structural (seen on imaging/histology)<br/>"
"<b>COEIN</b> = Non-structural (medical/hormonal)<br/><br/>"
"<b>P</b>olyp → Pedunculated or sessile; feeder vessel on Doppler<br/>"
"<b>A</b>denomyosis → Boggy, tender, enlarged uterus<br/>"
"<b>L</b>eiomyoma → Submucosal bleeds most<br/>"
"<b>M</b>alignancy → Must always exclude!<br/><br/>"
"<b>C</b>oagulopathy → vWD, ITP, liver disease<br/>"
"<b>O</b>vulatory dysfunction → PCOS, thyroid, prolactin<br/>"
"<b>E</b>ndometrial → excess PGE2, fibrinolysis<br/>"
"<b>I</b>atrogenic → OCP, warfarin, antipsychotics, IUD<br/>"
"<b>N</b>ot classified → AVM, myometrial hypertrophy",
style("Mnemo", fontName="Helvetica", fontSize=8.5, textColor=BLACK,
leading=15, leftIndent=5)
)]],
colWidths=[10*cm]
))
right_col.append(Spacer(1, 8))
right_col.append(Paragraph("Postmenopausal Bleeding - Key Rules:", HEADING2))
right_col.append(Table(
[[Paragraph(
"1. ANY PMB must be investigated<br/>"
"2. Most common cause: ATROPHY<br/>"
"3. Most feared cause: ENDOMETRIAL CANCER<br/>"
" (90% of Ca endometrium presents with PMB)<br/>"
"4. ET ≤4 mm on TVS → biopsy may be avoided<br/>"
"5. ET >4 mm → endometrial biopsy MANDATORY<br/>"
"6. Caution: 4 mm cutoff may miss Ca in Black patients<br/>"
"7. Persistent bleeding despite normal USS → biopsy",
style("PMB", fontName="Helvetica", fontSize=8.5, textColor=BLACK,
leading=15, leftIndent=5)
)]],
colWidths=[10*cm]
))
right_col[-1].setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), colors.HexColor("#FFF3F3")),
("BOX", (0,0), (-1,-1), 0.8, RED_SOFT),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
for item in left_items:
pass
# Rebuild left column as a single table
left_table_data = [[Paragraph("<b>Topic</b>", TABLE_HEADER), Paragraph("<b>Key Point</b>", TABLE_HEADER)]]
for title, fact in left_items:
left_table_data.append([Paragraph(title, TABLE_CELL_BOLD), Paragraph(fact, TABLE_CELL)])
left_table = Table(left_table_data, colWidths=[4.5*cm, 5.5*cm])
left_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), colors.HexColor("#8B0000")),
("ROWBACKGROUNDS", (0,1), (-1,-1), [GREY_LIGHT, WHITE]),
("BOX", (0,0), (-1,-1), 0.5, GREY_MID),
("INNERGRID", (0,0), (-1,-1), 0.3, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
right_mnemo = Table([[Paragraph(
"<b>PALM</b> = Structural (seen on imaging/histology)<br/>"
"<b>COEIN</b> = Non-structural (medical/hormonal)<br/><br/>"
"<b>P</b>olyp → Pedunculated or sessile; feeder vessel on Doppler<br/>"
"<b>A</b>denomyosis → Boggy, tender, globular uterus<br/>"
"<b>L</b>eiomyoma → Submucosal type bleeds most<br/>"
"<b>M</b>alignancy → Must ALWAYS be excluded!<br/><br/>"
"<b>C</b>oagulopathy → vWD (most common), ITP, liver Dx<br/>"
"<b>O</b>vulatory dysfunction → PCOS, thyroid, prolactin, POI<br/>"
"<b>E</b>ndometrial → abnormal PGE2/fibrinolytic activity<br/>"
"<b>I</b>atrogenic → OCP, warfarin, antipsychotics, IUD, tamoxifen<br/>"
"<b>N</b>ot classified → AVM, myometrial hypertrophy",
style("Mnemo2", fontName="Helvetica", fontSize=8.5, textColor=BLACK, leading=15, leftIndent=5)
)]], colWidths=[9.5*cm])
right_mnemo.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), ACCENT),
("BOX", (0,0), (-1,-1), 0.8, TEAL),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
right_pmb = Table([[Paragraph(
"<b>Postmenopausal Bleeding Rules:</b><br/>"
"1. ANY PMB = abnormal; MUST investigate<br/>"
"2. Most common cause: ENDOMETRIAL ATROPHY<br/>"
"3. Most feared: ENDOMETRIAL CANCER (90% present with AUB)<br/>"
"4. TVS ET ≤4 mm → biopsy may be deferred<br/>"
"5. TVS ET >4 mm OR persistent bleeding → BIOPSY mandatory<br/>"
"6. Note: 4 mm cutoff may under-diagnose Ca in Black patients",
style("PMB2", fontName="Helvetica", fontSize=8.5, textColor=BLACK, leading=15, leftIndent=5)
)]], colWidths=[9.5*cm])
right_pmb.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), colors.HexColor("#FFF3F3")),
("BOX", (0,0), (-1,-1), 0.8, RED_SOFT),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
two_col = Table(
[[
Table([[Paragraph("Classic Exam Facts:", HEADING2)], [left_table]], colWidths=[10.5*cm]),
Table([
[Paragraph("Quick Mnemonics:", HEADING2)],
[right_mnemo],
[Spacer(1, 6)],
[Paragraph("Postmenopausal Bleeding:", HEADING2)],
[right_pmb],
], colWidths=[9.5*cm])
]],
colWidths=[10.5*cm, 9.5*cm]
)
two_col.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "TOP"),
("LEFTPADDING", (0,0), (-1,-1), 0),
("RIGHTPADDING", (0,0), (-1,-1), 0),
("TOPPADDING", (0,0), (-1,-1), 0),
("BOTTOMPADDING", (0,0), (-1,-1), 0),
("COLPADDING", (0,0), (-1,-1), 4),
]))
story.append(two_col)
story.append(Spacer(1, 8))
# ====================================================
# OLD TERMINOLOGY TABLE
# ====================================================
story.append(mini_bar(" Old Terminology (Now Replaced by PALM-COEIN)", bg=TEAL))
story.append(Spacer(1, 4))
old_data = [
[Paragraph("<b>Old Term</b>", TABLE_HEADER),
Paragraph("<b>Meaning</b>", TABLE_HEADER),
Paragraph("<b>Status</b>", TABLE_HEADER)],
[Paragraph("Menorrhagia", TABLE_CELL_BOLD),
Paragraph("Regular cycle, excessive flow (>80 mL) or duration (>7 days)", TABLE_CELL),
Paragraph("Replaced by 'Heavy Menstrual Bleeding (HMB)'", TABLE_CELL)],
[Paragraph("Metrorrhagia", TABLE_CELL_BOLD),
Paragraph("Irregular bleeding between periods", TABLE_CELL),
Paragraph("Replaced by 'Intermenstrual Bleeding (IMB)'", TABLE_CELL)],
[Paragraph("Menometrorrhagia", TABLE_CELL_BOLD),
Paragraph("Irregular, excessive, prolonged bleeding", TABLE_CELL),
Paragraph("Abandoned; describe by FIGO parameters", TABLE_CELL)],
[Paragraph("Polymenorrhoea", TABLE_CELL_BOLD),
Paragraph("Cycle interval <21 days", TABLE_CELL),
Paragraph("Replaced by 'Frequent menstruation'", TABLE_CELL)],
[Paragraph("Oligomenorrhoea", TABLE_CELL_BOLD),
Paragraph("Cycle interval >35 days", TABLE_CELL),
Paragraph("Replaced by 'Infrequent menstruation'", TABLE_CELL)],
[Paragraph("Dysfunctional Uterine Bleeding (DUB)", TABLE_CELL_BOLD),
Paragraph("AUB with no structural/systemic cause; diagnosis of exclusion", TABLE_CELL),
Paragraph("ABANDONED — covered by AUB-O, AUB-E in PALM-COEIN", TABLE_CELL)],
[Paragraph("Postcoital Bleeding (PCB)", TABLE_CELL_BOLD),
Paragraph("Bleeding after intercourse", TABLE_CELL),
Paragraph("Still used; evaluate cervix (polyp, cervicitis, Ca cervix)", TABLE_CELL)],
]
old_tbl = Table(old_data, colWidths=[4*cm, 7*cm, 7.5*cm])
old_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), TEAL),
("ROWBACKGROUNDS", (0,1), (-1,-1), [GREY_LIGHT, WHITE]),
("BOX", (0,0), (-1,-1), 0.5, GREY_MID),
("INNERGRID", (0,0), (-1,-1), 0.3, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TEXTCOLOR", (2,7), (2,7), colors.HexColor("#555555")),
]))
story.append(old_tbl)
story.append(Spacer(1, 8))
# ====================================================
# QUICK REFERENCE FOOTER BOX
# ====================================================
footer_box = Table([[Paragraph(
"<b>Source:</b> Berek & Novak's Gynecology | DC Dutta's Textbook of Gynaecology | "
"Sabiston Textbook of Surgery | FIGO Working Group on Menstrual Disorders (2011) | "
"<b>Classification valid for non-pregnant, reproductive-age women</b>",
style("Footer", fontName="Helvetica-Oblique", fontSize=7.5, textColor=colors.HexColor("#444"),
leading=12, alignment=TA_CENTER)
)]], colWidths=[W - 2*cm])
footer_box.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), GREY_LIGHT),
("BOX", (0,0), (-1,-1), 0.5, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
story.append(footer_box)
# ====================================================
# BUILD
# ====================================================
doc.build(story, onFirstPage=on_page, onLaterPages=on_page)
print(f"PDF created: {OUTPUT}")
cd /home/daytona/workspace/palm-coein-guide && python3 generate_pdf.py 2>&1
ls -lh /home/daytona/workspace/palm-coein-guide/PALM_COEIN_Study_Guide.pdf
PALM COEIN Study Guide
PDF Document · PDF