immunomodulatory therapy for non infectious uveitis
"noninfectious uveitis" AND "immunomodulatory therapy"
PMID: 41412963
PMID: 41265720
| Drug | Typical Dose | Notes |
|---|---|---|
| Methotrexate (MTX) | 10-25 mg/week PO/SC + folate | Most widely used; effective for JIA uveitis, intermediate uveitis; monitor LFTs, CBC |
| Mycophenolate mofetil (MMF) | 1000-2000 mg/day | Often preferred for posterior/panuveitis; favorable efficacy/safety per recent meta-analysis |
| Azathioprine | 1-3 mg/kg/day | Check TPMT enzyme activity before starting; risk of lymphoma with anti-TNF combination |
Recent evidence (2026 meta-analysis, PMID 41412963): Among 16 RCTs covering 11 IMT agents, mycophenolic acid showed a favorable trend in both efficacy and safety. The overall treatment failure rate at 6 months was ~37.6%, underscoring that NIU relapse risk remains significant even on IMT.
| Drug | Notes |
|---|---|
| Cyclosporin A | 2.5-5 mg/kg/day; monitor BP and creatinine |
| Tacrolimus | More potent than cyclosporin; lower dose needed |
| Voclosporin / Sirolimus | Newer agents in this class |
| Drug | Notes |
|---|---|
| Cyclophosphamide | 1-5 mg/kg/day; used in severe systemic vasculitis with uveitis (e.g., Behçet, ANCA+ scleritis) |
| Chlorambucil | Rarely used now; historically for Behçet disease |
| Drug | Route | Approved for NIU |
|---|---|---|
| Adalimumab | SC 40 mg every 2 weeks | Yes - FDA approved for NIU |
| Infliximab | IV 5 mg/kg at 0, 2, 6 weeks, then every 8 weeks | Yes |
| Etanercept | SC | Less effective for uveitis; NOT recommended for isolated uveitis |
| Golimumab | SC | Yes |
| Certolizumab pegol | SC 200 mg q2 weeks or 400 mg monthly | Yes |
Key trial evidence: The VISUAL I and VISUAL II trials established adalimumab as the first FDA-approved biologic specifically for NIU. The 2026 meta-analysis (Wang et al., PMID 41412963) confirmed: adalimumab + corticosteroids significantly reduced hazard of treatment failure (HR 0.51, 95% CrI 0.24-0.95) vs corticosteroids alone.
Biosimilar switching (PMID 41265720): A 2026 systematic review found switching from originator adalimumab/infliximab to biosimilars was not associated with increased flare rates (IRR 1.20, 95% CI 0.79-1.83), supporting clinical equivalence - though ~10% reverted due to tolerability issues.
| Dominant Immune Cell Type | Disease Examples | Preferred Biologic Class |
|---|---|---|
| T-cell critical | VKH, birdshot retinochoroidopathy | Calcineurin inhibitors + anti-TNF |
| Neutrophil/macrophage critical | Behçet disease, sarcoidosis | Anti-TNF agents (infliximab preferred for Behçet) |
| B-cell critical | ANCA+ scleritis, refractory granulomatous | Rituximab |
| Drug | Key Monitoring |
|---|---|
| Methotrexate | LFTs, CBC, renal function; avoid alcohol; folate supplementation |
| Azathioprine | CBC, LFTs; TPMT genotyping before start |
| Mycophenolate mofetil | CBC, renal function |
| Cyclosporin A | BP, creatinine, drug levels |
| Anti-TNF agents | TB screening, CBC, LFTs; screen for HBV reactivation; contraindicated in NYHA III/IV heart failure, demyelinating disease, optic neuropathy |
| Rituximab | Infusion reactions; hepatitis B reactivation; PML risk |
Topical steroids + cycloplegics
↓ (if inadequate or posterior disease)
Systemic corticosteroids
↓ (if steroid-sparing needed, or refractory)
Antimetabolite (MTX or MMF as first choice)
+/- Calcineurin inhibitor (for T-cell dominant disease)
↓ (if refractory to non-biologic DMARD)
Biologic: Adalimumab or Infliximab (anti-TNF first-line)
↓ (if TNF-inhibitor refractory)
Tocilizumab / Rituximab / Abatacept (depending on disease type)
do you know about sketchy medical ?
can you make similar images for few topics for me
ries buvckler and thiel benke corneal dystrophies
Sketchy Medical style mnemonic illustration for Reis-Bucklers Corneal Dystrophy. A detailed cartoon scene: A GEOGRAPHY CLASSROOM with a MAP on the wall showing grey-white geographic landmass shapes (representing grey-white geographic subepithelial opacities). The teacher is a BUCKET (Reis-BUCKLERS = bucket) wearing a graduation cap. A CHILD student (onset in childhood) is crying in pain holding their eye (recurrent corneal erosions). A BULLDOZER is destroying a FLOOR (Bowman layer replaced by connective tissue). The WINDOW is frosted with a net/reticular pattern that gets thicker from center outward (increasing density centrally, reticular pattern with age). A LASER GUN is on the desk as treatment tool (Excimer laser PTK). There is a DNA strand labeled "TGFB1" and "AD" (autosomal dominant, TGFB1 gene). Label key objects with their mnemonics. Vibrant colors, rich detail, educational cartoon style like Sketchy Medical.
Sketchy Medical style mnemonic illustration for Thiel-Behnke Corneal Dystrophy. A detailed cartoon scene: A BEEHIVE scene (Thiel-BEHNKE sounds like "Bee-nk" and it is called HONEYCOMB dystrophy). Giant honeycomb hexagonal patterns are visible on a WINDOW (central cornea). A CHILD holding their eye (recurrent erosions in childhood). The FLOOR/GROUND has CURLY WORMS on it (Bowman layer curly fibres on electron microscopy). The opacities are shown as tiny rings arranged in a honeycomb network pattern - less individually defined than bricks (less severe than Reis-Bucklers). A DNA strand labeled "TGFB1" and "AD" (autosomal dominant). A BEE CHARACTER labeled "CBD2" (corneal basement dystrophy type 2). A sign says "Milder than next door" with an arrow pointing offscreen (less severe than Reis-Bucklers). Treatment area shows a small X (treatment not always necessary). Vibrant colors, rich detail, educational cartoon style like Sketchy Medical.
400, message: Got more than 4194304 bytes when reading: b'data: {"candidates": [{"content": {"role": "model","parts": [{"inlineData": {"mimeType": "image/png"...'.
We encountered an error while processing your request. Please try again or reach out to us for help.
?
Sketchy Medical style mnemonic illustration for Reis-Bucklers Corneal Dystrophy. A cartoon classroom scene: A BUCKET wearing a graduation cap stands at the front (Reis-BUCKLERS = bucket). A MAP on the wall shows grey-white geographic landmass shapes (geographic subepithelial opacities). A CHILD student crying holding their eye (recurrent erosions in childhood). A BULLDOZER destroying the FLOOR (Bowman layer replaced by connective tissue). A frosted window with reticular net pattern denser in the center (central opacities, reticular with age). A LASER on the desk (Excimer laser PTK treatment). DNA helix labeled TGFB1 and AD. Vibrant Sketchy Medical cartoon style with labeled mnemonics.
400, message: Got more than 4194304 bytes when reading: b'data: {"candidates": [{"content": {"role": "model","parts": [{"inlineData": {"mimeType": "image/png"...'.
We encountered an error while processing your request. Please try again or reach out to us for help.
try again
Sketchy Medical mnemonic scene for Reis-Bucklers corneal dystrophy. A cartoon bucket character destroying a floor with a bulldozer, a geographic map on the wall, a crying child, a laser gun, and a DNA strand labeled TGFB1. Simple colorful educational illustration.
400, message: Got more than 4194304 bytes when reading: b'data: {"candidates": [{"content": {"role": "model","parts": [{"inlineData": {"mimeType": "image/png"...'.
We encountered an error while processing your request. Please try again or reach out to us for help.
?
| Object/Character | What it represents |
|---|---|
| 🪣 Bucket teacher | Reis-Bücklers |
| 🗺️ Grey geographic MAP on the wall | Grey-white geographic subepithelial opacities |
| 🧒 Crying child student | Onset in childhood, recurrent painful erosions |
| 🏗️ Bulldozer destroying the FLOOR | Bowman layer replaced by connective tissue |
| 🕸️ Reticular net on window (dense at center) | Opacities become reticular, denser centrally |
| 🔫 Laser gun on the desk | Treatment: Excimer laser PTK |
| 🧬 DNA helix labeled "TGFB1 / AD" | Autosomal dominant, TGFB1 gene |
| 👁️ Numb eye on poster | Reduced corneal sensation |
| Tag: "CBD1" | Corneal Basement Dystrophy type 1 |
| Object/Character | What it represents |
|---|---|
| 🍯 Honeycomb everywhere | Called honeycomb-shaped corneal dystrophy |
| 🐝 Smaller, calmer bees | Less severe than Reis-Bücklers |
| 🧒 Child with mild eye rub | Recurrent erosions in childhood (milder) |
| 🐛 Curly worms on the floor | Curly fibres on electron microscopy (Bowman layer) |
| 🪟 Honeycomb window (tiny rings, central) | Subepithelial opacities in network of tiny rings, central cornea |
| 🚫 No treatment sign | Treatment not always necessary |
| 🧬 DNA labeled "TGFB1 / AD" | Autosomal dominant, TGFB1 gene |
| Tag: "CBD2" | Corneal Basement Dystrophy type 2 |
| Feature | Reis-Bücklers | Thiel-Behnke |
|---|---|---|
| Nickname | CBD1 | CBD2 (Honeycomb) |
| Gene | TGFB1 | TGFB1 (+others) |
| Inheritance | AD | AD |
| Histology | Connective tissue replacing Bowman | Curly fibres (EM) |
| Opacities | Geographic, reticular | Honeycomb rings |
| Severity | More severe | Less severe |
| Erosions | Severe, childhood | Mild, childhood |
| Treatment | Excimer PTK / keratectomy | Often not needed |
heres all the info you can use in generation of image
Sketchy Medical style mnemonic cartoon for Reis-Bucklers Corneal Dystrophy (RBCD). Single illustrated scene: A cartoon BUCKET character (Bucklers) as a child student (childhood onset) standing in front of a GEOGRAPHIC MAP with grey irregular landmass shapes on it (geographic opacification on slit lamp). The bucket is crying and holding its eye in pain (painful, affects vision). On the floor are ROD-SHAPED objects like rods/sticks (rod-shaped fibers on electron microscopy). The Bowman membrane shown as a SHEET of paper being torn (sheets appearance on light microscopy). A paint jar labeled MASSON TRICHROME with red color (stains red with Masson trichrome). A DNA double helix labeled TGFBI BIGH3 in the corner. Bold fun cartoon style, colorful, educational, labeled objects, Sketchy Medical aesthetic.
400, message: Got more than 4194304 bytes when reading: b'data: {"candidates": [{"content": {"role": "model","parts": [{"inlineData": {"mimeType": "image/png"...'.
We encountered an error while processing your request. Please try again or reach out to us for help.
?
Generate the images as downloadable PNG files using Python
mkdir -p /tmp/workspace/corneal-dystrophies && python3 -c "from PIL import Image; print('Pillow OK')"
~/corneal-dystrophies/rbcd.py
from PIL import Image, ImageDraw, ImageFont
import math, os
W, H = 1400, 900
img = Image.new("RGB", (W, H), "#FFFDF0")
draw = ImageDraw.Draw(img)
# ── font helpers ──────────────────────────────────────────────────────────────
def font(size, bold=False):
candidates = [
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf" if bold else
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
"/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf" if bold else
"/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf",
]
for p in candidates:
if os.path.exists(p):
return ImageFont.truetype(p, size)
return ImageFont.load_default()
def txt(draw, text, xy, size=18, color="#222", bold=False, anchor="la"):
draw.text(xy, text, font=font(size, bold), fill=color, anchor=anchor)
# ── BACKGROUND SECTIONS ───────────────────────────────────────────────────────
# Sky blue top strip
draw.rectangle([0, 0, W, 80], fill="#D0EEFF")
# Warm ground strip
draw.rectangle([0, H-120, W, H], fill="#C8E6C9")
# ── TITLE BANNER ──────────────────────────────────────────────────────────────
draw.rounded_rectangle([30, 10, 780, 70], radius=18, fill="#B71C1C")
txt(draw, "REIS-BÜCKLERS Corneal Dystrophy (RBCD)", (50, 38), size=26, color="white", bold=True)
# ── GENE BADGE ────────────────────────────────────────────────────────────────
draw.rounded_rectangle([820, 15, 1050, 65], radius=14, fill="#1565C0")
txt(draw, "Gene: TGFBI (BIGH3)", (835, 38), size=20, color="white", bold=True)
draw.rounded_rectangle([1070, 15, 1250, 65], radius=14, fill="#6A1B9A")
txt(draw, "Inheritance: AD", (1085, 38), size=20, color="white", bold=True)
# ══════════════════════════════════════════════════════════════════════════════
# 1. BUCKET CHARACTER (left)
# ══════════════════════════════════════════════════════════════════════════════
bx, by = 110, 200 # bucket center-top
# bucket body (trapezoid)
draw.polygon([(bx-55, by+40),(bx+55, by+40),(bx+45, by+130),(bx-45, by+130)],
fill="#FFD600", outline="#222", width=3)
# bucket rim
draw.rectangle([bx-58, by+35, bx+58, by+50], fill="#FFC107", outline="#222", width=2)
# bucket handle
draw.arc([bx-40, by-10, bx+40, by+40], start=0, end=180, fill="#222", width=4)
# face
draw.ellipse([bx-30, by+55, bx+30, by+100], fill="#FFE082", outline="#222", width=2)
# crying eyes
draw.ellipse([bx-18, by+65, bx-8, by+75], fill="white", outline="#222", width=1)
draw.ellipse([bx+8, by+65, bx+18, by+75], fill="white", outline="#222", width=1)
draw.ellipse([bx-15, by+68, bx-10, by+73], fill="#1565C0") # pupils
draw.ellipse([bx+10, by+68, bx+15, by+73], fill="#1565C0")
# tears
draw.line([bx-13, by+75, bx-16, by+88], fill="#64B5F6", width=3)
draw.line([bx+13, by+75, bx+16, by+88], fill="#64B5F6", width=3)
# mouth (frown)
draw.arc([bx-12, by+82, bx+12, by+98], start=200, end=340, fill="#222", width=3)
# arms
draw.line([bx-55, by+70, bx-90, by+100], fill="#FFD600", width=8)
draw.line([bx+55, by+70, bx+90, by+100], fill="#FFD600", width=8)
# label
txt(draw, "🪣 BUCKET = Bücklers", (bx-60, by+145), size=16, color="#B71C1C", bold=True)
txt(draw, "Childhood onset", (bx-50, by+168), size=15, color="#333")
# ══════════════════════════════════════════════════════════════════════════════
# 2. GEOGRAPHIC MAP (center-left)
# ══════════════════════════════════════════════════════════════════════════════
mx, my = 330, 130
draw.rounded_rectangle([mx, my, mx+220, my+200], radius=8, fill="#E3F2FD", outline="#1565C0", width=3)
txt(draw, "🗺 GEOGRAPHIC MAP", (mx+10, my+8), size=15, color="#1565C0", bold=True)
# landmass blobs (grey-white geographic opacities)
for ox, oy, ow, oh in [(mx+25,my+45,90,55),(mx+100,my+60,70,40),(mx+50,my+100,80,45),(mx+130,my+110,60,35)]:
draw.ellipse([ox,oy,ox+ow,oy+oh], fill="#B0BEC5", outline="#78909C", width=2)
txt(draw, "Grey-white Geographic", (mx+10, my+158), size=14, color="#333")
txt(draw, "Subepithelial Opacities", (mx+10, my+175), size=14, color="#333")
txt(draw, "(Dense centrally)", (mx+30, my+192), size=13, color="#555", bold=False)
# ══════════════════════════════════════════════════════════════════════════════
# 3. BOWMAN LAYER — SHEETS (center)
# ══════════════════════════════════════════════════════════════════════════════
sx, sy = 600, 120
draw.rounded_rectangle([sx, sy, sx+230, sy+210], radius=8, fill="#FFF8E1", outline="#F57F17", width=3)
txt(draw, "📄 SHEETS (LM)", (sx+10, sy+8), size=15, color="#F57F17", bold=True)
# sheet stack
for i in range(4):
draw.rectangle([sx+20+i*6, sy+45+i*6, sx+200+i*2, sy+80+i*6],
fill="white", outline="#BDBDBD", width=2)
txt(draw, "Bowman layer replaced", (sx+12, sy+120), size=14, color="#333")
txt(draw, "by connective tissue", (sx+12, sy+137), size=14, color="#333")
txt(draw, "→ 'Sheets' on LM", (sx+20, sy+158), size=14, color="#E65100", bold=True)
# ══════════════════════════════════════════════════════════════════════════════
# 4. ROD-SHAPED FIBRES (EM)
# ══════════════════════════════════════════════════════════════════════════════
rx, ry = 880, 120
draw.rounded_rectangle([rx, ry, rx+220, ry+210], radius=8, fill="#F3E5F5", outline="#6A1B9A", width=3)
txt(draw, "🔬 ROD FIBRES (EM)", (rx+10, ry+8), size=15, color="#6A1B9A", bold=True)
for i, (rox, roy, angle) in enumerate([
(rx+30, ry+60, 15),(rx+70, ry+50, -10),(rx+110, ry+65, 20),
(rx+50, ry+100, 5),(rx+90, ry+110, -15),(rx+130, ry+95, 10),
(rx+40, ry+140, 8),(rx+100, ry+145, -12),(rx+150, ry+130, 18),
]):
# draw rod as thick rounded rectangle rotated-ish via polygon
rad = math.radians(angle)
cx, cy, rl = rox+15, roy+6, 28
pts = []
for dx, dy in [(-rl,-4),(rl,-4),(rl,4),(-rl,4)]:
pts.append((cx + dx*math.cos(rad)-dy*math.sin(rad),
cy + dx*math.sin(rad)+dy*math.cos(rad)))
draw.polygon(pts, fill="#CE93D8", outline="#6A1B9A", width=1)
txt(draw, "Rod-shaped fibres", (rx+20, ry+170), size=14, color="#333")
txt(draw, "on Electron Microscopy", (rx+10, ry+187), size=13, color="#333")
# ══════════════════════════════════════════════════════════════════════════════
# 5. MASSON TRICHROME STAIN (bottom center)
# ══════════════════════════════════════════════════════════════════════════════
stx, sty = 600, 380
draw.rounded_rectangle([stx, sty, stx+230, sty+160], radius=8, fill="#FFEBEE", outline="#B71C1C", width=3)
txt(draw, "🧪 MASSON TRICHROME", (stx+10, sty+10), size=15, color="#B71C1C", bold=True)
# paint jar
draw.ellipse([stx+70, sty+45, stx+160, sty+130], fill="#EF9A9A", outline="#B71C1C", width=3)
draw.rectangle([stx+85, sty+30, stx+145, sty+55], fill="#FFCDD2", outline="#B71C1C", width=2)
txt(draw, "RED", (stx+100, sty+78), size=22, color="#B71C1C", bold=True)
txt(draw, "Stains Red", (stx+75, sty+138), size=15, color="#B71C1C", bold=True)
# ══════════════════════════════════════════════════════════════════════════════
# 6. PAINFUL EYE + VISION LOSS (bottom left)
# ══════════════════════════════════════════════════════════════════════════════
ex, ey = 50, 450
draw.rounded_rectangle([ex, ey, ex+200, ey+160], radius=8, fill="#FCE4EC", outline="#880E4F", width=3)
txt(draw, "👁 SYMPTOMS", (ex+10, ey+10), size=15, color="#880E4F", bold=True)
# eye shape
draw.arc([ex+30, ey+50, ex+170, ey+120], start=200, end=340, fill="#222", width=4)
draw.arc([ex+30, ey+50, ex+170, ey+120], start=20, end=160, fill="#222", width=4)
draw.ellipse([ex+85, ey+68, ex+115, ey+102], fill="#1565C0")
draw.ellipse([ex+90, ey+73, ex+110, ey+97], fill="#111")
# lightning bolts for pain
for lx, ly in [(ex+25, ey+55),(ex+160, ey+55)]:
draw.polygon([(lx,ly),(lx+8,ly+12),(lx+4,ly+12),(lx+10,ly+26),(lx+2,ly+14),(lx+6,ly+14)],
fill="#FFD600", outline="#F57F17", width=1)
txt(draw, "Painful ✓ Vision loss ✓", (ex+10, ey+128), size=14, color="#880E4F", bold=True)
txt(draw, "Recurrent erosions", (ex+20, ey+148), size=13, color="#555")
# ══════════════════════════════════════════════════════════════════════════════
# 7. RETICULAR PATTERN (bottom right)
# ══════════════════════════════════════════════════════════════════════════════
netx, nety = 880, 380
draw.rounded_rectangle([netx, nety, netx+220, nety+160], radius=8, fill="#E8F5E9", outline="#1B5E20", width=3)
txt(draw, "🕸 RETICULAR (with age)", (netx+8, nety+10), size=14, color="#1B5E20", bold=True)
# draw net/grid denser in center
for gx in range(netx+20, netx+210, 20):
draw.line([gx, nety+35, gx, nety+140], fill="#81C784", width=1)
for gy in range(nety+35, nety+145, 18):
draw.line([netx+20, gy, netx+210, gy], fill="#81C784", width=1)
# central denser blob
draw.ellipse([netx+75, nety+60, netx+150, nety+115], fill="#A5D6A7", outline="#388E3C", width=2)
txt(draw, "Dense centrally", (netx+45, nety+128), size=14, color="#1B5E20")
txt(draw, "→ Reticular pattern", (netx+30, nety+145), size=14, color="#1B5E20")
# ══════════════════════════════════════════════════════════════════════════════
# 8. TREATMENT BOX
# ══════════════════════════════════════════════════════════════════════════════
tx, ty = 330, 370
draw.rounded_rectangle([tx, ty, tx+220, ty+160], radius=8, fill="#E1F5FE", outline="#01579B", width=3)
txt(draw, "💊 TREATMENT", (tx+10, ty+10), size=15, color="#01579B", bold=True)
# laser shape
draw.rectangle([tx+80, ty+45, tx+140, ty+70], fill="#FF6F00", outline="#E65100", width=2)
draw.polygon([(tx+140,ty+52),(tx+180,ty+57),(tx+140,ty+62)], fill="#FFEB3B", outline="#F57F17")
draw.line([tx+180, ty+57, tx+210, ty+45], fill="#FFEB3B", width=3)
txt(draw, "Excimer Laser PTK", (tx+18, ty+100), size=14, color="#01579B", bold=True)
txt(draw, "Superficial keratectomy", (tx+10, ty+120), size=13, color="#333")
txt(draw, "Corneal graft (severe)", (tx+10, ty+138), size=13, color="#333")
# ══════════════════════════════════════════════════════════════════════════════
# CONNECTING ARROWS (simple lines)
# ══════════════════════════════════════════════════════════════════════════════
# bucket → map
draw.line([bx+70, by+80, mx, my+100], fill="#9E9E9E", width=2)
# bucket → eye
draw.line([bx, by+200, ex+100, ey], fill="#9E9E9E", width=2)
# ══════════════════════════════════════════════════════════════════════════════
# BOTTOM LEGEND BAR
# ══════════════════════════════════════════════════════════════════════════════
draw.rectangle([0, H-50, W, H], fill="#B71C1C")
items = [
("RBCD = CBD type 1", 30),
("Bowman layer dystrophy", 230),
("TGFBI gene (AD)", 460),
("LM: Sheets", 640),
("EM: Rod-shaped fibres", 800),
("Stain: Masson Trichrome → RED", 1020),
]
for label, lx in items:
txt(draw, label, (lx, H-30), size=15, color="white", bold=True)
# ══════════════════════════════════════════════════════════════════════════════
out = "/tmp/workspace/corneal-dystrophies/RBCD_mnemonic.png"
img.save(out, "PNG")
print(f"Saved: {out} size={os.path.getsize(out)//1024}KB")
python3 /tmp/workspace/corneal-dystrophies/rbcd.py
~/corneal-dystrophies/tbcd.py
from PIL import Image, ImageDraw, ImageFont
import math, os
W, H = 1400, 900
img = Image.new("RGB", (W, H), "#F1FFF4")
draw = ImageDraw.Draw(img)
def font(size, bold=False):
candidates = [
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf" if bold else
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
"/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf" if bold else
"/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf",
]
for p in candidates:
if os.path.exists(p):
return ImageFont.truetype(p, size)
return ImageFont.load_default()
def txt(draw, text, xy, size=18, color="#222", bold=False, anchor="la"):
draw.text(xy, text, font=font(size, bold), fill=color, anchor=anchor)
# Background
draw.rectangle([0, 0, W, 80], fill="#DCEDC8")
draw.rectangle([0, H-120, W, H], fill="#F9FBE7")
# ── TITLE ─────────────────────────────────────────────────────────────────────
draw.rounded_rectangle([30, 10, 800, 70], radius=18, fill="#2E7D32")
txt(draw, "THIEL-BEHNKE Corneal Dystrophy (TBCD)", (50, 38), size=26, color="white", bold=True)
draw.rounded_rectangle([830, 15, 1060, 65], radius=14, fill="#1565C0")
txt(draw, "Gene: TGFBI (BIGH3)", (845, 38), size=20, color="white", bold=True)
draw.rounded_rectangle([1080, 15, 1270, 65], radius=14, fill="#6A1B9A")
txt(draw, "Inheritance: AD", (1095, 38), size=20, color="white", bold=True)
# ══════════════════════════════════════════════════════════════════════════════
# 1. BEE CHARACTER (Behnke = Bee-nke)
# ══════════════════════════════════════════════════════════════════════════════
bx, by = 110, 200
# bee body (oval)
draw.ellipse([bx-45, by+30, bx+45, by+130], fill="#FFD600", outline="#222", width=3)
# bee stripes
for sy2 in [by+55, by+75, by+95, by+115]:
draw.rectangle([bx-45, sy2, bx+45, sy2+10], fill="#222")
# bee head
draw.ellipse([bx-25, by, bx+25, by+45], fill="#FFD600", outline="#222", width=3)
# antennae
draw.line([bx-10, by, bx-25, by-25], fill="#222", width=3)
draw.ellipse([bx-30, by-32, bx-18, by-20], fill="#FF8F00")
draw.line([bx+10, by, bx+25, by-25], fill="#222", width=3)
draw.ellipse([bx+18, by-32, bx+30, by-20], fill="#FF8F00")
# eyes (calmer - no tears)
draw.ellipse([bx-16, by+8, bx-6, by+18], fill="white", outline="#222", width=1)
draw.ellipse([bx+6, by+8, bx+16, by+18], fill="white", outline="#222", width=1)
draw.ellipse([bx-13, by+11, bx-8, by+16], fill="#333")
draw.ellipse([bx+8, by+11, bx+13, by+16], fill="#333")
# smile (milder)
draw.arc([bx-12, by+22, bx+12, by+36], start=20, end=160, fill="#222", width=3)
# wings
draw.ellipse([bx-80, by+20, bx-20, by+80], fill="#B3E5FC", outline="#29B6F6", width=2)
draw.ellipse([bx+20, by+20, bx+80, by+80], fill="#B3E5FC", outline="#29B6F6", width=2)
# label
txt(draw, "🐝 BEE = Behnke", (bx-55, by+148), size=16, color="#2E7D32", bold=True)
txt(draw, "Childhood onset", (bx-48, by+168), size=15, color="#333")
txt(draw, "(milder than RBCD)", (bx-55, by+186), size=14, color="#555")
# ══════════════════════════════════════════════════════════════════════════════
# 2. HONEYCOMB PATTERN (slit lamp appearance)
# ══════════════════════════════════════════════════════════════════════════════
hx, hy = 300, 120
draw.rounded_rectangle([hx, hy, hx+240, hy+220], radius=8, fill="#FFFDE7", outline="#F9A825", width=3)
txt(draw, "🍯 HONEYCOMB (SL)", (hx+10, hy+8), size=15, color="#F9A825", bold=True)
# draw hexagonal honeycomb grid
def hex_pts(cx, cy, r):
return [(cx + r*math.cos(math.radians(60*i-30)),
cy + r*math.sin(math.radians(60*i-30))) for i in range(6)]
hex_r = 22
cols = [(hx+60, hx+105, hx+150, hx+195)]
hex_centers = []
for row in range(4):
offset = 0 if row % 2 == 0 else hex_r * math.cos(math.radians(30))
for col in range(3):
cx = hx + 55 + col * int(hex_r * 1.73) + int(offset)
cy = hy + 50 + row * int(hex_r * 1.5)
if hy+40 < cy < hy+190:
draw.polygon(hex_pts(cx, cy, hex_r), fill="#FFF9C4", outline="#F9A825", width=2)
txt(draw, "'Honeycomb' opacification", (hx+8, hy+178), size=13, color="#555")
txt(draw, "Tiny rings, network pattern", (hx+8, hy+195), size=13, color="#555")
txt(draw, "Central cornea", (hx+40, hy+210), size=13, color="#F9A825", bold=True)
# ══════════════════════════════════════════════════════════════════════════════
# 3. SAW-TOOTHED BOWMAN LAYER (Light Microscopy)
# ══════════════════════════════════════════════════════════════════════════════
sx, sy = 590, 120
draw.rounded_rectangle([sx, sy, sx+230, sy+220], radius=8, fill="#FFF3E0", outline="#E65100", width=3)
txt(draw, "🔬 SAW-TOOTHED (LM)", (sx+8, sy+8), size=14, color="#E65100", bold=True)
# Draw a saw-tooth line
saw_pts = []
start_x = sx + 20
end_x = sx + 210
y_base = sy + 110
tooth_w = 25
tooth_h = 30
x = start_x
while x < end_x:
saw_pts.extend([(x, y_base), (x + tooth_w//2, y_base - tooth_h), (x + tooth_w, y_base)])
x += tooth_w
draw.line(saw_pts, fill="#E65100", width=4)
# Bowman layer label lines
draw.rectangle([sx+20, sy+45, sx+210, sy+60], fill="#FFCC80", outline="#E65100", width=1)
txt(draw, "Bowman layer", (sx+55, sy+48), size=12, color="#333")
draw.rectangle([sx+20, sy+130, sx+210, sy+145], fill="#FFCC80", outline="#E65100", width=1)
txt(draw, "Stroma", (sx+90, sy+133), size=12, color="#333")
txt(draw, "Saw-toothed pattern", (sx+28, sy+165), size=14, color="#E65100", bold=True)
txt(draw, "on Light Microscopy", (sx+32, sy+183), size=13, color="#333")
# ══════════════════════════════════════════════════════════════════════════════
# 4. CURLY FIBRES (Electron Microscopy)
# ══════════════════════════════════════════════════════════════════════════════
cx2, cy2 = 875, 120
draw.rounded_rectangle([cx2, cy2, cx2+230, cy2+220], radius=8, fill="#F3E5F5", outline="#6A1B9A", width=3)
txt(draw, "🔬 CURLY FIBRES (EM)", (cx2+10, cy2+8), size=14, color="#6A1B9A", bold=True)
# draw curly worm-like fibres
import random
random.seed(42)
for i in range(8):
start_x2 = cx2 + 20 + random.randint(0, 160)
start_y2 = cy2 + 45 + random.randint(0, 130)
pts = [(start_x2, start_y2)]
angle2 = random.uniform(0, math.pi*2)
for step in range(12):
angle2 += random.uniform(-0.8, 0.8)
pts.append((pts[-1][0] + math.cos(angle2)*8,
pts[-1][1] + math.sin(angle2)*6))
# clip and draw
clipped = [(max(cx2+5, min(cx2+225, px)), max(cy2+40, min(cy2+210, py))) for px,py in pts]
if len(clipped) > 1:
draw.line(clipped, fill="#CE93D8", width=4)
txt(draw, "CURLY fibres", (cx2+55, cy2+175), size=16, color="#6A1B9A", bold=True)
txt(draw, "on Electron Microscopy", (cx2+15, cy2+195), size=13, color="#333")
# ══════════════════════════════════════════════════════════════════════════════
# 5. MILDER THAN RBCD (comparison box)
# ══════════════════════════════════════════════════════════════════════════════
mx2, my2 = 300, 385
draw.rounded_rectangle([mx2, my2, mx2+230, my2+150], radius=8, fill="#E8F5E9", outline="#2E7D32", width=3)
txt(draw, "⚖ MILDER THAN RBCD", (mx2+10, my2+10), size=14, color="#2E7D32", bold=True)
# RBCD (bigger, darker)
draw.ellipse([mx2+20, my2+50, mx2+90, my2+120], fill="#B0BEC5", outline="#546E7A", width=3)
txt(draw, "RBCD", (mx2+38, my2+128), size=13, color="#546E7A", bold=True)
# TBCD (smaller, lighter)
draw.ellipse([mx2+120, my2+65, mx2+175, my2+115], fill="#DCEDC8", outline="#558B2F", width=2)
txt(draw, "TBCD", (mx2+131, my2+118), size=13, color="#558B2F", bold=True)
txt(draw, "(less severe)", (mx2+70, my2+135), size=12, color="#555")
# CBD2 badge
draw.rounded_rectangle([mx2+150, my2+10, mx2+225, my2+36], radius=8, fill="#558B2F")
txt(draw, "CBD type 2", (mx2+158, my2+20), size=12, color="white", bold=True)
# ══════════════════════════════════════════════════════════════════════════════
# 6. TREATMENT (often not needed)
# ══════════════════════════════════════════════════════════════════════════════
tx2, ty2 = 590, 385
draw.rounded_rectangle([tx2, ty2, tx2+230, ty2+150], radius=8, fill="#ECEFF1", outline="#546E7A", width=3)
txt(draw, "💊 TREATMENT", (tx2+10, ty2+10), size=15, color="#546E7A", bold=True)
# big X / not always sign
draw.ellipse([tx2+70, ty2+40, tx2+160, ty2+120], fill="#CFD8DC", outline="#546E7A", width=2)
draw.line([tx2+85, ty2+55, tx2+145, ty2+105], fill="#F44336", width=6)
draw.line([tx2+145, ty2+55, tx2+85, ty2+105], fill="#F44336", width=6)
txt(draw, "NOT always necessary", (tx2+12, ty2+126), size=13, color="#F44336", bold=True)
txt(draw, "PTK/keratectomy if needed", (tx2+8, ty2+143), size=12, color="#333")
# ══════════════════════════════════════════════════════════════════════════════
# 7. PAINFUL EYE (same as RBCD — both painful)
# ══════════════════════════════════════════════════════════════════════════════
ex2, ey2 = 875, 385
draw.rounded_rectangle([ex2, ey2, ex2+230, ey2+150], radius=8, fill="#FCE4EC", outline="#880E4F", width=3)
txt(draw, "👁 SYMPTOMS", (ex2+10, ey2+10), size=15, color="#880E4F", bold=True)
# eye shape
draw.arc([ex2+30, ey2+40, ex2+200, ey2+120], start=200, end=340, fill="#222", width=4)
draw.arc([ex2+30, ey2+40, ex2+200, ey2+120], start=20, end=160, fill="#222", width=4)
draw.ellipse([ex2+100, ey2+58, ex2+130, ey2+90], fill="#1565C0")
draw.ellipse([ex2+105, ey2+63, ex2+125, ey2+85], fill="#111")
# small tears (milder)
draw.line([ex2+105, ey2+90, ex2+100, ey2+105], fill="#64B5F6", width=3)
draw.line([ex2+125, ey2+90, ex2+130, ey2+105], fill="#64B5F6", width=3)
txt(draw, "Painful ✓ Vision loss ✓", (ex2+20, ey2+118), size=14, color="#880E4F", bold=True)
txt(draw, "Recurrent erosions (milder)", (ex2+10, ey2+136), size=12, color="#555")
# ══════════════════════════════════════════════════════════════════════════════
# BOTTOM LEGEND BAR
# ══════════════════════════════════════════════════════════════════════════════
draw.rectangle([0, H-50, W, H], fill="#2E7D32")
items = [
("TBCD = CBD type 2", 30),
("Bowman layer dystrophy", 230),
("TGFBI gene (AD)", 470),
("LM: Saw-toothed", 650),
("EM: Curly fibres", 840),
("No stain noted | Milder than RBCD", 1020),
]
for label, lx in items:
txt(draw, label, (lx, H-30), size=15, color="white", bold=True)
out = "/tmp/workspace/corneal-dystrophies/TBCD_mnemonic.png"
img.save(out, "PNG")
print(f"Saved: {out} size={os.path.getsize(out)//1024}KB")
python3 /tmp/workspace/corneal-dystrophies/tbcd.py
RBCD mnemonic
Image · PNG
TBCD mnemonic
Image · PNG
| Element | RBCD image | TBCD image |
|---|---|---|
| Main character | 🪣 Bucket (Bücklers) | 🐝 Bee (Behnke) |
| SL appearance | Geographic map blobs | Honeycomb hexagons |
| LM Bowman | Sheets of paper | Saw-toothed line |
| EM fibres | Rod-shaped fibres | Curly worm fibres |
| Stain | Masson Trichrome - RED jar | — |
| Severity | Full size | Smaller (milder) |
| Treatment | Laser gun | Big red ✗ (not always needed) |
| Gene/inheritance | TGFBI / AD badge | TGFBI / AD badge |