General bones
| Shape | Description | Example |
|---|---|---|
| Long | Tubular | Humerus, Femur |
| Short | Cuboidal | Carpal, Tarsal bones |
| Flat | Two compact plates + spongy bone sandwich | Skull |
| Irregular | Variable shape | Facial bones, vertebrae |
| Sesamoid | Round/oval bones within tendons | Patella, thumb/toe sesamoids |



| Component | Function | Notes |
|---|---|---|
| Type I collagen (90% of organic matrix) | Tensile strength | Triple helix of 2α₁ + 1α₂ chains; mineralization occurs in "hole zones" and "pores" between collagen molecules |
| Proteoglycans | Compressive strength; inhibit mineralization | Glycosaminoglycan-protein complexes |
| Osteocalcin | Most abundant noncollagenous protein (10-20%); marker of bone turnover | Stimulated by 1,25(OH)₂D₃; inhibited by PTH; attracts osteoclasts |
| Osteonectin | Regulates calcium; organizes mineral in matrix | Secreted by platelets and osteoblasts |
| Osteopontin | Cell-binding protein (integrin-like) | |
| Growth factors (TGF-β, IGF, IL-1, IL-6, BMPs) | Differentiation, activation, turnover |
| Component | Function |
|---|---|
| Calcium hydroxyapatite [Ca₁₀(PO₄)₆(OH)₂] | Compressive strength (primary inorganic mineral) |
| Osteocalcium phosphate (brushite) | Secondary inorganic component |
| System | Pressure | Coverage | Details |
|---|---|---|---|
| Nutrient artery | High | Inner 2/3 of cortex | Enters via nutrient foramen → medullary canal → branches into Haversian system |
| Metaphyseal-epiphyseal | - | Ends of bone | Arises from periarticular vascular plexus (e.g., geniculate arteries) |
| Periosteal | Low | Outer 1/3 of cortex | Mostly capillaries |
| Fact | Mnemonic / Quick Rule |
|---|---|
| Bone collagen type | "Bone" contains the word one → Type I collagen |
| Cortical bone fraction | 80% of skeleton; cancellous = 20% |
| Most abundant bone cell | Osteocytes = 90% of cells in mature skeleton |
| Osteoblast origin | Mesenchymal stem cell |
| Osteoclast origin | Hematopoietic / macrophage lineage |
| RANKL effect | Stimulates osteoclast differentiation (bone resorption) |
| OPG effect | Inhibits RANKL → inhibits bone resorption |
| Wnt effect | Promotes osteoblast survival → increases bone mass |
| Sclerostin effect | Inhibits Wnt → inhibits osteoblast activity (produced by osteocytes) |
Make a pdf of this topic
ls -la /home/daytona/workspace/
mkdir -p /home/daytona/workspace/bone-anatomy
~/bone-anatomy/generate_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether, Image
)
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.platypus import PageBreak
from urllib.request import urlretrieve
import os
OUTPUT = "/home/daytona/workspace/bone-anatomy/General_Bone_Anatomy_Structure.pdf"
IMG_DIR = "/home/daytona/workspace/bone-anatomy/imgs"
os.makedirs(IMG_DIR, exist_ok=True)
# Download images
IMAGES = {
"bone_types": "https://cdn.orris.care/cdss_images/4c49d5ab68aa34eb0f4dbf737952709e9f9fa998bd1e9d2e1b20571b423cccf4.png",
"cell_origins": "https://cdn.orris.care/cdss_images/ea0816c73f2f0c222947ba3225e694b439ef3306556f87da0a9220dd0d6d2d95.png",
"cell_receptors": "https://cdn.orris.care/cdss_images/4e7dc1ff98dcc72f2bcb7eed4451791669d2f03cadcf41d69b373a7573c2a4be.png",
}
local_imgs = {}
for key, url in IMAGES.items():
path = os.path.join(IMG_DIR, f"{key}.png")
try:
urlretrieve(url, path)
local_imgs[key] = path
print(f"Downloaded {key}")
except Exception as e:
print(f"Failed {key}: {e}")
# --- Styles ---
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
rightMargin=2*cm, leftMargin=2*cm,
topMargin=2.2*cm, bottomMargin=2.2*cm,
title="General Bone Anatomy & Structure",
author="Orris Medical Library"
)
styles = getSampleStyleSheet()
W = A4[0] - 4*cm # usable width
NAVY = colors.HexColor("#1a3a5c")
TEAL = colors.HexColor("#1a7a7a")
LGRAY = colors.HexColor("#f4f6f9")
MGRAY = colors.HexColor("#d0d7e3")
DGRAY = colors.HexColor("#4a4a4a")
WHITE = colors.white
ACCENT = colors.HexColor("#e8f0fe")
title_style = ParagraphStyle("TitleStyle", parent=styles["Title"],
fontSize=22, textColor=WHITE, spaceAfter=4, spaceBefore=0,
fontName="Helvetica-Bold", alignment=TA_CENTER)
h1_style = ParagraphStyle("H1", parent=styles["Heading1"],
fontSize=14, textColor=WHITE, spaceBefore=14, spaceAfter=4,
fontName="Helvetica-Bold", backColor=NAVY,
borderPad=(6, 6, 6, 8), leading=18)
h2_style = ParagraphStyle("H2", parent=styles["Heading2"],
fontSize=11, textColor=NAVY, spaceBefore=10, spaceAfter=3,
fontName="Helvetica-Bold", borderPad=2)
body_style = ParagraphStyle("Body", parent=styles["Normal"],
fontSize=9.5, textColor=DGRAY, spaceAfter=4, spaceBefore=2,
fontName="Helvetica", leading=14, alignment=TA_JUSTIFY)
bullet_style = ParagraphStyle("Bullet", parent=body_style,
leftIndent=14, bulletIndent=4, spaceAfter=2,
bulletFontName="Helvetica", bulletFontSize=9)
sub_bullet_style = ParagraphStyle("SubBullet", parent=bullet_style,
leftIndent=28, bulletIndent=18)
caption_style = ParagraphStyle("Caption", parent=styles["Normal"],
fontSize=8, textColor=colors.HexColor("#666666"), spaceAfter=8,
fontName="Helvetica-Oblique", alignment=TA_CENTER)
source_style = ParagraphStyle("Source", parent=styles["Normal"],
fontSize=7.5, textColor=TEAL, spaceAfter=2,
fontName="Helvetica-Oblique", alignment=TA_RIGHT)
mnemonic_style = ParagraphStyle("Mnemonic", parent=body_style,
backColor=ACCENT, borderPad=6, fontName="Helvetica",
leftIndent=6, rightIndent=6)
def section_header(text):
data = [[Paragraph(f" {text}", h1_style)]]
t = Table(data, colWidths=[W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), NAVY),
("ROUNDEDCORNERS", [4,4,4,4]),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
return t
def sub_header(text):
return Paragraph(f"<font color='#{TEAL.hexval()[2:]}'>■</font> <b>{text}</b>", h2_style)
def bullet(text, level=1):
if level == 1:
return Paragraph(f"• {text}", bullet_style)
else:
return Paragraph(f" ◦ {text}", sub_bullet_style)
def body(text):
return Paragraph(text, body_style)
def source(text):
return Paragraph(text, source_style)
def spacer(h=0.2):
return Spacer(1, h*cm)
def make_table(headers, rows, col_widths=None):
if col_widths is None:
col_widths = [W / len(headers)] * len(headers)
header_row = [Paragraph(f"<b>{h}</b>", ParagraphStyle("TH",
parent=body_style, textColor=WHITE, fontSize=9, fontName="Helvetica-Bold")) for h in headers]
data = [header_row]
for row in rows:
data.append([Paragraph(str(c), ParagraphStyle("TD", parent=body_style, fontSize=9)) for c in row])
t = Table(data, colWidths=col_widths, repeatRows=1)
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("BACKGROUND", (0,1), (-1,-1), LGRAY),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LGRAY]),
("GRID", (0,0), (-1,-1), 0.4, MGRAY),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
]))
return t
# ==============================
# TITLE BLOCK
# ==============================
def title_block():
data = [[
Paragraph("General Bone Anatomy & Structure", ParagraphStyle("TB",
fontSize=22, textColor=WHITE, fontName="Helvetica-Bold",
alignment=TA_CENTER, spaceAfter=0)),
],[
Paragraph("Detailed Exam-Level Review | Sources: Gray's Anatomy for Students & Miller's Review of Orthopaedics 9e",
ParagraphStyle("Sub", fontSize=9.5, textColor=colors.HexColor("#c8ddf5"),
fontName="Helvetica-Oblique", alignment=TA_CENTER)),
]]
t = Table([[row[0]] for row in data], colWidths=[W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), NAVY),
("TOPPADDING", (0,0), (-1,-1), 12),
("BOTTOMPADDING", (0,0), (-1,-1), 12),
("LEFTPADDING", (0,0), (-1,-1), 14),
("RIGHTPADDING", (0,0), (-1,-1), 14),
]))
return t
# ==============================
# BUILD STORY
# ==============================
story = []
story.append(title_block())
story.append(spacer(0.5))
# ----- SECTION 1: What Is Bone -----
story.append(section_header("1. What Is Bone?"))
story.append(spacer(0.15))
story.append(body(
"Bone is a <b>calcified, living connective tissue</b> — not inert. It contains cells, "
"receives a dedicated blood supply, and is continuously remodeled throughout life."
))
story.append(spacer(0.1))
story.append(sub_header("Functions of Bone"))
for f in [
"Structural support of the body",
"Protection of vital organs (e.g., skull → brain; ribcage → heart/lungs)",
"Calcium and phosphorus reservoir (mineral homeostasis)",
"Lever system for muscle-driven movement",
"Container for blood-producing (hematopoietic) cells",
]:
story.append(bullet(f))
story.append(source("— Gray's Anatomy for Students, p. 30"))
story.append(spacer(0.3))
# ----- SECTION 2: Classification by Shape -----
story.append(section_header("2. Macroscopic Classification (by Shape)"))
story.append(spacer(0.2))
shape_headers = ["Shape", "Description", "Example"]
shape_rows = [
["Long", "Tubular with a shaft (diaphysis) and two ends (epiphyses)", "Humerus, Femur, Tibia"],
["Short", "Cuboidal — roughly equal dimensions", "Carpal bones, Tarsal bones"],
["Flat", "Two compact bone plates sandwiching spongy bone", "Skull, Sternum, Scapula"],
["Irregular", "Variable, complex shapes", "Vertebrae, Facial bones"],
["Sesamoid", "Round/oval bones embedded within tendons", "Patella, thumb/big-toe sesamoids"],
]
story.append(make_table(shape_headers, shape_rows, [2.5*cm, 7.5*cm, 5.5*cm]))
story.append(spacer(0.1))
story.append(body(
"<b>Accessory bones</b> are normal variants (extra bones) found mainly in the wrist, "
"hands, ankles, and feet. They must not be mistaken for fractures on imaging."
))
story.append(source("— Gray's Anatomy for Students, p. 30"))
story.append(spacer(0.3))
# ----- SECTION 3: Microscopic Classification -----
story.append(section_header("3. Microscopic Classification"))
story.append(spacer(0.2))
if "bone_types" in local_imgs:
img = Image(local_imgs["bone_types"], width=W*0.85, height=W*0.85*0.55)
story.append(img)
story.append(Paragraph(
"FIG. 1 — Types of bone: Cortical (compact), Cancellous (trabecular), Immature (woven), "
"and Pathologic (e.g., giant cell tumor). Lower panel shows Haversian canal microstructure. "
"(Adapted from Miller's Review of Orthopaedics 9e, Fig. 1.1)",
caption_style))
micro_headers = ["Type", "Organization", "Turnover", "Strength", "Examples"]
micro_rows = [
["Woven (Immature / Pathologic)", "Random; NOT stress-oriented", "High", "Weaker, more flexible",
"Embryonic skeleton, fracture callus, osteogenic sarcoma, fibrous dysplasia"],
["Lamellar (Normal)", "Stress-oriented; organized along lines of force", "Low", "Stronger, less flexible",
"Normal adult cortical & cancellous bone"],
]
story.append(make_table(micro_headers, micro_rows, [2.8*cm, 3.5*cm, 1.8*cm, 2.5*cm, 4.9*cm]))
story.append(source("— Miller's Review of Orthopaedics 9e, p. 20"))
story.append(spacer(0.3))
# ----- SECTION 4: Cortical vs Cancellous -----
story.append(section_header("4. Cortical vs. Cancellous Bone"))
story.append(spacer(0.2))
story.append(sub_header("Cortical (Compact) Bone — 80% of skeleton"))
for item in [
"Slow turnover; high Young's modulus (stiff)",
"Composed of tightly packed <b>osteons (Haversian systems)</b>",
"Each osteon = concentric lamellae around a central <b>Haversian canal</b> (contains arterioles, venules, capillaries, nerves)",
"<b>Volkmann's canals</b> run transversely, connecting Haversian canals to each other and to the periosteum",
"<b>Cement lines</b> define the outer border of each osteon",
"<b>Interstitial lamellae</b> fill spaces between osteons",
"<b>Canaliculi</b> are tiny channels containing osteocyte processes — the nutritional highway of cortical bone",
]:
story.append(bullet(item))
story.append(spacer(0.15))
story.append(sub_header("Cancellous (Spongy / Trabecular) Bone — 20% of skeleton"))
for item in [
"Higher turnover; smaller Young's modulus (more elastic)",
"Loose network of struts and plates called <b>trabeculae</b>",
"30–90% of trabecular volume = pores filled with bone marrow",
"MSCs lining endosteum / Haversian canals become osteoblasts (low strain, high O₂)",
]:
story.append(bullet(item))
story.append(source("— Miller's Review of Orthopaedics 9e, p. 20–21"))
story.append(spacer(0.3))
# ----- SECTION 5: Bone Cells -----
story.append(section_header("5. Bone Cells"))
story.append(spacer(0.2))
if "cell_origins" in local_imgs:
img = Image(local_imgs["cell_origins"], width=W*0.82, height=W*0.82*1.1)
story.append(img)
story.append(Paragraph(
"FIG. 2 — Cellular origins of bone and cartilage cells. Osteoblasts/osteocytes "
"arise from mesenchymal stem cells; osteoclasts from hematopoietic progenitors. "
"(From Miller's Review of Orthopaedics 9e, Fig. 1.2)",
caption_style))
story.append(sub_header("Osteoblasts — Bone-Forming Cells"))
for item in [
"Derived from <b>undifferentiated mesenchymal stem cells (MSCs)</b>",
"Appear as cuboid cells aligned along immature osteoid",
"Fate depends on microenvironment: low strain + high O₂ → osteoblast; intermediate strain + low O₂ → chondrocyte; high strain → fibrous tissue",
"Directed by transcription factor <b>RUNX2</b> and <b>BMP</b> (bone morphogenetic protein); also β-catenin / Core-binding factor α-1",
"Rich in ER, Golgi, and mitochondria (synthesis/secretion machinery)",
]:
story.append(bullet(item))
story.append(body("<b>Osteoblasts produce:</b> Alkaline phosphatase, Osteocalcin, Type I collagen, Bone sialoprotein, RANKL, OPG"))
story.append(body("<b>Stimulated by:</b> Intermittent (pulsatile) PTH, Wnt proteins, BMP"))
story.append(body("<b>Inhibited by:</b> TNF-α, Sclerostin, Dkk-1, Glucocorticoids"))
story.append(spacer(0.15))
story.append(sub_header("Osteocytes — Maintenance Cells"))
for item in [
"Constitute <b>90% of all cells</b> in the mature skeleton",
"Former osteoblasts entrapped by newly formed matrix",
"High nucleus/cytoplasm ratio; long cytoplasmic processes through canaliculi",
"Function: maintain bone; regulate extracellular Ca²⁺ and phosphorus",
"Secrete <b>sclerostin (Scl)</b> → negative feedback on osteoblast bone deposition",
"Regulated by mechanical loading: decreased Scl in areas of high strain → increased bone formation",
"Directly stimulated by calcitonin; inhibited by PTH",
]:
story.append(bullet(item))
story.append(spacer(0.15))
story.append(sub_header("Osteoclasts — Bone-Resorbing Cells"))
for item in [
"<b>Multinucleated irregular giant cells</b>",
"Derived from hematopoietic cells in the <b>macrophage lineage</b> (monocyte progenitors fuse)",
"Primary function: <b>bone resorption</b>",
"Activated by <b>RANKL</b> binding to RANK receptor on cell surface",
"Inhibited by <b>OPG</b> (osteoprotegerin) which sequesters RANKL",
"Inhibited directly by <b>calcitonin</b>",
]:
story.append(bullet(item))
story.append(source("— Miller's Review of Orthopaedics 9e, p. 21–23"))
story.append(spacer(0.3))
# Receptor table image
if "cell_receptors" in local_imgs:
story.append(sub_header("Bone Cell Receptor Table & RANKL-OPG-Wnt Crosstalk"))
img = Image(local_imgs["cell_receptors"], width=W, height=W*0.55)
story.append(img)
story.append(Paragraph(
"FIG. 3 — Bone cell receptor types, effects, and paracrine crosstalk between osteoblasts and osteoclasts. "
"(From Miller's Review of Orthopaedics 9e, Table 1.2 & Fig. 1.3)",
caption_style))
story.append(spacer(0.3))
# ----- SECTION 6: Bone Matrix -----
story.append(section_header("6. Bone Matrix Composition"))
story.append(spacer(0.2))
story.append(body(
"Bone matrix = <b>~35% organic</b> (mainly collagen + proteins) + <b>~65% inorganic</b> (mainly calcium hydroxyapatite). "
"The combination gives bone both tensile strength (collagen) and compressive strength (mineral)."
))
story.append(spacer(0.15))
matrix_headers = ["Component", "Type", "Function", "Key Notes"]
matrix_rows = [
["Type I Collagen", "Organic (90% of organic)", "Tensile strength",
"Triple helix (2α₁ + 1α₂); mineralization occurs in 'hole zones' and 'pores'; cross-linking increases strength. Mnemonic: bone contains 'one' → Type I"],
["Proteoglycans", "Organic", "Compressive strength; inhibit mineralization",
"Glycosaminoglycan-protein complexes"],
["Osteocalcin", "Organic (noncollagenous)", "Most abundant noncollagenous protein (10–20%); attracts osteoclasts; marker of bone turnover",
"Stimulated by 1,25(OH)₂D₃; inhibited by PTH"],
["Osteonectin (SPARC)", "Organic (noncollagenous)", "Regulates calcium; organizes mineral in matrix",
"Secreted by platelets & osteoblasts"],
["Osteopontin", "Organic (noncollagenous)", "Cell-binding (integrin-like)", ""],
["Growth factors (TGF-β, IGF, BMPs, IL-1, IL-6)", "Organic", "Differentiation, activation, turnover", "Present in small amounts"],
["Calcium hydroxyapatite [Ca₁₀(PO₄)₆(OH)₂]", "Inorganic (primary)", "Compressive strength",
"Primary: mineralizes in collagen holes/pores; secondary: periphery"],
["Osteocalcium phosphate (brushite)", "Inorganic (secondary)", "Minor inorganic component", ""],
]
story.append(make_table(matrix_headers, matrix_rows, [3.5*cm, 3*cm, 4.5*cm, 4.5*cm]))
story.append(source("— Miller's Review of Orthopaedics 9e, p. 24"))
story.append(spacer(0.3))
# ----- SECTION 7: Periosteum & Endosteum -----
story.append(section_header("7. Periosteum & Endosteum"))
story.append(spacer(0.15))
story.append(sub_header("Periosteum"))
for item in [
"Fibrous connective tissue membrane covering ALL external bone surfaces (except articular cartilage)",
"Contains blood vessels (supply outer cortical layers) and <b>dense sensory nerve fibers</b> → very pain-sensitive",
"Unique capability of <b>forming new bone</b> (critical for fracture repair)",
"A bone stripped of its periosteum will not survive",
]:
story.append(bullet(item))
story.append(spacer(0.1))
story.append(sub_header("Endosteum"))
for item in [
"Thin cellular layer lining the medullary cavity and surfaces of Haversian canals",
"Contains MSCs that differentiate into osteoblasts under appropriate signals",
]:
story.append(bullet(item))
story.append(source("— Gray's Anatomy for Students, p. 30"))
story.append(spacer(0.3))
# ----- SECTION 8: Blood Supply -----
story.append(section_header("8. Blood Supply to Bone"))
story.append(spacer(0.2))
story.append(body("Long bones receive blood from <b>three systems</b>:"))
story.append(spacer(0.15))
blood_headers = ["System", "Pressure", "Coverage", "Details"]
blood_rows = [
["Nutrient Artery", "High", "Inner 2/3 of diaphyseal cortex",
"Enters via nutrient foramen → medullary canal → branches into ascending/descending arteries → Haversian system"],
["Metaphyseal-Epiphyseal", "Intermediate", "Bone ends (epiphyses & metaphyses)",
"Arises from periarticular vascular plexus (e.g., geniculate arteries around knee)"],
["Periosteal", "Low", "Outer 1/3 of cortex", "Mostly capillaries from adjacent soft tissue"],
]
story.append(make_table(blood_headers, blood_rows, [3.5*cm, 2.2*cm, 4.0*cm, 5.8*cm]))
story.append(spacer(0.15))
story.append(sub_header("Direction of Flow"))
for item in [
"<b>Mature bone:</b> arterial flow is <b>centrifugal</b> (inside → outside); venous flow is centripetal",
"<b>After fracture / immature bone:</b> periosteal system dominates → arterial flow becomes <b>centripetal</b>",
]:
story.append(bullet(item))
story.append(spacer(0.1))
story.append(sub_header("Clinical Points"))
for item in [
"Bone blood flow = major determinant of fracture healing quality",
"Flow peaks at ~2 weeks post-fracture; returns to normal in 3–5 months",
"<b>Unreamed intramedullary nails</b> preserve endosteal blood supply",
"<b>Reaming</b> devascularizes the inner 50–80% of cortex and delays endosteal revascularization",
]:
story.append(bullet(item))
story.append(source("— Miller's Review of Orthopaedics 9e, p. 25–26"))
story.append(spacer(0.3))
# ----- SECTION 9: Innervation -----
story.append(section_header("9. Innervation"))
story.append(spacer(0.15))
for item in [
"Most nerves entering the bone cavity (via nutrient artery) are <b>vasomotor fibers</b> regulating blood flow",
"Bone matrix itself has <b>few sensory nerve fibers</b>",
"The <b>periosteum</b> is densely innervated with sensory fibers — extremely pain-sensitive (explains deep periosteal pain with injury or tumors)",
]:
story.append(bullet(item))
story.append(source("— Gray's Anatomy for Students, p. 30"))
story.append(spacer(0.3))
# ----- SECTION 10: Key Exam Mnemonics -----
story.append(section_header("10. Key Exam Facts & Mnemonics"))
story.append(spacer(0.2))
mnemonic_headers = ["Fact", "Mnemonic / Rule"]
mnemonic_rows = [
["Bone collagen type", '"Bone" contains the word one → Type I collagen'],
["Cortical vs. cancellous fraction", "Cortical = 80%; Cancellous = 20% of skeleton"],
["Most abundant bone cell", "Osteocytes = 90% of all cells in mature skeleton"],
["Osteoblast origin", "Mesenchymal stem cell (MSC)"],
["Osteoclast origin", "Hematopoietic / macrophage lineage (monocyte fusion)"],
["RANKL effect", "Stimulates osteoclast differentiation → bone resorption ↑"],
["OPG effect", "Sequesters RANKL → blocks osteoclast activation → bone resorption ↓"],
["Wnt effect", "Promotes osteoblast survival & proliferation → bone mass ↑"],
["Sclerostin effect", "Inhibits Wnt signaling → inhibits osteoblast activity (produced by osteocytes)"],
["Woven vs. lamellar", "Woven = Weak, random, immature/pathologic; Lamellar = organized, strong, normal"],
["Arterial flow in mature bone", "Centrifugal (inside → out); reverses to centripetal after fracture"],
["Periosteum pain sensitivity", "Very sensitive (dense sensory innervation); bone itself has few sensory fibers"],
["PTH on osteoblasts", "Intermittent PTH → stimulates osteoblasts (anabolic); continuous PTH → promotes RANKL → osteoclast activation"],
["Calcitonin target", "Directly inhibits osteoclasts (bone resorption ↓)"],
["1,25(OH)₂D₃ on osteoblasts", "Stimulates matrix synthesis; increases osteocalcin production"],
]
story.append(make_table(mnemonic_headers, mnemonic_rows, [5.5*cm, 10.0*cm]))
story.append(spacer(0.4))
# Footer note
story.append(HRFlowable(width=W, thickness=0.5, color=MGRAY))
story.append(spacer(0.1))
story.append(Paragraph(
"Sources: Gray's Anatomy for Students (p. 30) | Miller's Review of Orthopaedics, 9th Ed. (pp. 20–26) | "
"Generated by Orris Medical AI",
ParagraphStyle("Footer", parent=styles["Normal"], fontSize=7.5,
textColor=colors.HexColor("#888888"), alignment=TA_CENTER)))
# ==============================
# BUILD PDF
# ==============================
doc.build(story)
print(f"PDF saved to: {OUTPUT}")
cd /home/daytona/workspace/bone-anatomy && python generate_pdf.py 2>&1
~/bone-anatomy/generate_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/bone-anatomy/generate_pdf.py'
cd /home/daytona/workspace/bone-anatomy && python generate_pdf.py 2>&1
General Bone Anatomy Structure
PDF Document · PDF