Explain Histology of Tonsils

Reading File
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Reading File
Reading File
Reading File
Finding Sources
Loading Image
Loading Image
Loading Image
Reading File
I have all the information I need. Let me now compose a thorough, well-illustrated answer.

Histology of Tonsils

Tonsils are masses of secondary lymphoid tissue that form Waldeyer's ring at the entrance to the oropharynx - a defensive ring surrounding the openings of the respiratory and digestive tracts. The ring consists of:
  • Palatine tonsils (paired, lateral)
  • Pharyngeal tonsil / adenoids (posterior-superior)
  • Lingual tonsil (on tongue base)
  • Tubal tonsils (near Eustachian tube openings)

1. Overall Architecture (Low Power)

Palatine Tonsil - H&E x47 (Orientation micrograph)
Low-power H&E section of palatine tonsil showing SSE (stratified squamous epithelium), TC (tonsillar crypts), L (lymphatic tissue masses), and MG (mucus-secreting glands)
Labels: SSE = stratified squamous epithelium, TC = tonsillar crypts, L = lymphatic tissue, MG = mucus-secreting glands
At low power, three features immediately stand out:
  • Dense hematoxylin-staining lymphoid aggregates (L) filling the parenchyma
  • Tonsillar crypts (TC) - channels formed by inward folding of the surface epithelium
  • Mucus-secreting glands (MG) at the bases of crypts

2. Surface Epithelium

The free (medial) surface of the palatine tonsil is covered by non-keratinized stratified squamous epithelium (SSE). This same epithelium dips inward to line the crypts.
Key feature: unlike most stratified squamous epithelia, the tonsillar epithelium is heavily infiltrated by lymphocytes that migrate from the underlying lamina propria. This is so pronounced that in many areas the epithelial-connective tissue boundary becomes indistinct or completely obliterated - making the tonsil unique among squamous-lined structures.

3. Tonsillar Crypts

  • There are 10-15 crypts on the free surface of each palatine tonsil
  • They are blind-ending, often highly branching invaginations that extend through the full thickness of the tonsil
  • Their walls contain lymphatic nodules - this dramatically increases the surface area for antigen sampling
  • The crypt epithelium is specifically adapted to allow antigen uptake from the oropharyngeal lumen

4. Lymphoid Tissue - Nodules and Germinal Centers

H&E x47 showing nodules (N), germinal centers (GC), surface epithelium (SE), submucosa (S), and lymphocytes (Ly)
H&E micrograph showing lymphatic nodules N with germinal centers GC, surface epithelium SE on right, submucosa S on left, and lymphocytes Ly infiltrating the epithelium
The body of the tonsil is packed with lymphatic nodules (N) that lie in the lamina propria/mucosa. Several key observations:
FeatureDescription
Nodule packingNodules are densely packed and often merge with each other
Germinal centers (GC)Many nodules show prominent pale-staining germinal centers, indicating active B-cell proliferation and differentiation
Mantle zoneDark-staining small lymphocytes surround the germinal center (not always obvious)
Nodule locationPrincipally in the mucosa, with walls of crypts also contributing
Germinal centers contain centroblasts and centrocytes (rapidly dividing B cells), follicular dendritic cells (antigen-presenting), and tingible body macrophages (clearing apoptotic cells - the "starry sky" appearance during active immune responses).

5. The Epithelial-Lymphocyte Interface (High Power)

H&E x365 - the defining histological feature of tonsil
This higher-power view shows the dramatic lymphocyte invasion of the epithelium:
  • Left side: clear basal cell (BC) layer visible; thin band of collagen fibers (CF) separates epithelium from lamina propria; only a few lymphocytes have entered the epithelium
  • Right side: lymphocytes have massively invaded; the collagen band is fragmented; isolated islands of epithelial cells (Ep) appear stranded within the nodule tissue
  • This process - called lymphocyte-epithelial interpenetration - is functionally important because it positions lymphocytes for immediate antigen sampling from swallowed/inhaled material

6. Connective Tissue and Capsule

  • Beneath the nodules lies the submucosa (S) - composed of dense connective tissue that is continuous deeper into the tonsil
  • The deep (lateral) surface of the palatine tonsil is covered by a fibrous hemicapsule - this separates it from the underlying superior constrictor muscle
  • Unlike lymph nodes, tonsils have no afferent lymphatic vessels - antigens enter directly through the overlying epithelium/crypts
  • Efferent lymphatics do drain the tonsillar tissue

7. Glands

Mucus-secreting glands (MG) are present deep to the tonsil, at the base of crypts. These are compound tubuloacinar glands that contribute mucus to the pharyngeal secretions.

8. Differences Among Tonsil Types

FeaturePalatine TonsilPharyngeal Tonsil (Adenoid)Lingual Tonsil
EpitheliumNon-keratinized stratified squamousPseudostratified ciliated columnar (respiratory)Non-keratinized stratified squamous
CryptsDeep, branching (10-15)Shallower folds/furrowsShallow, simple crypts
CapsuleHemicapsule presentIncomplete capsuleIncomplete/absent
LocationTonsillar fossa (lateral oropharynx)Posterior nasopharynxBase of tongue

9. Functional Significance

  • Tonsils lack afferent lymphatics - they sample antigens directly from the environment through the epithelium and crypts
  • The lymphoid tissue undergoes antigen-dependent B-cell activation in germinal centers, producing IgA, IgG, and IgM
  • They are most active immunologically in childhood and begin to atrophy at puberty; by old age, only remnant lymphoid tissue remains
  • Repeated infections can lead to crypts harboring bacteria, causing chronic tonsillitis that may necessitate tonsillectomy

Sources: Histology: A Text and Atlas with Correlated Cell and Molecular Biology (p. 1256-1259); Scott-Brown's Otorhinolaryngology Head & Neck Surgery, Palatine Tonsil section (p. 679)

Create a quick reference PDF comparing palatine, pharyngeal, and lingual tonsil histology

Reading File
Running Command

ls -la /home/daytona/workspace/ 2>/dev/null || echo "workspace does not exist"

Running Command

mkdir -p /home/daytona/workspace/tonsil-pdf && python3 -c "import reportlab; print('reportlab ok')" && python3 -c "from reportlab.lib.pagesizes import A4; print('A4 ok')"

Writing File

~/tonsil-pdf/build_pdf.py

from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm, mm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    HRFlowable, KeepTogether
)
from reportlab.platypus.flowables import Flowable
from reportlab.graphics.shapes import Drawing, Rect, String, Circle, Line
from reportlab.graphics import renderPDF
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
import os

# ── Colour palette ──────────────────────────────────────────────────────────
DARK_NAVY   = colors.HexColor("#1a2744")
MID_BLUE    = colors.HexColor("#2c4a8c")
LIGHT_BLUE  = colors.HexColor("#d9e4f5")
PALE_GREY   = colors.HexColor("#f4f6fb")
ACCENT_GOLD = colors.HexColor("#c8860a")
TEXT_DARK   = colors.HexColor("#1c1c2e")
TEXT_MID    = colors.HexColor("#3a3a5c")
WHITE       = colors.white

# Palatine / Pharyngeal / Lingual accent colours
COL_PAL  = colors.HexColor("#2c6fad")   # blue
COL_PHA  = colors.HexColor("#1e8a5e")   # teal-green
COL_LIN  = colors.HexColor("#8e3abf")   # purple

PATH = "/home/daytona/workspace/tonsil-pdf/Tonsil_Histology_Reference.pdf"

doc = SimpleDocTemplate(
    PATH,
    pagesize=A4,
    leftMargin=1.8*cm, rightMargin=1.8*cm,
    topMargin=1.6*cm, bottomMargin=1.8*cm,
    title="Tonsil Histology Quick Reference",
    author="Orris Medical Library",
)

W, H = A4
BODY_W = W - 3.6*cm

styles = getSampleStyleSheet()

def s(name, **kw):
    return ParagraphStyle(name, parent=styles["Normal"], **kw)

# ── Custom paragraph styles ──────────────────────────────────────────────────
TITLE_S = s("TITLE_S", fontSize=20, textColor=WHITE,
            fontName="Helvetica-Bold", alignment=TA_CENTER, leading=26)
SUBTITLE_S = s("SUBTITLE_S", fontSize=10, textColor=colors.HexColor("#c8d8f0"),
               fontName="Helvetica", alignment=TA_CENTER, leading=14)
SEC_HEAD = s("SEC_HEAD", fontSize=13, textColor=WHITE,
             fontName="Helvetica-Bold", alignment=TA_LEFT, leading=17)
BODY_S = s("BODY_S", fontSize=8.5, textColor=TEXT_DARK,
           fontName="Helvetica", leading=12, alignment=TA_JUSTIFY)
BOLD_S = s("BOLD_S", fontSize=8.5, textColor=TEXT_DARK,
           fontName="Helvetica-Bold", leading=12)
LABEL_S = s("LABEL_S", fontSize=7.5, textColor=TEXT_MID,
            fontName="Helvetica-BoldOblique", leading=10)
FOOT_S  = s("FOOT_S", fontSize=7, textColor=TEXT_MID,
            fontName="Helvetica-Oblique", alignment=TA_CENTER, leading=9)
KEY_S   = s("KEY_S", fontSize=8, textColor=TEXT_DARK,
            fontName="Helvetica", leading=11)
KEY_BOLD= s("KEY_BOLD", fontSize=8, textColor=TEXT_DARK,
            fontName="Helvetica-Bold", leading=11)

# ── Flowable helpers ─────────────────────────────────────────────────────────
class ColorRect(Flowable):
    def __init__(self, w, h, fill, radius=4):
        self.width, self.height, self.fill, self.radius = w, h, fill, radius
    def draw(self):
        self.canv.setFillColor(self.fill)
        self.canv.roundRect(0, 0, self.width, self.height, self.radius, fill=1, stroke=0)

class HeaderBanner(Flowable):
    def __init__(self, w):
        self.width = w
        self.height = 70
    def draw(self):
        c = self.canv
        # gradient-like background using two rects
        c.setFillColor(DARK_NAVY)
        c.roundRect(0, 0, self.width, self.height, 6, fill=1, stroke=0)
        # top accent stripe
        c.setFillColor(MID_BLUE)
        c.rect(0, self.height - 8, self.width, 8, fill=1, stroke=0)
        c.setFillColor(ACCENT_GOLD)
        c.rect(0, self.height - 11, self.width, 3, fill=1, stroke=0)

class SectionBanner(Flowable):
    def __init__(self, text, accent_color, w):
        self.text = text
        self.accent = accent_color
        self.width = w
        self.height = 28
    def draw(self):
        c = self.canv
        c.setFillColor(DARK_NAVY)
        c.roundRect(0, 0, self.width, self.height, 4, fill=1, stroke=0)
        c.setFillColor(self.accent)
        c.rect(0, 0, 5, self.height, fill=1, stroke=0)
        c.setFont("Helvetica-Bold", 11)
        c.setFillColor(WHITE)
        c.drawString(12, 9, self.text)

class DiagramFlowable(Flowable):
    """Hand-drawn schematic cross-section of each tonsil type."""
    def __init__(self, tonsil_type, w=None, h=None):
        self.tonsil_type = tonsil_type
        self.width  = w or 5.5*cm
        self.height = h or 4.2*cm
    def draw(self):
        c = self.canv
        W, H = self.width, self.height
        cx, cy = W/2, H/2

        if self.tonsil_type == "palatine":
            self._draw_palatine(c, W, H)
        elif self.tonsil_type == "pharyngeal":
            self._draw_pharyngeal(c, W, H)
        else:
            self._draw_lingual(c, W, H)

    def _draw_palatine(self, c, W, H):
        # Outer border
        c.setFillColor(colors.HexColor("#e8f0fa"))
        c.roundRect(2, 2, W-4, H-4, 5, fill=1, stroke=0)
        # Capsule
        c.setStrokeColor(colors.HexColor("#6a8cbf"))
        c.setLineWidth(1.5)
        c.roundRect(4, 4, W-8, H-8, 4, fill=0, stroke=1)
        # Lymphoid nodules with GC
        nodule_positions = [(W*0.27, H*0.62), (W*0.58, H*0.65), (W*0.43, H*0.35)]
        for nx, ny in nodule_positions:
            r = W*0.13
            c.setFillColor(colors.HexColor("#9db8d6"))
            c.setStrokeColor(colors.HexColor("#6a8cbf"))
            c.setLineWidth(0.5)
            c.circle(nx, ny, r, fill=1, stroke=1)
            # germinal centre
            c.setFillColor(colors.HexColor("#d4e3f7"))
            c.circle(nx, ny, r*0.45, fill=1, stroke=0)
        # Crypts (invaginations from top surface)
        c.setStrokeColor(colors.HexColor("#3a5a8c"))
        c.setLineWidth(1)
        for cx_pos in [W*0.22, W*0.42, W*0.65]:
            c.line(cx_pos, H-4, cx_pos, H*0.7)
        # Surface epithelium label line
        c.setFillColor(colors.HexColor("#1a2744"))
        c.setFont("Helvetica-Bold", 5)
        c.drawString(3, H-8, "SSE")
        c.setFont("Helvetica", 5)
        c.drawString(3, H*0.6, "GC")
        c.drawString(W*0.7, H*0.25, "Capsule")
        c.drawString(W*0.32, H-12, "Crypts")

    def _draw_pharyngeal(self, c, W, H):
        c.setFillColor(colors.HexColor("#e8f5ee"))
        c.roundRect(2, 2, W-4, H-4, 5, fill=1, stroke=0)
        c.setStrokeColor(colors.HexColor("#3a8a5e"))
        c.setLineWidth(1.5)
        c.roundRect(4, 4, W-8, H-8, 4, fill=0, stroke=1)
        # Pseudo-ciliated columnar surface (wavy top)
        c.setStrokeColor(colors.HexColor("#3a8a5e"))
        c.setLineWidth(1)
        path = c.beginPath()
        path.moveTo(6, H-7)
        for i in range(8):
            x = 6 + i*(W-12)/7
            y_up = H - 4
            y_dn = H - 10
            path.curveTo(x + 3, y_up, x + 5, y_dn, x + (W-12)/7, H - 7)
        c.drawPath(path, stroke=1, fill=0)
        # Folds/furrows (less deep than crypts)
        for fx in [W*0.3, W*0.55]:
            c.line(fx, H-10, fx, H*0.6)
        # Lymphoid tissue
        nodule_positions = [(W*0.28, H*0.42), (W*0.55, H*0.45), (W*0.42, H*0.25)]
        for nx, ny in nodule_positions:
            r = W*0.12
            c.setFillColor(colors.HexColor("#7dc2a0"))
            c.setStrokeColor(colors.HexColor("#3a8a5e"))
            c.setLineWidth(0.5)
            c.circle(nx, ny, r, fill=1, stroke=1)
            c.setFillColor(colors.HexColor("#c8ead9"))
            c.circle(nx, ny, r*0.45, fill=1, stroke=0)
        c.setFillColor(colors.HexColor("#1a2744"))
        c.setFont("Helvetica-Bold", 5)
        c.drawString(3, H-8, "PCCE")
        c.setFont("Helvetica", 5)
        c.drawString(W*0.34, H-14, "Folds")
        c.drawString(W*0.3, H*0.22, "GC")

    def _draw_lingual(self, c, W, H):
        c.setFillColor(colors.HexColor("#f0e8fa"))
        c.roundRect(2, 2, W-4, H-4, 5, fill=1, stroke=0)
        c.setStrokeColor(colors.HexColor("#7a3abf"))
        c.setLineWidth(1.5)
        c.roundRect(4, 4, W-8, H-8, 4, fill=0, stroke=1)
        # Flat SSE surface
        c.setFillColor(colors.HexColor("#c8b0e0"))
        c.rect(4, H-12, W-8, 8, fill=1, stroke=0)
        # Single simple crypt
        c.setStrokeColor(colors.HexColor("#5a2a8c"))
        c.setLineWidth(1.2)
        c.line(W/2, H-12, W/2, H*0.5)
        # Fewer lymphoid nodules
        for nx, ny in [(W*0.3, H*0.38), (W*0.65, H*0.42)]:
            r = W*0.12
            c.setFillColor(colors.HexColor("#b088d4"))
            c.setStrokeColor(colors.HexColor("#7a3abf"))
            c.setLineWidth(0.5)
            c.circle(nx, ny, r, fill=1, stroke=1)
            c.setFillColor(colors.HexColor("#ddd0f0"))
            c.circle(nx, ny, r*0.45, fill=1, stroke=0)
        c.setFillColor(colors.HexColor("#1a2744"))
        c.setFont("Helvetica-Bold", 5)
        c.drawString(3, H-8, "SSE")
        c.setFont("Helvetica", 5)
        c.drawString(W*0.35, H-16, "Crypt")
        c.drawString(W*0.28, H*0.22, "GC")
        c.drawString(W*0.55, H*0.18, "(fewer)")


# ════════════════════════════════════════════════════════════════════════════
# BUILD CONTENT
# ════════════════════════════════════════════════════════════════════════════
story = []

# ── HEADER ──────────────────────────────────────────────────────────────────
story.append(HeaderBanner(BODY_W))

# Title text overlaid (achieved by table-in-table trick)
title_table = Table([[
    Paragraph("TONSIL HISTOLOGY", TITLE_S),
]], colWidths=[BODY_W])
title_table.setStyle(TableStyle([
    ("BACKGROUND",  (0,0), (-1,-1), colors.transparent),
    ("TOPPADDING",  (0,0), (-1,-1), 10),
    ("BOTTOMPADDING",(0,0),(-1,-1), 4),
]))
story.append(Spacer(1, -60))
story.append(title_table)

sub_table = Table([[
    Paragraph("Quick Reference · Palatine · Pharyngeal · Lingual · Waldeyer's Ring", SUBTITLE_S)
]], colWidths=[BODY_W])
sub_table.setStyle(TableStyle([("TOPPADDING",(0,0),(-1,-1),0),("BOTTOMPADDING",(0,0),(-1,-1),10)]))
story.append(sub_table)

story.append(Spacer(1, 10))

# ── WALDEYER'S RING INTRO BOX ────────────────────────────────────────────────
intro_text = (
    "<b>Waldeyer's ring</b> is a circular arrangement of secondary lymphoid tissue guarding the "
    "openings of the respiratory and digestive tracts. It comprises the <b>palatine tonsils</b> "
    "(paired, lateral oropharynx), <b>pharyngeal tonsil / adenoids</b> (posterior nasopharynx), "
    "<b>lingual tonsil</b> (tongue base), and tubal tonsils (near Eustachian tube openings). "
    "All tonsils share lymphoid nodules with germinal centres but differ in epithelial type, "
    "crypt morphology, and capsule completeness."
)
intro_box = Table([[Paragraph(intro_text, BODY_S)]], colWidths=[BODY_W-16])
intro_box.setStyle(TableStyle([
    ("BACKGROUND",   (0,0),(-1,-1), LIGHT_BLUE),
    ("BOX",          (0,0),(-1,-1), 0.5, MID_BLUE),
    ("LEFTPADDING",  (0,0),(-1,-1), 10),
    ("RIGHTPADDING", (0,0),(-1,-1), 10),
    ("TOPPADDING",   (0,0),(-1,-1), 8),
    ("BOTTOMPADDING",(0,0),(-1,-1), 8),
    ("ROUNDEDCORNERS", (0,0),(-1,-1), [4,4,4,4]),
]))
story.append(intro_box)
story.append(Spacer(1, 10))

# ── THREE TONSIL COLUMNS ─────────────────────────────────────────────────────
COL_W = (BODY_W - 8) / 3

def tonsil_section(name, accent, diagram_key, rows):
    """Build one tonsil column card."""
    elements = []
    # Header
    hdr = Table([[Paragraph(name, SEC_HEAD)]], colWidths=[COL_W])
    hdr.setStyle(TableStyle([
        ("BACKGROUND",   (0,0),(-1,-1), accent),
        ("LEFTPADDING",  (0,0),(-1,-1), 8),
        ("TOPPADDING",   (0,0),(-1,-1), 6),
        ("BOTTOMPADDING",(0,0),(-1,-1), 6),
        ("ROUNDEDCORNERS",(0,0),(-1,-1),[4,4,0,0]),
    ]))
    elements.append(hdr)

    # Diagram
    diag = DiagramFlowable(diagram_key, w=COL_W-4, h=3.6*cm)
    diag_tbl = Table([[diag]], colWidths=[COL_W])
    diag_tbl.setStyle(TableStyle([
        ("BACKGROUND",   (0,0),(-1,-1), PALE_GREY),
        ("ALIGN",        (0,0),(-1,-1), "CENTER"),
        ("TOPPADDING",   (0,0),(-1,-1), 6),
        ("BOTTOMPADDING",(0,0),(-1,-1), 6),
    ]))
    elements.append(diag_tbl)

    # Rows
    for label, value in rows:
        row_tbl = Table([
            [Paragraph(label, LABEL_S)],
            [Paragraph(value, BODY_S)],
        ], colWidths=[COL_W])
        row_tbl.setStyle(TableStyle([
            ("BACKGROUND",   (0,0), (0,0), colors.HexColor("#eef2fc")),
            ("BACKGROUND",   (0,1), (0,1), WHITE),
            ("LEFTPADDING",  (0,0),(-1,-1), 6),
            ("RIGHTPADDING", (0,0),(-1,-1), 6),
            ("TOPPADDING",   (0,0),(0,0), 3),
            ("BOTTOMPADDING",(0,0),(0,0), 2),
            ("TOPPADDING",   (0,1),(0,1), 2),
            ("BOTTOMPADDING",(0,1),(0,1), 4),
            ("LINEBELOW",    (0,1),(0,1), 0.3, colors.HexColor("#dde4f0")),
        ]))
        elements.append(row_tbl)

    # Bottom border
    bot = Table([[""]], colWidths=[COL_W])
    bot.setStyle(TableStyle([
        ("BACKGROUND",  (0,0),(-1,-1), accent),
        ("TOPPADDING",  (0,0),(-1,-1), 3),
        ("BOTTOMPADDING",(0,0),(-1,-1), 3),
        ("ROUNDEDCORNERS",(0,0),(-1,-1),[0,0,4,4]),
    ]))
    elements.append(bot)
    return elements

palatine_rows = [
    ("LOCATION",          "Tonsillar fossa, lateral oropharynx; between palatoglossal and palatopharyngeal arches"),
    ("EPITHELIUM",        "<b>Non-keratinized stratified squamous epithelium (SSE)</b>; heavily infiltrated by lymphocytes"),
    ("CRYPTS",            "<b>10–15 deep, branching crypts</b> extending full thickness of tonsil; walls bear lymphoid nodules"),
    ("CAPSULE",           "Well-defined fibrous <b>hemicapsule</b> on deep (lateral) surface; separates from superior constrictor"),
    ("LYMPHOID TISSUE",   "Dense, packed secondary lymphoid nodules with prominent <b>germinal centres (GC)</b>; mantle zones present"),
    ("GERMINAL CENTRES",  "Active B-cell proliferation; centroblasts, centrocytes, follicular dendritic cells, tingible body macrophages"),
    ("LYMPHOCYTE INVASION","Characteristic: lymphocytes massively invade SSE, disrupting epithelial–CT boundary; 'reticular' / lympho-epithelium"),
    ("SUBMUCOSA",         "Dense connective tissue deep to nodules; mucus-secreting compound tubuloacinar glands at crypt bases"),
    ("AFFERENT LYMPHATICS","<b>Absent</b> – antigen sampling occurs directly via crypt epithelium and infiltrating lymphocytes"),
    ("EFFERENT LYMPHATICS","Present; drain to jugulodigastric (tonsillar) nodes"),
    ("BLOOD SUPPLY",      "Tonsillar branch of facial artery (main); paratonsillar vein runs lateral to capsule (risk in tonsillectomy)"),
    ("INVOLUTION",        "Hypertrophied in childhood; <b>atrophies at puberty</b>; remnants persist in old age"),
    ("CLINICAL NOTE",     "Deep crypts harbour bacteria → recurrent tonsillitis; asymmetric enlargement warrants biopsy to exclude lymphoma"),
]

pharyngeal_rows = [
    ("LOCATION",          "Posterior roof of nasopharynx; forms posterosuperior arc of Waldeyer's ring"),
    ("EPITHELIUM",        "<b>Pseudostratified ciliated columnar (respiratory) epithelium</b> predominates; patches of SSE may occur"),
    ("CRYPTS",            "Shallower folds/furrows (not true branching crypts); less complex than palatine"),
    ("CAPSULE",           "<b>Incomplete capsule</b>; fibrous septa extend into the lymphoid tissue forming lobules"),
    ("LYMPHOID TISSUE",   "Secondary lymphoid nodules with germinal centres; organised into lobules separated by fibrous septa"),
    ("GERMINAL CENTRES",  "Present but less prominent than in palatine tonsil"),
    ("LYMPHOCYTE INVASION","Present but less marked; ciliated epithelium partially replaced by infiltrating lymphocytes in active tissue"),
    ("SUBMUCOSA",         "Fibromuscular layer; mucous glands present"),
    ("AFFERENT LYMPHATICS","<b>Absent</b>"),
    ("EFFERENT LYMPHATICS","Drain to retropharyngeal and upper deep cervical nodes"),
    ("BLOOD SUPPLY",      "Ascending pharyngeal artery; branches of internal maxillary artery"),
    ("INVOLUTION",        "Maximal size 3–7 years; <b>regresses by puberty</b>; clinically insignificant in adults"),
    ("CLINICAL NOTE",     "Hypertrophy (adenoids) causes nasal obstruction, otitis media; adenoidectomy common in children"),
]

lingual_rows = [
    ("LOCATION",          "Posterior third (base) of tongue, behind sulcus terminalis; forms inferior arc of Waldeyer's ring"),
    ("EPITHELIUM",        "<b>Non-keratinized stratified squamous epithelium (SSE)</b>, similar to palatine tonsil"),
    ("CRYPTS",            "<b>Single, simple, unbranched crypt</b> per lymphoid nodule – much simpler than palatine"),
    ("CAPSULE",           "<b>No capsule</b>; lymphoid tissue merges with tongue musculature"),
    ("LYMPHOID TISSUE",   "Discrete but smaller lymphoid follicles; germinal centres present; less densely packed than palatine"),
    ("GERMINAL CENTRES",  "Present; less conspicuous; fewer nodules per unit area"),
    ("LYMPHOCYTE INVASION","Present in SSE; less dramatic than palatine"),
    ("SUBMUCOSA",         "Merges with tongue musculature; mucous and serous glands (of von Ebner) nearby"),
    ("AFFERENT LYMPHATICS","<b>Absent</b>"),
    ("EFFERENT LYMPHATICS","Drain to submental and submandibular nodes"),
    ("BLOOD SUPPLY",      "Lingual artery (dorsal lingual branches)"),
    ("INVOLUTION",        "Hypertrophy may occur if palatine tonsils removed (compensatory); gradual regression with age"),
    ("CLINICAL NOTE",     "May enlarge post-tonsillectomy; lingual tonsillar hypertrophy can cause dysphagia/snoring"),
]

pal_col  = tonsil_section("PALATINE TONSIL",    COL_PAL, "palatine",   palatine_rows)
pha_col  = tonsil_section("PHARYNGEAL TONSIL",  COL_PHA, "pharyngeal", pharyngeal_rows)
lin_col  = tonsil_section("LINGUAL TONSIL",     COL_LIN, "lingual",    lingual_rows)

# Zip all rows together
max_rows = max(len(pal_col), len(pha_col), len(lin_col))
def pad(lst, n): return lst + [Spacer(1,1)] * (n - len(lst))
pal_col = pad(pal_col, max_rows)
pha_col = pad(pha_col, max_rows)
lin_col = pad(lin_col, max_rows)

three_col_data = [[p, q, r] for p, q, r in zip(pal_col, pha_col, lin_col)]
three_col = Table(three_col_data, colWidths=[COL_W, COL_W, COL_W], spaceBefore=0)
three_col.setStyle(TableStyle([
    ("VALIGN",       (0,0),(-1,-1), "TOP"),
    ("LEFTPADDING",  (0,0),(-1,-1), 2),
    ("RIGHTPADDING", (0,0),(-1,-1), 2),
    ("TOPPADDING",   (0,0),(-1,-1), 0),
    ("BOTTOMPADDING",(0,0),(-1,-1), 0),
]))
story.append(three_col)
story.append(Spacer(1, 10))

# ── COMPARISON TABLE ─────────────────────────────────────────────────────────
story.append(SectionBanner("AT-A-GLANCE COMPARISON", ACCENT_GOLD, BODY_W))
story.append(Spacer(1, 6))

comp_headers = ["Feature", "Palatine", "Pharyngeal (Adenoid)", "Lingual"]
comp_rows = [
    ["Epithelium",         "Non-kerat. SSE",          "Pseudostrat. ciliated columnar", "Non-kerat. SSE"],
    ["Crypts",             "10–15, deep, branching",  "Shallow folds/furrows",          "1 per nodule, simple"],
    ["Capsule",            "Hemicapsule (well-defined)","Incomplete",                   "Absent"],
    ["Lymph. nodules",     "Dense, closely packed",   "Lobulated by septa",             "Discrete, fewer"],
    ["Germinal centres",   "Prominent",               "Present",                        "Present, less conspicuous"],
    ["Lymphocyte invasion\nof epithelium", "Marked – hallmark feature", "Moderate",     "Mild–moderate"],
    ["Afferent lymphatics","Absent",                  "Absent",                         "Absent"],
    ["Involution",         "Puberty",                 "Puberty (3–7 yrs peak)",         "Gradual"],
    ["Waldeyer's position","Lateral",                 "Posterosuperior",                "Inferior (tongue base)"],
]

comp_col_w = [BODY_W*0.22, BODY_W*0.24, BODY_W*0.27, BODY_W*0.27]
comp_style = [
    ("BACKGROUND",    (0,0), (-1,0),  DARK_NAVY),
    ("TEXTCOLOR",     (0,0), (-1,0),  WHITE),
    ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
    ("FONTSIZE",      (0,0), (-1,-1), 7.5),
    ("FONTNAME",      (0,1), (0,-1),  "Helvetica-Bold"),
    ("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, PALE_GREY]),
    ("ALIGN",         (0,0), (-1,-1), "LEFT"),
    ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ("LEFTPADDING",   (0,0), (-1,-1), 5),
    ("RIGHTPADDING",  (0,0), (-1,-1), 5),
    ("TOPPADDING",    (0,0), (-1,-1), 4),
    ("BOTTOMPADDING", (0,0), (-1,-1), 4),
    ("GRID",          (0,0), (-1,-1), 0.3, colors.HexColor("#c0cce0")),
    ("TEXTCOLOR",     (1,1), (1,-1),  COL_PAL),
    ("TEXTCOLOR",     (2,1), (2,-1),  COL_PHA),
    ("TEXTCOLOR",     (3,1), (3,-1),  COL_LIN),
]

header_cells = [Paragraph(h, ParagraphStyle("CH", fontName="Helvetica-Bold",
               fontSize=7.5, textColor=WHITE, leading=10)) for h in comp_headers]
body_cells = [[Paragraph(str(cell), ParagraphStyle("CC", fontName="Helvetica" if i>0 else "Helvetica-Bold",
               fontSize=7.5, textColor=COL_PAL if i==1 else (COL_PHA if i==2 else (COL_LIN if i==3 else TEXT_DARK)),
               leading=10)) for i, cell in enumerate(row)] for row in comp_rows]

comp_tbl = Table([header_cells] + body_cells, colWidths=comp_col_w)
comp_tbl.setStyle(TableStyle(comp_style))
story.append(comp_tbl)
story.append(Spacer(1, 10))

# ── KEY HISTOLOGICAL FEATURES BOX ────────────────────────────────────────────
story.append(SectionBanner("KEY HISTOLOGICAL FEATURES & MNEMONICS", MID_BLUE, BODY_W))
story.append(Spacer(1, 6))

key_data = [
    ["Lympho-epithelium",
     "Lymphocytes migrate into the surface/crypt epithelium of all tonsils. In palatine tonsil this is most extreme – the epithelial–CT boundary is obliterated and epithelial islands (Ep) appear within lymphoid nodules."],
    ["No afferent lymphatics",
     "Unlike lymph nodes, tonsils have NO afferent lymphatic vessels. Antigens enter directly through the overlying epithelium/crypts. Efferent lymphatics are present."],
    ["Germinal centres",
     "Pale-staining zones within dark lymphoid nodules. Contain centroblasts (large, dividing B cells), centrocytes, follicular dendritic cells, and tingible body macrophages (starry-sky appearance in reactive GCs)."],
    ["Capsule mnemonic",
     "P-P-L rule: Palatine → Partial (hemi)capsule | Pharyngeal → Partial (incomplete) | Lingual → Lacks capsule entirely"],
    ["Epithelium mnemonic",
     "Pharyngeal = P for Pseudostratified (respiratory) – faces the airway. Palatine & Lingual = Squamous – faces food/swallowing."],
    ["Crypt complexity",
     "Palatine > Lingual > Pharyngeal. Palatine crypts are deep and branching, making them prone to harbouring debris and bacteria."],
]

key_rows_tbl_data = []
for feature, desc in key_data:
    key_rows_tbl_data.append([
        Paragraph(feature, KEY_BOLD),
        Paragraph(desc, KEY_S),
    ])

key_tbl = Table(key_rows_tbl_data, colWidths=[BODY_W*0.22, BODY_W*0.78])
key_tbl.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (0,-1), LIGHT_BLUE),
    ("BACKGROUND",    (1,0), (1,-1), WHITE),
    ("ROWBACKGROUNDS",(1,0), (1,-1), [WHITE, PALE_GREY]),
    ("VALIGN",        (0,0), (-1,-1), "TOP"),
    ("LEFTPADDING",   (0,0), (-1,-1), 6),
    ("RIGHTPADDING",  (0,0), (-1,-1), 6),
    ("TOPPADDING",    (0,0), (-1,-1), 4),
    ("BOTTOMPADDING", (0,0), (-1,-1), 4),
    ("LINEBELOW",     (0,0), (-1,-2), 0.3, colors.HexColor("#c0cce0")),
    ("BOX",           (0,0), (-1,-1), 0.5, MID_BLUE),
]))
story.append(key_tbl)
story.append(Spacer(1, 8))

# ── FOOTER ───────────────────────────────────────────────────────────────────
story.append(HRFlowable(width=BODY_W, thickness=0.5, color=ACCENT_GOLD))
story.append(Spacer(1, 3))
story.append(Paragraph(
    "Sources: Histology: A Text and Atlas with Correlated Cell and Molecular Biology (Ross & Pawlina), pp. 1256–1259 · "
    "Scott-Brown's Otorhinolaryngology Head &amp; Neck Surgery · Orris Medical Library | Generated June 2026",
    FOOT_S
))

# ── BUILD ─────────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF saved to: {PATH}")
Running Command

cd /home/daytona/workspace/tonsil-pdf && python3 build_pdf.py 2>&1

Running Command

ls -lh /home/daytona/workspace/tonsil-pdf/Tonsil_Histology_Reference.pdf

Your PDF is ready for download:

Tonsil Histology Reference

PDF Document · PDF


Here's what's included in the document:
Layout - single A4 page, three-column design:
  1. Header banner - titled "Tonsil Histology Quick Reference" with Waldeyer's Ring overview box
  2. Three side-by-side tonsil columns (colour-coded: blue / teal / purple) each containing:
    • Schematic cross-section diagram showing the epithelium, crypts, lymphoid nodules, and germinal centres
    • 13 labelled fields: Location, Epithelium, Crypts, Capsule, Lymphoid tissue, Germinal centres, Lymphocyte invasion, Submucosa, Afferent/Efferent lymphatics, Blood supply, Involution, Clinical note
  3. At-a-glance comparison table - all three tonsils across 9 features in a single row
  4. Key histological features & mnemonics panel covering:
    • Lympho-epithelium (the defining hallmark)
    • No afferent lymphatics rule
    • Germinal centre cell composition
    • P-P-L capsule mnemonic (Palatine = Partial hemicapsule, Pharyngeal = Partial, Lingual = Lacks)
    • Epithelium mnemonic (Pharyngeal = Pseudostratified facing the airway; others = Squamous)
    • Crypt complexity ranking
This is a shared conversation. Sign in to Orris to start your own chat.