What should be my priority order in finishing these chapters? Um, according to TNMGR University, the repeated previous year questions.
TNMGR University MBBS pathology previous year question papers repeated topics
https://www.tnmgrmu.ac.in/index.php/library/e-questions/seco…
TNMGR university systemic pathology paper VI most repeated topics chapters 2017-2025
https://www.scribd.com/document/368114220/PATHology-question…
TNMGRMU systemic pathology paper II most repeated questions kidney glomerulonephritis lung carcinoma breast female genital
| Rank | Chapter | Your Annotation | Why |
|---|---|---|---|
| 1 | Ch. 21 - Lower Urinary Tract & Male Genital | Roman numeral II + crossed | Prostate carcinoma, BPH, Wilms' tumor - perennial essay & short note favourites |
| 2 | Ch. 22 - Female Genital Tract | Roman numeral II | Carcinoma cervix (HPV), endometrial carcinoma, PCOD - asked almost every year |
| 3 | Ch. 23 - The Breast | Roman numeral I | Your own top rank. Carcinoma breast (DCIS, invasive ductal), fibrocystic disease - single most repeated systemic pathology topic in TNMGR |
| Rank | Chapter | Your Annotation | Why |
|---|---|---|---|
| 4 | Ch. 20 - The Kidney | Roman numeral VI | Glomerulonephritis (nephrotic/nephritic), nephroblastoma, renal carcinoma - very high repeat rate |
| 5 | Ch. 17 - Gastrointestinal Tract | Roman numeral IV | Peptic ulcer, carcinoma stomach, IBD, colorectal carcinoma - large chapter, heavily tested |
| 6 | Ch. 15 - The Lung | Roman numeral V | Carcinoma lung (types), pneumoconiosis, TB pathology - consistent repeat |
| Rank | Chapter | Your Annotation | Why |
|---|---|---|---|
| 7 | Ch. 28 - CNS | Roman numeral XII + star | Meningitis, glioma, Alzheimer's - asked but less frequently than renal/GI |
| 8 | Ch. 19 - The Pancreas | Roman numeral VIII | Carcinoma pancreas, diabetes mellitus pathology |
| 9 | Ch. 18 - Liver & Gallbladder | Roman numeral VII | Hepatitis, cirrhosis, hepatocellular carcinoma |
| 10 | Ch. 24 - Endocrine System | Roman numeral IX (boxed) | Thyroid carcinoma, MEN syndromes, adrenal tumors |
| Rank | Chapter | Your Annotation | Why |
|---|---|---|---|
| 11 | Ch. 25 - The Skin | Star ★ | Melanoma, psoriasis - asked but short notes only usually |
| 12 | Ch. 26 - Bones, Joints & Soft Tissue | Star ★ | Osteosarcoma, gout - occasional short notes |
| 13 | Ch. 16 - Head & Neck | No numeral | Oral carcinoma, salivary gland - smaller weight |
| 14 | Ch. 27 - Peripheral Nerves | No numeral | Rarely a heavy scorer in TNMGR papers |
| 15 | Ch. 29 - The Eye | Roman numeral IX | Least tested in systemic pathology paper |
Can you make me a PDF with... The priority of chapters. And the repea- the most repeated essay questions and short notes that I must finish in order to say that I finished the first pass of this chapter.
TNMGRMU systemic pathology paper VI repeated essay questions kidney breast female genital lung GIT 2017-2025
mkdir -p /home/daytona/workspace/tnmgr-pathology && ls /home/daytona/workspace/
~/tnmgr-pathology/generate_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
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.platypus import PageBreak
OUTPUT = "/home/daytona/workspace/tnmgr-pathology/TNMGR_Systemic_Pathology_Priority.pdf"
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
rightMargin=1.8*cm,
leftMargin=1.8*cm,
topMargin=2*cm,
bottomMargin=2*cm
)
# ── Colour palette ──────────────────────────────────────────────────────────
MAROON = colors.HexColor("#7B1C1C")
DARK_RED = colors.HexColor("#A52A2A")
LIGHT_RED = colors.HexColor("#FDECEA")
AMBER = colors.HexColor("#E65100")
AMBER_LIGHT = colors.HexColor("#FFF3E0")
GREEN_DARK = colors.HexColor("#1B5E20")
GREEN_LIGHT = colors.HexColor("#E8F5E9")
BLUE_DARK = colors.HexColor("#0D47A1")
BLUE_LIGHT = colors.HexColor("#E3F2FD")
GRAY_DARK = colors.HexColor("#37474F")
GRAY_LIGHT = colors.HexColor("#ECEFF1")
WHITE = colors.white
BLACK = colors.black
styles = getSampleStyleSheet()
# Custom paragraph styles
title_style = ParagraphStyle(
"MainTitle", parent=styles["Title"],
fontSize=20, textColor=WHITE, alignment=TA_CENTER,
spaceAfter=4, fontName="Helvetica-Bold"
)
subtitle_style = ParagraphStyle(
"SubTitle", parent=styles["Normal"],
fontSize=11, textColor=colors.HexColor("#FFCDD2"),
alignment=TA_CENTER, spaceAfter=2, fontName="Helvetica"
)
section_style = ParagraphStyle(
"SectionHead", parent=styles["Normal"],
fontSize=13, textColor=WHITE, alignment=TA_LEFT,
fontName="Helvetica-Bold", leftIndent=4
)
chapter_title = ParagraphStyle(
"ChapterTitle", parent=styles["Normal"],
fontSize=10.5, textColor=GRAY_DARK,
fontName="Helvetica-Bold", spaceAfter=1
)
body_style = ParagraphStyle(
"Body", parent=styles["Normal"],
fontSize=9, textColor=GRAY_DARK,
fontName="Helvetica", leading=13, spaceAfter=1
)
bullet_style = ParagraphStyle(
"Bullet", parent=styles["Normal"],
fontSize=9, textColor=GRAY_DARK,
fontName="Helvetica", leading=13,
leftIndent=10, bulletIndent=0, spaceAfter=1
)
tag_essay = ParagraphStyle(
"TagEssay", parent=styles["Normal"],
fontSize=7.5, textColor=DARK_RED,
fontName="Helvetica-Bold", alignment=TA_CENTER
)
tag_sn = ParagraphStyle(
"TagSN", parent=styles["Normal"],
fontSize=7.5, textColor=BLUE_DARK,
fontName="Helvetica-Bold", alignment=TA_CENTER
)
small_gray = ParagraphStyle(
"SmallGray", parent=styles["Normal"],
fontSize=8, textColor=colors.HexColor("#78909C"),
fontName="Helvetica-Oblique", alignment=TA_CENTER
)
# ── Chapter data ─────────────────────────────────────────────────────────────
# tier: 1=highest, 2=high, 3=medium, 4=lower
chapters = [
# ── TIER 1 ──────────────────────────────────────────────────────────────
{
"tier": 1,
"num": "Ch. 23",
"title": "The Breast",
"robbins_pages": "1037",
"essays": [
"Carcinoma of the breast - classify, describe morphology, spread and prognosis",
"Fibrocystic changes of the breast - types, morphology and clinical significance",
"Invasive ductal carcinoma - pathogenesis, morphology, molecular subtypes (ER/PR/HER2)",
],
"short_notes": [
"Ductal carcinoma in situ (DCIS)",
"Paget's disease of nipple",
"Phyllodes tumour",
"Fibroadenoma",
"Inflammatory carcinoma of breast",
"Triple negative breast cancer",
"Gynecomastia",
],
},
{
"tier": 1,
"num": "Ch. 22",
"title": "The Female Genital Tract",
"robbins_pages": "985",
"essays": [
"Carcinoma cervix - etiology (HPV), pathogenesis, morphology, FIGO staging, spread",
"Endometrial carcinoma - types, morphology, clinical features",
"Gestational trophoblastic disease - hydatidiform mole, invasive mole, choriocarcinoma",
],
"short_notes": [
"CIN (Cervical Intraepithelial Neoplasia) - grades and significance",
"Polycystic ovarian syndrome (PCOS)",
"Ovarian tumours - classification with examples",
"Endometriosis",
"Leiomyoma (fibroid) of uterus",
"Teratoma of ovary",
"Krukenberg tumour",
],
},
{
"tier": 1,
"num": "Ch. 21",
"title": "Lower Urinary Tract & Male Genital System",
"robbins_pages": "953",
"essays": [
"Carcinoma prostate - etiology, morphology, Gleason grading, spread and prognosis",
"Benign prostatic hyperplasia (BPH) - pathogenesis, morphology, clinical features",
"Testicular tumours - classification, morphology (seminoma vs non-seminoma)",
],
"short_notes": [
"Cryptorchidism and its significance",
"Transitional cell carcinoma of urinary bladder",
"Wilms tumour (nephroblastoma)",
"PSA (Prostate Specific Antigen) in diagnosis",
"Hydrocele vs varicocele",
"Squamous cell carcinoma of penis",
],
},
# ── TIER 2 ──────────────────────────────────────────────────────────────
{
"tier": 2,
"num": "Ch. 20",
"title": "The Kidney",
"robbins_pages": "895",
"essays": [
"Glomerulonephritis - nephrotic syndrome: causes, pathogenesis, lab findings",
"Glomerulonephritis - nephritic syndrome: types, morphology (APSGN, IgA nephropathy)",
"Renal cell carcinoma - types, morphology, clinical features, paraneoplastic syndromes",
],
"short_notes": [
"Minimal change disease",
"Membranous nephropathy",
"Focal segmental glomerulosclerosis (FSGS)",
"Acute tubular necrosis (ATN)",
"Diabetic nephropathy",
"Lupus nephritis",
"Renal papillary necrosis",
"Horseshoe kidney",
],
},
{
"tier": 2,
"num": "Ch. 17",
"title": "The Gastrointestinal Tract",
"robbins_pages": "753",
"essays": [
"Carcinoma stomach - types (Lauren), morphology, spread, prognosis",
"Inflammatory bowel disease - UC vs Crohn's disease (compare morphology & complications)",
"Colorectal carcinoma - pathogenesis (APC pathway), morphology, Duke's staging",
],
"short_notes": [
"Peptic ulcer disease - pathogenesis, H. pylori role, complications",
"Hirschsprung's disease",
"GERD and Barrett's oesophagus",
"Appendicitis - morphological stages",
"Carcinoid tumour of GIT",
"Meckel's diverticulum",
"Coeliac disease (sprue)",
"Familial adenomatous polyposis (FAP)",
],
},
{
"tier": 2,
"num": "Ch. 15",
"title": "The Lung",
"robbins_pages": "673",
"essays": [
"Bronchogenic carcinoma - classify (SCLC vs NSCLC), morphology, spread, paraneoplastic syndromes",
"Pneumoconioses - coal workers, silicosis, asbestosis: pathogenesis and morphology",
"Lobar pneumonia - stages of consolidation, complications",
],
"short_notes": [
"Adult Respiratory Distress Syndrome (ARDS)",
"Pulmonary embolism - morphology and consequences",
"Mesothelioma",
"Sarcoidosis",
"Pulmonary tuberculosis - primary vs secondary",
"Lung abscess",
"Emphysema - types",
"Asthma - pathology",
],
},
# ── TIER 3 ──────────────────────────────────────────────────────────────
{
"tier": 3,
"num": "Ch. 28",
"title": "The Central Nervous System",
"robbins_pages": "1241",
"essays": [
"Meningitis - bacterial vs viral: CSF findings, morphology",
"Gliomas - astrocytoma, glioblastoma multiforme: grading and morphology",
"Cerebrovascular disease - infarcts, intracerebral haemorrhage: morphology",
],
"short_notes": [
"Glioblastoma multiforme (WHO grade IV)",
"Meningioma",
"Medulloblastoma",
"Alzheimer's disease - morphology (plaques & tangles)",
"Hydrocephalus",
"Subarachnoid haemorrhage - berry aneurysm",
"Wernicke's encephalopathy",
],
},
{
"tier": 3,
"num": "Ch. 19",
"title": "The Pancreas",
"robbins_pages": "881",
"essays": [
"Carcinoma pancreas - morphology, clinical features, CA 19-9, prognosis",
"Acute pancreatitis - pathogenesis, fat necrosis, morphology",
],
"short_notes": [
"Chronic pancreatitis",
"Insulinoma",
"Zollinger-Ellison syndrome",
"Cystic fibrosis and the pancreas",
"Diabetes mellitus - pancreatic pathology (Type 1 vs Type 2)",
],
},
{
"tier": 3,
"num": "Ch. 18",
"title": "Liver & Gallbladder",
"robbins_pages": "823",
"essays": [
"Hepatocellular carcinoma - etiology, morphology, alpha-fetoprotein, prognosis",
"Cirrhosis of liver - causes, morphology (macro & micro), complications",
],
"short_notes": [
"Viral hepatitis - types and morphological changes",
"Alcoholic liver disease - stages",
"Wilson's disease",
"Haemochromatosis",
"Primary biliary cirrhosis",
"Cholelithiasis - types of gallstones",
"Carcinoma gallbladder",
"Portal hypertension",
],
},
{
"tier": 3,
"num": "Ch. 24",
"title": "The Endocrine System",
"robbins_pages": "1065",
"essays": [
"Thyroid carcinoma - classify (papillary, follicular, medullary, anaplastic): morphology",
"Diabetes mellitus - pathogenesis, Type 1 vs Type 2, complications (micro/macro)",
],
"short_notes": [
"Hashimoto's thyroiditis",
"Graves' disease",
"Pheochromocytoma",
"Adrenocortical carcinoma",
"Multiple Endocrine Neoplasia (MEN) syndromes",
"Addison's disease",
"Cushing's syndrome - pathology",
],
},
# ── TIER 4 ──────────────────────────────────────────────────────────────
{
"tier": 4,
"num": "Ch. 25",
"title": "The Skin",
"robbins_pages": "1133",
"essays": [
"Malignant melanoma - pathogenesis (ABCDE), Clark's levels, Breslow thickness",
],
"short_notes": [
"Basal cell carcinoma vs squamous cell carcinoma of skin",
"Psoriasis - morphology",
"Pemphigus vulgaris",
"Dermatitis herpetiformis",
"Seborrhoeic keratosis",
],
},
{
"tier": 4,
"num": "Ch. 26",
"title": "Bones, Joints & Soft Tissue Tumours",
"robbins_pages": "1171",
"essays": [
"Osteosarcoma - pathogenesis, morphology, radiological features, prognosis",
],
"short_notes": [
"Gout - pathogenesis, morphology (tophi)",
"Rheumatoid arthritis - joint pathology",
"Ewing's sarcoma",
"Giant cell tumour (osteoclastoma)",
"Paget's disease of bone",
"Osteoporosis",
],
},
{
"tier": 4,
"num": "Ch. 16",
"title": "Head & Neck",
"robbins_pages": "731",
"essays": [
"Carcinoma larynx - sites, morphology, staging",
],
"short_notes": [
"Pleomorphic adenoma (mixed parotid tumour)",
"Oral squamous cell carcinoma - risk factors",
"Warthin's tumour",
"Nasopharyngeal carcinoma - EBV link",
"Thyroglossal cyst",
],
},
{
"tier": 4,
"num": "Ch. 27",
"title": "Peripheral Nerves & Skeletal Muscles",
"robbins_pages": "1217",
"essays": [
"Duchenne muscular dystrophy - pathogenesis, morphology",
],
"short_notes": [
"Myasthenia gravis - pathology",
"Guillain-Barre syndrome",
"Peripheral neuropathy - causes",
"Schwannoma vs neurofibroma",
],
},
{
"tier": 4,
"num": "Ch. 29",
"title": "The Eye",
"robbins_pages": "1305",
"essays": [
"Retinoblastoma - genetics, morphology",
],
"short_notes": [
"Diabetic retinopathy",
"Glaucoma - types",
"Cataract",
],
},
]
TIER_LABELS = {
1: "TIER 1 | HIGHEST PRIORITY",
2: "TIER 2 | HIGH PRIORITY",
3: "TIER 3 | MEDIUM PRIORITY",
4: "TIER 4 | LOWER PRIORITY (finish last)",
}
TIER_COLORS = {
1: MAROON,
2: DARK_RED,
3: colors.HexColor("#1565C0"),
4: GRAY_DARK,
}
TIER_BG = {
1: LIGHT_RED,
2: AMBER_LIGHT,
3: BLUE_LIGHT,
4: GRAY_LIGHT,
}
# ── Build story ───────────────────────────────────────────────────────────────
story = []
# ── Cover banner ─────────────────────────────────────────────────────────────
banner_data = [[
Paragraph("TNMGR UNIVERSITY", title_style),
]]
banner_table = Table(banner_data, colWidths=[doc.width])
banner_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), MAROON),
("TOPPADDING", (0, 0), (-1, -1), 14),
("BOTTOMPADDING", (0, 0), (-1, -1), 6),
("LEFTPADDING", (0, 0), (-1, -1), 10),
("RIGHTPADDING", (0, 0), (-1, -1), 10),
("ROUNDEDCORNERS", [6]),
]))
story.append(banner_table)
sub_data = [[
Paragraph("Systemic Pathology | Robbins Vol. II | First-Pass Study Guide", subtitle_style),
]]
sub_table = Table(sub_data, colWidths=[doc.width])
sub_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), colors.HexColor("#C62828")),
("TOPPADDING", (0, 0), (-1, -1), 6),
("BOTTOMPADDING", (0, 0), (-1, -1), 8),
("LEFTPADDING", (0, 0), (-1, -1), 10),
("RIGHTPADDING", (0, 0), (-1, -1), 10),
]))
story.append(sub_table)
story.append(Spacer(1, 0.3*cm))
note_p = Paragraph(
"<i>Priority based on TNMGR previous year papers 2003–2025 (Paper VI – Systemic Pathology). "
"Essay = Long Essay / 10-mark question. Short Note = 5-mark / short answer question.</i>",
small_gray
)
story.append(note_p)
story.append(Spacer(1, 0.5*cm))
# ── Priority summary table ────────────────────────────────────────────────────
summary_header = [
Paragraph("<b>Rank</b>", ParagraphStyle("th", parent=styles["Normal"], fontSize=9,
textColor=WHITE, fontName="Helvetica-Bold", alignment=TA_CENTER)),
Paragraph("<b>Chapter</b>", ParagraphStyle("th", parent=styles["Normal"], fontSize=9,
textColor=WHITE, fontName="Helvetica-Bold", alignment=TA_CENTER)),
Paragraph("<b>Priority</b>", ParagraphStyle("th", parent=styles["Normal"], fontSize=9,
textColor=WHITE, fontName="Helvetica-Bold", alignment=TA_CENTER)),
Paragraph("<b>Why</b>", ParagraphStyle("th", parent=styles["Normal"], fontSize=9,
textColor=WHITE, fontName="Helvetica-Bold", alignment=TA_CENTER)),
]
summary_rows = [summary_header]
rank_data = [
(1, "Ch. 23 – The Breast", "★★★★★", "Most repeated essay/SN in TNMGR. Carcinoma breast asked every 1-2 years."),
(2, "Ch. 22 – Female Genital Tract", "★★★★★", "Ca cervix (HPV), endometrial Ca, mole are annual fixtures."),
(3, "Ch. 21 – Lower Urinary Tract & Male Genital", "★★★★★", "BPH, Ca prostate, testicular tumours – highly repeated."),
(4, "Ch. 20 – The Kidney", "★★★★☆", "Nephrotic/nephritic, RCC – very high yield."),
(5, "Ch. 17 – GIT", "★★★★☆", "Ca stomach, IBD, CRC – large chapter, heavy question weight."),
(6, "Ch. 15 – The Lung", "★★★★☆", "Bronchogenic Ca, pneumoconiosis, pneumonia – consistent repeat."),
(7, "Ch. 28 – CNS", "★★★☆☆", "Meningitis, glioma, CVA – asked but less frequent."),
(8, "Ch. 19 – The Pancreas", "★★★☆☆", "Ca pancreas, acute pancreatitis."),
(9, "Ch. 18 – Liver & Gallbladder", "★★★☆☆", "HCC, cirrhosis, viral hepatitis."),
(10, "Ch. 24 – Endocrine System", "★★★☆☆", "Thyroid Ca, DM pathology."),
(11, "Ch. 25 – Skin", "★★☆☆☆", "Melanoma, BCC/SCC – mostly short notes."),
(12, "Ch. 26 – Bones, Joints & Soft Tissue", "★★☆☆☆", "Osteosarcoma, gout – occasional short notes."),
(13, "Ch. 16 – Head & Neck", "★★☆☆☆", "Pleomorphic adenoma, oral Ca."),
(14, "Ch. 27 – Peripheral Nerves & Muscles", "★☆☆☆☆", "Rarely heavy in TNMGR papers."),
(15, "Ch. 29 – The Eye", "★☆☆☆☆", "Retinoblastoma, diabetic retinopathy."),
]
rank_colors = {
range(1, 4): (LIGHT_RED, MAROON),
range(4, 7): (AMBER_LIGHT, AMBER),
range(7, 11): (BLUE_LIGHT, BLUE_DARK),
range(11, 16): (GRAY_LIGHT, GRAY_DARK),
}
def get_rank_color(r):
if r <= 3: return (LIGHT_RED, MAROON)
if r <= 6: return (AMBER_LIGHT, AMBER)
if r <= 10: return (BLUE_LIGHT, BLUE_DARK)
return (GRAY_LIGHT, GRAY_DARK)
for rank, chap, stars, reason in rank_data:
bg, fg = get_rank_color(rank)
row = [
Paragraph(f"<b>{rank}</b>", ParagraphStyle("rc", parent=styles["Normal"],
fontSize=9, textColor=fg, fontName="Helvetica-Bold", alignment=TA_CENTER)),
Paragraph(chap, ParagraphStyle("rc2", parent=styles["Normal"],
fontSize=8.5, textColor=GRAY_DARK, fontName="Helvetica-Bold")),
Paragraph(stars, ParagraphStyle("rc3", parent=styles["Normal"],
fontSize=9, textColor=fg, fontName="Helvetica-Bold", alignment=TA_CENTER)),
Paragraph(reason, ParagraphStyle("rc4", parent=styles["Normal"],
fontSize=8, textColor=GRAY_DARK, fontName="Helvetica")),
]
summary_rows.append(row)
col_widths = [1.0*cm, 5.5*cm, 2.2*cm, doc.width - 8.7*cm]
sum_table = Table(summary_rows, colWidths=col_widths, repeatRows=1)
ts = TableStyle([
("BACKGROUND", (0, 0), (-1, 0), MAROON),
("GRID", (0, 0), (-1, -1), 0.4, colors.HexColor("#BDBDBD")),
("ROWBACKGROUNDS",(0, 1), (-1, -1), [WHITE, colors.HexColor("#FAFAFA")]),
("TOPPADDING", (0, 0), (-1, -1), 4),
("BOTTOMPADDING", (0, 0), (-1, -1), 4),
("LEFTPADDING", (0, 0), (-1, -1), 5),
("RIGHTPADDING", (0, 0), (-1, -1), 5),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
])
# Row background tints
for rank, _, _, _ in rank_data:
row_idx = rank # 1-indexed, header is 0
bg, _ = get_rank_color(rank)
ts.add("BACKGROUND", (0, row_idx), (0, row_idx), bg)
ts.add("BACKGROUND", (2, row_idx), (2, row_idx), bg)
sum_table.setStyle(ts)
story.append(sum_table)
story.append(Spacer(1, 0.4*cm))
story.append(HRFlowable(width="100%", thickness=1.5, color=MAROON))
story.append(Spacer(1, 0.3*cm))
# ── Per-chapter detailed pages ────────────────────────────────────────────────
current_tier = None
for ch in chapters:
tier = ch["tier"]
# Tier header when tier changes
if tier != current_tier:
current_tier = tier
tier_col = TIER_COLORS[tier]
tier_label = TIER_LABELS[tier]
tier_hdr = Table(
[[Paragraph(tier_label, section_style)]],
colWidths=[doc.width]
)
tier_hdr.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), tier_col),
("TOPPADDING", (0, 0), (-1, -1), 7),
("BOTTOMPADDING", (0, 0), (-1, -1), 7),
("LEFTPADDING", (0, 0), (-1, -1), 10),
("RIGHTPADDING", (0, 0), (-1, -1), 10),
]))
story.append(tier_hdr)
story.append(Spacer(1, 0.2*cm))
bg = TIER_BG[tier]
fg = TIER_COLORS[tier]
# Chapter card
card_elements = []
# Chapter header row
ch_hdr = Table(
[[
Paragraph(f"<b>{ch['num']}</b>",
ParagraphStyle("chn", parent=styles["Normal"],
fontSize=9, textColor=WHITE,
fontName="Helvetica-Bold", alignment=TA_CENTER)),
Paragraph(f"<b>{ch['title']}</b> "
f"<font size='8' color='#FFCDD2'>(Robbins p. {ch['robbins_pages']})</font>",
ParagraphStyle("cht", parent=styles["Normal"],
fontSize=11, textColor=WHITE,
fontName="Helvetica-Bold")),
]],
colWidths=[1.5*cm, doc.width - 1.5*cm]
)
ch_hdr.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), fg),
("TOPPADDING", (0, 0), (-1, -1), 6),
("BOTTOMPADDING", (0, 0), (-1, -1), 6),
("LEFTPADDING", (0, 0), (-1, -1), 8),
("RIGHTPADDING", (0, 0), (-1, -1), 8),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
]))
card_elements.append(ch_hdr)
# Essays and short notes in two-column layout
essay_items = []
essay_items.append(
Paragraph("ESSAYS (Long questions – 10 marks)",
ParagraphStyle("eht", parent=styles["Normal"],
fontSize=8.5, textColor=DARK_RED,
fontName="Helvetica-Bold", spaceAfter=3))
)
for i, q in enumerate(ch["essays"], 1):
essay_items.append(
Paragraph(f"{i}. {q}", bullet_style)
)
sn_items = []
sn_items.append(
Paragraph("SHORT NOTES (5-mark / short answer)",
ParagraphStyle("sht", parent=styles["Normal"],
fontSize=8.5, textColor=BLUE_DARK,
fontName="Helvetica-Bold", spaceAfter=3))
)
for i, sn in enumerate(ch["short_notes"], 1):
sn_items.append(
Paragraph(f"{i}. {sn}", bullet_style)
)
from reportlab.platypus import ListFlowable, ListItem
body_table = Table(
[[essay_items, sn_items]],
colWidths=[doc.width * 0.5 - 0.2*cm, doc.width * 0.5 - 0.2*cm]
)
body_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), bg),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("TOPPADDING", (0, 0), (-1, -1), 8),
("BOTTOMPADDING", (0, 0), (-1, -1), 8),
("LEFTPADDING", (0, 0), (-1, -1), 8),
("RIGHTPADDING", (0, 0), (-1, -1), 8),
("LINEAFTER", (0, 0), (0, 0), 0.5, colors.HexColor("#BDBDBD")),
]))
card_elements.append(body_table)
card = KeepTogether(card_elements)
story.append(card)
story.append(Spacer(1, 0.35*cm))
# ── Footer note ───────────────────────────────────────────────────────────────
story.append(HRFlowable(width="100%", thickness=1, color=MAROON))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"Generated for TNMGR University MBBS 2nd Year Pathology Paper VI (Systemic Pathology) | "
"Reference: Robbins & Cotran Pathologic Basis of Disease, 10th Ed. | July 2026",
small_gray
))
# ── Build PDF ─────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF saved to: {OUTPUT}")
cd /home/daytona/workspace/tnmgr-pathology && python generate_pdf.py 2>&1
ls -lh /home/daytona/workspace/tnmgr-pathology/TNMGR_Systemic_Pathology_Priority…
TNMGR Systemic Pathology Priority
PDF Document · PDF
If I have, hmm, around... Eight hours plus additional six or seven hours. And maybe a day off, like three hours? Then how many days? Well, like, minimum, will I take to finish the entire system pathology? Like, if I'm just going for a first pass? In the quickest and the minimum time, how many days will it take?
| Chapter | Content Load | Est. Time |
|---|---|---|
| Ch. 23 – Breast | Moderate | 1.5 hrs |
| Ch. 22 – Female Genital | Heavy | 2.5 hrs |
| Ch. 21 – Lower Urinary + Male Genital | Heavy | 2.5 hrs |
| Ch. 20 – Kidney | Very Heavy | 3 hrs |
| Ch. 17 – GIT | Very Heavy | 3.5 hrs |
| Ch. 15 – Lung | Heavy | 2.5 hrs |
| Ch. 28 – CNS | Heavy | 2.5 hrs |
| Ch. 19 – Pancreas | Light-Moderate | 1.5 hrs |
| Ch. 18 – Liver & Gallbladder | Heavy | 2.5 hrs |
| Ch. 24 – Endocrine | Moderate | 2 hrs |
| Ch. 25 – Skin | Light | 1 hr |
| Ch. 26 – Bones & Joints | Light-Moderate | 1.5 hrs |
| Ch. 16 – Head & Neck | Light | 1 hr |
| Ch. 27 – Peripheral Nerves | Light | 45 min |
| Ch. 29 – The Eye | Very Light | 45 min |
| TOTAL | ~29 hours |
Generate a time-tracking template to monitor if I'm on pace
~/tnmgr-pathology/generate_tracker.py
import openpyxl
from openpyxl.styles import (
Font, PatternFill, Alignment, Border, Side, numbers
)
from openpyxl.utils import get_column_letter
from openpyxl.formatting.rule import ColorScaleRule, DataBarRule, FormulaRule
from openpyxl.chart import BarChart, Reference
from openpyxl.worksheet.datavalidation import DataValidation
import datetime
OUTPUT = "/home/daytona/workspace/tnmgr-pathology/Systemic_Pathology_Tracker.xlsx"
wb = openpyxl.Workbook()
# ── Colour helpers ────────────────────────────────────────────────────────────
def fill(hex_):
return PatternFill("solid", fgColor=hex_.lstrip("#"))
def font(bold=False, color="000000", size=11, italic=False, name="Arial"):
return Font(bold=bold, color=color, size=size, italic=italic, name=name)
def border(style="thin"):
s = Side(style=style)
return Border(left=s, right=s, top=s, bottom=s)
def center():
return Alignment(horizontal="center", vertical="center", wrap_text=True)
def left():
return Alignment(horizontal="left", vertical="center", wrap_text=True)
MAROON = "7B1C1C"
RED_LIGHT = "FDECEA"
AMBER = "E65100"
AMB_LIGHT = "FFF3E0"
BLUE_D = "0D47A1"
BLUE_L = "E3F2FD"
GRAY_D = "37474F"
GRAY_L = "ECEFF1"
GREEN_D = "1B5E20"
GREEN_L = "E8F5E9"
WHITE = "FFFFFF"
YELLOW = "FFFF00"
# ─────────────────────────────────────────────────────────────────────────────
# SHEET 1 — TRACKER
# ─────────────────────────────────────────────────────────────────────────────
ws = wb.active
ws.title = "Tracker"
ws.sheet_view.showGridLines = False
ws.freeze_panes = "A5"
# Row heights & col widths
ws.row_dimensions[1].height = 36
ws.row_dimensions[2].height = 18
ws.row_dimensions[3].height = 14
ws.row_dimensions[4].height = 30
col_widths = {
"A": 5, # Rank
"B": 10, # Chapter
"C": 28, # Chapter name
"D": 9, # Tier
"E": 11, # Allotted (hrs)
"F": 11, # Start time
"G": 11, # End time
"H": 12, # Actual (hrs)
"I": 12, # Variance (hrs)
"J": 12, # Status
"K": 14, # Date
"L": 28, # Notes / Weak topics
}
for col, w in col_widths.items():
ws.column_dimensions[col].width = w
# ── Title row ─────────────────────────────────────────────────────────────────
ws.merge_cells("A1:L1")
t = ws["A1"]
t.value = "TNMGR UNIVERSITY | Systemic Pathology | First-Pass Time Tracker"
t.font = font(bold=True, color=WHITE, size=15)
t.fill = fill(MAROON)
t.alignment = center()
t.border = border()
ws.merge_cells("A2:L2")
s = ws["A2"]
s.value = "Day 1 = Ch.23→17 | Day 2 = Ch.15→24 | Day 3 (off) = Ch.25→29 | Total planned: ~29 hrs"
s.font = font(italic=True, color="FFCDD2", size=9)
s.fill = fill("C62828")
s.alignment = center()
ws.merge_cells("A3:L3")
ws["A3"].value = ""
ws["A3"].fill = fill(WHITE)
# ── Column headers ────────────────────────────────────────────────────────────
headers = ["#", "Chapter", "Title", "Tier", "Target\n(hrs)", "Start\nTime",
"End\nTime", "Actual\n(hrs)", "Variance\n(hrs)", "Status",
"Date", "Weak Topics / Notes"]
header_cols = list("ABCDEFGHIJKL")
for col, hdr in zip(header_cols, headers):
c = ws[f"{col}4"]
c.value = hdr
c.font = font(bold=True, color=WHITE, size=9)
c.fill = fill(MAROON)
c.alignment = center()
c.border = border()
# ── Chapter data ──────────────────────────────────────────────────────────────
chapters = [
# rank, ch_num, title, tier, allot_hrs, day
(1, "Ch. 23", "The Breast", 1, 1.5, 1),
(2, "Ch. 22", "Female Genital Tract", 1, 2.5, 1),
(3, "Ch. 21", "Lower Urinary Tract & Male Genital", 1, 2.5, 1),
(4, "Ch. 20", "The Kidney", 2, 3.0, 1),
(5, "Ch. 17", "Gastrointestinal Tract", 2, 3.5, 1),
(6, "Ch. 15", "The Lung", 2, 2.5, 2),
(7, "Ch. 28", "Central Nervous System", 3, 2.5, 2),
(8, "Ch. 19", "The Pancreas", 3, 1.5, 2),
(9, "Ch. 18", "Liver & Gallbladder", 3, 2.5, 2),
(10, "Ch. 24", "Endocrine System", 3, 2.0, 2),
(11, "Ch. 25", "The Skin", 4, 1.0, 3),
(12, "Ch. 26", "Bones, Joints & Soft Tissue", 4, 1.5, 3),
(13, "Ch. 16", "Head & Neck", 4, 1.0, 3),
(14, "Ch. 27", "Peripheral Nerves & Skeletal Muscles", 4, 0.75, 3),
(15, "Ch. 29", "The Eye", 4, 0.75, 3),
]
TIER_FILL = {1: RED_LIGHT, 2: AMB_LIGHT, 3: BLUE_L, 4: GRAY_L}
TIER_FONT_COLOR = {1: MAROON, 2: AMBER, 3: BLUE_D, 4: GRAY_D}
TIER_LABEL = {1: "T1 ★★★★★", 2: "T2 ★★★★☆", 3: "T3 ★★★☆☆", 4: "T4 ★★☆☆☆"}
DAY_FILL = {"1": "FFE0E0", "2": "E0F0FF", "3": "E0FFE8"}
status_dv = DataValidation(
type="list",
formula1='"Not Started,In Progress,Done,Skipped"',
allow_blank=True,
showDropDown=False
)
ws.add_data_validation(status_dv)
# Day separator rows
current_day = None
row = 5
day_start_rows = {}
for rank, ch_num, title, tier, allot, day in chapters:
# Insert day header when day changes
if day != current_day:
current_day = day
day_start_rows[day] = row
day_labels = {1: "DAY 1 (14 hrs target)", 2: "DAY 2 (14 hrs target)", 3: "DAY 3 (3 hrs target — off day)"}
day_colors = {1: "B71C1C", 2: "1565C0", 3: "2E7D32"}
ws.merge_cells(f"A{row}:L{row}")
dc = ws[f"A{row}"]
dc.value = day_labels[day]
dc.font = font(bold=True, color=WHITE, size=10)
dc.fill = fill(day_colors[day])
dc.alignment = left()
dc.border = border()
ws.row_dimensions[row].height = 20
row += 1
tf = TIER_FILL[tier]
tc = TIER_FONT_COLOR[tier]
row_data = {
"A": rank,
"B": ch_num,
"C": title,
"D": TIER_LABEL[tier],
"E": allot,
"F": "", # start time - user fills
"G": "", # end time - user fills
# H = actual hrs formula (if F and G filled)
"I": None, # variance formula
"J": "Not Started",
"K": "", # date - user fills
"L": "", # notes
}
for col, val in row_data.items():
c = ws[f"{col}{row}"]
c.value = val
c.fill = fill(tf)
c.alignment = center() if col not in ("C", "L") else left()
c.border = border()
if col in ("A", "B", "D"):
c.font = font(bold=True, color=tc, size=9)
elif col == "E":
c.font = font(bold=True, color="000000", size=9)
c.number_format = "0.00"
elif col in ("F", "G"):
c.font = font(color="0000FF", size=9) # blue = user input
c.number_format = "HH:MM"
c.fill = fill("EBF5FB")
elif col == "J":
c.font = font(color=GRAY_D, size=9)
c.fill = fill("FFF9C4") # yellow = needs updating
status_dv.add(c)
elif col == "K":
c.font = font(color="0000FF", size=9) # blue = user input
c.number_format = "DD-MMM"
c.fill = fill("EBF5FB")
elif col == "L":
c.font = font(color=GRAY_D, size=9, italic=True)
c.fill = fill("FFFDE7")
else:
c.font = font(color="000000", size=9)
# H = actual hours formula (end - start) * 24
h_cell = ws[f"H{row}"]
h_cell.value = f'=IF(AND(F{row}<>"",G{row}<>""),IF(G{row}>F{row},(G{row}-F{row})*24,(G{row}+1-F{row})*24),"")'
h_cell.font = font(color="000000", size=9)
h_cell.fill = fill(tf)
h_cell.alignment = center()
h_cell.border = border()
h_cell.number_format = "0.00"
# I = variance (actual - target), colour coded via conditional formatting later
i_cell = ws[f"I{row}"]
i_cell.value = f'=IF(H{row}<>"",H{row}-E{row},"")'
i_cell.font = font(color="000000", size=9)
i_cell.fill = fill(tf)
i_cell.alignment = center()
i_cell.border = border()
i_cell.number_format = '+0.00;-0.00;"-"'
ws.row_dimensions[row].height = 22
row += 1
# ── Totals row ────────────────────────────────────────────────────────────────
ws.merge_cells(f"A{row}:D{row}")
tot = ws[f"A{row}"]
tot.value = "TOTALS"
tot.font = font(bold=True, color=WHITE, size=10)
tot.fill = fill(MAROON)
tot.alignment = center()
tot.border = border()
for col, formula in [
("E", f"=SUM(E5:E{row-1})"),
("H", f'=IFERROR(SUM(H5:H{row-1}),"")'),
("I", f'=IFERROR(SUM(I5:I{row-1}),"")'),
]:
c = ws[f"{col}{row}"]
c.value = formula
c.font = font(bold=True, color=WHITE, size=10)
c.fill = fill(MAROON)
c.alignment = center()
c.border = border()
c.number_format = "0.00"
for col in ["F", "G", "J", "K", "L"]:
c = ws[f"{col}{row}"]
c.fill = fill(MAROON)
c.border = border()
ws.row_dimensions[row].height = 22
# ── Conditional formatting: variance ─────────────────────────────────────────
# Green if on time (<=0), red if over (+ve)
green_rule = FormulaRule(
formula=[f'AND(I5<>"",I5<=0)'],
fill=fill("C8E6C9"), font=font(color=GREEN_D, bold=True)
)
red_rule = FormulaRule(
formula=[f'AND(I5<>"",I5>0.5)'],
fill=fill("FFCDD2"), font=font(color="B71C1C", bold=True)
)
amber_rule = FormulaRule(
formula=[f'AND(I5<>"",I5>0,I5<=0.5)'],
fill=fill("FFE0B2"), font=font(color=AMBER, bold=True)
)
ws.conditional_formatting.add(f"I5:I{row}", green_rule)
ws.conditional_formatting.add(f"I5:I{row}", red_rule)
ws.conditional_formatting.add(f"I5:I{row}", amber_rule)
# Status colour coding
done_rule = FormulaRule(formula=[f'J5="Done"'], fill=fill("C8E6C9"), font=font(color=GREEN_D, bold=True))
inprog_rule = FormulaRule(formula=[f'J5="In Progress"'], fill=fill("FFF9C4"), font=font(color=AMBER, bold=True))
skip_rule = FormulaRule(formula=[f'J5="Skipped"'], fill=fill("F5F5F5"), font=font(color="9E9E9E", italic=True))
ws.conditional_formatting.add(f"J5:J{row}", done_rule)
ws.conditional_formatting.add(f"J5:J{row}", inprog_rule)
ws.conditional_formatting.add(f"J5:J{row}", skip_rule)
# ─────────────────────────────────────────────────────────────────────────────
# SHEET 2 — PACE DASHBOARD
# ─────────────────────────────────────────────────────────────────────────────
dash = wb.create_sheet("Dashboard")
dash.sheet_view.showGridLines = False
dash.column_dimensions["A"].width = 2
dash.column_dimensions["B"].width = 26
dash.column_dimensions["C"].width = 16
dash.column_dimensions["D"].width = 16
dash.column_dimensions["E"].width = 16
dash.column_dimensions["F"].width = 16
# Title
dash.merge_cells("B1:F1")
dt = dash["B1"]
dt.value = "PACE DASHBOARD"
dt.font = font(bold=True, color=WHITE, size=14)
dt.fill = fill(MAROON)
dt.alignment = center()
dt.border = border()
dash.row_dimensions[1].height = 30
dash.merge_cells("B2:F2")
dash["B2"].value = "Summary — pull from Tracker sheet"
dash["B2"].font = font(italic=True, color="9E9E9E", size=9)
dash["B2"].fill = fill("F5F5F5")
dash["B2"].alignment = center()
dash.row_dimensions[2].height = 14
# KPI boxes
kpi_labels = [
("Total Chapters", f"=COUNTIF(Tracker!J:J,\"Done\")+COUNTIF(Tracker!J:J,\"In Progress\")+COUNTIF(Tracker!J:J,\"Not Started\")"),
("Chapters Done", f"=COUNTIF(Tracker!J:J,\"Done\")"),
("Total Hours Planned", f"=Tracker!E{row}"),
("Hours Spent So Far", f"=IFERROR(Tracker!H{row},0)"),
("Hours Remaining", f"=IFERROR(Tracker!E{row}-Tracker!H{row},Tracker!E{row})"),
("Overall Variance (hrs)",f"=IFERROR(Tracker!I{row},0)"),
]
kpi_colors = [GRAY_D, GREEN_D, BLUE_D, MAROON, AMBER, "6A1B9A"]
kpi_bg = [GRAY_L, GREEN_L, BLUE_L, RED_LIGHT, AMB_LIGHT, "F3E5F5"]
r = 4
for (label, formula), fc, bg in zip(kpi_labels, kpi_colors, kpi_bg):
dash.merge_cells(f"B{r}:C{r}")
lc = dash[f"B{r}"]
lc.value = label
lc.font = font(bold=True, color=WHITE, size=9)
lc.fill = fill(fc)
lc.alignment = left()
lc.border = border()
dash.row_dimensions[r].height = 24
dash.merge_cells(f"D{r}:F{r}")
vc = dash[f"D{r}"]
vc.value = formula
vc.font = font(bold=True, color=fc, size=14)
vc.fill = fill(bg)
vc.alignment = center()
vc.border = border()
r += 1
r += 1
# Day-wise breakdown table
day_hdr_row = r
dash.merge_cells(f"B{day_hdr_row}:F{day_hdr_row}")
dhdr = dash[f"B{day_hdr_row}"]
dhdr.value = "DAY-WISE PROGRESS"
dhdr.font = font(bold=True, color=WHITE, size=10)
dhdr.fill = fill(MAROON)
dhdr.alignment = center()
dhdr.border = border()
dash.row_dimensions[day_hdr_row].height = 22
r += 1
col_hdrs = ["Day", "Target Hrs", "Spent Hrs", "Variance", "Chapters Done"]
col_letters = ["B", "C", "D", "E", "F"]
for col, hdr in zip(col_letters, col_hdrs):
c = dash[f"{col}{r}"]
c.value = hdr
c.font = font(bold=True, color=WHITE, size=9)
c.fill = fill(GRAY_D)
c.alignment = center()
c.border = border()
dash.row_dimensions[r].height = 18
r += 1
# Day rows with formulas pulling from tracker
# Day 1 chapters: rows 6-10 in tracker (after day header row 5), Day 2: rows 13-17, Day 3: rows 20-22
# Since we know the exact rows we can hardcode ranges
# Let's compute from day_start_rows
# Re-derive data rows per day
data_rows_by_day = {1: [], 2: [], 3: []}
check_row = 5
check_day = None
for rank, ch_num, title, tier, allot, day in chapters:
if day != check_day:
check_day = day
check_row += 1 # skip day header
data_rows_by_day[day].append(check_row)
check_row += 1
day_targets = {1: 14, 2: 14, 3: 3}
day_colors = {1: "B71C1C", 2: "1565C0", 3: "2E7D32"}
day_bg = {1: RED_LIGHT, 2: BLUE_L, 3: GREEN_L}
for d in [1, 2, 3]:
rows_d = data_rows_by_day[d]
h_range = ",".join([f"Tracker!H{rr}" for rr in rows_d])
e_range = ",".join([f"Tracker!E{rr}" for rr in rows_d])
j_range = ",".join([f"Tracker!J{rr}" for rr in rows_d])
# spent hrs sum
spent_f = f"=IFERROR(SUM({h_range}),0)"
target_f = f"=SUM({e_range})"
var_f = f"=IFERROR(SUM({h_range})-SUM({e_range}),0-SUM({e_range}))"
done_f = f'=SUMPRODUCT(({"+".join([f"(Tracker!J{rr}" + chr(61) + chr(34) + "Done" + chr(34) + ")" for rr in rows_d])}))'
day_row_vals = [f"Day {d}", target_f, spent_f, var_f, done_f]
for col, val in zip(col_letters, day_row_vals):
c = dash[f"{col}{r}"]
c.value = val
c.font = font(bold=(col == "B"), color=day_colors[d], size=10)
c.fill = fill(day_bg[d])
c.alignment = center()
c.border = border()
c.number_format = "0.00" if col in ("C", "D", "E") else "General"
dash.row_dimensions[r].height = 22
r += 1
r += 1
# ── Legend ────────────────────────────────────────────────────────────────────
dash.merge_cells(f"B{r}:F{r}")
leg = dash[f"B{r}"]
leg.value = "LEGEND"
leg.font = font(bold=True, color=WHITE, size=9)
leg.fill = fill(GRAY_D)
leg.alignment = center()
leg.border = border()
dash.row_dimensions[r].height = 18
r += 1
legend_items = [
("Variance ≤ 0 (Green)", "On pace or ahead — great!", "C8E6C9", GREEN_D),
("Variance 0–0.5 (Amber)", "Slightly behind — push a bit", "FFE0B2", AMBER),
("Variance > 0.5 (Red)", "Behind — re-allocate or compress", "FFCDD2", "B71C1C"),
("Blue cells", "User-input cells (time / date)", "EBF5FB", BLUE_D),
("Yellow cells", "Status dropdown — update as you go","FFF9C4", "F57F17"),
]
for label, desc, bg, fc in legend_items:
c1 = dash[f"B{r}"]
c1.value = label
c1.font = font(bold=True, color=fc, size=9)
c1.fill = fill(bg)
c1.alignment = left()
c1.border = border()
dash.merge_cells(f"C{r}:F{r}")
c2 = dash[f"C{r}"]
c2.value = desc
c2.font = font(color=GRAY_D, size=9)
c2.fill = fill("FAFAFA")
c2.alignment = left()
c2.border = border()
dash.row_dimensions[r].height = 18
r += 1
# ─────────────────────────────────────────────────────────────────────────────
# SHEET 3 — INSTRUCTIONS
# ─────────────────────────────────────────────────────────────────────────────
ins = wb.create_sheet("How To Use")
ins.sheet_view.showGridLines = False
ins.column_dimensions["A"].width = 3
ins.column_dimensions["B"].width = 60
ins.merge_cells("A1:B1")
ins["A1"].value = "HOW TO USE THIS TRACKER"
ins["A1"].font = font(bold=True, color=WHITE, size=13)
ins["A1"].fill = fill(MAROON)
ins["A1"].alignment = center()
ins["A1"].border = border()
ins.row_dimensions[1].height = 28
steps = [
("TRACKER Sheet", None),
("1. Start Time", "When you begin a chapter, type the time in column F (e.g. 09:30)"),
("2. End Time", "When you finish, type the time in column G (e.g. 11:00). Actual hrs auto-calculates."),
("3. Status", "Click the yellow Status cell → choose from dropdown: Not Started / In Progress / Done / Skipped"),
("4. Date", "Type today's date in column K (e.g. 14-Jul)"),
("5. Notes", "Jot weak topics in column L so you know what to revisit in second pass"),
("6. Variance", "Negative = ahead of plan (green). Positive = behind (amber/red). Keep watching this!"),
("", ""),
("DASHBOARD Sheet", None),
("•", "Opens automatically to show total hours spent vs planned, and day-wise breakdown."),
("•", "Check variance daily — if Day 1 variance is +2 hrs you are 2 hrs behind."),
("", ""),
("TIPS", None),
("•", "Start with Tier 1 chapters (Breast, Female Genital, Male Genital) — highest exam yield."),
("•", "If a chapter runs over time, cut short notes for Tier 4 chapters (Eye, Nerves) first."),
("•", "First pass = concepts + essay outlines only. Do NOT re-read. Move on."),
]
r2 = 3
for label, desc in steps:
ins.row_dimensions[r2].height = 18
if desc is None:
ins.merge_cells(f"A{r2}:B{r2}")
c = ins[f"A{r2}"]
c.value = label
c.font = font(bold=True, color=WHITE, size=10)
c.fill = fill(GRAY_D)
c.alignment = left()
c.border = border()
elif label == "":
ins.row_dimensions[r2].height = 8
else:
c1 = ins[f"A{r2}"]
c1.value = label
c1.font = font(bold=True, color=MAROON, size=9)
c1.fill = fill(RED_LIGHT)
c1.alignment = center()
c1.border = border()
c2 = ins[f"B{r2}"]
c2.value = desc
c2.font = font(color=GRAY_D, size=9)
c2.fill = fill(WHITE)
c2.alignment = left()
c2.border = border()
r2 += 1
# ── Tab colours ───────────────────────────────────────────────────────────────
ws.sheet_properties.tabColor = "7B1C1C"
dash.sheet_properties.tabColor = "0D47A1"
ins.sheet_properties.tabColor = "1B5E20"
# ── Set active sheet to Tracker ───────────────────────────────────────────────
wb.active = ws
wb.save(OUTPUT)
print(f"Saved: {OUTPUT}")
cd /home/daytona/workspace/tnmgr-pathology && python generate_tracker.py 2>&1
~/tnmgr-pathology/generate_tracker.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/tnmgr-pathology/generate_tracker.py'
cd /home/daytona/workspace/tnmgr-pathology && python generate_tracker.py 2>&1
python3 -c " import openpyxl wb = openpyxl.Workbook() ws = wb.active ws['A1'] = …
# Try saving to /tmp first, then copy python3 -c " import openpyxl wb = openpyxl…
~/tnmgr-pathology/generate_tracker.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/tnmgr-pathology/generate_tracker.py'
~/tnmgr-pathology/generate_tracker.py
Error: String not found in file: 'wb.save(OUTPUT)
print(f"PDF saved to: {OUTPUT}")'~/tnmgr-pathology/generate_tracker.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/tnmgr-pathology/generate_tracker.py'
cd /home/daytona/workspace/tnmgr-pathology && python generate_tracker.py 2>&1
~/tnmgr-pathology/generate_tracker.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/tnmgr-pathology/generate_tracker.py'
cd /home/daytona/workspace/tnmgr-pathology && python generate_tracker.py 2>&1
# Use copyfileobj instead to avoid permission metadata issues python3 -c " impor…
~/tnmgr-pathology/generate_tracker.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/tnmgr-pathology/generate_tracker.py'
cd /home/daytona/workspace/tnmgr-pathology && python generate_tracker.py 2>&1
Systemic Pathology Tracker
Spreadsheet · XLSX