Tft in detail for notes and in clinical use simple way and understanding
Hypothalamus → TRH (Thyrotropin-Releasing Hormone)
↓
Pituitary → TSH (Thyroid-Stimulating Hormone)
↓
Thyroid gland → T4 (Thyroxine) + T3 (Triiodothyronine)
↓
Negative feedback back to hypothalamus + pituitary
Step 1: Measure TSH
│
├─ TSH NORMAL → Thyroid dysfunction essentially excluded (stop)
│
├─ TSH HIGH → Add free T4
│ ├─ High TSH + Low fT4 = OVERT HYPOTHYROIDISM
│ └─ High TSH + Normal fT4 = SUBCLINICAL HYPOTHYROIDISM
│
└─ TSH LOW → Add free T4 AND free/total T3
├─ Low TSH + High fT4/T3 = OVERT HYPERTHYROIDISM
├─ Low TSH + Normal fT4 → Check free T3
│ ├─ High T3 = T3 TOXICOSIS
│ └─ Normal T3 = SUBCLINICAL HYPERTHYROIDISM
└─ Very low/undetectable TSH alone = significant thyrotoxicosis
| Condition | TSH | fT4 | T3 | Notes |
|---|---|---|---|---|
| Overt hypothyroidism | ↑↑ | ↓ | ↓ or normal | Most common: Hashimoto |
| Subclinical hypothyroidism | ↑ | Normal | Normal | Earliest form |
| Overt hyperthyroidism | ↓↓ | ↑ | ↑ | Most common: Graves |
| Subclinical hyperthyroidism | ↓ | Normal | Normal | Treat if symptomatic |
| T3 toxicosis | ↓ | Normal | ↑↑ | ~5% of hyperthyroid cases |
| Central hypothyroidism (pituitary) | Low/normal | ↓ | ↓ | TSH fails to rise despite low T4 |
| Euthyroid sick syndrome | Low/normal | ↓ | ↓↓, rT3 ↑ | Critically ill patients |
| Pregnancy/estrogens (normal) | Normal | Normal | Normal (fT4) | Total T4 ↑ due to TBG, but fT4 normal |
| Antibody | What it Tells You | Associated Condition |
|---|---|---|
| Anti-TPO (anti-microsomal) | Autoimmune thyroid disease | Hashimoto (high sensitivity), also Graves |
| Anti-Tg (anti-thyroglobulin) | Autoimmune thyroid disease | Hashimoto; interferes with Tg tumor marker |
| TRAb / TSI / LATS (TSH receptor antibody) | Highly specific for Graves disease | Graves (stimulating antibody mimics TSH) |
| Drug | Effect | Mechanism |
|---|---|---|
| Amiodarone | Hypo or hyper | Contains ~37% iodine by weight; direct thyroid toxicity + iodine load. Hypo in iodine-sufficient patients; Hyper in iodine-deficient or multinodular goiter patients |
| Lithium | Hypothyroidism (15-50%) | Inhibits thyroid hormone synthesis AND secretion; concentrated by thyroid gland |
| Iodine/contrast media | Hypo (Wolff-Chaikoff) or hyper (Jod-Basedow) | Excess iodine → hypothyroidism (Wolff-Chaikoff); iodine deficiency + iodine load → hyperthyroidism (Jod-Basedow) |
| Tyrosine kinase inhibitors | Hypothyroidism | Varies by agent |
| Immune modulators (IFN-α, checkpoint inhibitors) | Hypo or hyper | Autoimmune thyroiditis |
| Drug | Effect on Tests | TSH | Mechanism |
|---|---|---|---|
| Estrogens, tamoxifen, raloxifene | ↑ Total T4, ↑ Total T3 | Normal | ↑ TBG production |
| Androgens | ↓ Total T4 | Normal | ↓ TBG |
| Furosemide (high dose), salicylates | ↓ Total T4 | Normal | Compete with T4 for TBG binding |
| Phenytoin, carbamazepine, rifampin, phenobarbital | ↓ Total T4 (+ accelerate T4 clearance) | Normal or ↓ | Displace T4 from TBG; increase T4 metabolism |
| Heparin/LMWH | ↑ Free T4 (artifact) | Normal | Liberate free fatty acids that displace T4 from TBG in vitro |
| Glucocorticoids, dopamine | ↓ TSH | Normal T4/T3 | Suppress TSH secretion directly |
| Propranolol (high dose) | ↓ T3 | Normal | Inhibits peripheral T4→T3 conversion |
| Biotin | Spurious results in ALL thyroid assays | False | Interferes with immunoassay streptavidin-biotin system; hold 1-2 days before testing |
Clinical tip: In patients on estrogens or OCPs - total T4/T3 will be high, but free T4 and TSH are normal. Patient is euthyroid. No intervention needed.
Create a downloadable quick reference PDF for TFT interpretation
ls -la /home/daytona/workspace/ 2>/dev/null || mkdir -p /home/daytona/workspace && echo "workspace ready"
mkdir -p /home/daytona/workspace/tft-pdf && python3 -c "import reportlab; print('reportlab OK')" && python3 -c "from reportlab.platypus import SimpleDocTemplate; print('platypus OK')"
~/tft-pdf/make_tft_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm, cm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether, PageBreak
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT
from reportlab.platypus import Flowable
import reportlab.platypus as plat
# ── Colour palette ─────────────────────────────────────────────────────────────
NAVY = colors.HexColor("#1B2A4A")
TEAL = colors.HexColor("#0D7377")
MINT = colors.HexColor("#14BDAC")
LIGHT_BG = colors.HexColor("#F0F7F7")
AMBER = colors.HexColor("#F5A623")
RED_SOFT = colors.HexColor("#E74C3C")
GREEN_SOFT= colors.HexColor("#27AE60")
GREY_LITE = colors.HexColor("#ECF0F1")
GREY_MID = colors.HexColor("#BDC3C7")
WHITE = colors.white
BLACK = colors.HexColor("#1A1A1A")
W, H = A4 # 595.28 x 841.89 pt
# ── Styles ─────────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
def S(name, **kw):
return ParagraphStyle(name, **kw)
HDR_TITLE = S("HDR_TITLE", fontName="Helvetica-Bold", fontSize=22,
textColor=WHITE, alignment=TA_CENTER, leading=28)
HDR_SUB = S("HDR_SUB", fontName="Helvetica", fontSize=10,
textColor=colors.HexColor("#CCE8E8"), alignment=TA_CENTER, leading=14)
SEC_TITLE = S("SEC_TITLE", fontName="Helvetica-Bold", fontSize=11,
textColor=WHITE, alignment=TA_LEFT, leading=14, spaceBefore=2)
SEC_BODY = S("SEC_BODY", fontName="Helvetica", fontSize=8.5,
textColor=BLACK, leading=12, spaceAfter=2)
SEC_BOLD = S("SEC_BOLD", fontName="Helvetica-Bold", fontSize=8.5,
textColor=BLACK, leading=12)
SMALL = S("SMALL", fontName="Helvetica", fontSize=7.5,
textColor=colors.HexColor("#555555"), leading=10)
FOOTER_S = S("FOOTER_S", fontName="Helvetica", fontSize=7,
textColor=colors.HexColor("#888888"), alignment=TA_CENTER)
PEARL = S("PEARL", fontName="Helvetica", fontSize=8,
textColor=BLACK, leading=12, leftIndent=8)
PEARL_HDR = S("PEARL_HDR", fontName="Helvetica-Bold", fontSize=8.5,
textColor=TEAL, leading=13, leftIndent=0)
# ── Helper: coloured banner ────────────────────────────────────────────────────
def banner(text, bg=TEAL, style=SEC_TITLE, pad=4):
tbl = Table([[Paragraph(text, style)]], colWidths=[W - 2*cm])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), pad),
("BOTTOMPADDING", (0,0), (-1,-1), pad),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("ROUNDEDCORNERS", [4, 4, 4, 4]),
]))
return tbl
def spacer(h=4): return Spacer(1, h)
# ── Page canvas (header stripe + footer) ──────────────────────────────────────
def on_page(canvas, doc):
canvas.saveState()
# top stripe
canvas.setFillColor(NAVY)
canvas.rect(0, H - 18*mm, W, 18*mm, fill=1, stroke=0)
canvas.setFillColor(MINT)
canvas.rect(0, H - 20*mm, W, 2*mm, fill=1, stroke=0)
# header text
canvas.setFillColor(WHITE)
canvas.setFont("Helvetica-Bold", 13)
canvas.drawString(cm, H - 12*mm, "TFT Quick Reference")
canvas.setFont("Helvetica", 8)
canvas.setFillColor(colors.HexColor("#9EC8C8"))
canvas.drawRightString(W - cm, H - 12*mm, "Thyroid Function Tests | Clinical Reference Card")
# page number footer
canvas.setFillColor(colors.HexColor("#AAAAAA"))
canvas.setFont("Helvetica", 7)
canvas.drawCentredString(W/2, 8*mm, f"Page {doc.page}")
canvas.setFillColor(MINT)
canvas.rect(0, 5*mm, W, 0.5*mm, fill=1, stroke=0)
canvas.restoreState()
# ── Document setup ─────────────────────────────────────────────────────────────
OUT = "/home/daytona/workspace/tft-pdf/TFT_Quick_Reference.pdf"
doc = SimpleDocTemplate(
OUT, pagesize=A4,
leftMargin=cm, rightMargin=cm,
topMargin=2.4*cm, bottomMargin=1.6*cm,
title="TFT Quick Reference",
author="Orris Medical Reference",
subject="Thyroid Function Tests - Clinical Quick Reference"
)
story = []
# ═══════════════════════════════════════════════════════════════════════════════
# TITLE BLOCK
# ═══════════════════════════════════════════════════════════════════════════════
title_tbl = Table(
[[Paragraph("THYROID FUNCTION TESTS", HDR_TITLE)],
[Paragraph("Quick Reference Card · Interpretation · Clinical Use · Drug Effects", HDR_SUB)]],
colWidths=[W - 2*cm]
)
title_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), NAVY),
("TOPPADDING", (0,0), (-1,-1), 10),
("BOTTOMPADDING", (0,0), (-1,-1), 10),
("LEFTPADDING", (0,0), (-1,-1), 12),
("RIGHTPADDING", (0,0), (-1,-1), 12),
("LINEBELOW", (0,1), (-1,1), 2, MINT),
]))
story += [title_tbl, spacer(8)]
# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 1: HPT AXIS
# ═══════════════════════════════════════════════════════════════════════════════
story += [banner("1 THE HPT AXIS — UNDERSTANDING THE FEEDBACK LOOP", NAVY), spacer(4)]
axis_data = [
[Paragraph("<b>Hypothalamus</b>", SEC_BODY),
Paragraph("Releases <b>TRH</b> (Thyrotropin-Releasing Hormone)", SEC_BODY)],
[Paragraph("↓", SEC_BODY), Paragraph("", SEC_BODY)],
[Paragraph("<b>Anterior Pituitary</b>", SEC_BODY),
Paragraph("Releases <b>TSH</b> (Thyroid-Stimulating Hormone)", SEC_BODY)],
[Paragraph("↓", SEC_BODY), Paragraph("", SEC_BODY)],
[Paragraph("<b>Thyroid Gland</b>", SEC_BODY),
Paragraph("Releases <b>T4</b> (Thyroxine) + <b>T3</b> (Triiodothyronine)", SEC_BODY)],
[Paragraph("↑ (Negative Feedback)", SMALL),
Paragraph("T3/T4 inhibit both hypothalamus and pituitary", SMALL)],
]
axis_tbl = Table(axis_data, colWidths=[4.5*cm, W - 2*cm - 4.5*cm])
axis_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), LIGHT_BG),
("ROWBACKGROUNDS", (0,0), (-1,-1), [LIGHT_BG, colors.HexColor("#E8F4F4")]),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 8),
("BOX", (0,0), (-1,-1), 0.5, GREY_MID),
("LINEBELOW", (0,1), (-1,1), 0.3, GREY_MID),
("LINEBELOW", (0,3), (-1,3), 0.3, GREY_MID),
]))
story += [axis_tbl, spacer(4)]
key_concept = Table(
[[Paragraph("⚠ KEY CONCEPT: TSH ↔ fT4 have a <b>LOG-LINEAR INVERSE</b> relationship — small changes in fT4 cause large amplified swings in TSH. This makes TSH the most sensitive early marker of thyroid dysfunction.", SEC_BODY)]],
colWidths=[W - 2*cm]
)
key_concept.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), colors.HexColor("#FFF8E1")),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
("BOX", (0,0), (-1,-1), 1, AMBER),
("LINEAFTER", (0,0), (0,-1), 4, AMBER),
]))
story += [key_concept, spacer(10)]
# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 2: THE TESTS
# ═══════════════════════════════════════════════════════════════════════════════
story += [banner("2 THE TESTS — WHAT THEY MEASURE", TEAL), spacer(4)]
tests_header = ["Test", "Normal Range", "Measures / Key Points"]
tests_data = [
["TSH", "0.5–4.5 mIU/L\n(0.1–4.0 in pregnancy)",
"Best first-line test. Amplifies T4 changes 10×. Third-generation assay detects 0.01 mU/L. Normal TSH = thyroid OK in most patients."],
["Free T4\n(fT4)", "12–28 pmol/L",
"Biologically active unbound fraction. Use when TSH is abnormal to confirm and grade severity. Reliable in most settings."],
["Total T4", "55–150 nmol/L",
"Includes protein-bound T4 (>99%). Affected by TBG changes (estrogens ↑, androgens ↓). Not first-line screening."],
["Free T3\n(fT3)", "3–9 pmol/L",
"Most useful in early hyperthyroidism (rises before total T4/T3). Difficult to measure accurately — total T3 often used instead."],
["Total T3", "1.5–3.5 nmol/L",
"Reflects peripheral T4→T3 conversion more than thyroid output. KEY USE: T3 toxicosis (high T3, normal T4, low TSH ~5% of hyper cases)."],
["TRH Stim.\nTest", "TSH rise ≥6 µIU/mL\nat 30 & 60 min",
"500 µg TRH IV → measure TSH at 30 & 60 min. Largely replaced by sensitive TSH. Still used to confirm central (pituitary) hypothyroidism."],
]
col_w = [2.2*cm, 3.0*cm, W - 2*cm - 5.2*cm]
tests_tbl = Table([tests_header] + tests_data, colWidths=col_w, repeatRows=1)
tests_tbl.setStyle(TableStyle([
# Header
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,0), 8.5),
("TOPPADDING", (0,0), (-1,0), 5),
("BOTTOMPADDING", (0,0), (-1,0), 5),
# Body
("FONTNAME", (0,1), (-1,-1), "Helvetica"),
("FONTSIZE", (0,1), (-1,-1), 8),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, GREY_LITE]),
("TOPPADDING", (0,1), (-1,-1), 4),
("BOTTOMPADDING", (0,1), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("BOX", (0,0), (-1,-1), 0.5, GREY_MID),
("INNERGRID", (0,0), (-1,-1), 0.3, GREY_MID),
# Highlight TSH row
("BACKGROUND", (0,1), (-1,1), colors.HexColor("#E8F8F0")),
("FONTNAME", (0,1), (0,1), "Helvetica-Bold"),
]))
# Convert multiline strings to paragraphs
p_data = [[Paragraph(tests_header[i], S("th", fontName="Helvetica-Bold", fontSize=8.5, textColor=WHITE, leading=11)) for i in range(3)]]
for row in tests_data:
p_data.append([Paragraph(row[0], SEC_BOLD), Paragraph(row[1], SMALL), Paragraph(row[2], SEC_BODY)])
tests_tbl2 = Table(p_data, colWidths=col_w, repeatRows=1)
tests_tbl2.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, GREY_LITE]),
("BACKGROUND", (0,1), (-1,1), colors.HexColor("#E8F8F0")),
("TOPPADDING", (0,0), (-1,-1), 4), ("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6), ("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("BOX", (0,0), (-1,-1), 0.5, GREY_MID),
("INNERGRID", (0,0), (-1,-1), 0.3, GREY_MID),
]))
story += [tests_tbl2, spacer(10)]
# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 3: TSH-FIRST ALGORITHM (visual flowchart as table)
# ═══════════════════════════════════════════════════════════════════════════════
story += [banner("3 THE TSH-FIRST ALGORITHM", TEAL), spacer(4)]
def flow_box(text, bg, tc=BLACK, fs=8.5, bold=False):
fn = "Helvetica-Bold" if bold else "Helvetica"
st = S("fb", fontName=fn, fontSize=fs, textColor=tc, alignment=TA_CENTER, leading=12)
tbl = Table([[Paragraph(text, st)]], colWidths=[None])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("BOX", (0,0), (-1,-1), 0.8, colors.HexColor("#AAAAAA")),
]))
return tbl
arrow = Paragraph("↓", S("arr", fontName="Helvetica-Bold", fontSize=14,
textColor=TEAL, alignment=TA_CENTER))
alg_col = 5.5*cm
side_col = (W - 2*cm - alg_col - 0.6*cm) / 2
alg = [
# Start
[flow_box("STEP 1: Measure TSH", NAVY, tc=WHITE, bold=True), "", ""],
["", arrow, ""],
# TSH branches
[flow_box("TSH NORMAL\n0.5–4.5 mIU/L", GREEN_SOFT, tc=WHITE, bold=True),
flow_box("TSH HIGH\n> 4.5 mIU/L", RED_SOFT, tc=WHITE, bold=True),
flow_box("TSH LOW\n< 0.5 mIU/L", AMBER, tc=BLACK, bold=True)],
# Outcome row
[flow_box("Thyroid dysfunction\nexcluded. STOP.", colors.HexColor("#D5F5E3")),
flow_box("Add FREE T4", LIGHT_BG),
flow_box("Add FREE T4 + T3", LIGHT_BG)],
# Sub-outcomes left side
["",
flow_box("↑TSH + ↓fT4\n→ OVERT HYPOTHYROID", RED_SOFT, tc=WHITE),
flow_box("↓TSH + ↑fT4/T3\n→ OVERT HYPERTHYROID", RED_SOFT, tc=WHITE)],
["",
flow_box("↑TSH + Normal fT4\n→ SUBCLINICAL HYPOTHYROID", AMBER, tc=BLACK),
flow_box("↓TSH + Normal fT4\n→ Check FREE T3", AMBER, tc=BLACK)],
["", "",
flow_box("↓TSH + ↑T3 (normal fT4)\n→ T3 TOXICOSIS", RED_SOFT, tc=WHITE)],
["", "",
flow_box("↓TSH + Normal T3 + Normal fT4\n→ SUBCLINICAL HYPERTHYROID", AMBER, tc=BLACK)],
]
flow_cw = [alg_col, alg_col, alg_col]
flow_tbl = Table(
[[flow_box("STEP 1: Measure TSH (Best First Test)", NAVY, tc=WHITE, bold=True, fs=9)],
[Spacer(1, 6)],
[Table([
[flow_box("TSH NORMAL\n0.5–4.5 mIU/L", GREEN_SOFT, tc=WHITE, bold=True),
flow_box("TSH HIGH\n> 4.5 mIU/L", RED_SOFT, tc=WHITE, bold=True),
flow_box("TSH LOW\n< 0.5 mIU/L", colors.HexColor("#E67E22"), tc=WHITE, bold=True)],
[Spacer(1,4), Spacer(1,4), Spacer(1,4)],
[flow_box("Thyroid disease\nexcluded. STOP.", colors.HexColor("#ABEBC6")),
flow_box("Add Free T4", LIGHT_BG),
flow_box("Add Free T4 + T3", LIGHT_BG)],
[Spacer(1,4), Spacer(1,4), Spacer(1,4)],
[Paragraph("", SEC_BODY),
flow_box("↑TSH + ↓fT4\n→ OVERT HYPOTHYROID", RED_SOFT, tc=WHITE),
flow_box("↓TSH + ↑fT4/T3\n→ OVERT HYPERTHYROID", RED_SOFT, tc=WHITE)],
[Paragraph("", SEC_BODY),
flow_box("↑TSH + Normal fT4\n→ SUBCLINICAL HYPOTHYROID", AMBER, tc=BLACK),
flow_box("↓TSH + Normal fT4\n→ Check Free T3", colors.HexColor("#F39C12"), tc=BLACK)],
[Paragraph("", SEC_BODY),
Paragraph("", SEC_BODY),
flow_box("↓TSH + ↑T3 (nml fT4)\n→ T3 TOXICOSIS", RED_SOFT, tc=WHITE)],
[Paragraph("", SEC_BODY),
Paragraph("", SEC_BODY),
flow_box("↓TSH + nml T3+fT4\n→ SUBCLINICAL HYPER", AMBER, tc=BLACK)],
], colWidths=[alg_col, alg_col, alg_col])],
],
colWidths=[W - 2*cm]
)
flow_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), colors.HexColor("#FAFAFA")),
("BOX", (0,0), (-1,-1), 0.5, GREY_MID),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 6),
]))
story += [flow_tbl, spacer(10)]
# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 4: INTERPRETATION TABLE
# ═══════════════════════════════════════════════════════════════════════════════
story += [banner("4 INTERPRETATION SUMMARY TABLE", TEAL), spacer(4)]
interp_header = ["Condition", "TSH", "fT4", "T3", "Notes"]
interp_data = [
["Overt Hypothyroidism", "↑↑", "↓", "↓/Nml", "Most common: Hashimoto thyroiditis"],
["Subclinical Hypothyroidism","↑", "Normal", "Normal","Earliest stage; treat if symptomatic or TSH >10"],
["Overt Hyperthyroidism", "↓↓", "↑", "↑", "Most common: Graves disease"],
["Subclinical Hyperthyroidism","↓", "Normal", "Normal","Treat if symptomatic / age >65 / AF risk"],
["T3 Toxicosis", "↓", "Normal", "↑↑", "~5% of hyper cases; Graves or toxic nodule"],
["Central Hypothyroidism", "Low/Nml","↓", "↓", "Pituitary/hypothalamic disease; TSH misleads"],
["Euthyroid Sick Syndrome", "Low/Nml","↓", "↓↓", "Critically ill; rT3 ↑; don't treat — patient is euthyroid"],
["Pregnancy (normal)", "Normal*","Normal", "Normal","*Lower TSH cutoff; Total T4 ↑ due to ↑TBG — use fT4"],
["Estrogen/OCP (normal)", "Normal", "Normal", "Normal","Total T4/T3 ↑ via TBG ↑; fT4 + TSH normal — no action"],
["Graves Disease", "↓↓", "↑", "↑", "TRAb positive; T3:T4 ratio >20:1 typical"],
["Hashimoto Thyroiditis", "↑", "↓/Nml", "↓/Nml","Anti-TPO + Anti-Tg elevated; TRAb absent"],
]
def colour_tsH(val):
if "↑↑" in val or "↑" in val: return RED_SOFT
if "↓↓" in val or "↓" in val: return GREEN_SOFT
if "Low/Nml" in val: return colors.HexColor("#E67E22")
return colors.HexColor("#7F8C8D")
i_cw = [3.8*cm, 1.2*cm, 1.2*cm, 1.2*cm, W - 2*cm - 7.4*cm]
i_head_row = [Paragraph(h, S("ih", fontName="Helvetica-Bold", fontSize=8, textColor=WHITE, leading=10))
for h in interp_header]
i_rows = [i_head_row]
for i, row in enumerate(interp_data):
bg = WHITE if i % 2 == 0 else GREY_LITE
i_rows.append([
Paragraph(row[0], S("ic", fontName="Helvetica-Bold" if "Overt" in row[0] else "Helvetica",
fontSize=8, textColor=BLACK, leading=10)),
Paragraph(f"<b>{row[1]}</b>", S("iv", fontName="Helvetica-Bold", fontSize=9,
textColor=RED_SOFT if "↑" in row[1] else (GREEN_SOFT if "↓" in row[1] else colors.HexColor("#E67E22")),
alignment=TA_CENTER, leading=11)),
Paragraph(f"<b>{row[2]}</b>", S("iv2", fontName="Helvetica-Bold", fontSize=9,
textColor=RED_SOFT if "↑" in row[2] else (GREEN_SOFT if "↓" in row[2] else colors.HexColor("#555555")),
alignment=TA_CENTER, leading=11)),
Paragraph(f"<b>{row[3]}</b>", S("iv3", fontName="Helvetica-Bold", fontSize=9,
textColor=RED_SOFT if "↑" in row[3] else (GREEN_SOFT if "↓" in row[3] else colors.HexColor("#555555")),
alignment=TA_CENTER, leading=11)),
Paragraph(row[4], SMALL),
])
i_tbl = Table(i_rows, colWidths=i_cw, repeatRows=1)
i_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, GREY_LITE]),
("TOPPADDING", (0,0), (-1,-1), 3), ("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 5), ("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("BOX", (0,0), (-1,-1), 0.5, GREY_MID),
("INNERGRID", (0,0), (-1,-1), 0.3, GREY_MID),
("ALIGN", (1,0), (3,-1), "CENTER"),
]))
story += [i_tbl, spacer(6)]
legend = Paragraph(
"<font color='#E74C3C'>↑ = elevated</font> "
"<font color='#27AE60'>↓ = decreased</font> "
"<font color='#555555'>Nml = normal</font> "
"rT3 = reverse T3 (inactive)",
S("leg", fontName="Helvetica", fontSize=7.5, textColor=colors.HexColor("#555555"),
alignment=TA_CENTER, leading=10)
)
story += [legend, spacer(10)]
# ═══════════════════════════════════════════════════════════════════════════════
# PAGE 2
# ═══════════════════════════════════════════════════════════════════════════════
story += [PageBreak()]
# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 5: THYROID ANTIBODIES
# ═══════════════════════════════════════════════════════════════════════════════
story += [banner("5 THYROID ANTIBODIES + SPECIAL MARKERS", NAVY), spacer(4)]
ab_header = ["Antibody", "Full Name", "Tells You", "Disease"]
ab_data = [
["Anti-TPO\n(Anti-microsomal)", "Anti-thyroid peroxidase",
"Autoimmune thyroid disease\n~80% sensitivity in Hashimoto", "Hashimoto > Graves (not specific)"],
["Anti-Tg", "Anti-thyroglobulin",
"Autoimmune thyroid disease\nInterferes with Tg assay", "Hashimoto (less sensitive than Anti-TPO)"],
["TRAb / TSI / LATS", "TSH receptor antibody\n(stimulating type)",
"Acts as TSH agonist →\ncontinuous stimulation", "HIGHLY specific for Graves disease"],
["Serum Thyroglobulin\n(Tg)", "Thyroglobulin protein",
"Tumor marker — post-thyroidectomy\n+ RAI ablation surveillance", "Differentiated thyroid cancer monitoring"],
["Calcitonin", "C-cell hormone",
"Tumor marker for C-cell origin", "Medullary thyroid cancer"],
]
ab_cw = [3.2*cm, 3.5*cm, 5.2*cm, W - 2*cm - 11.9*cm]
ab_rows = [[Paragraph(h, S("abh", fontName="Helvetica-Bold", fontSize=8, textColor=WHITE, leading=10))
for h in ab_header]]
for i, row in enumerate(ab_data):
bg = WHITE if i % 2 == 0 else GREY_LITE
ab_rows.append([Paragraph(c, SEC_BODY) for c in row])
ab_tbl = Table(ab_rows, colWidths=ab_cw, repeatRows=1)
ab_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), TEAL),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, GREY_LITE]),
("TOPPADDING", (0,0), (-1,-1), 4), ("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6), ("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
("BOX", (0,0), (-1,-1), 0.5, GREY_MID),
("INNERGRID", (0,0), (-1,-1), 0.3, GREY_MID),
# Highlight TRAb
("BACKGROUND", (0,3), (-1,3), colors.HexColor("#FEF9E7")),
("FONTNAME", (0,3), (-1,3), "Helvetica-Bold"),
]))
story += [ab_tbl, spacer(10)]
# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 6: WHEN TSH-FIRST RULE FAILS
# ═══════════════════════════════════════════════════════════════════════════════
story += [banner("6 WHEN TO ABANDON TSH-FIRST", colors.HexColor("#C0392B")), spacer(4)]
fail_data = [
["1. Critically Ill Patients\n(Euthyroid Sick Syndrome)",
"Cytokines suppress HPT axis. Pattern: ↓T3, ↓T4, ↑rT3, normal/↓TSH. Patient is euthyroid.\n"
"→ Do NOT routinely check TFTs in ICU unless strong prior suspicion of thyroid disease."],
["2. Thyroid Therapy\nTransitions",
"After treating hyperthyroidism: TSH stays low for months (thyrotroph suppression).\n"
"After starting levothyroxine: TSH stays high for weeks.\n"
"→ Wait 6–8 weeks after any dose change before rechecking (steady state ~end of month 2)."],
["3. Central Disease\nSuspected",
"Pituitary/hypothalamic disease → TSH inappropriately low/normal despite ↓fT4.\n"
"→ Must interpret TSH + fT4 together. TSH is NEVER the only pituitary hormone deficient."],
]
fail_cw = [3.5*cm, W - 2*cm - 3.5*cm]
fail_rows = []
for row in fail_data:
fail_rows.append([
Paragraph(row[0], S("fb2", fontName="Helvetica-Bold", fontSize=8.5, textColor=WHITE, leading=12)),
Paragraph(row[1], SEC_BODY)
])
fail_tbl = Table(fail_rows, colWidths=fail_cw)
fail_tbl.setStyle(TableStyle([
("ROWBACKGROUNDS", (0,0), (-1,-1), [colors.HexColor("#FDEDEC"), colors.HexColor("#FEF9E7")]),
("BACKGROUND", (0,0), (0,-1), colors.HexColor("#C0392B")),
("TOPPADDING", (0,0), (-1,-1), 6), ("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 7), ("RIGHTPADDING", (0,0), (-1,-1), 7),
("VALIGN", (0,0), (-1,-1), "TOP"),
("BOX", (0,0), (-1,-1), 0.5, colors.HexColor("#C0392B")),
("INNERGRID", (0,0), (-1,-1), 0.5, GREY_MID),
]))
story += [fail_tbl, spacer(10)]
# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 7: DRUGS AND TFTs (two-column layout)
# ═══════════════════════════════════════════════════════════════════════════════
story += [banner("7 DRUGS AND TFTs — CAUSES TRUE DYSFUNCTION vs. ALTERS TESTS ONLY", TEAL), spacer(4)]
# Left: true dysfunction
left_title = Table([[Paragraph("TRUE Thyroid Dysfunction (TSH Changes)", S("ct", fontName="Helvetica-Bold", fontSize=9, textColor=WHITE, alignment=TA_CENTER, leading=11))]],
colWidths=[(W - 2*cm - 0.3*cm)/2])
left_title.setStyle(TableStyle([("BACKGROUND", (0,0), (-1,-1), RED_SOFT),
("TOPPADDING", (0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4)]))
drug_true = [
["Amiodarone", "Hypo OR Hyper", "37% iodine; hypo in iodine-sufficient; hyper if iodine-deficient / MNG"],
["Lithium", "Hypothyroidism", "Inhibits thyroid hormone synthesis & secretion; 15-50% of patients"],
["Iodine / CT contrast", "Hypo (Wolff-Chaikoff)\nor Hyper (Jod-Basedow)", "Excess iodine → hypo; iodine deficiency + load → hyper"],
["Checkpoint inhibitors\nIFN-α", "Hypo or Hyper", "Immune-mediated thyroiditis"],
["Tyrosine kinase\ninhibitors", "Hypothyroidism", "Multiple mechanisms; monitor TSH"],
]
dt_rows = [[Paragraph(r[0], S("d0", fontName="Helvetica-Bold", fontSize=7.5, textColor=BLACK, leading=10)),
Paragraph(r[1], S("d1", fontName="Helvetica-Bold", fontSize=7.5, textColor=RED_SOFT, leading=10)),
Paragraph(r[2], SMALL)] for r in drug_true]
dt_cw = [2.0*cm, 2.3*cm, (W-2*cm-0.3*cm)/2 - 4.3*cm]
dt_tbl = Table(dt_rows, colWidths=dt_cw)
dt_tbl.setStyle(TableStyle([
("ROWBACKGROUNDS", (0,0), (-1,-1), [WHITE, GREY_LITE]),
("TOPPADDING",(0,0),(-1,-1),3),("BOTTOMPADDING",(0,0),(-1,-1),3),
("LEFTPADDING",(0,0),(-1,-1),4),("RIGHTPADDING",(0,0),(-1,-1),4),
("VALIGN",(0,0),(-1,-1),"TOP"),
("BOX",(0,0),(-1,-1),0.5,GREY_MID),("INNERGRID",(0,0),(-1,-1),0.3,GREY_MID),
]))
left_col = Table([[left_title],[dt_tbl]], colWidths=[(W-2*cm-0.3*cm)/2])
left_col.setStyle(TableStyle([("TOPPADDING",(0,0),(-1,-1),0),("BOTTOMPADDING",(0,0),(-1,-1),0),
("LEFTPADDING",(0,0),(-1,-1),0),("RIGHTPADDING",(0,0),(-1,-1),0)]))
# Right: alters tests only
right_title = Table([[Paragraph("Tests ONLY Affected (TSH Normal = Euthyroid)", S("ct2", fontName="Helvetica-Bold", fontSize=9, textColor=WHITE, alignment=TA_CENTER, leading=11))]],
colWidths=[(W - 2*cm - 0.3*cm)/2])
right_title.setStyle(TableStyle([("BACKGROUND", (0,0), (-1,-1), TEAL),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4)]))
drug_test = [
["Estrogens / OCP / Tamoxifen", "↑ Total T4, ↑ Total T3", "↑ TBG; fT4 & TSH remain normal"],
["Androgens", "↓ Total T4", "↓ TBG; fT4 & TSH normal"],
["Furosemide (high dose)\nSalicylates", "↓ Total T4", "Compete with T4 for TBG binding"],
["Phenytoin / Carbamazepine\nRifampin / Phenobarbital", "↓ Total T4", "Displace T4 from TBG; accelerate T4 clearance"],
["Heparin / LMWH", "↑ Free T4 (artifact)", "Free fatty acids displace T4 from TBG in vitro"],
["Glucocorticoids / Dopamine", "↓ TSH", "Suppress TSH secretion directly; T4 normal"],
["Propranolol (high dose)", "↓ T3", "Inhibits peripheral T4→T3 conversion"],
["Biotin (supplements)", "Spurious all assays", "⚠ Hold 1-2 days before TFTs — immunoassay interference"],
]
dtest_rows = [[Paragraph(r[0], S("dt0", fontName="Helvetica-Bold", fontSize=7.5, textColor=BLACK, leading=10)),
Paragraph(r[1], S("dt1", fontName="Helvetica-Bold", fontSize=7.5, textColor=TEAL, leading=10)),
Paragraph(r[2], SMALL)] for r in drug_test]
dtest_cw = [2.5*cm, 2.3*cm, (W-2*cm-0.3*cm)/2 - 4.8*cm]
dtest_tbl = Table(dtest_rows, colWidths=dtest_cw)
dtest_tbl.setStyle(TableStyle([
("ROWBACKGROUNDS", (0,0), (-1,-1), [WHITE, GREY_LITE]),
("BACKGROUND", (0,7), (-1,7), colors.HexColor("#FFF8E1")),
("TOPPADDING",(0,0),(-1,-1),3),("BOTTOMPADDING",(0,0),(-1,-1),3),
("LEFTPADDING",(0,0),(-1,-1),4),("RIGHTPADDING",(0,0),(-1,-1),4),
("VALIGN",(0,0),(-1,-1),"TOP"),
("BOX",(0,0),(-1,-1),0.5,GREY_MID),("INNERGRID",(0,0),(-1,-1),0.3,GREY_MID),
]))
right_col = Table([[right_title],[dtest_tbl]], colWidths=[(W-2*cm-0.3*cm)/2])
right_col.setStyle(TableStyle([("TOPPADDING",(0,0),(-1,-1),0),("BOTTOMPADDING",(0,0),(-1,-1),0),
("LEFTPADDING",(0,0),(-1,-1),0),("RIGHTPADDING",(0,0),(-1,-1),0)]))
drugs_outer = Table([[left_col, Spacer(0.3*cm, 1), right_col]],
colWidths=[(W-2*cm-0.3*cm)/2, 0.3*cm, (W-2*cm-0.3*cm)/2])
drugs_outer.setStyle(TableStyle([
("TOPPADDING",(0,0),(-1,-1),0),("BOTTOMPADDING",(0,0),(-1,-1),0),
("LEFTPADDING",(0,0),(-1,-1),0),("RIGHTPADDING",(0,0),(-1,-1),0),
("VALIGN",(0,0),(-1,-1),"TOP"),
]))
story += [drugs_outer, spacer(10)]
# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 8: 10 CLINICAL PEARLS
# ═══════════════════════════════════════════════════════════════════════════════
story += [banner("8 10 CLINICAL PEARLS", NAVY), spacer(4)]
pearls = [
("<b>1.</b>", "TSH ALWAYS FIRST — most sensitive test. Amplifies small fT4 changes 10×."),
("<b>2.</b>", "Normal TSH = thyroid function essentially normal (in most patients, most settings). STOP."),
("<b>3.</b>", "Add <b>fT4</b> when TSH is abnormal — confirms and grades severity."),
("<b>4.</b>", "Add <b>T3</b> when TSH is low but fT4 is normal — rule out T3 toxicosis (5% of hyper cases)."),
("<b>5.</b>", "Central disease: TSH + fT4 together. TSH alone will MISS pituitary hypothyroidism."),
("<b>6.</b>", "Critically ill patients: Euthyroid Sick Syndrome mimics central hypothyroidism. Don't treat."),
("<b>7.</b>", "Wait <b>6–8 weeks</b> after any dose change before rechecking TSH (steady state takes time)."),
("<b>8.</b>", "Amiodarone: inhibits T4→T3 (↑T4, ↓T3 even in euthyroid) + can cause hypo OR hyperthyroidism."),
("<b>9.</b>", "Biotin supplements → spurious results in ALL thyroid immunoassays. Hold 1–2 days before testing."),
("<b>10.</b>", "Estrogens/OCP → ↑ Total T4/T3 (↑TBG) but fT4 and TSH are normal. Patient is euthyroid. No action."),
]
pearl_rows = []
for num, text in pearls:
pearl_rows.append([
Paragraph(num, S("pn", fontName="Helvetica-Bold", fontSize=9, textColor=TEAL,
alignment=TA_CENTER, leading=12)),
Paragraph(text, PEARL)
])
pearl_tbl = Table(pearl_rows, colWidths=[0.7*cm, W - 2*cm - 0.7*cm])
pearl_tbl.setStyle(TableStyle([
("ROWBACKGROUNDS", (0,0), (-1,-1), [WHITE, GREY_LITE]),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),6),("RIGHTPADDING",(0,0),(-1,-1),6),
("VALIGN",(0,0),(-1,-1),"MIDDLE"),
("BOX",(0,0),(-1,-1),0.5,GREY_MID),("INNERGRID",(0,0),(-1,-1),0.3,GREY_MID),
("LINEBEFORE",(0,0),(0,-1),3,TEAL),
]))
story += [pearl_tbl, spacer(8)]
# ═══════════════════════════════════════════════════════════════════════════════
# FOOTER NOTE
# ═══════════════════════════════════════════════════════════════════════════════
footer_note = Table(
[[Paragraph(
"Sources: Quick Compendium of Clinical Pathology 5e · Schwartz's Principles of Surgery 11e · "
"Goldman-Cecil Medicine · Washington Manual of Medical Therapeutics · Henry's Clinical Diagnosis by Lab Methods · "
"Harrison's Principles of Internal Medicine 22e",
S("fn", fontName="Helvetica", fontSize=6.5, textColor=colors.HexColor("#888888"),
alignment=TA_CENTER, leading=9)
)]],
colWidths=[W - 2*cm]
)
footer_note.setStyle(TableStyle([
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("BACKGROUND",(0,0),(-1,-1),GREY_LITE),
("BOX",(0,0),(-1,-1),0.3,GREY_MID),
]))
story += [footer_note]
# ═══════════════════════════════════════════════════════════════════════════════
# BUILD
# ═══════════════════════════════════════════════════════════════════════════════
doc.build(story, onFirstPage=on_page, onLaterPages=on_page)
print(f"PDF saved to: {OUT}")
cd /home/daytona/workspace/tft-pdf && python3 make_tft_pdf.py 2>&1
ls -lh /home/daytona/workspace/tft-pdf/TFT_Quick_Reference.pdf
TFT Quick Reference
PDF Document · PDF