INDUCTION OF LABOUR. When and why and methods to use

Reading File
Finding Sources
Searching PubMed

"induction of labor" indications methods

Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Reading File
Reading File
Reading File
Reading File
Searching Images

induction of labour methods oxytocin misoprostol cervical ripening Bishop score

This diagnostic image is a transvaginal ultrasound in a sagittal plane focusing on the cervix during a gynecological/obstetric evaluation. The grayscale sonogram displays the anatomical structures of the cervix, including the hypoechoic (dark) cervical canal and the internal os. A linear measurement is performed across the internal cervical os, indicated by a green dotted line with calipers. The ultrasound software overlay shows a measurement value of 'L 2.27 cm', representing the diameter of the internal os opening. This measurement is clinically significant for assessing cervical ripening or the progress of labor induction, often used in conjunction with the Bishop score to predict successful cervical maturation. The anatomical orientation shows the superior uterine cavity transitioning into the cervical canal toward the lower external os. The image serves as an educational example of sonographic cervical assessment in an obstetrical context.

This diagnostic image is a transvaginal ultrasound in a sagittal plane focusing on the cervix during a gynecological/obstetric evaluation. The grayscale sonogram displays the anatomical structures of the cervix, including the hypoechoic (dark) cervical canal and the internal os. A linear measurement is performed across the internal cervical os, indicated by a green dotted line with calipers. The ultrasound software overlay shows a measurement value of 'L 2.27 cm', representing the diameter of the internal os opening. This measurement is clinically significant for assessing cervical ripening or the progress of labor induction, often used in conjunction with the Bishop score to predict successful cervical maturation. The anatomical orientation shows the superior uterine cavity transitioning into the cervical canal toward the lower external os. The image serves as an educational example of sonographic cervical assessment in an obstetrical context.

Two sagittal pelvic ultrasound images demonstrate a Cook Cervical Ripening Balloon (CCRB) positioned within the lower uterine segment of a pregnant woman. Image A (Control Group) shows a roughly spherical, fluid-filled balloon with a measured diameter of 3.10 cm, corresponding to a standard 80 mL fill volume. The internal echogenicity is heterogeneous with somewhat irregular borders. Image B (Study Group) depicts the balloon after increasing the volume to approximately 120 mL, resulting in an elongated, larger structure with a measured diameter of 6.14 cm. In both images, the relationship between the mechanical balloon and the adjacent fetal presenting part is visible, illustrating how the device exerts pressure on the internal cervical os to promote cervical ripening and mechanical dilation. These images serve as educational materials for obstetric induction of labor protocols, specifically comparing traditional versus high-volume balloon dilation techniques to improve Bishop scores and successful vaginal delivery rates.

Two sagittal pelvic ultrasound images demonstrate a Cook Cervical Ripening Balloon (CCRB) positioned within the lower uterine segment of a pregnant woman. Image A (Control Group) shows a roughly spherical, fluid-filled balloon with a measured diameter of 3.10 cm, corresponding to a standard 80 mL fill volume. The internal echogenicity is heterogeneous with somewhat irregular borders. Image B (Study Group) depicts the balloon after increasing the volume to approximately 120 mL, resulting in an elongated, larger structure with a measured diameter of 6.14 cm. In both images, the relationship between the mechanical balloon and the adjacent fetal presenting part is visible, illustrating how the device exerts pressure on the internal cervical os to promote cervical ripening and mechanical dilation. These images serve as educational materials for obstetric induction of labor protocols, specifically comparing traditional versus high-volume balloon dilation techniques to improve Bishop scores and successful vaginal delivery rates.

**Modality:** Magnetic Resonance Imaging (MRI)
**Sequence:** Sagittal T2-weighted image
**Anatomical Region:** Female pelvis, specifically focusing on the cervix and vagina.

**Description:**
The image demonstrates a mechanical cervical ripening device in situ. A double-balloon catheter is visible, characterized by two hyperintense (fluid-filled), spherical structures connected by a central catheter. 

*   **Proximal/Internal Balloon:** Positioned superiorly within the lower uterine segment/internal cervical os, exerting pressure against the internal os (indicated by the arrowhead).
*   **Central Catheter:** Transverses the cervical canal (indicated by the thin arrow), showing the mechanical dilation of the cervix.
*   **Distal/External Balloon:** Positioned inferiorly within the proximal vagina, abutting the external cervical os (indicated by the thick arrow).

**Clinical Context:** 
Findings are consistent with a Cook Cervical Ripening Balloon or similar dual-balloon catheter used for the mechanical induction of labor. The image provides high-contrast visualization of the device's placement relative to pelvic anatomy, confirming correct positioning with the cervix sandwiched between the two inflated balloons. Surroundings show the gravid uterus and adjacent pelvic structures including the bladder and rectum.

**Modality:** Magnetic Resonance Imaging (MRI) **Sequence:** Sagittal T2-weighted image **Anatomical Region:** Female pelvis, specifically focusing on the cervix and vagina. **Description:** The image demonstrates a mechanical cervical ripening device in situ. A double-balloon catheter is visible, characterized by two hyperintense (fluid-filled), spherical structures connected by a central catheter. * **Proximal/Internal Balloon:** Positioned superiorly within the lower uterine segment/internal cervical os, exerting pressure against the internal os (indicated by the arrowhead). * **Central Catheter:** Transverses the cervical canal (indicated by the thin arrow), showing the mechanical dilation of the cervix. * **Distal/External Balloon:** Positioned inferiorly within the proximal vagina, abutting the external cervical os (indicated by the thick arrow). **Clinical Context:** Findings are consistent with a Cook Cervical Ripening Balloon or similar dual-balloon catheter used for the mechanical induction of labor. The image provides high-contrast visualization of the device's placement relative to pelvic anatomy, confirming correct positioning with the cervix sandwiched between the two inflated balloons. Surroundings show the gravid uterus and adjacent pelvic structures including the bladder and rectum.

I now have comprehensive content. Let me compile the full, detailed answer.

Induction of Labour (IOL)

Definition

Induction of labour is the artificial initiation of uterine contractions before their spontaneous onset, with the aim of achieving vaginal delivery. It may be elective (for convenience of patient or provider) or indicated (for medical, obstetric, or fetal complications).
The rate of IOL has risen dramatically - in the United States from 9% of all births in 1989 to 19% in 1998, with continued increase since - largely driven by rising rates of elective induction. - Creasy & Resnik's Maternal-Fetal Medicine, p. 949

WHEN: Indications for IOL

Maternal (Indicated) Indications

  • Pregnancy-related hypertension (pre-eclampsia, gestational hypertension, chronic hypertension with superimposed pre-eclampsia)
  • Chorioamnionitis (intrauterine infection)
  • Fetal death (intrauterine fetal demise)
  • Prolonged rupture of membranes
  • Medical disease worsening with pregnancy (e.g., severe cardiac, renal, or hepatic disease)

Fetal (Indicated) Indications

  • Diabetes mellitus (especially when poorly controlled or complicated)
  • Postterm pregnancy (>41-42 weeks), especially with oligohydramnios
  • Hypertensive complications with evidence of fetal compromise
  • Intrauterine growth restriction (IUGR) - when fetal testing shows jeopardy
  • Isoimmunization (Rh or other blood group incompatibility with fetal hydrops)
  • Oligohydramnios
  • Fetal macrosomia in selected cases
Induction is indicated if prolongation of pregnancy is dangerous for either the mother or the fetus and there are no contraindications to amniotomy or augmentation of uterine contractions. - Creasy & Resnik's MFM

Elective Induction

Elective IOL is justified for reasons such as:
  • Patient reassurance that her chosen provider will attend the delivery
  • Distance from hospital / logistics
  • Psychosocial factors or maternal request at term
The landmark ARRIVE trial (Grobman et al.) - a randomized trial of over 6,000 nulliparous women - showed that elective induction at 39 weeks was associated with a lower caesarean delivery rate (15% vs 20%) compared to expectant management to 41 weeks, and no adverse neonatal outcomes. This challenged the long-held view that IOL increases caesarean risk.

WHY: Rationale and Key Principles

The core rationale is that continuing the pregnancy poses greater risk than delivering the baby. The decision requires weighing:
  1. Gestational age and fetal maturity
  2. Cervical favourability (Bishop score)
  3. Parity and obstetric history
  4. Risk of the underlying condition against the risks of IOL itself
Key contraindications to IOL include:
  • Placenta praevia / vasa praevia
  • Previous classical (vertical) uterine scar
  • Active genital herpes
  • Cord presentation or prolapse
  • Transverse/oblique lie
  • Severe CPD (cephalopelvic disproportion)

Cervical Assessment: The Bishop Score

Before induction, the cervix is assessed using the Bishop score (also called the Pelvic Scoring System). A higher score predicts a more successful and shorter induction.
Factor0123
Dilation (cm)01-23-45-6
Effacement (%)0-3040-5060-7080
Station-3-2-1 or 0+1 or +2
ConsistencyFirmMediumSoft-
PositionPosteriorMidAnterior-
  • Score ≥ 9: Favourable cervix - induction likely to succeed, may proceed directly to oxytocin
  • Score < 6: Unfavourable cervix - cervical ripening required first
  • Score 6-8: Intermediate
Creasy & Resnik's Maternal-Fetal Medicine

METHODS of Induction

Methods fall into three broad categories: pharmacological, mechanical, and surgical.

1. Cervical Ripening Methods (for unfavourable cervix)

a) Prostaglandins

Prostaglandins of the E and F series cause uterine contraction at any stage of gestation.
Dinoprostone (PGE₂)
  • Available as vaginal gel (Prepidil) or controlled-release vaginal insert (Cervidil/Propess)
  • Doses: Endocervical gel 0.5 mg every 6 hours (max 3 doses); vaginal insert 10 mg over 12 hours
  • Promotes cervical ripening AND initiates contractions
  • Remove insert if hyperstimulation occurs
Misoprostol (PGE₁ analogue)
  • Cheaper, stable at room temperature, highly effective
  • Routes: vaginal, oral, sublingual, buccal
  • Dose for term cervical ripening/induction: 25-50 mcg vaginally every 4-6 hours
  • For <28 weeks: 200-400 mcg vaginally or orally every 4 hours
  • For >28 weeks: 25-50 mcg vaginally/orally every 4 hours, or standard oxytocin
  • Recent meta-analysis of 53 RCTs (PMID 39465774) confirmed comparable efficacy between oral and vaginal misoprostol vs dinoprostone, with fewer side effects for misoprostol
Carboprost (15-methyl PGF₂α)
  • Used mainly for second-trimester abortion; significant side effects (vomiting, diarrhoea, fever)
Mifepristone + Misoprostol
  • Mifepristone 200 mg orally, followed 24-48 hours later by misoprostol 800 mcg vaginally (or 400 mcg buccally every 3 hours)
  • RCOG/WHO-recommended protocol for mid-trimester induction

b) Mechanical Methods

Foley/Balloon Catheter (Transcervical Catheter)
  • A Foley catheter (14-18 Fr) is inserted through the cervical os and the balloon inflated with 30-60 mL of saline
  • Provides mechanical stretching of the internal os, stimulating local prostaglandin release
  • Safe in women with previous caesarean section (no uterotonic effect)
  • Can be combined with oxytocin
  • Cook cervical ripening balloon (double balloon) uses both an intrauterine and an extrauterine balloon simultaneously
Cook cervical ripening balloon on ultrasound showing dual balloon positioning
Laminaria Tents
  • Hygroscopic dilators (natural seaweed or synthetic) placed in the cervical canal
  • Absorb moisture, expand over 4-12 hours, mechanically dilate the cervix
  • Used mainly in second-trimester induction or combined with surgical methods
Membrane Sweeping (Stretch and Sweep)
  • Digital separation of fetal membranes from the lower uterine segment at internal os
  • Stimulates local prostaglandin release
  • Reduces post-dates pregnancy and formal induction rates
  • Not a formal induction method but a preparatory/preventive one

2. Surgical Methods

Amniotomy (Artificial Rupture of Membranes - ARM)
  • Most direct method: the amniotic membranes are ruptured with an amniohook or Kocher forceps
  • Releases prostaglandins and allows the presenting part to press on the cervix
  • Used with an already ripe (favourable) cervix
  • Almost always combined with oxytocin
  • Risk: cord prolapse (especially with high or mobile presenting part), infection if prolonged latency

3. Pharmacological Oxytocin (the workhorse of augmentation/induction)

Oxytocin (Syntocinon)
  • A synthetic nonapeptide identical to endogenous posterior pituitary oxytocin
  • Given as IV infusion, titrated carefully
  • Low-dose regimen: start at 0.5-2 mU/min, increase by 1-2 mU/min every 15-40 min
  • High-dose regimen: start at 6 mU/min, increase by 6 mU/min every 15-40 min (higher risk of hyperstimulation)
  • Target: 3-5 contractions per 10 minutes, each lasting 40-60 seconds
  • Key risks: uterine hyperstimulation, fetal distress, water intoxication (at high doses), uterine rupture (in scarred uterus)
Special situation - Prior caesarean section:
  • If previous low-transverse incision and uterus >28 weeks: oxytocin protocol preferred; mechanical cervical ripening with Foley balloon catheter is safe
  • If previous low-transverse incision and uterus <28 weeks: misoprostol protocols for pre-viability may be used
  • If previous classical incision: repeat caesarean delivery is appropriate (IOL carries high rupture risk)
Creasy & Resnik's Maternal-Fetal Medicine

Summary Table: Methods at a Glance

MethodTypeUse CaseKey Points
Misoprostol (PGE₁)PharmacologicalAny gestation; unfavourable cervixCheap, oral/vaginal; caution with prior CS
Dinoprostone (PGE₂)PharmacologicalTerm; cervical ripeningGel or insert; removable
Mifepristone + MisoprostolPharmacologicalMid-trimester, IUFDRCOG/WHO protocol
Oxytocin IVPharmacologicalFavourable cervix; augmentationTitrated infusion; continuous CTG needed
Foley/Balloon catheterMechanicalUnfavourable cervix; prior CSNo systemic effects; safe in scarred uterus
Laminaria tentsMechanicalSecond trimester; cervical prepSlow acting over hours
Amniotomy (ARM)SurgicalFavourable cervix; adjunct to oxytocinCord prolapse risk
Membrane sweepPreparatoryPre/post-dates at termReduces formal IOL rates

Monitoring During IOL

  • Continuous cardiotocography (CTG) is mandatory during oxytocin/prostaglandin administration
  • Watch for uterine hyperstimulation (>5 contractions/10 min or contractions lasting >2 min)
  • If hyperstimulation: stop oxytocin, reposition patient left lateral, give tocolysis (terbutaline 0.25 mg SC) if needed
  • Monitor maternal vital signs, fluid balance (oxytocin has antidiuretic effect)

Key Takeaway

IOL is indicated when continuing pregnancy poses more risk than delivery. The method chosen depends on gestational age, cervical favourability (Bishop score), and obstetric history (particularly prior uterine scar). Misoprostol and oxytocin are the mainstays; mechanical methods (Foley balloon) are preferred when uterotonic drugs carry excess risk. The ARRIVE trial established that elective induction at 39 weeks in low-risk nulliparas reduces - not increases - caesarean rates.
Sources: Creasy & Resnik's Maternal-Fetal Medicine, Principles and Practice; Berek & Novak's Gynecology; Goodman & Gilman's Pharmacological Basis of Therapeutics. Recent evidence: PMID 39465774 (misoprostol vs dinoprostone meta-analysis, 2024).

At what gestation is inducation indicated in different cases

Finding Sources
Finding Sources
Finding Sources
Finding Sources
Reading File
Finding Sources
Finding Sources
Finding Sources
Reading File
Reading File
Reading File
Finding Sources
Finding Sources
Reading File
Searching the Web

ACOG SMFM guidelines gestational age induction labor indications 2024 postterm diabetes preeclampsia IUGR PROM

I now have solid content from the textbooks and current guidelines. Here is the full, structured answer:

Gestational Age for Induction of Labour by Indication

The precise timing of induction depends on the specific condition, its severity, and the balance between maternal/fetal risk versus prematurity risk. Below is a condition-by-condition breakdown.

1. Postterm / Prolonged Pregnancy

StatusGestational AgeAction
Late-term41+0 - 41+6 weeksBegin antenatal surveillance; offer/consider induction
Postterm≥ 42+0 weeksInduction recommended
Absolute cutoff42+6 weeksMust deliver by this point
"Induction of labor is typically recommended at or shortly after 41+0 weeks of gestation regardless of cervical status, because intervention at this time has been shown to reduce perinatal mortality without significantly increasing perinatal morbidity or cesarean delivery rates." - Creasy & Resnik's MFM
The NNT (number needed to treat to prevent one perinatal death) is 527 inductions at 41 weeks vs. 195 at 43 weeks - meaning the urgency increases with each passing week.

2. Hypertensive Disorders of Pregnancy

ConditionGestational AgeAction
Pre-eclampsia ≥37 weeks≥ 37+0 weeksDeliver - HYPITAT trial showed maternal risk significantly reduced by delivery after 37 weeks without excess perinatal risk
Pre-eclampsia 34-37 weeks34-37 weeksIndividualise - consider planned delivery; reduces severe hypertension and maternal morbidity (trial shows 3/4 of expectantly managed women progress to severe PE); neonatal unit admissions higher but no excess respiratory morbidity
Severe features / HELLP / uncontrolled BPAny gestationDeliver regardless of gestation once stabilised (after steroids if <34 weeks)
Pre-eclampsia <34 weeks<34 weeksExpectant management with intensive monitoring if mother and fetus stable; give corticosteroids; deliver if deterioration
Pre-eclampsia <24 weeks<24 weeksPerinatal mortality >80%; termination usually recommended
Chronic hypertension (uncomplicated)38+0 - 38+6 weeksOptimal delivery window (lowest perinatal morbidity); delivery at 36 weeks carries excess perinatal risk; delivery beyond 39 weeks increases pre-eclampsia risk
Sources: Comprehensive Clinical Nephrology 7e; Brenner & Rector's The Kidney; Creasy & Resnik's MFM

3. Diabetes in Pregnancy

ConditionGestational AgeNotes
Well-controlled GDM (diet only)40+0 - 41+0 weeksCan await spontaneous labour; no earlier elective delivery needed
GDM requiring insulin/metformin, well-controlled38+0 - 39+0 weeksStandard recommendation
Poorly controlled GDM / pre-gestational diabetes (Type 1 or 2), well-controlled38+0 - 39+0 weeksACOG/SMFM guidance
Pre-gestational diabetes, poorly controlled / with vascular disease36+0 - 37+6 weeksEarlier delivery justified by risk of stillbirth
Any diabetic with fetal macrosomia, oligohydramnios, or deteriorating testingAs dictated by fetal statusDeliver promptly
The key concern with diabetes is the excess risk of unexplained stillbirth that rises after 38-39 weeks, particularly with suboptimal control or vascular complications.

4. Prelabour Rupture of Membranes (PROM / PPROM)

ConditionGestational AgeAction
PROM at term (≥37 weeks)≥ 37+0 weeksInduction recommended - equivalent outcomes to expectant management but reduces chorioamnionitis risk; most guidelines recommend induction within 12-24 hours of rupture
PPROM 34-36+6 weeks34 - 36+6 weeksInduction/delivery generally recommended (lung maturity sufficient; chorioamnionitis risk rises with time)
PPROM 32-33+6 weeks32 - 33+6 weeksIndividualise; corticosteroids; consider delivery if pulmonary maturity confirmed or infection develops
PPROM 24-31+6 weeks24 - 31+6 weeksExpectant management with close monitoring; corticosteroids + magnesium sulphate (neuroprotection); deliver if infection, abruption, or fetal compromise
PPROM <24 weeks (previable)<24 weeksCounsel re. prognosis; expectant management or termination discussed; survival extremely poor

5. Intrauterine Growth Restriction (IUGR / FGR)

SeverityGestational AgeCriteria
Mild FGR, normal Dopplers37+0 weeksDeliver at term once maturity confirmed
FGR with abnormal umbilical artery (absent/reversed diastolic flow), 25-34 weeks34+0 weeks or earlier if fetal status deterioratesInpatient surveillance with daily antenatal testing
FGR with reversed UA flow, ductus venosus abnormal28-30 weeks (individualised)Delivery may be necessary even at severe prematurity
FGR with reversed UA flow, >30 weeks≥ 30+0 weeksSeriously consider delivery given rising risk of intrauterine death
UA reversed flow after 30 weeks≥ 30+0 weeksIndication for delivery
"Reversed UA flow following 30 weeks' gestation would be an indication for delivery." - Creasy & Resnik's MFM

6. Cholestasis of Pregnancy (Intrahepatic Cholestasis)

SeverityGestational Age
Mild (bile acids <40 µmol/L)37+0 - 38+0 weeks
Severe (bile acids ≥40 µmol/L)35+0 - 37+0 weeks
Very severe / prior IUD history34+0 weeks (individualised)
The primary risk is sudden unexpected stillbirth, which rises steeply after 37 weeks in severe disease.

7. Multiple Pregnancy

TypeGestational Age
Dichorionic diamniotic (DCDA) twins, uncomplicated38+0 weeks
Monochorionic diamniotic (MCDA) twins36+0 - 37+0 weeks (higher risk of IUFD)
Monochorionic monoamniotic (MCMA) twins32+0 - 34+0 weeks (cord entanglement risk)
Complicated twins (TTTS post-laser)34+0 - 37+0 weeks (individualised)

8. Fetal Death (Intrauterine Fetal Demise)

  • Induction as soon as the mother is ready, regardless of gestation
  • <28 weeks: Misoprostol 200-400 mcg vaginally/orally every 4 hours
  • >28 weeks: Misoprostol 25-50 mcg every 4 hours OR oxytocin infusion
  • Check fibrinogen if fetus has been dead >4 weeks (risk of DIC)

9. Isoimmunisation (Rh/Other)

  • Timing driven by fetal middle cerebral artery (MCA) Doppler (peak systolic velocity)
  • MCA-PSV >1.5 MoM triggers cordocentesis and possible intrauterine transfusion
  • Delivery typically by 34-37 weeks depending on severity and transfusion history; avoid postterm gestation

10. Elective Induction (Low-Risk Pregnancy)

  • ACOG/SMFM support offering elective IOL at 39+0 weeks in low-risk, nulliparous women
  • The ARRIVE trial showed this reduces (not increases) caesarean rates (15% vs 20%)
  • Not before 39 weeks electively - each week from 37 to 39 carries meaningful benefit in neurodevelopmental and respiratory outcomes

Quick Reference Summary Table

ConditionEarliest DeliveryTypical Delivery Target
Uncomplicated (elective)39+039+0 - 40+6
Postterm41+0By 42+6 at absolute latest
Pre-eclampsia ≥37 wks37+0Prompt at 37
Pre-eclampsia 34-37 wks34+0Consider delivery after 34
Severe PE/HELLPAny (after steroids if <34 wks)Expedient
Chronic hypertension38+038+0 - 38+6
GDM (well controlled, insulin)38+038+0 - 39+0
Pre-gestational diabetes (poor control)36+036+0 - 37+6
PROM at term37+0Within 12-24 hrs of PROM
PPROM 34-37 wks34+0Deliver promptly
Mild FGR, normal Dopplers37+037+0
FGR + absent/reversed UA flow34+034+0
FGR + reversed UA flow >30 wks30+0As soon as possible
Cholestasis (mild)37+037-38
Cholestasis (severe, bile acids ≥40)35+035-37
DCDA twins (uncomplicated)38+038+0
MCDA twins36+036-37
MCMA twins32+032-34
IUFDAnyPromptly on diagnosis
Sources: Creasy & Resnik's Maternal-Fetal Medicine; Comprehensive Clinical Nephrology 7e; Brenner & Rector's The Kidney

Create a clinical decision flowchart PDF for induction timing by indication

Reading File
Running Command

ls -la /tmp/workspace/ 2>/dev/null || echo "workspace empty or missing"

Running Command

mkdir -p /tmp/workspace/iol-flowchart

Writing File

~/iol-flowchart/build_flowchart.py

"""
Clinical Decision Flowchart: Induction of Labour - Timing by Indication
Multi-page A4 PDF using ReportLab
"""

from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm, mm
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    HRFlowable, KeepTogether
)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT
from reportlab.graphics.shapes import (
    Drawing, Rect, String, Line, Polygon, Arrow,
    Group, Circle
)
from reportlab.graphics import renderPDF
from reportlab.platypus import Flowable
import os

OUTPUT = "/tmp/workspace/iol-flowchart/IOL_Clinical_Decision_Flowchart.pdf"

# ─── Colour palette ────────────────────────────────────────────────────────
C_HEADER_BG  = colors.HexColor("#1A3557")   # deep navy
C_HEADER_TXT = colors.white
C_SECTION_A  = colors.HexColor("#2166AC")   # blue  – hypertension
C_SECTION_B  = colors.HexColor("#D6604D")   # red   – urgent/severe
C_SECTION_C  = colors.HexColor("#4DAC26")   # green – diabetes
C_SECTION_D  = colors.HexColor("#7B3294")   # purple – PROM
C_SECTION_E  = colors.HexColor("#E08214")   # orange – FGR
C_SECTION_F  = colors.HexColor("#35978F")   # teal  – other
C_DECISION   = colors.HexColor("#FFF3B0")   # pale yellow – decision nodes
C_ACTION_GR  = colors.HexColor("#D4EDDA")   # pale green  – safe/deliver
C_ACTION_OR  = colors.HexColor("#FFF3CD")   # pale amber  – monitor
C_ACTION_RD  = colors.HexColor("#F8D7DA")   # pale red    – urgent
C_RULE       = colors.HexColor("#AAAAAA")
C_BODY_BG    = colors.HexColor("#F7F9FC")
C_ALT_ROW    = colors.HexColor("#EBF2FA")
C_BORDER     = colors.HexColor("#CCDDEE")

# ─── Document setup ─────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
    OUTPUT,
    pagesize=A4,
    leftMargin=1.5*cm, rightMargin=1.5*cm,
    topMargin=1.8*cm,  bottomMargin=1.8*cm,
    title="IOL Clinical Decision Flowchart",
    author="Orris Medical Reference",
    subject="Induction of Labour – Timing by Indication"
)

W, H = A4
USABLE_W = W - 3*cm

styles = getSampleStyleSheet()

def S(name, **kw):
    """Create a paragraph style."""
    base = styles.get(name, styles["Normal"])
    return ParagraphStyle(name + str(id(kw)), parent=base, **kw)

title_style   = S("Normal", fontSize=18, leading=22, textColor=C_HEADER_TXT,
                  alignment=TA_CENTER, fontName="Helvetica-Bold")
sub_style     = S("Normal", fontSize=10, leading=13, textColor=C_HEADER_TXT,
                  alignment=TA_CENTER, fontName="Helvetica")
h1_style      = S("Normal", fontSize=13, leading=16, textColor=C_HEADER_TXT,
                  alignment=TA_LEFT, fontName="Helvetica-Bold", spaceBefore=4)
h2_style      = S("Normal", fontSize=11, leading=14, textColor=colors.white,
                  alignment=TA_LEFT, fontName="Helvetica-Bold")
body_style    = S("Normal", fontSize=9, leading=12, textColor=colors.HexColor("#1a1a1a"),
                  alignment=TA_LEFT, fontName="Helvetica")
small_style   = S("Normal", fontSize=7.5, leading=10, textColor=colors.HexColor("#444444"),
                  alignment=TA_LEFT, fontName="Helvetica")
bold_style    = S("Normal", fontSize=9, leading=12, textColor=colors.HexColor("#1a1a1a"),
                  alignment=TA_LEFT, fontName="Helvetica-Bold")
center_style  = S("Normal", fontSize=9, leading=12, textColor=colors.HexColor("#1a1a1a"),
                  alignment=TA_CENTER, fontName="Helvetica")
warn_style    = S("Normal", fontSize=8, leading=11, textColor=colors.HexColor("#7B0000"),
                  alignment=TA_LEFT, fontName="Helvetica-Bold")
note_style    = S("Normal", fontSize=8, leading=11, textColor=colors.HexColor("#333333"),
                  alignment=TA_LEFT, fontName="Helvetica-Oblique")
footer_style  = S("Normal", fontSize=7, leading=9, textColor=colors.HexColor("#888888"),
                  alignment=TA_CENTER, fontName="Helvetica")

# ─── Helper: section header banner ──────────────────────────────────────────
def section_banner(text, bg_color, text_color=colors.white, number=None):
    label = f"<b>{number}  {text}</b>" if number else f"<b>{text}</b>"
    data = [[Paragraph(label, S("Normal", fontSize=11, leading=14,
                                textColor=text_color, fontName="Helvetica-Bold"))]]
    t = Table(data, colWidths=[USABLE_W])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), bg_color),
        ("LEFTPADDING",  (0,0), (-1,-1), 10),
        ("RIGHTPADDING", (0,0), (-1,-1), 10),
        ("TOPPADDING",   (0,0), (-1,-1), 6),
        ("BOTTOMPADDING",(0,0), (-1,-1), 6),
        ("ROUNDEDCORNERS", [4]),
    ]))
    return t

# ─── Helper: decision table (condition → timing → action → notes) ────────────
def decision_table(rows, col_widths=None, header=True):
    """
    rows: list of (condition, timing, action_text, action_color, note)
    """
    if col_widths is None:
        col_widths = [USABLE_W*0.30, USABLE_W*0.20, USABLE_W*0.22, USABLE_W*0.28]

    hdr = [
        Paragraph("<b>Clinical Scenario</b>", bold_style),
        Paragraph("<b>Deliver by / at</b>", bold_style),
        Paragraph("<b>Action</b>", bold_style),
        Paragraph("<b>Key Notes</b>", bold_style),
    ]
    table_data = [hdr]

    for i, (cond, timing, action, acolor, note) in enumerate(rows):
        row = [
            Paragraph(cond, body_style),
            Paragraph(f"<b>{timing}</b>", S("Normal", fontSize=9, leading=12,
                                            textColor=colors.HexColor("#1a1a1a"),
                                            alignment=TA_CENTER, fontName="Helvetica-Bold")),
            Paragraph(action, S("Normal", fontSize=8.5, leading=11,
                                textColor=colors.HexColor("#1a1a1a"),
                                alignment=TA_CENTER, fontName="Helvetica-Bold")),
            Paragraph(note, small_style),
        ]
        table_data.append(row)

    t = Table(table_data, colWidths=col_widths, repeatRows=1)

    style_cmds = [
        ("BACKGROUND",    (0,0), (-1,0),  C_HEADER_BG),
        ("TEXTCOLOR",     (0,0), (-1,0),  colors.white),
        ("GRID",          (0,0), (-1,-1), 0.4, C_BORDER),
        ("ROWBACKGROUNDS",(0,1), (-1,-1), [C_BODY_BG, C_ALT_ROW]),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
        ("TOPPADDING",    (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING",   (0,0), (-1,-1), 6),
        ("RIGHTPADDING",  (0,0), (-1,-1), 6),
        ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
        ("FONTSIZE",      (0,0), (-1,0),  9),
    ]
    # Colour the action column cells individually
    for i, (_, _, _, acolor, _) in enumerate(rows, start=1):
        style_cmds.append(("BACKGROUND", (2,i), (2,i), acolor))

    t.setStyle(TableStyle(style_cmds))
    return t

# ─── Helper: flowchart node drawing ─────────────────────────────────────────
class FlowNode(Flowable):
    """A simple diamond or rectangle node for flowchart."""
    def __init__(self, text, width, height, shape="rect",
                 fill=C_DECISION, border=C_RULE, fontsize=9):
        Flowable.__init__(self)
        self.text = text
        self.width = width
        self.height = height
        self.shape = shape
        self.fill = fill
        self.border = border
        self.fontsize = fontsize

    def draw(self):
        c = self.canv
        w, h = self.width, self.height
        c.saveState()
        c.setFillColor(self.fill)
        c.setStrokeColor(self.border)
        c.setLineWidth(1.2)
        if self.shape == "diamond":
            path = c.beginPath()
            path.moveTo(w/2, h); path.lineTo(w, h/2)
            path.lineTo(w/2, 0); path.lineTo(0, h/2)
            path.close()
            c.drawPath(path, fill=1, stroke=1)
        else:
            c.roundRect(0, 0, w, h, 6, fill=1, stroke=1)
        c.setFont("Helvetica-Bold", self.fontsize)
        c.setFillColor(colors.HexColor("#1a1a1a"))
        # word wrap roughly
        words = self.text.split()
        lines, line = [], []
        for w_ in words:
            if len(" ".join(line + [w_])) * self.fontsize * 0.55 < self.width - 10:
                line.append(w_)
            else:
                if line: lines.append(" ".join(line))
                line = [w_]
        if line: lines.append(" ".join(line))
        total_h = len(lines) * (self.fontsize + 2)
        y_start = (h + total_h) / 2 - self.fontsize
        for i, l in enumerate(lines):
            c.drawCentredString(self.width/2, y_start - i*(self.fontsize+2), l)
        c.restoreState()

    def wrap(self, aw, ah):
        return self.width, self.height

# ─── Build the main flowchart drawing (page 2) ──────────────────────────────
def build_algorithm_drawing():
    """Draw the main decision algorithm as a ReportLab Drawing."""
    dw, dh = USABLE_W, 19*cm
    d = Drawing(dw, dh)
    
    NW = USABLE_W - 10   # node width
    NH = 1.1*cm          # normal node height
    DH = 1.4*cm          # diamond height
    cx = dw / 2          # centre x
    fs = 8               # font size for nodes

    def rect_node(x, y, w, h, text, fill, border=C_RULE, fontsize=8):
        d.add(Rect(x, y, w, h, rx=5, ry=5,
                   fillColor=fill, strokeColor=border, strokeWidth=1.2))
        # simple centred text
        d.add(String(x + w/2, y + h/2 - fontsize/2 + 1, text,
                     fontSize=fontsize, fontName="Helvetica-Bold",
                     fillColor=colors.HexColor("#1a1a1a"),
                     textAnchor="middle"))

    def arrow(x1, y1, x2, y2):
        d.add(Line(x1, y1, x2, y2, strokeColor=C_RULE, strokeWidth=1.0))
        # arrowhead
        d.add(Polygon([x2, y2, x2-4, y2+7, x2+4, y2+7],
                      fillColor=C_RULE, strokeColor=C_RULE, strokeWidth=0.5))

    y = dh - 0.5*cm

    # ── START ──
    y -= NH
    rect_node(cx - NW/2, y, NW, NH,
              "PATIENT REQUIRES DELIVERY DECISION", C_HEADER_BG, C_HEADER_BG, fontsize=9)
    arrow(cx, y, cx, y - 0.4*cm); y -= 0.4*cm

    # ── Diamond: Contraindications? ──
    y -= DH
    d.add(Rect(cx - NW/2, y, NW, DH, rx=5, ry=5,
               fillColor=C_DECISION, strokeColor=colors.HexColor("#CC8800"), strokeWidth=1.5))
    d.add(String(cx, y + DH/2 - 4, "Any ABSOLUTE CONTRAINDICATION to IOL?",
                 fontSize=8, fontName="Helvetica-Bold",
                 fillColor=colors.HexColor("#7B3800"), textAnchor="middle"))
    d.add(String(cx, y + DH/2 - 14, "(Placenta praevia | Prior classical CS | Cord prolapse | Transverse lie)",
                 fontSize=7, fontName="Helvetica",
                 fillColor=colors.HexColor("#555555"), textAnchor="middle"))

    # YES branch right
    y_ci = y + DH/2
    d.add(Line(cx + NW/2, y_ci, cx + NW/2 + 1.5*cm, y_ci,
               strokeColor=C_SECTION_B, strokeWidth=1.2))
    d.add(String(cx + NW/2 + 0.2*cm, y_ci + 2, "YES", fontSize=7,
                 fontName="Helvetica-Bold", fillColor=C_SECTION_B))
    rw = 2.5*cm; rh = 0.9*cm
    rx = cx + NW/2 + 1.5*cm - rw/2
    d.add(Rect(rx, y_ci - rh/2, rw, rh, rx=4, ry=4,
               fillColor=C_ACTION_RD, strokeColor=C_SECTION_B, strokeWidth=1))
    d.add(String(rx + rw/2, y_ci - 4, "CAESAREAN SECTION",
                 fontSize=7.5, fontName="Helvetica-Bold",
                 fillColor=C_SECTION_B, textAnchor="middle"))

    # NO arrow down
    arrow(cx, y, cx, y - 0.35*cm)
    d.add(String(cx + 4, y - 0.15*cm, "NO", fontSize=7,
                 fontName="Helvetica-Bold", fillColor=colors.HexColor("#1a7a1a")))
    y -= 0.35*cm

    # ── Diamond: Indication? ──
    y -= DH*1.1
    d.add(Rect(cx - NW/2, y, NW, DH*1.1, rx=5, ry=5,
               fillColor=C_DECISION, strokeColor=C_RULE, strokeWidth=1.2))
    d.add(String(cx, y + DH*1.1/2, "IDENTIFY PRIMARY INDICATION",
                 fontSize=9, fontName="Helvetica-Bold",
                 fillColor=colors.HexColor("#1A3557"), textAnchor="middle"))

    arrow(cx, y, cx, y - 0.4*cm); y -= 0.4*cm

    # ── Branch row: 4 categories ──
    cats = [
        ("HYPERTENSIVE\nDISORDER", C_SECTION_A),
        ("DIABETES /\nMACROSOMIA", C_SECTION_C),
        ("PROM / PPROM", C_SECTION_D),
        ("FGR / IUGR", C_SECTION_E),
    ]
    cat_w = NW / 4 - 4
    cat_h = 1.3*cm
    y -= cat_h + 0.3*cm
    cat_x_start = cx - NW/2
    cat_ys = []
    for i, (label, col) in enumerate(cats):
        bx = cat_x_start + i*(cat_w + 4) + 2
        d.add(Rect(bx, y, cat_w, cat_h, rx=4, ry=4,
                   fillColor=col, strokeColor=col, strokeWidth=0))
        lines = label.split("\n")
        for j, l in enumerate(lines):
            d.add(String(bx + cat_w/2, y + cat_h/2 + (len(lines)-1-j)*9 - 4,
                         l, fontSize=7.5, fontName="Helvetica-Bold",
                         fillColor=colors.white, textAnchor="middle"))
        cat_ys.append((bx + cat_w/2, y))

    # arrows from decision to categories
    for bx_mid, by in cat_ys:
        d.add(Line(cx, y + cat_h + 0.4*cm, bx_mid, by + cat_h,
                   strokeColor=C_RULE, strokeWidth=0.8))

    arrow(cx, y + cat_h + 0.4*cm + 0.3*cm, cx, y + cat_h + 0.4*cm)

    y -= 0.3*cm

    # ── Sub-decision boxes per category ──
    sub_font = 6.5
    sub_h = 2.8*cm
    y -= sub_h + 0.2*cm

    sub_data = [
        # HYPERTENSION
        ("≥37 wks → Deliver\n34-37 wks → Consider\n  planned delivery\n<34 wks → Expectant\n  (if stable)\nSevere/HELLP → ANY\n  gestation: DELIVER",
         C_SECTION_A),
        # DIABETES
        ("Diet-controlled GDM\n→ 40-41 wks\nInsulin GDM / T1/T2\n→ 38-39 wks\nPoor control /\n  vascular Dz\n→ 36-37 wks",
         C_SECTION_C),
        # PROM
        ("PROM ≥37 wks\n→ Induce <24 hrs\nPPROM 34-36+6\n→ Deliver\nPPROM 32-34 wks\n→ Individualise\nPPROM <32 wks\n→ Expectant",
         C_SECTION_D),
        # FGR
        ("Normal Dopplers\n→ 37 wks\nAbnormal UA (no ED)\n→ 37 wks, monitor\nAbsent ED flow\n→ 34 wks\nReversed ED flow\n→ ≥30 wks: DELIVER",
         C_SECTION_E),
    ]

    for i, ((text, col), (bx_mid, _)) in enumerate(zip(sub_data, cat_ys)):
        bx = bx_mid - cat_w/2
        d.add(Rect(bx, y, cat_w, sub_h, rx=4, ry=4,
                   fillColor=colors.HexColor("#F0F6FF"),
                   strokeColor=col, strokeWidth=1.5))
        lines = text.split("\n")
        for j, l in enumerate(lines):
            d.add(String(bx + 4, y + sub_h - 12 - j*9.5, l,
                         fontSize=sub_font, fontName="Helvetica",
                         fillColor=colors.HexColor("#1a1a1a")))
        # arrow from category box
        d.add(Line(bx_mid, y + sub_h, bx_mid, y + sub_h + 0.3*cm,
                   strokeColor=col, strokeWidth=1))
        d.add(Polygon([bx_mid, y+sub_h, bx_mid-3, y+sub_h+5, bx_mid+3, y+sub_h+5],
                      fillColor=col, strokeColor=col, strokeWidth=0.5))

    y -= 0.6*cm

    # ── "Other indications" banner ──
    arrow(cx, y + 0.6*cm, cx, y + 0.15*cm)
    y -= 0.9*cm
    d.add(Rect(cx - NW/2, y, NW, 0.85*cm, rx=4, ry=4,
               fillColor=C_SECTION_F, strokeColor=C_SECTION_F, strokeWidth=0))
    others = "OTHER: Postterm ≥41+0 wks  |  Cholestasis: 37 wks (mild) / 35 wks (severe)  |  Twins (DCDA 38w, MCDA 36w, MCMA 32-34w)  |  IUFD: any gestation"
    d.add(String(cx, y + 0.3*cm, others,
                 fontSize=6.8, fontName="Helvetica-Bold",
                 fillColor=colors.white, textAnchor="middle"))

    y -= 0.55*cm
    arrow(cx, y + 0.55*cm, cx, y + 0.1*cm)

    # ── Bishop Score Assessment ──
    y -= NH*1.1
    d.add(Rect(cx - NW/2, y, NW, NH*1.1, rx=5, ry=5,
               fillColor=colors.HexColor("#FFF9E6"),
               strokeColor=colors.HexColor("#CC8800"), strokeWidth=1.5))
    d.add(String(cx, y + NH*1.1/2 + 2,
                 "ASSESS CERVIX  →  Calculate Bishop Score",
                 fontSize=9, fontName="Helvetica-Bold",
                 fillColor=colors.HexColor("#7B4800"), textAnchor="middle"))
    d.add(String(cx, y + NH*1.1/2 - 9,
                 "(Dilation · Effacement · Station · Consistency · Position)",
                 fontSize=7, fontName="Helvetica",
                 fillColor=colors.HexColor("#555555"), textAnchor="middle"))

    arrow(cx, y, cx, y - 0.35*cm); y -= 0.35*cm

    # ── Two branches: favourable vs unfavourable ──
    bscore_y = y
    bh = 1.2*cm; bw = NW/2 - 8
    # Favourable ≥6 (left)
    d.add(Line(cx, bscore_y, cx - bw/2 - 4, bscore_y - 0.3*cm,
               strokeColor=C_RULE, strokeWidth=0.8))
    d.add(Rect(cx - bw - 8, bscore_y - 0.3*cm - bh, bw, bh, rx=4, ry=4,
               fillColor=C_ACTION_GR, strokeColor=colors.HexColor("#218c33"), strokeWidth=1.2))
    d.add(String(cx - bw/2 - 8, bscore_y - 0.3*cm - bh/2 + 2,
                 "Bishop ≥6 (FAVOURABLE)",
                 fontSize=7.5, fontName="Helvetica-Bold",
                 fillColor=colors.HexColor("#155724"), textAnchor="middle"))
    d.add(String(cx - bw/2 - 8, bscore_y - 0.3*cm - bh/2 - 6,
                 "Amniotomy + Oxytocin",
                 fontSize=7, fontName="Helvetica",
                 fillColor=colors.HexColor("#155724"), textAnchor="middle"))

    # Unfavourable <6 (right)
    d.add(Line(cx, bscore_y, cx + bw/2 + 4, bscore_y - 0.3*cm,
               strokeColor=C_RULE, strokeWidth=0.8))
    d.add(Rect(cx + 8, bscore_y - 0.3*cm - bh, bw, bh, rx=4, ry=4,
               fillColor=C_ACTION_OR, strokeColor=colors.HexColor("#856404"), strokeWidth=1.2))
    d.add(String(cx + bw/2 + 8, bscore_y - 0.3*cm - bh/2 + 2,
                 "Bishop <6 (UNFAVOURABLE)",
                 fontSize=7.5, fontName="Helvetica-Bold",
                 fillColor=colors.HexColor("#533f03"), textAnchor="middle"))
    d.add(String(cx + bw/2 + 8, bscore_y - 0.3*cm - bh/2 - 6,
                 "Cervical ripening first",
                 fontSize=7, fontName="Helvetica",
                 fillColor=colors.HexColor("#533f03"), textAnchor="middle"))

    y = bscore_y - 0.3*cm - bh - 0.5*cm
    arrow(cx, y + 0.5*cm, cx, y + 0.15*cm)

    # ── Final action bar ──
    y -= 0.9*cm
    d.add(Rect(cx - NW/2, y, NW, 0.85*cm, rx=4, ry=4,
               fillColor=C_HEADER_BG, strokeColor=C_HEADER_BG, strokeWidth=0))
    d.add(String(cx, y + 0.3*cm,
                 "PROCEED WITH INDUCTION  ·  Continuous CTG  ·  IV access  ·  Analgesia plan  ·  Obstetric review",
                 fontSize=7.5, fontName="Helvetica-Bold",
                 fillColor=colors.white, textAnchor="middle"))

    return d


# ─── Assemble PDF story ──────────────────────────────────────────────────────
story = []

# ── PAGE 1: Cover header + Reference tables ──────────────────────────────────

# Header block
header_data = [[
    Paragraph("INDUCTION OF LABOUR", title_style),
    Paragraph("Clinical Decision Guide: Timing by Indication", sub_style),
    Paragraph("Based on Creasy &amp; Resnik's MFM · ACOG/SMFM Guidelines · HYPITAT Trial · ARRIVE Trial",
              S("Normal", fontSize=8, textColor=colors.HexColor("#AACCEE"),
                alignment=TA_CENTER, fontName="Helvetica-Oblique")),
]]
header_table = Table([[p] for p in header_data[0]], colWidths=[USABLE_W])
header_table.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,-1), C_HEADER_BG),
    ("LEFTPADDING",  (0,0), (-1,-1), 12),
    ("RIGHTPADDING", (0,0), (-1,-1), 12),
    ("TOPPADDING",   (0,0), (-1,-1), 10),
    ("BOTTOMPADDING",(0,0), (-1,-1), 10),
    ("ROUNDEDCORNERS", [6]),
]))
story.append(header_table)
story.append(Spacer(1, 0.4*cm))

# ── SECTION 1: Hypertensive Disorders ────────────────────────────────────────
story.append(section_banner("HYPERTENSIVE DISORDERS OF PREGNANCY", C_SECTION_A, number="1"))
story.append(Spacer(1, 2*mm))

htn_rows = [
    ("Pre-eclampsia ≥37+0 wks",
     "≥ 37+0 wks",
     "DELIVER",
     C_ACTION_RD,
     "HYPITAT: maternal risk ↓ significantly after 37 wks. Induction or CS depending on cervix/fetal presentation."),
    ("Pre-eclampsia 34+0 – 36+6 wks",
     "34–37 wks\n(consider)",
     "PLAN DELIVERY",
     C_ACTION_OR,
     "Planned delivery ↓ severe HTN & maternal morbidity. ~75% progress to severe PE expectantly. Weigh prematurity risk. Shared decision-making."),
    ("Severe features / HELLP\n(any gestation)",
     "URGENT\n(any gestation)",
     "DELIVER\nURGENTLY",
     C_ACTION_RD,
     "After maternal stabilisation (MgSO₄, antihypertensives). Steroids if <34 wks and clinically safe to wait 24-48 hrs. If <24 wks: discuss prognosis."),
    ("Pre-eclampsia 24–33+6 wks\n(stable, no severe features)",
     "Expectant\nthen 34 wks",
     "EXPECTANT\nMONITOR",
     C_ACTION_OR,
     "Deliver if: deteriorating organ function, uncontrolled BP, non-reassuring fetal testing, abruption. Antenatal corticosteroids + MgSO₄ neuroprotection."),
    ("Pre-eclampsia <24 wks",
     "< 24 wks",
     "COUNSEL /\nTERMINATE",
     C_ACTION_RD,
     "Perinatal mortality >80% even with prolongation. Maternal complications common. Termination usually recommended."),
    ("Chronic hypertension\n(on antihypertensives, uncomplicated)",
     "38+0 – 38+6 wks",
     "ELECTIVE IOL",
     C_ACTION_GR,
     "Optimal: 38+0–38+6 (lowest perinatal morbidity). Delivery <36 wks ↑ perinatal risk. Delivery >39 wks ↑ superimposed PE risk."),
    ("Gestational hypertension ≥37 wks",
     "≥ 37+0 wks",
     "DELIVER",
     C_ACTION_RD,
     "Similar to pre-eclampsia guidance; aim not to exceed 41 wks."),
]
story.append(decision_table(htn_rows))
story.append(Spacer(1, 0.4*cm))

# ── SECTION 2: Diabetes ───────────────────────────────────────────────────────
story.append(section_banner("DIABETES IN PREGNANCY", C_SECTION_C, number="2"))
story.append(Spacer(1, 2*mm))

dm_rows = [
    ("GDM – diet controlled, well managed",
     "40+0 – 41+0 wks",
     "ELECTIVE IOL",
     C_ACTION_GR,
     "Low additional risk. Can await spontaneous labour but do not allow postterm. Fetal surveillance from 40 wks."),
    ("GDM – insulin or metformin,\nwell controlled",
     "38+0 – 39+0 wks",
     "ELECTIVE IOL",
     C_ACTION_GR,
     "Standard ACOG/SMFM recommendation. Reduces unexplained stillbirth risk that rises steeply after 38–39 wks."),
    ("Pre-gestational diabetes (T1/T2),\nwell controlled, no complications",
     "38+0 – 39+0 wks",
     "ELECTIVE IOL",
     C_ACTION_GR,
     "HbA1c target maintained. Assess for macrosomia (USS). Consider CS if EFW >4.5 kg."),
    ("Pre-gestational diabetes,\npoorly controlled / vascular disease",
     "36+0 – 37+6 wks",
     "EARLIER IOL",
     C_ACTION_OR,
     "Autonomic neuropathy, nephropathy, retinopathy, or suboptimal glycaemic control → earlier delivery. Individualize."),
    ("Any diabetic + macrosomia /\noligohydramnios / deteriorating tests",
     "Promptly",
     "DELIVER",
     C_ACTION_RD,
     "EFW >4.5 kg: discuss elective CS. Oligohydramnios or BPP decline → immediate delivery."),
]
story.append(decision_table(dm_rows))
story.append(Spacer(1, 0.4*cm))

# ── SECTION 3: PROM / PPROM ───────────────────────────────────────────────────
story.append(section_banner("PRELABOUR RUPTURE OF MEMBRANES (PROM / PPROM)", C_SECTION_D, number="3"))
story.append(Spacer(1, 2*mm))

prom_rows = [
    ("PROM at term ≥37+0 wks",
     "Within 12–24 hrs",
     "INDUCE",
     C_ACTION_RD,
     "Reduces chorioamnionitis & neonatal infection. Oxytocin first-line. GBS status: give prophylaxis if positive."),
    ("PPROM 34+0 – 36+6 wks\n(late preterm)",
     "34–36+6 wks:\nDeliver",
     "DELIVER",
     C_ACTION_RD,
     "Lung maturity generally sufficient; ongoing infection risk outweighs prematurity. Steroids may be considered."),
    ("PPROM 32+0 – 33+6 wks",
     "Individualise\n(32–34 wks)",
     "INDIVIDUALISE",
     C_ACTION_OR,
     "Corticosteroids. Deliver if: pulmonary maturity confirmed, infection, abruption, fetal compromise. Otherwise expectant."),
    ("PPROM 24+0 – 31+6 wks",
     "Expectant until\n≥34 wks",
     "EXPECTANT\nMONITOR",
     C_ACTION_OR,
     "IV antibiotics (latency – erythromycin). Antenatal corticosteroids + MgSO₄ (neuroprotection <32 wks). Daily fetal surveillance. Deliver on deterioration."),
    ("PPROM previable <24 wks",
     "< 24 wks",
     "COUNSEL",
     C_ACTION_RD,
     "Survival extremely poor (<50% even in tertiary centres). Offer expectant management or termination after detailed counselling. Pulmonary hypoplasia risk ~25%."),
    ("PROM + chorioamnionitis\n(any gestation)",
     "URGENT",
     "DELIVER\nPROMPTLY",
     C_ACTION_RD,
     "IV broad-spectrum antibiotics immediately. Deliver by most expedient route. Ongoing fetal monitoring."),
]
story.append(decision_table(prom_rows))

# ── PAGE BREAK ────────────────────────────────────────────────────────────────
from reportlab.platypus import PageBreak
story.append(PageBreak())

# Header repeat on page 2
story.append(header_table)
story.append(Spacer(1, 0.4*cm))

# ── SECTION 4: FGR / IUGR ────────────────────────────────────────────────────
story.append(section_banner("FETAL GROWTH RESTRICTION (FGR / IUGR)", C_SECTION_E, number="4"))
story.append(Spacer(1, 2*mm))

fgr_rows = [
    ("FGR, normal umbilical artery Dopplers",
     "37+0 wks",
     "ELECTIVE IOL",
     C_ACTION_GR,
     "Serial growth scans every 2–3 weeks. Twice-weekly antenatal testing from 36 wks. Deliver once term."),
    ("FGR, abnormal UA (↑ PI)\nbut end-diastolic flow present",
     "37+0 wks",
     "ELECTIVE IOL",
     C_ACTION_GR,
     "Intensify surveillance (twice weekly BPP/NST). Deliver at 37 wks or earlier if fetal status deteriorates."),
    ("FGR, absent end-diastolic flow\n(AEDF) in UA",
     "34+0 wks",
     "DELIVER",
     C_ACTION_OR,
     "Inpatient surveillance. Daily testing from 25 wks. Deliver at 34 wks. Earlier if BPP <4 or DV abnormal."),
    ("FGR, reversed end-diastolic flow\n(REDF) in UA, 25–30 wks",
     "Individualise\n≥28–30 wks",
     "DELIVER\n(CONSIDER)",
     C_ACTION_OR,
     "DV reversed a-wave or BPP ≤4 → deliver immediately regardless of gestation. Weigh extreme prematurity risks."),
    ("FGR, reversed UA flow >30 wks",
     "≥ 30+0 wks",
     "DELIVER",
     C_ACTION_RD,
     "Reversed UA flow after 30 wks = indication for delivery. Maximise corticosteroids before delivery if feasible."),
    ("FGR + abnormal MCA-PSV\n(>1.5 MoM – consider isoimmunisation)",
     "34–37 wks",
     "INDIVIDUALIS\nE",
     C_ACTION_OR,
     "Evaluate for anaemia. Cordocentesis ± IUT if before 34 wks. Deliver at 34–37 wks depending on response."),
]
story.append(decision_table(fgr_rows))
story.append(Spacer(1, 0.4*cm))

# ── SECTION 5: Other Indications ────────────────────────────────────────────
story.append(section_banner("OTHER COMMON INDICATIONS", C_SECTION_F, number="5"))
story.append(Spacer(1, 2*mm))

other_rows = [
    ("POSTTERM pregnancy\n(≥41+0 wks)",
     "41+0 – 42+0 wks\n(by 42+6 at latest)",
     "INDUCE",
     C_ACTION_RD,
     "Risk of stillbirth, meconium aspiration, macrosomia increases. NNT 527 at 41 wks vs 195 at 43 wks to prevent 1 death. Foetal surveillance from 41 wks."),
    ("Intrahepatic cholestasis –\nMild (bile acids <40 µmol/L)",
     "37+0 – 38+0 wks",
     "ELECTIVE IOL",
     C_ACTION_GR,
     "Unexplained stillbirth risk. UDCA may reduce pruritus but does not eliminate fetal risk. Do not allow postterm."),
    ("Intrahepatic cholestasis –\nSevere (bile acids ≥40 µmol/L)",
     "35+0 – 37+0 wks",
     "EARLIER IOL",
     C_ACTION_OR,
     "Bile acids ≥100 µmol/L: consider delivery at 35 wks. Prior IUFD history: deliver even earlier."),
    ("Dichorionic diamniotic (DCDA) twins\nuncomplicated",
     "38+0 wks",
     "ELECTIVE IOL",
     C_ACTION_GR,
     "Risk of IUFD rises after 38 wks. Confirm presentation of leading twin."),
    ("Monochorionic diamniotic (MCDA) twins\nuncomplicated",
     "36+0 – 37+0 wks",
     "ELECTIVE IOL",
     C_ACTION_OR,
     "Higher risk of IUFD from placental sharing. Weekly surveillance from 16 wks."),
    ("Monochorionic monoamniotic (MCMA)\ntwins",
     "32+0 – 34+0 wks",
     "DELIVER\n(usually CS)",
     C_ACTION_RD,
     "Cord entanglement risk. Inpatient surveillance from 28 wks with continuous CTG. Usually by CS."),
    ("Intrauterine fetal death (IUFD)",
     "As soon as\nmother ready",
     "INDUCE",
     C_ACTION_OR,
     "<28 wks: misoprostol 200–400 mcg q4h.  >28 wks: misoprostol 25–50 mcg q4h OR oxytocin. Check fibrinogen if >4 wks since death (DIC risk). RhD immunoglobulin if Rh-negative."),
    ("Chorioamnionitis / IAI",
     "URGENT",
     "DELIVER",
     C_ACTION_RD,
     "IV antibiotics immediately (ampicillin + gentamicin). Induction for vaginal delivery preferred unless obstetric contraindication. Neonatal team alert."),
    ("Elective (low-risk, nulliparous\nat 39+0 wks – ARRIVE trial)",
     "39+0 wks",
     "OFFER IOL",
     C_ACTION_GR,
     "ARRIVE trial: elective IOL at 39 wks ↓ CS rate (15% vs 20%) with no adverse neonatal outcomes. Discuss with patient; not mandatory."),
]
story.append(decision_table(other_rows))
story.append(Spacer(1, 0.4*cm))

# ── SECTION 6: Absolute Contraindications Table ──────────────────────────────
story.append(section_banner("CONTRAINDICATIONS TO IOL", C_SECTION_B, number="6"))
story.append(Spacer(1, 2*mm))

contra_data = [
    [Paragraph("<b>ABSOLUTE (IOL contraindicated → CS)</b>", warn_style),
     Paragraph("<b>RELATIVE (individualize; senior review)</b>",
               S("Normal", fontSize=8, fontName="Helvetica-Bold",
                 textColor=colors.HexColor("#533f03")))],
    [
        Paragraph(
            "• Placenta praevia / vasa praevia\n"
            "• Previous classical (vertical) uterine incision\n"
            "• Cord presentation or prolapse\n"
            "• Transverse / oblique lie\n"
            "• Acute severe fetal distress requiring immediate delivery\n"
            "• Floating / unengaged presenting part (floating)\n"
            "• Active primary genital herpes\n"
            "• Invasive cervical carcinoma",
            body_style),
        Paragraph(
            "• Previous low-transverse CS (TOLAC may be appropriate)\n"
            "• Grand multiparity (≥5 prior pregnancies >20 wks)\n"
            "• Multiple pregnancy\n"
            "• Suspected CPD / macrosomia\n"
            "• Breech presentation\n"
            "• Inability to adequately monitor FHR\n"
            "• Severe oligohydramnios",
            body_style),
    ]
]
contra_t = Table(contra_data, colWidths=[USABLE_W/2, USABLE_W/2])
contra_t.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (0,0), colors.HexColor("#F8D7DA")),
    ("BACKGROUND",    (1,0), (1,0), colors.HexColor("#FFF3CD")),
    ("BACKGROUND",    (0,1), (0,1), colors.HexColor("#FFF5F5")),
    ("BACKGROUND",    (1,1), (1,1), colors.HexColor("#FFFDF0")),
    ("GRID",          (0,0), (-1,-1), 0.5, C_BORDER),
    ("VALIGN",        (0,0), (-1,-1), "TOP"),
    ("TOPPADDING",    (0,0), (-1,-1), 6),
    ("BOTTOMPADDING", (0,0), (-1,-1), 6),
    ("LEFTPADDING",   (0,0), (-1,-1), 8),
    ("RIGHTPADDING",  (0,0), (-1,-1), 8),
]))
story.append(contra_t)
story.append(Spacer(1, 0.4*cm))

# ── SECTION 7: Bishop Score Quick Reference ───────────────────────────────────
story.append(section_banner("BISHOP SCORE – QUICK REFERENCE", colors.HexColor("#CC8800"), number="7"))
story.append(Spacer(1, 2*mm))

bishop_data = [
    [Paragraph("<b>Factor</b>", bold_style),
     Paragraph("<b>0</b>", center_style),
     Paragraph("<b>1</b>", center_style),
     Paragraph("<b>2</b>", center_style),
     Paragraph("<b>3</b>", center_style)],
    ["Dilation (cm)", "0", "1–2", "3–4", "5–6"],
    ["Effacement (%)", "0–30", "40–50", "60–70", "80"],
    ["Station", "−3", "−2", "−1 / 0", "+1 / +2"],
    ["Consistency", "Firm", "Medium", "Soft", "—"],
    ["Position", "Posterior", "Mid", "Anterior", "—"],
]
bishop_t = Table(bishop_data,
                 colWidths=[USABLE_W*0.3, USABLE_W*0.175, USABLE_W*0.175,
                             USABLE_W*0.175, USABLE_W*0.175])
bishop_style_cmds = [
    ("BACKGROUND",    (0,0), (-1,0),  colors.HexColor("#CC8800")),
    ("TEXTCOLOR",     (0,0), (-1,0),  colors.white),
    ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
    ("FONTSIZE",      (0,0), (-1,-1), 9),
    ("GRID",          (0,0), (-1,-1), 0.4, C_BORDER),
    ("ROWBACKGROUNDS",(0,1), (-1,-1), [C_BODY_BG, C_ALT_ROW]),
    ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ("ALIGN",         (1,0), (-1,-1), "CENTER"),
    ("TOPPADDING",    (0,0), (-1,-1), 5),
    ("BOTTOMPADDING", (0,0), (-1,-1), 5),
    ("LEFTPADDING",   (0,0), (-1,-1), 8),
    ("RIGHTPADDING",  (0,0), (-1,-1), 8),
]
bishop_t.setStyle(TableStyle(bishop_style_cmds))

# Interpretation alongside
interp_data = [
    [Paragraph("<b>Score</b>", bold_style),
     Paragraph("<b>Cervix</b>", bold_style),
     Paragraph("<b>Management</b>", bold_style)],
    ["≥ 9",  "Very favourable",  "Amniotomy alone may be sufficient"],
    ["6–8",  "Favourable",       "Amniotomy + oxytocin"],
    ["< 6",  "Unfavourable",     "Cervical ripening required first"],
    ["< 4",  "Unfavourable",     "Mechanical (Foley balloon) or PG preferred"],
]
interp_t = Table(interp_data,
                 colWidths=[USABLE_W*0.12, USABLE_W*0.23, USABLE_W*0.35])
interp_t.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,0),  colors.HexColor("#CC8800")),
    ("TEXTCOLOR",     (0,0), (-1,0),  colors.white),
    ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
    ("FONTSIZE",      (0,0), (-1,-1), 8.5),
    ("GRID",          (0,0), (-1,-1), 0.4, C_BORDER),
    ("ROWBACKGROUNDS",(0,1), (-1,-1), [C_BODY_BG, C_ALT_ROW]),
    ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ("TOPPADDING",    (0,0), (-1,-1), 5),
    ("BOTTOMPADDING", (0,0), (-1,-1), 5),
    ("LEFTPADDING",   (0,0), (-1,-1), 8),
    ("RIGHTPADDING",  (0,0), (-1,-1), 8),
]))

bishop_row = Table([[bishop_t, Spacer(0.3*cm, 1), interp_t]],
                   colWidths=[USABLE_W*0.50, 0.3*cm, USABLE_W*0.70 - 0.3*cm])
bishop_row.setStyle(TableStyle([("VALIGN",(0,0),(-1,-1),"TOP"),("LEFTPADDING",(0,0),(-1,-1),0),("RIGHTPADDING",(0,0),(-1,-1),0)]))
story.append(bishop_row)
story.append(Spacer(1, 0.5*cm))

# ── PAGE 3: Algorithm Flowchart ────────────────────────────────────────────
story.append(PageBreak())
story.append(header_table)
story.append(Spacer(1, 0.3*cm))

story.append(section_banner("DECISION ALGORITHM OVERVIEW", C_HEADER_BG))
story.append(Spacer(1, 0.3*cm))

drawing = build_algorithm_drawing()
story.append(drawing)
story.append(Spacer(1, 0.4*cm))

# ── Method selection table ────────────────────────────────────────────────────
story.append(section_banner("METHOD SELECTION GUIDE", colors.HexColor("#555555")))
story.append(Spacer(1, 2*mm))

method_data = [
    [Paragraph("<b>Method</b>", bold_style),
     Paragraph("<b>Bishop Score</b>", bold_style),
     Paragraph("<b>Prior CS?</b>", bold_style),
     Paragraph("<b>Dose / Route</b>", bold_style),
     Paragraph("<b>Key Caution</b>", bold_style)],
    ["Oxytocin IV infusion",      "≥ 6 (favourable)", "Use with caution\n(no PG)",
     "Start 0.5–2 mU/min; ↑ by 1–2 mU/min q15–40 min",
     "Hyperstimulation; antidiuretic effect at high doses"],
    ["Misoprostol (PGE₁)\nvaginal / oral",
     "Any (<6 preferred)", "AVOID if prior CS\n(uterine rupture ↑)",
     "25–50 mcg vaginally q4–6 h\nOR 25 mcg oral q2 h",
     "Do not use within 4 hrs of oxytocin; T risk uterine rupture"],
    ["Dinoprostone (PGE₂)\ngel / insert",
     "< 6 (ripening)", "AVOID if prior CS",
     "Gel 0.5 mg endocervical q6 h (max 3×)\nInsert 10 mg × 12 h",
     "Remove insert if hyperstimulation; keep CTG ×30 min after"],
    ["Foley balloon catheter\n(mechanical)",
     "Any (<6 preferred)", "SAFE\n(preferred in prior CS)",
     "14–18 Fr; inflate 30–60 mL saline; leave in situ",
     "No systemic effect; cord prolapse risk if head high"],
    ["Amniotomy (ARM)",            "≥ 6",             "With caution",
     "Amniohook at ARM; confirm presentation first",
     "Cord prolapse; do not rupture if head floating"],
    ["Membrane sweep",             "Any",             "Yes (safe)",
     "Digital stretch of membranes at internal os",
     "Not formal IOL; preparatory; reduces formal IOL rate"],
    ["Mifepristone + Misoprostol\n(mainly pre-viability / IUFD)",
     "Any",             "See notes",
     "Mifepristone 200 mg PO then misoprostol 800 mcg\nvaginally 24–48 h later",
     "RCOG/WHO protocol. For prior CS at <28 wks may use standard doses."],
]

method_t = Table(method_data,
                 colWidths=[USABLE_W*0.20, USABLE_W*0.13, USABLE_W*0.12,
                             USABLE_W*0.30, USABLE_W*0.25],
                 repeatRows=1)
method_t.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,0),  colors.HexColor("#555555")),
    ("TEXTCOLOR",     (0,0), (-1,0),  colors.white),
    ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
    ("FONTSIZE",      (0,0), (-1,-1), 8),
    ("LEADING",       (0,0), (-1,-1), 10),
    ("GRID",          (0,0), (-1,-1), 0.4, C_BORDER),
    ("ROWBACKGROUNDS",(0,1), (-1,-1), [C_BODY_BG, C_ALT_ROW]),
    ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ("TOPPADDING",    (0,0), (-1,-1), 4),
    ("BOTTOMPADDING", (0,0), (-1,-1), 4),
    ("LEFTPADDING",   (0,0), (-1,-1), 5),
    ("RIGHTPADDING",  (0,0), (-1,-1), 5),
]))
story.append(method_t)
story.append(Spacer(1, 0.4*cm))

# ── Footer / disclaimer ────────────────────────────────────────────────────────
story.append(HRFlowable(width=USABLE_W, thickness=0.5, color=C_RULE))
story.append(Spacer(1, 2*mm))
story.append(Paragraph(
    "Sources: Creasy &amp; Resnik's Maternal-Fetal Medicine (8e) · Comprehensive Clinical Nephrology (7e) · Brenner &amp; Rector's The Kidney · "
    "ACOG Practice Bulletin · SMFM Consult Series · HYPITAT Trial · ARRIVE Trial (Grobman et al. NEJM 2018)  |  "
    "This document is a clinical reference aid. Always apply local protocols and clinical judgement. August 2026.",
    footer_style))

# ─── Build ───────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF created: {OUTPUT}")
print(f"Size: {os.path.getsize(OUTPUT):,} bytes")
Running Command

cd /tmp/workspace/iol-flowchart && python build_flowchart.py 2>&1

Editing File

~/iol-flowchart/build_flowchart.py

Successfully replaced 1 instance(s) of the string in '/tmp/workspace/iol-flowchart/build_flowchart.py'
Running Command

cd /tmp/workspace/iol-flowchart && python build_flowchart.py 2>&1

Your PDF is ready:

IOL Clinical Decision Flowchart

PDF Document · PDF


What's inside (3 pages, A4):
Page 1 - Reference Tables
  • Section 1 - Hypertensive Disorders: Pre-eclampsia at each gestational window (≥37 wks, 34-37 wks, <34 wks, <24 wks), severe features/HELLP, chronic hypertension, gestational HTN - each with timing, action colour-coded (red/amber/green), and key notes
  • Section 2 - Diabetes: Diet-controlled GDM, insulin-requiring GDM, pre-gestational T1/T2 (well-controlled and poorly controlled), macrosomia
  • Section 3 - PROM/PPROM: PROM at term → <24 hrs; PPROM 34-37, 32-34, 24-32 wks, previable, + chorioamnionitis
Page 2 - More Tables + Bishop Score
  • Section 4 - FGR/IUGR: Normal Dopplers, absent end-diastolic flow, reversed end-diastolic flow by gestation
  • Section 5 - Other Indications: Postterm, cholestasis (mild/severe), DCDA/MCDA/MCMA twins, IUFD, chorioamnionitis, ARRIVE elective IOL
  • Section 6 - Contraindications: Absolute vs relative, side-by-side
  • Section 7 - Bishop Score: Full scoring table + interpretation guide
Page 3 - Algorithm + Method Guide
  • Visual decision algorithm flowchart (contraindications → indication → cervical assessment → Bishop score branches → action)
  • Method selection table (Oxytocin, Misoprostol, Dinoprostone, Foley balloon, ARM, membrane sweep, Mifepristone+Misoprostol) with dose, prior CS safety, and key cautions
This is a shared conversation. Sign in to Orris to start your own chat.