Explain the practical of estimation of total bilirubin in serum, estimation of direct bilirubin in serum and estimation of indirect bilirubin in serum along with clinicals

| Step | Action |
|---|---|
| 1 | Pipette 0.1 mL serum + 0.5 mL caffeine-benzoate (accelerator) + 0.4 mL diazo reagent into a test tube. Mix well. |
| 2 | Allow to stand for 10 minutes at room temperature (reaction time for both CB and UCB). |
| 3 | Add 1.5 mL alkaline tartrate (shifts product to blue color at alkaline pH, increasing sensitivity). |
| 4 | Read absorbance at 600 nm (blue color) or 540 nm (reddish-purple) within 1 hour. |
| 5 | Run a blank: serum + caffeine-benzoate + blank reagent (no diazo) - subtract this from the test reading. |
| 6 | Compare to standard bilirubin calibrator of known concentration. |
Total Bilirubin (mg/dL) = (Absorbance of Test / Absorbance of Standard) × Concentration of Standard
| Step | Action |
|---|---|
| 1 | Pipette 0.1 mL serum + 0.9 mL distilled water + 0.4 mL diazo reagent. Mix. |
| 2 | Allow to react for exactly 1 minute at room temperature (only direct-reacting CB reacts in this short window). |
| 3 | Read absorbance at 540 nm immediately. |
| 4 | Run a blank as above (serum + water + blank reagent). |
Indirect Bilirubin = Total Bilirubin - Direct Bilirubin
| Issue | Explanation |
|---|---|
| Hemolysis | Hemoglobin interferes; no significant interference up to 25 mg/dL Hb on automated analyzers (Beckman AU). Hemolysis can falsely lower bilirubin by oxidation. |
| Lipemia | No significant interference up to 500 mg/dL Intralipid. |
| Light exposure | Bilirubin is photosensitive; samples must be protected from light (covered tubes). |
| Methanol/ethanol accelerators | Cause protein precipitation and turbidity; caffeine-benzoate is preferred. |
| Delta bilirubin | Covalently albumin-bound conjugated bilirubin. Has a ~18-20 day half-life (albumin's half-life). Not accurately measured by standard diazo methods. Important in prolonged cholestasis. |
| Direct ≠ Conjugated | Direct and conjugated bilirubin are NOT equivalent. A small amount of UCB may appear in the "direct" fraction; some CB (especially delta bilirubin) may escape. Errors can occur if used to diagnose isolated disorders like Gilbert syndrome. |
| Calibrators | Human serum-based calibrators are preferred over bovine serum, which gives incomplete and unpredictable reactions with UCB. |
| Fraction | Normal Range (mg/dL) | Normal Range (μmol/L) |
|---|---|---|
| Total bilirubin | 0.2 - 1.0 | 3.4 - 17.1 |
| Direct (conjugated) | 0.0 - 0.3 | 0.0 - 5.1 |
| Indirect (unconjugated) | 0.1 - 0.8 | 1.7 - 13.7 |
| Category | Examples |
|---|---|
| Increased production (overproduction) | Hemolysis (intravascular/extravascular), ineffective erythropoiesis, blood transfusion, resorption of large hematomas |
| Decreased hepatocellular uptake | Drugs (rifampin, cyclosporine) |
| Decreased conjugation | Gilbert syndrome (mild UGT1A1 deficiency), Crigler-Najjar syndrome type I and II (severe/absent UGT1A1), neonatal physiologic jaundice (low UGT activity at birth), hypothyroidism |
| Category | Examples |
|---|---|
| Hepatocellular disease | Viral hepatitis (A, B, C, E), alcoholic hepatitis, drug-induced liver injury, cirrhosis, liver failure |
| Intrahepatic cholestasis | Primary biliary cholangitis (PBC), primary sclerosing cholangitis (PSC), intrahepatic cholestasis of pregnancy, drug-induced cholestasis |
| Extrahepatic (posthepatic) obstruction | Choledocholithiasis (bile duct stones), carcinoma of head of pancreas, cholangiocarcinoma, ampullary carcinoma, biliary strictures |
| Hereditary disorders | Dubin-Johnson syndrome, Rotor syndrome |
| Bilirubin Pattern | Likely Diagnosis |
|---|---|
| ↑ Indirect, Normal Direct | Hemolysis, Gilbert syndrome, Crigler-Najjar, neonatal jaundice |
| ↑ Direct, ↑ Indirect | Hepatocellular disease (hepatitis, cirrhosis) |
| ↑ Direct predominantly | Obstructive jaundice (intrahepatic or extrahepatic cholestasis) |
| ↑ Total, decreasing but jaundice persists | Delta bilirubin accumulation (prolonged cholestasis) |
Create a colorful pdf of that
ls /home/daytona/workspace/ 2>/dev/null || echo "workspace empty"
mkdir -p /home/daytona/workspace/bilirubin-pdf
~/bilirubin-pdf/create_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, mm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether, PageBreak
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import Flowable
from reportlab.pdfgen import canvas
# ── Color Palette ──────────────────────────────────────────────────────────
TEAL = colors.HexColor("#0D7C8F")
TEAL_LIGHT = colors.HexColor("#E0F4F7")
ORANGE = colors.HexColor("#E8720C")
ORANGE_LIGHT= colors.HexColor("#FEF0E6")
PURPLE = colors.HexColor("#6B3FA0")
PURPLE_LIGHT= colors.HexColor("#F0EAF9")
GREEN = colors.HexColor("#1A7A4A")
GREEN_LIGHT = colors.HexColor("#E5F5EC")
RED = colors.HexColor("#C0392B")
RED_LIGHT = colors.HexColor("#FDEDEC")
GOLD = colors.HexColor("#D4A017")
GOLD_LIGHT = colors.HexColor("#FDF8E1")
DARK = colors.HexColor("#1A1A2E")
GREY = colors.HexColor("#5A5A72")
LIGHT_GREY = colors.HexColor("#F5F5F7")
WHITE = colors.white
W, H = A4
# ── Page template with header/footer ───────────────────────────────────────
def on_page(canv, doc):
canv.saveState()
# Top header bar
canv.setFillColor(TEAL)
canv.rect(0, H - 28, W, 28, fill=1, stroke=0)
canv.setFillColor(WHITE)
canv.setFont("Helvetica-Bold", 10)
canv.drawString(18, H - 19, "BILIRUBIN ESTIMATION IN SERUM")
canv.setFont("Helvetica", 9)
canv.drawRightString(W - 18, H - 19, f"Page {doc.page}")
# Bottom footer bar
canv.setFillColor(TEAL)
canv.rect(0, 0, W, 20, fill=1, stroke=0)
canv.setFillColor(WHITE)
canv.setFont("Helvetica-Oblique", 7.5)
canv.drawCentredString(W / 2, 6, "Sources: Tietz Lab Medicine 7e · Henry's Clinical Diagnosis · Harrison's 22e · Lippincott Biochemistry 8e")
canv.restoreState()
# ── Styles ──────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
def S(name, **kw):
return ParagraphStyle(name, **kw)
TITLE_STYLE = S("Title",
fontSize=22, fontName="Helvetica-Bold", textColor=WHITE,
alignment=TA_CENTER, spaceAfter=4)
SUBTITLE_STYLE = S("Subtitle",
fontSize=11, fontName="Helvetica-Oblique", textColor=TEAL_LIGHT,
alignment=TA_CENTER, spaceAfter=8)
H1 = S("H1",
fontSize=14, fontName="Helvetica-Bold", textColor=WHITE,
spaceBefore=10, spaceAfter=4, leftIndent=0)
H2 = S("H2",
fontSize=11, fontName="Helvetica-Bold", textColor=TEAL,
spaceBefore=8, spaceAfter=3)
BODY = S("Body",
fontSize=9.5, fontName="Helvetica", textColor=DARK,
leading=14, spaceBefore=2, spaceAfter=2, alignment=TA_JUSTIFY)
BODY_BOLD = S("BodyBold",
fontSize=9.5, fontName="Helvetica-Bold", textColor=DARK, leading=14)
BULLET = S("Bullet",
fontSize=9.5, fontName="Helvetica", textColor=DARK,
leading=14, leftIndent=14, spaceBefore=1)
NOTE = S("Note",
fontSize=8.5, fontName="Helvetica-Oblique", textColor=GREY,
leading=12, spaceBefore=2, leftIndent=10)
FORMULA = S("Formula",
fontSize=11, fontName="Helvetica-Bold", textColor=PURPLE,
alignment=TA_CENTER, spaceBefore=6, spaceAfter=6, leading=16)
# ── Helper Flowables ────────────────────────────────────────────────────────
class ColorBanner(Flowable):
"""Full-width colored title banner."""
def __init__(self, text, subtext="", bg=TEAL, h=56):
super().__init__()
self.text = text
self.subtext = subtext
self.bg = bg
self.bh = h
self.width = W - 2.5*cm
self.height = h
def draw(self):
c = self.canv
c.setFillColor(self.bg)
c.roundRect(0, 0, self.width, self.bh, 6, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont("Helvetica-Bold", 17)
c.drawCentredString(self.width / 2, self.bh - 26, self.text)
if self.subtext:
c.setFont("Helvetica-Oblique", 9)
c.setFillColor(colors.HexColor("#D0EEF4"))
c.drawCentredString(self.width / 2, self.bh - 40, self.subtext)
class SectionHeader(Flowable):
"""Colored section header bar."""
def __init__(self, text, bg=TEAL, width=None):
super().__init__()
self.text = text
self.bg = bg
self.width = (width or W - 2.5*cm)
self.height = 24
def draw(self):
c = self.canv
c.setFillColor(self.bg)
c.roundRect(0, 0, self.width, self.height, 4, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont("Helvetica-Bold", 11)
c.drawString(12, 7, self.text)
class FormulaBox(Flowable):
"""Highlighted formula/equation box."""
def __init__(self, text, bg=PURPLE_LIGHT, border=PURPLE, width=None):
super().__init__()
self.text = text
self.bg = bg
self.border = border
self.width = width or W - 2.5*cm
self.height = 38
def draw(self):
c = self.canv
c.setFillColor(self.bg)
c.roundRect(0, 0, self.width, self.height, 5, fill=1, stroke=0)
c.setStrokeColor(self.border)
c.setLineWidth(1.5)
c.roundRect(0, 0, self.width, self.height, 5, fill=0, stroke=1)
c.setFillColor(self.border)
c.setFont("Helvetica-Bold", 11)
c.drawCentredString(self.width / 2, 12, self.text)
class InfoBox(Flowable):
"""Colored info callout box."""
def __init__(self, label, text, bg=TEAL_LIGHT, border=TEAL, width=None):
super().__init__()
self.label = label
self.text = text
self.bg = bg
self.border = border
self.width = width or W - 2.5*cm
self.height = 46
def draw(self):
c = self.canv
# Accent left bar
c.setFillColor(self.border)
c.rect(0, 0, 5, self.height, fill=1, stroke=0)
# Background
c.setFillColor(self.bg)
c.rect(5, 0, self.width - 5, self.height, fill=1, stroke=0)
# Label
c.setFillColor(self.border)
c.setFont("Helvetica-Bold", 9)
c.drawString(14, self.height - 16, self.label)
# Text
c.setFillColor(DARK)
c.setFont("Helvetica", 9)
# Wrap text manually
words = self.text.split()
line, lines = "", []
for w in words:
test = (line + " " + w).strip()
if c.stringWidth(test, "Helvetica", 9) < self.width - 28:
line = test
else:
lines.append(line)
line = w
lines.append(line)
y = self.height - 29
for l in lines:
c.drawString(14, y, l)
y -= 12
# ── Table helpers ────────────────────────────────────────────────────────────
def make_table(data, col_widths, header_bg=TEAL, header_text_color=WHITE,
alt_row_bg=LIGHT_GREY, border_color=TEAL):
t = Table(data, colWidths=col_widths)
style = [
('BACKGROUND', (0, 0), (-1, 0), header_bg),
('TEXTCOLOR', (0, 0), (-1, 0), header_text_color),
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
('FONTSIZE', (0, 0), (-1, 0), 9),
('ALIGN', (0, 0), (-1, 0), 'CENTER'),
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
('FONTNAME', (0, 1), (-1, -1), 'Helvetica'),
('FONTSIZE', (0, 1), (-1, -1), 9),
('ROWBACKGROUNDS', (0, 1), (-1, -1), [WHITE, alt_row_bg]),
('GRID', (0, 0), (-1, -1), 0.5, border_color),
('TOPPADDING', (0, 0), (-1, -1), 5),
('BOTTOMPADDING', (0, 0), (-1, -1), 5),
('LEFTPADDING', (0, 0), (-1, -1), 7),
('RIGHTPADDING', (0, 0), (-1, -1), 7),
('ROUNDEDCORNERS', [4]),
]
t.setStyle(TableStyle(style))
return t
def para(text, style=BODY):
return Paragraph(text, style)
# ── Build Document ──────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
"/home/daytona/workspace/bilirubin-pdf/Bilirubin_Estimation_Serum.pdf",
pagesize=A4,
leftMargin=1.25*cm, rightMargin=1.25*cm,
topMargin=1.5*cm, bottomMargin=1.2*cm,
title="Bilirubin Estimation in Serum",
author="Orris Medical"
)
story = []
SP = lambda n=6: Spacer(1, n)
# ════════════════════════════════════════════════════════════════════
# COVER BANNER
# ════════════════════════════════════════════════════════════════════
story.append(SP(10))
story.append(ColorBanner(
"ESTIMATION OF BILIRUBIN IN SERUM",
subtext="Total Bilirubin · Direct Bilirubin · Indirect Bilirubin · Clinical Significance",
bg=TEAL, h=70
))
story.append(SP(10))
# ════════════════════════════════════════════════════════════════════
# SECTION 1 — BACKGROUND
# ════════════════════════════════════════════════════════════════════
story.append(SectionHeader("1. BACKGROUND: WHAT IS BILIRUBIN?", bg=TEAL))
story.append(SP(6))
story.append(para(
"Bilirubin is an <b>orange-yellow pigment</b> derived from heme, primarily a product of red blood cell (RBC) "
"turnover (~80%). It is extracted, biotransformed, and excreted by the liver. Measurement of serum bilirubin "
"is a key liver function test and is vital in the assessment of jaundice, neonatal hyperbilirubinemia, and "
"hepatobiliary disorders."
))
story.append(SP(6))
bili_types = [
["Form", "Also Known As", "Solubility", "Albumin Bound?", "Appears in Urine?"],
["Unconjugated Bilirubin (UCB)", "Indirect Bilirubin", "Lipid-soluble", "Yes (tightly)", "No"],
["Conjugated Bilirubin (CB)", "Direct Bilirubin", "Water-soluble", "No", "Yes (when elevated)"],
["Delta Bilirubin (δ)", "Albumin-bound CB", "Water-soluble", "Covalently", "No"],
]
story.append(make_table(bili_types,
[4.5*cm, 3.8*cm, 3*cm, 3*cm, 3*cm],
header_bg=TEAL))
story.append(SP(5))
story.append(para(
"<b>Key chemistry:</b> UCB is stabilized by <b>six intramolecular hydrogen bonds</b> in a 'ridge-tile' configuration "
"(Z,Z conformation) — this makes it water-insoluble and shields it from the diazo reagent. "
"Phototherapy converts Z,Z → E-isomers, which are water-soluble and can be excreted without conjugation (neonatal jaundice treatment).",
NOTE
))
story.append(SP(10))
# ════════════════════════════════════════════════════════════════════
# SECTION 2 — PRINCIPLE
# ════════════════════════════════════════════════════════════════════
story.append(SectionHeader("2. PRINCIPLE: THE DIAZO (VAN DEN BERGH) REACTION", bg=ORANGE))
story.append(SP(6))
story.append(para(
"All routine serum bilirubin measurements are based on the <b>Diazo Reaction</b>, "
"discovered by Ehrlich (1883) and applied to serum by <b>Van den Bergh and Muller (1916)</b>. "
"The current standard method is the <b>Jendrassik-Grof method (1938)</b>, modified by Doumas — the method of choice."
))
story.append(SP(5))
story.append(InfoBox(
"CHEMICAL REACTION",
"Diazotized sulfanilic acid reacts with the two central pyrrole rings of bilirubin by electrophilic aromatic "
"substitution. The central methylene carbon is cleaved, producing two PHENYL-AZO ADDUCTS (azodipyroles / azobilirubin) "
"that absorb at 540 nm (reddish-purple at neutral pH) or 600 nm (blue at alkaline pH).",
bg=ORANGE_LIGHT, border=ORANGE
))
story.append(SP(7))
story.append(para("<b>Why the two-step approach?</b>", BODY_BOLD))
react_data = [
["Bilirubin Type", "Condition", "Reaction Speed", "Reason"],
["Conjugated (Direct)", "Aqueous, NO accelerator", "RAPID (< 1 min)", "Water-soluble; no internal H-bonds blocking diazo access"],
["Unconjugated (Indirect)", "Aqueous, NO accelerator", "Very slow", "Albumin-bound; internal H-bonds block diazo reagent"],
["Unconjugated (Indirect)", "With accelerator (caffeine-benzoate)", "Rapid", "Accelerator displaces UCB from albumin, breaks H-bonds"],
]
story.append(SP(5))
story.append(make_table(react_data,
[4*cm, 5*cm, 3.5*cm, 5.8*cm],
header_bg=ORANGE, alt_row_bg=ORANGE_LIGHT, border_color=ORANGE))
story.append(SP(5))
story.append(para(
"<b>Preferred accelerator:</b> Caffeine-sodium benzoate (aqueous). <i>NOT</i> methanol or ethanol — "
"those cause protein precipitation, turbidity, and matrix interference.",
NOTE
))
story.append(SP(10))
# ════════════════════════════════════════════════════════════════════
# SECTION 3 — REAGENTS
# ════════════════════════════════════════════════════════════════════
story.append(SectionHeader("3. REAGENTS REQUIRED", bg=PURPLE))
story.append(SP(6))
reagent_data = [
["Reagent", "Composition", "Purpose"],
["Diazo Reagent", "Sulfanilic acid + NaNO₂ + HCl (freshly prepared)", "Couples with bilirubin to form colored azobilirubin"],
["Accelerator", "Caffeine + Sodium benzoate (aqueous solution)", "Displaces UCB from albumin; breaks H-bonds"],
["Alkaline Tartrate", "NaOH + Sodium potassium tartrate", "Shifts pH → blue color at 600 nm; increases sensitivity"],
["Blank Reagent", "Same as diazo but NaNO₂ replaced by distilled water", "Controls for background color/turbidity of serum"],
["Standard", "Known bilirubin concentration in human serum base", "Calibrates the colorimetric reading"],
]
story.append(make_table(reagent_data,
[3.5*cm, 6.5*cm, 7.3*cm],
header_bg=PURPLE, alt_row_bg=PURPLE_LIGHT, border_color=PURPLE))
story.append(SP(10))
# ════════════════════════════════════════════════════════════════════
# SECTION 4 — TOTAL BILIRUBIN
# ════════════════════════════════════════════════════════════════════
story.append(SectionHeader("4. ESTIMATION OF TOTAL BILIRUBIN", bg=TEAL))
story.append(SP(6))
story.append(InfoBox(
"PRINCIPLE",
"Total bilirubin = Conjugated + Unconjugated bilirubin. Caffeine-benzoate accelerator displaces ALL bilirubin "
"from albumin. Both fractions react with diazo reagent. Measured at 600 nm after addition of alkaline tartrate.",
bg=TEAL_LIGHT, border=TEAL
))
story.append(SP(7))
story.append(para("<b>Procedure:</b>", BODY_BOLD))
total_proc = [
["Step", "Action", "Volume/Detail"],
["1", "Add serum to test tube", "0.1 mL serum"],
["2", "Add caffeine-benzoate accelerator", "0.5 mL — mix well"],
["3", "Add diazo reagent", "0.4 mL — mix immediately"],
["4", "Incubate at room temperature", "10 minutes (allows full reaction of all bilirubin)"],
["5", "Add alkaline tartrate solution", "1.5 mL — shifts to blue color"],
["6", "Read absorbance", "At 600 nm (or 540 nm) within 1 hour"],
["7", "Run blank simultaneously", "Serum + accelerator + blank reagent (no diazo) — subtract"],
["8", "Calculate concentration", "Use calibration curve or standard comparison"],
]
story.append(make_table(total_proc,
[1.2*cm, 8.5*cm, 7.6*cm],
header_bg=TEAL, alt_row_bg=TEAL_LIGHT, border_color=TEAL))
story.append(SP(7))
story.append(FormulaBox(
"Total Bilirubin (mg/dL) = (Absorbance of Test ÷ Absorbance of Standard) × Concentration of Standard",
bg=TEAL_LIGHT, border=TEAL
))
story.append(SP(5))
story.append(para(
"<b>Normal Range:</b> <b>0.2 – 1.0 mg/dL</b> (3.4 – 17.1 μmol/L) | "
"Jaundice becomes clinically visible at >2.5–3.0 mg/dL (scleral icterus at ~2 mg/dL)."
))
story.append(SP(10))
# ════════════════════════════════════════════════════════════════════
# SECTION 5 — DIRECT BILIRUBIN
# ════════════════════════════════════════════════════════════════════
story.append(SectionHeader("5. ESTIMATION OF DIRECT (CONJUGATED) BILIRUBIN", bg=GREEN))
story.append(SP(6))
story.append(InfoBox(
"PRINCIPLE",
"Direct bilirubin = fraction reacting with diazo reagent in AQUEOUS solution WITHOUT any accelerator. "
"Only conjugated (water-soluble) bilirubin reacts rapidly. Strict 1-minute reaction window prevents "
"unconjugated bilirubin from contributing.",
bg=GREEN_LIGHT, border=GREEN
))
story.append(SP(7))
story.append(para("<b>Procedure:</b>", BODY_BOLD))
direct_proc = [
["Step", "Action", "Volume/Detail"],
["1", "Add serum to test tube", "0.1 mL serum"],
["2", "Add distilled water", "0.9 mL — NO accelerator added"],
["3", "Add diazo reagent", "0.4 mL — mix immediately"],
["4", "Incubate at room temperature", "EXACTLY 1 minute only"],
["5", "Read absorbance immediately", "At 540 nm — do not delay"],
["6", "Run blank simultaneously", "Serum + water + blank reagent — subtract"],
]
story.append(make_table(direct_proc,
[1.2*cm, 8.5*cm, 7.6*cm],
header_bg=GREEN, alt_row_bg=GREEN_LIGHT, border_color=GREEN))
story.append(SP(7))
story.append(para(
"<b>Normal Range:</b> <b>0.0 – 0.3 mg/dL</b> (< 5.1 μmol/L)"
))
story.append(para(
"In normal plasma, only ~<b>4%</b> of total bilirubin is conjugated (direct-reacting). "
"If direct fraction is <b><15% of total bilirubin</b>, this indicates unconjugated hyperbilirubinemia.",
NOTE
))
story.append(SP(10))
# ════════════════════════════════════════════════════════════════════
# SECTION 6 — INDIRECT BILIRUBIN
# ════════════════════════════════════════════════════════════════════
story.append(SectionHeader("6. ESTIMATION OF INDIRECT (UNCONJUGATED) BILIRUBIN", bg=ORANGE))
story.append(SP(6))
story.append(InfoBox(
"PRINCIPLE",
"Indirect bilirubin CANNOT be measured directly. It is calculated by subtracting the Direct Bilirubin "
"from Total Bilirubin. Represents mostly albumin-bound unconjugated bilirubin (slow-reacting fraction).",
bg=ORANGE_LIGHT, border=ORANGE
))
story.append(SP(7))
story.append(FormulaBox(
"Indirect Bilirubin = Total Bilirubin – Direct Bilirubin",
bg=ORANGE_LIGHT, border=ORANGE
))
story.append(SP(6))
story.append(para(
"<b>Normal Range:</b> <b>0.1 – 0.8 mg/dL</b> (1.7 – 13.7 μmol/L)"
))
story.append(para(
"<b>Note:</b> The calculated indirect value may slightly <i>underestimate</i> true unconjugated bilirubin "
"because a small amount of UCB may react in the direct assay even without accelerator. "
"Direct and indirect values are not strictly equivalent to conjugated and unconjugated concentrations.",
NOTE
))
story.append(SP(10))
# ════════════════════════════════════════════════════════════════════
# SECTION 7 — REFERENCE RANGES SUMMARY
# ════════════════════════════════════════════════════════════════════
story.append(SectionHeader("7. REFERENCE RANGES SUMMARY", bg=PURPLE))
story.append(SP(6))
ref_data = [
["Fraction", "Normal Range (mg/dL)", "Normal Range (μmol/L)", "Represents"],
["Total Bilirubin", "0.2 – 1.0", "3.4 – 17.1", "All bilirubin species combined"],
["Direct (Conjugated)", "0.0 – 0.3", "0.0 – 5.1", "~4% of total in normal plasma"],
["Indirect (Unconjugated)", "0.1 – 0.8", "1.7 – 13.7", "~96% of total in normal plasma"],
]
story.append(make_table(ref_data,
[4.5*cm, 4.2*cm, 4.2*cm, 4.4*cm],
header_bg=PURPLE, alt_row_bg=PURPLE_LIGHT, border_color=PURPLE))
story.append(SP(10))
# ════════════════════════════════════════════════════════════════════
# SECTION 8 — SOURCES OF ERROR
# ════════════════════════════════════════════════════════════════════
story.append(SectionHeader("8. IMPORTANT TECHNICAL POINTS & SOURCES OF ERROR", bg=RED))
story.append(SP(6))
error_data = [
["Issue", "Explanation / Impact"],
["Hemolysis", "Hemoglobin competes with bilirubin; no significant interference up to 25 mg/dL Hb (Beckman AU analyzers). Hemolysis can falsely LOWER bilirubin by oxidation."],
["Lipemia", "No significant interference up to 500 mg/dL Intralipid."],
["Light exposure", "Bilirubin is photosensitive — samples must be protected from light (amber/covered tubes). Even minutes of exposure can degrade bilirubin significantly."],
["Methanol/Ethanol accelerators", "Cause protein precipitation and increased turbidity. Caffeine-benzoate preferred. Malloy-Evelyn method (methanol) is now largely abandoned."],
["Delta bilirubin", "Covalently albumin-bound CB. Has ~18–20 day half-life (albumin). NOT accurately measured by standard diazo methods. Important in prolonged cholestasis."],
["Direct ≠ Conjugated exactly", "Some UCB appears in 'direct' fraction; some CB (especially delta bilirubin) escapes. Can cause errors in diagnosing isolated disorders like Gilbert syndrome."],
["Bovine serum calibrators", "Give incomplete/unpredictable reactions with UCB. Human serum-based calibrators must be used (especially for neonatal bilirubin accuracy)."],
["Delayed measurement", "Total bilirubin assay should be read within 1 hour of adding alkaline tartrate. Direct bilirubin must be read immediately after 1-minute reaction."],
]
story.append(make_table(error_data,
[4.5*cm, 12.8*cm],
header_bg=RED, alt_row_bg=RED_LIGHT, border_color=RED))
story.append(SP(10))
# ════════════════════════════════════════════════════════════════════
# PAGE BREAK — CLINICAL SECTION
# ════════════════════════════════════════════════════════════════════
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════
# SECTION 9 — CLINICAL SIGNIFICANCE
# ════════════════════════════════════════════════════════════════════
story.append(SP(8))
story.append(SectionHeader("9. CLINICAL SIGNIFICANCE", bg=TEAL))
story.append(SP(6))
story.append(para(
"Bilirubin fractionation allows classification of jaundice and guides the differential diagnosis. "
"The pattern of elevation (total, direct, indirect) combined with other liver function tests and clinical features "
"determines whether jaundice is <b>pre-hepatic, hepatic, or post-hepatic</b> in origin."
))
story.append(SP(8))
# 9A — Elevated Indirect
story.append(SectionHeader("9A. ELEVATED INDIRECT (UNCONJUGATED) BILIRUBIN — Causes", bg=ORANGE, width=W-2.5*cm))
story.append(SP(5))
indirect_causes = [
["Category", "Examples"],
["↑ Production (overproduction)", "Hemolysis (intravascular/extravascular), ineffective erythropoiesis, blood transfusion, resorption of large hematomas"],
["↓ Hepatocellular uptake", "Drugs: rifampin, cyclosporine"],
["↓ Conjugation (UGT1A1 deficiency)", "Gilbert syndrome (mild), Crigler-Najjar type I (absent UGT) and type II (reduced UGT), neonatal physiologic jaundice, hypothyroidism"],
]
story.append(make_table(indirect_causes,
[5.5*cm, 11.8*cm],
header_bg=ORANGE, alt_row_bg=ORANGE_LIGHT, border_color=ORANGE))
story.append(SP(5))
story.append(InfoBox(
"NEONATAL JAUNDICE WARNING",
"UCB > 20–25 mg/dL exceeds albumin binding capacity → crosses blood-brain barrier → "
"deposits in basal ganglia → KERNICTERUS (toxic encephalopathy). Treatment: Blue-light phototherapy "
"(450 nm) converts Z,Z bilirubin to water-soluble E-isomers → excreted in bile without conjugation.",
bg=ORANGE_LIGHT, border=ORANGE
))
story.append(SP(10))
# 9B — Elevated Direct
story.append(SectionHeader("9B. ELEVATED DIRECT (CONJUGATED) BILIRUBIN — Causes", bg=GREEN, width=W-2.5*cm))
story.append(SP(5))
direct_causes = [
["Category", "Examples"],
["Hepatocellular disease", "Viral hepatitis (A, B, C, E), alcoholic hepatitis, drug-induced liver injury, cirrhosis, acute liver failure"],
["Intrahepatic cholestasis", "Primary biliary cholangitis (PBC), primary sclerosing cholangitis (PSC), intrahepatic cholestasis of pregnancy, drug-induced cholestasis"],
["Extrahepatic (post-hepatic) obstruction", "Choledocholithiasis, carcinoma of head of pancreas, cholangiocarcinoma, ampullary carcinoma, biliary strictures"],
["Hereditary / Benign", "Dubin-Johnson syndrome, Rotor syndrome"],
]
story.append(make_table(direct_causes,
[5.5*cm, 11.8*cm],
header_bg=GREEN, alt_row_bg=GREEN_LIGHT, border_color=GREEN))
story.append(SP(5))
story.append(InfoBox(
"KEY CLINICAL POINT",
"Even limited amounts of true conjugated bilirubin in serum indicate significant hepatobiliary pathology. "
"Conjugated hyperbilirubinemia is ALWAYS associated with bilirubinuria (dark urine / bilirubin on dipstick) "
"— EXCEPT when it is delta bilirubin (albumin-bound), which cannot be filtered by glomeruli.",
bg=GREEN_LIGHT, border=GREEN
))
story.append(SP(10))
# 9C — Pattern Diagnosis
story.append(SectionHeader("9C. DIFFERENTIAL DIAGNOSIS BY BILIRUBIN PATTERN", bg=PURPLE, width=W-2.5*cm))
story.append(SP(5))
pattern_data = [
["Bilirubin Pattern", "Likely Diagnosis / Condition"],
["↑ Indirect only, Normal Direct", "Hemolysis, Gilbert syndrome, Crigler-Najjar syndrome, neonatal physiologic jaundice"],
["↑ Direct predominantly", "Obstructive jaundice (cholestasis: intrahepatic or extrahepatic)"],
["↑ Both Direct + Indirect", "Hepatocellular disease (hepatitis, cirrhosis) — mixed pattern"],
["↑ Total serum, jaundice persists but Direct falling", "Delta bilirubin accumulation in prolonged cholestasis — 'post-recovery jaundice'"],
["Conjugated hyperbilirubinemia WITHOUT bilirubinuria", "Delta bilirubin fraction (albumin-bound; cannot pass glomerulus)"],
]
story.append(make_table(pattern_data,
[6.5*cm, 10.8*cm],
header_bg=PURPLE, alt_row_bg=PURPLE_LIGHT, border_color=PURPLE))
story.append(SP(10))
# ════════════════════════════════════════════════════════════════════
# SECTION 10 — DELTA BILIRUBIN
# ════════════════════════════════════════════════════════════════════
story.append(SectionHeader("10. THE DELTA BILIRUBIN ENIGMA", bg=GOLD))
story.append(SP(6))
story.append(InfoBox(
"WHAT IS DELTA BILIRUBIN?",
"Delta bilirubin is conjugated bilirubin COVALENTLY bound to albumin. It forms when hepatic excretion "
"of bilirubin glucuronides is impaired and glucuronides accumulate in serum. Its half-life mirrors albumin "
"(18–20 days) rather than free bilirubin (only ~4 hours).",
bg=GOLD_LIGHT, border=GOLD
))
story.append(SP(6))
delta_data = [
["Clinical Enigma", "Explanation"],
["Bilirubinuria absent despite conjugated hyperbilirubinemia", "Delta bilirubin (albumin-bound) cannot be filtered by glomeruli due to large molecular size"],
["Jaundice persists after apparent biochemical recovery", "Delta bilirubin has 18–20 day half-life matching albumin; clears slowly even after underlying cause resolves"],
["Underestimated by standard assays", "Diazo methods and some automated spectroscopic assays fail to accurately detect delta bilirubin"],
]
story.append(make_table(delta_data,
[6.5*cm, 10.8*cm],
header_bg=GOLD, alt_row_bg=GOLD_LIGHT, border_color=GOLD))
story.append(SP(10))
# ════════════════════════════════════════════════════════════════════
# SECTION 11 — METHODS COMPARISON
# ════════════════════════════════════════════════════════════════════
story.append(SectionHeader("11. METHODS FOR BILIRUBIN MEASUREMENT — COMPARISON", bg=TEAL))
story.append(SP(6))
methods_data = [
["Method", "Principle", "Status / Use"],
["Jendrassik-Grof (modified by Doumas)", "Diazo + caffeine-benzoate accelerator; alkaline tartrate for color development", "METHOD OF CHOICE — reproducible, reliable, transferable"],
["Malloy-Evelyn", "Diazo + methanol accelerator", "ABANDONED — protein precipitation, matrix effects, Hb interference"],
["Direct spectrophotometry", "Absorbance measurement at two wavelengths; solves two-component equations", "Used in neonates (only UCB present); requires Hb correction"],
["HPLC", "Chromatographic separation of α (UCB), β (monoglucuronide), γ (diglucuronide), δ (albumin-bound) fractions", "Research/reference method — not routine clinical use"],
["Transcutaneous bilirubinometry", "Non-invasive skin reflectance measurement", "Screening only — NOT a substitute for quantitative serum assay"],
]
story.append(make_table(methods_data,
[4.5*cm, 6.5*cm, 6.3*cm],
header_bg=TEAL, alt_row_bg=TEAL_LIGHT, border_color=TEAL))
story.append(SP(10))
# ════════════════════════════════════════════════════════════════════
# SOURCES
# ════════════════════════════════════════════════════════════════════
story.append(HRFlowable(color=TEAL, thickness=1.5, width="100%"))
story.append(SP(5))
story.append(para("<b>Sources:</b>", BODY_BOLD))
sources = [
"Tietz Textbook of Laboratory Medicine, 7th Edition, pp. 1971–1972",
"Henry's Clinical Diagnosis and Management by Laboratory Methods, p. 527",
"Harrison's Principles of Internal Medicine, 22nd Ed., pp. 1650–1655",
"Sleisenger and Fordtran's Gastrointestinal and Liver Disease, pp. 335–336",
"Lippincott's Illustrated Reviews: Biochemistry, 8th Ed., p. 805",
]
for s in sources:
story.append(para(f"• {s}", NOTE))
# ── Build PDF ────────────────────────────────────────────────────────────────
doc.build(story, onFirstPage=on_page, onLaterPages=on_page)
print("PDF created successfully.")
cd /home/daytona/workspace/bilirubin-pdf && python create_pdf.py 2>&1
ls -lh /home/daytona/workspace/bilirubin-pdf/
Bilirubin Estimation Serum
PDF Document · PDF