Partograph explain basics to clinic

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

partograph basics clinical use WHO cervical dilation alert action line explained

Reading Web Page

https://medicalguidelines.msf.org/en/viewport/ONC/english/5-…

Finding Sources
Loading Image
Searching the Web

partograph sections fetal heart rate descent of head maternal observations complete guide clinical

I now have excellent material including the actual partograph image. Let me compile a thorough clinical explanation.

The Partograph - Basics for Clinical Practice

WHO Partograph

What Is a Partograph?

The partograph (or partogram) is a single-page graphical tool used to monitor mother and fetus during the active phase of labour. Its core purpose is early detection of abnormal labour progress so that timely action - transfer, augmentation, or operative delivery - can be taken before complications develop.
It is designed to work at any level of care, from a rural health sub-centre to a tertiary hospital.

When to Start

  • Begin recording when the woman enters active labour: cervical dilatation 4-5 cm with regular contractions
  • The modified WHO partograph and MSF guideline start plotting at 5 cm dilation (or 4 cm for induced labour)
  • Do not start in the latent phase (< 4 cm)

The Partograph Has Three Main Sections

SECTION 1 - Fetal Condition (Top)

ParameterHow to RecordNormal Range / Alert
Fetal Heart Rate (FHR)Auscultate every 30 min (1st stage) / every 5 min (2nd stage); plot as a dot110-160 bpm; alarm lines at 100 and 180
Amniotic FluidRecord at each vaginal examI = intact; C = clear; M = meconium; B = blood
Moulding of skullOverlap of skull bones at each VE0 = none; 1+ = bones appose; 2+ = overlap, reducible; 3+ = fixed overlap (danger)

SECTION 2 - Labour Progress (Middle - the core graph)

This is the central graphical section. Two parameters share the same grid (0-10 scale, y-axis) against time (x-axis, each column = 1 hour):

A. Cervical Dilatation - plot with X

  • Y-axis: 0-10 cm
  • The first X is placed on the alert line at the dilatation found on admission
  • Subsequent Xs are plotted every 4 hours (or sooner if indicated)

B. Descent of Fetal Head - plot with O

  • Assessed by abdominal palpation (fifths of head palpable above the symphysis pubis)
  • Scale: 5/5 (fully above) → 0/5 (fully engaged)
  • Good progress = descent should accompany dilatation

C. Uterine Contractions

  • Plotted below the cervix/descent grid
  • Count contractions per 10 minutes; shade box according to duration:
    • Dotted = < 20 seconds
    • Hatched = 20-40 seconds
    • Solid = > 40 seconds
  • Normal active labour: 3 or more contractions per 10 min, each lasting > 40 seconds

SECTION 3 - Maternal Condition (Bottom)

ParameterFrequency
Oxytocin (units/L, drops/min)Every 30 min if in use
Drugs / IV fluidsAs given
Pulse (dot •)Every 30 min
Blood pressure (arrows ↕)Every 4 hours
TemperatureEvery 4 hours
Urine - protein, acetone, volumeEach void

The Two Critical Lines: Alert and Action

These are the most important clinical decision tools on the partograph:
  10 |                    /  Action
     |             /  Alert
   9 |          /       /
     |       /       /
   7 |    /       /
     |  /       /
   5 |/       /
     |_____________  Hours →
        0  1  2  3  4
LineWhat It MeansWhen Crossed
Alert LineExpected minimum progress = 1 cm/hour dilatation from 4 cm to 10 cmDilatation is slower than expected - reassess, consider transfer or closer monitoring
Action LineParallel to Alert line, 4 hours to the rightDefinitive action required: augmentation (oxytocin/ARM), or caesarean section
Key rule: If the cervical dilatation curve falls to the right of the Alert line, the clinician must respond. If it reaches the Action line, the decision cannot be delayed.

How to Use It Step by Step

  1. On admission - assess cervix, FHR, contractions, membranes, vitals
  2. Plot first X on the alert line at the measured dilatation
  3. Every 30 minutes - FHR, contractions, pulse
  4. Every 4 hours - vaginal exam (cervix + descent), BP, temperature, urine
  5. At each assessment - is the curve to the left of the alert line? Good. Has it crossed? Act.
  6. Document all interventions (oxytocin, fluids, drugs) in real time

Moulding - Quick Reference

GradeFindingSignificance
0Bones separated, sutures feltNormal
1+Bones just touchingMild
2+Bones overlap, can be separatedModerate - watch closely
3+Fixed overlapSevere - cephalopelvic disproportion, act urgently

Meconium Grading

GradeAppearanceAction
Grade 1 (thin)Slightly green/yellowIncrease FHR monitoring
Grade 2 (moderate)Clearly greenPrepare for neonatal resuscitation
Grade 3 (thick)Thick pea-soupFetal distress likely - expedite delivery

WHO Labor Care Guide (LCG) - 2020 Update

The WHO updated the traditional partograph with the Labour Care Guide (LCG), which differs in several ways:
FeatureTraditional PartographWHO LCG (2020)
Active phase starts4 cm5 cm
Alert/Action linesSingle fixed 1 cm/hr slopePer-centimetre time thresholds (evidence-based)
2nd stage monitoringLimitedExplicit section added
Supportive careNot recordedCompanionship, oral fluids, position documented
PhilosophyDetect abnormal labourWoman-centred, holistic

Common Errors to Avoid

  • Starting the partograph too early (latent phase) - leads to unnecessary interventions
  • Failing to act when the alert line is crossed
  • Recording FHR between contractions only - must auscultate during and after a contraction
  • Not re-examining when membranes rupture or pain pattern changes suddenly
  • Confusing the descent scale (0-5 fifths) with the dilatation scale on the same grid

Quick Summary

The partograph is a visual early-warning system for labour. It integrates fetal, labour-progress, and maternal data onto one sheet. The alert and action lines are your clinical trigger points. When the dilatation curve moves right of the alert line, you investigate. When it hits the action line, you act - augment or deliver.
Sources: MSF Essential Obstetric and Newborn Care Guidelines; WHO Labour Care Guide User's Manual (2020); Park's Textbook of Preventive and Social Medicine; Cureus - Ghulaxe et al. 2022 (PMC9652267)

Generate a visual poster of moulding grades and meconium staining

Generating Image

A clean, professional medical education poster titled "Intrapartum Monitoring: Moulding Grades & Meconium Staining" for clinical use. TOP HALF - MOULDING GRADES section with a teal/green header: Four side-by-side diagrams of fetal skull cross-sections showing skull bones and sutures, labeled Grade 0 through Grade 3+: - Grade 0: Bones well separated, sutures easily felt, labeled "Normal - No overlap" - Grade 1+: Bones just touching at suture lines, labeled "Mild - Bones apposed, sutures felt" - Grade 2+: Bones overlapping but reducible with pressure, labeled "Moderate - Overlap, reducible. Watch closely" - Grade 3+: Fixed bony overlap that cannot be reduced, red warning border, labeled "SEVERE - Fixed overlap. Suspect CPD. Act urgently" Each diagram shows simplified oval skull shapes with suture lines between them, illustrated in a clean anatomical style. BOTTOM HALF - MECONIUM STAINING section with a dark blue header: Three amniotic fluid sample illustrations in test tubes or fluid droplets side by side: - Grade 1 (Thin): Light yellowish-green fluid, labeled "Thin/Scanty - Slightly green or yellow - Increase FHR monitoring" - Grade 2 (Moderate): Medium green fluid, labeled "Moderate - Clearly green - Prepare neonatal resuscitation team" - Grade 3 (Thick): Dark thick pea-soup brown-green fluid with a red warning symbol, labeled "THICK 'Pea Soup' - Dark green/brown - Likely fetal distress - Expedite delivery NOW" Each grade has a colored severity indicator: green dot for Grade 1, orange dot for Grade 2, red dot for Grade 3. Footer text: "Partograph Monitoring Guide | Intrapartum Care" Clean white background, bold headers, medical illustration style, easy to read at a glance in a clinical setting.

Moulding Grades & Meconium Staining Poster
Here is your clinical poster covering both topics side by side:
Top section - Moulding Grades (0 to 3+):
  • Grade 0 = normal, bones separated
  • Grade 1+ = bones touching
  • Grade 2+ = overlap, reducible (watch closely)
  • Grade 3+ = fixed overlap, red flag for cephalopelvic disproportion - act urgently
Bottom section - Meconium Staining (Grades 1-3):
  • Grade 1 (thin, yellow-green) = increase FHR monitoring
  • Grade 2 (moderate green) = prepare neonatal resuscitation team
  • Grade 3 (thick pea-soup) = likely fetal distress, expedite delivery immediately
The severity colour coding (green → orange → red) makes it quick to interpret at a glance in a busy delivery room. You can print this and display it near the partograph charting area.

Create a quick reference PDF checklist for partograph documentation

Reading File
Running Command

ls /home/daytona/workspace/ 2>/dev/null || echo "workspace empty or not found"

Running Command

mkdir -p /home/daytona/workspace/partograph && python3 -c "from reportlab.lib.pa…

Writing File

~/partograph/build_checklist.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_RIGHT
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    HRFlowable, KeepTogether
)
from reportlab.graphics.shapes import Drawing, Rect, String, Line, Circle
from reportlab.graphics import renderPDF

OUTPUT = "/home/daytona/workspace/partograph/Partograph_Checklist.pdf"

# ── Colours ──────────────────────────────────────────────────────────────────
TEAL      = colors.HexColor("#006D77")
TEAL_LT   = colors.HexColor("#83C5BE")
TEAL_BG   = colors.HexColor("#EDF6F9")
ORANGE    = colors.HexColor("#E29578")
RED       = colors.HexColor("#C1121F")
RED_LT    = colors.HexColor("#FFDDD2")
GREEN     = colors.HexColor("#2D6A4F")
GREEN_LT  = colors.HexColor("#D8F3DC")
AMBER     = colors.HexColor("#F4A261")
AMBER_LT  = colors.HexColor("#FFF3E0")
GREY_BG   = colors.HexColor("#F8F9FA")
GREY_LINE = colors.HexColor("#DEE2E6")
WHITE     = colors.white
BLACK     = colors.HexColor("#212529")
HEADER_BG = colors.HexColor("#004E57")

# ── Document ──────────────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
    OUTPUT,
    pagesize=A4,
    leftMargin=1.5*cm, rightMargin=1.5*cm,
    topMargin=1.5*cm, bottomMargin=1.5*cm,
    title="Partograph Quick Reference Checklist",
    author="Clinical Reference Tool"
)

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

styles = getSampleStyleSheet()

def ps(name, **kw):
    return ParagraphStyle(name, **kw)

# Custom styles
TITLE_S  = ps("title_s",  fontSize=20, textColor=WHITE,      fontName="Helvetica-Bold", alignment=TA_CENTER, leading=24)
SUB_S    = ps("sub_s",    fontSize=9,  textColor=TEAL_LT,    fontName="Helvetica",      alignment=TA_CENTER, leading=12)
SECT_S   = ps("sect_s",   fontSize=10, textColor=WHITE,      fontName="Helvetica-Bold", alignment=TA_LEFT,   leading=13)
BODY_S   = ps("body_s",   fontSize=8,  textColor=BLACK,      fontName="Helvetica",      alignment=TA_LEFT,   leading=11)
BOLD_S   = ps("bold_s",   fontSize=8,  textColor=BLACK,      fontName="Helvetica-Bold", alignment=TA_LEFT,   leading=11)
SMALL_S  = ps("small_s",  fontSize=7,  textColor=colors.HexColor("#555555"), fontName="Helvetica", alignment=TA_LEFT, leading=10)
WARN_S   = ps("warn_s",   fontSize=8,  textColor=RED,        fontName="Helvetica-Bold", alignment=TA_LEFT,   leading=11)
GREEN_S  = ps("green_s",  fontSize=8,  textColor=GREEN,      fontName="Helvetica-Bold", alignment=TA_LEFT,   leading=11)
LABEL_S  = ps("label_s",  fontSize=7.5,textColor=TEAL,       fontName="Helvetica-Bold", alignment=TA_LEFT,   leading=10)
CENTER_S = ps("center_s", fontSize=8,  textColor=BLACK,      fontName="Helvetica",      alignment=TA_CENTER, leading=11)
FOOT_S   = ps("foot_s",   fontSize=6.5,textColor=colors.HexColor("#888888"), fontName="Helvetica", alignment=TA_CENTER, leading=9)

story = []

# ═══════════════════════════════════════════════════════════════════════════════
# HEADER BANNER
# ═══════════════════════════════════════════════════════════════════════════════
header_data = [[
    Paragraph("PARTOGRAPH", TITLE_S),
    Paragraph("Quick Reference Checklist for Labour Monitoring", SUB_S),
    Paragraph("WHO / MSF Standard", ps("r_s", fontSize=8, textColor=TEAL_LT, fontName="Helvetica", alignment=TA_RIGHT, leading=11)),
]]
header_tbl = Table(header_data, colWidths=[CONTENT_W*0.3, CONTENT_W*0.45, CONTENT_W*0.25])
header_tbl.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,-1), HEADER_BG),
    ("TOPPADDING",    (0,0), (-1,-1), 10),
    ("BOTTOMPADDING", (0,0), (-1,-1), 10),
    ("LEFTPADDING",   (0,0), (-1,-1), 8),
    ("RIGHTPADDING",  (0,0), (-1,-1), 8),
    ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ("ROUNDEDCORNERS", [6]),
]))
story.append(header_tbl)
story.append(Spacer(1, 6))

# ── Helper: section header row ────────────────────────────────────────────────
def section_header(text, color=TEAL, icon=""):
    label = f"{icon}  {text}" if icon else text
    t = Table([[Paragraph(label, SECT_S)]], colWidths=[CONTENT_W])
    t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,-1), color),
        ("TOPPADDING",    (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING",   (0,0), (-1,-1), 8),
        ("ROUNDEDCORNERS", [4]),
    ]))
    return t

def checkbox_row(label, note="", warn=False):
    box = "☐"
    sty = WARN_S if warn else BODY_S
    note_sty = ps("n", fontSize=7, textColor=colors.HexColor("#777777"), fontName="Helvetica-Oblique", leading=9)
    row = [[
        Paragraph(box, ps("ck", fontSize=10, fontName="Helvetica", leading=12)),
        Paragraph(f"<b>{label}</b>" if warn else label, sty),
        Paragraph(note, note_sty) if note else Paragraph("", note_sty),
    ]]
    t = Table(row, colWidths=[0.5*cm, CONTENT_W*0.52, CONTENT_W*0.41])
    t.setStyle(TableStyle([
        ("VALIGN",        (0,0), (-1,-1), "TOP"),
        ("TOPPADDING",    (0,0), (-1,-1), 2),
        ("BOTTOMPADDING", (0,0), (-1,-1), 2),
        ("LEFTPADDING",   (0,0), (-1,-1), 3),
    ]))
    return t

# ═══════════════════════════════════════════════════════════════════════════════
# ROW 1 (two columns): WHEN TO START  |  PATIENT IDENTIFIERS
# ═══════════════════════════════════════════════════════════════════════════════
start_checks = [
    ("Active labour confirmed (≥4-5 cm dilatation)", "Start plotting at 5 cm (or 4 cm if induced)"),
    ("Regular uterine contractions present", "≥2 contractions per 10 min"),
    ("Membranes status noted (intact / ruptured)", "Record hours since rupture"),
    ("Admission vitals recorded", "BP, Pulse, Temp, Urine"),
    ("Fetal presentation confirmed cephalic", "Transverse/breech = refer"),
]
ident_fields = [
    "Name / ID number",
    "Gravida & Para",
    "Date & Time of admission",
    "Hours since membrane rupture",
    "Hospital number / ward",
    "EDD / Gestational age",
]

left_items = [section_header("BEFORE YOU START", TEAL)]
for lbl, note in start_checks:
    left_items.append(checkbox_row(lbl, note))

right_items = [section_header("PATIENT IDENTIFIERS", TEAL)]
for f in ident_fields:
    right_items.append(checkbox_row(f))

# Pad to same length
while len(left_items) < len(right_items):
    left_items.append(Spacer(1, 5))
while len(right_items) < len(left_items):
    right_items.append(Spacer(1, 5))

two_col = Table(
    [[left_items, right_items]],
    colWidths=[CONTENT_W*0.52, CONTENT_W*0.48]
)
two_col.setStyle(TableStyle([
    ("VALIGN",        (0,0), (-1,-1), "TOP"),
    ("LEFTPADDING",   (0,0), (-1,-1), 0),
    ("RIGHTPADDING",  (0,0), (0,-1),  4),
    ("TOPPADDING",    (0,0), (-1,-1), 0),
    ("BOTTOMPADDING", (0,0), (-1,-1), 0),
]))
story.append(two_col)
story.append(Spacer(1, 5))

# ═══════════════════════════════════════════════════════════════════════════════
# MONITORING FREQUENCY TABLE
# ═══════════════════════════════════════════════════════════════════════════════
story.append(section_header("MONITORING FREQUENCY — What to Record & When", TEAL))
story.append(Spacer(1, 3))

freq_data = [
    [
        Paragraph("Parameter", BOLD_S),
        Paragraph("Symbol", BOLD_S),
        Paragraph("1st Stage\n(Active)", BOLD_S),
        Paragraph("2nd Stage", BOLD_S),
        Paragraph("Normal Range / Alert", BOLD_S),
    ],
    # Fetal
    [Paragraph("Fetal Heart Rate (FHR)", BODY_S), Paragraph("Dot •", CENTER_S),
     Paragraph("Every 30 min\n(during + after contraction)", SMALL_S),
     Paragraph("Every 5 min", SMALL_S),
     Paragraph("110-160 bpm\n⚠ <100 or >180 = fetal distress", SMALL_S)],
    [Paragraph("Amniotic Fluid", BODY_S), Paragraph("I/C/M/B", CENTER_S),
     Paragraph("Each VE", SMALL_S), Paragraph("Each VE", SMALL_S),
     Paragraph("I=Intact  C=Clear  M=Meconium  B=Blood", SMALL_S)],
    [Paragraph("Skull Moulding", BODY_S), Paragraph("0/1+/2+/3+", CENTER_S),
     Paragraph("Each VE (4-hrly)", SMALL_S), Paragraph("Each VE", SMALL_S),
     Paragraph("0-1+ normal; 2+ watch; 3+ act urgently", SMALL_S)],
    # Labour progress
    [Paragraph("Cervical Dilatation", BODY_S), Paragraph("X", CENTER_S),
     Paragraph("Every 4 hours\n(or earlier if concern)", SMALL_S),
     Paragraph("N/A", SMALL_S),
     Paragraph("≥1 cm/hr; right of alert line = act", SMALL_S)],
    [Paragraph("Descent of Head", BODY_S), Paragraph("O", CENTER_S),
     Paragraph("Every 4 hours\n(abdominal palpation)", SMALL_S),
     Paragraph("Each push\nassessment", SMALL_S),
     Paragraph("5/5 → 0/5 (fifths above symphysis)", SMALL_S)],
    [Paragraph("Uterine Contractions", BODY_S), Paragraph("Shading", CENTER_S),
     Paragraph("Every 30 min\n(count per 10 min)", SMALL_S),
     Paragraph("Every 5 min", SMALL_S),
     Paragraph("≥3 per 10 min, each >40 sec (solid box)", SMALL_S)],
    # Maternal
    [Paragraph("Pulse", BODY_S), Paragraph("• (dot)", CENTER_S),
     Paragraph("Every 30 min", SMALL_S), Paragraph("Every 30 min", SMALL_S),
     Paragraph("60-100 bpm; >120 = tachycardia", SMALL_S)],
    [Paragraph("Blood Pressure", BODY_S), Paragraph("↕ (arrows)", CENTER_S),
     Paragraph("Every 4 hours", SMALL_S), Paragraph("Every 4 hours", SMALL_S),
     Paragraph("⚠ ≥140/90 = hypertension", SMALL_S)],
    [Paragraph("Temperature", BODY_S), Paragraph("°C", CENTER_S),
     Paragraph("Every 4 hours", SMALL_S), Paragraph("Every 4 hours", SMALL_S),
     Paragraph("36.5-37.5°C; >38°C = pyrexia", SMALL_S)],
    [Paragraph("Urine (protein/acetone/vol)", BODY_S), Paragraph("+/-", CENTER_S),
     Paragraph("Each void", SMALL_S), Paragraph("Each void", SMALL_S),
     Paragraph("Protein 2+ = pre-eclampsia risk", SMALL_S)],
    [Paragraph("Oxytocin (if augmenting)", BODY_S), Paragraph("U/L, drops", CENTER_S),
     Paragraph("Every 30 min", SMALL_S), Paragraph("Every 30 min", SMALL_S),
     Paragraph("Document dose, rate changes, response", SMALL_S)],
]

col_w = [CONTENT_W*0.22, CONTENT_W*0.10, CONTENT_W*0.17, CONTENT_W*0.13, CONTENT_W*0.38]
freq_tbl = Table(freq_data, colWidths=col_w, repeatRows=1)

row_colors = []
for i in range(1, len(freq_data)):
    bg = GREY_BG if i % 2 == 0 else WHITE
    row_colors.append(("BACKGROUND", (0,i), (-1,i), bg))

freq_tbl.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,0), TEAL_LT),
    ("TEXTCOLOR",     (0,0), (-1,0), HEADER_BG),
    ("FONTNAME",      (0,0), (-1,0), "Helvetica-Bold"),
    ("GRID",          (0,0), (-1,-1), 0.4, GREY_LINE),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 4),
    ("VALIGN",        (0,0), (-1,-1), "TOP"),
    # Fetal rows background
    ("BACKGROUND",    (0,1), (-1,3), colors.HexColor("#F0FAFA")),
    # Labour rows background
    ("BACKGROUND",    (0,4), (-1,6), colors.HexColor("#F5F5FF")),
    # Maternal rows background
    ("BACKGROUND",    (0,7), (-1,-1), colors.HexColor("#FFF9F0")),
    # Row group labels
    ("FONTNAME",      (0,1), (0,3), "Helvetica-BoldOblique"),
    ("TEXTCOLOR",     (0,1), (0,3), TEAL),
    ("FONTNAME",      (0,4), (0,6), "Helvetica-BoldOblique"),
    ("TEXTCOLOR",     (0,4), (0,6), colors.HexColor("#3D405B")),
    ("FONTNAME",      (0,7), (0,-1), "Helvetica-BoldOblique"),
    ("TEXTCOLOR",     (0,7), (0,-1), ORANGE),
]))
story.append(freq_tbl)
story.append(Spacer(1, 5))

# ═══════════════════════════════════════════════════════════════════════════════
# ROW 2 (three columns): ALERT/ACTION | MOULDING | MECONIUM
# ═══════════════════════════════════════════════════════════════════════════════

# ── Alert / Action Lines ──────────────────────────────────────────────────────
alert_rows = [
    [Paragraph("Line", BOLD_S), Paragraph("Meaning", BOLD_S), Paragraph("Action", BOLD_S)],
    [Paragraph("Alert\nLine", ps("al", fontSize=7.5, textColor=GREEN, fontName="Helvetica-Bold", leading=10)),
     Paragraph("Dilatation < 1 cm/hr\nCurve crosses right", SMALL_S),
     Paragraph("Re-assess. Transfer if at BEmONC. Closer monitoring at CEmONC.", SMALL_S)],
    [Paragraph("Action\nLine", ps("acl", fontSize=7.5, textColor=RED, fontName="Helvetica-Bold", leading=10)),
     Paragraph("4 hrs right of alert\nNo progress", SMALL_S),
     Paragraph("DECIDE: Augment (oxytocin/ARM) OR caesarean section.", SMALL_S)],
]
alert_tbl = Table(alert_rows, colWidths=[1.4*cm, 3.2*cm, 4.0*cm])
alert_tbl.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,0), colors.HexColor("#2D6A4F")),
    ("TEXTCOLOR",     (0,0), (-1,0), WHITE),
    ("GRID",          (0,0), (-1,-1), 0.4, GREY_LINE),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 4),
    ("VALIGN",        (0,0), (-1,-1), "TOP"),
    ("BACKGROUND",    (0,1), (-1,1), GREEN_LT),
    ("BACKGROUND",    (0,2), (-1,2), RED_LT),
]))

# ── Moulding ─────────────────────────────────────────────────────────────────
mould_rows = [
    [Paragraph("Grade", BOLD_S), Paragraph("Finding", BOLD_S), Paragraph("Action", BOLD_S)],
    [Paragraph("0",  SMALL_S), Paragraph("Bones separated",         SMALL_S), Paragraph("Normal",          SMALL_S)],
    [Paragraph("1+", SMALL_S), Paragraph("Bones just touching",      SMALL_S), Paragraph("Monitor closely", SMALL_S)],
    [Paragraph("2+", SMALL_S), Paragraph("Overlap, reducible",       SMALL_S), Paragraph("Watch; may need intervention", SMALL_S)],
    [Paragraph("3+", ps("w3", fontSize=7.5, textColor=RED, fontName="Helvetica-Bold", leading=10)),
     Paragraph("Fixed overlap",     SMALL_S),
     Paragraph("URGENT — suspect CPD", ps("urgm", fontSize=7, textColor=RED, fontName="Helvetica-Bold", leading=10))],
]
mould_tbl = Table(mould_rows, colWidths=[0.9*cm, 2.8*cm, 2.8*cm])
mould_tbl.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,0), TEAL),
    ("TEXTCOLOR",     (0,0), (-1,0), WHITE),
    ("GRID",          (0,0), (-1,-1), 0.4, GREY_LINE),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 4),
    ("VALIGN",        (0,0), (-1,-1), "TOP"),
    ("BACKGROUND",    (0,4), (-1,4), RED_LT),
]))

# ── Meconium ──────────────────────────────────────────────────────────────────
mec_rows = [
    [Paragraph("Grade", BOLD_S), Paragraph("Appearance", BOLD_S), Paragraph("Action", BOLD_S)],
    [Paragraph("1\nThin", ps("g1", fontSize=7, textColor=GREEN, fontName="Helvetica-Bold", leading=10)),
     Paragraph("Slight yellow/green",  SMALL_S), Paragraph("Increase FHR monitoring", SMALL_S)],
    [Paragraph("2\nModerate", ps("g2", fontSize=7, textColor=AMBER, fontName="Helvetica-Bold", leading=10)),
     Paragraph("Clearly green",        SMALL_S), Paragraph("Prepare NICU/resus team", SMALL_S)],
    [Paragraph("3\nThick", ps("g3", fontSize=7, textColor=RED, fontName="Helvetica-Bold", leading=10)),
     Paragraph("Thick pea-soup",       SMALL_S),
     Paragraph("FETAL DISTRESS — expedite delivery", ps("urg", fontSize=7, textColor=RED, fontName="Helvetica-Bold", leading=10))],
]
mec_tbl = Table(mec_rows, colWidths=[1.1*cm, 2.5*cm, 3.0*cm])
mec_tbl.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,0), colors.HexColor("#78350F")),
    ("TEXTCOLOR",     (0,0), (-1,0), WHITE),
    ("GRID",          (0,0), (-1,-1), 0.4, GREY_LINE),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 4),
    ("VALIGN",        (0,0), (-1,-1), "TOP"),
    ("BACKGROUND",    (0,1), (-1,1), GREEN_LT),
    ("BACKGROUND",    (0,2), (-1,2), AMBER_LT),
    ("BACKGROUND",    (0,3), (-1,3), RED_LT),
]))

# Combine three tables in a row
three_col_hdr = Table(
    [[section_header("ALERT & ACTION LINES", GREEN),
      section_header("SKULL MOULDING GRADES", TEAL),
      section_header("MECONIUM GRADING", colors.HexColor("#78350F"))]],
    colWidths=[CONTENT_W*0.36, CONTENT_W*0.33, CONTENT_W*0.31]
)
three_col_hdr.setStyle(TableStyle([
    ("VALIGN",        (0,0), (-1,-1), "TOP"),
    ("LEFTPADDING",   (0,0), (-1,-1), 0),
    ("RIGHTPADDING",  (0,0), (0,-1), 4),
    ("RIGHTPADDING",  (0,0), (1,-1), 4),
    ("TOPPADDING",    (0,0), (-1,-1), 0),
    ("BOTTOMPADDING", (0,0), (-1,-1), 2),
]))
three_col_data = Table(
    [[alert_tbl, mould_tbl, mec_tbl]],
    colWidths=[CONTENT_W*0.36, CONTENT_W*0.33, CONTENT_W*0.31]
)
three_col_data.setStyle(TableStyle([
    ("VALIGN",        (0,0), (-1,-1), "TOP"),
    ("LEFTPADDING",   (0,0), (-1,-1), 0),
    ("RIGHTPADDING",  (0,0), (0,-1), 4),
    ("RIGHTPADDING",  (0,0), (1,-1), 4),
    ("TOPPADDING",    (0,0), (-1,-1), 0),
    ("BOTTOMPADDING", (0,0), (-1,-1), 0),
]))
story.append(three_col_hdr)
story.append(three_col_data)
story.append(Spacer(1, 5))

# ═══════════════════════════════════════════════════════════════════════════════
# CONTRACTION SHADING KEY
# ═══════════════════════════════════════════════════════════════════════════════
story.append(section_header("CONTRACTION DOCUMENTATION KEY", colors.HexColor("#3D405B")))
story.append(Spacer(1, 3))

cont_data = [
    [Paragraph("Symbol", BOLD_S), Paragraph("Duration", BOLD_S), Paragraph("Box Shading", BOLD_S), Paragraph("Interpretation", BOLD_S)],
    [Paragraph("Dotted / Stippled", BODY_S), Paragraph("< 20 seconds", SMALL_S),
     Paragraph("Dots", SMALL_S), Paragraph("Weak / Inefficient contractions", SMALL_S)],
    [Paragraph("Hatched / Diagonal lines", BODY_S), Paragraph("20-40 seconds", SMALL_S),
     Paragraph("Diagonal hatching", SMALL_S), Paragraph("Moderate contractions", SMALL_S)],
    [Paragraph("Solid / Filled black", BODY_S), Paragraph("> 40 seconds", SMALL_S),
     Paragraph("Solid fill", SMALL_S), Paragraph("Strong / Effective contractions (desired in active labour)", SMALL_S)],
]
cont_tbl = Table(cont_data, colWidths=[CONTENT_W*0.25, CONTENT_W*0.17, CONTENT_W*0.18, CONTENT_W*0.40])
cont_tbl.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,0), colors.HexColor("#3D405B")),
    ("TEXTCOLOR",     (0,0), (-1,0), WHITE),
    ("GRID",          (0,0), (-1,-1), 0.4, GREY_LINE),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 4),
    ("VALIGN",        (0,0), (-1,-1), "TOP"),
    ("BACKGROUND",    (0,1), (-1,1), GREY_BG),
    ("BACKGROUND",    (0,2), (-1,2), WHITE),
    ("BACKGROUND",    (0,3), (-1,3), GREY_BG),
]))
story.append(cont_tbl)
story.append(Spacer(1, 5))

# ═══════════════════════════════════════════════════════════════════════════════
# RED FLAGS / DANGER SIGNS
# ═══════════════════════════════════════════════════════════════════════════════
story.append(section_header("⚠  RED FLAGS — Act Immediately", RED))
story.append(Spacer(1, 3))

flags = [
    ("FHR < 100 or > 180 bpm",                    "Fetal distress — change position, O₂, IV fluids, prepare for delivery"),
    ("Dilatation curve crosses ACTION line",        "Augment or proceed to caesarean section NOW"),
    ("Moulding Grade 3+",                          "Fixed skull overlap — suspect cephalopelvic disproportion"),
    ("Thick meconium (Grade 3)",                   "Expedite delivery; NICU alert; suction at perineum"),
    ("Maternal BP ≥ 160/110 mmHg",                 "Severe hypertension — antihypertensives, consider MgSO₄"),
    ("Maternal temperature > 38°C",                "Chorioamnionitis — antibiotics, senior review, may need delivery"),
    ("Proteinuria 2+ or more",                     "Pre-eclampsia screen — check reflexes, headache, visual changes"),
    ("Absent or very weak contractions + no progress","Consider augmentation; rule out obstruction before giving oxytocin"),
    ("Sudden severe pain between contractions",    "Uterine rupture — EMERGENCY laparotomy"),
    ("Bleeding per vaginum (fresh blood)",         "Placenta praevia / abruption — immediate senior review"),
]

flag_rows = [[
    Paragraph("Red Flag", ps("rfh", fontSize=7.5, textColor=WHITE, fontName="Helvetica-Bold", leading=10)),
    Paragraph("Immediate Response", ps("rfa", fontSize=7.5, textColor=WHITE, fontName="Helvetica-Bold", leading=10)),
]]
for f, a in flags:
    flag_rows.append([
        Paragraph(f"⚠ {f}", WARN_S),
        Paragraph(a, BODY_S),
    ])

flag_tbl = Table(flag_rows, colWidths=[CONTENT_W*0.40, CONTENT_W*0.60])
flag_style = [
    ("BACKGROUND",    (0,0), (-1,0), RED),
    ("GRID",          (0,0), (-1,-1), 0.4, GREY_LINE),
    ("TOPPADDING",    (0,0), (-1,-1), 2),
    ("BOTTOMPADDING", (0,0), (-1,-1), 2),
    ("LEFTPADDING",   (0,0), (-1,-1), 5),
    ("VALIGN",        (0,0), (-1,-1), "TOP"),
]
for i in range(1, len(flag_rows)):
    bg = RED_LT if i % 2 == 1 else WHITE
    flag_style.append(("BACKGROUND", (0,i), (-1,i), bg))
flag_tbl.setStyle(TableStyle(flag_style))
story.append(flag_tbl)
story.append(Spacer(1, 5))

# ═══════════════════════════════════════════════════════════════════════════════
# STEP-BY-STEP WORKFLOW
# ═══════════════════════════════════════════════════════════════════════════════
story.append(section_header("STEP-BY-STEP WORKFLOW", TEAL))
story.append(Spacer(1, 3))

steps = [
    ("1", "ADMISSION ASSESSMENT",
     "Confirm active labour (≥4-5 cm). Document gravida/para, EDD, vitals, membrane status, FHR, presentation."),
    ("2", "PLOT FIRST POINT",
     "Place first X on the ALERT LINE at the current cervical dilatation. Note the time."),
    ("3", "EVERY 30 MINUTES",
     "Auscultate FHR (during + after contraction). Count and shade contractions. Record pulse."),
    ("4", "EVERY 4 HOURS",
     "Vaginal examination: cervical dilatation (X) + skull moulding + amniotic fluid. Abdominal palpation: descent of head (O). Record BP and temperature."),
    ("5", "CHECK THE CURVE",
     "Is the dilatation curve to the LEFT of the Alert line? ✓ Good — continue. Has it crossed RIGHT of Alert? Reassess, consider transfer. Has it reached Action line? ACT NOW."),
    ("6", "DOCUMENT ALL INTERVENTIONS",
     "Oxytocin rate, IV fluids, medications — write in the partograph in real time."),
    ("7", "SECOND STAGE",
     "Switch to FHR every 5 min. Monitor maternal pushing effort. Document time of full dilatation and time of delivery."),
    ("8", "IMMEDIATE POSTPARTUM",
     "Record time of placenta delivery, estimated blood loss, maternal vitals at 15 min and 1 hour postpartum."),
]

step_rows = []
for num, title, desc in steps:
    step_rows.append([
        Paragraph(num, ps("sn", fontSize=12, textColor=WHITE, fontName="Helvetica-Bold", alignment=TA_CENTER, leading=15)),
        Paragraph(title, LABEL_S),
        Paragraph(desc, SMALL_S),
    ])

step_tbl = Table(step_rows, colWidths=[0.7*cm, CONTENT_W*0.22, CONTENT_W*0.72])
step_style = [
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 5),
    ("RIGHTPADDING",  (0,0), (-1,-1), 5),
    ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ("GRID",          (0,0), (-1,-1), 0.4, GREY_LINE),
]
for i, (num, _, _) in enumerate(steps):
    bg = TEAL if i % 2 == 0 else TEAL_LT
    step_style.append(("BACKGROUND", (0,i), (0,i), bg))
    row_bg = colors.HexColor("#F0FAFA") if i % 2 == 0 else WHITE
    step_style.append(("BACKGROUND", (1,i), (-1,i), row_bg))
step_tbl.setStyle(TableStyle(step_style))
story.append(step_tbl)
story.append(Spacer(1, 5))

# ═══════════════════════════════════════════════════════════════════════════════
# COMMON ERRORS
# ═══════════════════════════════════════════════════════════════════════════════
story.append(section_header("COMMON DOCUMENTATION ERRORS — Avoid These", ORANGE))
story.append(Spacer(1, 3))

errors = [
    "Starting partograph in the latent phase (< 4 cm) — leads to unnecessary interventions",
    "Not starting on the alert line — placing first X anywhere other than on the alert line",
    "Auscultating FHR only between contractions — must listen during AND after",
    "Confusing descent scale (0-5 fifths) with dilatation scale on the same graph",
    "Failing to act when the alert line is crossed",
    "Delaying VE once action line is reached",
    "Omitting contraction duration from shading (just recording number, not duration)",
    "Not documenting membrane rupture time — critical for infection risk calculation",
    "Forgetting to update oxytocin dose changes in real time",
]

err_data = [[Paragraph("✗  " + e, BODY_S)] for e in errors]
err_tbl = Table(err_data, colWidths=[CONTENT_W])
err_style = [
    ("TOPPADDING",    (0,0), (-1,-1), 2),
    ("BOTTOMPADDING", (0,0), (-1,-1), 2),
    ("LEFTPADDING",   (0,0), (-1,-1), 8),
    ("GRID",          (0,0), (-1,-1), 0.4, GREY_LINE),
]
for i in range(len(err_data)):
    bg = AMBER_LT if i % 2 == 0 else WHITE
    err_style.append(("BACKGROUND", (0,i), (-1,i), bg))
    err_style.append(("TEXTCOLOR", (0,i), (-1,i), colors.HexColor("#7C2D12")))
err_tbl.setStyle(TableStyle(err_style))
story.append(err_tbl)
story.append(Spacer(1, 5))

# ═══════════════════════════════════════════════════════════════════════════════
# FOOTER
# ═══════════════════════════════════════════════════════════════════════════════
story.append(HRFlowable(width=CONTENT_W, thickness=0.5, color=GREY_LINE))
story.append(Spacer(1, 3))
footer_data = [[
    Paragraph("Based on: WHO Labour Care Guide (2020) | MSF Essential Obstetric Care Guidelines | Park's Preventive & Social Medicine", FOOT_S),
    Paragraph("For clinical reference only — always follow local institutional protocols", ps("fr", fontSize=6.5, textColor=RED, fontName="Helvetica-Oblique", alignment=TA_RIGHT, leading=9)),
]]
footer_tbl = Table(footer_data, colWidths=[CONTENT_W*0.65, CONTENT_W*0.35])
footer_tbl.setStyle(TableStyle([
    ("VALIGN",        (0,0), (-1,-1), "TOP"),
    ("LEFTPADDING",   (0,0), (-1,-1), 0),
    ("TOPPADDING",    (0,0), (-1,-1), 0),
]))
story.append(footer_tbl)

# ── Build ─────────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF created: {OUTPUT}")
Running Command

cd /home/daytona/workspace/partograph && python3 build_checklist.py 2>&1

Running Command

ls -lh /home/daytona/workspace/partograph/Partograph_Checklist.pdf

Your PDF checklist is ready:

Partograph Checklist

PDF Document · PDF


Here is what the single-page PDF contains, organized into colour-coded sections:
SectionContents
HeaderTitle banner with WHO/MSF reference
Before You Start5 admission checkboxes + Patient identifier fields (2-column layout)
Monitoring Frequency TableAll parameters (FHR, amniotic fluid, moulding, cervix, descent, contractions, BP, pulse, temp, urine, oxytocin) with symbol, frequency per stage, and normal range
Alert & Action LinesSide-by-side tables: what each line means + required action
Skull Moulding GradesGrade 0 to 3+ with colour-coded actions (green → red)
Meconium GradingGrade 1 (thin) to Grade 3 (thick) with responses
Contraction Shading KeyDotted / hatched / solid with duration and meaning
Red Flags10 danger signs with immediate responses (red background)
Step-by-Step Workflow8 numbered steps from admission through postpartum
Common Errors9 documentation mistakes to avoid (amber background)
FooterSource citations + "for reference only" disclaimer
Print it A4 and laminate it for the delivery room wall or keep it inside the labour room binder.
This is a shared conversation. Sign in to Orris to start your own chat.