~/thiamine-pdf/build_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm
from reportlab.lib import colors
from reportlab.platypus import (SimpleDocTemplate, Paragraph, Spacer, Table,
TableStyle, HRFlowable, KeepTogether, Image)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
OUTPUT = "/tmp/workspace/thiamine-pdf/Thiamine_Vitamin_B1_Rafi.pdf"
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
rightMargin=2*cm, leftMargin=2*cm,
topMargin=2.2*cm, bottomMargin=2*cm,
title="Thiamine (Vitamin B1) - Biochemistry Notes",
author="Rafi MD Biochemistry - NMC Curriculum"
)
W, H = A4
PAGE_W = W - 4*cm # usable width
# ── Colour palette ──────────────────────────────────────────────
DARK_BLUE = colors.HexColor("#1a3a5c")
MID_BLUE = colors.HexColor("#2e6da4")
LIGHT_BLUE = colors.HexColor("#ddeeff")
ACCENT = colors.HexColor("#e07b00")
LIGHT_GREY = colors.HexColor("#f5f5f5")
TABLE_HEAD = colors.HexColor("#2e6da4")
TABLE_ALT = colors.HexColor("#eaf3fb")
RED_BOX = colors.HexColor("#fff0f0")
RED_BORDER = colors.HexColor("#cc0000")
GREEN_BOX = colors.HexColor("#f0fff4")
GREEN_BORDER= colors.HexColor("#2e7d32")
# ── Styles ──────────────────────────────────────────────────────
styles = getSampleStyleSheet()
title_style = ParagraphStyle("TitleS", parent=styles["Title"],
fontSize=22, textColor=DARK_BLUE, spaceAfter=4,
alignment=TA_CENTER, fontName="Helvetica-Bold")
subtitle_style = ParagraphStyle("SubtitleS", parent=styles["Normal"],
fontSize=11, textColor=MID_BLUE, spaceAfter=14,
alignment=TA_CENTER, fontName="Helvetica-Oblique")
h1 = ParagraphStyle("H1", parent=styles["Heading1"],
fontSize=13, textColor=colors.white, spaceAfter=4, spaceBefore=14,
fontName="Helvetica-Bold", backColor=DARK_BLUE,
borderPad=5, leading=18)
h2 = ParagraphStyle("H2", parent=styles["Heading2"],
fontSize=11, textColor=DARK_BLUE, spaceAfter=2, spaceBefore=8,
fontName="Helvetica-Bold", borderPad=2)
body = ParagraphStyle("Body", parent=styles["Normal"],
fontSize=9.5, leading=14, spaceAfter=4,
alignment=TA_JUSTIFY, fontName="Helvetica")
body_bold = ParagraphStyle("BodyBold", parent=body,
fontName="Helvetica-Bold")
bullet = ParagraphStyle("Bullet", parent=body,
leftIndent=14, bulletIndent=4, spaceAfter=2)
caption = ParagraphStyle("Caption", parent=styles["Normal"],
fontSize=8, textColor=colors.grey, alignment=TA_CENTER,
fontName="Helvetica-Oblique", spaceAfter=8)
box_title = ParagraphStyle("BoxTitle", parent=styles["Normal"],
fontSize=10, textColor=RED_BORDER, fontName="Helvetica-Bold",
spaceAfter=3)
box_body = ParagraphStyle("BoxBody", parent=body, fontSize=9.5)
green_title = ParagraphStyle("GreenTitle", parent=box_title,
textColor=GREEN_BORDER)
# ── Helpers ─────────────────────────────────────────────────────
def section(title):
return [Paragraph(f" {title}", h1), Spacer(1, 4)]
def sub(title):
return Paragraph(title, h2)
def p(text):
return Paragraph(text, body)
def b(text):
"""Bullet point"""
return Paragraph(f"• {text}", bullet)
def sp(n=6):
return Spacer(1, n)
def hr():
return HRFlowable(width="100%", thickness=0.5,
color=colors.HexColor("#cccccc"), spaceAfter=6)
def make_table(data, col_widths=None, header=True):
t = Table(data, colWidths=col_widths, hAlign="LEFT",
repeatRows=1 if header else 0)
style = [
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 9),
("BACKGROUND", (0,0), (-1,0), TABLE_HEAD),
("TEXTCOLOR", (0,0), (-1,0), colors.white),
("ALIGN", (0,0), (-1,-1), "LEFT"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("ROWBACKGROUNDS", (0,1), (-1,-1), [colors.white, TABLE_ALT]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#aaaaaa")),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
]
t.setStyle(TableStyle(style))
return t
def red_box(title, items):
"""Warning / critical box"""
content = [Paragraph(f"⚠ {title}", box_title)]
for item in items:
content.append(Paragraph(f"• {item}", box_body))
t = Table([[content]], colWidths=[PAGE_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), RED_BOX),
("BOX", (0,0), (-1,-1), 1.5, RED_BORDER),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
]))
return t
def green_box(title, items):
"""Key point / summary box"""
content = [Paragraph(f"✔ {title}", green_title)]
for item in items:
content.append(Paragraph(f"• {item}", box_body))
t = Table([[content]], colWidths=[PAGE_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), GREEN_BOX),
("BOX", (0,0), (-1,-1), 1.5, GREEN_BORDER),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
]))
return t
# ── Content ─────────────────────────────────────────────────────
story = []
# Title block
story.append(Spacer(1, 8))
story.append(Paragraph("Thiamine (Vitamin B<sub>1</sub>)", title_style))
story.append(Paragraph("Biochemistry Notes | As per NMC CBME Curriculum | Rafi MD — 5th Edition", subtitle_style))
story.append(HRFlowable(width="100%", thickness=2, color=ACCENT, spaceAfter=12))
# ── 1. Structure ────────────────────────────────────────────────
story += section("1. Structure and Active Coenzyme Form")
story.append(p("Thiamine is a <b>water-soluble B-group vitamin</b> (Vitamin B<sub>1</sub>) — the first B vitamin to be identified. Its molecule consists of:"))
story += [
b("A <b>pyrimidine ring</b> — containing amino and methyl substituents"),
b("A <b>thiazole ring</b> — containing a reactive carbon between N and S atoms"),
b("The two rings are joined by a <b>methylene bridge</b>"),
]
story.append(sp(6))
story.append(sub("Activation to Coenzyme Form"))
story.append(p("Thiamine is converted to its active form <b>Thiamine Pyrophosphate (TPP)</b> — also called <b>thiamine diphosphate</b> or <b>cocarboxylase</b> — by the enzyme <b>thiamine pyrophosphokinase</b>:"))
story.append(sp(4))
rxn_data = [["Reaction", "Enzyme", "Products"],
["Thiamine + ATP", "Thiamine pyrophosphokinase", "TPP + AMP"]]
story.append(make_table(rxn_data, col_widths=[PAGE_W*0.35, PAGE_W*0.38, PAGE_W*0.27]))
story.append(sp(8))
story.append(p("The <b>reactive carbon on the thiazole ring</b> of TPP is responsible for all its catalytic activity (it attacks the carbonyl group of α-keto acids)."))
story.append(sp(10))
# Images side by side
img1 = Image("/tmp/workspace/thiamine-pdf/tpp_structure.png", width=7.2*cm, height=9.6*cm)
img2 = Image("/tmp/workspace/thiamine-pdf/tpp_reactions.png", width=7.2*cm, height=9.6*cm)
img_table = Table(
[[img1, img2]],
colWidths=[PAGE_W/2 - 0.5*cm, PAGE_W/2 - 0.5*cm],
hAlign="CENTER"
)
img_table.setStyle(TableStyle([
("ALIGN", (0,0), (-1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "TOP"),
("LEFTPADDING", (0,0), (-1,-1), 4),
("RIGHTPADDING", (0,0), (-1,-1), 4),
]))
story.append(img_table)
cap_table = Table(
[[Paragraph("<i>Fig. A: Structure of Thiamine → TPP (Thiamine + ATP → TPP + AMP via thiamine pyrophosphokinase). The reactive carbon on the thiazole ring is shown.</i>", caption),
Paragraph("<i>Fig. B: Reactions using TPP as coenzyme. A — Transketolase (pentose phosphate pathway). B — Pyruvate dehydrogenase and α-ketoglutarate dehydrogenase (TCA cycle).</i>", caption)]],
colWidths=[PAGE_W/2 - 0.5*cm, PAGE_W/2 - 0.5*cm]
)
cap_table.setStyle(TableStyle([("ALIGN",(0,0),(-1,-1),"CENTER"), ("VALIGN",(0,0),(-1,-1),"TOP")]))
story.append(cap_table)
story.append(p("<i>Source: Lippincott Illustrated Reviews: Biochemistry, 8th Ed., Figs. 28.11 & 28.12</i>"))
# ── 2. Biochemical Functions ─────────────────────────────────────
story += section("2. Biochemical Functions — Enzymes Requiring TPP")
story.append(p("TPP acts as coenzyme in two major categories of reactions:"))
story.append(sp(4))
story.append(sub("A. Oxidative Decarboxylation of α-Keto Acids"))
story.append(p("These reactions are critical for energy generation. The CNS is especially vulnerable because neurons depend almost entirely on aerobic glucose oxidation."))
story.append(sp(4))
enz_data = [
["Substrate → Product", "Enzyme Complex", "Pathway / Significance"],
["Pyruvate → Acetyl-CoA + CO₂", "Pyruvate dehydrogenase complex (PDHC)", "Entry into TCA cycle"],
["α-Ketoglutarate → Succinyl-CoA + CO₂", "α-Ketoglutarate dehydrogenase", "TCA cycle step"],
["Branched-chain α-keto acids → acyl-CoA", "Branched-chain α-keto acid dehydrogenase", "Amino acid catabolism (muscle)"],
]
story.append(make_table(enz_data, col_widths=[PAGE_W*0.36, PAGE_W*0.37, PAGE_W*0.27]))
story.append(sp(8))
story.append(sub("B. Transketolase Reaction — Pentose Phosphate Pathway"))
story.append(p("TPP is the coenzyme for <b>transketolase</b>, which interconverts hexose and pentose phosphates:"))
story += [
b("Xylulose 5-P + Ribose 5-P → Sedoheptulose 7-P + Glyceraldehyde 3-P"),
b("This reaction links the pentose phosphate pathway to glycolysis"),
b("RBCs contain only the cytosolic transketolase (no PDH — no mitochondria), making <b>RBC transketolase the clinical assay marker for thiamine status</b>"),
]
story.append(sp(8))
story.append(red_box("Key Biochemical Consequence of Thiamine Deficiency", [
"Pyruvate dehydrogenase and α-KG dehydrogenase both fail → pyruvate and lactate accumulate in blood/tissues",
"Impaired ATP synthesis → cellular dysfunction, especially in CNS and cardiac muscle",
"Giving IV glucose to a thiamine-deficient patient sharply increases demand for PDHC → precipitates/worsens Wernicke's encephalopathy — ALWAYS give thiamine BEFORE or with glucose",
]))
story.append(sp(8))
# ── 3. Sources ────────────────────────────────────────────────────
story += section("3. Dietary Sources and Losses")
src_data = [
["Food (Vegetable Origin)", "mg/100 g", "Food (Animal Origin)", "mg/100 g"],
["Gingelly seeds", "1.01", "Sheep liver", "0.36"],
["Groundnut", "0.90", "Mutton", "0.18"],
["Bengal gram dhal", "0.48", "Hen's egg", "0.10"],
["Wheat (whole)", "0.45", "Cow's milk", "0.05"],
["Almonds", "0.24", "", ""],
["Rice (home-pounded)", "0.21", "", ""],
["Rice (milled/polished)", "0.06 ⚠", "", ""],
]
story.append(make_table(src_data, col_widths=[PAGE_W*0.32, PAGE_W*0.18, PAGE_W*0.32, PAGE_W*0.18]))
story.append(sp(6))
story.append(sub("Anti-Thiamine Factors in Food"))
story += [
b("<b>Thiaminases</b> (heat-labile) — in raw fish and shellfish; enzymatically destroy thiamine"),
b("<b>Tannins / polyhydroxyphenols</b> (heat-stable) — in tea, coffee, betel nuts, Brussels sprouts; inactivate thiamine. Excessive tea/coffee consumption can lower thiamine stores"),
]
story.append(sp(4))
story.append(sub("Thiamine Losses During Processing"))
story += [
b("Milling/polishing rice removes the thiamine-rich bran/husk — polished rice retains only 0.06 mg/100 g"),
b("Parboiling drives thiamine from bran into the endosperm before milling — parboiled rice retains more thiamine"),
b("Being water-soluble, thiamine is further lost during washing and prolonged cooking of rice"),
]
story.append(sp(8))
# ── 4. Absorption, Metabolism, Stores ────────────────────────────
story += section("4. Absorption, Metabolism, and Body Stores")
story += [
b("Absorbed in the <b>proximal small intestine</b> via a saturable thiamine transporter at low concentrations (≤1 µmol/L); passive diffusion at higher doses"),
b("<b>Alcohol impairs intestinal thiamine absorption</b> — key mechanism in alcoholism-associated deficiency"),
b("Transported in blood; phosphorylated intracellularly to TPP by thiamine pyrophosphokinase"),
b("<b>Total body store: ~30 mg</b> — depleted within <b>4–6 weeks</b> of inadequate intake"),
b("Excess thiamine is excreted in urine — no significant long-term storage possible"),
b("Patients on <b>hemodialysis</b> lose thiamine and require routine supplementation"),
]
story.append(sp(8))
# ── 5. Daily Requirement ──────────────────────────────────────────
story += section("5. Daily Requirement")
req_data = [
["Population Group", "Recommended Daily Allowance"],
["Adults (general)", "~1.0–1.4 mg/day"],
["Median US dietary intake", "~2 mg/day"],
["Overt deficiency threshold", "<0.3 mg/1000 kcal/day"],
]
story.append(make_table(req_data, col_widths=[PAGE_W*0.55, PAGE_W*0.45]))
story.append(sp(4))
story.append(p("Requirements <b>increase with high-carbohydrate diets</b> (more TPP needed for pyruvate dehydrogenase). Special supplementation needed in: hemodialysis patients, chronic alcoholics, persistent vomiting, prolonged gastric aspiration, long fasts."))
story.append(sp(8))
# ── 6. Causes of Deficiency ───────────────────────────────────────
story += section("6. Causes of Thiamine Deficiency")
cause_data = [
["Cause", "Mechanism"],
["Alcoholism (most common in developed world)", "Poor intake + impaired intestinal absorption by alcohol"],
["Polished rice-based diet (South/SE Asia)", "Milling removes thiamine-rich bran"],
["Chronic diuretic use", "Increased urinary losses"],
["Bariatric surgery / malabsorption", "Reduced absorption"],
["Hyperemesis gravidarum", "Vomiting + reduced intake"],
["Prolonged IV feeding (without thiamine)", "Absent supplementation; glucose increases demand"],
["Hemodialysis", "Dialytic removal of water-soluble vitamins"],
["Raw fish / excess tea/coffee", "Anti-thiamine factors destroy/inactivate vitamin"],
]
story.append(make_table(cause_data, col_widths=[PAGE_W*0.5, PAGE_W*0.5]))
story.append(sp(8))
# ── 7. Deficiency Diseases ────────────────────────────────────────
story += section("7. Clinical Features of Thiamine Deficiency")
story.append(sub("A. Beriberi"))
story.append(sp(4))
beri_data = [
["Type", "Key Features", "Mechanism"],
["Dry Beriberi\n(Neuritic)", "Symmetrical peripheral neuropathy (esp. lower limbs)\nMuscle weakness & wasting\nBurning/tingling in feet\nLoss of deep tendon reflexes", "Impaired ATP production in peripheral neurons"],
["Wet Beriberi\n(Cardiac)", "High-output cardiac failure\nCardiomegaly\nBilateral pitting edema → anasarca\nTachycardia, palpitations", "Thiamine deficiency in myocardium → reduced ATP → dilated cardiomyopathy + peripheral vasodilation"],
["Infantile Beriberi", "Age 2–4 months; breastfed by deficient mother\nAphonic cry (hoarseness)\nCardiac failure, cyanosis\nCan be rapidly fatal", "Mother has peripheral neuropathy; infant's high metabolic demand"],
]
story.append(make_table(beri_data, col_widths=[PAGE_W*0.18, PAGE_W*0.44, PAGE_W*0.38]))
story.append(sp(10))
story.append(sub("B. Wernicke–Korsakoff Syndrome"))
story.append(p("Primarily in <b>chronic alcoholics</b>; also in: hyperemesis gravidarum, prolonged fasting, malignancy, post-bariatric surgery."))
story.append(sp(4))
wk_data = [
["Stage", "Features"],
["Wernicke's Encephalopathy (Acute)", "Classic triad:\n1. Ophthalmoplegia — lateral rectus palsy, conjugate gaze palsy, nystagmus\n2. Cerebellar ataxia — wide-based unsteady gait\n3. Mental confusion / altered consciousness\nPathology: hemorrhagic lesions in mammillary bodies, thalamus, periaqueductal grey"],
["Korsakoff's Psychosis (Chronic)", "Anterograde + retrograde amnesia (new memory formation severely impaired)\nConfabulation (unconscious fabrication of answers/memories)\nRelatively intact cognition otherwise\nOften IRREVERSIBLE even with thiamine treatment"],
]
story.append(make_table(wk_data, col_widths=[PAGE_W*0.32, PAGE_W*0.68]))
story.append(sp(8))
# ── 8. Diagnosis ──────────────────────────────────────────────────
story += section("8. Diagnosis of Thiamine Deficiency")
story.append(p("<b>Test of choice: Erythrocyte Transketolase Activity (ETKA) + TPP Stimulation Test</b>"))
story += [
b("Measure RBC transketolase activity <b>before</b> and <b>after</b> addition of TPP in vitro"),
b("<b>>25% increase</b> in transketolase activity after TPP addition = thiamine deficiency (enzyme was coenzyme-starved)"),
b("RBCs are used because they contain transketolase but <b>lack mitochondria</b> (so PDH is absent) — makes transketolase the specific assay marker"),
b("Serum/blood thiamine concentration can also be measured directly but is less reliable alone"),
]
story.append(sp(6))
story.append(green_box("Why RBCs for the Assay?", [
"Red blood cells do not have mitochondria → do not contain pyruvate dehydrogenase",
"However, RBCs DO contain the cytosolic TPP-requiring transketolase",
"Transketolase activity in RBCs is therefore the specific clinical test for thiamine status",
"Source: Lippincott Illustrated Reviews: Biochemistry, 8th Ed."
]))
story.append(sp(8))
# ── 9. Treatment ──────────────────────────────────────────────────
story += section("9. Treatment")
story += [
b("<b>IV or IM thiamine</b> preferred initially (especially in Wernicke's — oral absorption is unreliable in alcoholics)"),
b("Wet beriberi: <b>rapid response</b> within hours to days after thiamine"),
b("Dry beriberi/neuropathy: slower, often incomplete recovery"),
b("Korsakoff's dementia: <b>poor recovery</b> even with treatment; memory recovery typically incomplete"),
]
story.append(sp(6))
story.append(red_box("CRITICAL CLINICAL RULE — Thiamine Before Glucose", [
"ALWAYS administer thiamine BEFORE or simultaneously with IV glucose in a thiamine-deficient patient",
"Glucose load → sharp increase in demand for pyruvate dehydrogenase → depletes remaining TPP",
"This can precipitate or dramatically worsen Wernicke's encephalopathy",
"This rule applies to all ER patients with suspected thiamine deficiency (alcoholics, malnourished, hyperemesis)",
]))
story.append(sp(8))
# ── 10. Prevention ────────────────────────────────────────────────
story += section("10. Prevention")
story += [
b("Promote <b>parboiled or hand-pounded rice</b> (parboiling drives thiamine into endosperm before milling)"),
b("Encourage <b>mixed, varied diets</b> — legumes, pulses, whole grains, nuts"),
b("Avoid raw fish, excess tea/coffee, betel nuts"),
b("Routine thiamine supplementation for: <b>alcoholics, pregnant women with hyperemesis, hemodialysis patients, post-bariatric surgery patients, prolonged IV nutrition</b>"),
b("Supplement lactating mothers in endemic areas (prevents infantile beriberi)"),
b("Beriberi disappears as socioeconomic conditions and dietary diversity improve"),
]
story.append(sp(8))
# ── 11. Quick Recall Summary ─────────────────────────────────────
story += section("11. Quick Recall Summary Table")
summary_data = [
["Feature", "Key Point"],
["Chemical name", "Thiamine / Vitamin B1 (first B vitamin identified)"],
["Active coenzyme form", "Thiamine Pyrophosphate (TPP) / Cocarboxylase"],
["Synthesis of TPP", "Thiamine + ATP → TPP + AMP (thiamine pyrophosphokinase)"],
["Enzymes needing TPP", "Pyruvate dehydrogenase, α-KG dehydrogenase, Transketolase, Branched-chain α-keto acid dehydrogenase"],
["Key metabolic effect of deficiency", "Pyruvate + lactate accumulation; impaired ATP synthesis"],
["Best food sources", "Yeast, whole grains, legumes, pork, groundnuts, gingelly seeds"],
["Anti-thiamine factors", "Thiaminases (raw fish, shellfish); Tannins (tea, coffee, betel nuts)"],
["Body stores", "~30 mg total; depleted in 4–6 weeks"],
["Daily requirement (adults)", "~1.0–1.4 mg/day; deficiency at <0.3 mg/1000 kcal"],
["Deficiency diseases", "Dry beriberi, Wet beriberi, Infantile beriberi, Wernicke–Korsakoff syndrome"],
["Diagnostic test", "RBC transketolase activity + TPP stimulation test (>25% increase = deficient)"],
["Treatment", "IV/IM thiamine; give BEFORE glucose in suspected Wernicke's"],
["Key clinical rule", "THIAMINE BEFORE GLUCOSE — never give glucose alone to a thiamine-deficient patient"],
]
story.append(make_table(summary_data, col_widths=[PAGE_W*0.38, PAGE_W*0.62]))
story.append(sp(10))
# Footer note
story.append(hr())
story.append(Paragraph(
"<i>Content compiled from: Lippincott Illustrated Reviews: Biochemistry, 8th Ed. | "
"Harrison's Principles of Internal Medicine, 22nd Ed. (2025) | "
"Park's Textbook of Preventive & Social Medicine. "
"Aligned with NMC CBME Biochemistry curriculum as in Rafi MD Textbook of Biochemistry, 5th Ed.</i>",
caption
))
# ── Build ────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF created: {OUTPUT}")