Explain in simple words with flowchart and diagrams
Medical education flowchart showing endochondral ossification - the process of bone formation from cartilage. Show step by step: 1) Mesenchymal precursor cells form cartilage mold (anlagen), 2) Central medullary canal forms, 3) Chondroblasts deposit cortex at ~8 weeks, 4) Osteoblasts deposit periosteum at midshaft forming primary ossification center, 5) Radial bone growth occurs, 6) Secondary ossification centers form at epiphysis, 7) Cartilage plates become trapped forming growth plates (physes), 8) Growth plate chondrocytes proliferate, hypertrophy, undergo apoptosis, 9) Matrix mineralization, capillary invasion, osteoblast activation, 10) Calcified cartilage resorbed leaving primary spongiosa (scaffold), 11) Longitudinal bone growth. Also show intramembranous ossification for flat bones (skull) as a separate simpler pathway: mesenchyme directly ossified by osteoblasts without cartilage. Use clean arrows, color coding, medical illustration style with light blue and pink colors.
Medical diagram of the 5 zones of the growth plate (epiphyseal plate) in long bone endochondral ossification, shown as a vertical cross-section with labeled zones from top to bottom: Zone 1 - Reserve Zone (resting chondrocytes, stem cells), Zone 2 - Proliferative Zone (rapidly dividing chondrocytes in columns, growth occurs here), Zone 3 - Hypertrophic Zone (enlarged chondrocytes, matrix mineralization begins), Zone 4 - Zone of Mineralization/Calcification (matrix calcifies, chondrocytes undergo apoptosis), Zone 5 - Primary Spongiosa (bone trabeculae, osteoblasts deposit new bone on calcified cartilage scaffold). Show blood vessels invading from below. Use distinct colors for each zone with arrows showing direction of growth. Clean medical textbook illustration style.
404 Not Found. {'message': '{\n "error": {\n "code": 404,\n "message": "Publisher model `projects/engaged-beaker-474810-u2/locations/global/publishers/google/models/gemini-3-pro-image-preview` was not found or your project does not have access to it. Ensure you are using a valid model name and that the model is available in the specified region. For more information, see: https://docs.cloud.google.com/gemini-enterprise-agent-platform/resources/locations.",\n "status": "NOT_FOUND"\n }\n}\n', 'status': 'Not Found'}
We encountered an error while processing your request. Please try again or reach out to us for help.
Explain simply with flowcharts
mkdir -p /tmp/workspace/bone-diagrams && ls /tmp/workspace/
pip install matplotlib --quiet 2>/dev/null; python3 -c "import matplotlib; print('OK')"
~/bone-diagrams/make_diagrams.py
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.patches import FancyArrowPatch, FancyBboxPatch
import matplotlib.patheffects as pe
import numpy as np
# ─────────────────────────────────────────────────────────────
# DIAGRAM 1: Bone Development – Endochondral vs Intramembranous
# ─────────────────────────────────────────────────────────────
fig, ax = plt.subplots(figsize=(16, 14))
ax.set_xlim(0, 16)
ax.set_ylim(0, 14)
ax.axis('off')
ax.set_facecolor('#F5F9FF')
fig.patch.set_facecolor('#F5F9FF')
def box(ax, x, y, w, h, text, color, fontsize=11, text_color='white', bold=False):
rect = FancyBboxPatch((x - w/2, y - h/2), w, h,
boxstyle="round,pad=0.12", linewidth=1.5,
edgecolor='#333333', facecolor=color, zorder=3)
ax.add_patch(rect)
weight = 'bold' if bold else 'normal'
ax.text(x, y, text, ha='center', va='center', fontsize=fontsize,
color=text_color, fontweight=weight, wrap=True,
multialignment='center', zorder=4)
def arrow(ax, x1, y1, x2, y2, color='#444444'):
ax.annotate('', xy=(x2, y2), xytext=(x1, y1),
arrowprops=dict(arrowstyle='->', color=color, lw=2.0),
zorder=2)
# Title
ax.text(8, 13.5, 'BONE DEVELOPMENT', ha='center', va='center',
fontsize=18, fontweight='bold', color='#1A237E')
ax.text(8, 13.0, 'Two pathways from mesenchymal precursor cells', ha='center',
fontsize=12, color='#555')
# Root node
box(ax, 8, 12.2, 4.2, 0.7, 'Mesenchymal Precursor Cells', '#1A237E', 12, bold=True)
# Branch arrows
arrow(ax, 5.5, 11.85, 4.0, 11.2)
arrow(ax, 10.5, 11.85, 12.0, 11.2)
# LEFT: Endochondral
box(ax, 4, 10.8, 3.8, 0.7, 'ENDOCHONDRAL\nOSSIFICATION', '#0D47A1', 11, bold=True)
ax.text(4, 10.2, 'Most bones\n(long bones, ribs, vertebrae)', ha='center',
fontsize=9.5, color='#0D47A1', style='italic')
steps_endo = [
(4, 9.0, '#1565C0', 'Step 1: Cartilage Mold\n(Anlagen) formed'),
(4, 7.5, '#1976D2', 'Step 2: Medullary canal\nforms inside anlagen'),
(4, 6.0, '#1E88E5', 'Step 3: Osteoblasts deposit\nperiosteum at midshaft\n→ Primary Ossification Center'),
(4, 4.4, '#42A5F5', 'Step 4: Radial + Longitudinal\nGrowth begins'),
(4, 2.9, '#64B5F6', 'Step 5: Secondary Ossification\nCenters at epiphysis'),
(4, 1.4, '#90CAF9', 'Step 6: Growth Plates (physes)\nform between centers'),
]
for i, (x, y, c, t) in enumerate(steps_endo):
box(ax, x, y, 3.7, 0.85, t, c, 9.5, '#FFFFFF' if i < 4 else '#1A237E')
if i > 0:
arrow(ax, x, steps_endo[i-1][1] - 0.43, x, y + 0.43)
# RIGHT: Intramembranous
box(ax, 12, 10.8, 3.8, 0.7, 'INTRAMEMBRANOUS\nOSSIFICATION', '#880E4F', 11, bold=True)
ax.text(12, 10.2, 'Flat bones\n(skull, clavicle, mandible)', ha='center',
fontsize=9.5, color='#880E4F', style='italic')
steps_intra = [
(12, 9.0, '#AD1457', 'Step 1: Dense mesenchyme\nlayer forms'),
(12, 7.5, '#C2185B', 'Step 2: Osteoblasts directly\nossify mesenchyme\n(NO cartilage model!)'),
(12, 5.8, '#E91E63', 'Step 3: Appositional Growth\n(new bone deposited on\npreexisting surface)'),
(12, 4.3, '#F48FB1', 'Step 4: Flat bone formed'),
]
for i, (x, y, c, t) in enumerate(steps_intra):
box(ax, x, y, 3.7, 0.85, t, c, 9.5, '#FFFFFF' if i < 3 else '#880E4F')
if i > 0:
arrow(ax, x, steps_intra[i-1][1] - 0.43, x, y + 0.43)
# Key difference label
ax.text(8, 6.5, 'KEY\nDIFF', ha='center', va='center', fontsize=9,
fontweight='bold', color='#BF360C',
bbox=dict(boxstyle='round', facecolor='#FFF3E0', edgecolor='#BF360C', lw=2))
ax.annotate('', xy=(5.9, 7.2), xytext=(7.0, 6.7),
arrowprops=dict(arrowstyle='->', color='#BF360C', lw=1.5))
ax.annotate('', xy=(10.1, 7.2), xytext=(9.0, 6.7),
arrowprops=dict(arrowstyle='->', color='#BF360C', lw=1.5))
# Bottom note
ax.text(8, 0.5, 'Both processes: Bones enlarge by APPOSITIONAL GROWTH\n'
'(deposition of new bone on a pre-existing surface)',
ha='center', va='center', fontsize=10.5, color='#333',
bbox=dict(boxstyle='round', facecolor='#E8EAF6', edgecolor='#3949AB', lw=2))
plt.tight_layout()
plt.savefig('/tmp/workspace/bone-diagrams/diagram1_bone_development.png',
dpi=150, bbox_inches='tight', facecolor='#F5F9FF')
plt.close()
print("Diagram 1 saved.")
~/bone-diagrams/make_diagram2.py
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.patches import FancyBboxPatch, FancyArrowPatch
import numpy as np
# ─────────────────────────────────────────────────────────────
# DIAGRAM 2: Growth Plate Zones (cross-section style)
# ─────────────────────────────────────────────────────────────
fig, ax = plt.subplots(figsize=(14, 13))
ax.set_xlim(0, 14)
ax.set_ylim(0, 13)
ax.axis('off')
ax.set_facecolor('#FAFAFA')
fig.patch.set_facecolor('#FAFAFA')
ax.text(7, 12.6, 'THE 5 ZONES OF THE GROWTH PLATE', ha='center',
fontsize=17, fontweight='bold', color='#1A237E')
ax.text(7, 12.1, '(Active Endochondral Ossification – Fig 26.3 explained)', ha='center',
fontsize=11, color='#555', style='italic')
zones = [
# (y_center, height, face_color, zone_label, description, cell_color)
(11.0, 1.1, '#E1F5FE', '① RESERVE ZONE\n(Resting Zone)', 'Quiescent chondrocytes stored here\nStem cells waiting to be activated\nNo division happening yet', '#0288D1'),
(9.4, 1.1, '#C8E6C9', '② PROLIFERATIVE ZONE\n(Zone of Multiplication)', 'Chondrocytes rapidly DIVIDE\nStack in columns (like coins)\n↑ GROWTH HORMONE acts here\n⬆ This zone = bone LENGTHENS', '#2E7D32'),
(7.8, 1.1, '#FFF9C4', '③ HYPERTROPHIC ZONE\n(Zone of Enlargement)', 'Chondrocytes SWELL (5-10x bigger)\nMatrix starts to mineralize\nRANKL expressed here\nCells prepare for death', '#F57F17'),
(6.2, 1.1, '#FFCCBC', '④ ZONE OF MINERALIZATION\n(Zone of Calcification)', 'Chondrocytes undergo APOPTOSIS\nMatrix fully calcifies\nCapillaries INVADE this area\nOsteoblasts arrive & activate', '#BF360C'),
(4.6, 1.1, '#E8EAF6', '⑤ PRIMARY SPONGIOSA\n(Earliest Bone)', 'Dead cartilage = scaffold only\nOsteoblasts deposit REAL BONE\non calcified cartilage struts\nFirst true bone trabeculae formed', '#283593'),
]
for (yc, h, fc, label, desc, lc) in zones:
# Zone band
rect = FancyBboxPatch((1.5, yc - h/2), 11, h,
boxstyle="round,pad=0.1", linewidth=2,
edgecolor=lc, facecolor=fc, zorder=2)
ax.add_patch(rect)
# Zone label (left side)
ax.text(2.2, yc, label, ha='left', va='center', fontsize=10,
fontweight='bold', color=lc, zorder=3)
# Description (right side)
ax.text(7.5, yc, desc, ha='left', va='center', fontsize=9.2,
color='#333', zorder=3)
# Vertical divider
ax.plot([7.3, 7.3], [yc - h/2 + 0.1, yc + h/2 - 0.1],
color=lc, lw=1.2, ls='--', zorder=3)
# Arrow showing direction of growth
ax.annotate('', xy=(0.6, 4.0), xytext=(0.6, 11.5),
arrowprops=dict(arrowstyle='->', color='#C62828', lw=3.0))
ax.text(0.3, 7.8, 'BONE\nGROWTH\nDIRECTION', ha='center', va='center',
fontsize=8.5, fontweight='bold', color='#C62828', rotation=90)
# Arrow showing cartilage-to-bone direction
ax.annotate('', xy=(13.4, 11.5), xytext=(13.4, 4.6),
arrowprops=dict(arrowstyle='->', color='#1565C0', lw=2.5))
ax.text(13.7, 8.0, 'CARTILAGE\n→\nBONE', ha='center', va='center',
fontsize=8.5, fontweight='bold', color='#1565C0', rotation=90)
# Labels for epiphysis and diaphysis
box_style = dict(boxstyle='round', facecolor='#B2EBF2', edgecolor='#006064', lw=2)
ax.text(7, 11.95, 'EPIPHYSIS (cartilage end)', ha='center', va='center',
fontsize=10, fontweight='bold', color='#006064',
bbox=dict(boxstyle='round', facecolor='#B2EBF2', edgecolor='#006064', lw=2))
ax.text(7, 3.7, 'DIAPHYSIS (bone shaft)', ha='center', va='center',
fontsize=10, fontweight='bold', color='#4A148C',
bbox=dict(boxstyle='round', facecolor='#EDE7F6', edgecolor='#4A148C', lw=2))
# Blood vessel icon label
ax.text(7, 4.05, '🩸 Capillaries invade from diaphysis side', ha='center',
fontsize=9.5, color='#B71C1C', style='italic')
# Summary box at bottom
ax.text(7, 2.8, 'SIMPLE SUMMARY: Cartilage cells are born (①) → multiply (②) → enlarge (③) → die (④) → replaced by real bone (⑤)',
ha='center', va='center', fontsize=9.5, color='#1A237E',
bbox=dict(boxstyle='round', facecolor='#E8EAF6', edgecolor='#283593', lw=2.5),
wrap=True)
ax.text(7, 2.0, 'Growth plate = The "engine" of bone lengthening in children\n'
'Closes after puberty (epiphyseal fusion) → stops height growth',
ha='center', va='center', fontsize=9.5, color='#333',
bbox=dict(boxstyle='round', facecolor='#FFF8E1', edgecolor='#F57F17', lw=2))
ax.text(7, 1.1, 'Regulators: Growth Hormone (GH) | PTHrP | Indian Hedgehog (Ihh) | WNT | SOX9 | RUNX2 | BMPs | FGFs',
ha='center', va='center', fontsize=9, color='#333',
bbox=dict(boxstyle='round', facecolor='#F3E5F5', edgecolor='#6A1B9A', lw=2))
plt.tight_layout()
plt.savefig('/tmp/workspace/bone-diagrams/diagram2_growth_plate.png',
dpi=150, bbox_inches='tight', facecolor='#FAFAFA')
plt.close()
print("Diagram 2 saved.")
~/bone-diagrams/make_diagram3.py
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib.patches import FancyBboxPatch, Circle, FancyArrowPatch
import numpy as np
# ─────────────────────────────────────────────────────────────
# DIAGRAM 3: RANK / RANKL / OPG Pathway + Bone Remodeling
# ─────────────────────────────────────────────────────────────
fig, axes = plt.subplots(1, 2, figsize=(18, 13))
fig.patch.set_facecolor('#F8F9FA')
# ── LEFT PANEL: RANK/RANKL/OPG ──────────────────────────────
ax = axes[0]
ax.set_xlim(0, 10)
ax.set_ylim(0, 14)
ax.axis('off')
ax.set_facecolor('#F8F9FA')
def box(ax, x, y, w, h, text, fc, ec, tc='white', fs=10, bold=False):
r = FancyBboxPatch((x - w/2, y - h/2), w, h,
boxstyle="round,pad=0.12", linewidth=2,
edgecolor=ec, facecolor=fc, zorder=3)
ax.add_patch(r)
ax.text(x, y, text, ha='center', va='center', fontsize=fs,
color=tc, fontweight='bold' if bold else 'normal',
multialignment='center', zorder=4)
def arr(ax, x1, y1, x2, y2, col='#333', ls='-'):
ax.annotate('', xy=(x2, y2), xytext=(x1, y1),
arrowprops=dict(arrowstyle='->', color=col, lw=2.2,
linestyle=ls), zorder=2)
ax.text(5, 13.6, 'RANK / RANKL / OPG PATHWAY', ha='center',
fontsize=14, fontweight='bold', color='#1A237E')
ax.text(5, 13.15, 'How osteoclasts are made & controlled', ha='center',
fontsize=10, color='#555', style='italic')
# OSTEOBLAST (top)
box(ax, 5, 11.8, 5.5, 1.2,
'OSTEOBLAST / STROMAL CELL\n(Bone-MAKING cell)',
'#1565C0', '#0D47A1', 'white', 10, True)
# Three outputs of osteoblast
ax.text(5, 11.0, 'This cell produces 3 key signals:', ha='center',
fontsize=9.5, color='#333', style='italic')
# Signal 1: RANKL
box(ax, 1.8, 9.6, 2.8, 0.85,
'RANKL\n(activates osteoclasts)', '#E53935', '#B71C1C', 'white', 9.5)
arr(ax, 3.2, 11.2, 2.4, 10.05, '#E53935')
# Signal 2: M-CSF
box(ax, 5, 9.6, 2.8, 0.85,
'M-CSF\n(helps osteoclast grow)', '#E65100', '#BF360C', 'white', 9.5)
arr(ax, 5, 11.2, 5, 10.05, '#E65100')
# Signal 3: OPG (DECOY)
box(ax, 8.2, 9.6, 2.8, 0.9,
'OPG\n(BLOCKS RANKL\n– a decoy receptor)', '#2E7D32', '#1B5E20', 'white', 9.5)
arr(ax, 6.8, 11.2, 7.6, 10.05, '#2E7D32')
# OSTEOCLAST PRECURSOR
box(ax, 3.3, 7.8, 3.6, 1.0,
'OSTEOCLAST PRECURSOR\n(has RANK receptor on surface)',
'#7B1FA2', '#4A148C', 'white', 9.5)
# RANKL binds RANK
arr(ax, 1.8, 9.15, 3.0, 8.3, '#E53935')
ax.text(1.8, 8.7, 'RANKL\nbinds RANK', ha='center', fontsize=8.5,
color='#E53935', fontweight='bold')
# M-CSF binds receptor
arr(ax, 4.5, 9.15, 3.8, 8.3, '#E65100')
# NF-kB activation
box(ax, 3.3, 6.5, 3.2, 0.85,
'NF-kB activated\ninside cell', '#6A1B9A', '#4A148C', 'white', 9.5)
arr(ax, 3.3, 7.3, 3.3, 6.95, '#7B1FA2')
# Differentiation arrow
arr(ax, 3.3, 6.05, 3.3, 5.3, '#4A148C')
ax.text(4.1, 5.65, 'Differentiates', ha='left', fontsize=9, color='#4A148C', style='italic')
# MATURE OSTEOCLAST
box(ax, 3.3, 4.7, 4.0, 1.0,
'MATURE OSTEOCLAST\n(Bone-RESORBING cell)',
'#BF360C', '#870000', 'white', 10, True)
# Bone resorption
arr(ax, 3.3, 4.2, 3.3, 3.4, '#BF360C')
box(ax, 3.3, 3.0, 4.5, 0.85,
'BONE RESORPTION\n(breaks down bone matrix)', '#D32F2F', '#B71C1C', 'white', 9.5)
# OPG BLOCKS pathway
ax.annotate('', xy=(2.0, 8.1), xytext=(7.2, 9.2),
arrowprops=dict(arrowstyle='->', color='#2E7D32', lw=2.5,
connectionstyle='arc3,rad=-0.4'), zorder=2)
ax.text(5.5, 8.1, 'OPG intercepts\nRANKL here\n(blocks activation)', ha='center',
fontsize=9, color='#2E7D32', fontweight='bold',
bbox=dict(boxstyle='round', facecolor='#E8F5E9', edgecolor='#2E7D32', lw=1.5))
# NET EFFECT BOXES
ax.text(5, 2.2, 'NET EFFECT:', ha='center', fontsize=10,
fontweight='bold', color='#333')
box(ax, 2.5, 1.5, 3.8, 0.8,
'MORE RANKL or LESS OPG\n= MORE bone resorption',
'#FFCDD2', '#E53935', '#B71C1C', 9.5)
box(ax, 7.5, 1.5, 3.8, 0.8,
'LESS RANKL or MORE OPG\n= LESS bone resorption',
'#C8E6C9', '#2E7D32', '#1B5E20', 9.5)
ax.text(5, 0.6, 'WNT proteins (from osteoprogenitor cells) bind LRP5/LRP6 on osteoblasts\n'
'→ activate beta-catenin + stimulate OPG synthesis = FAVORS bone formation',
ha='center', va='center', fontsize=8.5, color='#333',
bbox=dict(boxstyle='round', facecolor='#E3F2FD', edgecolor='#1565C0', lw=1.5))
# ── RIGHT PANEL: Bone Remodeling BMU Cycle ───────────────────
ax2 = axes[1]
ax2.set_xlim(0, 10)
ax2.set_ylim(0, 14)
ax2.axis('off')
ax2.set_facecolor('#F8F9FA')
ax2.text(5, 13.6, 'BONE REMODELING CYCLE', ha='center',
fontsize=14, fontweight='bold', color='#1A237E')
ax2.text(5, 13.15, 'At the Bone Multicellular Unit (BMU) – happens continuously', ha='center',
fontsize=10, color='#555', style='italic')
steps = [
(5, 11.8, '#F57F17', '#F9A825', '1. OSTEOCLAST ATTACHMENT\nOsteoclasts attach to bone surface\nand create a sealed "pit"'),
(5, 10.2, '#E53935', '#EF5350', '2. BONE RESORPTION\nOsteoclasts release acid & enzymes\n(matrix metalloproteinases = MMPs)\n→ Dissolves mineral + organic matrix\n→ Creates a "pit" (Howship lacuna)'),
(5, 8.3, '#1565C0', '#1976D2', '3. OSTEOBLAST ARRIVAL\nResorption releases growth factors\n(TGF-beta, IGF, BMPs) from matrix\n→ These attract osteoblasts to the pit'),
(5, 6.5, '#2E7D32', '#43A047', '4. OSTEOBLAST PROLIFERATION\n& MATRIX SYNTHESIS\nOsteoblasts fill the pit with\nnew bone matrix (osteoid)'),
(5, 4.7, '#00695C', '#00897B', '5. MINERALIZATION\nOsteoid gets mineralized\n(calcium + phosphate deposited)\n→ New hard bone formed'),
(5, 2.9, '#37474F', '#546E7A', '6. OSTEOCYTE EMBEDDING\nSome osteoblasts get trapped\n→ become OSTEOCYTES\n(sense mechanical stress;\nproduce sclerostin to INHIBIT WNT)'),
]
for i, (x, y, fc, ec, text) in enumerate(steps):
h = 1.4 if i == 1 else 1.1
r = FancyBboxPatch((x - 4.5, y - h/2), 9, h,
boxstyle="round,pad=0.12", linewidth=2,
edgecolor=ec, facecolor=fc, zorder=3,
alpha=0.92)
ax2.add_patch(r)
ax2.text(x, y, text, ha='center', va='center', fontsize=9.2,
color='white', fontweight='normal', multialignment='center', zorder=4)
ax2.text(0.3, y, str(i+1), ha='center', va='center', fontsize=13,
fontweight='bold', color='white', zorder=4)
if i < len(steps) - 1:
ax2.annotate('', xy=(x, steps[i+1][1] + h/2 + 0.02),
xytext=(x, y - h/2 - 0.02),
arrowprops=dict(arrowstyle='->', color='#555', lw=2.3), zorder=2)
# Cycle indicator (back from 6 to 1 approximately)
ax2.annotate('', xy=(9.2, 11.4), xytext=(9.2, 3.4),
arrowprops=dict(arrowstyle='->', color='#9C27B0', lw=2.5,
connectionstyle='arc3,rad=-0.5'), zorder=2)
ax2.text(9.5, 7.5, 'CYCLE\nREPEATS', ha='center', va='center', fontsize=8.5,
fontweight='bold', color='#9C27B0', rotation=90)
# Bottom note
ax2.text(5, 1.65, 'Turns over ~10% of skeleton per year\nRepairs damage | Responds to mechanical load',
ha='center', va='center', fontsize=9.5, color='#1A237E',
bbox=dict(boxstyle='round', facecolor='#EDE7F6', edgecolor='#4A148C', lw=2))
ax2.text(5, 0.7, 'Balance matters: After 4th decade → RESORPTION > FORMATION\n'
'→ Bone mass slowly DECREASES (especially with low estrogen, vitamin D deficiency)',
ha='center', va='center', fontsize=8.8, color='#555',
bbox=dict(boxstyle='round', facecolor='#FFF3E0', edgecolor='#E65100', lw=1.5))
plt.tight_layout(pad=1.5)
plt.savefig('/tmp/workspace/bone-diagrams/diagram3_remodeling.png',
dpi=150, bbox_inches='tight', facecolor='#F8F9FA')
plt.close()
print("Diagram 3 saved.")
~/bone-diagrams/make_diagram4.py
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib.patches import FancyBboxPatch
import numpy as np
# ─────────────────────────────────────────────────────────────
# DIAGRAM 4: Regulators / Signaling Molecules Summary Table
# ─────────────────────────────────────────────────────────────
fig, ax = plt.subplots(figsize=(16, 11))
ax.set_xlim(0, 16)
ax.set_ylim(0, 11)
ax.axis('off')
ax.set_facecolor('#FAFBFF')
fig.patch.set_facecolor('#FAFBFF')
ax.text(8, 10.6, 'REGULATORS OF BONE & CARTILAGE DEVELOPMENT', ha='center',
fontsize=16, fontweight='bold', color='#1A237E')
ax.text(8, 10.2, 'Simple cheat-sheet: WHO does WHAT', ha='center',
fontsize=11, color='#555', style='italic')
headers = ['Regulator', 'Source', 'Acts On', 'Effect (Simple)']
col_x = [1.5, 4.5, 8.0, 12.5]
col_w = [3.0, 4.0, 5.0, 6.0]
# Header row
for i, (hdr, cx) in enumerate(zip(headers, col_x)):
r = FancyBboxPatch((cx - col_w[i]/2, 9.55), col_w[i] - 0.1, 0.55,
boxstyle="round,pad=0.05", linewidth=1.5,
edgecolor='#1A237E', facecolor='#1A237E', zorder=3)
ax.add_patch(r)
ax.text(cx, 9.82, hdr, ha='center', va='center', fontsize=10.5,
fontweight='bold', color='white', zorder=4)
data = [
# name, source, acts on, effect, row_color
('Growth Hormone\n(GH)', 'Anterior Pituitary', 'Proliferative zone\nchondrocytes', 'Induces & maintains\nchondrocyte proliferation', '#E3F2FD'),
('Thyroid Hormone', 'Thyroid Gland', 'Proliferating\nchondrocytes', 'Causes hypertrophy\n(chondrocytes to enlarge)', '#E8F5E9'),
('Indian Hedgehog\n(Ihh)', 'Prehypertrophic\nchondrocytes', 'Chondrocytes +\nOsteoblasts', 'Coordinates proliferation &\ndifferentiation of both cell types', '#FFF8E1'),
('PTHrP', 'Perichondrial\nstromal cells', 'PTH receptor on\nchondrocytes', 'Keeps chondrocytes\nproliferating (anti-hypertrophy)', '#FCE4EC'),
('WNT / beta-catenin', 'Multiple cells', 'Growth plate\nchondrocytes', 'Promotes proliferation\n& maturation via LRP5/6', '#E8EAF6'),
('SOX9', 'Proliferating\nchondrocytes', 'Chondrocyte\nprecursors', 'ESSENTIAL for chondrocyte\ndifferentiation (NOT hypertrophic)', '#E0F7FA'),
('RUNX2', 'Hypertrophic\nchondrocytes', 'Immature mesenchymal\ncells', 'Controls terminal chondrocyte\n& osteoblast differentiation', '#F3E5F5'),
('FGFs (esp. FGF-3)', 'Mesenchymal cells', 'Hypertrophic\nchondrocytes', 'INHIBITS proliferation\n& promotes differentiation', '#FBE9E7'),
('BMPs\n(TGF-beta family)', 'Various cells', 'Chondrocytes\n(all stages)', 'Diverse effects on development\n& hypertrophy at growth plate', '#E8F5E9'),
('OPG', 'Osteoblasts +\nmultiple cells', 'RANKL\n(decoy receptor)', 'BLOCKS RANKL from binding RANK\n= prevents osteoclast activation', '#FFFDE7'),
('M-CSF', 'Osteoblasts', 'Osteoclast\nprecursors', 'Needed for osteoclasts\nto grow and survive', '#F9FBE7'),
('Sclerostin', 'Osteocytes\n(embedded)', 'WNT pathway', 'INHIBITS WNT signaling\n= inhibits bone formation', '#FCE4EC'),
]
row_h = 0.67
y_start = 9.2
for i, (name, source, acts_on, effect, rc) in enumerate(data):
y = y_start - i * row_h
cols_data = [name, source, acts_on, effect]
for j, (txt, cx) in enumerate(zip(cols_data, col_x)):
r = FancyBboxPatch((cx - col_w[j]/2, y - row_h + 0.04), col_w[j] - 0.1, row_h - 0.04,
boxstyle="round,pad=0.04", linewidth=1,
edgecolor='#BBDEFB', facecolor=rc, zorder=2)
ax.add_patch(r)
ax.text(cx, y - row_h/2 + 0.04, txt, ha='center', va='center',
fontsize=8.8, color='#212121', multialignment='center', zorder=3)
# Color legend
ax.text(8, 0.55, 'KEY BALANCE: OPG opposes RANKL. More RANKL = more resorption. More OPG = more formation.\n'
'PTH, IL-1, glucocorticoids → promote osteoclast activity | BMPs, sex hormones → promote OPG = favor formation',
ha='center', va='center', fontsize=9.5, color='#333',
bbox=dict(boxstyle='round', facecolor='#E8EAF6', edgecolor='#3949AB', lw=2.5))
plt.tight_layout()
plt.savefig('/tmp/workspace/bone-diagrams/diagram4_regulators.png',
dpi=150, bbox_inches='tight', facecolor='#FAFBFF')
plt.close()
print("Diagram 4 saved.")
cd /tmp/workspace/bone-diagrams && python3 make_diagrams.py && python3 make_diagram2.py && python3 make_diagram3.py && python3 make_diagram4.py && ls -lh *.png
diagram1 bone development
Image · PNG
MESENCHYMAL PRECURSOR CELLS
|
┌──────┴──────┐
▼ ▼
ENDOCHONDRAL INTRAMEMBRANOUS
OSSIFICATION OSSIFICATION
(Most bones) (Flat bones: skull)
| |
Cartilage Dense
model first mesenchyme
(anlagen) forms directly
| |
Bone grows Osteoblasts
THROUGH ossify it
cartilage WITHOUT
cartilage step
diagram2 growth plate
Image · PNG
EPIPHYSIS (cartilage end)
|
──────────────────
① RESERVE ZONE → Resting stem cells, just waiting
──────────────────
② PROLIFERATIVE ZONE → Cells DIVIDE rapidly in stacked columns
← GH acts here = bone lengthens
──────────────────
③ HYPERTROPHIC ZONE → Cells SWELL up (5-10x bigger)
Matrix starts mineralizing
──────────────────
④ MINERALIZATION ZONE → Cells DIE (apoptosis)
Capillaries invade
Osteoblasts arrive
──────────────────
⑤ PRIMARY SPONGIOSA → Dead cartilage = scaffold
Osteoblasts lay down REAL BONE
──────────────────
DIAPHYSIS (bone shaft)
diagram3 remodeling
Image · PNG
OSTEOBLAST (bone-making cell)
│ │ │
▼ ▼ ▼
RANKL M-CSF OPG
(activates) (growth (BLOCKS
osteoclasts factor) RANKL)
│ │
▼ ▼
Osteoclast precursor
(has RANK receptor)
│
RANKL binds RANK
│
NF-kB activated
│
▼
MATURE OSTEOCLAST
(bone-DESTROYING cell)
│
▼
BONE RESORPTION
BUT... if OPG intercepts RANKL first → osteoclast NEVER activated
① Osteoclast ATTACHES to bone surface
↓
② RESORPTION: Acid + enzymes dissolve
bone (creates a pit = Howship lacuna)
↓
③ Osteoblasts RECRUITED to the pit
(attracted by growth factors released
from the old bone matrix)
↓
④ Osteoblasts FILL the pit with new
bone matrix (called "osteoid")
↓
⑤ Osteoid MINERALIZES → hard new bone
↓
⑥ Some osteoblasts get trapped = OSTEOCYTES
(sense pressure; secrete sclerostin
to slow WNT = negative feedback)
↓
CYCLE REPEATS (~10% of skeleton/year)
diagram4 regulators
Image · PNG
| Regulator | Simple job |
|---|---|
| GH | Makes chondrocytes divide |
| Thyroid hormone | Makes chondrocytes enlarge |
| Indian Hedgehog (Ihh) | Coordinates chondrocytes + osteoblasts together |
| PTHrP | Keeps chondrocytes multiplying (prevents premature hypertrophy) |
| WNT | Promotes chondrocyte proliferation and maturation |
| SOX9 | Master switch for chondrocyte identity |
| RUNX2 | Master switch for osteoblast identity |
| FGFs | Put the brakes on - inhibit proliferation |
| BMPs | Fine-tune development at all stages |
| OPG | Decoy receptor - blocks RANKL = less bone destruction |
| M-CSF | Helps osteoclasts survive and grow |
| Sclerostin | Made by osteocytes - shuts off WNT = slows bone formation |
BONE FORMATION (Osteoblasts) vs BONE RESORPTION (Osteoclasts)
▲ ▲
| |
WNT, BMPs, sex hormones RANKL, PTH, IL-1,
promote formation glucocorticoids
(block OPG degradation) promote resorption
← BALANCED in healthy adults →
After age 40:
RESORPTION > FORMATION
→ Steady loss of bone mass
→ Risk of osteoporosis