Imp topics notes for practical of biochemistry
MBBS 1st year biochemistry practical important topics urine analysis blood analysis enzymes carbohydrates
| Reagent | Mechanism | Notes |
|---|---|---|
| TCA (trichloroacetic acid) | Irreversible denaturation | Forms white precipitate |
| Heat coagulation | Denaturation at isoelectric pH | Add few drops acetic acid |
| Tannic acid | Heavy metal precipitation | Tannin-protein complex |
| Picric acid | Heavy metal/acid precipitant | Yellow precipitate |
| Salting out (ammonium sulphate) | Reversible; removes hydration shell | Globulins (half saturation), albumin (full saturation) |
| Parameter | Normal Value | Abnormal |
|---|---|---|
| Volume | 1000-1500 mL/day | Oliguria <400 mL, polyuria >3000 mL |
| Color | Pale yellow to amber | Dark = bilirubinuria; red = hematuria |
| Appearance | Clear | Turbid = infection, crystals |
| Specific gravity | 1.010-1.025 | Fixed SG (isosthenuria) in renal failure |
| pH | 4.6-8.0 (avg 6.0) | Acid = high protein diet; alkaline = UTI |
| Odor | Slightly aromatic | Fruity = ketones (DM); ammoniacal = stale/UTI |
| Enzyme | Principle | Normal | Clinical Significance |
|---|---|---|---|
| ALP | p-nitrophenyl phosphate hydrolysis | 30-120 IU/L | Obstructive jaundice, bone disease |
| SGPT/ALT | Transamination, NADH oxidation | 7-56 IU/L | Viral hepatitis, liver necrosis |
| SGOT/AST | Transamination | 10-40 IU/L | MI, liver disease |
| Amylase | Starch hydrolysis (iodometric/saccharogenic) | 25-125 IU/L | Acute pancreatitis |
| LDH | Pyruvate/lactate interconversion | 100-190 IU/L | MI, hemolysis |
| Test | Reagent | Positive Result |
|---|---|---|
| Molisch | α-Naphthol + conc. H₂SO₄ | Purple ring |
| Benedict | Cu²⁺ in citrate-carbonate | Brick-red ppt |
| Seliwanoff | Resorcinol + HCl | Cherry-red |
| Biuret | NaOH + CuSO₄ | Violet |
| Xanthoproteic | Conc. HNO₃ | Yellow → orange (with NaOH) |
| Ninhydrin | 0.1% ninhydrin | Purple/blue |
| Rothera | Nitroprusside + NH₃ | Purple ring |
| Fouchet | BaCl₂ + Fouchet's reagent | Green/blue |
| Hay's Sulphur | Sulfur powder on urine | Sulfur sinks |
| Liebermann-Burchard | Acetic anhydride + H₂SO₄ | Emerald green |
Create a comprehensive study guide PDF with all practical procedures and flowcharts
ls -la /home/daytona/workspace/ && mkdir -p /home/daytona/workspace/biochem-practical-guide
~/biochem-practical-guide/generate_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm, mm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak, KeepTogether
)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import Flowable
from reportlab.graphics.shapes import Drawing, Rect, String, Line, Arrow, Polygon
from reportlab.graphics import renderPDF
import os
OUTPUT_PATH = "/home/daytona/workspace/biochem-practical-guide/Biochemistry_Practical_Guide.pdf"
# ── Colours ──────────────────────────────────────────────────────────────────
DARK_BLUE = colors.HexColor("#1A3560")
MED_BLUE = colors.HexColor("#2B5DA8")
LIGHT_BLUE = colors.HexColor("#D6E4F7")
TEAL = colors.HexColor("#0D7A75")
LIGHT_TEAL = colors.HexColor("#D0F0EE")
ORANGE = colors.HexColor("#E06C2A")
LIGHT_ORANGE= colors.HexColor("#FDE8D8")
GOLD = colors.HexColor("#C49A22")
LIGHT_GOLD = colors.HexColor("#FFF3CC")
RED = colors.HexColor("#C0392B")
LIGHT_RED = colors.HexColor("#FADBD8")
GREEN = colors.HexColor("#1E7E45")
LIGHT_GREEN = colors.HexColor("#D5F5E3")
PURPLE = colors.HexColor("#6C3483")
LIGHT_PURPLE= colors.HexColor("#E8DAEF")
GREY_LIGHT = colors.HexColor("#F4F6F8")
GREY_MED = colors.HexColor("#BDC3C7")
PAGE_W, PAGE_H = A4
# ── Styles ────────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
def make_style(name, parent="Normal", **kw):
s = ParagraphStyle(name, parent=styles[parent], **kw)
return s
ST = {
"cover_title": make_style("CoverTitle", fontSize=28, textColor=colors.white,
fontName="Helvetica-Bold", alignment=TA_CENTER, spaceAfter=6),
"cover_sub": make_style("CoverSub", fontSize=14, textColor=LIGHT_BLUE,
fontName="Helvetica", alignment=TA_CENTER, spaceAfter=4),
"cover_tag": make_style("CoverTag", fontSize=11, textColor=LIGHT_GOLD,
fontName="Helvetica-Oblique", alignment=TA_CENTER),
"ch_title": make_style("ChTitle", fontSize=16, textColor=colors.white,
fontName="Helvetica-Bold", alignment=TA_CENTER,
spaceAfter=2, spaceBefore=4),
"section": make_style("Section", fontSize=13, textColor=DARK_BLUE,
fontName="Helvetica-Bold", spaceBefore=12, spaceAfter=4,
borderPad=4),
"subsection": make_style("Subsection", fontSize=11, textColor=MED_BLUE,
fontName="Helvetica-Bold", spaceBefore=8, spaceAfter=3),
"body": make_style("Body", fontSize=9.5, textColor=colors.black,
fontName="Helvetica", leading=14, spaceAfter=4,
alignment=TA_JUSTIFY),
"bullet": make_style("Bullet", fontSize=9.5, textColor=colors.black,
fontName="Helvetica", leading=13, spaceAfter=2,
leftIndent=14, firstLineIndent=-8),
"note": make_style("Note", fontSize=9, textColor=DARK_BLUE,
fontName="Helvetica-Oblique", leading=12,
backColor=LIGHT_GOLD, borderPad=6, spaceAfter=4),
"table_hdr": make_style("TblHdr", fontSize=9, textColor=colors.white,
fontName="Helvetica-Bold", alignment=TA_CENTER),
"table_cell": make_style("TblCell", fontSize=8.5, textColor=colors.black,
fontName="Helvetica", leading=12),
"table_cell_c":make_style("TblCellC", fontSize=8.5, textColor=colors.black,
fontName="Helvetica", leading=12, alignment=TA_CENTER),
"footer": make_style("Footer", fontSize=8, textColor=GREY_MED,
fontName="Helvetica", alignment=TA_CENTER),
"pos": make_style("Pos", fontSize=9, textColor=GREEN,
fontName="Helvetica-Bold"),
"neg": make_style("Neg", fontSize=9, textColor=RED,
fontName="Helvetica-Bold"),
"key_box": make_style("KeyBox", fontSize=9, textColor=PURPLE,
fontName="Helvetica-Bold", leading=13,
backColor=LIGHT_PURPLE, borderPad=5),
}
# ── Helper Flowables ──────────────────────────────────────────────────────────
def hline(color=GREY_MED, thickness=0.5):
return HRFlowable(width="100%", thickness=thickness, color=color, spaceAfter=4, spaceBefore=4)
def sp(h=6):
return Spacer(1, h)
def P(text, style="body"):
return Paragraph(text, ST[style])
def B(text):
"""Bullet paragraph."""
return Paragraph(f"• {text}", ST["bullet"])
def chapter_banner(title, color=DARK_BLUE, sub=""):
"""Returns a coloured banner for chapter headings."""
data = [[Paragraph(title, ST["ch_title"])]]
if sub:
data.append([Paragraph(sub, make_style("ChSub", fontSize=10,
textColor=LIGHT_BLUE, fontName="Helvetica", alignment=TA_CENTER))])
t = Table(data, colWidths=[PAGE_W - 4*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), color),
("ROWBACKGROUNDS", (0,0), (-1,-1), [color]),
("TOPPADDING", (0,0), (-1,-1), 10),
("BOTTOMPADDING",(0,0),(-1,-1), 10),
("LEFTPADDING", (0,0), (-1,-1), 12),
("RIGHTPADDING",(0,0), (-1,-1), 12),
("ROUNDEDCORNERS", [6]),
]))
return t
def section_box(title, color=MED_BLUE):
t = Table([[Paragraph(title, ST["section"])]], colWidths=[PAGE_W - 4*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), LIGHT_BLUE),
("LEFTPADDING", (0,0), (-1,-1), 8),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1),4),
("LINEBELOW", (0,0), (-1,0), 2, color),
]))
return t
def info_box(text, bg=LIGHT_GOLD, border=GOLD):
t = Table([[Paragraph(f"<b>📌 Note:</b> {text}", ST["body"])]], colWidths=[PAGE_W - 4*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), bg),
("LINEBEFORE", (0,0),(0,-1), 3, border),
("LEFTPADDING", (0,0),(-1,-1),10),
("TOPPADDING", (0,0),(-1,-1),6),
("BOTTOMPADDING",(0,0),(-1,-1),6),
]))
return t
def make_table(headers, rows, col_widths=None, hdr_color=DARK_BLUE, alt=True):
data = [[Paragraph(h, ST["table_hdr"]) for h in headers]]
for row in rows:
data.append([Paragraph(str(c), ST["table_cell"]) for c in row])
if col_widths is None:
n = len(headers)
col_widths = [(PAGE_W - 4*cm) / n] * n
t = Table(data, colWidths=col_widths, repeatRows=1)
style = [
("BACKGROUND", (0,0), (-1,0), hdr_color),
("TEXTCOLOR", (0,0), (-1,0), colors.white),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,0), 9),
("ROWBACKGROUNDS", (0,1), (-1,-1), [colors.white, GREY_LIGHT]),
("GRID", (0,0), (-1,-1), 0.4, GREY_MED),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING",(0,0), (-1,-1), 5),
]
t.setStyle(TableStyle(style))
return t
# ── Flowchart Drawing Helper ──────────────────────────────────────────────────
class FlowchartDrawing(Flowable):
"""A simple vertical flowchart rendered as a ReportLab Drawing."""
def __init__(self, steps, width=460, title="", colors_list=None):
Flowable.__init__(self)
self.steps = steps
self.fc_width = width
self.title = title
self.colors_list = colors_list
BOX_H = 32
ARROW_H = 18
self.width = width
n = len(steps)
self.height = (BOX_H + ARROW_H) * n + (30 if title else 0)
def draw(self):
BOX_H = 32
ARROW_H = 18
BOX_W = self.fc_width - 20
x0 = 10
y_start = self.height - (30 if self.title else 0)
from reportlab.graphics.shapes import Drawing as D, Rect, String, Line, Polygon
from reportlab.lib import colors as C
canvas = self.canv
if self.title:
canvas.setFont("Helvetica-Bold", 11)
canvas.setFillColor(DARK_BLUE)
canvas.drawCentredString(self.fc_width / 2, self.height - 18, self.title)
default_colors = [MED_BLUE, TEAL, GREEN, ORANGE, PURPLE, DARK_BLUE, TEAL, MED_BLUE]
for i, step in enumerate(self.steps):
y = y_start - (BOX_H + ARROW_H) * i - BOX_H
bcolor = (self.colors_list[i] if self.colors_list and i < len(self.colors_list)
else default_colors[i % len(default_colors)])
# Box
canvas.setFillColor(bcolor)
canvas.setStrokeColor(bcolor)
canvas.roundRect(x0, y, BOX_W, BOX_H, radius=5, fill=1, stroke=0)
# Text
canvas.setFillColor(colors.white)
canvas.setFont("Helvetica-Bold", 8.5)
# split label / detail
if "|" in step:
label, detail = step.split("|", 1)
canvas.drawCentredString(x0 + BOX_W/2, y + BOX_H/2 + 3, label.strip())
canvas.setFont("Helvetica", 7.5)
canvas.drawCentredString(x0 + BOX_W/2, y + BOX_H/2 - 9, detail.strip())
else:
canvas.drawCentredString(x0 + BOX_W/2, y + BOX_H/2 - 4, step)
# Arrow (not after last)
if i < len(self.steps) - 1:
ax = x0 + BOX_W / 2
ay_top = y
ay_bot = y - ARROW_H
canvas.setStrokeColor(GREY_MED)
canvas.setFillColor(GREY_MED)
canvas.setLineWidth(1.5)
canvas.line(ax, ay_top, ax, ay_bot + 5)
# Arrow head
canvas.setFillColor(ORANGE)
canvas.setStrokeColor(ORANGE)
canvas.polygon([ax-5, ay_bot+5, ax+5, ay_bot+5, ax, ay_bot], fill=1, stroke=0)
def wrap(self, availWidth, availHeight):
return self.width, self.height
# ── Page Template ─────────────────────────────────────────────────────────────
def on_page(canvas, doc):
canvas.saveState()
# Top bar
canvas.setFillColor(DARK_BLUE)
canvas.rect(0, PAGE_H - 1.2*cm, PAGE_W, 1.2*cm, fill=1, stroke=0)
canvas.setFillColor(colors.white)
canvas.setFont("Helvetica-Bold", 9)
canvas.drawString(1.5*cm, PAGE_H - 0.8*cm, "BIOCHEMISTRY PRACTICAL GUIDE — MBBS 1st Year")
canvas.setFont("Helvetica", 9)
canvas.drawRightString(PAGE_W - 1.5*cm, PAGE_H - 0.8*cm, f"Page {doc.page}")
# Bottom bar
canvas.setFillColor(DARK_BLUE)
canvas.rect(0, 0, PAGE_W, 0.8*cm, fill=1, stroke=0)
canvas.setFillColor(LIGHT_BLUE)
canvas.setFont("Helvetica", 7.5)
canvas.drawCentredString(PAGE_W/2, 0.22*cm,
"For educational use only | Based on Harper's Biochemistry, Lippincott & Henry's Lab Medicine")
canvas.restoreState()
# ── Cover Page ────────────────────────────────────────────────────────────────
def cover_page():
elems = []
# Big background gradient rectangle simulated with stacked rects — just one colour block
class CoverBg(Flowable):
def wrap(self, w, h): return w, 14*cm
def draw(self):
c = self.canv
c.setFillColor(DARK_BLUE)
c.rect(-2*cm, -1*cm, PAGE_W + 4*cm, 15*cm, fill=1, stroke=0)
# Decorative circles
c.setFillColor(MED_BLUE)
c.circle(PAGE_W - 1*cm, 12*cm, 4*cm, fill=1, stroke=0)
c.setFillColor(colors.HexColor("#1E4A8A"))
c.circle(1*cm, -1*cm, 3*cm, fill=1, stroke=0)
c.setFillColor(TEAL)
c.circle(PAGE_W/2 + 5*cm, 8*cm, 1.5*cm, fill=1, stroke=0)
elems.append(CoverBg())
elems.append(sp(28))
elems.append(P("BIOCHEMISTRY", "cover_title"))
elems.append(P("Practical Study Guide", "cover_sub"))
elems.append(sp(8))
line_t = Table([[""]], colWidths=[8*cm])
line_t.setStyle(TableStyle([("LINEABOVE",(0,0),(0,0),2,GOLD),("TOPPADDING",(0,0),(-1,-1),0)]))
elems.append(line_t)
elems.append(sp(8))
elems.append(P("MBBS 1st Year | Complete Practical Procedures & Flowcharts", "cover_tag"))
elems.append(sp(16))
badges = [
["Carbohydrates", "Proteins", "Urine Analysis"],
["Blood Biochemistry", "Enzymes", "Lipids"],
]
badge_data = []
for row in badges:
badge_row = []
for b in row:
cell = Table([[Paragraph(b, make_style("Badge", fontSize=9, textColor=DARK_BLUE,
fontName="Helvetica-Bold", alignment=TA_CENTER))]],
colWidths=[4.5*cm])
cell.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,-1), LIGHT_GOLD),
("TOPPADDING",(0,0),(-1,-1),5),
("BOTTOMPADDING",(0,0),(-1,-1),5),
("ROUNDEDCORNERS",[4]),
]))
badge_row.append(cell)
badge_data.append(badge_row)
badge_tbl = Table(badge_data, colWidths=[4.8*cm]*3, hAlign="CENTER")
badge_tbl.setStyle(TableStyle([
("ALIGN",(0,0),(-1,-1),"CENTER"),
("VALIGN",(0,0),(-1,-1),"MIDDLE"),
("TOPPADDING",(0,0),(-1,-1),3),
("BOTTOMPADDING",(0,0),(-1,-1),3),
]))
elems.append(badge_tbl)
elems.append(sp(20))
elems.append(P("Compiled from: Harper's Illustrated Biochemistry 32e | Lippincott Biochemistry 8e | "
"Henry's Clinical Lab Methods | Basic Medical Biochemistry 6e", "cover_tag"))
elems.append(PageBreak())
return elems
# ── TABLE OF CONTENTS ─────────────────────────────────────────────────────────
def toc_page():
elems = []
elems.append(sp(6))
elems.append(chapter_banner("TABLE OF CONTENTS", DARK_BLUE))
elems.append(sp(12))
toc_items = [
("1", "Qualitative Tests for Carbohydrates", "3"),
("2", "Qualitative Tests for Proteins & Amino Acids", "7"),
("3", "Urine Analysis — Physical & Chemical", "12"),
("4", "Blood Biochemistry — Quantitative Estimations", "17"),
("5", "Enzyme Assays & Kinetics", "22"),
("6", "Lipid Tests & Estimations", "25"),
("7", "Quick Reference Tables & Viva Points", "28"),
]
for num, title, pg in toc_items:
row_data = [[
Paragraph(f"<b>{num}.</b>", make_style("N", fontSize=11, textColor=DARK_BLUE,
fontName="Helvetica-Bold")),
Paragraph(title, make_style("T", fontSize=11, textColor=colors.black, fontName="Helvetica")),
Paragraph(pg, make_style("P", fontSize=10, textColor=MED_BLUE, fontName="Helvetica-Bold",
alignment=TA_CENTER)),
]]
t = Table(row_data, colWidths=[1.2*cm, 12.5*cm, 1.3*cm])
t.setStyle(TableStyle([
("VALIGN",(0,0),(-1,-1),"MIDDLE"),
("LINEBELOW",(0,0),(-1,0), 0.3, GREY_MED),
("TOPPADDING",(0,0),(-1,-1),7),
("BOTTOMPADDING",(0,0),(-1,-1),7),
]))
elems.append(t)
elems.append(PageBreak())
return elems
# ── CHAPTER 1: CARBOHYDRATES ──────────────────────────────────────────────────
def chapter_carbohydrates():
elems = []
elems.append(chapter_banner("CHAPTER 1: QUALITATIVE TESTS FOR CARBOHYDRATES", DARK_BLUE,
sub="Molisch • Benedict • Fehling • Seliwanoff • Barfoed • Osazone • Iodine"))
elems.append(sp(10))
# Overview flowchart
elems.append(section_box("1.1 Overview — Classification of Carbohydrate Tests"))
elems.append(sp(6))
overview_data = [
[Paragraph("<b>TYPE OF TEST</b>", ST["table_hdr"]),
Paragraph("<b>TEST NAME</b>", ST["table_hdr"]),
Paragraph("<b>DETECTS</b>", ST["table_hdr"]),
Paragraph("<b>POSITIVE RESULT</b>", ST["table_hdr"])],
[P("General (all CHO)", "table_cell"), P("Molisch's", "table_cell"),
P("All carbohydrates", "table_cell"), P("Purple ring", "table_cell")],
[P("Reducing sugar", "table_cell"), P("Benedict's", "table_cell"),
P("Reducing sugars", "table_cell"), P("Brick-red precipitate", "table_cell")],
[P("Reducing sugar", "table_cell"), P("Fehling's", "table_cell"),
P("Reducing sugars", "table_cell"), P("Brick-red precipitate", "table_cell")],
[P("Ketose specific", "table_cell"), P("Seliwanoff's", "table_cell"),
P("Ketoses (fructose)", "table_cell"), P("Cherry-red color", "table_cell")],
[P("Mono vs Di", "table_cell"), P("Barfoed's", "table_cell"),
P("Monosaccharides", "table_cell"), P("Red ppt within 2-3 min", "table_cell")],
[P("Crystal formation", "table_cell"), P("Osazone", "table_cell"),
P("Reducing sugars", "table_cell"), P("Characteristic crystals", "table_cell")],
[P("Polysaccharide", "table_cell"), P("Iodine", "table_cell"),
P("Starch/glycogen", "table_cell"), P("Blue-black / Brown", "table_cell")],
]
ov_tbl = Table(overview_data, colWidths=[3.5*cm, 3.2*cm, 4.2*cm, 4.1*cm], repeatRows=1)
ov_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0), DARK_BLUE),
("TEXTCOLOR",(0,0),(-1,0), colors.white),
("ROWBACKGROUNDS",(0,1),(-1,-1), [colors.white, LIGHT_BLUE]),
("GRID",(0,0),(-1,-1),0.4,GREY_MED),
("VALIGN",(0,0),(-1,-1),"MIDDLE"),
("TOPPADDING",(0,0),(-1,-1),5),
("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),5),
("RIGHTPADDING",(0,0),(-1,-1),5),
]))
elems.append(ov_tbl)
elems.append(sp(10))
# Molisch
elems.append(section_box("1.2 Molisch's Test — General Test for Carbohydrates"))
elems.append(sp(6))
elems.append(FlowchartDrawing([
"Add 2 mL test solution to a test tube",
"Add 2 drops of Molisch's reagent (α-naphthol in alcohol) | Mix well",
"TILT the tube and add 1 mL conc. H₂SO₄ gently down the side | Do NOT mix",
"OBSERVE the interface between two layers | Wait 2-3 minutes",
"Purple/Violet ring at junction = POSITIVE ✓ | No ring = NEGATIVE ✗",
], title="MOLISCH'S TEST PROCEDURE", colors_list=[MED_BLUE, MED_BLUE, TEAL, ORANGE, GREEN]))
elems.append(sp(4))
elems.append(P("<b>Principle:</b> H₂SO₄ hydrolyzes polysaccharides to monosaccharides, then dehydrates "
"them to furfural (pentoses) or 5-hydroxymethylfurfural (hexoses). These condense with "
"α-naphthol to form a purple-coloured complex.", "body"))
elems.append(info_box("Proteins give a false positive Molisch's test due to triose formation. "
"Sucrose gives a positive result (hydrolyzed to glucose + fructose)."))
elems.append(sp(8))
# Benedict's
elems.append(section_box("1.3 Benedict's Test — Reducing Sugars"))
elems.append(sp(6))
elems.append(FlowchartDrawing([
"Add 5 mL Benedict's reagent to a test tube",
"Add 8 drops (0.5 mL) of test solution",
"Mix and place in BOILING water bath for 5 minutes",
"Remove and allow to cool — observe colour change",
"Green → Yellow → Orange → Brick-Red = Increasing sugar concentration",
], title="BENEDICT'S TEST PROCEDURE", colors_list=[TEAL,TEAL,TEAL,ORANGE,GREEN]))
elems.append(sp(4))
elems.append(P("<b>Principle:</b> Reducing sugars reduce Cu²⁺ (blue cupric ions) to Cu⁺ (red cuprous "
"oxide precipitate) in alkaline medium. The degree of color change is "
"semi-quantitative.", "body"))
semi_data = [
[Paragraph("<b>Colour</b>", ST["table_hdr"]),
Paragraph("<b>Approximate Glucose</b>", ST["table_hdr"]),
Paragraph("<b>Interpretation</b>", ST["table_hdr"])],
[P("Blue (no change)", "table_cell"), P("NIL", "table_cell"), P("Negative", "table_cell")],
[P("Green", "table_cell"), P("<0.5%", "table_cell"), P("Trace / 1+", "table_cell")],
[P("Yellow", "table_cell"), P("0.5–1%", "table_cell"), P("Moderate / 2+", "table_cell")],
[P("Orange", "table_cell"), P("1–2%", "table_cell"), P("Significant / 3+", "table_cell")],
[P("Brick-Red", "table_cell"), P(">2%", "table_cell"), P("Heavy / 4+", "table_cell")],
]
st = Table(semi_data, colWidths=[4*cm, 5*cm, 5*cm])
st.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),MED_BLUE),("TEXTCOLOR",(0,0),(-1,0),colors.white),
("ROWBACKGROUNDS",(0,1),(-1,-1),[colors.white,LIGHT_BLUE]),
("GRID",(0,0),(-1,-1),0.4,GREY_MED),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),5),("RIGHTPADDING",(0,0),(-1,-1),5),
]))
elems.append(st)
elems.append(sp(8))
# Seliwanoff's
elems.append(section_box("1.4 Seliwanoff's Test — Ketoses"))
elems.append(sp(4))
elems.append(FlowchartDrawing([
"Add 3 mL Seliwanoff's reagent (resorcinol + conc. HCl) to test tube",
"Add 3 drops of test solution",
"Heat in boiling water bath for 2 minutes — NOTE TIME",
"Cherry-red within 2 min = KETOSE (fructose) POSITIVE",
"Faint/delayed red (>5 min) = ALDOSE (glucose) — very slow reaction",
], title="SELIWANOFF'S TEST PROCEDURE", colors_list=[PURPLE,PURPLE,ORANGE,GREEN,TEAL]))
elems.append(sp(4))
elems.append(P("<b>Principle:</b> Ketoses are more readily dehydrated by HCl than aldoses. "
"Fructose → 5-hydroxymethylfurfural reacts with resorcinol to give a cherry-red colour. "
"Aldoses give a faint pink after prolonged heating.", "body"))
elems.append(sp(8))
# Osazone
elems.append(section_box("1.5 Osazone Test — Crystal Identification"))
elems.append(sp(4))
elems.append(FlowchartDrawing([
"Add 5 mL test solution + phenylhydrazine HCl + Na acetate + glacial acetic acid",
"Heat in water bath at 70-80°C for 30 minutes",
"Cool slowly and examine crystals under microscope",
"Identify crystal shape to identify the sugar",
], title="OSAZONE TEST PROCEDURE", colors_list=[DARK_BLUE,DARK_BLUE,ORANGE,GREEN]))
elems.append(sp(4))
crystal_data = [
[Paragraph("<b>Sugar</b>", ST["table_hdr"]),
Paragraph("<b>Crystal Shape</b>", ST["table_hdr"]),
Paragraph("<b>Melting Point</b>", ST["table_hdr"]),
Paragraph("<b>Time to Form</b>", ST["table_hdr"])],
[P("Glucose", "table_cell"), P("Needle-shaped (broom-like bundles)", "table_cell"),
P("204°C", "table_cell"), P("5 min", "table_cell")],
[P("Fructose", "table_cell"), P("Same as glucose (glucosazone)", "table_cell"),
P("204°C", "table_cell"), P("2 min", "table_cell")],
[P("Maltose", "table_cell"), P("Sunflower / hedgehog crystals", "table_cell"),
P("206°C", "table_cell"), P("30-45 min", "table_cell")],
[P("Lactose", "table_cell"), P("Powder puff / cotton ball", "table_cell"),
P("200°C", "table_cell"), P("30 min", "table_cell")],
[P("Sucrose", "table_cell"), P("No crystals (non-reducing)", "table_cell"),
P("—", "table_cell"), P("Never", "table_cell")],
]
ct = Table(crystal_data, colWidths=[3*cm, 6.5*cm, 2.5*cm, 3*cm])
ct.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),TEAL),("TEXTCOLOR",(0,0),(-1,0),colors.white),
("ROWBACKGROUNDS",(0,1),(-1,-1),[colors.white,LIGHT_TEAL]),
("GRID",(0,0),(-1,-1),0.4,GREY_MED),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),5),("RIGHTPADDING",(0,0),(-1,-1),5),
]))
elems.append(ct)
elems.append(info_box("Glucose and fructose give the SAME osazone crystal (glucosazone) because both "
"form the same C1-C2 derivative. This is how Osazone distinguishes them from "
"disaccharides."))
elems.append(PageBreak())
return elems
# ── CHAPTER 2: PROTEINS ───────────────────────────────────────────────────────
def chapter_proteins():
elems = []
elems.append(chapter_banner("CHAPTER 2: QUALITATIVE TESTS FOR PROTEINS & AMINO ACIDS", TEAL,
sub="Biuret • Ninhydrin • Xanthoproteic • Millon's • Hopkins-Cole • Precipitation"))
elems.append(sp(10))
# Overview table
elems.append(section_box("2.1 Overview — Protein & Amino Acid Tests"))
elems.append(sp(6))
prot_data = [
[P("<b>Test</b>", "table_hdr"), P("<b>Reagent</b>", "table_hdr"),
P("<b>Detects</b>", "table_hdr"), P("<b>Positive Result</b>", "table_hdr")],
[P("Biuret", "table_cell"), P("NaOH + CuSO₄", "table_cell"),
P("Peptide bonds (≥2)", "table_cell"), P("Violet/purple", "table_cell")],
[P("Ninhydrin", "table_cell"), P("0.1% ninhydrin", "table_cell"),
P("α-amino acids", "table_cell"), P("Purple-blue (yellow for Pro)", "table_cell")],
[P("Xanthoproteic", "table_cell"), P("Conc. HNO₃", "table_cell"),
P("Aromatic AA (Phe, Tyr, Trp)", "table_cell"), P("Yellow → orange with NaOH", "table_cell")],
[P("Millon's", "table_cell"), P("Mercuric nitrate", "table_cell"),
P("Tyrosine", "table_cell"), P("Brick-red/rose", "table_cell")],
[P("Hopkins-Cole", "table_cell"), P("Glyoxylic acid + H₂SO₄", "table_cell"),
P("Tryptophan", "table_cell"), P("Violet ring at interface", "table_cell")],
[P("Lead sulphide", "table_cell"), P("NaOH + lead acetate", "table_cell"),
P("Cys, Cystine, Met", "table_cell"), P("Black precipitate", "table_cell")],
[P("Sakaguchi", "table_cell"), P("α-Naphthol + NaOBr", "table_cell"),
P("Arginine (guanidinium)", "table_cell"), P("Red colour", "table_cell")],
]
pt = Table(prot_data, colWidths=[3.2*cm, 4*cm, 4.5*cm, 3.3*cm], repeatRows=1)
pt.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),TEAL),("TEXTCOLOR",(0,0),(-1,0),colors.white),
("ROWBACKGROUNDS",(0,1),(-1,-1),[colors.white,LIGHT_TEAL]),
("GRID",(0,0),(-1,-1),0.4,GREY_MED),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),5),("RIGHTPADDING",(0,0),(-1,-1),5),
]))
elems.append(pt)
elems.append(sp(10))
# Biuret
elems.append(section_box("2.2 Biuret Test — General Test for Proteins"))
elems.append(sp(6))
elems.append(FlowchartDrawing([
"Add 1 mL test solution to test tube",
"Add 1 mL 10% NaOH — mix well",
"Add 2-3 drops of 1% CuSO₄ (drop by drop) — mix after each drop",
"Observe colour — DO NOT add excess CuSO₄",
"Violet/Purple = POSITIVE (≥2 peptide bonds) | Blue = only 1 bond | Pink = dipeptides",
], title="BIURET TEST PROCEDURE", colors_list=[MED_BLUE,MED_BLUE,MED_BLUE,ORANGE,GREEN]))
elems.append(sp(4))
elems.append(P("<b>Principle:</b> In alkaline medium, Cu²⁺ ions form a coordinate complex with "
"two or more adjacent peptide bonds (-CO-NH-), producing a violet/purple colour. "
"Single amino acids and dipeptides do NOT give this reaction.", "body"))
elems.append(info_box("Add CuSO₄ SPARINGLY. Excess CuSO₄ gives a blue colour that masks "
"the violet of a positive biuret reaction."))
elems.append(sp(8))
# Ninhydrin
elems.append(section_box("2.3 Ninhydrin Test — α-Amino Acids"))
elems.append(sp(6))
elems.append(FlowchartDrawing([
"Add 1 mL test solution to test tube",
"Add 1 mL 0.1% ninhydrin reagent — mix",
"Heat in boiling water bath for 2-5 minutes",
"Purple-Blue (Ruhemann's purple) = α-Amino acid POSITIVE",
"EXCEPTION: Proline/Hydroxyproline → Yellow-Orange (secondary amines)",
], title="NINHYDRIN TEST PROCEDURE", colors_list=[PURPLE,PURPLE,ORANGE,GREEN,GOLD]))
elems.append(sp(4))
elems.append(P("<b>Principle:</b> Ninhydrin reacts with α-amino groups (primary amines) to give "
"Ruhemann's purple (diketohydrindylidene-diketohydrindamine). Proline and hydroxyproline "
"give yellow (imino acids — secondary amine). Ammonia gives blue.", "body"))
elems.append(sp(8))
# Xanthoproteic
elems.append(section_box("2.4 Xanthoproteic Test — Aromatic Amino Acids"))
elems.append(sp(6))
elems.append(FlowchartDrawing([
"Add 1 mL protein solution to test tube",
"Add 0.5 mL CONCENTRATED HNO₃ (carefully!) — heat gently",
"White precipitate forms → dissolves on heating → Yellow colour",
"Cool, then add 40% NaOH drop by drop",
"Yellow → Deep Orange = POSITIVE (Phe, Tyr, Trp present)",
], title="XANTHOPROTEIC TEST PROCEDURE", colors_list=[RED,RED,ORANGE,ORANGE,GREEN]))
elems.append(sp(4))
elems.append(P("<b>Principle:</b> Concentrated HNO₃ nitrates aromatic rings of Phenylalanine, "
"Tyrosine, and Tryptophan to form yellow xanthoproteic acid. Adding NaOH converts it to "
"the orange sodium salt.", "body"))
elems.append(sp(8))
# Precipitation
elems.append(section_box("2.5 Protein Precipitation Reactions"))
elems.append(sp(6))
prec_data = [
[P("<b>Method</b>","table_hdr"), P("<b>Agent</b>","table_hdr"),
P("<b>Mechanism</b>","table_hdr"), P("<b>Reversible?</b>","table_hdr")],
[P("Heat coagulation","table_cell"), P("Heat (at pI)","table_cell"),
P("Protein denaturation at isoelectric pH","table_cell"), P("No","table_cell")],
[P("Acid precipitation","table_cell"), P("TCA, Picric acid","table_cell"),
P("Charge neutralization at pI","table_cell"), P("No","table_cell")],
[P("Salting out","table_cell"), P("(NH₄)₂SO₄","table_cell"),
P("Removes hydration shell; globulins (50%), albumin (100%)","table_cell"), P("Yes","table_cell")],
[P("Heavy metals","table_cell"), P("CuSO₄, lead acetate","table_cell"),
P("Protein-metal complex","table_cell"), P("No","table_cell")],
[P("Alkaloids","table_cell"), P("Tannic acid, picric acid","table_cell"),
P("Ionic interactions","table_cell"), P("No","table_cell")],
]
prect = Table(prec_data, colWidths=[3.5*cm, 3.5*cm, 5.5*cm, 2.5*cm], repeatRows=1)
prect.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),TEAL),("TEXTCOLOR",(0,0),(-1,0),colors.white),
("ROWBACKGROUNDS",(0,1),(-1,-1),[colors.white,LIGHT_TEAL]),
("GRID",(0,0),(-1,-1),0.4,GREY_MED),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),5),("RIGHTPADDING",(0,0),(-1,-1),5),
]))
elems.append(prect)
elems.append(PageBreak())
return elems
# ── CHAPTER 3: URINE ANALYSIS ────────────────────────────────────────────────
def chapter_urine():
elems = []
elems.append(chapter_banner("CHAPTER 3: URINE ANALYSIS", ORANGE,
sub="Physical Examination • Chemical Tests • Interpretation"))
elems.append(sp(10))
elems.append(section_box("3.1 Physical Examination of Urine"))
elems.append(sp(4))
phys_data = [
[P("<b>Parameter</b>","table_hdr"), P("<b>Normal Value</b>","table_hdr"),
P("<b>Abnormal Finding</b>","table_hdr"), P("<b>Clinical Significance</b>","table_hdr")],
[P("Volume","table_cell"), P("1000–1500 mL/day","table_cell"),
P("Oliguria <400 mL | Polyuria >3000 mL","table_cell"),
P("Dehydration | Diabetes insipidus","table_cell")],
[P("Colour","table_cell"), P("Pale yellow to amber","table_cell"),
P("Dark yellow-brown | Red","table_cell"),
P("Bilirubinuria | Haematuria","table_cell")],
[P("Appearance","table_cell"), P("Clear","table_cell"),
P("Turbid/Cloudy","table_cell"),
P("Infection, phosphaturia, chyluria","table_cell")],
[P("Specific Gravity","table_cell"), P("1.010–1.025","table_cell"),
P("Fixed 1.010 (isosthenuria)","table_cell"),
P("Renal failure","table_cell")],
[P("pH","table_cell"), P("4.6–8.0 (avg 6.0)","table_cell"),
P("Persistent alkaline (>8)","table_cell"),
P("UTI (urease-producing organisms)","table_cell")],
[P("Odour","table_cell"), P("Slightly aromatic","table_cell"),
P("Fruity/sweet | Ammoniacal","table_cell"),
P("Ketosis, DM | Stale urine, UTI","table_cell")],
]
phyt = Table(phys_data, colWidths=[2.8*cm, 3.2*cm, 4.5*cm, 4.5*cm], repeatRows=1)
phyt.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),ORANGE),("TEXTCOLOR",(0,0),(-1,0),colors.white),
("ROWBACKGROUNDS",(0,1),(-1,-1),[colors.white,LIGHT_ORANGE]),
("GRID",(0,0),(-1,-1),0.4,GREY_MED),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),4),("RIGHTPADDING",(0,0),(-1,-1),4),
]))
elems.append(phyt)
elems.append(sp(10))
# Glucose in urine
elems.append(section_box("3.2 Test for Glucose (Glycosuria)"))
elems.append(sp(6))
elems.append(FlowchartDrawing([
"Collect fresh urine sample (midstream)",
"BENEDICT'S TEST: 5 mL Benedict's + 8 drops urine → Boil 5 min",
"Brick-red precipitate = GLYCOSURIA POSITIVE",
"CONFIRM with glucose oxidase dipstick (GOD-POD method)",
"Positive if Blood glucose >180 mg/dL (renal threshold)",
], title="URINE GLUCOSE DETECTION", colors_list=[MED_BLUE,MED_BLUE,GREEN,TEAL,ORANGE]))
elems.append(info_box("Renal threshold for glucose = 180 mg/dL. Below this level, glucose is "
"fully reabsorbed by SGLT2 transporters. Glycosuria occurs in DM, "
"pregnancy, and renal glycosuria (normal blood glucose)."))
elems.append(sp(8))
# Protein in urine
elems.append(section_box("3.3 Test for Protein (Proteinuria)"))
elems.append(sp(6))
elems.append(FlowchartDrawing([
"Take 5 mL urine in a test tube",
"Acidify with 2-3 drops dilute acetic acid",
"HEAT the upper portion of tube over flame",
"White cloudiness/turbidity = POSITIVE for protein",
"Add more acetic acid: if cloudiness persists = PROTEIN, if dissolves = phosphates",
], title="HEAT & ACETIC ACID TEST FOR PROTEIN", colors_list=[MED_BLUE,MED_BLUE,ORANGE,GREEN,TEAL]))
elems.append(sp(4))
elems.append(P("<b>Sulphosalicylic Acid (SSA) Test:</b> Add 3 mL 3% SSA to 3 mL urine. "
"White precipitate = protein positive. More sensitive than heat test. "
"Detects albumin, globulins, and Bence Jones proteins.", "body"))
prot_urine_data = [
[P("<b>Degree</b>","table_hdr"), P("<b>Protein</b>","table_hdr"), P("<b>Clinical Significance</b>","table_hdr")],
[P("Trace","table_cell"), P("<150 mg/day","table_cell"), P("Normal physiological limit","table_cell")],
[P("Mild 1+","table_cell"), P("150–500 mg/day","table_cell"), P("UTI, mild nephritis","table_cell")],
[P("Moderate 2+","table_cell"), P("500–3500 mg/day","table_cell"), P("Significant renal disease","table_cell")],
[P("Heavy 3+/4+","table_cell"), P(">3.5 g/day","table_cell"), P("Nephrotic syndrome","table_cell")],
]
put = Table(prot_urine_data, colWidths=[3*cm, 4*cm, 8*cm], repeatRows=1)
put.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),ORANGE),("TEXTCOLOR",(0,0),(-1,0),colors.white),
("ROWBACKGROUNDS",(0,1),(-1,-1),[colors.white,LIGHT_ORANGE]),
("GRID",(0,0),(-1,-1),0.4,GREY_MED),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),5),("RIGHTPADDING",(0,0),(-1,-1),5),
]))
elems.append(put)
elems.append(sp(8))
# Ketones
elems.append(section_box("3.4 Test for Ketone Bodies (Ketonuria)"))
elems.append(sp(6))
elems.append(FlowchartDrawing([
"Take 5 mL fresh urine",
"ROTHERA'S TEST: Add solid ammonium sulphate (saturate) + 1-2 drops sodium nitroprusside",
"Mix, then carefully layer strong ammonia solution on top",
"PURPLE/MAGENTA ring at interface = POSITIVE",
"Gerhardt's (FeCl₃) also done: Wine-red = acetoacetate positive",
], title="ROTHERA'S TEST FOR KETONES", colors_list=[PURPLE,PURPLE,PURPLE,GREEN,TEAL]))
elems.append(sp(4))
ketone_data = [
[P("<b>Test</b>","table_hdr"), P("<b>Detects</b>","table_hdr"), P("<b>Positive Result</b>","table_hdr"), P("<b>Sensitivity</b>","table_hdr")],
[P("Rothera's","table_cell"), P("Acetoacetate + Acetone","table_cell"), P("Purple ring","table_cell"), P("High","table_cell")],
[P("Gerhardt's (FeCl₃)","table_cell"), P("Acetoacetate ONLY","table_cell"), P("Wine-red colour","table_cell"), P("Moderate","table_cell")],
[P("Dipstick","table_cell"), P("Acetoacetate","table_cell"), P("Colour change","table_cell"), P("High","table_cell")],
]
kt = Table(ketone_data, colWidths=[3.5*cm, 4.5*cm, 3.5*cm, 3.5*cm], repeatRows=1)
kt.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),PURPLE),("TEXTCOLOR",(0,0),(-1,0),colors.white),
("ROWBACKGROUNDS",(0,1),(-1,-1),[colors.white,LIGHT_PURPLE]),
("GRID",(0,0),(-1,-1),0.4,GREY_MED),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),5),("RIGHTPADDING",(0,0),(-1,-1),5),
]))
elems.append(kt)
elems.append(sp(8))
# Bilirubin + bile salts
elems.append(section_box("3.5 Tests for Bilirubin, Urobilinogen & Bile Salts"))
elems.append(sp(6))
elems.append(FlowchartDrawing([
"FOUCHET'S TEST (Bilirubin): Add BaCl₂ to urine → filter precipitate",
"Add Fouchet's reagent (FeCl₃ + trichloroacetic acid) to precipitate on filter paper",
"Green/Blue colour = BILIRUBIN POSITIVE",
"GMELIN'S TEST: Layer conc. HNO₃ under urine — colour play (yellow→violet) = positive",
"HAY'S SULPHUR TEST (Bile salts): Sprinkle sulphur powder on urine surface",
"Sulphur SINKS = bile salts present (reduced surface tension)",
], title="BILIRUBIN & BILE SALT TESTS", colors_list=[GOLD,GOLD,GREEN,TEAL,ORANGE,GREEN]))
elems.append(sp(4))
bili_data = [
[P("<b>Type</b>","table_hdr"), P("<b>Found In</b>","table_hdr"), P("<b>Test Detects</b>","table_hdr")],
[P("Conjugated bilirubin","table_cell"), P("Obstructive & hepatocellular jaundice","table_cell"),
P("Fouchet, Gmelin, dipstick (water-soluble)","table_cell")],
[P("Unconjugated bilirubin","table_cell"), P("Haemolytic jaundice","table_cell"),
P("NOT detected in urine (protein-bound, not filtered)","table_cell")],
[P("Urobilinogen","table_cell"), P("Hepatocellular & haemolytic (increased)","table_cell"),
P("Ehrlich's reagent (DMAB) → pink/red","table_cell")],
]
bt = Table(bili_data, colWidths=[4*cm, 5.5*cm, 5.5*cm], repeatRows=1)
bt.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),GOLD),("TEXTCOLOR",(0,0),(-1,0),colors.white),
("ROWBACKGROUNDS",(0,1),(-1,-1),[colors.white,LIGHT_GOLD]),
("GRID",(0,0),(-1,-1),0.4,GREY_MED),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),5),("RIGHTPADDING",(0,0),(-1,-1),5),
]))
elems.append(bt)
elems.append(PageBreak())
return elems
# ── CHAPTER 4: BLOOD BIOCHEMISTRY ─────────────────────────────────────────────
def chapter_blood():
elems = []
elems.append(chapter_banner("CHAPTER 4: BLOOD BIOCHEMISTRY — QUANTITATIVE ESTIMATIONS", GREEN,
sub="Glucose • Urea • Creatinine • Total Protein • Bilirubin • ALP"))
elems.append(sp(10))
elems.append(section_box("4.1 Blood Glucose Estimation"))
elems.append(sp(6))
elems.append(FlowchartDrawing([
"Collect 2 mL fasting venous blood (sodium fluoride anticoagulant)",
"Centrifuge → obtain plasma/serum",
"GOD-POD METHOD: Glucose + O₂ → Gluconic acid + H₂O₂ (glucose oxidase)",
"H₂O₂ + 4-aminoantipyrine + phenol → Pink complex (peroxidase)",
"Measure absorbance at 505 nm | Compare with standard",
"Calculate: Glucose (mg/dL) = (OD sample / OD standard) × standard concentration",
], title="GOD-POD METHOD FOR BLOOD GLUCOSE", colors_list=[GREEN,GREEN,TEAL,TEAL,ORANGE,ORANGE]))
elems.append(sp(4))
gluc_data = [
[P("<b>Status</b>","table_hdr"), P("<b>Fasting (mg/dL)</b>","table_hdr"),
P("<b>2-hr PP (mg/dL)</b>","table_hdr"), P("<b>Interpretation</b>","table_hdr")],
[P("Normal","table_cell"), P("70–99","table_cell"), P("<140","table_cell"), P("Normal","table_cell")],
[P("Impaired fasting","table_cell"), P("100–125","table_cell"), P("140–199","table_cell"), P("Pre-diabetes","table_cell")],
[P("Diabetes","table_cell"), P("≥126","table_cell"), P("≥200","table_cell"), P("Diabetes mellitus","table_cell")],
]
gt = Table(gluc_data, colWidths=[3.5*cm, 4*cm, 4*cm, 3.5*cm], repeatRows=1)
gt.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),GREEN),("TEXTCOLOR",(0,0),(-1,0),colors.white),
("ROWBACKGROUNDS",(0,1),(-1,-1),[colors.white,LIGHT_GREEN]),
("GRID",(0,0),(-1,-1),0.4,GREY_MED),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),5),("RIGHTPADDING",(0,0),(-1,-1),5),
]))
elems.append(gt)
elems.append(sp(8))
elems.append(section_box("4.2 Blood Urea Estimation (Berthelot Method)"))
elems.append(sp(6))
elems.append(FlowchartDrawing([
"Serum/plasma sample collected",
"UREASE METHOD: Urea + H₂O → 2NH₃ + CO₂ (urease enzyme)",
"NH₃ + Berthelot's reagent (hypochlorite + phenol) → Blue indophenol",
"Measure absorbance at 630 nm",
"Normal: Blood Urea 20–40 mg/dL | BUN 10–20 mg/dL",
], title="BLOOD UREA ESTIMATION", colors_list=[GREEN,TEAL,TEAL,ORANGE,GREEN]))
elems.append(sp(4))
elems.append(P("<b>Alternative (Diacetyl Monoxime):</b> Urea + diacetyl monoxime → yellow colour "
"in acidic conditions with heat. Measure at 520 nm.", "body"))
elems.append(info_box("Urea is elevated in: Pre-renal azotemia (dehydration, heart failure), "
"Renal failure, Post-renal obstruction. BUN:Creatinine ratio >20:1 "
"suggests pre-renal cause."))
elems.append(sp(8))
elems.append(section_box("4.3 Serum Creatinine (Jaffe's Reaction)"))
elems.append(sp(6))
elems.append(FlowchartDrawing([
"Serum sample collected (no haemolysis — falsely lowers result)",
"Add alkaline picrate reagent to sample",
"Creatinine + Picric acid + NaOH → Orange-red creatinine picrate complex",
"Measure absorbance at 520 nm | Compare to creatinine standard",
"Male: 0.6–1.2 mg/dL | Female: 0.5–1.0 mg/dL",
], title="JAFFE'S REACTION — SERUM CREATININE", colors_list=[GREEN,GREEN,TEAL,ORANGE,MED_BLUE]))
elems.append(sp(8))
elems.append(section_box("4.4 Serum Bilirubin (van den Bergh Reaction)"))
elems.append(sp(6))
elems.append(FlowchartDrawing([
"Collect serum — protect from light (bilirubin is photosensitive)",
"DIRECT (conjugated): Bilirubin + diazo reagent → purple azo pigment (no methanol)",
"INDIRECT (unconjugated): Add methanol (accelerator) first, then diazo reagent",
"Total bilirubin = Direct + Indirect reading at 540 nm",
"Normal: Total <1.0 | Direct <0.3 | Indirect <0.8 mg/dL",
], title="VAN DEN BERGH — SERUM BILIRUBIN", colors_list=[GOLD,GOLD,GOLD,ORANGE,GREEN]))
elems.append(sp(4))
jaundice_data = [
[P("<b>Type</b>","table_hdr"), P("<b>Direct</b>","table_hdr"),
P("<b>Indirect</b>","table_hdr"), P("<b>Urine Bilirubin</b>","table_hdr"), P("<b>Urine Urobilinogen</b>","table_hdr")],
[P("Haemolytic","table_cell"), P("Normal","table_cell"), P("↑↑","table_cell"),
P("Absent","table_cell"), P("↑↑↑","table_cell")],
[P("Hepatocellular","table_cell"), P("↑","table_cell"), P("↑","table_cell"),
P("Present","table_cell"), P("↑ or Normal","table_cell")],
[P("Obstructive","table_cell"), P("↑↑","table_cell"), P("Normal","table_cell"),
P("Present (dark)","table_cell"), P("Absent","table_cell")],
]
jt = Table(jaundice_data, colWidths=[3.2*cm, 2.3*cm, 2.5*cm, 3.2*cm, 3.8*cm], repeatRows=1)
jt.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),GOLD),("TEXTCOLOR",(0,0),(-1,0),colors.white),
("ROWBACKGROUNDS",(0,1),(-1,-1),[colors.white,LIGHT_GOLD]),
("GRID",(0,0),(-1,-1),0.4,GREY_MED),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),5),("RIGHTPADDING",(0,0),(-1,-1),5),
]))
elems.append(jt)
elems.append(sp(8))
elems.append(section_box("4.5 Total Protein Estimation (Biuret Method)"))
elems.append(sp(6))
elems.append(FlowchartDrawing([
"Collect 1 mL serum",
"Add 4 mL Biuret reagent (CuSO₄ + NaKTartrate + NaOH + KI)",
"Mix and incubate at room temperature for 30 minutes",
"Measure absorbance at 540 nm against protein standard (e.g., bovine serum albumin)",
"Normal: Total protein 6.0–8.0 g/dL | Albumin 3.5–5.0 | Globulin 2.0–3.5 g/dL",
], title="TOTAL PROTEIN — BIURET METHOD", colors_list=[TEAL,TEAL,TEAL,ORANGE,GREEN]))
elems.append(info_box("A/G ratio = Albumin/Globulin = 1.2–2.0 normally. Ratio is reversed in "
"cirrhosis (↓ albumin), multiple myeloma (↑ globulins), nephrotic syndrome (↓ albumin)."))
elems.append(PageBreak())
return elems
# ── CHAPTER 5: ENZYMES ────────────────────────────────────────────────────────
def chapter_enzymes():
elems = []
elems.append(chapter_banner("CHAPTER 5: ENZYME ASSAYS & KINETICS", PURPLE,
sub="ALP • ALT/AST • Amylase • LDH • Michaelis-Menten • Inhibition"))
elems.append(sp(10))
elems.append(section_box("5.1 Factors Affecting Enzyme Activity"))
elems.append(sp(6))
factor_data = [
[P("<b>Factor</b>","table_hdr"), P("<b>Optimal Value</b>","table_hdr"),
P("<b>Effect of Change</b>","table_hdr")],
[P("Temperature","table_cell"), P("37°C (body temperature)","table_cell"),
P("↑ temp → ↑ activity until denaturation occurs above ~60°C","table_cell")],
[P("pH","table_cell"), P("Enzyme-specific (pepsin=2, ALP=9–10, trypsin=8)","table_cell"),
P("Activity ↓ on either side of optimum pH","table_cell")],
[P("Substrate [S]","table_cell"), P("Saturating conc. → Vmax","table_cell"),
P("Activity ↑ with [S] until saturation (Michaelis-Menten)","table_cell")],
[P("Enzyme [E]","table_cell"), P("Proportional","table_cell"),
P("Activity directly proportional to enzyme concentration","table_cell")],
[P("Competitive inhibitor","table_cell"), P("Increases apparent Km","table_cell"),
P("↑ Km, Vmax unchanged; overcome with excess substrate","table_cell")],
[P("Non-competitive inhibitor","table_cell"), P("Decreases Vmax","table_cell"),
P("↓ Vmax, Km unchanged; NOT overcome with excess substrate","table_cell")],
]
ft = Table(factor_data, colWidths=[4*cm, 4.5*cm, 6.5*cm], repeatRows=1)
ft.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),PURPLE),("TEXTCOLOR",(0,0),(-1,0),colors.white),
("ROWBACKGROUNDS",(0,1),(-1,-1),[colors.white,LIGHT_PURPLE]),
("GRID",(0,0),(-1,-1),0.4,GREY_MED),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),5),("RIGHTPADDING",(0,0),(-1,-1),5),
]))
elems.append(ft)
elems.append(sp(8))
elems.append(section_box("5.2 Alkaline Phosphatase (ALP) Assay"))
elems.append(sp(6))
elems.append(FlowchartDrawing([
"Serum sample collected",
"Substrate: p-nitrophenyl phosphate (pNPP) in alkaline buffer (pH 10.0)",
"ALP hydrolyses pNPP → p-nitrophenol (yellow) + phosphate",
"Reaction stopped with NaOH at fixed time interval",
"Measure absorbance at 405 nm (yellow p-nitrophenol)",
"Normal: 30–120 IU/L (adults) | ↑ in obstructive jaundice, bone disease",
], title="ALP ASSAY PROCEDURE", colors_list=[PURPLE,PURPLE,TEAL,TEAL,ORANGE,GREEN]))
elems.append(sp(8))
elems.append(section_box("5.3 Lineweaver-Burk Plot (Enzyme Kinetics)"))
elems.append(sp(4))
elems.append(P("The Lineweaver-Burk (double-reciprocal) plot linearizes Michaelis-Menten "
"kinetics to determine Km and Vmax graphically.", "body"))
lbdata = [
[P("<b>Axis</b>","table_hdr"), P("<b>Representation</b>","table_hdr"), P("<b>Intercept Value</b>","table_hdr")],
[P("X-axis","table_cell"), P("1/[S]","table_cell"), P("X-intercept = −1/Km","table_cell")],
[P("Y-axis","table_cell"), P("1/V","table_cell"), P("Y-intercept = 1/Vmax","table_cell")],
[P("Slope","table_cell"), P("Km/Vmax","table_cell"), P("Slope = Km/Vmax","table_cell")],
]
lbt = Table(lbdata, colWidths=[3*cm, 5*cm, 7*cm], repeatRows=1)
lbt.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),PURPLE),("TEXTCOLOR",(0,0),(-1,0),colors.white),
("ROWBACKGROUNDS",(0,1),(-1,-1),[colors.white,LIGHT_PURPLE]),
("GRID",(0,0),(-1,-1),0.4,GREY_MED),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),5),("RIGHTPADDING",(0,0),(-1,-1),5),
]))
elems.append(lbt)
elems.append(sp(8))
elems.append(section_box("5.4 Clinically Important Enzyme Tests"))
elems.append(sp(6))
enz_data = [
[P("<b>Enzyme</b>","table_hdr"), P("<b>Normal</b>","table_hdr"), P("<b>Substrate</b>","table_hdr"), P("<b>↑ In</b>","table_hdr")],
[P("ALP","table_cell"), P("30–120 IU/L","table_cell"), P("p-nitrophenyl phosphate","table_cell"), P("Obstructive jaundice, bone disease","table_cell")],
[P("ALT (SGPT)","table_cell"), P("7–56 IU/L","table_cell"), P("Alanine + α-KG","table_cell"), P("Viral hepatitis (most specific)","table_cell")],
[P("AST (SGOT)","table_cell"), P("10–40 IU/L","table_cell"), P("Aspartate + α-KG","table_cell"), P("MI, hepatitis, muscle disease","table_cell")],
[P("Amylase","table_cell"), P("25–125 IU/L","table_cell"), P("Starch","table_cell"), P("Acute pancreatitis (↑ 3× normal)","table_cell")],
[P("Lipase","table_cell"), P("0–160 IU/L","table_cell"), P("Triglycerides","table_cell"), P("Acute pancreatitis (more specific)","table_cell")],
[P("LDH","table_cell"), P("100–190 IU/L","table_cell"), P("Lactate/Pyruvate","table_cell"), P("MI, haemolysis, malignancy","table_cell")],
[P("CK-MB","table_cell"), P("<25 IU/L","table_cell"), P("Creatine phosphate","table_cell"), P("MI (rises in 4–8 hrs)","table_cell")],
]
et = Table(enz_data, colWidths=[2.8*cm, 2.8*cm, 4*cm, 5.4*cm], repeatRows=1)
et.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),PURPLE),("TEXTCOLOR",(0,0),(-1,0),colors.white),
("ROWBACKGROUNDS",(0,1),(-1,-1),[colors.white,LIGHT_PURPLE]),
("GRID",(0,0),(-1,-1),0.4,GREY_MED),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),5),("RIGHTPADDING",(0,0),(-1,-1),5),
]))
elems.append(et)
elems.append(PageBreak())
return elems
# ── CHAPTER 6: LIPIDS ─────────────────────────────────────────────────────────
def chapter_lipids():
elems = []
elems.append(chapter_banner("CHAPTER 6: LIPID TESTS & ESTIMATIONS", RED,
sub="Sudan III • Acrolein • Cholesterol (Liebermann-Burchard) • TG • Lipid Profile"))
elems.append(sp(10))
elems.append(section_box("6.1 Qualitative Tests for Lipids"))
elems.append(sp(6))
ql_data = [
[P("<b>Test</b>","table_hdr"), P("<b>Reagent</b>","table_hdr"), P("<b>Positive Result</b>","table_hdr"), P("<b>Detects</b>","table_hdr")],
[P("Solubility","table_cell"), P("Ether, chloroform, benzene","table_cell"), P("Dissolves (soluble)","table_cell"), P("All lipids","table_cell")],
[P("Sudan III","table_cell"), P("Sudan III dye","table_cell"), P("Orange-red droplets","table_cell"), P("Fat droplets","table_cell")],
[P("Spot test","table_cell"), P("Brown paper","table_cell"), P("Translucent grease spot","table_cell"), P("Fats and oils","table_cell")],
[P("Acrolein (saponification)","table_cell"), P("KHSO₄ + heat","table_cell"), P("Pungent smell (acrolein)","table_cell"), P("Glycerol (confirms triglycerides)","table_cell")],
[P("Saponification","table_cell"), P("KOH + ethanol + heat","table_cell"), P("Soap (soapy feel/foam)","table_cell"), P("Ester linkage (fats)","table_cell")],
]
qlt = Table(ql_data, colWidths=[3.2*cm, 3.5*cm, 4*cm, 4.3*cm], repeatRows=1)
qlt.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),RED),("TEXTCOLOR",(0,0),(-1,0),colors.white),
("ROWBACKGROUNDS",(0,1),(-1,-1),[colors.white,LIGHT_RED]),
("GRID",(0,0),(-1,-1),0.4,GREY_MED),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),5),("RIGHTPADDING",(0,0),(-1,-1),5),
]))
elems.append(qlt)
elems.append(sp(10))
elems.append(section_box("6.2 Serum Cholesterol (Liebermann-Burchard Reaction)"))
elems.append(sp(6))
elems.append(FlowchartDrawing([
"Serum sample (fasting 12 hours preferred)",
"Add acetic anhydride + conc. H₂SO₄ to sample (LB reagent)",
"Cholesterol → Cholesta-3,5-diene (dehydration by H₂SO₄) → Green colour",
"Colour develops: Pink → Blue → Blue-Green → Green (final colour)",
"Measure absorbance at 620 nm",
"Normal: <200 mg/dL (desirable) | 200–239 borderline | ≥240 high",
], title="LIEBERMANN-BURCHARD REACTION — SERUM CHOLESTEROL", colors_list=[RED,RED,TEAL,TEAL,ORANGE,GREEN]))
elems.append(sp(8))
elems.append(section_box("6.3 Lipid Profile — Reference Values"))
elems.append(sp(6))
lipid_data = [
[P("<b>Lipid Parameter</b>","table_hdr"), P("<b>Desirable</b>","table_hdr"),
P("<b>Borderline</b>","table_hdr"), P("<b>High Risk</b>","table_hdr")],
[P("Total Cholesterol","table_cell"), P("<200 mg/dL","table_cell"),
P("200–239 mg/dL","table_cell"), P("≥240 mg/dL","table_cell")],
[P("LDL-Cholesterol","table_cell"), P("<100 mg/dL (optimal)","table_cell"),
P("130–159 mg/dL","table_cell"), P("≥160 mg/dL","table_cell")],
[P("HDL-Cholesterol","table_cell"), P(">60 mg/dL (protective)","table_cell"),
P("40–59 mg/dL","table_cell"), P("<40 mg/dL (risk)","table_cell")],
[P("Triglycerides","table_cell"), P("<150 mg/dL","table_cell"),
P("150–199 mg/dL","table_cell"), P("≥200 mg/dL","table_cell")],
[P("Non-HDL Cholesterol","table_cell"), P("<130 mg/dL","table_cell"),
P("130–159 mg/dL","table_cell"), P("≥160 mg/dL","table_cell")],
]
ldt = Table(lipid_data, colWidths=[4*cm, 3.5*cm, 3.5*cm, 4*cm], repeatRows=1)
ldt.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),RED),("TEXTCOLOR",(0,0),(-1,0),colors.white),
("ROWBACKGROUNDS",(0,1),(-1,-1),[colors.white,LIGHT_RED]),
("GRID",(0,0),(-1,-1),0.4,GREY_MED),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),5),("RIGHTPADDING",(0,0),(-1,-1),5),
]))
elems.append(ldt)
elems.append(PageBreak())
return elems
# ── CHAPTER 7: QUICK REFERENCE & VIVA ────────────────────────────────────────
def chapter_quick_ref():
elems = []
elems.append(chapter_banner("CHAPTER 7: QUICK REFERENCE & VIVA POINTS", DARK_BLUE,
sub="Master Table • High-Yield Viva Q&A • Lab Safety"))
elems.append(sp(10))
elems.append(section_box("7.1 Master Reagent-Result Table"))
elems.append(sp(6))
master_data = [
[P("<b>Test</b>","table_hdr"), P("<b>Reagent(s)</b>","table_hdr"),
P("<b>Positive Result</b>","table_hdr"), P("<b>Detects</b>","table_hdr")],
[P("Molisch","table_cell"), P("α-Naphthol + conc. H₂SO₄","table_cell"), P("Purple ring","table_cell"), P("All carbohydrates","table_cell")],
[P("Benedict","table_cell"), P("Cu²⁺ citrate-carbonate","table_cell"), P("Brick-red precipitate","table_cell"), P("Reducing sugars","table_cell")],
[P("Fehling","table_cell"), P("Fehling A + Fehling B","table_cell"), P("Brick-red precipitate","table_cell"), P("Reducing sugars","table_cell")],
[P("Seliwanoff","table_cell"), P("Resorcinol + HCl","table_cell"), P("Cherry-red <2 min","table_cell"), P("Ketoses (fructose)","table_cell")],
[P("Barfoed","table_cell"), P("Cu acetate + acetic acid","table_cell"), P("Red ppt <3 min","table_cell"), P("Monosaccharides","table_cell")],
[P("Iodine","table_cell"), P("Iodine-KI solution","table_cell"), P("Blue-black","table_cell"), P("Starch","table_cell")],
[P("Biuret","table_cell"), P("NaOH + CuSO₄","table_cell"), P("Violet colour","table_cell"), P("Peptide bonds ≥2","table_cell")],
[P("Ninhydrin","table_cell"), P("0.1% ninhydrin","table_cell"), P("Purple (yellow for Pro)","table_cell"), P("α-Amino acids","table_cell")],
[P("Xanthoproteic","table_cell"), P("Conc. HNO₃ → NaOH","table_cell"), P("Yellow → Orange","table_cell"), P("Aromatic AA","table_cell")],
[P("Millon's","table_cell"), P("Mercuric nitrate","table_cell"), P("Brick-red","table_cell"), P("Tyrosine","table_cell")],
[P("Hopkins-Cole","table_cell"), P("Glyoxylic acid + H₂SO₄","table_cell"), P("Violet ring","table_cell"), P("Tryptophan","table_cell")],
[P("Rothera's","table_cell"), P("Nitroprusside + NH₃","table_cell"), P("Purple ring","table_cell"), P("Ketones (urine)","table_cell")],
[P("Fouchet's","table_cell"), P("BaCl₂ + Fouchet's","table_cell"), P("Green/Blue on paper","table_cell"), P("Bilirubin (urine)","table_cell")],
[P("Hay's Sulphur","table_cell"), P("Sulphur powder","table_cell"), P("Sulphur sinks","table_cell"), P("Bile salts","table_cell")],
[P("Liebermann-Burchard","table_cell"), P("Acetic anhydride + H₂SO₄","table_cell"), P("Emerald green","table_cell"), P("Cholesterol","table_cell")],
[P("Jaffe's","table_cell"), P("Alkaline picrate","table_cell"), P("Orange-red","table_cell"), P("Creatinine","table_cell")],
[P("van den Bergh","table_cell"), P("Diazo reagent","table_cell"), P("Purple/pink","table_cell"), P("Serum bilirubin","table_cell")],
]
mt = Table(master_data, colWidths=[3*cm, 4.2*cm, 3.5*cm, 4.3*cm], repeatRows=1)
mt.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),DARK_BLUE),("TEXTCOLOR",(0,0),(-1,0),colors.white),
("ROWBACKGROUNDS",(0,1),(-1,-1),[colors.white,GREY_LIGHT]),
("GRID",(0,0),(-1,-1),0.4,GREY_MED),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),5),("RIGHTPADDING",(0,0),(-1,-1),5),
("FONTSIZE",(0,0),(-1,-1),8.5),
]))
elems.append(mt)
elems.append(sp(10))
elems.append(section_box("7.2 High-Yield Viva Questions & Answers"))
elems.append(sp(6))
viva = [
("Q: Why does sucrose not give Benedict's test positive?",
"Sucrose is a non-reducing sugar — it has no free anomeric (C1) -OH group because glucose and "
"fructose are joined at both anomeric carbons (α-1,β-2 glycosidic bond). No free aldehyde or "
"ketone group means no reduction of Cu²⁺."),
("Q: Why does proline give yellow with ninhydrin instead of purple?",
"Proline is an imino acid — it has a secondary amine (N is part of the ring), not a free primary "
"α-amino group. The product formed is yellow (proline-ninhydrin complex) rather than Ruhemann's purple."),
("Q: Glucose and fructose give the same osazone. Explain.",
"Phenylhydrazine reacts with C1 and C2 of both sugars. Both glucose (aldose) and fructose (ketose) "
"have identical configurations at C3–C6. The C1–C2 derivative (glucosazone) is identical for both, "
"so the same needle-shaped crystals form."),
("Q: What is the renal threshold for glucose?",
"180 mg/dL. Below this blood glucose concentration, all filtered glucose is reabsorbed by SGLT2 "
"(and SGLT1) transporters in the proximal tubule. Above 180 mg/dL, the transporters are saturated "
"and glucose spills into urine (glycosuria)."),
("Q: Why is Rothera's test more sensitive than Gerhardt's for ketones?",
"Rothera's test (nitroprusside method) detects both acetoacetate AND acetone in urine, with very "
"high sensitivity. Gerhardt's test (FeCl₃) detects only acetoacetate, not acetone or "
"β-hydroxybutyrate, and is less sensitive."),
("Q: Direct vs indirect bilirubin — which appears in urine in obstructive jaundice?",
"Direct (conjugated) bilirubin appears in urine in obstructive jaundice. It is water-soluble "
"(glucuronide conjugate) and passes freely through the glomerulus. Indirect (unconjugated) "
"bilirubin is protein-bound, non-polar, and is NOT filtered — so it never appears in urine."),
("Q: What does a reversed A/G ratio indicate?",
"Normally A/G ratio = 1.2–2.0 (albumin > globulin). Reversal (<1.0) indicates: "
"decreased albumin (cirrhosis, nephrotic syndrome, malnutrition) or increased globulins "
"(multiple myeloma, chronic infections, autoimmune disease)."),
("Q: Which enzyme is most specific for acute pancreatitis — amylase or lipase?",
"Lipase is more specific for acute pancreatitis. Amylase rises faster (within 2–12 hours) "
"but is also elevated in parotitis, bowel obstruction, and renal failure. Lipase is more "
"specific to the pancreas and remains elevated longer (7–14 days vs 3–7 days for amylase)."),
]
for q, a in viva:
qrow = Table([[Paragraph(q, make_style("Q", fontSize=9.5, textColor=DARK_BLUE,
fontName="Helvetica-Bold"))]],
colWidths=[PAGE_W - 4*cm])
qrow.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,-1),LIGHT_BLUE),
("LINEBEFORE",(0,0),(0,-1),3,MED_BLUE),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),3),
("LEFTPADDING",(0,0),(-1,-1),8),
]))
arow = Table([[Paragraph(a, ST["body"])]], colWidths=[PAGE_W - 4*cm])
arow.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,-1),colors.white),
("LINEBEFORE",(0,0),(0,-1),3,GREY_MED),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),8),
]))
elems.append(qrow)
elems.append(arow)
elems.append(sp(4))
elems.append(sp(8))
elems.append(section_box("7.3 Lab Safety Rules"))
elems.append(sp(6))
safety = [
"Always wear lab coat, gloves, and safety glasses when handling reagents.",
"When diluting concentrated acids: always add ACID to WATER (never water to acid).",
"Concentrated H₂SO₄ and HNO₃ are corrosive — handle under fume hood.",
"Sodium nitroprusside (used in Rothera's test) is toxic — avoid inhalation.",
"Blood and urine samples are biohazardous — dispose in yellow biohazard containers.",
"Mercury compounds (Millon's reagent) are highly toxic — avoid skin contact, dispose as chemical waste.",
"Phenylhydrazine (osazone test) is toxic and carcinogenic — minimize exposure.",
"Label all reagents clearly with name, concentration, date, and hazard symbols.",
"Know the location of the fire extinguisher, eye wash station, and first aid kit.",
"Never pipette by mouth — use mechanical pipette aids.",
]
for s in safety:
elems.append(B(s))
elems.append(sp(20))
# Final signature box
sig = Table([[Paragraph(
"<b>Best of Luck for your Biochemistry Practical Examination!</b><br/>"
"Remember: State the PRINCIPLE before the PROCEDURE in your viva. Know your "
"REAGENTS and EXPECTED RESULTS. Practice writing CHEMICAL REACTIONS where applicable.",
make_style("Sig", fontSize=10, textColor=DARK_BLUE, fontName="Helvetica",
alignment=TA_CENTER, leading=16)
)]], colWidths=[PAGE_W - 4*cm])
sig.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,-1),LIGHT_BLUE),
("BOX",(0,0),(-1,-1),2,MED_BLUE),
("TOPPADDING",(0,0),(-1,-1),14),("BOTTOMPADDING",(0,0),(-1,-1),14),
("LEFTPADDING",(0,0),(-1,-1),16),("RIGHTPADDING",(0,0),(-1,-1),16),
]))
elems.append(sig)
return elems
# ── BUILD PDF ─────────────────────────────────────────────────────────────────
def build():
doc = SimpleDocTemplate(
OUTPUT_PATH,
pagesize=A4,
leftMargin=2*cm, rightMargin=2*cm,
topMargin=1.6*cm, bottomMargin=1.4*cm,
title="Biochemistry Practical Guide — MBBS 1st Year",
author="Orris Medical Education",
subject="MBBS Biochemistry Practicals",
)
story = []
story += cover_page()
story += toc_page()
story += chapter_carbohydrates()
story += chapter_proteins()
story += chapter_urine()
story += chapter_blood()
story += chapter_enzymes()
story += chapter_lipids()
story += chapter_quick_ref()
doc.build(story, onFirstPage=on_page, onLaterPages=on_page)
print(f"PDF generated: {OUTPUT_PATH}")
if __name__ == "__main__":
build()
cd /home/daytona/workspace/biochem-practical-guide && python generate_pdf.py 2>&1
~/biochem-practical-guide/generate_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/biochem-practical-guide/generate_pdf.py'
cd /home/daytona/workspace/biochem-practical-guide && python generate_pdf.py 2>&1
~/biochem-practical-guide/generate_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/biochem-practical-guide/generate_pdf.py'
cd /home/daytona/workspace/biochem-practical-guide && python generate_pdf.py 2>&1
ls -lh /home/daytona/workspace/biochem-practical-guide/Biochemistry_Practical_Guide.pdf
Biochemistry Practical Guide
PDF Document · PDF
| Chapter | Contents |
|---|---|
| 1 - Carbohydrates | Molisch, Benedict, Fehling, Seliwanoff, Barfoed, Osazone, Iodine - each with colour-coded step-by-step flowcharts |
| 2 - Proteins & Amino Acids | Biuret, Ninhydrin, Xanthoproteic, Millon's, Hopkins-Cole, precipitation reactions - all with flowcharts |
| 3 - Urine Analysis | Physical examination table + flowcharts for glucose, protein, ketones, bilirubin, bile salts, urobilinogen |
| 4 - Blood Biochemistry | GOD-POD (glucose), urea (urease/Berthelot), creatinine (Jaffe's), bilirubin (van den Bergh), total protein - with diagnostic tables |
| 5 - Enzyme Assays | ALP assay, Michaelis-Menten kinetics, Lineweaver-Burk plot, complete enzyme reference table |
| 6 - Lipids | Qualitative tests, Liebermann-Burchard reaction, full lipid profile reference values |
| 7 - Quick Reference | Master reagent-result table, 8 high-yield viva Q&As with full answers, lab safety rules |