Small bowel transplantation Illustrated images Flowcharts Give in PDF
mkdir -p /tmp/workspace/sbt-pdf && ls /tmp/workspace/sbt-pdf/
cd /tmp/workspace/sbt-pdf && python3 -c " import urllib.request images = { 'trend.png': 'https://cdn.orris.care/cdss_images/39a781f3b753b2884868f5b22751c5333f585763897f52e1bcb119d491229deb.png', 'full_multivisceral.png': 'https://cdn.orris.care/cdss_images/3e24006b711a378210565b8aa3eaaf2a5b4c81120af4aa2989761f7efc826381.png', 'liver_small_bowel.png': 'https://cdn.orris.care/cdss_images/8f657d7ea2c55608d17877ddb2fb4af4ce370556661c3d01115040a0938234cf.png', 'modified_multivisceral.png': 'https://cdn.orris.care/cdss_images/22e0e085b9a6ec179f227404b40e30d6451d63f9697f008200eaeb9f6355f308.png', 'sb_pancreas_colon.png': 'https://cdn.orris.care/cdss_images/1e630c09aeb71ebb4ed3c9d531b5ae11c6cb38dacfe8288c4666c202cbddc7e4.png', } for fname, url in images.items(): urllib.request.urlretrieve(url, fname) print(f'Downloaded {fname}') "
~/sbt-pdf/generate_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm, mm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Image, Table, TableStyle,
PageBreak, HRFlowable, KeepTogether
)
from reportlab.platypus.flowables import Flowable
from reportlab.graphics.shapes import Drawing, Rect, String, Line, Polygon, Arrow
from reportlab.graphics import renderPDF
from reportlab.graphics.charts.barcharts import VerticalBarChart
import os
# ── Page setup ──────────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
"/tmp/workspace/sbt-pdf/Small_Bowel_Transplantation.pdf",
pagesize=A4,
leftMargin=2*cm, rightMargin=2*cm,
topMargin=2.5*cm, bottomMargin=2.5*cm,
title="Small Bowel Transplantation",
author="Medical Library – Orris"
)
W, H = A4
CONTENT_W = W - 4*cm
# ── Colour palette ────────────────────────────────────────────────────────
DARK_BLUE = colors.HexColor("#1A3A5C")
MID_BLUE = colors.HexColor("#2E6DA4")
LIGHT_BLUE = colors.HexColor("#D6E8F7")
ACCENT = colors.HexColor("#E8523A")
GREEN = colors.HexColor("#2E8B57")
LIGHT_GREEN = colors.HexColor("#D4EDDA")
ORANGE = colors.HexColor("#E07B39")
LIGHT_ORANGE= colors.HexColor("#FFF3E0")
YELLOW_BG = colors.HexColor("#FFFDE7")
GREY_BG = colors.HexColor("#F5F5F5")
WHITE = colors.white
# ── Styles ─────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
title_style = ParagraphStyle("Title",
fontName="Helvetica-Bold", fontSize=26, leading=32,
textColor=WHITE, alignment=TA_CENTER, spaceAfter=4)
subtitle_style = ParagraphStyle("Subtitle",
fontName="Helvetica", fontSize=13, leading=18,
textColor=colors.HexColor("#B8D4F0"), alignment=TA_CENTER, spaceAfter=8)
h1 = ParagraphStyle("H1",
fontName="Helvetica-Bold", fontSize=16, leading=20,
textColor=WHITE, spaceBefore=14, spaceAfter=6,
backColor=DARK_BLUE, leftIndent=-4, rightIndent=-4,
borderPad=6)
h2 = ParagraphStyle("H2",
fontName="Helvetica-Bold", fontSize=13, leading=17,
textColor=MID_BLUE, spaceBefore=10, spaceAfter=4,
borderPadding=(0,0,2,0))
h3 = ParagraphStyle("H3",
fontName="Helvetica-Bold", fontSize=11, leading=14,
textColor=DARK_BLUE, spaceBefore=6, spaceAfter=3)
body = ParagraphStyle("Body",
fontName="Helvetica", fontSize=10, leading=14,
textColor=colors.HexColor("#222222"), spaceAfter=5,
alignment=TA_JUSTIFY)
bullet = ParagraphStyle("Bullet",
fontName="Helvetica", fontSize=10, leading=13,
textColor=colors.HexColor("#333333"),
leftIndent=14, bulletIndent=4, spaceAfter=2)
caption = ParagraphStyle("Caption",
fontName="Helvetica-Oblique", fontSize=8.5, leading=11,
textColor=colors.HexColor("#555555"), alignment=TA_CENTER, spaceAfter=6)
box_title = ParagraphStyle("BoxTitle",
fontName="Helvetica-Bold", fontSize=10, leading=13,
textColor=DARK_BLUE)
box_body = ParagraphStyle("BoxBody",
fontName="Helvetica", fontSize=9.5, leading=13,
textColor=colors.HexColor("#333333"), leftIndent=8, spaceAfter=2)
# ── Helper: section header bar ─────────────────────────────────────────────
def section_header(text):
tbl = Table([[Paragraph(text, h1)]], colWidths=[CONTENT_W])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), DARK_BLUE),
("BOTTOMPADDING",(0,0),(-1,-1), 6),
("TOPPADDING", (0,0),(-1,-1), 6),
("LEFTPADDING", (0,0),(-1,-1), 10),
("RIGHTPADDING", (0,0),(-1,-1), 10),
("ROUNDEDCORNERS", [4]),
]))
return tbl
def info_box(title, items, bg=LIGHT_BLUE, title_color=DARK_BLUE):
content = [Paragraph(title, ParagraphStyle("BT", fontName="Helvetica-Bold",
fontSize=10, textColor=title_color, spaceAfter=4))]
for item in items:
content.append(Paragraph(f"• {item}", box_body))
tbl = Table([[content]], colWidths=[CONTENT_W])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("BOX", (0,0), (-1,-1), 1, title_color),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
]))
return tbl
# ── Flowchart helper ───────────────────────────────────────────────────────
class FlowchartBox(Flowable):
"""Draws a simple vertical flowchart with boxes and arrows."""
def __init__(self, steps, width=None, step_height=28, gap=18, title=""):
Flowable.__init__(self)
self.steps = steps # list of (text, bg_color, text_color)
self.width = width or CONTENT_W
self.step_height = step_height
self.gap = gap
self.title = title
self.n = len(steps)
self.height = self.n * step_height + (self.n-1)*gap + (30 if title else 0) + 10
def draw(self):
c = self.canv
y = self.height - 5
bw = self.width
if self.title:
c.setFont("Helvetica-Bold", 11)
c.setFillColor(DARK_BLUE)
c.drawCentredString(bw/2, y - 14, self.title)
y -= 30
for i, (text, bg, fg) in enumerate(self.steps):
box_y = y - self.step_height
# Drop shadow
c.setFillColor(colors.HexColor("#CCCCCC"))
c.roundRect(3, box_y - 3, bw - 6, self.step_height, 6, fill=1, stroke=0)
# Box
c.setFillColor(bg)
c.setStrokeColor(DARK_BLUE)
c.setLineWidth(0.8)
c.roundRect(0, box_y, bw - 6, self.step_height, 6, fill=1, stroke=1)
# Text
c.setFillColor(fg)
c.setFont("Helvetica-Bold" if i == 0 else "Helvetica", 9)
# Wrap text manually
words = text.split()
lines, cur = [], []
for w in words:
test = " ".join(cur + [w])
if c.stringWidth(test, "Helvetica", 9) < bw - 30:
cur.append(w)
else:
lines.append(" ".join(cur))
cur = [w]
if cur:
lines.append(" ".join(cur))
total_h = len(lines) * 11
start_y = box_y + self.step_height/2 + total_h/2 - 3
for li, line in enumerate(lines):
c.drawCentredString((bw-6)/2, start_y - li*11, line)
y = box_y - 2
# Arrow to next
if i < self.n - 1:
c.setStrokeColor(MID_BLUE)
c.setFillColor(MID_BLUE)
c.setLineWidth(1.5)
ax = (bw-6)/2
ay_top = y
ay_bot = y - self.gap + 6
c.line(ax, ay_top, ax, ay_bot)
# Arrowhead
c.setFillColor(MID_BLUE)
c.polygon([ax-5, ay_bot+7, ax+5, ay_bot+7, ax, ay_bot], fill=1, stroke=0)
y -= self.gap
def wrap(self, *args):
return self.width, self.height
class DecisionFlowchart(Flowable):
"""Decision tree / branching flowchart."""
def __init__(self, width=None):
Flowable.__init__(self)
self.width = width or CONTENT_W
self.height = 310
def draw(self):
c = self.canv
W = self.width
cx = W / 2
def box(x, y, w, h, text, bg, fg=WHITE, bold=True):
c.setFillColor(colors.HexColor("#BBBBBB"))
c.roundRect(x+2, y-2, w, h, 5, fill=1, stroke=0)
c.setFillColor(bg)
c.setStrokeColor(DARK_BLUE)
c.setLineWidth(0.8)
c.roundRect(x, y, w, h, 5, fill=1, stroke=1)
c.setFillColor(fg)
fn = "Helvetica-Bold" if bold else "Helvetica"
c.setFont(fn, 8.5)
words = text.split("\n")
tot = len(words)*10
sy = y + h/2 + tot/2 - 8
for i, line in enumerate(words):
c.drawCentredString(x + w/2, sy - i*10, line)
def diamond(x, y, w, h, text, bg=ORANGE):
pts = [x+w/2, y+h, x+w, y+h/2, x+w/2, y, x, y+h/2]
c.setFillColor(bg)
c.setStrokeColor(DARK_BLUE)
c.setLineWidth(0.8)
c.polygon(pts, fill=1, stroke=1)
c.setFillColor(WHITE)
c.setFont("Helvetica-Bold", 8)
c.drawCentredString(x+w/2, y+h/2-4, text)
def arrow(x1, y1, x2, y2, label=""):
c.setStrokeColor(MID_BLUE)
c.setLineWidth(1.2)
c.line(x1, y1, x2, y2)
dx, dy = x2-x1, y2-y1
import math
l = math.sqrt(dx*dx+dy*dy)
if l > 0:
ux, uy = dx/l, dy/l
ax = x2 - 6*ux; ay = y2 - 6*uy
c.setFillColor(MID_BLUE)
perp_x, perp_y = -uy, ux
c.polygon([x2, y2, ax+4*perp_x, ay+4*perp_y, ax-4*perp_x, ay-4*perp_y], fill=1, stroke=0)
if label:
mx, my = (x1+x2)/2, (y1+y2)/2
c.setFillColor(colors.HexColor("#333333"))
c.setFont("Helvetica", 7.5)
c.drawCentredString(mx+8, my+3, label)
BW = 140; BH = 28; DW = 110; DH = 36
# START
box(cx-70, 278, 140, 28, "Intestinal Failure", DARK_BLUE)
arrow(cx, 278, cx, 258)
# Diamond 1
diamond(cx-DW/2, 222, DW, DH, "PN Dependent?", ORANGE)
arrow(cx, 222, cx, 198)
# Yes continue
box(cx-70, 170, 140, 26, "Assess PN Complications", MID_BLUE)
arrow(cx, 170, cx, 148)
# Diamond 2
diamond(cx-55, 108, 110, 38, "Life-threatening\nComplications?", colors.HexColor("#C0392B"))
# No - right
arrow(cx+55, 127, cx+110, 127, "No")
box(cx+110, 113, 110, 28, "Continue PN\n+ Rehabilitation", GREEN, WHITE, False)
# Yes - down
arrow(cx, 108, cx, 86)
box(cx-70, 60, 140, 26, "List for Transplant", DARK_BLUE)
arrow(cx, 60, cx, 38)
box(cx-70, 12, 140, 26, "Transplant Type Selection", MID_BLUE)
# No from diamond 1 (right)
arrow(cx+DW/2, 240, cx+140, 240, "No")
box(cx+140, 226, 105, 28, "Medical\nManagement", GREEN, WHITE, False)
# Title
c.setFont("Helvetica-Bold", 10)
c.setFillColor(DARK_BLUE)
c.drawCentredString(W/2, self.height-12, "Decision Flowchart: Pathway to Small Bowel Transplantation")
def wrap(self, *args):
return self.width, self.height
# ── Cover page ─────────────────────────────────────────────────────────────
def cover_page(story):
# Blue header block
cover_tbl = Table(
[[Paragraph("SMALL BOWEL\nTRANSPLANTATION", title_style)],
[Paragraph("Comprehensive Clinical Reference with Illustrated Diagrams & Flowcharts", subtitle_style)],
[Paragraph("Sources: Sabiston Textbook of Surgery (22e) · Bailey & Love's Surgery (28e)\n"
"Yamada's Gastroenterology (7e) · Fischer's Mastery of Surgery (8e)", subtitle_style)]],
colWidths=[CONTENT_W]
)
cover_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), DARK_BLUE),
("TOPPADDING", (0,0), (-1,-1), 24),
("BOTTOMPADDING", (0,-1), (-1,-1), 24),
("LEFTPADDING", (0,0), (-1,-1), 20),
("RIGHTPADDING", (0,0), (-1,-1), 20),
]))
story.append(cover_tbl)
story.append(Spacer(1, 0.5*cm))
# Quick facts boxes
facts = [
("Least Common Solid Organ Transplant",
"~82 performed in the USA in 2022 (UNOS). Peak ~200/year in 2007. "
"Only ~3,400 total procedures since 1985."),
("1-Year Patient Survival",
"~76% (ITR registry). Up from 25% in early 1990s cyclosporine era. "
"Improved markedly after tacrolimus introduction (1994)."),
("Most Common Indication",
"Short bowel syndrome (SBS) ~63–64% in both pediatric and adult recipients. "
"Pediatric: gastroschisis, volvulus, NEC. Adults: ischaemia, Crohn disease."),
]
cols = []
for title, text in facts:
cell = [
Paragraph(title, ParagraphStyle("FT", fontName="Helvetica-Bold", fontSize=10,
textColor=DARK_BLUE, spaceAfter=4)),
Paragraph(text, ParagraphStyle("FB", fontName="Helvetica", fontSize=9.5,
textColor=colors.HexColor("#333333")))
]
cols.append(cell)
ft = Table([cols], colWidths=[CONTENT_W/3 - 3]*3, rowHeights=None)
ft.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), LIGHT_BLUE),
("BACKGROUND", (1,0), (1,0), LIGHT_GREEN),
("BACKGROUND", (2,0), (2,0), LIGHT_ORANGE),
("BOX", (0,0), (0,0), 1, MID_BLUE),
("BOX", (1,0), (1,0), 1, GREEN),
("BOX", (2,0), (2,0), 1, ORANGE),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "TOP"),
("COLPADDING", (0,0), (-1,-1), 6),
]))
story.append(ft)
story.append(Spacer(1, 0.4*cm))
# Trend image
if os.path.exists("/tmp/workspace/sbt-pdf/trend.png"):
img = Image("/tmp/workspace/sbt-pdf/trend.png", width=12*cm, height=4*cm)
story.append(img)
story.append(Paragraph(
"Fig 1. Number of intestinal transplants performed annually in the United States, 1990–2023. "
"(Source: UNOS OPTN Metrics / Sabiston Textbook of Surgery, 22e)",
caption))
story.append(PageBreak())
# ── Section 1: Background & History ───────────────────────────────────────
def section_history(story):
story.append(section_header("1. Background & Historical Overview"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"The small bowel (intestine) is the most immunogenic solid organ due to its large lymphoid mass. "
"This made early transplantation attempts uniformly fatal. The history of intestinal transplantation "
"spans decades of incremental progress:", body))
timeline = [
["1960s", "Starzl performs first experimental SBT in dogs; all died within 9 days. "
"Clinical attempts in humans fail — no patient achieves enteral autonomy."],
["Late 1960s", "PN introduced. Clinical SBT abandoned due to poor outcomes and the availability "
"of a safer alternative."],
["1983", "Cyclosporine enters clinical use. Renewed interest in SBT alongside growing awareness "
"of PN-related morbidity."],
["1988", "First successful SBT by Deltz (living donor) achieving enteral autonomy. "
"Same year: Grant et al. perform first cadaveric liver–intestine transplant with >1-year survival."],
["1990–94", "1-year survival ~25% with cyclosporine. Tacrolimus introduced (1994) — major "
"improvement in rejection control."],
["2007", "Peak activity: ~200 intestinal transplants/year in the USA."],
["2010s–present", "Volume stabilises at ~80–150/year. Improvement in pediatric intestinal "
"rehabilitation reduces need in children. Adults now dominate the waitlist."],
]
tbl = Table(
[[Paragraph(r[0], ParagraphStyle("Year", fontName="Helvetica-Bold", fontSize=9.5,
textColor=DARK_BLUE)),
Paragraph(r[1], ParagraphStyle("Evt", fontName="Helvetica", fontSize=9.5, leading=13))]
for r in timeline],
colWidths=[2.8*cm, CONTENT_W - 2.8*cm]
)
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,-1), LIGHT_BLUE),
("BACKGROUND", (1,0), (1,-1), GREY_BG),
("ROWBACKGROUNDS", (1,0), (1,-1), [WHITE, GREY_BG]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#CCCCCC")),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(tbl)
story.append(Spacer(1, 0.3*cm))
# ── Section 2: Indications ─────────────────────────────────────────────────
def section_indications(story):
story.append(section_header("2. Indications for Small Bowel Transplantation"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"<b>PN dependence alone is NOT an indication.</b> Transplant is reserved for patients with "
"irreversible intestinal failure AND at least one life-threatening PN complication "
"(Sixth International SBT Symposium 2001; updated 2015 at XIV Symposium):", body))
indications = [
("Advanced / Progressive IFALD",
"Intestinal failure-associated liver disease progressing despite optimised management. "
"Combined liver–intestine transplant is considered."),
("Loss of Central Venous Access",
"Multiple central vein thromboses leaving <2 usable central venous sites."),
("Recurrent Life-Threatening Sepsis",
"≥2 ICU admissions for catheter-related bloodstream infections."),
("Invasive Intraabdominal Desmoids",
"Unresectable desmoid tumours rendering enteral feeding impossible."),
("Acute Diffuse Intestinal Infarction with Hepatic Failure",
"Rare emergency indication — acute loss of entire gut with concomitant liver failure."),
("First Transplant Failure",
"Retransplantation following graft loss."),
("High Morbidity / Poor QoL",
"Frequent hospitalisation, severe electrolyte disturbances — not universally accepted."),
("Diffuse Portomesenteric Thrombosis (Yerdel grade 4)",
"Multivisceral transplant replaces entire portal system; only definitive treatment."),
]
rows = []
for i, (ind, detail) in enumerate(indications):
rows.append([
Paragraph(f"{i+1}. {ind}", ParagraphStyle("IndT", fontName="Helvetica-Bold",
fontSize=9.5, textColor=DARK_BLUE)),
Paragraph(detail, ParagraphStyle("IndD", fontName="Helvetica", fontSize=9.5, leading=13))
])
tbl = Table(rows, colWidths=[5.2*cm, CONTENT_W-5.2*cm])
tbl.setStyle(TableStyle([
("ROWBACKGROUNDS", (0,0), (-1,-1), [LIGHT_BLUE, WHITE]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#BBBBBB")),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "TOP"),
("BOX", (0,0), (-1,-1), 1, MID_BLUE),
]))
story.append(tbl)
story.append(Spacer(1, 0.3*cm))
# Underlying conditions table
story.append(Paragraph("Underlying Conditions Necessitating Intestinal Transplantation (ITR Data):", h2))
story.append(Spacer(1, 0.15*cm))
cond_data = [
[Paragraph("<b>Pediatric Condition</b>", box_title),
Paragraph("<b>%</b>", box_title),
Paragraph("<b>Adult Condition</b>", box_title),
Paragraph("<b>%</b>", box_title)],
["Short bowel syndrome", "63%", "Short bowel syndrome", "64%"],
["Gastroschisis", "22%", "Ischaemia", "11%"],
["Volvulus", "16%", "Crohn disease", "10%"],
["Necrotising enterocolitis", "14%", "Volvulus", "7%"],
["Motility disorders", "18%", "Motility disorders", "11%"],
["Atresia", "4%", "Trauma", "7%"],
["Malabsorption syndromes", "8%", "Tumour", "13%"],
["Retransplantation", "8%", "Retransplantation", "7%"],
]
cw = CONTENT_W / 4
ctbl = Table(cond_data, colWidths=[cw*1.6, cw*0.4, cw*1.6, cw*0.4])
ctbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 9),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_BLUE]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#CCCCCC")),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 7),
("BOX", (0,0), (-1,-1), 1, MID_BLUE),
("ALIGN", (1,0), (1,-1), "CENTER"),
("ALIGN", (3,0), (3,-1), "CENTER"),
]))
story.append(ctbl)
story.append(Spacer(1, 0.3*cm))
# Decision flowchart
story.append(Paragraph("Decision Pathway – From Intestinal Failure to Transplant:", h2))
story.append(Spacer(1, 0.2*cm))
story.append(DecisionFlowchart(width=CONTENT_W))
story.append(Spacer(1, 0.2*cm))
# ── Section 3: Types of Transplant ────────────────────────────────────────
def section_types(story):
story.append(PageBreak())
story.append(section_header("3. Types of Intestinal / Multivisceral Transplant"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"Intestinal transplantation encompasses several 'cluster' configurations depending on which "
"organs are included. Selection depends on hepatic function, portal vein patency, "
"intraabdominal anatomy, and intraoperative findings.", body))
types_data = [
[Paragraph("<b>Transplant Type</b>", box_title),
Paragraph("<b>Organs Included</b>", box_title),
Paragraph("<b>Extent of Resection</b>", box_title),
Paragraph("<b>Proximal Anastomosis</b>", box_title)],
["Isolated Small Intestine (+/- colon)",
"Small intestine ± colon ± pancreas",
"Small intestine + part of colon",
"Duodenum or proximal jejunum"],
["Liver + Small Bowel",
"Liver, pancreas, small intestine, colon",
"Liver, small intestine + part of colon",
"Duodenum or proximal jejunum"],
["Modified Multivisceral",
"Stomach, pancreas, small intestine, colon",
"Stomach, pancreas, spleen, small intestine, colon",
"Proximal stomach or oesophagus"],
["Full Multivisceral",
"Liver, stomach, pancreas, small intestine, colon",
"Liver, stomach, pancreas, spleen, small intestine, colon",
"Proximal stomach or oesophagus"],
]
cws = [3.5*cm, 4.2*cm, 4.5*cm, 3.8*cm]
ttbl = Table(types_data, colWidths=cws)
ttbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 9),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_BLUE]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#CCCCCC")),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("BOX", (0,0), (-1,-1), 1, MID_BLUE),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(ttbl)
story.append(Spacer(1, 0.4*cm))
# Images in 2x2 grid
img_data = []
imgs_info = [
("full_multivisceral.png", "Full Multivisceral Transplant\n(Liver, stomach, pancreas, SB, colon)"),
("liver_small_bowel.png", "Liver + Small Bowel Transplant\n(Liver, pancreas, SB, colon)"),
("modified_multivisceral.png", "Modified Multivisceral Transplant\n(No liver: stomach, pancreas, SB, colon)"),
("sb_pancreas_colon.png", "Small Bowel, Pancreas & Colon Transplant\n(SMA, ileocolic, middle colic arteries shown)"),
]
cell_w = CONTENT_W / 2 - 0.3*cm
row1, row2 = [], []
for i, (fname, cap) in enumerate(imgs_info):
fp = f"/tmp/workspace/sbt-pdf/{fname}"
if os.path.exists(fp):
img = Image(fp, width=cell_w - 0.4*cm, height=7*cm, kind="proportional")
else:
img = Paragraph("[Image not found]", caption)
cell = [img, Paragraph(cap, caption)]
if i < 2:
row1.append(cell)
else:
row2.append(cell)
img_tbl = Table([row1, row2], colWidths=[cell_w, cell_w])
img_tbl.setStyle(TableStyle([
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 4),
("RIGHTPADDING", (0,0), (-1,-1), 4),
("BOX", (0,0), (-1,-1), 0.5, colors.HexColor("#BBBBBB")),
("GRID", (0,0), (-1,-1), 0.5, colors.HexColor("#DDDDDD")),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(img_tbl)
story.append(Paragraph(
"Figure 2. Types of intestinal/multivisceral transplant — Bailey & Love's Short Practice of Surgery, 28th ed.", caption))
story.append(Spacer(1, 0.3*cm))
# ── Section 4: Assessment ──────────────────────────────────────────────────
def section_assessment(story):
story.append(PageBreak())
story.append(section_header("4. Pre-Transplant Assessment"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"Assessment requires a dedicated multidisciplinary team (MDT). Key components include:", body))
mdt = [
["Transplant Surgeons", "Transplant Anaesthetists", "Intestinal Failure Physicians"],
["Hepatologist", "Psychiatrist / Psychologist", "Radiologist"],
["Infectious Disease Physician", "Transplant Specialist Nurses", "Dietician"],
]
mtbl = Table(mdt, colWidths=[CONTENT_W/3]*3)
mtbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), LIGHT_BLUE),
("TEXTCOLOR", (0,0), (-1,-1), DARK_BLUE),
("FONTNAME", (0,0), (-1,-1), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 9),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("GRID", (0,0), (-1,-1), 0.5, colors.HexColor("#AAAAAA")),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("BOX", (0,0), (-1,-1), 1, MID_BLUE),
]))
story.append(mtbl)
story.append(Spacer(1, 0.3*cm))
assess_steps = [
(DARK_BLUE, WHITE, "1. Venous Access Assessment", "Detailed venous mapping essential. "
"Patients with prolonged PN or ultra-short gut at high risk for IFALD. "
"Central venous patency determines feasibility."),
(MID_BLUE, WHITE, "2. Liver Biopsy", "Patients at risk for IFALD require liver biopsy "
"to stage fibrosis. Significant fibrosis may mandate combined liver–intestine transplant."),
(GREEN, WHITE, "3. Cardiovascular & Respiratory Assessment",
"Full cardiac workup (ECG, echo). Pulmonary function tests. "
"Correct any reversible comorbidities."),
(ORANGE, WHITE, "4. GI Endoscopy",
"Upper and lower GI endoscopies may be required to assess residual gut anatomy."),
(colors.HexColor("#7B2D8B"), WHITE, "5. Cross-Sectional Abdominal Imaging",
"CT/MRI abdomen — essential for operative planning. "
"Assess abdominal domain, vascular anatomy, and portal system."),
(colors.HexColor("#C0392B"), WHITE, "6. Renal Assessment",
"Significant renal impairment may necessitate inclusion of a kidney at transplant."),
(DARK_BLUE, WHITE, "7. Anaesthetic & Psychiatric Assessment",
"Anaesthetic risk stratification. Psychosocial evaluation mandatory. Dietetic review."),
]
rows = []
for bg, fg, title, detail in assess_steps:
rows.append([
Paragraph(title, ParagraphStyle("AT", fontName="Helvetica-Bold", fontSize=9.5,
textColor=fg, backColor=bg)),
Paragraph(detail, ParagraphStyle("AD", fontName="Helvetica", fontSize=9.5, leading=13))
])
atbl = Table(rows, colWidths=[5.5*cm, CONTENT_W - 5.5*cm])
atbl.setStyle(TableStyle([
("ROWBACKGROUNDS", (1,0), (1,-1), [WHITE, GREY_BG]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#CCCCCC")),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "TOP"),
("BOX", (0,0), (-1,-1), 1, MID_BLUE),
]))
story.append(atbl)
story.append(Spacer(1, 0.3*cm))
# ── Section 5: Surgical Technique ─────────────────────────────────────────
def section_surgery(story):
story.append(section_header("5. Surgical Technique"))
story.append(Spacer(1, 0.2*cm))
steps = [
(DARK_BLUE, WHITE, "Donor Procurement",
"Modified abdominal perfusion technique. Rapid infusion of cold preservation solution "
"(University of Wisconsin or HTK). En bloc procurement of relevant organs. "
"SMA with Carrel patch preserved."),
(MID_BLUE, WHITE, "Back-Table Preparation",
"Arterial reconstruction (if needed) using donor iliac vessels. "
"Lymphatic channels oversewn to prevent chylous ascites. "
"Length and viability assessed."),
(colors.HexColor("#1A7A5C"), WHITE, "Recipient Preparation",
"Extensive enterectomy. Careful identification and preservation of vascular structures. "
"Assessment of abdominal domain — loss of domain may require staged closure."),
(colors.HexColor("#A0522D"), WHITE, "Vascular Anastomoses",
"Arterial: donor SMA to recipient aorta (infrarenal or supracoeliac). "
"Venous: donor SMV/portal vein to recipient portal vein or IVC (systemic drainage). "
"Portal drainage preferred (more physiological)."),
(colors.HexColor("#7B2D8B"), WHITE, "Enteric Reconstruction",
"Proximal anastomosis: jejunum to proximal recipient gut. "
"Distal anastomosis: to native colon or ileostomy creation. "
"Decompressing ileostomy (chimney stoma) created for endoscopic surveillance."),
(colors.HexColor("#C0392B"), WHITE, "Abdominal Closure",
"Temporary closure with mesh or VAC if domain loss. "
"Feeding jejunostomy tube placed. Drain placement."),
]
for bg, fg, title, detail in steps:
row = Table([[
Paragraph(title, ParagraphStyle("ST", fontName="Helvetica-Bold", fontSize=10,
textColor=fg)),
Paragraph(detail, ParagraphStyle("SD", fontName="Helvetica", fontSize=9.5,
leading=13, textColor=colors.HexColor("#222222")))
]], colWidths=[4.0*cm, CONTENT_W - 4.0*cm])
row.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), bg),
("BACKGROUND", (1,0), (1,0), GREY_BG),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#BBBBBB")),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(row)
story.append(Spacer(1, 0.3*cm))
# Surgical flowchart
story.append(Paragraph("Operative Sequence – Flowchart:", h2))
story.append(Spacer(1, 0.1*cm))
op_steps = [
("DONOR PROCUREMENT\nSMA Carrel patch • Cold perfusion • En-bloc harvest",
DARK_BLUE, WHITE),
("BACK-TABLE PREPARATION\nArterial reconstruction • Lymphatics oversewn",
MID_BLUE, WHITE),
("RECIPIENT HEPATECTOMY / ENTERECTOMY\nAbdominal domain assessment",
colors.HexColor("#1A7A5C"), WHITE),
("VASCULAR ANASTOMOSES\nArterial (aorta) • Venous (portal/IVC)",
colors.HexColor("#A0522D"), WHITE),
("REPERFUSION & INSPECTION\nAssess perfusion, colour, peristalsis",
colors.HexColor("#C0392B"), WHITE),
("ENTERIC ANASTOMOSES\nProximal & distal bowel continuity • Stoma creation",
colors.HexColor("#7B2D8B"), WHITE),
("ABDOMINAL CLOSURE\nFeed tube • Drains • Temporary closure if needed",
DARK_BLUE, WHITE),
]
story.append(FlowchartBox(op_steps, width=CONTENT_W, step_height=32, gap=14))
story.append(Spacer(1, 0.3*cm))
# ── Section 6: Immunosuppression ──────────────────────────────────────────
def section_immuno(story):
story.append(PageBreak())
story.append(section_header("6. Immunosuppression"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"The intestine is the most immunogenic solid organ transplant, requiring intensive "
"immunosuppression. Tacrolimus-based triple therapy is the current standard.", body))
immuno_data = [
[Paragraph("<b>Agent</b>", box_title),
Paragraph("<b>Role</b>", box_title),
Paragraph("<b>Notes</b>", box_title)],
["Tacrolimus (FK506)",
"Primary calcineurin inhibitor – backbone of all regimens",
"Target trough 10–15 ng/mL early. Risk: nephrotoxicity, neurotoxicity, PTLD."],
["Corticosteroids",
"Induction & maintenance",
"High-dose perioperative. Wean to low dose or attempt withdrawal at 3–6 months."],
["Mycophenolate Mofetil",
"Antiproliferative – often added as third agent",
"Reduces tacrolimus requirement. GI side effects common."],
["Basiliximab / Daclizumab",
"IL-2 receptor blockade – induction agent",
"Used perioperatively to delay calcineurin initiation in renal impairment."],
["Anti-thymocyte Globulin (ATG)",
"T-cell depletion – induction and rejection treatment",
"Used perioperatively at many centres; also first-line for steroid-resistant rejection."],
["Sirolimus (mTOR inhibitor)",
"Alternative / rescue immunosuppression",
"Avoid early post-op due to wound healing impairment and thrombosis risk."],
["Rituximab (anti-CD20)",
"Treatment of EBV-PTLD with B-cell proliferation",
"Used when PTLD presents as B-cell tumour."],
]
itbl = Table(immuno_data, colWidths=[3.8*cm, 4.8*cm, CONTENT_W - 8.6*cm])
itbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 9),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_BLUE]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#CCCCCC")),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 7),
("BOX", (0,0), (-1,-1), 1, MID_BLUE),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(itbl)
story.append(Spacer(1, 0.3*cm))
# Immunosuppression flowchart
story.append(Paragraph("Immunosuppression Protocol – Flowchart:", h2))
story.append(Spacer(1, 0.1*cm))
is_steps = [
("PRE-OPERATIVE INDUCTION\nATG or Basiliximab • High-dose methylprednisolone",
DARK_BLUE, WHITE),
("EARLY POST-OP (0–3 months)\nTacrolimus (high trough) + Steroids + MMF\nCMV/PCP prophylaxis",
MID_BLUE, WHITE),
("MAINTENANCE (3–12 months)\nTacrolimus (lower trough) + Taper steroids\nFrequent endoscopic surveillance",
GREEN, WHITE),
("LONG-TERM (>12 months)\nMinimise steroids • Monitor for PTLD, CMV, rejection\nSirolimus switch if nephrotoxicity",
colors.HexColor("#1A7A5C"), WHITE),
("REJECTION TREATMENT\nACR: pulse steroids + ATG\nChronic: optimise tacrolimus level",
ACCENT, WHITE),
]
story.append(FlowchartBox(is_steps, width=CONTENT_W, step_height=34, gap=14))
story.append(Spacer(1, 0.3*cm))
# ── Section 7: Complications ───────────────────────────────────────────────
def section_complications(story):
story.append(section_header("7. Complications"))
story.append(Spacer(1, 0.2*cm))
comps = [
("REJECTION", ACCENT, [
"Acute Cellular Rejection (ACR): Most common. Villous blunting, crypt apoptosis on biopsy.",
"Chronic Rejection: Foam cell arteriopathy; progressive graft dysfunction.",
"Diagnosis: Protocol endoscopic biopsies via stoma (every 1–2 weeks initially).",
"Grading: Indeterminate → Mild → Moderate → Severe (NEC-like).",
"Treatment: Pulse methylprednisolone; ATG for steroid-resistant; retransplant for chronic.",
]),
("INFECTION", MID_BLUE, [
"CMV Enteritis: Mimics rejection. Diagnose with biopsy (inclusion bodies) or PCR. "
"Treat with IV ganciclovir ± CMV-IVIG.",
"EBV / PTLD: Incidence 5–10% (much higher than other SOT). Risk with EBV-D+/R-. "
"Reduce immunosuppression; rituximab; chemotherapy for Burkitt/T-cell lymphoma.",
"Bacterial: High risk due to mucosal disruption. Gram-negatives & anaerobes. "
"Selective gut decontamination used at some centres.",
"Fungal: Candida, Aspergillus. Azole prophylaxis standard.",
]),
("GRAFT-VERSUS-HOST DISEASE (GVHD)", colors.HexColor("#7B2D8B"), [
"Incidence ~10% — higher than other SOT due to massive intestinal lymphoid mass.",
"Targets skin and epithelial cells. More common with large grafts (colon, liver inclusion).",
"Treat with high-dose steroids, ATG. Survival <50% once established.",
"Some centres use ATG donor pre-treatment to deplete graft lymphocytes.",
]),
("TECHNICAL COMPLICATIONS", GREEN, [
"Vascular thrombosis (arterial or venous) → graft infarction, retransplantation urgently needed.",
"Anastomotic leak → peritonitis, fistula.",
"Abdominal domain loss → wound dehiscence, hernia.",
"Chylous ascites → lymphatic disruption.",
]),
("POST-TRANSPLANT LYMPHOPROLIFERATIVE DISORDER (PTLD)", ORANGE, [
"Incidence 5–10% after intestinal transplant (higher than any other SOT).",
"Usually within 1st year. EBV-driven B-cell proliferation in most cases.",
"Risk factors: EBV D+/R−, strong immunosuppression, history of rejection.",
"Treatment: Reduce immunosuppression; rituximab; chemotherapy; surgical excision if localised.",
"Mortality exceeds 25% despite treatment.",
]),
]
for title, color, items in comps:
content = [
Paragraph(title, ParagraphStyle("CT", fontName="Helvetica-Bold", fontSize=10,
textColor=WHITE))
] + [Paragraph(f"• {item}", ParagraphStyle("CI", fontName="Helvetica", fontSize=9.5,
leading=13, textColor=colors.HexColor("#222222")))
for item in items]
header_cell = Table([[Paragraph(title, ParagraphStyle("CH",
fontName="Helvetica-Bold", fontSize=10, textColor=WHITE))]],
colWidths=[CONTENT_W])
header_cell.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), color),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
body_rows = [[Paragraph(f"• {item}", ParagraphStyle("CI", fontName="Helvetica",
fontSize=9.5, leading=13))] for item in items]
body_tbl = Table(body_rows, colWidths=[CONTENT_W])
body_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), GREY_BG),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 12),
("BOX", (0,0), (-1,-1), 1, color),
]))
story.append(header_cell)
story.append(body_tbl)
story.append(Spacer(1, 0.15*cm))
story.append(Spacer(1, 0.2*cm))
# Complications flowchart
story.append(Paragraph("Post-Transplant Monitoring & Complication Management:", h2))
story.append(Spacer(1, 0.1*cm))
mon_steps = [
("EARLY POST-OP MONITORING\nProtocol endoscopic biopsies via stoma • Tacrolimus levels\nCMV/EBV PCR weekly • Blood cultures if febrile",
DARK_BLUE, WHITE),
("SIGNS OF DYSFUNCTION?\nIncreased stoma output • Abdominal pain • Fever\nRising creatinine • Abnormal LFTs",
ORANGE, WHITE),
("ENDOSCOPIC BIOPSY\nVillous blunting → Rejection grading\nInclusion bodies / CMV IHC → CMV enteritis\nEBV ISH → PTLD",
MID_BLUE, WHITE),
("TREAT ACCORDINGLY\nRejection: steroids/ATG | CMV: ganciclovir | PTLD: reduce IS + rituximab\nGVHD: steroids + ATG",
ACCENT, WHITE),
("LONG-TERM FOLLOW-UP\nAnnual imaging • Nutritional status • QoL assessment\nMonitor for chronic rejection and malignancy",
GREEN, WHITE),
]
story.append(FlowchartBox(mon_steps, width=CONTENT_W, step_height=36, gap=14))
story.append(Spacer(1, 0.3*cm))
# ── Section 8: Outcomes ────────────────────────────────────────────────────
def section_outcomes(story):
story.append(PageBreak())
story.append(section_header("8. Outcomes & Survival"))
story.append(Spacer(1, 0.2*cm))
out_data = [
[Paragraph("<b>Era / Regimen</b>", box_title),
Paragraph("<b>1-Year Patient Survival</b>", box_title),
Paragraph("<b>Key Factor</b>", box_title)],
["1985–1992 (pre-tacrolimus)", "~25%", "Rejection poorly controlled with cyclosporine"],
["1992–2000 (tacrolimus era)", "~50–60%", "Tacrolimus introduced 1994 — major improvement"],
["2001–2010", "~70–76%", "ITR 76% 1-year survival (most recent registry report)"],
["2010–present (selected centres)", "60–90%", "Varies by centre volume and patient selection"],
["Paediatric cohort (2010–15)", "90% at 6 years", "Best outcomes: favourable anatomy + high-volume centre"],
]
otbl = Table(out_data, colWidths=[5.5*cm, 4.5*cm, CONTENT_W - 10*cm])
otbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 9),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_BLUE]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#CCCCCC")),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 7),
("BOX", (0,0), (-1,-1), 1, MID_BLUE),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(otbl)
story.append(Spacer(1, 0.3*cm))
story.append(info_box(
"Favourable Prognostic Factors for Enteral Autonomy",
[
"≥50% small bowel length remaining",
"Presence of ileocecal valve",
"Short bowel syndrome as aetiology (vs. motility disorder)",
"Absence of portal hypertension",
"Treatment at high-volume transplantation centre",
"Patient well enough to wait at home until transplant",
],
bg=LIGHT_GREEN, title_color=GREEN
))
story.append(Spacer(1, 0.3*cm))
story.append(info_box(
"Quality of Life After Transplant",
[
"SBT offers return to near-normal activities vs. lifelong PN dependency.",
"Home PN: QoL affected by infusion time, catheter complications, social limitations.",
"Post-transplant: freedom from PN, improved nutritional status, restored gut function.",
"Key QoL determinants: self-esteem, family support, days of PN per week (pre-transplant).",
],
bg=LIGHT_ORANGE, title_color=ORANGE
))
story.append(Spacer(1, 0.3*cm))
# ── Section 9: Summary Flowchart ──────────────────────────────────────────
def section_summary(story):
story.append(section_header("9. Complete Management Summary Flowchart"))
story.append(Spacer(1, 0.3*cm))
summary_steps = [
("INTESTINAL FAILURE\nPN-dependent patient • Irreversible loss of gut function",
DARK_BLUE, WHITE),
("INTESTINAL REHABILITATION\nGLP-2 analogues (teduglutide) • Surgical lengthening\nDietetic optimisation • Gut adaptation",
MID_BLUE, WHITE),
("INDICATIONS MET?\nIFALD • Lost venous access • Recurrent sepsis\nDesmoids • Acute infarction • Retransplant",
ORANGE, WHITE),
("MDT ASSESSMENT\nVenous mapping • Liver biopsy • CT abdomen • Echo\nPsychiatric + anaesthetic review",
colors.HexColor("#1A7A5C"), WHITE),
("WAITLIST & ORGAN ALLOCATION\nUNOS / ETN registration • ABO matching • Size matching\nDonor CMV/EBV serostatus",
colors.HexColor("#7B2D8B"), WHITE),
("TRANSPLANT OPERATION\nProcurement → Back-table → Recipient enterectomy\nVascular anastomoses → Enteric reconstruction",
ACCENT, WHITE),
("EARLY POST-OP ICU CARE\nTacrolimus induction • Surveillance biopsies • Antimicrobials\nNutritional support (TPN transitioning to enteral)",
DARK_BLUE, WHITE),
("DISCHARGE & LONG-TERM FOLLOW-UP\nEnteral autonomy goal • Monitor rejection/PTLD/CMV\nAnnual surveillance • QoL assessment",
GREEN, WHITE),
]
story.append(FlowchartBox(summary_steps, width=CONTENT_W, step_height=36, gap=14))
story.append(Spacer(1, 0.5*cm))
story.append(Paragraph(
"Sources: Sabiston Textbook of Surgery 22e (Ch. 56) · Bailey & Love's Short Practice of Surgery 28e (Ch. 91) · "
"Yamada's Textbook of Gastroenterology 7e (Ch. 59) · Fischer's Mastery of Surgery 8e",
ParagraphStyle("Src", fontName="Helvetica-Oblique", fontSize=8, textColor=colors.grey,
alignment=TA_CENTER)))
# ── Page number footer ─────────────────────────────────────────────────────
def add_page_number(canvas, doc):
canvas.saveState()
canvas.setFont("Helvetica", 8)
canvas.setFillColor(colors.HexColor("#777777"))
canvas.drawRightString(W - 2*cm, 1.5*cm, f"Page {doc.page}")
canvas.drawString(2*cm, 1.5*cm, "Small Bowel Transplantation | Orris Medical Library")
canvas.setStrokeColor(colors.HexColor("#CCCCCC"))
canvas.line(2*cm, 1.7*cm, W - 2*cm, 1.7*cm)
canvas.restoreState()
# ── Build document ─────────────────────────────────────────────────────────
story = []
cover_page(story)
section_history(story)
section_indications(story)
section_types(story)
section_assessment(story)
section_surgery(story)
section_immuno(story)
section_complications(story)
section_outcomes(story)
section_summary(story)
doc.build(story, onFirstPage=add_page_number, onLaterPages=add_page_number)
print("PDF generated successfully!")
cd /tmp/workspace/sbt-pdf && python3 generate_pdf.py 2>&1
~/sbt-pdf/generate_pdf.py
Successfully replaced 1 instance(s) of the string in '/tmp/workspace/sbt-pdf/generate_pdf.py'
cd /tmp/workspace/sbt-pdf && python3 generate_pdf.py 2>&1
~/sbt-pdf/generate_pdf.py
Successfully replaced 1 instance(s) of the string in '/tmp/workspace/sbt-pdf/generate_pdf.py'
~/sbt-pdf/generate_pdf.py
Successfully replaced 1 instance(s) of the string in '/tmp/workspace/sbt-pdf/generate_pdf.py'
cd /tmp/workspace/sbt-pdf && python3 generate_pdf.py 2>&1
~/sbt-pdf/generate_pdf.py
Successfully replaced 1 instance(s) of the string in '/tmp/workspace/sbt-pdf/generate_pdf.py'
diamond function) and then it will build successfully. The script has been fixed and is ready to run. Here is a summary of everything that has been prepared:/tmp/workspace/sbt-pdf/generate_pdf.py) is fully written and almost compiled. All source images have been downloaded:trend.png - US intestinal transplant volume trend 1990-2023 (UNOS/Sabiston)full_multivisceral.png - Full multivisceral transplant diagramliver_small_bowel.png - Liver + small bowel transplant diagrammodified_multivisceral.png - Modified multivisceral diagramsb_pancreas_colon.png - Small bowel, pancreas & colon diagramContinue
cd /tmp/workspace/sbt-pdf && python3 generate_pdf.py 2>&1
ls -lh /tmp/workspace/sbt-pdf/Small_Bowel_Transplantation.pdf
Small Bowel Transplantation
PDF Document · PDF
| Section | Content |
|---|---|
| Cover Page | Key stats panel (volume, survival, indications) + UNOS trend graph 1990-2023 |
| 1. History | Colour-coded timeline from Starzl 1960s → tacrolimus era → present |
| 2. Indications | 8-row indications table + ITR conditions data (pediatric vs adult) + decision flowchart |
| 3. Types of Transplant | 4-image grid (full multivisceral, liver+SB, modified multivisceral, SB+pancreas+colon) from Bailey & Love |
| 4. Assessment | MDT grid + 7-step pre-transplant assessment table |
| 5. Surgical Technique | 6-step colour table + operative sequence flowchart |
| 6. Immunosuppression | Drug reference table + protocol flowchart (induction → maintenance → rejection) |
| 7. Complications | Rejection, CMV, EBV/PTLD, GVHD, technical + post-transplant monitoring flowchart |
| 8. Outcomes | Era-by-era survival table + prognostic factors + QoL box |
| 9. Summary Flowchart | Complete 8-step pathway from intestinal failure to long-term follow-up |