I dont know about this topics. I want to easily understand about this topic in easy language with flowsheet and with diagram also. Provide me a pdf that contains all the topic along with diagram and flowsheet diagram
mkdir -p /home/daytona/workspace/shock-notes && ls /home/daytona/workspace/shock-notes/
~/shock-notes/generate_pdf.py
#!/usr/bin/env python3
"""
Shock, Haemorrhage and Transfusion - Easy Study Notes PDF
Uses ReportLab to create a comprehensive, visually rich PDF
"""
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_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether, PageBreak
)
from reportlab.platypus.flowables import Flowable
from reportlab.graphics.shapes import (
Drawing, Rect, String, Line, Arrow, Polygon,
Circle, Group, Path
)
from reportlab.graphics import renderPDF
from reportlab.graphics.shapes import Drawing, Rect, String, Line, Circle, Polygon, Path, Group
import math
# ─────────────────────────────────────────────
# COLOR PALETTE
# ─────────────────────────────────────────────
C_RED = colors.HexColor("#C0392B")
C_DARK_RED = colors.HexColor("#922B21")
C_ORANGE = colors.HexColor("#E67E22")
C_YELLOW = colors.HexColor("#F4D03F")
C_GREEN = colors.HexColor("#1E8449")
C_LIGHT_GREEN = colors.HexColor("#D5F5E3")
C_BLUE = colors.HexColor("#1A5276")
C_LIGHT_BLUE= colors.HexColor("#D6EAF8")
C_TEAL = colors.HexColor("#117A65")
C_LIGHT_TEAL= colors.HexColor("#D1F2EB")
C_PURPLE = colors.HexColor("#6C3483")
C_LIGHT_PURPLE = colors.HexColor("#E8DAEF")
C_GREY = colors.HexColor("#F2F3F4")
C_DARK_GREY = colors.HexColor("#555555")
C_BLACK = colors.black
C_WHITE = colors.white
C_BG = colors.HexColor("#FDFEFE")
C_HEADER_BG = colors.HexColor("#1A5276")
C_BOX_WARN = colors.HexColor("#FDEBD0")
C_BOX_INFO = colors.HexColor("#EBF5FB")
C_BOX_TIP = colors.HexColor("#E9F7EF")
# ─────────────────────────────────────────────
# CUSTOM FLOWABLE: Colored Box
# ─────────────────────────────────────────────
class ColorBox(Flowable):
def __init__(self, width, height, fill_color, stroke_color=None, radius=6):
super().__init__()
self.width = width
self.height = height
self.fill_color = fill_color
self.stroke_color = stroke_color or fill_color
self.radius = radius
def draw(self):
self.canv.setFillColor(self.fill_color)
self.canv.setStrokeColor(self.stroke_color)
self.canv.roundRect(0, 0, self.width, self.height, self.radius, fill=1, stroke=1)
# ─────────────────────────────────────────────
# CUSTOM FLOWABLE: Flowchart - Types of Shock
# ─────────────────────────────────────────────
class ShockTypesFlowchart(Flowable):
def __init__(self, width=500):
super().__init__()
self.width = width
self.height = 320
def draw(self):
c = self.canv
w = self.width
# Title box - SHOCK
c.setFillColor(C_DARK_RED)
c.setStrokeColor(C_DARK_RED)
c.roundRect(w/2-80, 270, 160, 42, 8, fill=1, stroke=0)
c.setFillColor(C_WHITE)
c.setFont("Helvetica-Bold", 16)
c.drawCentredString(w/2, 285, "⚠ SHOCK")
# Arrow down
c.setStrokeColor(C_DARK_GREY)
c.setLineWidth(1.5)
c.line(w/2, 270, w/2, 248)
# Arrowhead
c.setFillColor(C_DARK_GREY)
c.polygon([w/2-5, 252, w/2+5, 252, w/2, 240], fill=1, stroke=0)
# Splitter bar
c.setStrokeColor(C_DARK_GREY)
c.setLineWidth(1.5)
c.line(55, 240, w-55, 240)
# 5 boxes for types
types = [
("Haemorrhagic\n/Hypovolaemic", C_RED, C_WHITE, 35),
("Cardiogenic", colors.HexColor("#1A5276"), C_WHITE, 130),
("Obstructive", colors.HexColor("#117A65"), C_WHITE, 225),
("Distributive\n(Septic/Anaphylactic)", colors.HexColor("#6C3483"), C_WHITE, 320),
("Endocrine", colors.HexColor("#784212"), C_WHITE, 415),
]
box_w = 85
box_h = 52
for label, bg, fg, x_center in types:
# Vertical line down
c.setStrokeColor(C_DARK_GREY)
c.setLineWidth(1)
c.line(x_center, 240, x_center, 215)
# Arrow tip
c.setFillColor(C_DARK_GREY)
c.polygon([x_center-4, 218, x_center+4, 218, x_center, 207], fill=1, stroke=0)
# Box
c.setFillColor(bg)
c.setStrokeColor(bg)
c.roundRect(x_center - box_w//2, 150, box_w, box_h, 6, fill=1, stroke=0)
c.setFillColor(fg)
c.setFont("Helvetica-Bold", 7.5)
lines = label.split('\n')
if len(lines) == 2:
c.drawCentredString(x_center, 150 + box_h - 15, lines[0])
c.drawCentredString(x_center, 150 + box_h - 27, lines[1])
else:
c.drawCentredString(x_center, 150 + box_h//2 - 4, label)
# Brief description below each box
descs = [
("Low blood\nvolume", 35),
("Heart\npump fails", 130),
("Blocked\nblood flow", 225),
("Vessels\nwiden abnormally", 320),
("Hormone\ndeficiency", 415),
]
for desc, x_center in descs:
c.setFillColor(C_DARK_GREY)
c.setFont("Helvetica", 6.5)
lines = desc.split('\n')
c.drawCentredString(x_center, 143, lines[0])
if len(lines) > 1:
c.drawCentredString(x_center, 134, lines[1])
# Common feature bar at bottom
c.setFillColor(colors.HexColor("#FDEBD0"))
c.setStrokeColor(C_ORANGE)
c.setLineWidth(1)
c.roundRect(20, 10, w-40, 40, 6, fill=1, stroke=1)
c.setFillColor(C_DARK_RED)
c.setFont("Helvetica-Bold", 9)
c.drawCentredString(w/2, 37, "ALL TYPES share: Low tissue perfusion → Cells switch to anaerobic metabolism → Lactic acidosis")
c.setFont("Helvetica", 8)
c.setFillColor(C_DARK_GREY)
c.drawCentredString(w/2, 22, "→ Cell death if not treated quickly")
def wrap(self, *args):
return self.width, self.height
# ─────────────────────────────────────────────
# CUSTOM FLOWABLE: Pathophysiology Cascade
# ─────────────────────────────────────────────
class PathophysiologyCascade(Flowable):
def __init__(self, width=480):
super().__init__()
self.width = width
self.height = 360
def draw(self):
c = self.canv
w = self.width
steps = [
("TRIGGER: Injury / Blood loss / Infection / Heart failure",
colors.HexColor("#C0392B"), C_WHITE),
("↓ Preload & Blood pressure drop",
colors.HexColor("#E74C3C"), C_WHITE),
("Baroreceptors detect low BP → Brain signals ↑ sympathetic activity",
colors.HexColor("#D35400"), C_WHITE),
("↑ Heart rate + Vasoconstriction (to maintain BP)",
colors.HexColor("#E67E22"), colors.black),
("Cells get LESS oxygen → Switch to anaerobic respiration",
colors.HexColor("#F39C12"), colors.black),
("Lactic acid builds up → Metabolic acidosis",
colors.HexColor("#F1C40F"), colors.black),
("Kidneys: ↓ filtration → ↓ urine output",
colors.HexColor("#2ECC71"), colors.black),
("Endocrine: ADH + Cortisol + Catecholamines released",
colors.HexColor("#1ABC9C"), colors.black),
("If untreated: Multiple Organ Failure → DEATH",
colors.HexColor("#8E44AD"), C_WHITE),
]
box_h = 30
gap = 8
start_y = self.height - 20
box_w = w - 40
for i, (text, bg, fg) in enumerate(steps):
y = start_y - i * (box_h + gap)
c.setFillColor(bg)
c.setStrokeColor(colors.HexColor("#AAAAAA"))
c.setLineWidth(0.5)
c.roundRect(20, y - box_h, box_w, box_h, 5, fill=1, stroke=1)
c.setFillColor(fg)
c.setFont("Helvetica-Bold" if i == 0 or i == len(steps)-1 else "Helvetica", 8.5)
c.drawCentredString(w/2, y - box_h + 10, text)
# Arrow (except last)
if i < len(steps) - 1:
mid_x = w / 2
arrow_top = y - box_h
arrow_bot = arrow_top - gap
c.setStrokeColor(C_DARK_GREY)
c.setLineWidth(1.5)
c.line(mid_x, arrow_top, mid_x, arrow_bot + 4)
c.setFillColor(C_DARK_GREY)
c.polygon([mid_x-4, arrow_bot+5, mid_x+4, arrow_bot+5, mid_x, arrow_bot-1], fill=1, stroke=0)
def wrap(self, *args):
return self.width, self.height
# ─────────────────────────────────────────────
# CUSTOM FLOWABLE: Haemorrhage Classes Diagram
# ─────────────────────────────────────────────
class HaemorrhageClasses(Flowable):
def __init__(self, width=490):
super().__init__()
self.width = width
self.height = 220
def draw(self):
c = self.canv
w = self.width
# Title
c.setFillColor(C_DARK_RED)
c.setFont("Helvetica-Bold", 11)
c.drawCentredString(w/2, 205, "TRADITIONAL CLASSIFICATION OF HAEMORRHAGIC SHOCK (4 Classes)")
classes = [
("CLASS I\n(Mild)", "<15%\n<750 mL", "Normal BP\nNormal HR\nNormal urine\nMild anxiety", colors.HexColor("#82E0AA")),
("CLASS II\n(Compensated)", "15-30%\n750-1500 mL", "Normal BP\n↑ HR\nReduced urine\nAnxious", colors.HexColor("#F9E79F")),
("CLASS III\n(Moderate)", "30-40%\n1500-2000 mL", "↓ BP\n↑↑ HR\nAnuric\nConfused", colors.HexColor("#F0B27A")),
("CLASS IV\n(Severe)", ">40%\n>2000 mL", "↓↓ BP\n↑↑↑ HR\nAnuric\nComatose", colors.HexColor("#E74C3C")),
]
box_w = (w - 60) / 4
for i, (cls, vol, signs, color) in enumerate(classes):
x = 20 + i * (box_w + 6)
# Main box
c.setFillColor(color)
c.setStrokeColor(colors.HexColor("#888888"))
c.setLineWidth(0.8)
c.roundRect(x, 30, box_w, 160, 6, fill=1, stroke=1)
# Class label
c.setFillColor(C_WHITE if i >= 2 else C_BLACK)
c.setFont("Helvetica-Bold", 9)
for j, line in enumerate(cls.split('\n')):
c.drawCentredString(x + box_w/2, 170 - j*13, line)
# Volume
c.setFont("Helvetica-Bold", 8)
c.setFillColor(C_WHITE if i == 3 else colors.HexColor("#1A1A1A"))
for j, line in enumerate(vol.split('\n')):
c.drawCentredString(x + box_w/2, 140 - j*12, line)
# Signs
c.setFont("Helvetica", 7.5)
c.setFillColor(C_WHITE if i >= 2 else colors.HexColor("#1A1A1A"))
for j, line in enumerate(signs.split('\n')):
c.drawCentredString(x + box_w/2, 108 - j*13, line)
# Arrow showing severity
c.setStrokeColor(C_DARK_RED)
c.setLineWidth(2)
c.line(20, 18, w-20, 18)
c.setFillColor(C_DARK_RED)
c.polygon([w-20, 22, w-20, 14, w-10, 18], fill=1, stroke=0)
c.setFont("Helvetica-Bold", 8)
c.setFillColor(C_DARK_RED)
c.drawString(22, 10, "Increasing Severity →")
def wrap(self, *args):
return self.width, self.height
# ─────────────────────────────────────────────
# CUSTOM FLOWABLE: Damage Control Resuscitation
# ─────────────────────────────────────────────
class DCRFlowchart(Flowable):
def __init__(self, width=490):
super().__init__()
self.width = width
self.height = 300
def draw(self):
c = self.canv
w = self.width
# Header
c.setFillColor(C_DARK_RED)
c.roundRect(10, 268, w-20, 28, 5, fill=1, stroke=0)
c.setFillColor(C_WHITE)
c.setFont("Helvetica-Bold", 11)
c.drawCentredString(w/2, 278, "DAMAGE CONTROL RESUSCITATION (DCR) FLOWCHART")
# Phase 1
c.setFillColor(colors.HexColor("#FDEDEC"))
c.setStrokeColor(C_RED)
c.setLineWidth(1.2)
c.roundRect(10, 200, w/2 - 20, 60, 6, fill=1, stroke=1)
c.setFillColor(C_RED)
c.setFont("Helvetica-Bold", 9)
c.drawCentredString(w/4, 252, "PHASE 1: ACTIVE BLEEDING")
c.setFont("Helvetica", 8)
c.setFillColor(C_DARK_GREY)
phase1 = ["• Stop the bleeding FIRST", "• Permissive hypotension (MAP >50 mmHg)", "• Balanced transfusion (RBC:FFP:Platelets = 1:1:1)", "• Tranexamic acid ASAP"]
for i, line in enumerate(phase1):
c.drawString(20, 240 - i*13, line)
# Phase 2
c.setFillColor(colors.HexColor("#EBF5FB"))
c.setStrokeColor(C_BLUE)
c.setLineWidth(1.2)
c.roundRect(w/2 + 10, 200, w/2 - 20, 60, 6, fill=1, stroke=1)
c.setFillColor(C_BLUE)
c.setFont("Helvetica-Bold", 9)
c.drawCentredString(3*w/4, 252, "PHASE 2: BLEEDING CONTROLLED")
c.setFont("Helvetica", 8)
c.setFillColor(C_DARK_GREY)
phase2 = ["• Target normal end-organ perfusion", "• IV fluids + vasopressors if needed", "• Monitor: BP, HR, urine output", "• Fix coagulopathy"]
for i, line in enumerate(phase2):
c.drawString(w/2 + 20, 240 - i*13, line)
# Arrow between phases
c.setStrokeColor(C_DARK_GREY)
c.setLineWidth(1.5)
c.line(w/2 - 10, 230, w/2 + 10, 230)
c.setFillColor(C_DARK_GREY)
c.polygon([w/2+6, 233, w/2+6, 227, w/2+12, 230], fill=1, stroke=0)
# 4 principles boxes
principles = [
("1. RAPID\nHAEMORRHAGE\nCONTROL", C_RED),
("2. PERMISSIVE\nHYPOTENSION\n(MAP ~50)", C_ORANGE),
("3. AVOID\nDILUTIONAL\nCOAGULOPATHY", C_BLUE),
("4. TREAT\nCOAGULATION\nDEFICITS", C_TEAL),
]
c.setFillColor(C_DARK_GREY)
c.setFont("Helvetica-Bold", 8.5)
c.drawCentredString(w/2, 192, "4 KEY PRINCIPLES OF DCR")
pw = (w - 40) / 4
for i, (text, bg) in enumerate(principles):
x = 10 + i * (pw + 6)
c.setFillColor(bg)
c.setStrokeColor(bg)
c.roundRect(x, 120, pw, 62, 5, fill=1, stroke=0)
c.setFillColor(C_WHITE)
c.setFont("Helvetica-Bold", 7.5)
lines = text.split('\n')
for j, line in enumerate(lines):
c.drawCentredString(x + pw/2, 168 - j*14, line)
# Monitoring row
c.setFillColor(colors.HexColor("#E8DAEF"))
c.setStrokeColor(C_PURPLE)
c.setLineWidth(1)
c.roundRect(10, 70, w-20, 42, 5, fill=1, stroke=1)
c.setFillColor(C_PURPLE)
c.setFont("Helvetica-Bold", 9)
c.drawString(20, 101, "MONITOR:")
c.setFont("Helvetica", 8)
c.setFillColor(C_DARK_GREY)
monitors = ["BP + HR (continuous)", "Urine output (hourly)", "pH / Lactate / Base deficit", "PT / Fibrinogen / ROTEM", "Temp (avoid hypothermia)"]
col_w = (w - 60) / len(monitors)
for i, m in enumerate(monitors):
c.drawString(75 + i * (col_w + 8), 101, f"• {m}")
# Outcome box
c.setFillColor(C_LIGHT_GREEN)
c.setStrokeColor(C_GREEN)
c.roundRect(10, 10, w-20, 52, 5, fill=1, stroke=1)
c.setFillColor(C_GREEN)
c.setFont("Helvetica-Bold", 9)
c.drawCentredString(w/2, 52, "GOAL: Haemostasis → Normal physiology → Definitive repair")
c.setFont("Helvetica", 8)
c.setFillColor(C_DARK_GREY)
goals = [
"Temp >36°C | pH >7.35 | Lactate <2 | Hb >7 g/dL | Platelet >50×10⁹/L | Fibrinogen >2 g/L"
]
for i, g in enumerate(goals):
c.drawCentredString(w/2, 36 - i*14, g)
def wrap(self, *args):
return self.width, self.height
# ─────────────────────────────────────────────
# CUSTOM FLOWABLE: Fluid Response Flowchart
# ─────────────────────────────────────────────
class FluidResponseFlowchart(Flowable):
def __init__(self, width=460):
super().__init__()
self.width = width
self.height = 260
def draw(self):
c = self.canv
w = self.width
# Start
c.setFillColor(C_BLUE)
c.roundRect(w/2-100, 235, 200, 28, 6, fill=1, stroke=0)
c.setFillColor(C_WHITE)
c.setFont("Helvetica-Bold", 9)
c.drawCentredString(w/2, 245, "Give Bolus IV Fluid / Blood Transfusion")
# Arrow
c.setStrokeColor(C_DARK_GREY)
c.setLineWidth(1.5)
c.line(w/2, 235, w/2, 215)
c.setFillColor(C_DARK_GREY)
c.polygon([w/2-4, 218, w/2+4, 218, w/2, 207], fill=1, stroke=0)
# Decision diamond
c.setFillColor(colors.HexColor("#FEF9E7"))
c.setStrokeColor(C_ORANGE)
c.setLineWidth(1.5)
pts = [w/2, 200, w/2+90, 170, w/2, 140, w/2-90, 170]
path = c.beginPath()
path.moveTo(pts[0], pts[1])
path.lineTo(pts[2], pts[3])
path.lineTo(pts[4], pts[5])
path.lineTo(pts[6], pts[7])
path.close()
c.drawPath(path, fill=1, stroke=1)
c.setFillColor(C_DARK_GREY)
c.setFont("Helvetica-Bold", 8)
c.drawCentredString(w/2, 178, "Blood pressure response?")
# Three branches
# RESPONDER (left)
c.setStrokeColor(C_DARK_GREY)
c.setLineWidth(1.2)
c.line(w/2-90, 170, 50, 170)
c.line(50, 170, 50, 120)
c.setFillColor(C_DARK_GREY)
c.polygon([46, 122, 54, 122, 50, 110], fill=1, stroke=0)
c.setFillColor(C_LIGHT_GREEN)
c.setStrokeColor(C_GREEN)
c.roundRect(10, 70, 110, 38, 5, fill=1, stroke=1)
c.setFillColor(C_GREEN)
c.setFont("Helvetica-Bold", 8)
c.drawCentredString(65, 100, "RESPONDER ✓")
c.setFont("Helvetica", 7.5)
c.setFillColor(C_DARK_GREY)
c.drawCentredString(65, 88, "Good & sustained BP rise")
c.drawCentredString(65, 78, "→ Bleeding controlled")
c.setFillColor(C_GREEN)
c.setFont("Helvetica-BoldOblique", 7)
c.drawCentredString(50, 162, "Good BP rise")
# TRANSIENT (centre)
c.setStrokeColor(C_DARK_GREY)
c.line(w/2, 140, w/2, 110)
c.setFillColor(C_DARK_GREY)
c.polygon([w/2-4, 112, w/2+4, 112, w/2, 102], fill=1, stroke=0)
c.setFillColor(C_BOX_WARN)
c.setStrokeColor(C_ORANGE)
c.roundRect(w/2-70, 60, 140, 40, 5, fill=1, stroke=1)
c.setFillColor(C_ORANGE)
c.setFont("Helvetica-Bold", 8)
c.drawCentredString(w/2, 91, "TRANSIENT RESPONDER ⚠")
c.setFont("Helvetica", 7.5)
c.setFillColor(C_DARK_GREY)
c.drawCentredString(w/2, 79, "BP rises then falls again")
c.drawCentredString(w/2, 69, "→ Still bleeding → Operate!")
c.setFillColor(C_ORANGE)
c.setFont("Helvetica-BoldOblique", 7)
c.drawCentredString(w/2, 133, "BP rises, not sustained")
# NON-RESPONDER (right)
c.setStrokeColor(C_DARK_GREY)
c.line(w/2+90, 170, w-50, 170)
c.line(w-50, 170, w-50, 120)
c.setFillColor(C_DARK_GREY)
c.polygon([w-54, 122, w-46, 122, w-50, 110], fill=1, stroke=0)
c.setFillColor(colors.HexColor("#FDEDEC"))
c.setStrokeColor(C_RED)
c.roundRect(w-120, 70, 110, 40, 5, fill=1, stroke=1)
c.setFillColor(C_RED)
c.setFont("Helvetica-Bold", 8)
c.drawCentredString(w-65, 101, "NON-RESPONDER ✗")
c.setFont("Helvetica", 7.5)
c.setFillColor(C_DARK_GREY)
c.drawCentredString(w-65, 89, "No BP improvement")
c.drawCentredString(w-65, 78, "→ Massive haemorrhage")
c.setFillColor(C_RED)
c.setFont("Helvetica-BoldOblique", 7)
c.drawCentredString(w-50, 162, "No BP change")
# Bottom action bar
c.setFillColor(C_LIGHT_BLUE)
c.setStrokeColor(C_BLUE)
c.roundRect(10, 8, w-20, 32, 5, fill=1, stroke=1)
c.setFont("Helvetica-Bold", 8.5)
c.setFillColor(C_BLUE)
c.drawCentredString(w/2, 32, "Action: Identify bleeding source → Activate Major Haemorrhage Protocol → Damage Control Surgery")
def wrap(self, *args):
return self.width, self.height
# ─────────────────────────────────────────────
# CUSTOM FLOWABLE: Transfusion Decision Tree
# ─────────────────────────────────────────────
class TransfusionDecision(Flowable):
def __init__(self, width=460):
super().__init__()
self.width = width
self.height = 230
def draw(self):
c = self.canv
w = self.width
# Title
c.setFillColor(C_TEAL)
c.roundRect(10, 208, w-20, 24, 5, fill=1, stroke=0)
c.setFillColor(C_WHITE)
c.setFont("Helvetica-Bold", 10)
c.drawCentredString(w/2, 216, "BLOOD TRANSFUSION DECISION TREE")
# Hb thresholds
thresholds = [
("<6 g/dL", "TRANSFUSE NOW\n(Probably will benefit)", colors.HexColor("#E74C3C"), C_WHITE),
("6-8 g/dL", "TRANSFUSE IF:\nBleeding / Pre-op / Symptoms", colors.HexColor("#E67E22"), C_WHITE),
(">8 g/dL", "NO TRANSFUSION\n(No indication in stable patient)", colors.HexColor("#27AE60"), C_WHITE),
]
bw = (w - 40) / 3
for i, (hb, action, bg, fg) in enumerate(thresholds):
x = 10 + i * (bw + 5)
# Hb label
c.setFillColor(C_DARK_GREY)
c.setFont("Helvetica-Bold", 9)
c.drawCentredString(x + bw/2, 196, f"Haemoglobin = {hb}")
# Arrow
c.setStrokeColor(C_DARK_GREY)
c.setLineWidth(1)
c.line(x + bw/2, 192, x + bw/2, 178)
c.setFillColor(C_DARK_GREY)
c.polygon([x+bw/2-4, 181, x+bw/2+4, 181, x+bw/2, 172], fill=1, stroke=0)
# Action box
c.setFillColor(bg)
c.setStrokeColor(bg)
c.roundRect(x, 120, bw, 50, 6, fill=1, stroke=0)
c.setFillColor(fg)
c.setFont("Helvetica-Bold", 8)
lines = action.split('\n')
c.drawCentredString(x + bw/2, 158, lines[0])
if len(lines) > 1:
c.setFont("Helvetica", 7.5)
c.drawCentredString(x + bw/2, 145, lines[1])
# Products table
c.setFillColor(colors.HexColor("#EBF5FB"))
c.setStrokeColor(C_BLUE)
c.roundRect(10, 10, w-20, 100, 5, fill=1, stroke=1)
c.setFillColor(C_BLUE)
c.setFont("Helvetica-Bold", 9)
c.drawString(18, 100, "BLOOD PRODUCTS QUICK GUIDE:")
products = [
("Packed Red Blood Cells (pRBC)", "Carries oxygen - given for blood loss / anaemia"),
("Fresh Frozen Plasma (FFP)", "Has clotting factors - given for coagulopathy"),
("Platelets", "Helps clotting - given if platelets <50×10⁹/L or dysfunctional"),
("Cryoprecipitate", "Rich in fibrinogen + Factor VIII - given for low fibrinogen"),
("Tranexamic Acid", "Stops fibrinolysis (clot breakdown) - give EARLY in trauma"),
]
c.setFont("Helvetica", 8)
c.setFillColor(C_DARK_GREY)
for i, (prod, use) in enumerate(products):
y = 88 - i * 16
c.setFont("Helvetica-Bold", 7.5)
c.setFillColor(C_BLUE)
c.drawString(18, y, f"• {prod}:")
c.setFont("Helvetica", 7.5)
c.setFillColor(C_DARK_GREY)
c.drawString(18 + 155, y, use)
def wrap(self, *args):
return self.width, self.height
# ─────────────────────────────────────────────
# CUSTOM FLOWABLE: Shock Resuscitation Steps
# ─────────────────────────────────────────────
class ResuscitationSteps(Flowable):
def __init__(self, width=490):
super().__init__()
self.width = width
self.height = 200
def draw(self):
c = self.canv
w = self.width
steps = [
("AIRWAY", "Ensure patent airway\nand ventilation", colors.HexColor("#C0392B"), "A"),
("BREATHING", "Assess breathing\nOxygenation 100%", colors.HexColor("#D35400"), "B"),
("CIRCULATION", "IV access (large bore)\nFluid resuscitation", colors.HexColor("#1A5276"), "C"),
("STOP BLEEDING", "Pressure / Tourniquet\nActivate MHP", colors.HexColor("#117A65"), "D"),
("MONITOR", "BP, HR, SpO₂\nUrine output / GCS", colors.HexColor("#6C3483"), "E"),
("DEFINITIVE Rx", "Surgery / ICU\nEnd-organ support", colors.HexColor("#1A5276"), "F"),
]
step_w = (w - 20) / 6 - 4
for i, (title, desc, bg, letter) in enumerate(steps):
x = 10 + i * (step_w + 5)
# Main box
c.setFillColor(bg)
c.setStrokeColor(bg)
c.roundRect(x, 50, step_w, 130, 6, fill=1, stroke=0)
# Letter circle
c.setFillColor(C_WHITE)
c.circle(x + step_w/2, 165, 14, fill=1, stroke=0)
c.setFillColor(bg)
c.setFont("Helvetica-Bold", 14)
c.drawCentredString(x + step_w/2, 159, letter)
# Title
c.setFillColor(C_WHITE)
c.setFont("Helvetica-Bold", 7.5)
c.drawCentredString(x + step_w/2, 148, title)
# Desc
c.setFont("Helvetica", 7)
for j, line in enumerate(desc.split('\n')):
c.drawCentredString(x + step_w/2, 130 - j*14, line)
# Arrow
if i < len(steps) - 1:
c.setFillColor(C_DARK_GREY)
c.setStrokeColor(C_DARK_GREY)
ax = x + step_w + 2.5
c.polygon([ax, 118, ax+4, 122, ax+4, 114], fill=1, stroke=0)
# Goal bar
c.setFillColor(C_LIGHT_GREEN)
c.setStrokeColor(C_GREEN)
c.roundRect(10, 10, w-20, 32, 5, fill=1, stroke=1)
c.setFillColor(C_GREEN)
c.setFont("Helvetica-Bold", 9)
c.drawCentredString(w/2, 34, "RESUSCITATION END POINTS")
c.setFont("Helvetica", 8)
c.setFillColor(C_DARK_GREY)
c.drawCentredString(w/2, 20, "Urine output >0.5 mL/kg/hr | Lactate <2 mmol/L | Normal base deficit | Mixed venous O₂ sat >70%")
def wrap(self, *args):
return self.width, self.height
# ─────────────────────────────────────────────
# HELPER: Styled section heading
# ─────────────────────────────────────────────
def section_heading(text, color=C_BLUE, size=14):
d = Drawing(490, 30)
d.add(Rect(0, 0, 490, 28, fillColor=color, strokeColor=color, rx=5, ry=5))
d.add(String(12, 9, text, fontSize=size, fontName='Helvetica-Bold', fillColor=colors.white))
return d
def sub_heading(text, color=C_TEAL):
d = Drawing(490, 22)
d.add(Rect(0, 0, 490, 20, fillColor=color, strokeColor=color, rx=3, ry=3))
d.add(String(8, 5, text, fontSize=11, fontName='Helvetica-Bold', fillColor=colors.white))
return d
def info_box(lines_list, bg_color=C_BOX_INFO, border_color=C_BLUE):
data = [[Paragraph(line, ParagraphStyle('ib', fontName='Helvetica', fontSize=8.5,
leading=13, textColor=C_DARK_GREY))]
for line in lines_list]
t = Table(data, colWidths=[460])
t.setStyle(TableStyle([
('BACKGROUND', (0, 0), (-1, -1), bg_color),
('BOX', (0, 0), (-1, -1), 1, border_color),
('ROWBACKGROUNDS', (0, 0), (-1, -1), [bg_color]),
('TOPPADDING', (0, 0), (-1, -1), 4),
('BOTTOMPADDING', (0, 0), (-1, -1), 4),
('LEFTPADDING', (0, 0), (-1, -1), 10),
('ROUNDEDCORNERS', [6, 6, 6, 6]),
]))
return t
def key_point(text, bg=colors.HexColor("#FEF9E7"), border=C_ORANGE):
style = ParagraphStyle('kp', fontName='Helvetica-BoldOblique', fontSize=9,
leading=14, textColor=C_DARK_GREY)
t = Table([[Paragraph(f"💡 {text}", style)]], colWidths=[460])
t.setStyle(TableStyle([
('BACKGROUND', (0, 0), (-1, -1), bg),
('BOX', (0, 0), (-1, -1), 1.5, border),
('TOPPADDING', (0, 0), (-1, -1), 6),
('BOTTOMPADDING', (0, 0), (-1, -1), 6),
('LEFTPADDING', (0, 0), (-1, -1), 10),
]))
return t
def comparison_table(headers, rows, col_widths=None):
data = [headers] + rows
if not col_widths:
col_widths = [460 // len(headers)] * len(headers)
t = Table(data, colWidths=col_widths)
style = [
('BACKGROUND', (0, 0), (-1, 0), C_BLUE),
('TEXTCOLOR', (0, 0), (-1, 0), C_WHITE),
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
('FONTSIZE', (0, 0), (-1, 0), 9),
('ALIGN', (0, 0), (-1, -1), 'CENTER'),
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
('FONTNAME', (0, 1), (-1, -1), 'Helvetica'),
('FONTSIZE', (0, 1), (-1, -1), 8),
('GRID', (0, 0), (-1, -1), 0.5, colors.HexColor("#AAAAAA")),
('ROWBACKGROUNDS', (0, 1), (-1, -1), [C_WHITE, C_GREY]),
('TOPPADDING', (0, 0), (-1, -1), 5),
('BOTTOMPADDING', (0, 0), (-1, -1), 5),
]
t.setStyle(TableStyle(style))
return t
# ─────────────────────────────────────────────
# BUILD PDF
# ─────────────────────────────────────────────
def build_pdf():
output_path = "/home/daytona/workspace/shock-notes/Shock_Haemorrhage_Transfusion_Notes.pdf"
doc = SimpleDocTemplate(
output_path,
pagesize=A4,
rightMargin=1.8*cm, leftMargin=1.8*cm,
topMargin=1.8*cm, bottomMargin=1.8*cm,
title="Shock, Haemorrhage and Transfusion - Easy Study Notes",
author="Bailey & Love Surgical Notes"
)
styles = getSampleStyleSheet()
normal = ParagraphStyle('normal', fontName='Helvetica', fontSize=9, leading=14,
textColor=C_DARK_GREY, spaceAfter=4)
bold_normal = ParagraphStyle('bold_normal', fontName='Helvetica-Bold', fontSize=9.5,
leading=14, textColor=C_DARK_GREY, spaceAfter=3)
body = ParagraphStyle('body', fontName='Helvetica', fontSize=9, leading=15,
textColor=colors.HexColor("#2C3E50"), spaceAfter=5, spaceBefore=2,
alignment=TA_JUSTIFY)
story = []
sp = lambda n=6: Spacer(1, n)
HR = lambda: HRFlowable(width="100%", thickness=0.5, color=colors.HexColor("#CCCCCC"), spaceAfter=4)
# ──────────────────────────────────────────
# COVER / TITLE
# ──────────────────────────────────────────
cover = Drawing(490, 100)
cover.add(Rect(0, 0, 490, 100, fillColor=C_DARK_RED, strokeColor=C_DARK_RED, rx=10, ry=10))
cover.add(String(245, 72, "CHAPTER 2", fontSize=13, fontName='Helvetica',
fillColor=colors.HexColor("#FAB8B8"), textAnchor='middle'))
cover.add(String(245, 50, "Shock, Haemorrhage & Transfusion", fontSize=20,
fontName='Helvetica-Bold', fillColor=C_WHITE, textAnchor='middle'))
cover.add(String(245, 28, "Easy Study Notes • Bailey & Love Surgery", fontSize=11,
fontName='Helvetica-Oblique', fillColor=colors.HexColor("#FAD7A0"),
textAnchor='middle'))
cover.add(String(245, 10, "Complete guide with Flowcharts, Diagrams & Tables", fontSize=9,
fontName='Helvetica', fillColor=C_YELLOW, textAnchor='middle'))
story.append(cover)
story.append(sp(10))
# ──────────────────────────────────────────
# SECTION 1: WHAT IS SHOCK?
# ──────────────────────────────────────────
story.append(section_heading("SECTION 1: WHAT IS SHOCK?", C_DARK_RED))
story.append(sp(6))
story.append(key_point("SHOCK = A state of low tissue perfusion — cells don't get enough oxygen and die if untreated."))
story.append(sp(6))
story.append(Paragraph(
"Think of it like this: Your body is a city. Blood is the water supply. "
"SHOCK is when the water supply drops so low that the city (your organs) starts shutting down.",
body))
story.append(sp(4))
story.append(info_box([
"• Normal metabolism = Aerobic (uses oxygen) → produces CO₂ + water (safe)",
"• In shock → Anaerobic metabolism (no oxygen) → produces LACTIC ACID",
"• Lactic acid builds up → Metabolic acidosis → Organs start failing",
], C_BOX_INFO, C_BLUE))
story.append(sp(8))
# Types of Shock flowchart
story.append(sub_heading("DIAGRAM 1: Types of Shock", C_RED))
story.append(sp(4))
story.append(ShockTypesFlowchart(490))
story.append(sp(8))
# Pathophysiology cascade
story.append(sub_heading("FLOWCHART 1: Pathophysiology of Shock (Step-by-step)", C_DARK_RED))
story.append(sp(4))
story.append(PathophysiologyCascade(490))
story.append(sp(8))
# ──────────────────────────────────────────
# SECTION 2: TYPES OF SHOCK - DETAILED
# ──────────────────────────────────────────
story.append(PageBreak())
story.append(section_heading("SECTION 2: TYPES OF SHOCK - EXPLAINED SIMPLY", C_BLUE))
story.append(sp(6))
types_data = [
["Type", "Simple Analogy", "Main Cause", "Key Features", "Treatment"],
["Hypovolaemic\n(most common)", "Water leak in pipe",
"Blood loss / dehydration\n(haemorrhage, burns, diarrhoea)",
"Low CO, High SVR\nLow CVP, Low BP",
"Stop bleeding\nIV fluids / blood"],
["Cardiogenic", "Broken pump",
"Heart attack, arrhythmia\nvalve disease, cardiomyopathy",
"Low CO, High SVR\nHigh CVP",
"Inotropes\n(dobutamine)"],
["Obstructive", "Kinked hose",
"Tension pneumothorax\ncardiac tamponade, PE",
"Low CO, High SVR\nHigh CVP",
"Remove obstruction\n(needle decompression, pericardiocentesis)"],
["Distributive\n(Septic/Anaphylactic)", "Hose made wider",
"Sepsis, anaphylaxis\nspinal cord injury",
"High CO (early sepsis)\nLow SVR, Low BP",
"Fluids + vasopressors\n(noradrenaline)"],
["Endocrine", "Wrong fuel mixture",
"Adrenal insufficiency\nhypo/hyperthyroidism",
"Mixed features",
"Treat hormone deficit\n(steroids)"],
]
story.append(comparison_table(
types_data[0], types_data[1:],
col_widths=[80, 90, 110, 90, 90]
))
story.append(sp(8))
story.append(sub_heading("Cardiovascular Profile of Each Shock Type", C_TEAL))
story.append(sp(4))
cv_data = [
["Parameter", "Hypovolaemic", "Cardiogenic", "Obstructive", "Distributive"],
["Cardiac Output (CO)", "⬇ LOW", "⬇ LOW", "⬇ LOW", "⬆ HIGH (early)"],
["Systemic Vascular Resistance", "⬆ HIGH", "⬆ HIGH", "⬆ HIGH", "⬇ LOW"],
["Venous Pressure (CVP)", "⬇ LOW", "⬆ HIGH", "⬆ HIGH", "⬇ LOW"],
["Mixed Venous O₂ Sat", "⬇ LOW", "⬇ LOW", "⬇ LOW", "⬆ HIGH"],
["Base Deficit", "HIGH", "HIGH", "HIGH", "HIGH"],
]
story.append(comparison_table(cv_data[0], cv_data[1:], col_widths=[130, 82, 82, 82, 84]))
story.append(sp(4))
story.append(key_point(
"Memory trick: ALL types have LOW cardiac output EXCEPT Distributive shock (e.g. early sepsis) "
"which has HIGH cardiac output because the heart is pumping fast but blood pressure is low because vessels are too dilated."
))
story.append(sp(8))
# ──────────────────────────────────────────
# SECTION 3: CLINICAL FEATURES
# ──────────────────────────────────────────
story.append(section_heading("SECTION 3: CLINICAL FEATURES OF SHOCK", C_TEAL))
story.append(sp(6))
clin_data = [
["Feature", "Compensated (MILD)", "Uncompensated MODERATE", "Uncompensated SEVERE"],
["Lactic Acidosis", "+", "++", "+++"],
["Urine Output", "Normal", "Reduced", "Anuric (none)"],
["Conscious Level", "Mild anxiety", "Drowsy", "Comatose"],
["Respiratory Rate", "Increased", "Increased", "Laboured"],
["Pulse Rate", "Increased", "Increased", "Increased"],
["Blood Pressure", "NORMAL", "Mild hypotension", "Severe hypotension"],
]
story.append(comparison_table(clin_data[0], clin_data[1:], col_widths=[120, 112, 115, 113]))
story.append(sp(6))
story.append(info_box([
"IMPORTANT: Blood pressure is the LAST thing to fall in shock!",
"→ A patient can be in severe shock with a NORMAL blood pressure (especially young, fit patients).",
"→ Always check urine output, lactate, and mental status — these are more sensitive early indicators.",
"→ Tachycardia may be absent if patient is on beta-blockers or has a pacemaker.",
], C_BOX_WARN, C_ORANGE))
story.append(sp(6))
story.append(sub_heading("Phases of Shock", C_DARK_RED))
story.append(sp(4))
phases = [
["Phase", "What Happens", "Signs"],
["COMPENSATED\n(Mild)", "Body compensates: ↑ HR, ↑ SVR, ↑ ADH\nOrgans still perfused",
"Tachycardia, cool peripheries\nNormal BP, mildly anxious"],
["DECOMPENSATED\n(Moderate–Severe)", "Compensation fails\nOrgan perfusion ↓↓",
"BP starts to fall, ↑↑ HR\nDrowsy, ↓ urine output"],
["IRREVERSIBLE", "Multiple organ failure\nCell death widespread",
"Comatose, anuric, severe acidosis\nDeath inevitable without treatment"],
]
story.append(comparison_table(phases[0], phases[1:], col_widths=[110, 195, 155]))
story.append(sp(8))
# ──────────────────────────────────────────
# SECTION 4: HAEMORRHAGE
# ──────────────────────────────────────────
story.append(PageBreak())
story.append(section_heading("SECTION 4: HAEMORRHAGE (BLEEDING)", C_RED))
story.append(sp(6))
story.append(key_point(
"Haemorrhage = Bleeding. It is the MOST COMMON cause of shock in trauma. "
"The priority is to STOP the bleeding — not just replace blood with fluids!"
))
story.append(sp(6))
# Types of Haemorrhage
story.append(sub_heading("Types of Haemorrhage", C_DARK_RED))
story.append(sp(4))
haem_types = [
["Type", "Timing", "Cause", "Example"],
["PRIMARY", "Immediately at injury/surgery", "Direct vessel damage", "Arterial bleeding from wound"],
["REACTIONARY", "Within 24 hours", "Clot dislodges with ↑ BP", "Post-op drain becomes bloody"],
["SECONDARY", "7-14 days later", "Infection erodes vessel wall", "Slippage of ligature"],
["REVEALED", "Visible outside body", "External haemorrhage", "Bleeding wound"],
["CONCEALED", "Hidden inside body cavities", "Internal bleeding", "Retroperitoneal haematoma, ruptured aortic aneurysm"],
]
story.append(comparison_table(haem_types[0], haem_types[1:], col_widths=[90, 110, 130, 130]))
story.append(sp(8))
# Haemorrhage classes
story.append(sub_heading("DIAGRAM 2: 4 Classes of Haemorrhagic Shock", C_RED))
story.append(sp(4))
story.append(HaemorrhageClasses(490))
story.append(sp(8))
# Fluid response flowchart
story.append(sub_heading("FLOWCHART 2: Response to IV Fluid Bolus", C_BLUE))
story.append(sp(4))
story.append(FluidResponseFlowchart(490))
story.append(sp(8))
# ──────────────────────────────────────────
# SECTION 5: DAMAGE CONTROL RESUSCITATION
# ──────────────────────────────────────────
story.append(PageBreak())
story.append(section_heading("SECTION 5: DAMAGE CONTROL RESUSCITATION (DCR)", C_DARK_RED))
story.append(sp(6))
story.append(info_box([
"DCR = A strategy used when patients are ACTIVELY BLEEDING.",
"The goal: Prioritise STOPPING BLEEDING and RESTORING COAGULATION over normalising blood pressure.",
"Key concept: Do NOT give too much clear fluid — it dilutes clotting factors and worsens bleeding!",
"Instead: Give blood + plasma + platelets in a balanced ratio (1:1:1).",
], C_BOX_WARN, C_ORANGE))
story.append(sp(6))
story.append(DCRFlowchart(490))
story.append(sp(6))
story.append(sub_heading("Trauma-Induced Coagulopathy (TIC)", C_PURPLE))
story.append(sp(4))
story.append(Paragraph(
"In major trauma, a vicious cycle develops (the 'Lethal Triad'):",
bold_normal))
story.append(sp(3))
lethal_data = [
["HYPOTHERMIA\n(Low body temp)", "ACIDOSIS\n(Lactic acid buildup)", "COAGULOPATHY\n(Can't form clots)"],
["Impairs enzyme function\nInhibits coagulation",
"Inhibits coagulation\nReduces cardiac function",
"Leads to more bleeding\nMore acidosis and hypothermia"],
]
t = Table(lethal_data, colWidths=[155, 155, 150])
t.setStyle(TableStyle([
('BACKGROUND', (0, 0), (-1, 0), C_PURPLE),
('TEXTCOLOR', (0, 0), (-1, 0), C_WHITE),
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
('FONTSIZE', (0, 0), (-1, 0), 9),
('ALIGN', (0, 0), (-1, -1), 'CENTER'),
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
('FONTNAME', (0, 1), (-1, -1), 'Helvetica'),
('FONTSIZE', (0, 1), (-1, -1), 8),
('GRID', (0, 0), (-1, -1), 0.5, colors.HexColor("#AAAAAA")),
('ROWBACKGROUNDS', (0, 1), (-1, -1), [C_LIGHT_PURPLE]),
('TOPPADDING', (0, 0), (-1, -1), 7),
('BOTTOMPADDING', (0, 0), (-1, -1), 7),
]))
story.append(t)
story.append(sp(4))
story.append(key_point(
"Treatment of Lethal Triad: Warm the patient (heating blankets), "
"correct acidosis (resuscitate), treat coagulopathy (FFP + cryoprecipitate + platelets + tranexamic acid)."
))
story.append(sp(8))
# ──────────────────────────────────────────
# SECTION 6: SHOCK RESUSCITATION
# ──────────────────────────────────────────
story.append(PageBreak())
story.append(section_heading("SECTION 6: SHOCK RESUSCITATION - STEP BY STEP", C_BLUE))
story.append(sp(6))
story.append(ResuscitationSteps(490))
story.append(sp(8))
story.append(sub_heading("Fluid Therapy Guide", C_TEAL))
story.append(sp(4))
fluid_data = [
["Fluid Type", "When to Use", "Why"],
["Whole Blood / pRBC", "Active blood loss\nHb <7-8 g/dL", "Replaces RBCs + oxygen carrying capacity"],
["Normal Saline (0.9% NaCl)", "Volume depletion\nNo active bleeding", "Expands intravascular volume"],
["Hartmann's Solution\n(Ringer's Lactate)", "Similar to saline\nbetter electrolyte balance", "More physiological, less hyperchloraemia"],
["Colloids (albumin)", "Rarely used now", "No proven benefit over crystalloids"],
["Dextrose 5%", "NOT for shock resuscitation", "Free water - does NOT expand blood volume"],
]
story.append(comparison_table(fluid_data[0], fluid_data[1:], col_widths=[130, 130, 200]))
story.append(sp(4))
story.append(key_point(
"In active haemorrhage: Crystalloids are NOT the best choice. "
"Use blood products (pRBC + FFP + platelets). "
"Avoid large volumes of clear fluids — they cause dilutional coagulopathy and hypothermia."
))
story.append(sp(8))
story.append(sub_heading("Vasopressors and Inotropes", C_DARK_RED))
story.append(sp(4))
vasopress_data = [
["Drug", "Type", "Use", "Shock Type"],
["Noradrenaline\n(Norepinephrine)", "Vasopressor\n(α1 >> β1)", "First-line for septic/distributive shock",
"Distributive / Septic"],
["Dobutamine", "Inotrope (β1)", "Low cardiac output states\nCardiogenic shock",
"Cardiogenic"],
["Vasopressin", "Vasopressor (V1)", "Catecholamine-resistant septic shock\nalternative to noradrenaline",
"Septic shock (adjunct)"],
["Phenylephrine", "Vasopressor (α1)", "Neurogenic shock\nrelative steroid deficiency",
"Distributive"],
]
story.append(comparison_table(vasopress_data[0], vasopress_data[1:], col_widths=[110, 95, 150, 105]))
story.append(sp(4))
story.append(key_point(
"Remember: Vasopressors should NEVER replace adequate fluid resuscitation. "
"Always fill the tank first, THEN use vasopressors if needed."
))
story.append(sp(8))
# ──────────────────────────────────────────
# SECTION 7: MONITORING
# ──────────────────────────────────────────
story.append(sub_heading("SECTION 7: MONITORING IN SHOCK", C_PURPLE))
story.append(sp(4))
monitoring_data = [
["Parameter", "Normal", "Shock", "Significance"],
["Heart Rate", "60-100 /min", ">100 /min (tachycardia)", "First sign of shock"],
["Blood Pressure", "MAP >65 mmHg", "MAP <65 mmHg", "Late sign — don't wait for this!"],
["Urine Output", ">0.5 mL/kg/hr", "<0.5 mL/kg/hr", "Best bedside organ perfusion marker"],
["GCS / Consciousness", "15 (normal)", "Drowsy → Comatose", "Reflects brain perfusion"],
["Lactate", "<2 mmol/L", ">2 mmol/L (↑ in shock)", "Indicates anaerobic metabolism"],
["Base Deficit", "0 to -2 mEq/L", "< -6 (severe shock)", "Severity of metabolic acidosis"],
["Mixed Venous O₂ Sat", "65-75%", "<50% (low delivery)", ">70% = target for resuscitation"],
["Central Venous Pressure", "5-10 cmH₂O", "Low in hypovolaemia", "Rough guide to preload (not perfect)"],
]
story.append(comparison_table(monitoring_data[0], monitoring_data[1:], col_widths=[115, 85, 125, 135]))
story.append(sp(8))
# ──────────────────────────────────────────
# SECTION 8: TRANSFUSION
# ──────────────────────────────────────────
story.append(PageBreak())
story.append(section_heading("SECTION 8: BLOOD TRANSFUSION", C_TEAL))
story.append(sp(6))
story.append(TransfusionDecision(490))
story.append(sp(8))
# ABO system
story.append(sub_heading("ABO Blood Group System", C_BLUE))
story.append(sp(4))
abo_data = [
["Blood Group", "Genotype", "Antigens on RBC", "Antibodies in Serum", "Can Give To", "Can Receive From"],
["O (Universal donor)", "OO", "None", "Anti-A + Anti-B", "ALL groups", "O only"],
["A", "AA or AO", "A antigen", "Anti-B", "A and AB", "A and O"],
["B", "BB or BO", "B antigen", "Anti-A", "B and AB", "B and O"],
["AB (Universal recipient)", "AB", "A and B antigens", "None", "AB only", "ALL groups"],
]
story.append(comparison_table(abo_data[0], abo_data[1:], col_widths=[90, 55, 65, 75, 75, 100]))
story.append(sp(4))
story.append(key_point(
"Group O negative = Universal DONOR (no antigens, safe for everyone in emergency). "
"Group AB = Universal RECIPIENT (no antibodies in serum, accepts all). "
"In emergencies, give O negative blood while cross-matching is pending."
))
story.append(sp(6))
# Transfusion reactions
story.append(sub_heading("Transfusion Reactions - What Can Go Wrong", C_RED))
story.append(sp(4))
reaction_data = [
["Reaction Type", "Cause", "Signs", "Action"],
["Acute Haemolytic\n(most dangerous)", "ABO incompatibility\n(wrong blood given)", "Fever, rigors, loin pain\nHaemoglobinuria, shock",
"STOP transfusion immediately\nHydrate, monitor kidneys"],
["Febrile Non-Haemolytic", "White cell antibodies\n(graft-vs-host)", "Fever, chills, rigors\n(no haemolysis)", "Slow/stop transfusion\nAntipyretic"],
["Allergic / Anaphylaxis", "IgE reaction to plasma proteins", "Urticaria, wheeze\nbronchospasm, hypotension",
"Stop transfusion\nEpinephrine, antihistamine"],
["TRALI (Transfusion-Related\nAcute Lung Injury)", "Antibodies in donor plasma\ndamage recipient's lungs",
"Acute respiratory distress\nwithin 6 hours", "Stop transfusion\nICU, ventilatory support"],
["Infection\n(bacterial/viral)", "Faulty storage / HIV / Hep B/C", "Fever, sepsis picture",
"Stop transfusion\nCultures + antibiotics"],
]
story.append(comparison_table(reaction_data[0], reaction_data[1:], col_widths=[100, 105, 120, 135]))
story.append(sp(6))
react_extra = [
["Massive Transfusion Complication", "Why it Happens", "Treatment"],
["Coagulopathy (dilution of clotting factors)", "Large volumes → clotting factor dilution", "FFP + cryoprecipitate + platelets"],
["Hypocalcaemia", "Citrate in stored blood chelates Ca²⁺", "IV calcium gluconate"],
["Hyperkalaemia", "Old stored blood leaks K⁺", "Monitor K⁺, treat if needed"],
["Hypothermia", "Cold stored blood given rapidly", "Blood warmer before transfusion"],
["Iron overload", "Repeated transfusions (e.g. thalassaemia)", "Chelation therapy"],
]
story.append(comparison_table(react_extra[0], react_extra[1:], col_widths=[175, 160, 125]))
story.append(sp(8))
# ──────────────────────────────────────────
# SECTION 9: MULTIPLE ORGAN FAILURE
# ──────────────────────────────────────────
story.append(sub_heading("SECTION 9: COMPLICATIONS OF PROLONGED SHOCK", C_DARK_RED))
story.append(sp(4))
mof_data = [
["Organ", "Effect of Prolonged Shock", "Clinical Sign"],
["Heart", "Myocardial depression, ischaemia", "Arrhythmia, low CO"],
["Lungs", "ARDS (Acute Respiratory Distress Syndrome)", "Low O₂ despite high FiO₂, stiff lungs"],
["Kidneys", "Acute Tubular Necrosis", "No urine output (oliguria → anuria)"],
["Liver", "Hepatic failure, coagulopathy", "Jaundice, raised LFTs, coagulopathy"],
["Brain", "Cerebral oedema, encephalopathy", "Confusion, coma"],
["Gut", "Bacterial translocation, ileus", "Abdominal distension, sepsis"],
]
story.append(comparison_table(mof_data[0], mof_data[1:], col_widths=[80, 200, 180]))
story.append(sp(4))
story.append(key_point(
"SIRS (Systemic Inflammatory Response Syndrome) → MODS (Multi-Organ Dysfunction Syndrome). "
"Mortality of established MOF is 60%+. Prevention is KEY: early resuscitation and early control of the shock source."
))
story.append(sp(8))
# ──────────────────────────────────────────
# SUMMARY TABLE
# ──────────────────────────────────────────
story.append(PageBreak())
story.append(section_heading("QUICK SUMMARY: SHOCK AT A GLANCE", C_DARK_RED))
story.append(sp(6))
# Mini summary boxes
summary_items = [
("DEFINITION", "Low tissue perfusion → Anaerobic metabolism → Lactic acidosis → Cell death"),
("TYPES", "Hypovolaemic | Cardiogenic | Obstructive | Distributive | Endocrine"),
("RECOGNITION", "Tachycardia (FIRST sign) → ↓ Urine output → ↓ BP (LATE) → ↓ GCS"),
("TREATMENT", "Stop bleeding → Fluids → Blood products → Vasopressors → Monitor → Definitive Rx"),
("DCR 4 PILLARS", "1. Rapid haemorrhage control 2. Permissive hypotension 3. Avoid dilutional coagulopathy 4. Treat coagulation deficits"),
("TRANSFUSION", "pRBC (<8 g/dL) + FFP (coagulopathy) + Platelets (<50×10⁹) + TXA (trauma) + Cryoprecipitate (low fibrinogen)"),
("MONITORING", "Urine output + Lactate + Base deficit + Mixed venous O₂ sat + Temperature"),
("COMPLICATIONS", "Lethal triad (Hypothermia + Acidosis + Coagulopathy) → MOF → Death if untreated"),
]
for title, content in summary_items:
row_data = [[
Paragraph(f"<b>{title}</b>", ParagraphStyle('th', fontName='Helvetica-Bold', fontSize=9,
textColor=C_WHITE)),
Paragraph(content, ParagraphStyle('td', fontName='Helvetica', fontSize=8.5,
leading=13, textColor=C_DARK_GREY)),
]]
t = Table(row_data, colWidths=[115, 345])
t.setStyle(TableStyle([
('BACKGROUND', (0, 0), (0, -1), C_DARK_RED),
('BACKGROUND', (1, 0), (1, -1), colors.HexColor("#FDEDEC")),
('BOX', (0, 0), (-1, -1), 0.5, C_RED),
('TOPPADDING', (0, 0), (-1, -1), 7),
('BOTTOMPADDING', (0, 0), (-1, -1), 7),
('LEFTPADDING', (0, 0), (-1, -1), 8),
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
]))
story.append(t)
story.append(sp(3))
story.append(sp(10))
# Footer note
footer_style = ParagraphStyle('footer', fontName='Helvetica-Oblique', fontSize=8,
textColor=colors.HexColor("#999999"), alignment=TA_CENTER)
story.append(Paragraph(
"Study notes based on Bailey & Love's Short Practice of Surgery, Chapter 2: Shock, Haemorrhage and Transfusion. "
"For educational purposes only.",
footer_style))
# Build
doc.build(story)
print(f"PDF created: {output_path}")
return output_path
if __name__ == "__main__":
path = build_pdf()
print(f"Done: {path}")
cd /home/daytona/workspace/shock-notes && python3 generate_pdf.py 2>&1
~/shock-notes/generate_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/shock-notes/generate_pdf.py'
cd /home/daytona/workspace/shock-notes && python3 generate_pdf.py 2>&1
drawPath not polygon. Let me fix all the canvas drawing calls throughout the file:cd /home/daytona/workspace/shock-notes && python3 -c " import re with open('generate_pdf.py', 'r') as f: content = f.read() # Replace c.polygon([...], fill=1, stroke=0) with proper path drawing # We need a helper function instead print('polygon count:', content.count('c.polygon(')) print('c.beginPath count (in draw method):', content.count('c.beginPath()')) "