Detail about complications of laparoscopic cholecystectomy Flowcharts Illustrative diagrams Give inPDF
mkdir -p /tmp/workspace/lap-chole-pdf && ls /tmp/workspace/lap-chole-pdf/
~/lap-chole-pdf/generate_pdf.py
import urllib.request
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm, mm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak, KeepTogether, Image
)
from reportlab.graphics.shapes import (
Drawing, Rect, String, Line, Polygon, Arrow, Circle,
RoundedRect, Path, Group
)
from reportlab.graphics import renderPDF
from reportlab.graphics.charts.flowchart import FlowChart
from reportlab.platypus.flowables import Flowable
import io
import os
# ── Download the Strasberg image ──────────────────────────────────────────────
strasberg_url = "https://cdn.orris.care/cdss_images/03bf417319fcd7615ecc2e50fc17fca8410c7432180cd80e3c027def2f1bfcb7.png"
strasberg_path = "/tmp/workspace/lap-chole-pdf/strasberg.png"
if not os.path.exists(strasberg_path):
urllib.request.urlretrieve(strasberg_url, strasberg_path)
# ── Colour palette ─────────────────────────────────────────────────────────────
C_DARK_BLUE = colors.HexColor("#1a3a5c")
C_MED_BLUE = colors.HexColor("#2e6da4")
C_LIGHT_BLUE = colors.HexColor("#d6eaf8")
C_SKY = colors.HexColor("#e8f4fc")
C_RED = colors.HexColor("#c0392b")
C_ORANGE = colors.HexColor("#e67e22")
C_GREEN = colors.HexColor("#27ae60")
C_YELLOW = colors.HexColor("#f39c12")
C_PURPLE = colors.HexColor("#8e44ad")
C_TEAL = colors.HexColor("#16a085")
C_LIGHT_GREEN = colors.HexColor("#d5f5e3")
C_LIGHT_RED = colors.HexColor("#fadbd8")
C_LIGHT_ORANGE= colors.HexColor("#fdebd0")
C_LIGHT_PURPLE= colors.HexColor("#e8daef")
C_GREY = colors.HexColor("#95a5a6")
C_LIGHT_GREY = colors.HexColor("#f2f3f4")
C_WHITE = colors.white
C_BLACK = colors.black
# ── Document setup ─────────────────────────────────────────────────────────────
OUTPUT = "/tmp/workspace/lap-chole-pdf/Laparoscopic_Cholecystectomy_Complications.pdf"
doc = SimpleDocTemplate(
OUTPUT, pagesize=A4,
leftMargin=1.5*cm, rightMargin=1.5*cm,
topMargin=2*cm, bottomMargin=2*cm,
title="Complications of Laparoscopic Cholecystectomy",
author="Medical Reference"
)
styles = getSampleStyleSheet()
# Custom styles
H1 = ParagraphStyle("H1", fontName="Helvetica-Bold", fontSize=22, textColor=C_WHITE,
alignment=TA_CENTER, spaceAfter=4)
H2 = ParagraphStyle("H2", fontName="Helvetica-Bold", fontSize=15, textColor=C_WHITE,
alignment=TA_CENTER, spaceAfter=4)
H3 = ParagraphStyle("H3", fontName="Helvetica-Bold", fontSize=12, textColor=C_DARK_BLUE,
spaceBefore=8, spaceAfter=4)
BODY = ParagraphStyle("BODY", fontName="Helvetica", fontSize=9.5, textColor=C_BLACK,
leading=14, spaceAfter=4, alignment=TA_JUSTIFY)
BULLET = ParagraphStyle("BULLET", fontName="Helvetica", fontSize=9, textColor=C_BLACK,
leading=13, leftIndent=12, spaceAfter=2,
bulletIndent=0, bulletFontName="Helvetica")
CAPTION = ParagraphStyle("CAPTION", fontName="Helvetica-Oblique", fontSize=8,
textColor=C_GREY, alignment=TA_CENTER, spaceAfter=6)
SMALL_BOLD = ParagraphStyle("SMALL_BOLD", fontName="Helvetica-Bold", fontSize=8.5,
textColor=C_DARK_BLUE, spaceAfter=2)
SOURCE = ParagraphStyle("SOURCE", fontName="Helvetica-Oblique", fontSize=7.5,
textColor=C_GREY, spaceAfter=2)
# ── Helper: coloured banner ────────────────────────────────────────────────────
def banner(text, style=H2, bg=C_MED_BLUE, pad=8):
d = Drawing(doc.width, 32)
d.add(RoundedRect(0, 0, doc.width, 32, 6, 6, fillColor=bg, strokeColor=bg))
return [d, Paragraph(text, style)]
def section_header(text, bg=C_MED_BLUE):
tbl = Table([[Paragraph(text, H3)]], colWidths=[doc.width])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TEXTCOLOR", (0,0), (-1,-1), C_WHITE),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
("ROUNDEDCORNERS", [6,6,6,6]),
]))
return tbl
# ── Flowable: Flowchart node helper ───────────────────────────────────────────
class FlowBox(Flowable):
"""A coloured rounded-rect box with centred text for flowcharts."""
def __init__(self, text, width=200, height=30, fill=C_LIGHT_BLUE,
stroke=C_MED_BLUE, font_size=9, text_color=C_DARK_BLUE):
Flowable.__init__(self)
self.text = text
self.width = width
self.height = height
self.fill = fill
self.stroke = stroke
self.font_size = font_size
self.text_color = text_color
def draw(self):
self.canv.setFillColor(self.fill)
self.canv.setStrokeColor(self.stroke)
self.canv.setLineWidth(1.2)
self.canv.roundRect(0, 0, self.width, self.height, 6, fill=1, stroke=1)
self.canv.setFillColor(self.text_color)
self.canv.setFont("Helvetica-Bold", self.font_size)
self.canv.drawCentredString(self.width/2, self.height/2 - self.font_size/3, self.text)
# ══════════════════════════════════════════════════════════════════════════════
# BUILD CONTENT
# ══════════════════════════════════════════════════════════════════════════════
story = []
# ── PAGE 1 : TITLE ─────────────────────────────────────────────────────────────
# Title banner
title_tbl = Table([[Paragraph("COMPLICATIONS OF", H1),
Paragraph("LAPAROSCOPIC CHOLECYSTECTOMY", H1)]],
colWidths=[doc.width])
title_bg = Table([[""]], colWidths=[doc.width], rowHeights=[110])
title_bg.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_DARK_BLUE),
("ROUNDEDCORNERS", [10,10,10,10]),
]))
title_content = Table([
[Paragraph("COMPLICATIONS OF", ParagraphStyle("TC", fontName="Helvetica-Bold", fontSize=20, textColor=C_WHITE, alignment=TA_CENTER))],
[Paragraph("LAPAROSCOPIC CHOLECYSTECTOMY", ParagraphStyle("TC2", fontName="Helvetica-Bold", fontSize=24, textColor=colors.HexColor("#f9ca24"), alignment=TA_CENTER))],
[Paragraph("A Comprehensive Clinical Reference", ParagraphStyle("TC3", fontName="Helvetica-Oblique", fontSize=13, textColor=C_LIGHT_BLUE, alignment=TA_CENTER))],
[Paragraph("Sources: Maingot's Abdominal Operations · Bailey & Love's Surgery · Greenfield's Surgery · Tintinalli's Emergency Medicine",
ParagraphStyle("TC4", fontName="Helvetica", fontSize=8, textColor=C_GREY, alignment=TA_CENTER))],
], colWidths=[doc.width])
title_content.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_DARK_BLUE),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
("ROUNDEDCORNERS", [10,10,10,10]),
]))
story.append(title_content)
story.append(Spacer(1, 12))
# ── OVERVIEW BOX ──────────────────────────────────────────────────────────────
overview_data = [
[Paragraph("<b>OVERVIEW</b>", SMALL_BOLD)],
[Paragraph(
"Laparoscopic cholecystectomy (LC) is the gold-standard treatment for symptomatic cholelithiasis. "
"Complications occur in <b>10-15% of cases</b>. Serious complications fall into two major areas: "
"<b>access complications</b> and <b>bile duct injuries</b>. "
"Overall mortality is <b><0.3%</b>. The incidence of major bile duct injury is "
"<b>0.4-0.6%</b> (vs 0.1-0.2% for open surgery). "
"Most serious complications are more common early in the surgeon's learning curve.",
BODY)],
]
overview_tbl = Table(overview_data, colWidths=[doc.width])
overview_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_DARK_BLUE),
("BACKGROUND", (0,1), (-1,-1), C_SKY),
("TEXTCOLOR", (0,0), (-1,0), C_WHITE),
("BOX", (0,0), (-1,-1), 1, C_MED_BLUE),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
("ROUNDEDCORNERS", [6,6,6,6]),
]))
story.append(overview_tbl)
story.append(Spacer(1, 14))
# ── MASTER CLASSIFICATION TABLE ───────────────────────────────────────────────
story.append(section_header("CLASSIFICATION OF COMPLICATIONS"))
story.append(Spacer(1, 6))
class_data = [
[Paragraph("<b>Category</b>", SMALL_BOLD), Paragraph("<b>Specific Complications</b>", SMALL_BOLD), Paragraph("<b>Incidence</b>", SMALL_BOLD)],
[Paragraph("Biliary", BODY),
Paragraph("Bile duct injury, bile leak, biliary stricture, retained stones, biliary fistula", BODY),
Paragraph("BDI: 0.4-0.6%\nBile leak: 1-2%", BODY)],
[Paragraph("Vascular / Haemorrhagic", BODY),
Paragraph("Cystic artery bleeding, RHA injury, trocar vessel laceration, abdominal wall haematoma", BODY),
Paragraph("1-2%", BODY)],
[Paragraph("Pneumoperitoneum-related", BODY),
Paragraph("CO2 embolism, vagal reflex, cardiac arrhythmias, hypercarbic acidosis, subcutaneous emphysema, pneumothorax, pneumomediastinum", BODY),
Paragraph("Rare", BODY)],
[Paragraph("Trocar / Access", BODY),
Paragraph("GI tract injury (bowel perforation), GU tract injury, major vessel injury (aorta, IVC, iliac), trocar-site hernia, wound infection", BODY),
Paragraph("0.1-0.4%", BODY)],
[Paragraph("Visceral / Miscellaneous", BODY),
Paragraph("Pancreatitis, splenic injury, retained intraperitoneal stones, intra-abdominal abscess, incisional hernia, biliary cutaneous fistula", BODY),
Paragraph("Varied", BODY)],
[Paragraph("Post-operative General", BODY),
Paragraph("Wound infection, DVT/PE, pulmonary complications, acute MI, urinary retention", BODY),
Paragraph("Varied", BODY)],
]
class_tbl = Table(class_data, colWidths=[3.5*cm, 10.5*cm, 3*cm])
class_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_DARK_BLUE),
("TEXTCOLOR", (0,0), (-1,0), C_WHITE),
("BACKGROUND", (0,1), (-1,1), C_LIGHT_RED),
("BACKGROUND", (0,2), (-1,2), C_LIGHT_ORANGE),
("BACKGROUND", (0,3), (-1,3), C_LIGHT_BLUE),
("BACKGROUND", (0,4), (-1,4), C_LIGHT_PURPLE),
("BACKGROUND", (0,5), (-1,5), C_LIGHT_GREEN),
("BACKGROUND", (0,6), (-1,6), C_LIGHT_GREY),
("BOX", (0,0), (-1,-1), 1, C_MED_BLUE),
("INNERGRID", (0,0), (-1,-1), 0.5, colors.HexColor("#aab7b8")),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
]))
story.append(class_tbl)
story.append(Spacer(1, 8))
story.append(Paragraph("Sources: Maingot's Abdominal Operations; Bailey & Love's Surgery 28e; Tintinalli's Emergency Medicine", SOURCE))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# PAGE 2 : FLOWCHART — INTRAOPERATIVE DECISION (Bile Duct Injury)
# ══════════════════════════════════════════════════════════════════════════════
def draw_flowchart_page1(story):
story.append(section_header("FLOWCHART 1 — INTRAOPERATIVE RECOGNITION & MANAGEMENT OF BILE DUCT INJURY"))
story.append(Spacer(1, 8))
w = doc.width
def box(text, fill, stroke, width=None, height=34, font_size=9, text_color=C_WHITE, bold=True):
_w = width or w * 0.7
_font = "Helvetica-Bold" if bold else "Helvetica"
tbl = Table([[Paragraph(f"<font name='{_font}' size='{font_size}' color='#{text_color.hexval()[2:]}'>{text}</font>",
ParagraphStyle("fb", alignment=TA_CENTER, leading=12))]],
colWidths=[_w])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), fill),
("BOX", (0,0), (-1,-1), 1.5, stroke),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("ROUNDEDCORNERS", [8,8,8,8]),
]))
# Centre
return Table([[tbl]], colWidths=[w], style=[
("ALIGN", (0,0), (-1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
])
def arrow():
d = Drawing(w, 16)
mid = w/2
d.add(Line(mid, 16, mid, 0, strokeColor=C_MED_BLUE, strokeWidth=2))
d.add(Polygon([mid-5, 4, mid+5, 4, mid, 0], fillColor=C_MED_BLUE, strokeColor=C_MED_BLUE))
return d
def diamond(text, fill=C_YELLOW, stroke=C_ORANGE, width=None):
_w = width or w * 0.65
tbl = Table([[Paragraph(f"<font name='Helvetica-Bold' size='9'>◆ {text} ◆</font>",
ParagraphStyle("dm", alignment=TA_CENTER, leading=12))]],
colWidths=[_w])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), fill),
("BOX", (0,0), (-1,-1), 1.5, stroke),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("ROUNDEDCORNERS", [14,14,14,14]),
]))
return Table([[tbl]], colWidths=[w], style=[
("ALIGN", (0,0), (-1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
])
def two_branch(left_text, right_text, lc=C_GREEN, rc=C_RED):
l = Table([[Paragraph(f"<font name='Helvetica-Bold' size='8.5' color='white'>{left_text}</font>",
ParagraphStyle("lb", alignment=TA_CENTER, leading=11))]],
colWidths=[w*0.44])
l.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),lc),("BOX",(0,0),(-1,-1),1,lc),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("ROUNDEDCORNERS",[6,6,6,6])]))
r = Table([[Paragraph(f"<font name='Helvetica-Bold' size='8.5' color='white'>{right_text}</font>",
ParagraphStyle("rb", alignment=TA_CENTER, leading=11))]],
colWidths=[w*0.44])
r.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),rc),("BOX",(0,0),(-1,-1),1,rc),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("ROUNDEDCORNERS",[6,6,6,6])]))
return Table([[l, "", r]], colWidths=[w*0.44, w*0.12, w*0.44])
story.append(box("INTRAOPERATIVE BILE DUCT INJURY SUSPECTED", C_RED, C_RED))
story.append(arrow())
story.append(diamond("Is injury recognised INTRAOPERATIVELY?"))
story.append(Spacer(1, 4))
story.append(two_branch("YES — Recognised Intraop", "NO — Post-op Presentation"))
story.append(Spacer(1, 4))
# YES branch details
yes_tbl = Table([[
Paragraph("<b>Partial BDI:</b> Immediate primary repair ± T-tube\n"
"<b>Complete transection:</b> End-to-end repair or\n"
"hepaticojejunostomy by hepatobiliary surgeon\n"
"<b>Vascular co-injury:</b> Urgent vascular repair", BULLET)
]], colWidths=[w*0.44])
yes_tbl.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),C_LIGHT_GREEN),
("BOX",(0,0),(-1,-1),1,C_GREEN),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),6),
("ROUNDEDCORNERS",[6,6,6,6])]))
no_tbl = Table([[
Paragraph("<b>Bile leak / peritonitis:</b> Presents days 1-5\n"
"<b>Obstructive jaundice:</b> Days to weeks\n"
"<b>Investigations:</b> USS → CT → MRCP/ERCP\n"
"Drain any collections percutaneously", BULLET)
]], colWidths=[w*0.44])
no_tbl.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),C_LIGHT_RED),
("BOX",(0,0),(-1,-1),1,C_RED),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),6),
("ROUNDEDCORNERS",[6,6,6,6])]))
story.append(Table([[yes_tbl, "", no_tbl]], colWidths=[w*0.44, w*0.12, w*0.44]))
story.append(arrow())
story.append(diamond("Injury Type / Strasberg Grade?", fill=colors.HexColor("#fef9e7"), stroke=C_ORANGE))
story.append(Spacer(1, 4))
grade_data = [
[Paragraph("<b>Strasberg Grade</b>", SMALL_BOLD),
Paragraph("<b>Description</b>", SMALL_BOLD),
Paragraph("<b>Management</b>", SMALL_BOLD)],
[Paragraph("A", BODY), Paragraph("Bile leak from cystic duct stump or minor duct", BODY),
Paragraph("ERCP + stent / sphincterotomy", BODY)],
[Paragraph("B", BODY), Paragraph("Occluded right posterior sectoral duct", BODY),
Paragraph("Observation or surgical repair", BODY)],
[Paragraph("C", BODY), Paragraph("Bile leak from divided right posterior duct", BODY),
Paragraph("ERCP + stent; repair if persistent", BODY)],
[Paragraph("D", BODY), Paragraph("Lateral injury to main bile duct, no tissue loss", BODY),
Paragraph("Primary repair over T-tube", BODY)],
[Paragraph("E1-E5", BODY), Paragraph("Transection/stricture of main bile duct at various levels", BODY),
Paragraph("Hepaticojejunostomy (Roux-en-Y) by expert HBP surgeon", BODY)],
]
grade_tbl = Table(grade_data, colWidths=[2.0*cm, 8.5*cm, 6.5*cm])
grade_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_DARK_BLUE),
("TEXTCOLOR", (0,0), (-1,0), C_WHITE),
("BACKGROUND", (0,1), (-1,1), colors.HexColor("#d5f5e3")),
("BACKGROUND", (0,2), (-1,2), colors.HexColor("#d5f5e3")),
("BACKGROUND", (0,3), (-1,3), colors.HexColor("#fdebd0")),
("BACKGROUND", (0,4), (-1,4), colors.HexColor("#fdebd0")),
("BACKGROUND", (0,5), (-1,5), colors.HexColor("#fadbd8")),
("BOX", (0,0), (-1,-1), 1, C_MED_BLUE),
("INNERGRID", (0,0), (-1,-1), 0.4, C_GREY),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(grade_tbl)
story.append(Spacer(1, 6))
story.append(arrow())
story.append(box("REFER TO SPECIALIST HBP UNIT if complex (E1-E5) or uncertain", C_PURPLE, C_PURPLE))
draw_flowchart_page1(story)
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# PAGE 3 : FLOWCHART 2 — POST-OP MANAGEMENT
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_header("FLOWCHART 2 — POST-OPERATIVE COMPLICATION ASSESSMENT"))
story.append(Spacer(1, 8))
w = doc.width
def centred_box(text, fill, stroke, col_w=None, height=32, fsize=9, bold=True):
cw = col_w or w * 0.70
fn = "Helvetica-Bold" if bold else "Helvetica"
p = Paragraph(f"<font name='{fn}' size='{fsize}'>{text}</font>",
ParagraphStyle("cb", alignment=TA_CENTER, leading=13,
textColor=C_WHITE))
tbl = Table([[p]], colWidths=[cw])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), fill),
("BOX", (0,0), (-1,-1), 1.5, stroke),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("ROUNDEDCORNERS", [8,8,8,8]),
]))
return Table([[tbl]], colWidths=[w], style=[("ALIGN",(0,0),(-1,-1),"CENTER")])
def small_arrow():
d = Drawing(w, 14)
mid = w/2
d.add(Line(mid, 14, mid, 0, strokeColor=C_MED_BLUE, strokeWidth=1.5))
d.add(Polygon([mid-4, 3, mid+4, 3, mid, 0], fillColor=C_MED_BLUE, strokeColor=C_MED_BLUE))
return d
story.append(centred_box("PATIENT POST LAPAROSCOPIC CHOLECYSTECTOMY with NEW SYMPTOMS", C_DARK_BLUE, C_DARK_BLUE))
story.append(small_arrow())
# Symptom assessment
sym_data = [
[Paragraph("<b>Key Symptoms to Assess</b>", ParagraphStyle("ksa", fontName="Helvetica-Bold", fontSize=9, textColor=C_WHITE, alignment=TA_CENTER))],
[Table([
[Paragraph("• Abdominal pain / peritonism", BULLET),
Paragraph("• Fever / rigors / chills", BULLET)],
[Paragraph("• Jaundice / dark urine", BULLET),
Paragraph("• Nausea / vomiting", BULLET)],
[Paragraph("• Shoulder-tip pain (referred)", BULLET),
Paragraph("• Bile from drain / wound", BULLET)],
], colWidths=[w*0.48, w*0.48])],
]
sym_tbl = Table(sym_data, colWidths=[w])
sym_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), C_MED_BLUE),
("BACKGROUND", (0,1), (0,1), C_SKY),
("BOX", (0,0), (-1,-1), 1, C_MED_BLUE),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
]))
story.append(sym_tbl)
story.append(small_arrow())
# Three pathways
p_bile = Table([[
Paragraph("<b>BILIARY COMPLICATION?</b>", ParagraphStyle("bc", fontName="Helvetica-Bold", fontSize=8.5, textColor=C_WHITE, alignment=TA_CENTER)),
]], colWidths=[w*0.31])
p_bile.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),C_RED),("TOPPADDING",(0,0),(-1,-1),6),
("BOTTOMPADDING",(0,0),(-1,-1),6),("BOX",(0,0),(-1,-1),1,C_RED),
("ROUNDEDCORNERS",[6,6,6,6])]))
p_vasc = Table([[
Paragraph("<b>VASCULAR / HAEMORRHAGE?</b>", ParagraphStyle("vc", fontName="Helvetica-Bold", fontSize=8.5, textColor=C_WHITE, alignment=TA_CENTER)),
]], colWidths=[w*0.31])
p_vasc.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),C_ORANGE),("TOPPADDING",(0,0),(-1,-1),6),
("BOTTOMPADDING",(0,0),(-1,-1),6),("BOX",(0,0),(-1,-1),1,C_ORANGE),
("ROUNDEDCORNERS",[6,6,6,6])]))
p_gen = Table([[
Paragraph("<b>GENERAL SURGICAL?</b>", ParagraphStyle("gc", fontName="Helvetica-Bold", fontSize=8.5, textColor=C_WHITE, alignment=TA_CENTER)),
]], colWidths=[w*0.31])
p_gen.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),C_TEAL),("TOPPADDING",(0,0),(-1,-1),6),
("BOTTOMPADDING",(0,0),(-1,-1),6),("BOX",(0,0),(-1,-1),1,C_TEAL),
("ROUNDEDCORNERS",[6,6,6,6])]))
story.append(Table([[p_bile, "", p_vasc, "", p_gen]], colWidths=[w*0.31, w*0.02, w*0.31, w*0.04, w*0.31]))
story.append(Spacer(1, 4))
# Details for each pathway
d_bile = Table([[
Paragraph("• Jaundice → USS → MRCP/ERCP\n"
"• Bile peritonitis → CT → percutaneous drain\n"
"• Small leak → observe or ERCP stent\n"
"• Stricture → stent or surgical repair\n"
"• Retained stone → ERCP extraction", BULLET)
]], colWidths=[w*0.31])
d_bile.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),C_LIGHT_RED),
("BOX",(0,0),(-1,-1),1,C_RED),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),4),
("ROUNDEDCORNERS",[4,4,4,4])]))
d_vasc = Table([[
Paragraph("• Active bleed → resuscitate\n"
"• CT angiogram\n"
"• Embolisation or re-operation\n"
"• Trocar wound bleed: pressure /\n"
" tamponade / suture", BULLET)
]], colWidths=[w*0.31])
d_vasc.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),C_LIGHT_ORANGE),
("BOX",(0,0),(-1,-1),1,C_ORANGE),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),4),
("ROUNDEDCORNERS",[4,4,4,4])]))
d_gen = Table([[
Paragraph("• Wound infection → antibiotics, open\n"
"• Incisional hernia → repair\n"
"• Abscess → CT-guided drainage\n"
"• Pancreatitis → supportive care\n"
"• DVT/PE → anticoagulation", BULLET)
]], colWidths=[w*0.31])
d_gen.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),colors.HexColor("#d1f2eb")),
("BOX",(0,0),(-1,-1),1,C_TEAL),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),4),
("ROUNDEDCORNERS",[4,4,4,4])]))
story.append(Table([[d_bile, "", d_vasc, "", d_gen]], colWidths=[w*0.31, w*0.02, w*0.31, w*0.04, w*0.31]))
story.append(Spacer(1, 6))
story.append(small_arrow())
story.append(centred_box("MULTIDISCIPLINARY REVIEW: Surgeon + Radiologist + Endoscopist", C_PURPLE, C_PURPLE, col_w=w*0.80))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# PAGE 4 : DETAILED COMPLICATIONS
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_header("DETAILED COMPLICATIONS — BILIARY SYSTEM", C_RED))
story.append(Spacer(1, 6))
# Bile duct injury
bdi_data = [
[Paragraph("<b>BILE DUCT INJURY (BDI)</b>", SMALL_BOLD),
Paragraph("<b>Details</b>", SMALL_BOLD)],
[Paragraph("Incidence", BODY), Paragraph("0.4-0.6% (LC) vs 0.1-0.2% (open)", BODY)],
[Paragraph("Classic mechanism", BODY),
Paragraph("CBD or RHD mistaken for cystic duct; traction aligns CBD with cystic duct making them appear as one", BODY)],
[Paragraph("Risk factors", BODY),
Paragraph("• Surgeon inexperience (1.7% risk in 1st case → 0.17% by 50th)\n"
"• Aberrant anatomy\n"
"• Dense adhesions / acute inflammation\n"
"• Short cystic duct\n"
"• Large Hartmann's pouch stone\n"
"• Operative bleeding obscuring field", BODY)],
[Paragraph("Recognition", BODY),
Paragraph("Only 15% recognised intraoperatively; remainder present postoperatively as bile leak, biloma, peritonitis, or obstructive jaundice", BODY)],
[Paragraph("Prevention", BODY),
Paragraph("Critical view of safety (CVS): dissect Calot's triangle until only two structures seen entering GB base; consider intraoperative cholangiography", BODY)],
[Paragraph("Management", BODY),
Paragraph("Partial: primary repair ± T-tube\nComplete transection: Roux-en-Y hepaticojejunostomy\nComplex (E1-E5): specialist HBP centre", BODY)],
]
bdi_tbl = Table(bdi_data, colWidths=[4*cm, 13*cm])
bdi_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_RED),
("TEXTCOLOR", (0,0), (-1,0), C_WHITE),
("BACKGROUND", (0,1), (-1,1), C_LIGHT_RED),
("BACKGROUND", (0,2), (-1,2), C_WHITE),
("BACKGROUND", (0,3), (-1,3), C_LIGHT_RED),
("BACKGROUND", (0,4), (-1,4), C_WHITE),
("BACKGROUND", (0,5), (-1,5), C_LIGHT_RED),
("BACKGROUND", (0,6), (-1,6), C_WHITE),
("BOX", (0,0), (-1,-1), 1, C_RED),
("INNERGRID", (0,0), (-1,-1), 0.4, colors.HexColor("#f1948a")),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(bdi_tbl)
story.append(Spacer(1, 8))
# Bile leak
bl_data = [
[Paragraph("<b>BILE LEAK</b>", SMALL_BOLD), Paragraph("<b>Details</b>", SMALL_BOLD)],
[Paragraph("Sources", BODY), Paragraph("Cystic duct stump, gallbladder fossa ducts (Luschka's ducts), main bile duct", BODY)],
[Paragraph("Presentation", BODY), Paragraph("Abdominal pain, fever, peritonitis (bile peritonitis if no drain); bile from drain", BODY)],
[Paragraph("Investigation", BODY), Paragraph("USS → CT → ERCP (diagnostic and therapeutic)", BODY)],
[Paragraph("Management", BODY), Paragraph("Small leaks: observation (often self-limiting if no distal obstruction)\n"
"Symptomatic: ERCP + sphincterotomy ± stent\n"
"Collections: percutaneous/surgical drainage", BODY)],
]
bl_tbl = Table(bl_data, colWidths=[4*cm, 13*cm])
bl_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_ORANGE),
("TEXTCOLOR", (0,0), (-1,0), C_WHITE),
("ROWBACKGROUNDS", (0,1), (-1,-1), [C_LIGHT_ORANGE, C_WHITE]),
("BOX", (0,0), (-1,-1), 1, C_ORANGE),
("INNERGRID", (0,0), (-1,-1), 0.4, colors.HexColor("#f0b27a")),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(bl_tbl)
story.append(Spacer(1, 8))
# Retained stones
rs_data = [
[Paragraph("<b>RETAINED / SPILLED STONES</b>", SMALL_BOLD), Paragraph("<b>Details</b>", SMALL_BOLD)],
[Paragraph("Spilled stones", BODY), Paragraph("Gallbladder perforation occurs in 10-40% of LC cases; spilled stones in 5-40%", BODY)],
[Paragraph("Consequences", BODY), Paragraph("Intra-abdominal abscess, subcutaneous abscess, biliary-cutaneous fistula, trocar-site abscess (months–years later)", BODY)],
[Paragraph("Retained CBD stones", BODY), Paragraph("Presents with pain, pancreatitis, jaundice post-op; ERCP is treatment of choice", BODY)],
[Paragraph("Prevention", BODY), Paragraph("Retrieve all spilled stones; use retrieval bag for GB extraction", BODY)],
]
rs_tbl = Table(rs_data, colWidths=[4*cm, 13*cm])
rs_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_TEAL),
("TEXTCOLOR", (0,0), (-1,0), C_WHITE),
("ROWBACKGROUNDS", (0,1), (-1,-1), [colors.HexColor("#d1f2eb"), C_WHITE]),
("BOX", (0,0), (-1,-1), 1, C_TEAL),
("INNERGRID", (0,0), (-1,-1), 0.4, C_GREY),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(rs_tbl)
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# PAGE 5 : VASCULAR + PNEUMOPERITONEUM + TROCAR
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_header("VASCULAR, PNEUMOPERITONEUM & TROCAR COMPLICATIONS", C_DARK_BLUE))
story.append(Spacer(1, 6))
# Vascular
vasc_data = [
[Paragraph("<b>VASCULAR / HAEMORRHAGIC COMPLICATIONS</b>", SMALL_BOLD), ""],
[Paragraph("Cystic artery bleeding", BODY),
Paragraph("Most common intraop bleed; controlled by haemostatic clips or conversion to open", BODY)],
[Paragraph("Right hepatic artery injury", BODY),
Paragraph("Often co-exists with BDI (close anatomic relationship); may cause hepatic ischaemia; urgent repair needed", BODY)],
[Paragraph("Major vessel injury (aorta, IVC, iliac)", BODY),
Paragraph("During trocar insertion especially with closed technique; do NOT remove trocar — open immediately and isolate vessel", BODY)],
[Paragraph("Abdominal wall vessel (epigastric)", BODY),
Paragraph("Trocar laceration; controlled with Foley catheter tamponade or through-and-through suture", BODY)],
]
vasc_tbl = Table(vasc_data, colWidths=[5*cm, 12*cm])
vasc_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_DARK_BLUE),
("TEXTCOLOR", (0,0), (-1,0), C_WHITE),
("SPAN", (0,0), (1,0)),
("ROWBACKGROUNDS", (0,1), (-1,-1), [C_LIGHT_BLUE, C_WHITE]),
("BOX", (0,0), (-1,-1), 1, C_DARK_BLUE),
("INNERGRID", (0,0), (-1,-1), 0.4, C_GREY),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(vasc_tbl)
story.append(Spacer(1, 8))
# Pneumoperitoneum
pneu_data = [
[Paragraph("<b>PNEUMOPERITONEUM-RELATED COMPLICATIONS</b>", SMALL_BOLD), "", ""],
[Paragraph("<b>Complication</b>", SMALL_BOLD), Paragraph("<b>Mechanism</b>", SMALL_BOLD), Paragraph("<b>Management</b>", SMALL_BOLD)],
[Paragraph("CO2 Gas Embolism", BODY), Paragraph("CO2 enters torn vessel during insufflation", BODY),
Paragraph("Deflate pneumoperitoneum; left lateral decubitus; 100% O2; CPR if arrest", BODY)],
[Paragraph("Vaso-vagal Reflex", BODY), Paragraph("Peritoneal stretch → bradycardia", BODY),
Paragraph("Deflate; atropine", BODY)],
[Paragraph("Cardiac Arrhythmias", BODY), Paragraph("Hypercarbia → sympathetic activation", BODY),
Paragraph("Ventilation adjustment; anti-arrhythmics", BODY)],
[Paragraph("Hypercarbic Acidosis", BODY), Paragraph("CO2 absorption especially in long cases", BODY),
Paragraph("Increase ventilation; reduce insufflation pressure", BODY)],
[Paragraph("Subcutaneous Emphysema", BODY), Paragraph("CO2 tracking into subcutaneous tissue", BODY),
Paragraph("Usually self-limiting; monitor", BODY)],
[Paragraph("Pneumothorax / Pneumomediastinum", BODY), Paragraph("CO2 tracking through diaphragmatic defect", BODY),
Paragraph("Chest drain if tension; otherwise conservative", BODY)],
]
pneu_tbl = Table(pneu_data, colWidths=[5*cm, 5.5*cm, 6.5*cm])
pneu_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_MED_BLUE),
("TEXTCOLOR", (0,0), (-1,0), C_WHITE),
("SPAN", (0,0), (2,0)),
("BACKGROUND", (0,1), (-1,1), C_DARK_BLUE),
("TEXTCOLOR", (0,1), (-1,1), C_WHITE),
("ROWBACKGROUNDS", (0,2), (-1,-1), [C_LIGHT_BLUE, C_WHITE]),
("BOX", (0,0), (-1,-1), 1, C_MED_BLUE),
("INNERGRID", (0,0), (-1,-1), 0.4, C_GREY),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(pneu_tbl)
story.append(Spacer(1, 8))
# Trocar
trocar_data = [
[Paragraph("<b>TROCAR / ACCESS COMPLICATIONS</b>", SMALL_BOLD), ""],
[Paragraph("GI tract perforation (bowel)", BODY),
Paragraph("Most common with blind trocar insertion; Veress needle injury can be managed conservatively; trocar bowel injury requires repair", BODY)],
[Paragraph("GU tract injury (bladder)", BODY),
Paragraph("Seen with prior pelvic surgery; Foley catheter decompression preoperative; intraop repair if recognised", BODY)],
[Paragraph("Trocar-site hernia (port-site hernia)", BODY),
Paragraph("Incidence 1-3%; higher at 10-12mm ports; prevent by closing fascial defects ≥10mm; treat with elective repair", BODY)],
[Paragraph("Wound infection", BODY),
Paragraph("Higher risk with acute cholecystitis, gallbladder perforation, or immunocompromise; treat with antibiotics ± drainage", BODY)],
[Paragraph("Port-site metastasis", BODY),
Paragraph("Rare; reported with unsuspected gallbladder carcinoma; use retrieval bag", BODY)],
]
trocar_tbl = Table(trocar_data, colWidths=[5*cm, 12*cm])
trocar_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_PURPLE),
("TEXTCOLOR", (0,0), (-1,0), C_WHITE),
("SPAN", (0,0), (1,0)),
("ROWBACKGROUNDS", (0,1), (-1,-1), [C_LIGHT_PURPLE, C_WHITE]),
("BOX", (0,0), (-1,-1), 1, C_PURPLE),
("INNERGRID", (0,0), (-1,-1), 0.4, C_GREY),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(trocar_tbl)
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# PAGE 6 : STRASBERG CLASSIFICATION + DIAGRAM
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_header("STRASBERG CLASSIFICATION OF BILE DUCT INJURIES", C_DARK_BLUE))
story.append(Spacer(1, 8))
# Embed Strasberg image
if os.path.exists(strasberg_path):
img = Image(strasberg_path, width=doc.width*0.95, height=8*cm)
img.hAlign = "CENTER"
story.append(img)
story.append(Paragraph("Figure: Strasberg Classification of Bile Duct Injuries — Bailey & Love's Surgery 28th Edition", CAPTION))
story.append(Spacer(1, 8))
stras_data = [
[Paragraph("<b>Grade</b>", SMALL_BOLD), Paragraph("<b>Description</b>", SMALL_BOLD),
Paragraph("<b>Anatomical Injury</b>", SMALL_BOLD), Paragraph("<b>Treatment</b>", SMALL_BOLD)],
[Paragraph("A", BODY), Paragraph("Bile leak — minor", BODY),
Paragraph("Cystic duct stump / Luschka duct", BODY), Paragraph("ERCP + sphincterotomy ± stent", BODY)],
[Paragraph("B", BODY), Paragraph("Occlusion — no leak", BODY),
Paragraph("Right posterior sectoral duct occluded", BODY), Paragraph("Observe or surgical repair", BODY)],
[Paragraph("C", BODY), Paragraph("Bile leak — sectoral", BODY),
Paragraph("Right posterior sectoral duct divided + leaking", BODY), Paragraph("ERCP + stent; repair if persistent", BODY)],
[Paragraph("D", BODY), Paragraph("Lateral injury", BODY),
Paragraph("Lateral laceration of main bile duct; no tissue loss", BODY), Paragraph("Primary repair over T-tube", BODY)],
[Paragraph("E1", BODY), Paragraph("Transection — distal", BODY),
Paragraph("Stricture >2 cm from hepatic hilus", BODY), Paragraph("Hepaticojejunostomy", BODY)],
[Paragraph("E2", BODY), Paragraph("Transection — mid", BODY),
Paragraph("Stricture <2 cm from hepatic hilus", BODY), Paragraph("Hepaticojejunostomy", BODY)],
[Paragraph("E3", BODY), Paragraph("Hilar — R+L in continuity", BODY),
Paragraph("Stricture at hilus; R and L hepatic ducts communicate", BODY), Paragraph("Complex Roux-en-Y (specialist)", BODY)],
[Paragraph("E4", BODY), Paragraph("Hilar — R+L separated", BODY),
Paragraph("Stricture with separation of right and left hepatic ducts", BODY), Paragraph("Complex biliary reconstruction", BODY)],
[Paragraph("E5", BODY), Paragraph("Combined injury", BODY),
Paragraph("Right aberrant sectoral duct + main bile duct stricture", BODY), Paragraph("Specialist HBP reconstruction", BODY)],
]
stras_tbl = Table(stras_data, colWidths=[1.4*cm, 3.5*cm, 6.5*cm, 5.6*cm])
stras_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_DARK_BLUE),
("TEXTCOLOR", (0,0), (-1,0), C_WHITE),
("BACKGROUND", (0,1), (-1,1), colors.HexColor("#d5f5e3")),
("BACKGROUND", (0,2), (-1,2), colors.HexColor("#d5f5e3")),
("BACKGROUND", (0,3), (-1,3), colors.HexColor("#fdebd0")),
("BACKGROUND", (0,4), (-1,4), colors.HexColor("#fdebd0")),
("BACKGROUND", (0,5), (-1,5), colors.HexColor("#fadbd8")),
("BACKGROUND", (0,6), (-1,6), colors.HexColor("#fadbd8")),
("BACKGROUND", (0,7), (-1,7), colors.HexColor("#fadbd8")),
("BACKGROUND", (0,8), (-1,8), colors.HexColor("#fadbd8")),
("BACKGROUND", (0,9), (-1,9), colors.HexColor("#fadbd8")),
("BOX", (0,0), (-1,-1), 1, C_MED_BLUE),
("INNERGRID", (0,0), (-1,-1), 0.4, C_GREY),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(stras_tbl)
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# PAGE 7 : FLOWCHART 3 — CONVERSION TO OPEN
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_header("FLOWCHART 3 — DIFFICULT CHOLECYSTECTOMY: BAIL-OUT STRATEGIES"))
story.append(Spacer(1, 10))
def flow_box_row(text, fill, stroke, col_w=None, fsize=9.5):
cw = col_w or w * 0.72
p = Paragraph(f"<font name='Helvetica-Bold' size='{fsize}' color='white'>{text}</font>",
ParagraphStyle("fbr", alignment=TA_CENTER, leading=13))
t = Table([[p]], colWidths=[cw])
t.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),fill),("BOX",(0,0),(-1,-1),1.5,stroke),
("TOPPADDING",(0,0),(-1,-1),6),("BOTTOMPADDING",(0,0),(-1,-1),6),
("ROUNDEDCORNERS",[8,8,8,8])]))
return Table([[t]], colWidths=[w], style=[("ALIGN",(0,0),(-1,-1),"CENTER")])
def arr():
d = Drawing(w, 15)
m = w/2
d.add(Line(m, 15, m, 0, strokeColor=C_DARK_BLUE, strokeWidth=2))
d.add(Polygon([m-5, 4, m+5, 4, m, 0], fillColor=C_DARK_BLUE, strokeColor=C_DARK_BLUE))
return d
story.append(flow_box_row("DIFFICULT LAPAROSCOPIC CHOLECYSTECTOMY", C_DARK_BLUE, C_DARK_BLUE, fsize=11))
story.append(arr())
# Warning signs
warn_data = [
[Paragraph("<b>Warning Signs / Triggers for Bail-out</b>", ParagraphStyle("ws", fontName="Helvetica-Bold",
fontSize=9.5, textColor=C_WHITE, alignment=TA_CENTER))],
[Table([
[Paragraph("• Anatomy not clearly defined", BULLET),
Paragraph("• No progress with dissection", BULLET),
Paragraph("• Active uncontrolled bleeding", BULLET)],
[Paragraph("• Dense adhesions / frozen pelvis", BULLET),
Paragraph("• Mirizzi syndrome suspected", BULLET),
Paragraph("• BDI risk is high", BULLET)],
], colWidths=[w*0.33]*3)],
]
warn_tbl = Table(warn_data, colWidths=[w])
warn_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(0,0), C_RED),
("BACKGROUND",(0,1),(0,1), C_LIGHT_RED),
("BOX",(0,0),(-1,-1),1,C_RED),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),4),
]))
story.append(warn_tbl)
story.append(arr())
# 5 bail-out options
bail_options = [
("1. CONVERT TO OPEN", C_ORANGE, "Choose early — 'by choice' not forced by complication"),
("2. SUBTOTAL CHOLECYSTECTOMY", C_MED_BLUE, "Remove GB fundus/body; leave Hartmann's pouch; safer than risky dissection"),
("3. TUBE CHOLECYSTOSTOMY", C_TEAL, "14Fr Foley catheter; temporary relief; definitive surgery later"),
("4. FUNDUS-FIRST APPROACH", C_PURPLE, "Dissect from fundus down instead of Calot's triangle"),
("5. INTRAOPERATIVE CHOLANGIOGRAPHY", C_GREEN, "Delineate biliary anatomy when in doubt; reduces BDI risk"),
]
for title, fill, desc in bail_options:
opt_tbl = Table([[
Table([[Paragraph(f"<font name='Helvetica-Bold' size='9' color='white'>{title}</font>",
ParagraphStyle("op", alignment=TA_CENTER, leading=12))]],
colWidths=[5.5*cm],
style=[("BACKGROUND",(0,0),(-1,-1),fill),("TOPPADDING",(0,0),(-1,-1),6),
("BOTTOMPADDING",(0,0),(-1,-1),6),("ROUNDEDCORNERS",[6,6,6,6]),
("BOX",(0,0),(-1,-1),1,fill)]),
Paragraph(desc, BODY)
]], colWidths=[5.5*cm, w - 5.5*cm - 0.5*cm])
opt_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,-1),C_LIGHT_GREY),
("BOX",(0,0),(-1,-1),0.5,C_GREY),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),5),
("VALIGN",(0,0),(-1,-1),"MIDDLE"),
("ROUNDEDCORNERS",[4,4,4,4]),
]))
story.append(opt_tbl)
story.append(Spacer(1, 4))
story.append(arr())
story.append(flow_box_row("DOCUMENT DECISION + INFORM PATIENT POST-OP", C_GREEN, C_GREEN, fsize=10))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# PAGE 8 : PREVENTION & SUMMARY
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_header("PREVENTION OF COMPLICATIONS & CLINICAL PEARLS", C_GREEN))
story.append(Spacer(1, 8))
# Critical view of safety
cvs_data = [
[Paragraph("<b>THE CRITICAL VIEW OF SAFETY (CVS)</b>", SMALL_BOLD), ""],
[Paragraph("Requirement 1", BODY),
Paragraph("Hepatocystic triangle is cleared of fat and fibrous tissue", BODY)],
[Paragraph("Requirement 2", BODY),
Paragraph("Lower third of gallbladder is separated from liver bed", BODY)],
[Paragraph("Requirement 3", BODY),
Paragraph("Only TWO structures seen entering the gallbladder (cystic duct + cystic artery)", BODY)],
[Paragraph("Clinical Pearl", BODY),
Paragraph("⚠️ Do NOT clip any structure until CVS is achieved. When in doubt, do NOT clip.", BODY)],
]
cvs_tbl = Table(cvs_data, colWidths=[4.5*cm, 12.5*cm])
cvs_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0), C_GREEN),("TEXTCOLOR",(0,0),(-1,0),C_WHITE),
("SPAN",(0,0),(1,0)),
("ROWBACKGROUNDS",(0,1),(-1,-1),[C_LIGHT_GREEN,C_WHITE]),
("BOX",(0,0),(-1,-1),1,C_GREEN),
("INNERGRID",(0,0),(-1,-1),0.4,C_GREY),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),6),("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(cvs_tbl)
story.append(Spacer(1, 8))
# Key prevention table
prev_data = [
[Paragraph("<b>Complication</b>", SMALL_BOLD), Paragraph("<b>Key Prevention Strategy</b>", SMALL_BOLD)],
[Paragraph("Bile duct injury", BODY), Paragraph("CVS; intraoperative cholangiography; early conversion if anatomy unclear; go fundus-first", BODY)],
[Paragraph("Major vessel injury", BODY), Paragraph("Never aim trocar at spine; use hand as brake; open technique for high-risk patients", BODY)],
[Paragraph("Gallbladder perforation / spilled stones", BODY), Paragraph("Gentle dissection; use retrieval bag; retrieve all spilled stones meticulously", BODY)],
[Paragraph("Port-site hernia", BODY), Paragraph("Close fascial defects at all ≥10mm ports", BODY)],
[Paragraph("CO2 embolism", BODY), Paragraph("Low insufflation pressure; avoid Trendelenburg until peritoneum established", BODY)],
[Paragraph("Pancreatitis", BODY), Paragraph("Intraoperative cholangiography; ERCP for retained stones if suspected", BODY)],
[Paragraph("Wound infection", BODY), Paragraph("Perioperative antibiotics in acute cholecystitis; retrieval bag prevents GB contamination", BODY)],
]
prev_tbl = Table(prev_data, colWidths=[5*cm, 12*cm])
prev_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0), C_DARK_BLUE),("TEXTCOLOR",(0,0),(-1,0),C_WHITE),
("ROWBACKGROUNDS",(0,1),(-1,-1),[C_LIGHT_BLUE,C_WHITE]),
("BOX",(0,0),(-1,-1),1,C_DARK_BLUE),
("INNERGRID",(0,0),(-1,-1),0.4,C_GREY),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),6),("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(prev_tbl)
story.append(Spacer(1, 10))
# Summary box
summ_tbl = Table([[
Paragraph("<b>KEY TAKEAWAYS</b>", ParagraphStyle("kt", fontName="Helvetica-Bold", fontSize=11, textColor=C_WHITE, alignment=TA_CENTER))
],[
Paragraph(
"• Overall mortality <0.3%; complications 10-15% of cases\n"
"• Bile duct injury is the most feared complication: 0.4-0.6% (LC) vs 0.1-0.2% (open)\n"
"• Only 15% of BDIs are recognised intraoperatively\n"
"• Critical View of Safety (CVS) is the single most important preventive measure\n"
"• When in doubt — stop, call for help, convert, or use intraoperative cholangiography\n"
"• Spilled stones must always be retrieved to prevent late abscesses\n"
"• Complex BDI (E1-E5) mandates referral to specialist HBP centre\n"
"• MDT (surgeon + radiologist + endoscopist) is essential for post-op complication management",
BULLET)
]], colWidths=[w])
summ_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),C_DARK_BLUE),
("BACKGROUND",(0,1),(-1,1),C_SKY),
("BOX",(0,0),(-1,-1),2,C_DARK_BLUE),
("TOPPADDING",(0,0),(-1,-1),8),("BOTTOMPADDING",(0,0),(-1,-1),8),
("LEFTPADDING",(0,0),(-1,-1),10),
("ROUNDEDCORNERS",[8,8,8,8]),
]))
story.append(summ_tbl)
story.append(Spacer(1, 6))
story.append(Paragraph(
"References: Maingot's Abdominal Operations 12e | Bailey & Love's Short Practice of Surgery 28e | "
"Mulholland & Greenfield's Surgery 7e | Tintinalli's Emergency Medicine",
SOURCE))
# ── BUILD ──────────────────────────────────────────────────────────────────────
def on_first_page(canvas, doc):
pass
def on_later_pages(canvas, doc):
canvas.saveState()
canvas.setFont("Helvetica", 7.5)
canvas.setFillColor(C_GREY)
canvas.drawCentredString(A4[0]/2, 1.2*cm, f"Complications of Laparoscopic Cholecystectomy | Page {doc.page}")
canvas.restoreState()
doc.build(story, onFirstPage=on_first_page, onLaterPages=on_later_pages)
print(f"PDF saved to: {OUTPUT}")
cd /tmp/workspace/lap-chole-pdf && python generate_pdf.py 2>&1
~/lap-chole-pdf/generate_pdf.py
Successfully replaced 1 instance(s) of the string in '/tmp/workspace/lap-chole-pdf/generate_pdf.py'
cd /tmp/workspace/lap-chole-pdf && python generate_pdf.py 2>&1
python3 -c "import reportlab.graphics.shapes as s; print(dir(s))"
~/lap-chole-pdf/generate_pdf.py
Successfully replaced 1 instance(s) of the string in '/tmp/workspace/lap-chole-pdf/generate_pdf.py'
RoundedRect usage from the script and replace with Rect:cd /tmp/workspace/lap-chole-pdf && sed -i 's/RoundedRect(/Rect(/g' generate_pdf.py && python generate_pdf.py 2>&1
cd /tmp/workspace/lap-chole-pdf && sed -i '/from reportlab.graphics.charts.flowchart import FlowChart/d' generate_pdf.py && python generate_pdf.py 2>&1
ls -lh /tmp/workspace/lap-chole-pdf/Laparoscopic_Cholecystectomy_Complications.pdf
Laparoscopic Cholecystectomy Complications
PDF Document · PDF
Lumbar hernia and lumbar triangle Illustrative diagrams


| Boundary | Structure |
|---|---|
| Anterior | Posterior edge of external oblique muscle |
| Posterior (medial) | Anterior extent of latissimus dorsi muscle |
| Inferior (base) | Iliac crest |
| Floor | Lumbar fascia (internal oblique) |
| Roof | Skin + subcutaneous tissue (superficial) |
| Boundary | Structure |
|---|---|
| Superior | 12th rib + serratus posterior inferior muscle |
| Medial | Erector spinae / sacrospinalis muscles |
| Lateral | Posterior border of internal oblique muscle |
| Floor | Transversalis fascia |
| Roof | Entirely covered by latissimus dorsi muscle |
| Also contains | Quadratus lumborum posteriorly |





| Primary | Secondary (Acquired) | |
|---|---|---|
| Cause | Congenital or spontaneous | Trauma, surgery, infection, poliomyelitis |
| Specific causes | Developmental weakness | Flank/back trauma, iliac crest bone graft donor site, renal surgery, back surgery |
| Feature | Triangle of Petit | Triangle of Grynfeltt |
|---|---|---|
| Position | Inferior | Superior |
| Frequency | More common | Less common (but larger space) |
| Superior border | - | 12th rib + serratus posterior inferior |
| Medial border | Latissimus dorsi | Erector spinae / sacrospinalis |
| Lateral/anterior border | External oblique | Internal oblique (posterior border) |
| Base | Iliac crest | Quadratus lumborum |
| Floor | Lumbar fascia (int. oblique) | Transversalis fascia |
| Roof | Skin | Latissimus dorsi |
| Depth | Superficial | Deep (hidden under latissimus) |
Modern management of Aortic dissection TEVAR indications and procedure Stanford classification illustrative images

Type A:Type B ratio = 2:1 overall; TBAD more common in Black patients. Overall incidence: 3.5-16.3 per 100,000 patient-years.
| Category | Specific Conditions |
|---|---|
| Hypertension | Most common - chronic HTN, drug use (cocaine, meth) |
| Connective tissue | Marfan (FBN1 mutation), Loeys-Dietz (TGFB1/TGFBR2), Ehlers-Danlos |
| Genetic | MYH11, ACTA2, SMAD3 mutations |
| Structural | Bicuspid aortic valve, coarctation, prior aortic surgery |
| Inflammatory | Aortitis, giant cell arteritis |
| Precipitating lesions | Penetrating aortic ulcer (PAU), Intramural haematoma (IMH) |
| Drug | Class | Mechanism | Dose |
|---|---|---|---|
| Esmolol | β-blocker (1st choice) | Reduces HR and contractility (dP/dt) | 500 mcg/kg load → 50-200 mcg/kg/min infusion |
| Labetalol | α+β-blocker | BP + dP/dt reduction | 20 mg IV → 40-80 mg q10-15 min (max 300 mg); or 2-10 mg/min infusion |
| Sodium nitroprusside | Vasodilator | BP reduction (use WITH β-blocker) | 0.3 mcg/kg/min → 1-3 mcg/kg/min |
| Diltiazem | CCB (if β-blocked contraindicated) | HR + BP | 0.25 mg/kg bolus → 5-10 mg/h |
| Nicardipine | CCB | BP reduction | 5 mg/h → titrate to 15 mg/h |
⚠️ Vasodilators alone INCREASE shear stress on aortic wall by increasing dP/dt. Always combine with a β-blocker.


| Complication | Definition |
|---|---|
| Rupture / impending rupture | Haemothorax, haemomediastinum, periaortic haematoma expansion |
| Malperfusion | Branch vessel occlusion → bowel/renal/limb ischaemia |
| Refractory hypertension | Uncontrolled despite maximal medical therapy |
| Persistent or recurrent pain | Despite adequate medication |
| Rapid aortic expansion | ≥5 mm growth/year; diameter ≥55 mm |
| False lumen expansion | Progressive despite medical therapy |
| Indication | Evidence Level |
|---|---|
| Complicated acute TBAD (rupture, malperfusion) | Strong - now standard of care |
| Complicated chronic TBAD | Strong |
| Uncomplicated TBAD with high-risk features | Emerging (INSTEAD-XL: aortic-related mortality benefit at 5 years) |
| Uncomplicated TBAD, no high-risk features | Medical therapy preferred; TEVAR not yet proven superior |
| Complication | Rate / Notes |
|---|---|
| Stroke | 3-5% (higher if Zone 2 without LSA revascularisation) |
| Spinal cord ischaemia | 3-8% (varies with coverage length) |
| Endoleak (Type I/II) | 5-10% — requires re-intervention if Type I |
| Retrograde Type A dissection | ~1-2% — life-threatening; needs immediate surgery |
| Access site complications | 2-5% |
| Stent graft migration | Rare with modern devices |
| 30-day mortality (complicated TBAD) | ~8-10% vs >30% for open surgery |
Give the above in PDF
mkdir -p /tmp/workspace/aortic-dissection-pdf && ls /tmp/workspace/aortic-dissection-pdf/
cd /tmp/workspace/aortic-dissection-pdf && python3 -c " import urllib.request imgs = { 'classification.png': 'https://cdn.orris.care/cdss_images/2d68cf89a82d2f1c170edc224d5fab63eaa17f0d14cb9ef3dfb86ed31711a671.png', 'type_a_repair.png': 'https://cdn.orris.care/cdss_images/ce3baa95cd303738300ba6e859572558bafde83d845166767673a0d3884d4b70.png', 'frozen_elephant.png': 'https://cdn.orris.care/cdss_images/4c38c7ea710ded92f13ba61439cb3d1882e7e53fe6be1de7788809801cd6dad9.png', } for fn, url in imgs.items(): try: urllib.request.urlretrieve(url, fn) print(f'Downloaded {fn}') except Exception as e: print(f'FAILED {fn}: {e}') "
~/aortic-dissection-pdf/generate.py
import os
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak, KeepTogether, Image
)
from reportlab.graphics.shapes import Drawing, Line, Polygon, Rect, String, Path
from reportlab.platypus.flowables import Flowable
# ── Palette ───────────────────────────────────────────────────────────────────
C_NAVY = colors.HexColor("#0d2137")
C_DARK_BLUE = colors.HexColor("#1a3a5c")
C_MED_BLUE = colors.HexColor("#2e6da4")
C_LIGHT_BLUE = colors.HexColor("#d6eaf8")
C_SKY = colors.HexColor("#ebf5fb")
C_RED = colors.HexColor("#c0392b")
C_CRIMSON = colors.HexColor("#922b21")
C_ORANGE = colors.HexColor("#d35400")
C_GREEN = colors.HexColor("#1e8449")
C_TEAL = colors.HexColor("#117a65")
C_PURPLE = colors.HexColor("#7d3c98")
C_YELLOW = colors.HexColor("#b7950b")
C_LIGHT_RED = colors.HexColor("#fadbd8")
C_LIGHT_ORG = colors.HexColor("#fdebd0")
C_LIGHT_GRN = colors.HexColor("#d5f5e3")
C_LIGHT_PUR = colors.HexColor("#e8daef")
C_LIGHT_YELL = colors.HexColor("#fef9e7")
C_GREY = colors.HexColor("#7f8c8d")
C_LGREY = colors.HexColor("#f2f3f4")
C_WHITE = colors.white
C_BLACK = colors.black
W = A4[0] - 3*cm # usable width
OUTPUT = "/tmp/workspace/aortic-dissection-pdf/Aortic_Dissection_Management.pdf"
doc = SimpleDocTemplate(
OUTPUT, pagesize=A4,
leftMargin=1.5*cm, rightMargin=1.5*cm,
topMargin=1.8*cm, bottomMargin=1.8*cm,
title="Modern Management of Aortic Dissection",
author="Medical Reference"
)
# ── Styles ────────────────────────────────────────────────────────────────────
TITLE = ParagraphStyle("TITLE", fontName="Helvetica-Bold", fontSize=22, textColor=C_WHITE, alignment=TA_CENTER, leading=28)
TITLE2 = ParagraphStyle("TITLE2", fontName="Helvetica-Bold", fontSize=15, textColor=colors.HexColor("#f9ca24"), alignment=TA_CENTER, leading=20)
TITLE3 = ParagraphStyle("TITLE3", fontName="Helvetica-Oblique",fontSize=11, textColor=C_LIGHT_BLUE, alignment=TA_CENTER)
SRC = ParagraphStyle("SRC", fontName="Helvetica", fontSize=8, textColor=C_GREY, alignment=TA_CENTER)
H2 = ParagraphStyle("H2", fontName="Helvetica-Bold", fontSize=11, textColor=C_WHITE, alignment=TA_CENTER, leading=15)
H3 = ParagraphStyle("H3", fontName="Helvetica-Bold", fontSize=10, textColor=C_DARK_BLUE, spaceBefore=4, spaceAfter=3)
BODY = ParagraphStyle("BODY", fontName="Helvetica", fontSize=9, textColor=C_BLACK, leading=13, spaceAfter=3, alignment=TA_JUSTIFY)
BSMALL = ParagraphStyle("BSMALL", fontName="Helvetica", fontSize=8.5,textColor=C_BLACK, leading=12, spaceAfter=2)
BULLET = ParagraphStyle("BULLET", fontName="Helvetica", fontSize=8.5,textColor=C_BLACK, leading=12, leftIndent=10, spaceAfter=2)
SBOLD = ParagraphStyle("SBOLD", fontName="Helvetica-Bold", fontSize=8.5,textColor=C_DARK_BLUE, spaceAfter=2)
CAP = ParagraphStyle("CAP", fontName="Helvetica-Oblique",fontSize=7.5,textColor=C_GREY, alignment=TA_CENTER, spaceAfter=4)
WARN = ParagraphStyle("WARN", fontName="Helvetica-Bold", fontSize=9, textColor=C_RED, spaceAfter=3)
# ── Helpers ───────────────────────────────────────────────────────────────────
def sec_hdr(text, bg=C_DARK_BLUE, fg=C_WHITE):
p = Paragraph(f"<font name='Helvetica-Bold' size='11' color='white'>{text}</font>",
ParagraphStyle("sh", alignment=TA_LEFT, leading=14))
t = Table([[p]], colWidths=[W])
t.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,-1),bg),
("TOPPADDING",(0,0),(-1,-1),6),("BOTTOMPADDING",(0,0),(-1,-1),6),
("LEFTPADDING",(0,0),(-1,-1),10),
]))
return t
def arrow_down(w=W):
d = Drawing(w, 14)
m = w/2
d.add(Line(m,14,m,0, strokeColor=C_MED_BLUE, strokeWidth=1.8))
d.add(Polygon([m-5,4,m+5,4,m,0], fillColor=C_MED_BLUE, strokeColor=C_MED_BLUE))
return d
def info_box(title, text, bg, stroke):
rows = [[Paragraph(f"<font name='Helvetica-Bold' size='9' color='white'>{title}</font>",
ParagraphStyle("ib1", alignment=TA_CENTER))],
[Paragraph(text, BULLET)]]
t = Table(rows, colWidths=[W])
t.setStyle(TableStyle([
("BACKGROUND",(0,0),(0,0),stroke),
("BACKGROUND",(0,1),(0,1),bg),
("BOX",(0,0),(-1,-1),1,stroke),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),8),
]))
return t
def two_col(left_data, right_data, lw=None, rw=None, ls=C_MED_BLUE, rs=C_RED):
lw = lw or W*0.47
rw = rw or W*0.47
gap = W - lw - rw
def mkbox(data, stroke):
rows = [[Paragraph(f"<font name='Helvetica-Bold' size='9' color='white'>{data[0]}</font>",
ParagraphStyle("hdr", alignment=TA_CENTER))]]
for item in data[1:]:
rows.append([Paragraph(item, BULLET)])
t = Table(rows, colWidths=[lw if stroke==ls else rw])
t.setStyle(TableStyle([
("BACKGROUND",(0,0),(0,0),stroke),
("BACKGROUND",(0,1),(-1,-1),colors.HexColor("#eaf4fb") if stroke==ls else C_LIGHT_RED),
("BOX",(0,0),(-1,-1),1,stroke),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),6),("VALIGN",(0,0),(-1,-1),"TOP"),
]))
return t
return Table([[mkbox(left_data,ls), "", mkbox(right_data,rs)]],
colWidths=[lw, gap, rw])
# ═══════════════════════════════════════════════════════════════════════════════
story = []
# ── PAGE 1: TITLE + CLASSIFICATION ────────────────────────────────────────────
title_tbl = Table([
[Paragraph("MODERN MANAGEMENT OF", TITLE)],
[Paragraph("AORTIC DISSECTION", TITLE2)],
[Paragraph("Stanford Classification · Type A Surgery · Type B TEVAR", TITLE3)],
[Spacer(1,4)],
[Paragraph("Sources: Sabiston Textbook of Surgery · Fuster & Hurst's The Heart 15e · Current Surgical Therapy 14e", SRC)],
], colWidths=[W])
title_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,-1),C_NAVY),
("TOPPADDING",(0,0),(-1,-1),8),("BOTTOMPADDING",(0,0),(-1,-1),8),
("LEFTPADDING",(0,0),(-1,-1),10),
]))
story.append(title_tbl)
story.append(Spacer(1,10))
# Epidemiology box
epi = Table([[
Paragraph("<b>EPIDEMIOLOGY:</b> Incidence 3.5-16.3 per 100,000 patient-years | "
"Type A : Type B = 2:1 | Males 16/100,000 vs females 7.9/100,000 | "
"Mortality without treatment: ~1-2% per hour (Type A first 24 h)", BSMALL)
]], colWidths=[W])
epi.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,-1),C_LIGHT_YELL),
("BOX",(0,0),(-1,-1),1.5,C_YELLOW),
("TOPPADDING",(0,0),(-1,-1),6),("BOTTOMPADDING",(0,0),(-1,-1),6),
("LEFTPADDING",(0,0),(-1,-1),10),
]))
story.append(epi)
story.append(Spacer(1,8))
story.append(sec_hdr("STANFORD & DeBakey CLASSIFICATION"))
story.append(Spacer(1,6))
# Classification image
if os.path.exists("classification.png"):
img = Image("classification.png", width=W, height=7.5*cm)
img.hAlign = "CENTER"
story.append(img)
story.append(Paragraph("FIGURE: DeBakey (left) and Stanford (right) aortic dissection classifications. "
"Sabiston Textbook of Surgery, Figure 102.1.", CAP))
story.append(Spacer(1,6))
# Classification table
cls_data = [
[Paragraph("<b>System</b>",SBOLD), Paragraph("<b>Type</b>",SBOLD),
Paragraph("<b>Extent</b>",SBOLD), Paragraph("<b>Treatment</b>",SBOLD)],
[Paragraph("DeBakey",BODY), Paragraph("Type I",BODY),
Paragraph("Ascending + arch + descending aorta",BODY),
Paragraph("Emergency surgery",BODY)],
[Paragraph("DeBakey",BODY), Paragraph("Type II",BODY),
Paragraph("Ascending aorta only",BODY),
Paragraph("Emergency surgery",BODY)],
[Paragraph("DeBakey",BODY), Paragraph("Type IIIa",BODY),
Paragraph("Descending thoracic aorta (above diaphragm)",BODY),
Paragraph("Medical ± TEVAR",BODY)],
[Paragraph("DeBakey",BODY), Paragraph("Type IIIb",BODY),
Paragraph("Descending aorta extending below diaphragm",BODY),
Paragraph("Medical ± TEVAR",BODY)],
[Paragraph("<b>Stanford</b>",BODY), Paragraph("<b>Type A</b>",BODY),
Paragraph("<b>ANY ascending aorta involvement</b>",BODY),
Paragraph("<b>SURGICAL EMERGENCY</b>",BODY)],
[Paragraph("<b>Stanford</b>",BODY), Paragraph("<b>Type B</b>",BODY),
Paragraph("<b>Descending aorta only (distal to L. subclavian)</b>",BODY),
Paragraph("<b>Medical first; TEVAR if complicated</b>",BODY)],
]
cls_tbl = Table(cls_data, colWidths=[2.8*cm, 2.5*cm, 7.5*cm, 4.2*cm])
cls_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),C_DARK_BLUE),("TEXTCOLOR",(0,0),(-1,0),C_WHITE),
("BACKGROUND",(0,1),(-1,2),C_LIGHT_RED),
("BACKGROUND",(0,3),(-1,4),C_LIGHT_BLUE),
("BACKGROUND",(0,5),(-1,5),C_RED),("TEXTCOLOR",(0,5),(-1,5),C_WHITE),
("BACKGROUND",(0,6),(-1,6),C_MED_BLUE),("TEXTCOLOR",(0,6),(-1,6),C_WHITE),
("BOX",(0,0),(-1,-1),1,C_MED_BLUE),
("INNERGRID",(0,0),(-1,-1),0.4,C_GREY),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),6),("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(cls_tbl)
story.append(PageBreak())
# ── PAGE 2: RISK FACTORS + DIAGNOSIS + MEDICAL MANAGEMENT ────────────────────
story.append(sec_hdr("RISK FACTORS & PATHOPHYSIOLOGY"))
story.append(Spacer(1,6))
rf_data = [
[Paragraph("<b>Category</b>",SBOLD), Paragraph("<b>Specific Conditions</b>",SBOLD)],
[Paragraph("Hypertension",BODY), Paragraph("Most common (67% in IRAD); cocaine/methamphetamines (younger patients)",BODY)],
[Paragraph("Connective tissue",BODY), Paragraph("Marfan (FBN1 mutation), Loeys-Dietz (TGFB1/TGFBR2), Ehlers-Danlos",BODY)],
[Paragraph("Genetic",BODY), Paragraph("MYH11, ACTA2, SMAD3 mutations; bicuspid aortic valve",BODY)],
[Paragraph("Structural / Iatrogenic",BODY), Paragraph("Coarctation; prior aortic surgery; cardiac catheterisation",BODY)],
[Paragraph("Inflammatory",BODY), Paragraph("Aortitis; giant cell arteritis; Takayasu arteritis",BODY)],
[Paragraph("Precipitating lesions",BODY), Paragraph("Penetrating aortic ulcer (PAU); Intramural haematoma (IMH)",BODY)],
]
rf_tbl = Table(rf_data, colWidths=[4.5*cm, W-4.5*cm])
rf_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),C_DARK_BLUE),("TEXTCOLOR",(0,0),(-1,0),C_WHITE),
("ROWBACKGROUNDS",(0,1),(-1,-1),[C_LIGHT_BLUE,C_WHITE]),
("BOX",(0,0),(-1,-1),1,C_MED_BLUE),("INNERGRID",(0,0),(-1,-1),0.4,C_GREY),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),6),("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(rf_tbl)
story.append(Spacer(1,8))
story.append(sec_hdr("DIAGNOSIS — INVESTIGATIONS"))
story.append(Spacer(1,6))
diag_data = [
[Paragraph("<b>Investigation</b>",SBOLD), Paragraph("<b>Sensitivity / Specificity</b>",SBOLD),
Paragraph("<b>Notes</b>",SBOLD)],
[Paragraph("CT Aortography",BODY), Paragraph("Sens ~100% / Spec ~100%",BODY),
Paragraph("Gold standard. 'Triple rule-out' protocol (dissection + PE + ACS). Most widely used in acute setting.",BODY)],
[Paragraph("TEE",BODY), Paragraph("Sens 98% / Spec 63-96%",BODY),
Paragraph("Excellent for TAAD; detects flap in descending aorta; evaluates aortic valve and pericardium",BODY)],
[Paragraph("MRI",BODY), Paragraph("Sens ~100% / Spec ~100%",BODY),
Paragraph("Equivalent to CT but impractical in acute/haemodynamically unstable patients",BODY)],
[Paragraph("TTE",BODY), Paragraph("Sens 35-80% / Spec 35-96%",BODY),
Paragraph("Limited utility. Normal TTE does NOT exclude dissection.",BODY)],
[Paragraph("D-dimer",BODY), Paragraph("Normal = excludes",BODY),
Paragraph("False lumen thrombosis raises D-dimer. Negative / normal D-dimer effectively rules out dissection.",BODY)],
[Paragraph("CXR",BODY), Paragraph("Widened mediastinum ~60%",BODY),
Paragraph("May show widened mediastinum, left pleural effusion; non-specific; not diagnostic.",BODY)],
]
diag_tbl = Table(diag_data, colWidths=[3.5*cm, 4.5*cm, W-8*cm])
diag_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),C_DARK_BLUE),("TEXTCOLOR",(0,0),(-1,0),C_WHITE),
("ROWBACKGROUNDS",(0,1),(-1,-1),[C_SKY,C_WHITE]),
("BOX",(0,0),(-1,-1),1,C_MED_BLUE),("INNERGRID",(0,0),(-1,-1),0.4,C_GREY),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),6),("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(diag_tbl)
story.append(Spacer(1,8))
story.append(sec_hdr("IMMEDIATE MEDICAL MANAGEMENT — ANTI-IMPULSE THERAPY (ALL TYPES)", bg=C_TEAL))
story.append(Spacer(1,4))
target_box = Table([[
Paragraph("<b>Haemodynamic Targets:</b> SBP 100-120 mmHg | HR <60 bpm | "
"Reduce rate of pressure rise (dP/dt) — the primary driver of propagation", BSMALL)
]], colWidths=[W])
target_box.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,-1),C_LIGHT_GRN),("BOX",(0,0),(-1,-1),1.5,C_GREEN),
("TOPPADDING",(0,0),(-1,-1),6),("BOTTOMPADDING",(0,0),(-1,-1),6),("LEFTPADDING",(0,0),(-1,-1),10),
]))
story.append(target_box)
story.append(Spacer(1,4))
warn_box = Table([[
Paragraph("⚠ Vasodilators ALONE increase aortic wall shear stress by raising dP/dt. "
"ALWAYS combine with a beta-blocker.", WARN)
]], colWidths=[W])
warn_box.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,-1),C_LIGHT_RED),("BOX",(0,0),(-1,-1),1.5,C_RED),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),("LEFTPADDING",(0,0),(-1,-1),10),
]))
story.append(warn_box)
story.append(Spacer(1,4))
drug_data = [
[Paragraph("<b>Drug</b>",SBOLD), Paragraph("<b>Class</b>",SBOLD),
Paragraph("<b>Dose</b>",SBOLD), Paragraph("<b>Notes</b>",SBOLD)],
[Paragraph("Esmolol",BODY), Paragraph("β-blocker (1st line)",BODY),
Paragraph("500 mcg/kg load → 50-200 mcg/kg/min infusion",BODY),
Paragraph("Short-acting; titratable; preferred agent",BODY)],
[Paragraph("Labetalol",BODY), Paragraph("α+β-blocker",BODY),
Paragraph("20 mg IV → 40-80 mg q10-15 min (max 300 mg); or 2-10 mg/min infusion",BODY),
Paragraph("Dual action; single agent option",BODY)],
[Paragraph("Propranolol",BODY), Paragraph("β-blocker",BODY),
Paragraph("1 mg q3 min → 1-3 mg q4h",BODY),
Paragraph("Older agent; avoid in asthma",BODY)],
[Paragraph("Sodium nitroprusside",BODY), Paragraph("Vasodilator",BODY),
Paragraph("0.3-1.3 mcg/kg/min → 1-3 mcg/kg/min",BODY),
Paragraph("Use ONLY WITH β-blocker; avoid in hepatic/renal failure",BODY)],
[Paragraph("Diltiazem",BODY), Paragraph("CCB (if β-blocked CI)",BODY),
Paragraph("0.25 mg/kg bolus → 5-10 mg/h",BODY),
Paragraph("Alternative when β-blockers contraindicated",BODY)],
[Paragraph("Nicardipine",BODY), Paragraph("CCB",BODY),
Paragraph("5 mg/h → titrate to max 15 mg/h",BODY),
Paragraph("BP reduction; combine with β-blocker",BODY)],
]
drug_tbl = Table(drug_data, colWidths=[2.8*cm, 3.5*cm, 6.2*cm, W-12.5*cm])
drug_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),C_TEAL),("TEXTCOLOR",(0,0),(-1,0),C_WHITE),
("ROWBACKGROUNDS",(0,1),(-1,-1),[C_LIGHT_GRN,C_WHITE]),
("BOX",(0,0),(-1,-1),1,C_TEAL),("INNERGRID",(0,0),(-1,-1),0.4,C_GREY),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),5),("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(drug_tbl)
story.append(PageBreak())
# ── PAGE 3: TYPE A FLOWCHART + SURGICAL DETAIL ────────────────────────────────
story.append(sec_hdr("TYPE A DISSECTION — FLOWCHART & SURGICAL MANAGEMENT", bg=C_RED))
story.append(Spacer(1,8))
def flow_node(text, fill, stroke, col_w=None, fsize=9, bold=True):
cw = col_w or W*0.72
fn = "Helvetica-Bold" if bold else "Helvetica"
p = Paragraph(f"<font name='{fn}' size='{fsize}' color='white'>{text}</font>",
ParagraphStyle("fn",alignment=TA_CENTER,leading=13))
t = Table([[p]], colWidths=[cw])
t.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),fill),("BOX",(0,0),(-1,-1),1.5,stroke),
("TOPPADDING",(0,0),(-1,-1),6),("BOTTOMPADDING",(0,0),(-1,-1),6)]))
return Table([[t]], colWidths=[W], style=[("ALIGN",(0,0),(-1,-1),"CENTER")])
story.append(flow_node("ACUTE TYPE A AORTIC DISSECTION (Stanford A / DeBakey I+II)", C_RED, C_CRIMSON, fsize=10))
story.append(arrow_down())
story.append(flow_node("IMMEDIATE ANTI-IMPULSE THERAPY + EMERGENCY SURGICAL REFERRAL", C_DARK_BLUE, C_DARK_BLUE))
story.append(arrow_down())
# Branch: Surgical vs Medical
can_surg = Table([[Paragraph("<b>SURGICAL CANDIDATE?</b>",
ParagraphStyle("cs",fontName="Helvetica-Bold",fontSize=9.5,textColor=C_WHITE,alignment=TA_CENTER))]],
colWidths=[W*0.55])
can_surg.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),colors.HexColor("#e67e22")),
("TOPPADDING",(0,0),(-1,-1),7),("BOTTOMPADDING",(0,0),(-1,-1),7),
("BOX",(0,0),(-1,-1),1.5,colors.HexColor("#d35400"))]))
story.append(Table([[can_surg]], colWidths=[W], style=[("ALIGN",(0,0),(-1,-1),"CENTER")]))
story.append(Spacer(1,4))
br_yes = Table([[Paragraph("<b>YES</b><br/>Open surgical repair\nMortality 15-25% overall;\n<10% at specialist centres",
ParagraphStyle("by",fontName="Helvetica-Bold",fontSize=8.5,textColor=C_WHITE,alignment=TA_CENTER,leading=12))]],
colWidths=[W*0.44])
br_yes.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),C_GREEN),("BOX",(0,0),(-1,-1),1,C_GREEN),
("TOPPADDING",(0,0),(-1,-1),6),("BOTTOMPADDING",(0,0),(-1,-1),6)]))
br_no = Table([[Paragraph("<b>NO (relative CI)</b><br/>Frailty, extreme comorbidity,\nadvanced CVA, patient refusal\n→ Medical palliation / observation",
ParagraphStyle("bn",fontName="Helvetica-Bold",fontSize=8.5,textColor=C_WHITE,alignment=TA_CENTER,leading=12))]],
colWidths=[W*0.44])
br_no.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),C_GREY),("BOX",(0,0),(-1,-1),1,C_GREY),
("TOPPADDING",(0,0),(-1,-1),6),("BOTTOMPADDING",(0,0),(-1,-1),6)]))
story.append(Table([[br_yes,"",br_no]], colWidths=[W*0.44,W*0.12,W*0.44]))
story.append(Spacer(1,6))
story.append(arrow_down())
# Surgical steps
surg_steps = [
("1. Arterial Cannulation", C_MED_BLUE, "Axillary artery preferred (avoids true/false lumen confusion; enables selective antegrade cerebral perfusion [ACP])"),
("2. Cardiopulmonary Bypass + Cooling", C_MED_BLUE, "Cool to hypothermia. Deep HCA (14-20°C, 20-30 min safe) or profound (<14°C, 30-40 min)"),
("3. Circulatory Arrest + Cerebral Protection", C_MED_BLUE, "Antegrade cerebral perfusion (ACP) via axillary/direct cannulation — preferred over retrograde"),
("4. Resect Dissected Ascending Aorta", C_RED, "From sinotubular junction to innominate artery; inspect arch for complex intimal disruptions"),
("5. Obliterate False Lumen", C_RED, "Aortic wall layers sandwiched between Teflon felt strips; reconstruct all three layers"),
("6. Distal Anastomosis", C_RED, "Dacron graft sewn to reconstituted felt-reinforced aorta; reperfuse head/body"),
("7. Proximal Repair (Root + Valve)", C_DARK_BLUE, "Simple AR: valve resuspension\nComplex root dissection: Bentall procedure\nNo root involvement: direct graft to sinotubular junction"),
("8. Aortic Arch", C_DARK_BLUE, "Routine: hemiarch replacement\nIndications for total arch: tear in arch, aneurysm >5 cm, Marfan/genetic disease"),
]
for step, col, desc in surg_steps:
row = Table([[
Table([[Paragraph(f"<font name='Helvetica-Bold' size='8.5' color='white'>{step}</font>",
ParagraphStyle("ss",alignment=TA_CENTER,leading=12))]],
colWidths=[5*cm],
style=[("BACKGROUND",(0,0),(-1,-1),col),("TOPPADDING",(0,0),(-1,-1),5),
("BOTTOMPADDING",(0,0),(-1,-1),5),("BOX",(0,0),(-1,-1),1,col)]),
Paragraph(desc, BSMALL)
]], colWidths=[5*cm, W-5.5*cm])
row.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),C_LGREY),
("BOX",(0,0),(-1,-1),0.5,C_GREY),
("TOPPADDING",(0,0),(-1,-1),3),("BOTTOMPADDING",(0,0),(-1,-1),3),
("LEFTPADDING",(0,0),(-1,-1),4),("VALIGN",(0,0),(-1,-1),"MIDDLE")]))
story.append(row)
story.append(Spacer(1,2))
story.append(Spacer(1,6))
# Type A repair image
if os.path.exists("type_a_repair.png"):
img = Image("type_a_repair.png", width=W*0.7, height=12*cm)
img.hAlign = "CENTER"
story.append(img)
story.append(Paragraph(
"FIGURE: Surgical repair of acute Type A dissection. (A) Aortic layers sandwiched between Teflon felt. "
"(B) Distal anastomosis complete; flow restored via axillary graft. (C) Antegrade perfusion via side-arm. "
"(D) Completed repair with valve resuspended. (Current Surgical Therapy 14e, Fig. 3)", CAP))
story.append(PageBreak())
# ── PAGE 4: FROZEN ELEPHANT TRUNK + TYPE A COMPLICATIONS ─────────────────────
story.append(sec_hdr("FROZEN ELEPHANT TRUNK (FET) TECHNIQUE", bg=C_DARK_BLUE))
story.append(Spacer(1,6))
fet_data = [
[Paragraph("<b>Indication</b>",SBOLD), Paragraph("<b>Details</b>",SBOLD)],
[Paragraph("Large intimal tear in distal arch / proximal descending aorta",BODY),
Paragraph("Stent graft deployed ANTEGRADE under direct vision into descending aorta during circulatory arrest period",BODY)],
[Paragraph("Aim",BODY),
Paragraph("Stabilises distal dissection; obliterates distal false lumen; reduces need for early re-intervention",BODY)],
[Paragraph("Anatomy",BODY),
Paragraph("Dacron graft (ascending/hemiarch) + distal stent graft = 'elephant trunk' shape in descending aorta",BODY)],
[Paragraph("Indication extension",BODY),
Paragraph("Marfan syndrome; Loeys-Dietz; complex intimal disruptions; arch aneurysms >5 cm",BODY)],
]
fet_tbl = Table(fet_data, colWidths=[5.5*cm, W-5.5*cm])
fet_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),C_DARK_BLUE),("TEXTCOLOR",(0,0),(-1,0),C_WHITE),
("ROWBACKGROUNDS",(0,1),(-1,-1),[C_LIGHT_BLUE,C_WHITE]),
("BOX",(0,0),(-1,-1),1,C_DARK_BLUE),("INNERGRID",(0,0),(-1,-1),0.4,C_GREY),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),6),("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(fet_tbl)
story.append(Spacer(1,8))
# Aortic regurgitation mechanisms
story.append(sec_hdr("AORTIC REGURGITATION IN TYPE A — 3 MECHANISMS", bg=C_CRIMSON))
story.append(Spacer(1,4))
ar_items = [
("Mechanism 1", "Sinotubular junction dilation by expanding false lumen → incomplete cusp coaptation"),
("Mechanism 2", "Dissection extends into aortic root → commissural post disruption → cusp prolapse"),
("Mechanism 3", "Intimal flap prolapses through the valve orifice during diastole"),
]
ar_rows = []
for m, desc in ar_items:
ar_rows.append([Paragraph(f"<b>{m}</b>",SBOLD), Paragraph(desc,BODY)])
ar_tbl = Table(ar_rows, colWidths=[3.5*cm, W-3.5*cm])
ar_tbl.setStyle(TableStyle([
("ROWBACKGROUNDS",(0,0),(-1,-1),[C_LIGHT_RED,C_WHITE]),
("BOX",(0,0),(-1,-1),1,C_CRIMSON),("INNERGRID",(0,0),(-1,-1),0.4,C_GREY),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),6),("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(ar_tbl)
story.append(Spacer(1,8))
# Type A post-op complications
story.append(sec_hdr("TYPE A POST-OPERATIVE COMPLICATIONS", bg=C_CRIMSON))
story.append(Spacer(1,4))
comp_a = [
[Paragraph("<b>Complication</b>",SBOLD), Paragraph("<b>Notes</b>",SBOLD)],
[Paragraph("Coagulopathic bleeding",BODY), Paragraph("Massive transfusion; re-exploration may be needed",BODY)],
[Paragraph("Stroke / neurological deficit",BODY), Paragraph("84.3% of CVA patients recover with surgery vs medical management; ACP reduces risk",BODY)],
[Paragraph("New malperfusion syndromes",BODY), Paragraph("Bowel ischaemia, renal failure — may need pre-op revascularisation in selected patients",BODY)],
[Paragraph("Acute lung injury",BODY), Paragraph("CPB-related; managed with lung-protective ventilation",BODY)],
[Paragraph("Multiorgan failure",BODY), Paragraph("ICU management; mortality driver in unstable patients (>30%)",BODY)],
[Paragraph("Refractory hypertension",BODY), Paragraph("Persistent dissection in aortic root / arch; medical management",BODY)],
]
comp_a_tbl = Table(comp_a, colWidths=[5*cm, W-5*cm])
comp_a_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),C_CRIMSON),("TEXTCOLOR",(0,0),(-1,0),C_WHITE),
("ROWBACKGROUNDS",(0,1),(-1,-1),[C_LIGHT_RED,C_WHITE]),
("BOX",(0,0),(-1,-1),1,C_CRIMSON),("INNERGRID",(0,0),(-1,-1),0.4,C_GREY),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),6),("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(comp_a_tbl)
story.append(PageBreak())
# ── PAGE 5: TYPE B FLOWCHART + MANAGEMENT ────────────────────────────────────
story.append(sec_hdr("TYPE B DISSECTION — FLOWCHART & MANAGEMENT ALGORITHM", bg=C_MED_BLUE))
story.append(Spacer(1,8))
story.append(flow_node("ACUTE TYPE B AORTIC DISSECTION (Stanford B / DeBakey III)", C_MED_BLUE, C_DARK_BLUE, fsize=10))
story.append(arrow_down())
story.append(flow_node("IMMEDIATE ANTI-IMPULSE THERAPY (ALL patients)", C_TEAL, C_TEAL))
story.append(arrow_down())
# Diamond decision
dmd = Table([[Paragraph("<b>◆ COMPLICATED or UNCOMPLICATED? ◆</b>",
ParagraphStyle("dm",fontName="Helvetica-Bold",fontSize=9.5,textColor=C_BLACK,alignment=TA_CENTER))]],
colWidths=[W*0.65])
dmd.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),colors.HexColor("#fef9e7")),
("BOX",(0,0),(-1,-1),2,C_ORANGE),
("TOPPADDING",(0,0),(-1,-1),8),("BOTTOMPADDING",(0,0),(-1,-1),8)]))
story.append(Table([[dmd]], colWidths=[W], style=[("ALIGN",(0,0),(-1,-1),"CENTER")]))
story.append(Spacer(1,4))
# Complicated features box
comp_feat = Table([[
Paragraph("<b>Features of COMPLICATED Type B (any one = intervention):</b> "
"Rupture / haemothorax | Malperfusion (bowel, renal, limb) | "
"Refractory hypertension | Persistent/recurrent pain | "
"Rapid expansion ≥5 mm / aorta ≥55 mm | False lumen enlargement", BSMALL)
]], colWidths=[W])
comp_feat.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,-1),C_LIGHT_ORG),("BOX",(0,0),(-1,-1),1.5,C_ORANGE),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),("LEFTPADDING",(0,0),(-1,-1),8),
]))
story.append(comp_feat)
story.append(Spacer(1,4))
comp_br = Table([[Paragraph("<b>COMPLICATED (~20%)</b><br/>TEVAR — treatment of choice\n(Mortality ~10% vs open ~34%)",
ParagraphStyle("cb",fontName="Helvetica-Bold",fontSize=9,textColor=C_WHITE,alignment=TA_CENTER,leading=13))]],
colWidths=[W*0.44])
comp_br.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),C_ORANGE),("BOX",(0,0),(-1,-1),1,C_ORANGE),
("TOPPADDING",(0,0),(-1,-1),7),("BOTTOMPADDING",(0,0),(-1,-1),7)]))
unco_br = Table([[Paragraph("<b>UNCOMPLICATED (~80%)</b><br/>Best Medical Therapy (BMT)\nOptimal anti-impulse therapy\nLifelong surveillance CT",
ParagraphStyle("ub",fontName="Helvetica-Bold",fontSize=9,textColor=C_WHITE,alignment=TA_CENTER,leading=13))]],
colWidths=[W*0.44])
unco_br.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),C_MED_BLUE),("BOX",(0,0),(-1,-1),1,C_DARK_BLUE),
("TOPPADDING",(0,0),(-1,-1),7),("BOTTOMPADDING",(0,0),(-1,-1),7)]))
story.append(Table([[comp_br,"",unco_br]], colWidths=[W*0.44,W*0.12,W*0.44]))
story.append(Spacer(1,8))
# Key trial evidence
story.append(sec_hdr("KEY CLINICAL TRIAL EVIDENCE FOR TEVAR vs MEDICAL THERAPY", bg=C_DARK_BLUE))
story.append(Spacer(1,4))
trial_data = [
[Paragraph("<b>Trial</b>",SBOLD), Paragraph("<b>Population</b>",SBOLD),
Paragraph("<b>Finding</b>",SBOLD), Paragraph("<b>Significance</b>",SBOLD)],
[Paragraph("INSTEAD",BODY), Paragraph("Uncomplicated TBAD",BODY),
Paragraph("2 yr: No mortality difference TEVAR vs BMT; better aortic remodelling with TEVAR",BODY),
Paragraph("Underpowered; remodelling benefit noted",BODY)],
[Paragraph("INSTEAD-XL",BODY), Paragraph("Uncomplicated TBAD (5-yr extension)",BODY),
Paragraph("5 yr: Aortic-related mortality benefit with TEVAR",BODY),
Paragraph("First long-term mortality advantage for TEVAR",BODY)],
[Paragraph("ADSORB",BODY), Paragraph("Uncomplicated TBAD",BODY),
Paragraph("BMT+TEVAR vs BMT: False lumen thrombosis 57% vs 3% (p<0.001) at 1 yr",BODY),
Paragraph("Superior remodelling; not powered for mortality",BODY)],
[Paragraph("IRAD Registry",BODY), Paragraph("All TBAD",BODY),
Paragraph("Open surgery mortality ~34%; TEVAR ~10%; Medical ~10% for acute TBAD",BODY),
Paragraph("Established TEVAR as preferred over open surgery",BODY)],
]
trial_tbl = Table(trial_data, colWidths=[2.5*cm, 4.5*cm, 7*cm, W-14*cm])
trial_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),C_DARK_BLUE),("TEXTCOLOR",(0,0),(-1,0),C_WHITE),
("ROWBACKGROUNDS",(0,1),(-1,-1),[C_LIGHT_BLUE,C_WHITE]),
("BOX",(0,0),(-1,-1),1,C_DARK_BLUE),("INNERGRID",(0,0),(-1,-1),0.4,C_GREY),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),5),("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(trial_tbl)
story.append(PageBreak())
# ── PAGE 6: TEVAR PROCEDURE ───────────────────────────────────────────────────
story.append(sec_hdr("TEVAR — THORACIC ENDOVASCULAR AORTIC REPAIR: PROCEDURE", bg=C_PURPLE))
story.append(Spacer(1,6))
# Goals
goals_data = [
[Paragraph("<b>Goals of TEVAR in Type B Dissection</b>",
ParagraphStyle("gd",fontName="Helvetica-Bold",fontSize=9.5,textColor=C_WHITE,alignment=TA_CENTER))],
[Table([
[Paragraph("1. Cover primary intimal tear", BULLET),
Paragraph("2. Obliterate / thrombose false lumen", BULLET)],
[Paragraph("3. Relieve malperfusion", BULLET),
Paragraph("4. Promote true lumen expansion + aortic remodelling", BULLET)],
], colWidths=[W*0.5]*2)],
]
goals_tbl = Table(goals_data, colWidths=[W])
goals_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(0,0),C_PURPLE),
("BACKGROUND",(0,1),(0,1),C_LIGHT_PUR),
("BOX",(0,0),(-1,-1),1,C_PURPLE),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),5),
]))
story.append(goals_tbl)
story.append(Spacer(1,8))
# Coverage zones
story.append(Paragraph("<b>ENDOVASCULAR COVERAGE ZONES (Mitchell / SVS Zones)</b>", H3))
zones_data = [
[Paragraph("<b>Zone</b>",SBOLD), Paragraph("<b>Anatomical Location</b>",SBOLD), Paragraph("<b>Relevance</b>",SBOLD)],
[Paragraph("Zone 0",BODY), Paragraph("Ascending aorta",BODY), Paragraph("Origin of all arch vessels",BODY)],
[Paragraph("Zone 1",BODY), Paragraph("Between brachiocephalic + left common carotid",BODY), Paragraph("Near innominate",BODY)],
[Paragraph("Zone 2",BODY), Paragraph("Between left CCA + left subclavian artery (LSA)",BODY),
Paragraph("LSA coverage needed → carotid-subclavian bypass first",BODY)],
[Paragraph("Zone 3 ★",BODY), Paragraph("Just distal to LSA (proximal descending)",BODY),
Paragraph("Standard PROXIMAL landing zone for Type B TEVAR",BODY)],
[Paragraph("Zone 4",BODY), Paragraph("Mid-descending thoracic aorta (T4-T6)",BODY), Paragraph("",BODY)],
[Paragraph("Zone 5 ★",BODY), Paragraph("Distal descending thoracic / just proximal to celiac axis",BODY),
Paragraph("Standard DISTAL landing zone for Type B TEVAR",BODY)],
]
zones_tbl = Table(zones_data, colWidths=[2*cm, 7.5*cm, W-9.5*cm])
zones_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),C_PURPLE),("TEXTCOLOR",(0,0),(-1,0),C_WHITE),
("BACKGROUND",(0,3),(-1,3),C_LIGHT_PUR),("BACKGROUND",(0,6),(-1,6),C_LIGHT_PUR),
("ROWBACKGROUNDS",(0,1),(-1,-1),[C_WHITE,C_LGREY]),
("BACKGROUND",(0,3),(-1,3),C_LIGHT_PUR),("BACKGROUND",(0,6),(-1,6),C_LIGHT_PUR),
("BOX",(0,0),(-1,-1),1,C_PURPLE),("INNERGRID",(0,0),(-1,-1),0.4,C_GREY),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),6),("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(zones_tbl)
story.append(Spacer(1,8))
# TEVAR step-by-step
story.append(Paragraph("<b>TEVAR PROCEDURE — STEP BY STEP</b>", H3))
tevar_steps = [
("Step 1: Access", "Common femoral artery — open cut-down OR percutaneous with fluoroscopy + ultrasound guidance"),
("Step 2: Anticoagulation", "Systemic heparin → ACT >250 seconds"),
("Step 3: Wire Placement", "J-wire advanced into ascending aorta"),
("Step 4: IVUS Confirmation", "Intravascular ultrasound confirms TRUE LUMEN access along entire wire. Also identifies: LSA origin, celiac axis, compressed true lumen, branch vessel dissection"),
("Step 5: Wire Exchange", "Soft J-wire exchanged for stiff Lunderquist exchange wire"),
("Step 6: Sheath Advancement", "Large delivery sheath advanced into abdominal aorta"),
("Step 7: Aortography", "Pigtail catheter from contralateral femoral access; LAO projection thoracic aortography; delineate LSA and primary tear"),
("Step 8: Device Positioning", "Proximal end at Zone 3 (or Zone 2 if LSA coverage required); ventilation HELD during deployment"),
("Step 9: Sequential Deployment", "Multiple overlapping stent grafts deployed until primary tear sealed to Zone 5"),
("Step 10: Balloon Moulding", "Proximal and distal landing zone apposition; avoid aggressive ballooning in dissected segment"),
("Step 11: Completion Aortography", "Assess for endoleak (esp. Type I), residual malperfusion, false lumen perfusion"),
]
for step, desc in tevar_steps:
row = Table([[
Table([[Paragraph(f"<font name='Helvetica-Bold' size='8.5' color='white'>{step}</font>",
ParagraphStyle("ts",alignment=TA_CENTER,leading=12))]],
colWidths=[4.5*cm],
style=[("BACKGROUND",(0,0),(-1,-1),C_PURPLE),("TOPPADDING",(0,0),(-1,-1),4),
("BOTTOMPADDING",(0,0),(-1,-1),4),("BOX",(0,0),(-1,-1),1,C_PURPLE)]),
Paragraph(desc, BSMALL)
]], colWidths=[4.5*cm, W-5*cm])
row.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),C_LGREY),
("BOX",(0,0),(-1,-1),0.5,C_GREY),
("TOPPADDING",(0,0),(-1,-1),3),("BOTTOMPADDING",(0,0),(-1,-1),3),
("LEFTPADDING",(0,0),(-1,-1),4),("VALIGN",(0,0),(-1,-1),"MIDDLE")]))
story.append(row)
story.append(Spacer(1,2))
story.append(PageBreak())
# ── PAGE 7: LSA + PETTICOAT + TEVAR COMPLICATIONS ────────────────────────────
story.append(sec_hdr("TEVAR — SPECIAL CONSIDERATIONS & COMPLICATIONS", bg=C_PURPLE))
story.append(Spacer(1,6))
# LSA revascularisation
lsa_data = [
[Paragraph("<b>LEFT SUBCLAVIAN ARTERY (LSA) MANAGEMENT</b>",
ParagraphStyle("lsa",fontName="Helvetica-Bold",fontSize=9.5,textColor=C_WHITE,alignment=TA_CENTER))],
[Table([
[Paragraph("<b>When Zone 2 coverage is needed</b> (intimal tear close to LSA):",SBOLD)],
[Paragraph("• Pre-emptive carotid-subclavian bypass or subclavian-carotid transposition recommended",BULLET)],
[Paragraph("• Reduces risk of: vertebrobasilar stroke | left arm ischaemia | spinal cord ischaemia (artery of Adamkiewicz via T8-L2)",BULLET)],
[Paragraph("• If TEVAR is emergent and LSA cannot be revascularised first: accept risk and treat post-op if symptoms develop",BULLET)],
], colWidths=[W-0.5*cm])],
]
lsa_tbl = Table(lsa_data, colWidths=[W])
lsa_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(0,0),C_DARK_BLUE),
("BACKGROUND",(0,1),(0,1),C_LIGHT_BLUE),
("BOX",(0,0),(-1,-1),1,C_DARK_BLUE),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),6),
]))
story.append(lsa_tbl)
story.append(Spacer(1,8))
# PETTICOAT
pet_data = [
[Paragraph("<b>PETTICOAT TECHNIQUE</b>",
ParagraphStyle("pt",fontName="Helvetica-Bold",fontSize=9.5,textColor=C_WHITE,alignment=TA_CENTER))],
[Table([
[Paragraph("<b>Indication:</b> Persistent distal false lumen flow / true lumen collapse after TEVAR (seen in ~12% of initial TEVAR cases)",SBOLD)],
[Paragraph("<b>Technique:</b> Deploy uncovered (bare metal) stent DISTAL to the covered stent graft",BULLET)],
[Paragraph("<b>Effect:</b> Reperfuses true lumen; abolishes distal malperfusion; improves aortic remodelling at 1 year",BULLET)],
[Paragraph("<b>e-PETTICOAT:</b> Extended variant covering entire descending thoracic AND abdominal aorta pre-emptively",BULLET)],
[Paragraph("<b>Adaptation for Type A:</b> Used as part of Frozen Elephant Trunk during open repair to address distal aorta",BULLET)],
], colWidths=[W-0.5*cm])],
]
pet_tbl = Table(pet_data, colWidths=[W])
pet_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(0,0),C_TEAL),
("BACKGROUND",(0,1),(0,1),C_LIGHT_GRN),
("BOX",(0,0),(-1,-1),1,C_TEAL),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),6),
]))
story.append(pet_tbl)
story.append(Spacer(1,8))
# SCI prevention
story.append(sec_hdr("SPINAL CORD ISCHAEMIA (SCI) PREVENTION", bg=C_ORANGE))
story.append(Spacer(1,4))
sci_data = [
[Paragraph("<b>Risk Factor</b>",SBOLD), Paragraph("<b>Prevention Strategy</b>",SBOLD)],
[Paragraph("Artery of Adamkiewicz (T8-L2) coverage",BODY),
Paragraph("Avoid unnecessary coverage below T8; staged repairs",BODY)],
[Paragraph("Prior abdominal aortic surgery",BODY),
Paragraph("Recognise pre-existing collateral sacrifice; lower threshold for CSF drainage",BODY)],
[Paragraph("LSA coverage without revascularisation",BODY),
Paragraph("Revascularise LSA pre-emptively when possible",BODY)],
[Paragraph("Intraoperative hypotension",BODY),
Paragraph("Maintain MAP >90 mmHg during and after procedure",BODY)],
[Paragraph("CSF drainage",BODY),
Paragraph("Lumbar CSF drain: target CSF pressure <10 mmHg; reduces SCI risk in extended coverage cases",BODY)],
]
sci_tbl = Table(sci_data, colWidths=[5.5*cm, W-5.5*cm])
sci_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),C_ORANGE),("TEXTCOLOR",(0,0),(-1,0),C_WHITE),
("ROWBACKGROUNDS",(0,1),(-1,-1),[C_LIGHT_ORG,C_WHITE]),
("BOX",(0,0),(-1,-1),1,C_ORANGE),("INNERGRID",(0,0),(-1,-1),0.4,C_GREY),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),6),("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(sci_tbl)
story.append(Spacer(1,8))
# TEVAR complications
story.append(sec_hdr("TEVAR COMPLICATIONS SUMMARY", bg=C_PURPLE))
story.append(Spacer(1,4))
comp_tevar = [
[Paragraph("<b>Complication</b>",SBOLD), Paragraph("<b>Rate</b>",SBOLD), Paragraph("<b>Management</b>",SBOLD)],
[Paragraph("Stroke",BODY), Paragraph("3-5%",BODY), Paragraph("Higher if Zone 2 without LSA revascularisation; carotid-subclavian bypass",BODY)],
[Paragraph("Spinal cord ischaemia",BODY), Paragraph("3-8%",BODY), Paragraph("CSF drainage; MAP >90 mmHg; staged repair",BODY)],
[Paragraph("Endoleak (Type I)",BODY), Paragraph("5-10%",BODY), Paragraph("Type I requires re-intervention (cuff extension, balloon); Type II: observe",BODY)],
[Paragraph("Retrograde Type A dissection",BODY), Paragraph("~1-2%",BODY), Paragraph("Life-threatening; immediate emergency surgery",BODY)],
[Paragraph("Access site complications",BODY), Paragraph("2-5%",BODY), Paragraph("Haematoma, pseudoaneurysm, limb ischaemia",BODY)],
[Paragraph("Renal impairment",BODY), Paragraph("Varied",BODY), Paragraph("Contrast nephropathy; preserve renal arteries in coverage",BODY)],
[Paragraph("30-day mortality (complicated TBAD)",BODY), Paragraph("~8-10%",BODY), Paragraph("vs >30% for open surgery (IRAD)",BODY)],
]
comp_tevar_tbl = Table(comp_tevar, colWidths=[5*cm, 2.5*cm, W-7.5*cm])
comp_tevar_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),C_PURPLE),("TEXTCOLOR",(0,0),(-1,0),C_WHITE),
("ROWBACKGROUNDS",(0,1),(-1,-1),[C_LIGHT_PUR,C_WHITE]),
("BOX",(0,0),(-1,-1),1,C_PURPLE),("INNERGRID",(0,0),(-1,-1),0.4,C_GREY),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),5),("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(comp_tevar_tbl)
story.append(PageBreak())
# ── PAGE 8: LONG-TERM FOLLOW-UP + SUMMARY ────────────────────────────────────
story.append(sec_hdr("LONG-TERM FOLLOW-UP & SURVEILLANCE", bg=C_TEAL))
story.append(Spacer(1,6))
fu_data = [
[Paragraph("<b>Interval</b>",SBOLD), Paragraph("<b>Action</b>",SBOLD)],
[Paragraph("Pre-discharge",BODY), Paragraph("CT aortography (baseline post-repair)",BODY)],
[Paragraph("1 month",BODY), Paragraph("CT aortography; check BP control",BODY)],
[Paragraph("6 months",BODY), Paragraph("CT aortography; assess aortic diameter and false lumen status",BODY)],
[Paragraph("Annual (lifelong)",BODY), Paragraph("CT aortography; BP targets; beta-blocker compliance check",BODY)],
[Paragraph("Intervention threshold",BODY), Paragraph("Aortic diameter ≥55-60 mm OR growth ≥5 mm/year → consider TEVAR or open repair",BODY)],
[Paragraph("BP targets",BODY), Paragraph("SBP <130 mmHg lifelong; beta-blocker continued indefinitely (especially Marfan / genetic)",BODY)],
[Paragraph("Residual dissection (post Type A repair)",BODY), Paragraph("Persistent arch/descending dissection requires monitoring; delayed TEVAR if progression",BODY)],
]
fu_tbl = Table(fu_data, colWidths=[5*cm, W-5*cm])
fu_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),C_TEAL),("TEXTCOLOR",(0,0),(-1,0),C_WHITE),
("ROWBACKGROUNDS",(0,1),(-1,-1),[C_LIGHT_GRN,C_WHITE]),
("BOX",(0,0),(-1,-1),1,C_TEAL),("INNERGRID",(0,0),(-1,-1),0.4,C_GREY),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),6),("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(fu_tbl)
story.append(Spacer(1,10))
# Final key takeaways
summ_tbl = Table([
[Paragraph("<b>KEY CLINICAL TAKEAWAYS</b>",
ParagraphStyle("kt",fontName="Helvetica-Bold",fontSize=11,textColor=C_WHITE,alignment=TA_CENTER))],
[Paragraph(
"• Type A dissection = surgical emergency; mortality 1-2%/hr untreated; surgery goal: eliminate entry tear + obliterate ascending false lumen\n"
"• Type B dissection: 80% uncomplicated → medical; 20% complicated → TEVAR\n"
"• Anti-impulse therapy (esmolol/labetalol) is the cornerstone: target SBP 100-120 mmHg, HR <60 bpm\n"
"• NEVER use vasodilators alone — they increase aortic wall shear stress\n"
"• TEVAR: cover Zone 3 to Zone 5; IVUS mandatory to confirm true lumen access\n"
"• Always revascularise LSA before elective Zone 2 coverage\n"
"• PETTICOAT technique rescues persistent distal malperfusion after TEVAR\n"
"• Retrograde Type A dissection after TEVAR is rare (~1-2%) but immediately fatal without re-surgery\n"
"• INSTEAD-XL: 5-year aortic-related mortality benefit favours TEVAR even for uncomplicated TBAD\n"
"• Lifelong surveillance CT + beta-blocker in ALL patients; intervene at ≥55 mm or ≥5 mm growth/year",
BULLET)],
], colWidths=[W])
summ_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(0,0),C_NAVY),
("BACKGROUND",(0,1),(0,1),C_SKY),
("BOX",(0,0),(-1,-1),2,C_NAVY),
("TOPPADDING",(0,0),(-1,-1),8),("BOTTOMPADDING",(0,0),(-1,-1),8),
("LEFTPADDING",(0,0),(-1,-1),10),
]))
story.append(summ_tbl)
story.append(Spacer(1,6))
ref_tbl = Table([[Paragraph(
"References: Sabiston Textbook of Surgery — Biological Basis of Modern Surgical Practice | "
"Fuster & Hurst's The Heart 15e | Current Surgical Therapy 14e | "
"IRAD (International Registry of Acute Aortic Dissection) | "
"INSTEAD/INSTEAD-XL Trial | ADSORB Trial",
ParagraphStyle("ref",fontName="Helvetica-Oblique",fontSize=7.5,textColor=C_GREY,alignment=TA_CENTER)
)]], colWidths=[W])
story.append(ref_tbl)
# ── Build ─────────────────────────────────────────────────────────────────────
def later_pages(canvas, doc):
canvas.saveState()
canvas.setFont("Helvetica", 7.5)
canvas.setFillColor(C_GREY)
canvas.drawCentredString(A4[0]/2, 1.1*cm,
f"Modern Management of Aortic Dissection | Page {doc.page}")
canvas.restoreState()
doc.build(story, onFirstPage=later_pages, onLaterPages=later_pages)
print(f"Saved: {OUTPUT}")
cd /tmp/workspace/aortic-dissection-pdf && python3 generate.py 2>&1
ls -lh /tmp/workspace/aortic-dissection-pdf/Aortic_Dissection_Management.pdf
Aortic Dissection Management
PDF Document · PDF
| Page | Content |
|---|---|
| 1 | Title + Epidemiology + Stanford/DeBakey classification table with full textbook diagram (Sabiston, Fig. 102.1) |
| 2 | Risk factors + Investigations (CT/TEE/MRI/D-dimer comparison) + Anti-impulse drug table with doses |
| 3 | Type A flowchart (Emergency → Surgical candidate? → Steps 1-8) + Type A repair illustration |
| 4 | Frozen Elephant Trunk technique + Aortic regurgitation 3 mechanisms + Type A post-op complications |
| 5 | Type B algorithm flowchart (Complicated vs Uncomplicated) + Key trials (INSTEAD, INSTEAD-XL, ADSORB, IRAD) |
| 6 | TEVAR goals + Mitchell coverage zones table + 11-step TEVAR procedure |
| 7 | LSA management + PETTICOAT technique + SCI prevention + TEVAR complications table |
| 8 | Long-term surveillance schedule + 10-point key clinical takeaways summary |
Recent advances in intestinal transplantation - definition , indications procedure and steps with images , immunosuppression Flowcharts Illustrative images Give in PDF
mkdir -p /tmp/workspace/intestinal-tx-pdf && cd /tmp/workspace/intestinal-tx-pdf && python3 -c " import urllib.request, os imgs = { 'full_multivisceral.png': 'https://cdn.orris.care/cdss_images/3e24006b711a378210565b8aa3eaaf2a5b4c81120af4aa2989761f7efc826381.png', 'modified_multivisceral.png': 'https://cdn.orris.care/cdss_images/22e0e085b9a6ec179f227404b40e30d6451d63f9697f008200eaeb9f6355f308.png', 'liver_small_bowel.png': 'https://cdn.orris.care/cdss_images/8f657d7ea2c55608d17877ddb2fb4af4ce370556661c3d01115040a0938234cf.png', 'small_bowel_colon.png': 'https://cdn.orris.care/cdss_images/1e630c09aeb71ebb4ed3c9d531b5ae11c6cb38dacfe8288c4666c202cbddc7e4.png', 'liver_intestine_graft.png': 'https://cdn.orris.care/cdss_images/64393ab4296ecf0b10db3abf7ddba14714f5714bc615a0db71e86172e24010a9.png', 'volume_graph.png': 'https://cdn.orris.care/cdss_images/39a781f3b753b2884868f5b22751c5333f585763897f52e1bcb119d491229deb.png', } for fn, url in imgs.items(): try: urllib.request.urlretrieve(url, fn) print(f'OK {fn}') except Exception as e: print(f'FAIL {fn}: {e}') "
~/intestinal-tx-pdf/gen.py
import os
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
PageBreak, Image
)
from reportlab.graphics.shapes import Drawing, Line, Polygon, Rect
# ── Palette ────────────────────────────────────────────────────────────────────
C_NAVY = colors.HexColor("#0b2341")
C_DBLUE = colors.HexColor("#1a3a5c")
C_MBLUE = colors.HexColor("#2e6da4")
C_LBLUE = colors.HexColor("#d6eaf8")
C_SKY = colors.HexColor("#ebf5fb")
C_RED = colors.HexColor("#c0392b")
C_ORANGE = colors.HexColor("#d35400")
C_GREEN = colors.HexColor("#1e8449")
C_TEAL = colors.HexColor("#117a65")
C_PURPLE = colors.HexColor("#7d3c98")
C_YELLOW = colors.HexColor("#b7950b")
C_MAROON = colors.HexColor("#6e2c00")
C_LRED = colors.HexColor("#fadbd8")
C_LORG = colors.HexColor("#fdebd0")
C_LGRN = colors.HexColor("#d5f5e3")
C_LPUR = colors.HexColor("#e8daef")
C_LYELL = colors.HexColor("#fef9e7")
C_LGREY = colors.HexColor("#f2f3f4")
C_GREY = colors.HexColor("#7f8c8d")
C_WHITE = colors.white
C_BLACK = colors.black
W = A4[0] - 3*cm
OUTPUT = "/tmp/workspace/intestinal-tx-pdf/Intestinal_Transplantation.pdf"
doc = SimpleDocTemplate(OUTPUT, pagesize=A4,
leftMargin=1.5*cm, rightMargin=1.5*cm,
topMargin=1.8*cm, bottomMargin=1.8*cm,
title="Intestinal Transplantation – Comprehensive Reference")
# ── Styles ─────────────────────────────────────────────────────────────────────
S = lambda **kw: ParagraphStyle("_", **kw)
TI = S(fontName="Helvetica-Bold", fontSize=22, textColor=C_WHITE, alignment=TA_CENTER, leading=28)
TI2 = S(fontName="Helvetica-Bold", fontSize=15, textColor=colors.HexColor("#f9ca24"), alignment=TA_CENTER, leading=20)
TI3 = S(fontName="Helvetica-Oblique",fontSize=11, textColor=colors.HexColor("#aed6f1"), alignment=TA_CENTER)
SRC = S(fontName="Helvetica", fontSize=7.5,textColor=C_GREY, alignment=TA_CENTER)
H2 = S(fontName="Helvetica-Bold", fontSize=11, textColor=C_WHITE, alignment=TA_LEFT, leading=15)
H3 = S(fontName="Helvetica-Bold", fontSize=10, textColor=C_DBLUE, spaceBefore=4, spaceAfter=3)
BD = S(fontName="Helvetica", fontSize=9, textColor=C_BLACK, leading=13, spaceAfter=3, alignment=TA_JUSTIFY)
BS = S(fontName="Helvetica", fontSize=8.5,textColor=C_BLACK, leading=12, spaceAfter=2)
BL = S(fontName="Helvetica", fontSize=8.5,textColor=C_BLACK, leading=12, leftIndent=10, spaceAfter=2)
SB = S(fontName="Helvetica-Bold", fontSize=8.5,textColor=C_DBLUE, spaceAfter=2)
CAP = S(fontName="Helvetica-Oblique",fontSize=7.5,textColor=C_GREY, alignment=TA_CENTER, spaceAfter=4)
WRN = S(fontName="Helvetica-Bold", fontSize=9, textColor=C_RED, spaceAfter=3)
def shdr(text, bg=C_DBLUE):
p = Paragraph(f"<font name='Helvetica-Bold' size='11' color='white'>{text}</font>",
S(alignment=TA_LEFT, leading=14))
t = Table([[p]], colWidths=[W])
t.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),bg),
("TOPPADDING",(0,0),(-1,-1),6),("BOTTOMPADDING",(0,0),(-1,-1),6),
("LEFTPADDING",(0,0),(-1,-1),10)]))
return t
def arr():
d = Drawing(W, 14); m = W/2
d.add(Line(m,14,m,0, strokeColor=C_MBLUE, strokeWidth=1.8))
d.add(Polygon([m-5,4,m+5,4,m,0], fillColor=C_MBLUE, strokeColor=C_MBLUE))
return d
def fnode(text, fill, col_w=None, fsize=9.5):
cw = col_w or W*0.75
p = Paragraph(f"<font name='Helvetica-Bold' size='{fsize}' color='white'>{text}</font>",
S(alignment=TA_CENTER, leading=13))
t = Table([[p]], colWidths=[cw])
t.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),fill),("BOX",(0,0),(-1,-1),1.5,fill),
("TOPPADDING",(0,0),(-1,-1),6),("BOTTOMPADDING",(0,0),(-1,-1),6)]))
return Table([[t]], colWidths=[W], style=[("ALIGN",(0,0),(-1,-1),"CENTER")])
def img(fn, w=None, h=None):
if not os.path.exists(fn): return Spacer(1,4)
iw = w or W*0.88; ih = h or 7*cm
i = Image(fn, width=iw, height=ih); i.hAlign="CENTER"; return i
story = []
# ══════════════════════════════════════════════════════════════════════
# PAGE 1 – TITLE + EPIDEMIOLOGY + VOLUME GRAPH
# ══════════════════════════════════════════════════════════════════════
title_tbl = Table([
[Paragraph("INTESTINAL TRANSPLANTATION", TI)],
[Paragraph("Definition · Types · Indications · Procedure · Immunosuppression · Complications", TI2)],
[Paragraph("Recent Advances & Clinical Guidelines", TI3)],
[Spacer(1,4)],
[Paragraph("Sources: Sabiston Textbook of Surgery · Bailey & Love's Surgery 28e · Fischer's Mastery of Surgery 8e · Sleisenger & Fordtran's GI Disease", SRC)],
], colWidths=[W])
title_tbl.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),C_NAVY),
("TOPPADDING",(0,0),(-1,-1),8),("BOTTOMPADDING",(0,0),(-1,-1),8),("LEFTPADDING",(0,0),(-1,-1),10)]))
story.append(title_tbl); story.append(Spacer(1,8))
# Definition box
def_tbl = Table([[
Paragraph("<b>DEFINITION:</b> Intestinal transplantation (ITx) is the surgical procedure of transplanting a donor small intestine "
"(and optionally colon, liver, stomach, and pancreas) into a recipient with irreversible intestinal failure who cannot "
"survive or maintain quality of life on parenteral nutrition (PN). The graft must achieve <i>enteral autonomy</i> — "
"the ability to sustain the recipient nutritionally through oral/enteral feeding without PN.", BS)
]], colWidths=[W])
def_tbl.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),C_LBLUE),("BOX",(0,0),(-1,-1),1.5,C_MBLUE),
("TOPPADDING",(0,0),(-1,-1),7),("BOTTOMPADDING",(0,0),(-1,-1),7),("LEFTPADDING",(0,0),(-1,-1),10)]))
story.append(def_tbl); story.append(Spacer(1,8))
story.append(shdr("HISTORICAL MILESTONES & VOLUME TRENDS"))
story.append(Spacer(1,6))
hist = [
["1966","First intestine-containing transplant (short duodenal segment with pancreas); no long-term survival"],
["1988","First 'successful' intestine-containing transplant reported"],
["Early 1990s","Introduction of tacrolimus (FK-506) — transformed outcomes; rejection now manageable"],
["1996","International Intestinal Transplant Registry (ITR) established; 180 transplants in 25 centres"],
["2001 / 2015","International Small Bowel Transplant Symposia formalised indications"],
["2007","Peak volume: ~200 intestinal transplants/year in the USA (UNOS data)"],
["2014","FDA approves Pleximmune — first cell-based rejection test for paediatric ITx"],
["2019","ITR reports >4100 transplants performed worldwide; >50 active centres"],
["2023","~82 procedures/year in USA; adults now outnumber paediatric patients on waitlist"],
]
for row in hist:
story.append(Table([[
Paragraph(f"<b>{row[0]}</b>", SB),
Paragraph(row[1], BS)
]], colWidths=[2.2*cm, W-2.2*cm], style=[
("BACKGROUND",(0,0),(-1,-1),C_LGREY),("BOX",(0,0),(-1,-1),0.5,C_GREY),
("TOPPADDING",(0,0),(-1,-1),3),("BOTTOMPADDING",(0,0),(-1,-1),3),
("LEFTPADDING",(0,0),(-1,-1),5),("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(Spacer(1,1))
story.append(Spacer(1,6))
story.append(img("volume_graph.png", W*0.85, 4.5*cm))
story.append(Paragraph("FIGURE 56.1 — Number of intestinal transplants performed annually in the United States 1990–2023. "
"Peak in 2007; decline after improved intestinal rehabilitation for paediatric patients. "
"(Sabiston Textbook of Surgery, from UNOS data)", CAP))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════
# PAGE 2 – INDICATIONS FLOWCHART
# ══════════════════════════════════════════════════════════════════════
story.append(shdr("INDICATIONS FOR INTESTINAL TRANSPLANTATION — DECISION FLOWCHART", bg=C_GREEN))
story.append(Spacer(1,8))
story.append(fnode("PATIENT WITH INTESTINAL FAILURE", C_NAVY, fsize=11))
story.append(arr())
story.append(fnode("Is intestinal failure IRREVERSIBLE? (failed/impossible intestinal rehabilitation)", C_DBLUE))
story.append(Spacer(1,4))
# Two branches
no_br = Table([[Paragraph("<b>NO</b>\nContinue intestinal rehabilitation\nPN support + optimisation",
S(fontName="Helvetica-Bold",fontSize=8.5,textColor=C_WHITE,alignment=TA_CENTER,leading=12))]],
colWidths=[W*0.37])
no_br.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),C_GREY),("BOX",(0,0),(-1,-1),1,C_GREY),
("TOPPADDING",(0,0),(-1,-1),7),("BOTTOMPADDING",(0,0),(-1,-1),7)]))
yes_br = Table([[Paragraph("<b>YES — Irreversible intestinal failure</b>\nConsider transplantation assessment",
S(fontName="Helvetica-Bold",fontSize=8.5,textColor=C_WHITE,alignment=TA_CENTER,leading=12))]],
colWidths=[W*0.55])
yes_br.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),C_GREEN),("BOX",(0,0),(-1,-1),1,C_GREEN),
("TOPPADDING",(0,0),(-1,-1),7),("BOTTOMPADDING",(0,0),(-1,-1),7)]))
story.append(Table([[no_br,"",yes_br]], colWidths=[W*0.37,W*0.08,W*0.55]))
story.append(Spacer(1,6)); story.append(arr())
# Indication categories
story.append(fnode("FORMAL INDICATIONS (≥1 required)", C_DBLUE, fsize=10))
story.append(Spacer(1,4))
ind_data = [
[Paragraph("<b>Category</b>",SB), Paragraph("<b>Specific Indication</b>",SB), Paragraph("<b>Notes</b>",SB)],
[Paragraph("1. PN Complications",BD),
Paragraph("Intestinal failure-associated liver disease (IFALD) — progressive or advanced",BD),
Paragraph("Biochemistry + biopsy; combined ITx+liver if portal HTN or advanced fibrosis",BD)],
[Paragraph("",BD),
Paragraph("Severe sepsis — ≥2 life-threatening catheter-related sepsis episodes (endocarditis / metastatic infection)",BD),
Paragraph("Most common indication. No remediable cause.",BD)],
[Paragraph("",BD),
Paragraph("Limited central venous access — ≤3 major sites adults / ≤2 sites (above diaphragm) in children",BD),
Paragraph("CVC sites = IJV, subclavian, femoral",BD)],
[Paragraph("2. Quality of Life",BD),
Paragraph("Severe fluid/electrolyte disturbances; frequent hospitalisation; very poor QoL on PN",BD),
Paragraph("Increasingly accepted; controversial",BD)],
[Paragraph("3. Surgical Necessity",BD),
Paragraph("Abdominal tumours requiring extensive evisceration (desmoids, pseudomyxoma peritonei, neuroendocrine tumours)",BD),
Paragraph("Only if curative resection untenable without ITx",BD)],
[Paragraph("4. Diffuse Ischaemia",BD),
Paragraph("Acute widespread splanchnic ischaemia (arterial + venous); acute abdominal catastrophes",BD),
Paragraph("Rare; super-urgent listing",BD)],
[Paragraph("5. Technical Indication",BD),
Paragraph("Diffuse portomesenteric thrombosis (Yerdel grade 4) — multivisceral only option for definitive treatment",BD),
Paragraph("Replaces entire portal system",BD)],
[Paragraph("6. Re-transplantation",BD),
Paragraph("Failed primary intestinal transplant",BD),
Paragraph("8% of ITx in both adults and paediatric (ITR data)",BD)],
]
ind_tbl = Table(ind_data, colWidths=[3.5*cm, 8.5*cm, W-12*cm])
ind_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),C_GREEN),("TEXTCOLOR",(0,0),(-1,0),C_WHITE),
("ROWBACKGROUNDS",(0,1),(-1,-1),[C_LGRN,C_WHITE]),
("BOX",(0,0),(-1,-1),1,C_GREEN),("INNERGRID",(0,0),(-1,-1),0.4,C_GREY),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),5),("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(ind_tbl); story.append(Spacer(1,8))
# Underlying diseases table
story.append(shdr("UNDERLYING DISEASES REQUIRING TRANSPLANTATION (ITR Data)"))
story.append(Spacer(1,4))
dis_data = [
[Paragraph("<b>Paediatric</b>",SB), Paragraph("<b>%</b>",SB), Paragraph("<b>Adult</b>",SB), Paragraph("<b>%</b>",SB)],
[Paragraph("Short bowel syndrome",BD), Paragraph("63",BD), Paragraph("Short bowel syndrome",BD), Paragraph("64",BD)],
[Paragraph("Gastroschisis",BD), Paragraph("22",BD), Paragraph("Ischaemia",BD), Paragraph("11",BD)],
[Paragraph("Volvulus",BD), Paragraph("16",BD), Paragraph("Crohn disease",BD), Paragraph("10",BD)],
[Paragraph("Necrotising enterocolitis",BD), Paragraph("14",BD), Paragraph("Volvulus",BD), Paragraph("7",BD)],
[Paragraph("Motility disorders",BD), Paragraph("18",BD), Paragraph("Trauma",BD), Paragraph("7",BD)],
[Paragraph("Malabsorption syndromes",BD), Paragraph("8",BD), Paragraph("Motility disorders",BD), Paragraph("11",BD)],
[Paragraph("Re-transplantation",BD), Paragraph("8",BD), Paragraph("Re-transplantation",BD), Paragraph("7",BD)],
]
dis_tbl = Table(dis_data, colWidths=[6.5*cm, 1.5*cm, 6.5*cm, 1.5*cm])
dis_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),C_DBLUE),("TEXTCOLOR",(0,0),(-1,0),C_WHITE),
("ROWBACKGROUNDS",(0,1),(-1,-1),[C_LBLUE,C_WHITE]),
("BOX",(0,0),(-1,-1),1,C_MBLUE),("INNERGRID",(0,0),(-1,-1),0.4,C_GREY),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),5),("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(dis_tbl)
story.append(Paragraph("Source: Sabiston Textbook of Surgery, Table 56.1 (ITR Registry data)", CAP))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════
# PAGE 3 – TYPES OF TRANSPLANT + DIAGRAMS
# ══════════════════════════════════════════════════════════════════════
story.append(shdr("TYPES OF INTESTINAL TRANSPLANT — 'CLUSTER' TRANSPLANTS"))
story.append(Spacer(1,6))
types_data = [
[Paragraph("<b>Type</b>",SB), Paragraph("<b>Organs Included</b>",SB),
Paragraph("<b>Recipient Resection</b>",SB), Paragraph("<b>Proximal Anastomosis</b>",SB)],
[Paragraph("Isolated small bowel + colon",BD),
Paragraph("Small intestine ± colon (± pancreas)",BD),
Paragraph("Small intestine + part of colon",BD),
Paragraph("Duodenum or proximal jejunum",BD)],
[Paragraph("Modified multivisceral",BD),
Paragraph("Stomach, pancreas, small intestine, colon",BD),
Paragraph("Stomach, pancreas, spleen, small intestine + part of colon",BD),
Paragraph("Proximal stomach or oesophagus",BD)],
[Paragraph("Liver + small bowel",BD),
Paragraph("Liver, pancreas, small intestine, colon",BD),
Paragraph("Liver, small intestine + part of colon",BD),
Paragraph("Duodenum or proximal jejunum",BD)],
[Paragraph("Full multivisceral",BD),
Paragraph("Liver, stomach, pancreas, small intestine, colon",BD),
Paragraph("Liver, stomach, pancreas, spleen, small intestine + part of colon",BD),
Paragraph("Proximal stomach or oesophagus",BD)],
]
types_tbl = Table(types_data, colWidths=[3.8*cm, 4.8*cm, 5.5*cm, W-14.1*cm])
types_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),C_DBLUE),("TEXTCOLOR",(0,0),(-1,0),C_WHITE),
("BACKGROUND",(0,1),(-1,1),C_LGREY),
("BACKGROUND",(0,2),(-1,2),C_LPUR),
("BACKGROUND",(0,3),(-1,3),C_LGRN),
("BACKGROUND",(0,4),(-1,4),C_LRED),
("BOX",(0,0),(-1,-1),1,C_DBLUE),("INNERGRID",(0,0),(-1,-1),0.4,C_GREY),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),5),("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(types_tbl); story.append(Spacer(1,10))
# 4 type diagrams side by side in 2x2
def mini_img(fn, caption, w=W*0.47, h=7.5*cm):
if not os.path.exists(fn): return ["",caption]
i = Image(fn, width=w, height=h); i.hAlign="CENTER"
return [i, Paragraph(caption, CAP)]
img1 = mini_img("full_multivisceral.png", "Full Multivisceral Transplant\n(Liver + Stomach + Pancreas + Small Intestine + Colon)")
img2 = mini_img("modified_multivisceral.png", "Modified Multivisceral Transplant\n(Stomach + Pancreas + Small Intestine + Colon; NO liver)")
img3 = mini_img("liver_small_bowel.png", "Liver + Small Bowel Transplant\n(Liver + Pancreas + Small Intestine + Colon)")
img4 = mini_img("small_bowel_colon.png", "Small Bowel + Pancreas + Colon Transplant\n(Hepatic artery, SMA, portal vein, ileocolic artery labelled)")
story.append(Table([[img1[0],"",img2[0]], [img1[1],"",img2[1]]],
colWidths=[W*0.47, W*0.06, W*0.47],
style=[("ALIGN",(0,0),(-1,-1),"CENTER"),("VALIGN",(0,0),(-1,-1),"TOP")]))
story.append(Spacer(1,8))
story.append(Table([[img3[0],"",img4[0]], [img3[1],"",img4[1]]],
colWidths=[W*0.47, W*0.06, W*0.47],
style=[("ALIGN",(0,0),(-1,-1),"CENTER"),("VALIGN",(0,0),(-1,-1),"TOP")]))
story.append(Paragraph("Figure 91.1 — Types of intestinal transplant. SMA = superior mesenteric artery. "
"Bailey & Love's Short Practice of Surgery 28e", CAP))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════
# PAGE 4 – DONOR OPERATION + RECIPIENT PROCEDURE STEPS
# ══════════════════════════════════════════════════════════════════════
story.append(shdr("SURGICAL PROCEDURE — DONOR OPERATION", bg=C_ORANGE))
story.append(Spacer(1,6))
donor_steps = [
("1. Donor Selection", "Brain-dead or DCD donor. ABO-compatible. No absolute size limit but size-matching preferred (±20%). CMV status noted."),
("2. Vascular Flush", "Cold UW (University of Wisconsin) solution or HTK (histidine-tryptophan-ketoglutarate) perfusion via aorta. Target cold ischaemia time: <8-10 hours."),
("3. En Bloc Dissection", "Liver, stomach, pancreas, duodenum, small intestine, colon mobilised as a unit with their vascular pedicles."),
("4. Arterial Preparation", "Donor coeliac axis and SMA left on an aortic patch (Carrel patch) or reconstructed on a common conduit (donor thoracic aorta as conduit for supracoeliac placement)."),
("5. Venous Outflow", "Portal vein preserved. Hepatic veins used if liver included. For isolated intestine: SMV or portal vein used for venous anastomosis."),
("6. Bowel Preparation", "Non-absorbable antibiotics for bowel decontamination. Some protocols use mechanical bowel prep."),
("7. Cold Storage", "Graft flushed and stored in 4°C preservation solution. Minimise cold ischaemia time to reduce ischaemia-reperfusion injury."),
]
for step, desc in donor_steps:
r = Table([[
Table([[Paragraph(f"<font name='Helvetica-Bold' size='8.5' color='white'>{step}</font>",
S(alignment=TA_CENTER,leading=12))]],
colWidths=[4.5*cm],
style=[("BACKGROUND",(0,0),(-1,-1),C_ORANGE),("TOPPADDING",(0,0),(-1,-1),4),
("BOTTOMPADDING",(0,0),(-1,-1),4),("BOX",(0,0),(-1,-1),1,C_ORANGE)]),
Paragraph(desc, BS)
]], colWidths=[4.5*cm, W-5*cm])
r.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),C_LGREY),("BOX",(0,0),(-1,-1),0.5,C_GREY),
("TOPPADDING",(0,0),(-1,-1),3),("BOTTOMPADDING",(0,0),(-1,-1),3),
("LEFTPADDING",(0,0),(-1,-1),4),("VALIGN",(0,0),(-1,-1),"MIDDLE")]))
story.append(r); story.append(Spacer(1,2))
story.append(Spacer(1,8))
story.append(shdr("SURGICAL PROCEDURE — RECIPIENT OPERATION", bg=C_RED))
story.append(Spacer(1,6))
recip_steps = [
("1. Native Visceral Evisceration", "Diseased small intestine (and other diseased organs per type of transplant) removed. For full/modified multivisceral: stomach, pancreas, spleen, liver resected. Preserve recipient native duodenum if possible for proximal reconstruction."),
("2. Vascular Anastomosis — Arterial", "Donor aortic conduit (Carrel patch or conduit) anastomosed to recipient infrarenal aorta (end-to-side). Alternatively: supracoeliac placement of donor thoracic aortic conduit for multivisceral grafts."),
("3. Vascular Anastomosis — Venous", "Donor portal/SMV to recipient IVC (portocaval shunt) — systemic drainage. OR: Donor portal vein to recipient portal vein — portal/physiological drainage (preferred when possible; maintains hepatic first-pass metabolism)."),
("4. Portocaval Shunt (if needed)", "When recipient native foregut (stomach, pancreas, duodenum) is retained: portocaval or splenorenal shunt required to prevent foregut venous hypertension and varices."),
("5. Graft Reperfusion", "Venous clamp released first, then arterial. Inspect bowel for colour, peristalsis, bleeding. Warm ischaemia time tracked."),
("6. Proximal Enteric Anastomosis", "Isolated/SB graft: duodenojejunostomy or proximal jejuno-jejunostomy. Modified multivisceral: gastrogastrostomy or oesophagogastrostomy. Depends on native remnant anatomy."),
("7. Distal Enteric Anastomosis", "Ileum (or colon if included) anastomosed to recipient native transverse colon or terminal ileum remnant."),
("8. Ileostomy Creation (mandatory)", "A loop ileostomy (or end ileostomy from the distal graft) is created to allow repeated endoscopic access for surveillance biopsies and monitoring of graft mucosa. Critical for post-transplant management."),
("9. Abdominal Closure", "Primary closure if feasible. Mesh or staged closure may be necessary for large-volume multivisceral grafts or abdominal domain issues. Use of an abdominal wall transplant is reported in selected cases."),
]
for step, desc in recip_steps:
r = Table([[
Table([[Paragraph(f"<font name='Helvetica-Bold' size='8.5' color='white'>{step}</font>",
S(alignment=TA_CENTER,leading=12))]],
colWidths=[4.5*cm],
style=[("BACKGROUND",(0,0),(-1,-1),C_RED),("TOPPADDING",(0,0),(-1,-1),4),
("BOTTOMPADDING",(0,0),(-1,-1),4),("BOX",(0,0),(-1,-1),1,C_RED)]),
Paragraph(desc, BS)
]], colWidths=[4.5*cm, W-5*cm])
r.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),C_LGREY),("BOX",(0,0),(-1,-1),0.5,C_GREY),
("TOPPADDING",(0,0),(-1,-1),3),("BOTTOMPADDING",(0,0),(-1,-1),3),
("LEFTPADDING",(0,0),(-1,-1),4),("VALIGN",(0,0),(-1,-1),"MIDDLE")]))
story.append(r); story.append(Spacer(1,2))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════
# PAGE 5 – GRAFT IMAGE + VASCULAR DIAGRAM
# ══════════════════════════════════════════════════════════════════════
story.append(shdr("ILLUSTRATIVE DIAGRAMS — GRAFT IMPLANTATION"))
story.append(Spacer(1,8))
story.append(img("liver_intestine_graft.png", W*0.9, 9*cm))
story.append(Paragraph(
"FIGURE 56.3 — Liver-intestine-pancreas transplant implantation. "
"(A) Donor coeliac axis and SMA on aortic conduit anastomosed to recipient infrarenal aorta. "
"Venous outflow through donor hepatic veins to recipient suprahepatic IVC. "
"Donor duodenum and pancreatic head preserved to maintain common bile duct. "
"(B) Supracoeliac placement of donor thoracic aortic conduit. "
"Sabiston Textbook of Surgery, Figure 56.3", CAP))
story.append(Spacer(1,10))
story.append(shdr("SMALL BOWEL GRAFT — VASCULAR ANATOMY"))
story.append(Spacer(1,6))
story.append(img("small_bowel_colon.png", W*0.65, 9*cm))
story.append(Paragraph(
"Small bowel, pancreas and colon transplant graft vascular anatomy. "
"Hepatic artery (blue), SMA (red), portal vein, middle colic artery, ileocolic artery labelled. "
"Bailey & Love's Surgery 28e, Figure 91.1", CAP))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════
# PAGE 6 – IMMUNOSUPPRESSION
# ══════════════════════════════════════════════════════════════════════
story.append(shdr("IMMUNOSUPPRESSION — RATIONALE & PROTOCOLS", bg=C_PURPLE))
story.append(Spacer(1,6))
# Why high IS needed
why_tbl = Table([[
Paragraph("<b>Why intestinal transplantation requires MORE immunosuppression than other solid organ transplants:</b><br/>"
"The intestine contains the largest amount of lymphoid tissue in the body — "
"<b>mucosal-associated lymphoid tissue (MALT)</b> and Peyer's patches — plus massive bacterial colonisation. "
"This makes the graft highly immunogenic. Acute cellular rejection (ACR) rates historically reached 70-85% "
"and remain the highest of any solid organ allograft. Without adequate immunosuppression, "
"rejection is frequent, severe, and potentially life-threatening.", BS)
]], colWidths=[W])
why_tbl.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),C_LPUR),("BOX",(0,0),(-1,-1),1.5,C_PURPLE),
("TOPPADDING",(0,0),(-1,-1),8),("BOTTOMPADDING",(0,0),(-1,-1),8),("LEFTPADDING",(0,0),(-1,-1),10)]))
story.append(why_tbl); story.append(Spacer(1,8))
story.append(shdr("PHASE 1 — INDUCTION IMMUNOSUPPRESSION (Peri-operative)", bg=C_PURPLE))
story.append(Spacer(1,4))
ind_is = [
[Paragraph("<b>Agent</b>",SB), Paragraph("<b>Class</b>",SB), Paragraph("<b>Mechanism</b>",SB),
Paragraph("<b>Notes</b>",SB)],
[Paragraph("Alemtuzumab (Campath)",BD), Paragraph("Anti-CD52 mAb (depleting)",BD),
Paragraph("Depletes T and B lymphocytes, NK cells, monocytes",BD),
Paragraph("Preferred in adult protocols; ~80% of ITx centres; reduces early rejection; associated with survival advantage (ITR)",BD)],
[Paragraph("Antithymocyte globulin (ATG/Thymoglobulin)",BD), Paragraph("Polyclonal anti-thymocyte (depleting)",BD),
Paragraph("Depletes T lymphocytes; induces apoptosis",BD),
Paragraph("Widely used alternative to alemtuzumab",BD)],
[Paragraph("Basiliximab (Simulect)",BD), Paragraph("Anti-CD25 mAb (non-depleting)",BD),
Paragraph("Blocks IL-2 receptor on activated T cells",BD),
Paragraph("Preferred in paediatric protocols; lower infection risk",BD)],
[Paragraph("Daclizumab",BD), Paragraph("Anti-CD25 mAb (non-depleting)",BD),
Paragraph("Blocks IL-2Rα (CD25)",BD),
Paragraph("Historical; less used now",BD)],
]
ind_is_tbl = Table(ind_is, colWidths=[3.8*cm, 3.5*cm, 4.5*cm, W-11.8*cm])
ind_is_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),C_PURPLE),("TEXTCOLOR",(0,0),(-1,0),C_WHITE),
("ROWBACKGROUNDS",(0,1),(-1,-1),[C_LPUR,C_WHITE]),
("BOX",(0,0),(-1,-1),1,C_PURPLE),("INNERGRID",(0,0),(-1,-1),0.4,C_GREY),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),5),("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(ind_is_tbl); story.append(Spacer(1,8))
story.append(shdr("PHASE 2 — MAINTENANCE IMMUNOSUPPRESSION", bg=C_DBLUE))
story.append(Spacer(1,4))
maint_is = [
[Paragraph("<b>Drug</b>",SB), Paragraph("<b>Class</b>",SB), Paragraph("<b>Mechanism</b>",SB),
Paragraph("<b>Target level/Dose</b>",SB), Paragraph("<b>Key Notes</b>",SB)],
[Paragraph("Tacrolimus (FK-506, Prograf)",BD), Paragraph("Calcineurin inhibitor (CNI)",BD),
Paragraph("Blocks calcineurin → inhibits IL-2 transcription → T-cell activation blocked",BD),
Paragraph("Trough 10-20 ng/mL early; 5-15 ng/mL maintenance",BD),
Paragraph("BACKBONE of maintenance IS. Higher levels needed than other solid organs. Nephrotoxic.",BD)],
[Paragraph("Mycophenolate mofetil (MMF, CellCept)",BD), Paragraph("Antimetabolite",BD),
Paragraph("Inhibits IMPDH → blocks de novo purine synthesis → inhibits lymphocyte proliferation",BD),
Paragraph("1-3g/day in divided doses",BD),
Paragraph("Added to tacrolimus. Risk of enterocolitis (can mimic ACR on histology)",BD)],
[Paragraph("Prednisolone / methylprednisolone",BD), Paragraph("Corticosteroid",BD),
Paragraph("Broad anti-inflammatory; blocks NF-κB; reduces cytokine production",BD),
Paragraph("Tapered over months",BD),
Paragraph("Still widely used despite long-term side effects. Steroid-avoidance protocols reported.",BD)],
[Paragraph("Sirolimus (Rapamycin)",BD), Paragraph("mTOR inhibitor",BD),
Paragraph("Blocks mTOR → inhibits T-cell proliferation + cytokine signalling",BD),
Paragraph("Trough 5-15 ng/mL",BD),
Paragraph("Started ≥1 month post-op (avoid early wound complications). Alternative when tacrolimus toxicity occurs.",BD)],
[Paragraph("Everolimus",BD), Paragraph("mTOR inhibitor",BD),
Paragraph("Same as sirolimus; oral bioavailability improved",BD),
Paragraph("Trough 3-8 ng/mL",BD),
Paragraph("Sometimes added to maintenance regimen",BD)],
[Paragraph("Azathioprine",BD), Paragraph("Antimetabolite (older)",BD),
Paragraph("Inhibits purine synthesis; used in LIP protocol",BD),
Paragraph("1-2 mg/kg/day",BD),
Paragraph("Used in Leuven LIP protocol at low dose; rarely used as primary agent",BD)],
]
maint_tbl = Table(maint_is, colWidths=[3.5*cm, 3*cm, 4*cm, 3*cm, W-13.5*cm])
maint_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),C_DBLUE),("TEXTCOLOR",(0,0),(-1,0),C_WHITE),
("ROWBACKGROUNDS",(0,1),(-1,-1),[C_LBLUE,C_WHITE]),
("BOX",(0,0),(-1,-1),1,C_DBLUE),("INNERGRID",(0,0),(-1,-1),0.4,C_GREY),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),4),("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(maint_tbl); story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════
# PAGE 7 – NOVEL IS + REJECTION FLOWCHART
# ══════════════════════════════════════════════════════════════════════
story.append(shdr("NOVEL & EMERGING IMMUNOSUPPRESSION STRATEGIES", bg=C_TEAL))
story.append(Spacer(1,6))
novel_data = [
[Paragraph("<b>Agent / Strategy</b>",SB), Paragraph("<b>Target</b>",SB),
Paragraph("<b>Evidence / Status</b>",SB)],
[Paragraph("Vedolizumab (Entyvio)",BD),
Paragraph("Anti-α4β7 integrin — blocks gut-homing of lymphocytes",BD),
Paragraph("Emerging use for antibody-mediated rejection (AMR); gut-selective; reduces GI lymphocyte trafficking",BD)],
[Paragraph("Rituximab (anti-CD20)",BD),
Paragraph("Depletes B cells — targets AMR",BD),
Paragraph("Used in centres for donor-specific antibody (DSA)-mediated rejection; evidence accumulating",BD)],
[Paragraph("Infliximab (anti-TNFα)",BD),
Paragraph("Blocks TNF-α — anti-inflammatory",BD),
Paragraph("Used for refractory ACR; also reduces GVHD risk",BD)],
[Paragraph("Belatacept (Nulojix)",BD),
Paragraph("CTLA4-Ig — blocks CD80/86-CD28 costimulatory pathway",BD),
Paragraph("Limited use; used in tacrolimus nephrotoxicity; high rejection rate reported",BD)],
[Paragraph("Leuven Immunomodulatory Protocol (LIP)",BD),
Paragraph("Multifactorial tolerance-promoting strategy",BD),
Paragraph("5-year graft/patient survival 92%; 4/13 patients rejected (all steroid/ATG controlled); no DSA, GVHD or PTLD; no nephrotoxicity",BD)],
[Paragraph("Pleximmune (FDA approved 2014)",BD),
Paragraph("Cell-based rejection prediction test — CD154+ T-cytotoxic memory cells",BD),
Paragraph("Only FDA-approved test for ITx; predicts ACR in paediatric ITx; single lab (shipping required)",BD)],
[Paragraph("Donor-specific blood transfusion (DST)",BD),
Paragraph("Pro-tolerogenic regulatory T-cell promotion",BD),
Paragraph("Component of LIP; induces donor-specific tolerance",BD)],
]
novel_tbl = Table(novel_data, colWidths=[4*cm, 4.5*cm, W-8.5*cm])
novel_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),C_TEAL),("TEXTCOLOR",(0,0),(-1,0),C_WHITE),
("ROWBACKGROUNDS",(0,1),(-1,-1),[colors.HexColor("#d1f2eb"),C_WHITE]),
("BOX",(0,0),(-1,-1),1,C_TEAL),("INNERGRID",(0,0),(-1,-1),0.4,C_GREY),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),5),("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(novel_tbl); story.append(Spacer(1,8))
# LIP box
lip_tbl = Table([[
Paragraph("<b>Leuven Immunomodulatory Protocol (LIP) — Components:</b><br/>"
"1. Donor-specific blood transfusion (DST) pre-transplant<br/>"
"2. Depleting antibody induction (ATG)<br/>"
"3. Tacrolimus at LOWER-than-usual trough levels<br/>"
"4. Steroid taper (steroid avoidance)<br/>"
"5. Low-dose azathioprine<br/>"
"6. Minimise cold ischaemia time<br/>"
"7. Pre-operative bowel decontamination<br/>"
"→ 5-year graft + patient survival: <b>92%</b> | No GVHD | No PTLD | Low infection rates", BS)
]], colWidths=[W])
lip_tbl.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),colors.HexColor("#d1f2eb")),("BOX",(0,0),(-1,-1),2,C_TEAL),
("TOPPADDING",(0,0),(-1,-1),8),("BOTTOMPADDING",(0,0),(-1,-1),8),("LEFTPADDING",(0,0),(-1,-1),10)]))
story.append(lip_tbl); story.append(Spacer(1,8))
# Rejection flowchart
story.append(shdr("FLOWCHART — ACUTE CELLULAR REJECTION (ACR) DIAGNOSIS & MANAGEMENT", bg=C_RED))
story.append(Spacer(1,8))
story.append(fnode("SUSPECTED INTESTINAL GRAFT REJECTION", C_RED, fsize=10))
story.append(arr())
# Clinical features box
cf_tbl = Table([[
Paragraph("<b>Clinical Features of ACR:</b> Increased stoma output / diarrhoea | "
"Abdominal pain / distension | Fever | Nausea / vomiting | "
"Blood/mucus in stool | Graft ileus | Raised serum citrulline (falling)", BS)
]], colWidths=[W])
cf_tbl.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),C_LRED),("BOX",(0,0),(-1,-1),1.5,C_RED),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),("LEFTPADDING",(0,0),(-1,-1),8)]))
story.append(cf_tbl); story.append(arr())
story.append(fnode("ILEOSCOPY THROUGH ILEOSTOMY (Post-op days 5-7; then 1-2x/week for first 1-3 months)", C_DBLUE))
story.append(arr())
rej_grade = [
[Paragraph("<b>Grade</b>",SB), Paragraph("<b>Histology</b>",SB), Paragraph("<b>Treatment</b>",SB)],
[Paragraph("Indeterminate",BD), Paragraph("Minimal inflammation; cryptitis",BD),
Paragraph("Increase tacrolimus trough; close follow-up biopsies",BD)],
[Paragraph("Mild ACR",BD), Paragraph("Increased crypt apoptosis (>3/10 crypts); mild villous blunting",BD),
Paragraph("High-dose IV methylprednisolone 10 mg/kg/day × 3-5 days",BD)],
[Paragraph("Moderate ACR",BD), Paragraph("Confluent apoptosis; moderate villous blunting; mucosal erosions",BD),
Paragraph("High-dose steroids; add ATG if steroid-refractory",BD)],
[Paragraph("Severe ACR",BD), Paragraph("Diffuse ulceration; exfoliation; severe mucosal destruction",BD),
Paragraph("ATG; alemtuzumab; consider re-transplantation if no response",BD)],
[Paragraph("Antibody-mediated (AMR)",BD), Paragraph("C4d deposition; donor-specific antibodies (DSA)",BD),
Paragraph("Rituximab; IVIG; plasmapheresis; vedolizumab; infliximab",BD)],
]
rej_tbl = Table(rej_grade, colWidths=[2.8*cm, 6.5*cm, W-9.3*cm])
rej_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),C_RED),("TEXTCOLOR",(0,0),(-1,0),C_WHITE),
("BACKGROUND",(0,1),(-1,1),C_LGREY),
("BACKGROUND",(0,2),(-1,2),C_LRED),
("BACKGROUND",(0,3),(-1,3),colors.HexColor("#f5b7b1")),
("BACKGROUND",(0,4),(-1,4),colors.HexColor("#e74c3c")),
("TEXTCOLOR",(0,4),(-1,4),C_WHITE),
("BACKGROUND",(0,5),(-1,5),C_LPUR),
("BOX",(0,0),(-1,-1),1,C_RED),("INNERGRID",(0,0),(-1,-1),0.4,C_GREY),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),5),("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(rej_tbl)
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════
# PAGE 8 – COMPLICATIONS + OUTCOMES + SUMMARY
# ══════════════════════════════════════════════════════════════════════
story.append(shdr("COMPLICATIONS OF INTESTINAL TRANSPLANTATION", bg=C_MAROON))
story.append(Spacer(1,6))
comp_data = [
[Paragraph("<b>Category</b>",SB), Paragraph("<b>Complication</b>",SB),
Paragraph("<b>Incidence / Notes</b>",SB)],
[Paragraph("Surgical",BD), Paragraph("Bowel anastomotic leak; intestinal perforation; wound complications",BD),
Paragraph("Overall complication rate ~50%; immunosuppression masks signs",BD)],
[Paragraph("Vascular",BD), Paragraph("Arterial / venous thrombosis → sudden graft necrosis; post-op haemorrhage",BD),
Paragraph("Rare but catastrophic; coagulopathy from hepatic dysfunction amplifies bleeding",BD)],
[Paragraph("Rejection (ACR)",BD), Paragraph("Most common early complication; highest rate of any solid organ",BD),
Paragraph("ACR rates 70-85% historically; improved with tacrolimus + induction to ~40-50%",BD)],
[Paragraph("AMR",BD), Paragraph("Antibody-mediated rejection; donor-specific antibodies (DSA)",BD),
Paragraph("Emerging recognition; worse outcomes; novel targets (rituximab, vedolizumab)",BD)],
[Paragraph("GVHD",BD), Paragraph("Graft-versus-host disease — donor lymphocytes attack recipient",BD),
Paragraph("Rare but severe; skin, liver, bone marrow affected; LIP protocol reduces risk",BD)],
[Paragraph("Infection",BD), Paragraph("CMV enteritis; EBV-PTLD; bacterial/fungal line sepsis; C. difficile",BD),
Paragraph("Major cause of morbidity/mortality; CMV prophylaxis mandatory",BD)],
[Paragraph("PTLD",BD), Paragraph("Post-transplant lymphoproliferative disorder (EBV-driven)",BD),
Paragraph("Higher incidence than other solid organs; reduce IS; rituximab",BD)],
[Paragraph("Renal impairment",BD), Paragraph("Tacrolimus nephrotoxicity; acute kidney injury post-op",BD),
Paragraph("Particularly marked in multivisceral ITx; consider renal transplant if GFR <45 mL/min",BD)],
[Paragraph("Enteric leak",BD), Paragraph("Proximal anastomotic leak (esp. oesophagogastric)",BD),
Paragraph("EndoVac therapy for oesophageal leaks; aggressive radiological drainage",BD)],
[Paragraph("Nutritional",BD), Paragraph("Chylous ascites; electrolyte disturbances",BD),
Paragraph("MCT diet if enterally fed; PN modification",BD)],
]
comp_tbl = Table(comp_data, colWidths=[3*cm, 6*cm, W-9*cm])
comp_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),C_MAROON),("TEXTCOLOR",(0,0),(-1,0),C_WHITE),
("ROWBACKGROUNDS",(0,1),(-1,-1),[C_LGREY,C_WHITE]),
("BOX",(0,0),(-1,-1),1,C_MAROON),("INNERGRID",(0,0),(-1,-1),0.4,C_GREY),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),5),("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(comp_tbl); story.append(Spacer(1,8))
# Outcomes
story.append(shdr("OUTCOMES & SURVIVAL DATA"))
story.append(Spacer(1,4))
out_data = [
[Paragraph("<b>Measure</b>",SB), Paragraph("<b>Isolated ITx</b>",SB),
Paragraph("<b>Liver+Intestine</b>",SB), Paragraph("<b>Multivisceral</b>",SB)],
[Paragraph("1-year patient survival",BD), Paragraph("~77-80%",BD), Paragraph("~65-75%",BD), Paragraph("~70%",BD)],
[Paragraph("5-year patient survival",BD), Paragraph("~50-60%",BD), Paragraph("~45-55%",BD), Paragraph("~45%",BD)],
[Paragraph("Graft survival (5-yr)",BD), Paragraph("~40-50%",BD), Paragraph("~40-50%",BD), Paragraph("~40%",BD)],
[Paragraph("Enteral autonomy",BD), Paragraph("~60-70% achieve",BD), Paragraph("~60%",BD), Paragraph("~60%",BD)],
[Paragraph("LIP protocol (Leuven)",BD), Paragraph("<b>92% at 5 years</b>",BD), Paragraph("—",BD), Paragraph("—",BD)],
[Paragraph("Chronic 5-yr survival (paeds)",BD), Paragraph("90% at 6 yr (rehabilitation cohort)",BD), Paragraph("—",BD), Paragraph("—",BD)],
]
out_tbl = Table(out_data, colWidths=[4.5*cm, W*0.2, W*0.2, W*0.2])
out_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),C_DBLUE),("TEXTCOLOR",(0,0),(-1,0),C_WHITE),
("ROWBACKGROUNDS",(0,1),(-1,-1),[C_LBLUE,C_WHITE]),
("BOX",(0,0),(-1,-1),1,C_DBLUE),("INNERGRID",(0,0),(-1,-1),0.4,C_GREY),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),5),("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story.append(out_tbl); story.append(Spacer(1,10))
# Summary box
summ_tbl = Table([
[Paragraph("<b>KEY TAKEAWAYS</b>",S(fontName="Helvetica-Bold",fontSize=11,textColor=C_WHITE,alignment=TA_CENTER))],
[Paragraph(
"• Intestinal transplantation is the only curative treatment for irreversible intestinal failure in patients failing or unable to tolerate PN\n"
"• Tacrolimus + depletional induction (alemtuzumab/ATG) are the cornerstones of IS; used in ~80% of cases\n"
"• The intestine is the most immunogenic solid organ allograft — rejection rates remain highest of any organ\n"
"• Ileoscopy through the stoma with biopsy is the gold-standard monitoring tool (begin day 5-7 post-op)\n"
"• Novel strategies: vedolizumab (AMR), rituximab (AMR), infliximab (refractory ACR), LIP protocol (tolerance induction)\n"
"• Pleximmune (FDA 2014): first approved test to predict ACR in paediatric ITx\n"
"• Leuven LIP protocol achieves 92% 5-year survival — most promising advance in IS optimisation\n"
"• Overall 5-year survival ~50%; long-term outcomes inferior to other solid organs but improving\n"
"• Key complications: ACR, AMR, CMV/EBV, PTLD, GVHD, vascular thrombosis, anastomotic leak\n"
"• Improve outcomes by: minimising cold ischaemia, bowel decontamination, early enteral feeding, multidisciplinary care",
BL)],
], colWidths=[W])
summ_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(0,0),C_NAVY),
("BACKGROUND",(0,1),(0,1),C_SKY),
("BOX",(0,0),(-1,-1),2,C_NAVY),
("TOPPADDING",(0,0),(-1,-1),8),("BOTTOMPADDING",(0,0),(-1,-1),8),("LEFTPADDING",(0,0),(-1,-1),10),
]))
story.append(summ_tbl); story.append(Spacer(1,6))
story.append(Paragraph(
"References: Sabiston Textbook of Surgery | Bailey & Love's Short Practice of Surgery 28e | "
"Fischer's Mastery of Surgery 8e | International Intestinal Transplant Registry (ITR) | "
"Sleisenger & Fordtran's Gastrointestinal & Liver Disease | UNOS/OPTN data",
S(fontName="Helvetica-Oblique",fontSize=7.5,textColor=C_GREY,alignment=TA_CENTER)))
# ── Build ──────────────────────────────────────────────────────────────
def on_page(canvas, doc):
canvas.saveState()
canvas.setFont("Helvetica", 7.5)
canvas.setFillColor(C_GREY)
canvas.drawCentredString(A4[0]/2, 1.1*cm, f"Intestinal Transplantation — Comprehensive Reference | Page {doc.page}")
canvas.restoreState()
doc.build(story, onFirstPage=on_page, onLaterPages=on_page)
print(f"Saved: {OUTPUT}")
cd /tmp/workspace/intestinal-tx-pdf && python3 gen.py 2>&1
ls -lh /tmp/workspace/intestinal-tx-pdf/Intestinal_Transplantation.pdf
Intestinal Transplantation
PDF Document · PDF
| Page | Content |
|---|---|
| 1 | Title banner + Definition box + Historical milestones timeline (1966-2023) + UNOS volume trend graph (1990-2023) |
| 2 | Indications decision flowchart (Irreversible failure → formal criteria) + All 6 indications table + ITR underlying disease data (paediatric vs adult) |
| 3 | Types of transplant — cluster transplant table + All 4 type diagrams side by side from Bailey & Love (Full multivisceral, Modified multivisceral, Liver+small bowel, Small bowel+pancreas+colon) |
| 4 | Donor operation steps (7 steps) + Recipient operation steps (9 steps including ileostomy creation) |
| 5 | Liver-intestine-pancreas graft implantation diagram (Sabiston Fig 56.3 — infra/supracoeliac conduit placement) + Vascular anatomy of small bowel graft (SMA, hepatic artery, portal vein, ileocolic artery labelled) |
| 6 | Why intestine requires more IS (MALT rationale) + Induction IS table (alemtuzumab, ATG, basiliximab) + Maintenance IS table (tacrolimus, MMF, steroids, sirolimus, everolimus, azathioprine) |
| 7 | Novel/emerging IS strategies (vedolizumab, rituximab, infliximab, belatacept, LIP protocol, Pleximmune) + LIP protocol components box + ACR diagnosis & management flowchart (grading + treatment by severity) |
| 8 | Complications table (surgical, vascular, rejection, AMR, GVHD, PTLD, infection, renal) + Survival outcomes table + 10-point key clinical takeaways |
Recent advances in intestinal transplantation - definition , indications procedure and steps with images , immunosuppression Flowcharts Illustrative images Give in PDF
Intestinal Transplantation
PDF Document · PDF
| Page | Content |
|---|---|
| 1 | Definition box + Historical milestones timeline (1966–2023) + UNOS annual volume trend graph |
| 2 | Indications decision flowchart + All 6 formal indications table + Underlying diseases (paediatric vs adult, ITR data) |
| 3 | Types of transplant table + 4 textbook diagrams side by side — Full multivisceral, Modified multivisceral, Liver+Small bowel, Small bowel+colon (Bailey & Love Fig 91.1) |
| 4 | Donor operation — 7 colour-coded steps + Recipient operation — 9 steps (incl. ileostomy creation) |
| 5 | Graft implantation illustration (Sabiston Fig 56.3 — infra/supracoeliac aortic conduit) + Vascular anatomy diagram (SMA, hepatic artery, portal vein, ileocolic artery labelled) |
| 6 | Why intestine needs MORE immunosuppression (MALT rationale) + Induction IS table + Maintenance IS table (tacrolimus, MMF, steroids, sirolimus, everolimus) |
| 7 | Novel IS strategies (vedolizumab, rituximab, LIP protocol, Pleximmune) + ACR management flowchart (grade-by-grade treatment) |
| 8 | Complications table + Survival outcomes data + 10-point clinical takeaways |
Give Illustrative diagrams of intestinal transplants Vascular anastomosis
You already have the comprehensive Intestinal_Transplantation.pdf with all 4 graft type diagrams and vascular anatomy illustrations on Pages 3 & 5
Give illustrative easy image of rectal injuries
Cleft lip and cleft palate illustrative images
Esophageal perforation illustrative image
Malrotation of gut illustrative images