/visulize Calots triangle And its borders with labels
| Border | Structure |
|---|---|
| Inferior | Cystic duct |
| Medial | Common hepatic duct (CHD) |
| Superior | Cystic artery |
| Border | Structure |
|---|---|
| Inferior / Lateral | Cystic duct + medial wall of gallbladder |
| Medial | Common hepatic duct |
| Superior | Inferior surface of the liver (segment V) |



/visulize Colitis
| Feature | UC |
|---|---|
| GI tract involvement | Colon + rectum only |
| Pattern | Continuous, no skip lesions |
| Wall depth | Mucosal & submucosal only (not transmural) |
| Ulcers | Superficial, broad-based |
| Characteristic lesion | Pseudopolyps (regenerating mucosa bulging into lumen) |
| Strictures | Rare |
| Fistulae | No |
| Perianal disease | No |
| Feature | Crohn's |
|---|---|
| GI tract involvement | Mouth to anus (esophagus to anus) |
| Pattern | Skip lesions |
| Wall depth | Transmural (full thickness) |
| Ulcers | Deep, knife-like / "cobblestoning" |
| Characteristic lesion | Creeping fat, strictures, fistulae |
| Granulomas | Yes (~35%) |
| Fistulae / sinuses | Yes |
| Perianal disease | Yes |


| Watershed Zone | Location | Eponym |
|---|---|---|
| #1 (most common) | Splenic flexure | Griffiths' point |
| #2 | Rectosigmoid junction | Sudeck's point |
| #3 (embolic) | Right colon (cecum/ascending) | Terminal branch of SMA (ileocolic) |
The rectum is usually spared - it has dual supply from both IMA and iliac circulations.


| Feature | Ulcerative Colitis | Crohn's Colitis | Ischemic Colitis |
|---|---|---|---|
| Location | Colon only | Any part of GI tract | Colon (watershed zones) |
| Pattern | Continuous from rectum | Skip lesions | Focal (splenic flexure, rectosigmoid, right colon) |
| Rectum | Always involved | Often spared | Usually spared |
| Wall depth | Mucosa/submucosa | Transmural | Variable (mucosal → full thickness necrosis) |
| Mechanism | Autoimmune | Autoimmune | Ischemia / hypoperfusion |
| Fistulae | No | Yes | No |
| Age predilection | 20-40 years | 15-30 years | Elderly (>60 years) |
Colitis
| Type | Cause | Location | Key Feature |
|---|---|---|---|
| Ulcerative Colitis | Autoimmune | Rectum → continuous proximal spread | Mucosal only, bloody diarrhea |
| Crohn's Colitis | Autoimmune | Any GI segment, skip lesions | Transmural, fistulae, strictures |
| Ischemic Colitis | Vascular / low flow | Watershed zones (splenic flexure, rectosigmoid) | Rectum spared, elderly |
| Infectious Colitis | Bacteria, parasites (C. diff, E. coli, Shigella) | Variable | Acute onset, often self-limiting |
| Microscopic Colitis | Idiopathic / autoimmune | Right colon predominant | Normal endoscopy, watery diarrhea |


| Organism | Notes |
|---|---|
| Clostridioides difficile | Most common healthcare-associated colitis; antibiotic-associated; pseudomembranous pattern |
| Escherichia coli O157:H7 | Enterohemorrhagic; hemolytic-uremic syndrome risk |
| Shigella | Dysentery; invasive mucosa |
| Campylobacter jejuni | Most common infectious diarrhea worldwide |
| Entamoeba histolytica | Amebic colitis; "flask-shaped" ulcers |
| Cytomegalovirus (CMV) | Immunocompromised patients |

| Feature | UC | Crohn's | Ischemic | Infectious | Microscopic |
|---|---|---|---|---|---|
| Bloody diarrhea | Yes (common) | Sometimes | Yes (acute) | Sometimes | No |
| Rectal involvement | Always | Often spared | Spared | Variable | Often spared |
| Skip lesions | No | Yes | No | No | No |
| Transmural | No | Yes | Variable | No | No |
| Fistulae | No | Yes | No | No | No |
| Normal endoscopy | No | No | No | No | Yes |
| Cancer risk | Yes (duration-dependent) | Slightly elevated | No | No | No |
| Age | 20-40 | 15-30 | Elderly | Any | Middle-aged women |
Create a diagnostic flowchart for colitis workup
mkdir -p /tmp/workspace/colitis-flowchart && ls /tmp/workspace/colitis-flowchart/
~/colitis-flowchart/generate_flowchart.py
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.patches import FancyBboxPatch, FancyArrowPatch
import matplotlib.patheffects as pe
fig, ax = plt.subplots(figsize=(22, 32))
ax.set_xlim(0, 22)
ax.set_ylim(0, 32)
ax.axis('off')
fig.patch.set_facecolor('#F7F9FC')
# ── Color palette ────────────────────────────────────────────────────────────
C = {
'start': '#1A237E', # dark navy – start/end
'step': '#1565C0', # blue – process step
'decision': '#E65100', # orange – decision diamond
'lab': '#2E7D32', # green – labs / investigations
'dx': '#6A1B9A', # purple – final diagnosis boxes
'tx': '#00695C', # teal – treatment hint
'arrow': '#37474F', # dark grey – arrows
'warn': '#C62828', # red – red-flag / urgent
'bg': '#FFFFFF',
'text_lt': '#FFFFFF',
'text_dk': '#1A1A1A',
}
def box(ax, x, y, w, h, text, facecolor, textcolor='white', fontsize=9,
bold=False, radius=0.4, style='round,pad=0.1', wrap=True):
patch = FancyBboxPatch((x - w/2, y - h/2), w, h,
boxstyle=f"round,pad=0.15",
facecolor=facecolor, edgecolor='white',
linewidth=1.5, zorder=3)
ax.add_patch(patch)
weight = 'bold' if bold else 'normal'
ax.text(x, y, text, ha='center', va='center', fontsize=fontsize,
color=textcolor, fontweight=weight, wrap=True,
multialignment='center', zorder=4,
bbox=dict(boxstyle='square,pad=0', facecolor='none', edgecolor='none'))
def diamond(ax, x, y, w, h, text, facecolor=None, textcolor='white', fontsize=8.5):
if facecolor is None:
facecolor = C['decision']
dx, dy = w/2, h/2
pts = [(x, y+dy), (x+dx, y), (x, y-dy), (x-dx, y)]
polygon = plt.Polygon(pts, closed=True, facecolor=facecolor,
edgecolor='white', linewidth=1.5, zorder=3)
ax.add_patch(polygon)
ax.text(x, y, text, ha='center', va='center', fontsize=fontsize,
color=textcolor, fontweight='bold', multialignment='center', zorder=4)
def arrow(ax, x1, y1, x2, y2, label='', color=None):
if color is None:
color = C['arrow']
ax.annotate('', xy=(x2, y2), xytext=(x1, y1),
arrowprops=dict(arrowstyle='->', color=color,
lw=2.0, connectionstyle='arc3,rad=0.0'),
zorder=2)
if label:
mx, my = (x1+x2)/2, (y1+y2)/2
ax.text(mx+0.15, my, label, fontsize=7.5, color=color,
fontweight='bold', va='center', zorder=5)
def harrow(ax, x1, y1, x2, y2, label='', color=None):
"""Horizontal-then-vertical arrow via a bend."""
if color is None:
color = C['arrow']
ax.annotate('', xy=(x2, y2), xytext=(x1, y1),
arrowprops=dict(arrowstyle='->', color=color, lw=1.8,
connectionstyle='angle,angleA=0,angleB=90,rad=6'),
zorder=2)
if label:
ax.text((x1+x2)/2, (y1+y2)/2 + 0.15, label, fontsize=7.5, color=color,
fontweight='bold', ha='center', zorder=5)
# ── Title ─────────────────────────────────────────────────────────────────────
ax.text(11, 31.3, 'COLITIS — DIAGNOSTIC WORKUP FLOWCHART',
ha='center', va='center', fontsize=16, fontweight='bold',
color=C['start'],
bbox=dict(boxstyle='round,pad=0.4', facecolor='#E8EAF6', edgecolor=C['start'], lw=2))
# ══════════════════════════════════════════════════════════════════════════════
# ROW 1 – Presentation
# ══════════════════════════════════════════════════════════════════════════════
Y1 = 29.5
box(ax, 11, Y1, 9, 0.9,
'PATIENT PRESENTATION\nDiarrhea ± blood | Abdominal pain | Urgency / tenesmus',
C['start'], fontsize=9, bold=True)
arrow(ax, 11, Y1-0.45, 11, Y1-1.15)
# ══════════════════════════════════════════════════════════════════════════════
# ROW 2 – History & Exam
# ══════════════════════════════════════════════════════════════════════════════
Y2 = 27.9
box(ax, 11, Y2, 14, 1.1,
'HISTORY & PHYSICAL EXAM\nOnset (acute vs chronic) | Blood in stool? | Recent antibiotics / NSAIDs / travel\n'
'Wt loss, fever, fistulae, perianal disease | Family history IBD | Cardiovascular risk (ischemia)',
C['step'], fontsize=8.5, bold=False)
arrow(ax, 11, Y2-0.55, 11, Y2-1.3)
# ══════════════════════════════════════════════════════════════════════════════
# ROW 3 – First branch: Acute vs Chronic
# ══════════════════════════════════════════════════════════════════════════════
Y3 = 26.1
diamond(ax, 11, Y3, 5.5, 1.1,
'Onset\nACUTE (<3 wks) or CHRONIC (>3 wks)?',
fontsize=8.5)
# ── LEFT branch: ACUTE ────────────────────────────────────────────────────────
harrow(ax, 8.25, Y3, 4.5, Y3, label='ACUTE', color=C['warn'])
Y3L = 26.1
box(ax, 3.0, Y3L, 4.8, 1.2,
'ACUTE COLITIS WORKUP\n① Stool MC&S (Salmonella, Shigella,\n'
' Campylobacter, E.coli O157, Yersinia)\n'
'② C. difficile toxin PCR (EIA/GDH)\n'
'③ Ova & Parasites (travel history)\n'
'④ CBC, CRP, electrolytes, LFTs',
C['lab'], fontsize=7.5)
arrow(ax, 3.0, Y3L-0.6, 3.0, Y3L-1.45)
Y3La = 24.3
diamond(ax, 3.0, Y3La, 4.2, 0.95,
'Stool cultures / C. diff\nPOSITIVE?', fontsize=8)
arrow(ax, 3.0, Y3La-0.47, 3.0, Y3La-1.1, label='YES')
box(ax, 3.0, 22.8, 4.2, 0.85,
'⚕ INFECTIOUS COLITIS\nTargeted antimicrobial / supportive Rx',
C['dx'], fontsize=8, bold=True)
# "No" from acute → proceeds to chronic workup
harrow(ax, 5.1, Y3La, 8.0, Y3La-1.0, label='NO → proceed\nas chronic', color='#37474F')
# ── RIGHT branch: CHRONIC ─────────────────────────────────────────────────────
harrow(ax, 13.75, Y3, 17.5, Y3, label='CHRONIC', color=C['step'])
Y3R = 26.1
box(ax, 19.0, Y3R, 4.8, 1.2,
'⚠ RED FLAGS → URGENT\n• Bloody diarrhea + fever + tachycardia\n'
'• Toxic megacolon (distension, peritonism)\n'
'• Haemodynamic instability\n→ Admit, IV fluids, urgent imaging',
C['warn'], fontsize=7.5)
# ══════════════════════════════════════════════════════════════════════════════
# ROW 4 – Initial Labs (chronic / after excluding infection)
# ══════════════════════════════════════════════════════════════════════════════
Y4 = 24.1
arrow(ax, 11, Y3-0.55, 11, Y4+0.55) # centre arrow from diamond down
box(ax, 11, Y4, 14, 1.1,
'INITIAL INVESTIGATIONS\n'
'Bloods: CBC | CRP / ESR | CMP (albumin, LFTs, creatinine) | Iron studies | B12 / Folate | TFTs\n'
'Stool: Fecal calprotectin | C. diff PCR | MC&S | Ova & Parasites',
C['lab'], fontsize=8.5)
arrow(ax, 11, Y4-0.55, 11, Y4-1.3)
# ══════════════════════════════════════════════════════════════════════════════
# ROW 5 – Fecal Calprotectin branch
# ══════════════════════════════════════════════════════════════════════════════
Y5 = 22.4
diamond(ax, 11, Y5, 6.0, 1.1,
'Fecal Calprotectin\n< 50 µg/g or ≥ 50 µg/g?', fontsize=8.5)
# Low calprotectin → left
harrow(ax, 8.0, Y5, 4.5, Y5, label='< 50', color=C['tx'])
box(ax, 3.0, Y5, 4.0, 0.85,
'IBD unlikely\nConsider IBS / functional disorder\nReview & reassess if symptoms persist',
C['tx'], fontsize=7.5)
# High calprotectin → continue
arrow(ax, 11, Y5-0.55, 11, Y5-1.2, label='≥ 50', color=C['decision'])
# ══════════════════════════════════════════════════════════════════════════════
# ROW 6 – Serology
# ══════════════════════════════════════════════════════════════════════════════
Y6 = 20.9
box(ax, 11, Y6, 13, 0.95,
'SEROLOGY (to help differentiate IBD subtypes)\n'
'pANCA (UC positive ~60-70%) | ASCA IgG/IgA (Crohn positive ~50-60%) | Anti-OmpC | Anti-CBir1',
C['lab'], fontsize=8.5)
arrow(ax, 11, Y6-0.47, 11, Y6-1.2)
# ══════════════════════════════════════════════════════════════════════════════
# ROW 7 – Colonoscopy branch
# ══════════════════════════════════════════════════════════════════════════════
Y7 = 19.3
box(ax, 11, Y7, 13, 1.0,
'COLONOSCOPY + ILEOSCOPY WITH BIOPSY (gold standard)\n'
'Note: extent & pattern of inflammation | mucosal appearance | multiple biopsies ≥6 sites',
C['step'], fontsize=8.5, bold=True)
arrow(ax, 11, Y7-0.5, 11, Y7-1.25)
# ══════════════════════════════════════════════════════════════════════════════
# ROW 8 – Endoscopic findings branch (3 columns)
# ══════════════════════════════════════════════════════════════════════════════
Y8 = 17.65
diamond(ax, 11, Y8, 9, 1.0,
'ENDOSCOPIC + HISTOLOGICAL PATTERN?', fontsize=9)
# ── UC column ────────────────────────────────────────────────────────────────
XUC = 3.5
harrow(ax, 6.5, Y8, XUC+1.8, Y8, label='Continuous\nmucosal', color='#1565C0')
Y8a = 17.65
box(ax, XUC, Y8a-1.3, 5.2, 1.75,
'ULCERATIVE COLITIS\n──────────────\n'
'• Continuous from rectum\n'
'• Erythema, granularity,\n pseudopolyps\n'
'• Mucosa / submucosa only\n'
'• No fistulae or granulomas',
'#1565C0', fontsize=8, bold=True)
# ── Crohn column ─────────────────────────────────────────────────────────────
XCD = 11
harrow(ax, 11, Y8-0.5, XCD, Y8-1.55, label='', color=C['step'])
box(ax, XCD, Y8-2.05, 5.2, 1.75,
"CROHN'S DISEASE\n──────────────\n"
'• Skip lesions, any GI segment\n'
'• Deep fissures, cobblestoning\n'
'• Transmural, creeping fat\n'
'• Granulomas (~35%)',
'#6A1B9A', fontsize=8, bold=True)
# ── Normal endoscopy column ──────────────────────────────────────────────────
XMC = 18.5
harrow(ax, 15.5, Y8, XMC-1.8, Y8, label='Normal\nappearance', color='#2E7D32')
box(ax, XMC, Y8a-1.3, 5.2, 1.75,
'MICROSCOPIC COLITIS\n──────────────\n'
'• Normal mucosa on endoscopy\n'
'• Biopsy: collagen band >10µm\n (collagenous) or IEL >20/100\n (lymphocytic)\n'
'• Watery non-bloody diarrhea',
'#2E7D32', fontsize=8, bold=True)
# ══════════════════════════════════════════════════════════════════════════════
# ROW 9 – Cannot distinguish UC vs Crohn → further imaging
# ══════════════════════════════════════════════════════════════════════════════
Y9 = 14.9
# Arrow from Crohn box down to "indeterminate / need small bowel imaging"
arrow(ax, XCD, Y8-2.93, XCD, Y9+0.55)
box(ax, XCD, Y9, 6.0, 1.0,
'INDETERMINATE or NEED SMALL BOWEL EVAL?\n'
'→ MR Enterography (preferred, no radiation)\n'
'→ CT Enterography (widely available)\n'
'→ Capsule Endoscopy (rule out stricture first)',
C['lab'], fontsize=8)
# ══════════════════════════════════════════════════════════════════════════════
# ROW 10 – Ischemic colitis pathway (side branch from history)
# ══════════════════════════════════════════════════════════════════════════════
# Draw as a side note from the clinical features step
Y10 = 20.0
box(ax, 19.5, Y10, 4.8, 2.2,
'SUSPECT ISCHEMIC COLITIS\nif:\n'
'• Elderly + CVD risk factors\n'
'• Sudden pain → bloody diarrhea\n'
'• Post-aortic surgery\n──────────────\n'
'① CT Abdomen/Pelvis with contrast\n'
' (thumbprinting, wall thickening)\n'
'② Flexible sigmoidoscopy / colonoscopy\n'
' (when stable, avoid air insufflation)\n'
'③ Mesenteric angiography (if occlusive)',
C['warn'], fontsize=7.5)
ax.text(16.8, 25.5, '▶ If ischaemic\n pattern', fontsize=7.5, color=C['warn'],
fontweight='bold', ha='center')
ax.annotate('', xy=(19.5, Y10+1.1), xytext=(17.3, Y2-0.6),
arrowprops=dict(arrowstyle='->', color=C['warn'], lw=1.5,
connectionstyle='arc3,rad=0.2'), zorder=2)
# ══════════════════════════════════════════════════════════════════════════════
# ROW 11 – Final Diagnosis summary bar
# ══════════════════════════════════════════════════════════════════════════════
Y11 = 13.3
box(ax, 11, Y11, 20, 0.75,
'FINAL DIAGNOSIS → Classify, Stage Severity, and Plan Management',
C['start'], fontsize=10, bold=True)
# 5 diagnosis boxes
DX_Y = 11.9
dx_labels = [
('ULCERATIVE\nCOLITIS', '#1565C0'),
("CROHN'S\nDISEASE", '#6A1B9A'),
('ISCHEMIC\nCOLITIS', '#C62828'),
('INFECTIOUS\nCOLITIS', '#2E7D32'),
('MICROSCOPIC\nCOLITIS', '#00695C'),
]
dx_x = [2.3, 6.3, 11, 15.7, 19.7]
for (lbl, col), x in zip(dx_labels, dx_x):
box(ax, x, DX_Y, 3.4, 0.95, lbl, col, fontsize=8.5, bold=True)
ax.annotate('', xy=(x, DX_Y+0.47), xytext=(11, Y11-0.37),
arrowprops=dict(arrowstyle='->', color=col, lw=1.2,
connectionstyle='arc3,rad=0.0'), zorder=1)
# ══════════════════════════════════════════════════════════════════════════════
# ROW 12 – Treatment summary per type
# ══════════════════════════════════════════════════════════════════════════════
TX_Y = 10.4
tx_data = [
('5-ASA (mild-mod)\nCorticosteroids (acute)\nAzathioprine/6-MP\nBiologics (anti-TNF,\nvedolizumab, ustekinumab)\nSurgery: proctocolectomy', '#BBDEFB', '#0D47A1'),
('Corticosteroids\nAzathioprine / MTX\nBiologics (anti-TNF,\nvedolizumab, ustekinumab)\nSurgery: bowel resection\n(not curative)', '#E1BEE7', '#4A148C'),
('Conservative (mild):\nIV fluids, bowel rest, O2\nSurgery (severe):\ncolectomy for gangrene\nor perforation', '#FFCDD2', '#B71C1C'),
('C. diff: oral vancomycin\nor fidaxomicin\nBacterial: supportive\n± targeted antibiotics\nSevere/recurrent C.diff:\nFMT', '#C8E6C9', '#1B5E20'),
('Stop offending drugs\n(NSAIDs, PPIs, SSRIs)\nBudesonide (first line)\nBismuth subsalicylate\nCholestyramine', '#B2DFDB', '#004D40'),
]
tx_x = [2.3, 6.3, 11, 15.7, 19.7]
for (tx, bg, tc), x in zip(tx_data, tx_x):
box(ax, x, TX_Y, 3.7, 1.9, tx, bg, textcolor=tc, fontsize=7, bold=False)
arrow(ax, x, DX_Y-0.47, x, TX_Y+0.95)
# Treatment header labels
for lbl, x in zip(['UC Rx', "CD Rx", 'Ischaemic Rx', 'Infectious Rx', 'Microscopic Rx'], tx_x):
ax.text(x, TX_Y+1.1, lbl, ha='center', va='bottom', fontsize=7.5,
color='#37474F', fontweight='bold')
# ══════════════════════════════════════════════════════════════════════════════
# LEGEND
# ══════════════════════════════════════════════════════════════════════════════
legend_y = 8.8
ax.text(1.0, legend_y, 'LEGEND:', fontsize=8, fontweight='bold', color='#37474F')
legend_items = [
(C['start'], 'Start / End / Final step'),
(C['step'], 'Process / Action'),
(C['decision'], 'Decision point'),
(C['lab'], 'Investigations / Labs'),
(C['dx'], 'Diagnosis'),
(C['warn'], 'Urgent / Red flag'),
(C['tx'], 'Treatment / Management'),
]
for i, (col, lbl) in enumerate(legend_items):
xi = 1.0 + i * 2.95
p = FancyBboxPatch((xi-0.3, legend_y-0.55), 0.6, 0.4,
boxstyle='round,pad=0.05', facecolor=col,
edgecolor='white', lw=1)
ax.add_patch(p)
ax.text(xi+0.45, legend_y-0.38, lbl, va='center', fontsize=7, color='#37474F')
# ══════════════════════════════════════════════════════════════════════════════
# Footer
# ══════════════════════════════════════════════════════════════════════════════
ax.text(11, 7.9,
'Sources: Symptom to Diagnosis (4e) • Sabiston Textbook of Surgery (21e) • '
'Sleisenger & Fordtran\'s GI & Liver Disease • Robbins Pathologic Basis of Disease',
ha='center', va='center', fontsize=7, color='#78909C', style='italic')
plt.tight_layout(pad=0.5)
plt.savefig('/tmp/workspace/colitis-flowchart/colitis_diagnostic_flowchart.png',
dpi=180, bbox_inches='tight', facecolor=fig.get_facecolor())
plt.close()
print("Saved successfully.")
cd /tmp/workspace/colitis-flowchart && python generate_flowchart.py 2>&1
ls -lh /tmp/workspace/colitis-flowchart/colitis_diagnostic_flowchart.png
colitis diagnostic flowchart
Image · PNG