Do you know about the inicet and pg neet exam
INICET INI-CET exam 2026 latest updates schedule
NEET PG 2026 exam date schedule NBE updates
INI-CET NEET PG 2026 India medical entrance exam
| Feature | INI-CET | NEET-PG |
|---|---|---|
| Conducting body | AIIMS Delhi | NBEMS |
| Institutes covered | AIIMS, JIPMER, NIMHANS, PGIMER | All medical colleges |
| Frequency | Twice/year | Once/year |
| Difficulty | Higher (conceptual) | Slightly moderate |
| Seats | ~600-700 (prestigious) | 50,000+ |
| Result use | Only INI institutions | All other colleges |
Generate a study guide for INI-CET/NEET-PG prep
INI-CET NEET PG subject wise weightage high yield topics books 2026
https://reflexprep.com/blog/inicet-syllabus-high-yield-topic…
mkdir -p /home/daytona/workspace/inicet-studyguide && ls /home/daytona/workspace…
~/inicet-studyguide/generate_guide.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm, mm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import BalancedColumns
from reportlab.lib.colors import HexColor
# ── Palette ──────────────────────────────────────────────────────────────────
DARK_BLUE = HexColor("#1A237E")
MID_BLUE = HexColor("#283593")
ACCENT_BLUE = HexColor("#3F51B5")
LIGHT_BLUE = HexColor("#E8EAF6")
TEAL = HexColor("#00695C")
TEAL_LIGHT = HexColor("#E0F2F1")
AMBER = HexColor("#E65100")
AMBER_LIGHT = HexColor("#FFF3E0")
GREEN = HexColor("#2E7D32")
GREEN_LIGHT = HexColor("#E8F5E9")
RED = HexColor("#B71C1C")
RED_LIGHT = HexColor("#FFEBEE")
GREY_DARK = HexColor("#37474F")
GREY_MED = HexColor("#78909C")
GREY_LIGHT = HexColor("#ECEFF1")
WHITE = colors.white
OUTPUT = "/home/daytona/workspace/inicet-studyguide/INICET_NEET_PG_Study_Guide.pdf"
# ── Document ──────────────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
leftMargin=2*cm, rightMargin=2*cm,
topMargin=2.2*cm, bottomMargin=2.2*cm,
title="INI-CET / NEET-PG Study Guide 2026",
author="Orris AI",
)
W, H = A4
CONTENT_W = W - 4*cm
styles = getSampleStyleSheet()
# ── Custom Styles ─────────────────────────────────────────────────────────────
def S(name, **kw):
return ParagraphStyle(name, **kw)
sNormal = S("sNormal", fontName="Helvetica", fontSize=9, leading=14, textColor=GREY_DARK)
sBody = S("sBody", fontName="Helvetica", fontSize=9.5,leading=15, textColor=GREY_DARK, spaceAfter=4)
sBullet = S("sBullet", fontName="Helvetica", fontSize=9, leading=13, textColor=GREY_DARK,
leftIndent=12, firstLineIndent=-10, spaceAfter=2)
sSubBullet = S("sSubBullet", fontName="Helvetica", fontSize=8.5,leading=12, textColor=GREY_MED,
leftIndent=24, firstLineIndent=-10, spaceAfter=1)
sH1 = S("sH1", fontName="Helvetica-Bold", fontSize=22, leading=28, textColor=WHITE, alignment=TA_CENTER)
sH1s = S("sH1s", fontName="Helvetica-Bold", fontSize=12, leading=16, textColor=WHITE, alignment=TA_CENTER)
sH2 = S("sH2", fontName="Helvetica-Bold", fontSize=13, leading=18, textColor=WHITE, spaceAfter=2)
sH3 = S("sH3", fontName="Helvetica-Bold", fontSize=10.5,leading=14,textColor=DARK_BLUE, spaceBefore=8, spaceAfter=3)
sH4 = S("sH4", fontName="Helvetica-Bold", fontSize=9.5, leading=13,textColor=TEAL, spaceBefore=5, spaceAfter=2)
sTip = S("sTip", fontName="Helvetica-Oblique",fontSize=8.5,leading=13,textColor=AMBER, leftIndent=6)
sTag = S("sTag", fontName="Helvetica-Bold", fontSize=7.5, leading=10, textColor=WHITE, alignment=TA_CENTER)
# ── Helpers ───────────────────────────────────────────────────────────────────
def sp(h=6):
return Spacer(1, h)
def hr(color=GREY_LIGHT, thickness=0.5):
return HRFlowable(width="100%", thickness=thickness, color=color, spaceAfter=4, spaceBefore=4)
def section_header(title, subtitle="", bg=DARK_BLUE):
data = [[Paragraph(title, sH2)]]
if subtitle:
data[0].append(Paragraph(subtitle, S("sh_sub", fontName="Helvetica", fontSize=8.5,
leading=12, textColor=HexColor("#C5CAE9"))))
cell_content = [Paragraph(title, sH2)]
if subtitle:
cell_content.append(Paragraph(subtitle, S("sh_sub2", fontName="Helvetica",
fontSize=8.5, leading=12, textColor=HexColor("#C5CAE9"))))
t = Table([[cell_content]], colWidths=[CONTENT_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING",(0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 12),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("ROUNDEDCORNERS",(0,0),(-1,-1), [4,4,4,4]),
]))
return t
def tag_box(label, bg=ACCENT_BLUE):
t = Table([[Paragraph(label, sTag)]], colWidths=[2.8*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), bg),
("TOPPADDING", (0,0),(-1,-1), 3),
("BOTTOMPADDING",(0,0),(-1,-1), 3),
("LEFTPADDING", (0,0),(-1,-1), 5),
("RIGHTPADDING", (0,0),(-1,-1), 5),
]))
return t
def info_box(title, lines, bg=LIGHT_BLUE, title_color=DARK_BLUE):
title_s = S("ib_title", fontName="Helvetica-Bold", fontSize=9, leading=12,
textColor=title_color)
body_s = S("ib_body", fontName="Helvetica", fontSize=8.5, leading=12,
textColor=GREY_DARK)
content = [Paragraph(title, title_s), sp(3)]
for l in lines:
content.append(Paragraph(l, body_s))
t = Table([[content]], colWidths=[CONTENT_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), bg),
("TOPPADDING", (0,0),(-1,-1), 8),
("BOTTOMPADDING",(0,0),(-1,-1), 8),
("LEFTPADDING", (0,0),(-1,-1), 10),
("RIGHTPADDING", (0,0),(-1,-1), 10),
("BOX", (0,0),(-1,-1), 0.5, GREY_MED),
]))
return t
def two_col_table(rows, col_headers, col_widths=None):
if col_widths is None:
col_widths = [CONTENT_W*0.35, CONTENT_W*0.65]
hdr_s = S("th", fontName="Helvetica-Bold", fontSize=9, leading=12, textColor=WHITE)
cell_s= S("td", fontName="Helvetica", fontSize=8.5, leading=12, textColor=GREY_DARK)
data = [[Paragraph(h, hdr_s) for h in col_headers]]
for r in rows:
data.append([Paragraph(str(c), cell_s) for c in r])
t = Table(data, colWidths=col_widths, repeatRows=1)
style = [
("BACKGROUND", (0,0),(-1, 0), DARK_BLUE),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 8),
("RIGHTPADDING", (0,0),(-1,-1), 8),
("GRID", (0,0),(-1,-1), 0.4, GREY_LIGHT),
("VALIGN", (0,0),(-1,-1), "TOP"),
]
for i in range(1, len(data)):
bg = GREY_LIGHT if i % 2 == 0 else WHITE
style.append(("BACKGROUND", (0,i),(-1,i), bg))
t.setStyle(TableStyle(style))
return t
def subject_table(rows):
"""Subject / weightage / books / strategy table — 4 cols."""
hdr_s = S("th4", fontName="Helvetica-Bold", fontSize=8.5, leading=11, textColor=WHITE)
cell_s= S("td4", fontName="Helvetica", fontSize=8, leading=11, textColor=GREY_DARK)
hdrs = ["Subject", "Weightage", "Best Book(s)", "Strategy"]
cw = [CONTENT_W*0.18, CONTENT_W*0.12, CONTENT_W*0.32, CONTENT_W*0.38]
data = [[Paragraph(h, hdr_s) for h in hdrs]]
for r in rows:
data.append([Paragraph(str(c), cell_s) for c in r])
t = Table(data, colWidths=cw, repeatRows=1)
style = [
("BACKGROUND", (0,0),(-1, 0), DARK_BLUE),
("TOPPADDING", (0,0),(-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 6),
("RIGHTPADDING", (0,0),(-1,-1), 6),
("GRID", (0,0),(-1,-1), 0.4, GREY_LIGHT),
("VALIGN", (0,0),(-1,-1), "TOP"),
]
for i in range(1, len(data)):
bg = LIGHT_BLUE if i % 2 == 0 else WHITE
style.append(("BACKGROUND", (0,i),(-1,i), bg))
t.setStyle(TableStyle(style))
return t
def week_block(wk_label, tasks, bg=LIGHT_BLUE):
label_s = S("wl", fontName="Helvetica-Bold", fontSize=9, leading=12, textColor=DARK_BLUE)
task_s = S("wt", fontName="Helvetica", fontSize=8.5, leading=13, textColor=GREY_DARK)
cell = [Paragraph(wk_label, label_s), sp(2)]
for t in tasks:
cell.append(Paragraph(f"• {t}", task_s))
tb = Table([[cell]], colWidths=[CONTENT_W/2 - 0.3*cm])
tb.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), bg),
("TOPPADDING", (0,0),(-1,-1), 7),
("BOTTOMPADDING",(0,0),(-1,-1), 7),
("LEFTPADDING", (0,0),(-1,-1), 9),
("RIGHTPADDING", (0,0),(-1,-1), 9),
("BOX", (0,0),(-1,-1), 0.5, GREY_MED),
]))
return tb
# ─────────────────────────────────────────────────────────────────────────────
# BUILD STORY
# ─────────────────────────────────────────────────────────────────────────────
story = []
# ══════════════════════════════════════════════════════════
# COVER PAGE
# ══════════════════════════════════════════════════════════
# Full-width cover banner
cover_data = [[
Paragraph("INI-CET / NEET-PG", sH1),
Paragraph("Complete Study Guide for First-Attempt Candidates", sH1s),
Paragraph("Subject Weightage • High-Yield Topics • Recommended Books • 12-Month Schedule • Exam Strategy",
S("cov_sub2", fontName="Helvetica", fontSize=9, leading=14, textColor=HexColor("#9FA8DA"), alignment=TA_CENTER)),
sp(4),
Paragraph("Edition: July 2026", S("cov_ed", fontName="Helvetica-Oblique", fontSize=8.5,
leading=12, textColor=HexColor("#7986CB"), alignment=TA_CENTER)),
]]
cov = Table([[[
sp(20),
Paragraph("INI-CET / NEET-PG", sH1),
sp(8),
Paragraph("Complete Study Guide for First-Attempt Candidates",
S("cs1", fontName="Helvetica-Bold", fontSize=14, leading=20, textColor=WHITE, alignment=TA_CENTER)),
sp(6),
Paragraph("Subject Weightage • High-Yield Topics • Recommended Books • 12-Month Schedule • Exam Strategy",
S("cs2", fontName="Helvetica", fontSize=9.5, leading=14, textColor=HexColor("#9FA8DA"), alignment=TA_CENTER)),
sp(12),
Paragraph("Edition: July 2026",
S("cs3", fontName="Helvetica-Oblique", fontSize=9, leading=12, textColor=HexColor("#7986CB"), alignment=TA_CENTER)),
sp(20),
]]], colWidths=[CONTENT_W])
cov.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), DARK_BLUE),
("TOPPADDING", (0,0),(-1,-1), 0),
("BOTTOMPADDING",(0,0),(-1,-1), 0),
("LEFTPADDING", (0,0),(-1,-1), 30),
("RIGHTPADDING", (0,0),(-1,-1), 30),
]))
story.append(cov)
story.append(sp(20))
# Quick stats bar
stats = [
("200 MCQs", "per exam"),
("19 Subjects", "tested"),
("12 Months", "study plan"),
("Top 3%", "target rank"),
]
stat_s_big = S("stb", fontName="Helvetica-Bold", fontSize=16, leading=20, textColor=DARK_BLUE, alignment=TA_CENTER)
stat_s_sm = S("sts", fontName="Helvetica", fontSize=8, leading=11, textColor=GREY_MED, alignment=TA_CENTER)
stat_cells = [[Paragraph(v, stat_s_big), Paragraph(l, stat_s_sm)] for v,l in stats]
stat_row = [[Table([[c]], colWidths=[CONTENT_W/4]) for c in stat_cells]]
stat_t = Table(stat_row, colWidths=[CONTENT_W/4]*4)
stat_t.setStyle(TableStyle([
("TOPPADDING", (0,0),(-1,-1), 10),
("BOTTOMPADDING",(0,0),(-1,-1), 10),
("BOX", (0,0),(-1,-1), 0.8, ACCENT_BLUE),
("LINEAFTER", (0,0),(2,-1), 0.5, GREY_LIGHT),
("BACKGROUND", (0,0),(-1,-1), LIGHT_BLUE),
]))
story.append(stat_t)
story.append(PageBreak())
# ══════════════════════════════════════════════════════════
# SECTION 1 – EXAM OVERVIEW
# ══════════════════════════════════════════════════════════
story.append(section_header("SECTION 1", "Exam Overview & Key Differences", bg=DARK_BLUE))
story.append(sp(10))
overview_rows = [
("Conducting Body", "AIIMS, New Delhi", "NBEMS (NBE)"),
("Seats Covered", "AIIMS, JIPMER, NIMHANS, PGIMER (~700 seats)", "All medical colleges (50,000+ seats)"),
("Frequency", "Twice a year (May & November)", "Once a year"),
("Duration", "3 hours (180 min)", "3.5 hours (210 min)"),
("Questions", "200 MCQs", "200 MCQs"),
("Marking", "+1 correct / -0.33 wrong", "+4 correct / -1 wrong"),
("Time per Question", "~54 seconds", "~63 seconds"),
("Difficulty", "Higher – scenario/image-based, protocol-heavy", "Moderate – mix of recall & clinical"),
("Counselling", "Centralized via AIIMS", "MCC for Govt; private colleges separate"),
("Eligibility", "MBBS with 55% aggregate (50% SC/ST/OBC)", "MBBS + 1-year internship completion"),
]
hdr3_s = S("h3w", fontName="Helvetica-Bold", fontSize=9, leading=12, textColor=WHITE)
cell3_s= S("c3", fontName="Helvetica", fontSize=8.5, leading=12, textColor=GREY_DARK)
cw3 = [CONTENT_W*0.25, CONTENT_W*0.375, CONTENT_W*0.375]
tdata = [[Paragraph(h, hdr3_s) for h in ["Feature","INI-CET","NEET-PG"]]]
for r in overview_rows:
tdata.append([Paragraph(c, cell3_s) for c in r])
ov_t = Table(tdata, colWidths=cw3, repeatRows=1)
ov_style = [
("BACKGROUND", (0,0),(-1, 0), DARK_BLUE),
("TOPPADDING", (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 7), ("RIGHTPADDING", (0,0),(-1,-1), 7),
("GRID", (0,0),(-1,-1), 0.4, GREY_LIGHT),
("VALIGN", (0,0),(-1,-1), "TOP"),
("BACKGROUND", (1,1),(1,-1), LIGHT_BLUE),
]
for i in range(1, len(tdata)):
if i % 2 == 0:
ov_style.append(("BACKGROUND", (0,i),(0,i), GREY_LIGHT))
ov_style.append(("BACKGROUND", (2,i),(2,i), TEAL_LIGHT))
else:
ov_style.append(("BACKGROUND", (0,i),(0,i), WHITE))
ov_style.append(("BACKGROUND", (2,i),(2,i), WHITE))
ov_t.setStyle(TableStyle(ov_style))
story.append(ov_t)
story.append(sp(12))
story.append(info_box(
"Key Insight for First-Attempt Candidates",
[
"Prepare for BOTH exams simultaneously — the syllabus overlaps ~90%.",
"INI-CET rewards clinical reasoning speed; NEET-PG rewards breadth of recall.",
"Start your prep at least 12 months before your target exam date.",
"Attempt INI-CET (November) + NEET-PG in the same year to maximize seat options.",
],
bg=AMBER_LIGHT, title_color=AMBER
))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════
# SECTION 2 – SUBJECT WEIGHTAGE
# ══════════════════════════════════════════════════════════
story.append(section_header("SECTION 2", "Subject-Wise Weightage & Priority", bg=MID_BLUE))
story.append(sp(10))
story.append(Paragraph("Subject Distribution (based on 5-year trend analysis)", sH3))
story.append(sp(4))
subj_rows = [
("Medicine", "18-22% (~40 Qs)", "Harrison's / Davidson's / Mathew's", "Protocol-heavy; memorize current guidelines; ECG, CXR interpretation"),
("Surgery", "15-18% (~33 Qs)", "Bailey & Love / SRB's Surgery", "Focus on surgical emergencies, post-op complications, GI & vascular"),
("Obs & Gynae", "10-13% (~22 Qs)", "Dutta / Sheila Balakrishnan", "High-risk pregnancy, labor management, contraception, oncology"),
("Paediatrics", "8-10% (~18 Qs)", "OP Ghai / Nelson (reference)", "Developmental milestones, vaccination schedule, neonatal emergencies"),
("Pharmacology", "8-10% (~18 Qs)", "KD Tripathi / Govind Garg", "Drug of choice, MOA, ADRs; scenario-based prescribing"),
("Pathology", "7-9% (~16 Qs)", "Robbins / Harsh Mohan", "Tumor markers, morphology, lab values; link to clinical medicine"),
("Microbiology", "5-7% (~12 Qs)", "Ananthanarayan / Apurba Sastry", "Organism identification, culture media, antibiotic sensitivity"),
("Anatomy", "5-7% (~12 Qs)", "BD Chaurasia / Snell (reference)", "Nerve injuries, surface anatomy, applied/clinical anatomy"),
("Physiology", "4-6% (~10 Qs)", "Ganong / AK Jain", "Graphs, values, integrated physiology; link to clinical scenarios"),
("Biochemistry", "4-6% (~10 Qs)", "Harper / U Satyanarayana", "Enzymes, metabolic pathways, genetic disorders"),
("Orthopaedics", "3-5% (~8 Qs)", "Maheshwari / Apley's", "Fractures, nerve injuries, bone tumours, infections"),
("Ophthalmology", "3-5% (~8 Qs)", "AK Khurana / Renu Jogi", "Glaucoma, retinal diseases, cataracts, optic nerve"),
("ENT", "3-4% (~7 Qs)", "Dhingra / Logan Turner", "Hearing loss types, vertigo, vocal cord lesions, sinusitis"),
("Anaesthesia", "2-3% (~5 Qs)", "Morgan & Mikhail / Ajay Yadav", "Anaesthetic agents, CPR, airway management"),
("Skin (Derma)", "2-3% (~5 Qs)", "Behl & Aggarwal / Valia", "Rashes identification, leprosy grading, STI management"),
("Psychiatry", "2-3% (~5 Qs)", "Ahuja / Kaplan & Sadock (reference)", "ICD-11/DSM-5 criteria, drug of choice per disorder"),
("Radiology", "1-2% (~3 Qs)", "Sutton / Dahnert", "X-ray & CT patterns, 'aunt minnie' signs"),
("PSM/Comm Med", "3-5% (~8 Qs)", "Park's Textbook", "National health programs, biostatistics, screening criteria"),
("Forensic Med", "1-2% (~3 Qs)", "Reddy's Essentials", "Wound characteristics, poisons, medico-legal"),
]
story.append(subject_table(subj_rows))
story.append(sp(10))
story.append(info_box(
"Priority Tiers",
[
"TIER 1 (60-65% of paper) — Medicine, Surgery, OBG, Paediatrics: Give 50% of your study time here.",
"TIER 2 (20-25%) — Pharmacology, Pathology, Microbiology: Give 30% of your study time.",
"TIER 3 (10-15%) — Anatomy, Physiology, Biochemistry, Others: Give 20% of your time; high-yield revision only.",
],
bg=GREEN_LIGHT, title_color=GREEN
))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════
# SECTION 3 – HIGH-YIELD TOPICS
# ══════════════════════════════════════════════════════════
story.append(section_header("SECTION 3", "High-Yield Topics Per Subject", bg=TEAL))
story.append(sp(8))
hyt_data = [
("Medicine", [
"Cardiology: ACS protocols (STEMI/NSTEMI management), ECG interpretation, Heart failure (HFrEF vs HFpEF), Arrhythmias",
"Pulmonology: GOLD criteria for COPD, CAP vs HAP management, TB treatment regimens (RNTCP), Pleural effusion workup",
"Nephrology: CKD staging & dialysis indications, AKI criteria (KDIGO), Glomerulonephritis patterns, Electrolyte disorders",
"Gastroenterology: IBD (Crohn's vs UC) management, Upper GI bleeding algorithm, NAFLD, Liver cirrhosis & portal hypertension",
"Endocrinology: Diabetes management targets & insulin types, Thyroid function tests & thyroid disorders, Adrenal insufficiency",
"Neurology: Stroke management (tPA window, thrombectomy), Seizure classification & drugs, GBS vs MG, Meningitis management",
"Infectious Disease: Antimicrobial selection (DOC for common infections), Fever of unknown origin, Tropical diseases (malaria, dengue)",
]),
("Surgery", [
"Surgical Emergencies: Acute abdomen, Intestinal obstruction, Perforated viscus, Ruptured ectopic",
"GI Surgery: GERD (Barrett's oesophagus), PUD (H. pylori eradication), Colorectal cancer staging, Appendicitis",
"Breast: BIRADS classification, Breast cancer staging & surgical options, Nipple discharge",
"Thyroid & Parathyroid: Thyroid nodule workup, Types of thyroidectomy, Parathyroid adenoma",
"Vascular: DVT management, AAA, Peripheral arterial disease, ABI values",
"Post-operative Complications: Wound infection timeline, PE prophylaxis, Anastomotic leak",
]),
("Obs & Gynae", [
"Antenatal Care: Booking visit investigations, Gestational diabetes screening, Pre-eclampsia criteria & management",
"Labour: Partogram interpretation, Instrumental delivery indications, LSCS indications, Shoulder dystocia",
"Antepartum Hemorrhage: Placenta praevia vs abruption — distinguishing features",
"Contraception: OCP types & contraindications, IUCD insertion timing, Emergency contraception",
"Gynaec Oncology: Cervical cancer screening (Pap smear intervals), FIGO staging (cervical, endometrial, ovarian)",
"Infertility: Semen analysis parameters, HSG vs laparoscopy, IVF indications",
"Menstrual Disorders: PALM-COEIN classification, PCOS (Rotterdam criteria), Endometriosis",
]),
("Pharmacology", [
"Drug of Choice (DOC): For all common infectious, cardiac, psychiatric & GI conditions — make a DOC master list",
"Mechanism of Action: Beta-blockers, ACE inhibitors, Statins, Anticoagulants, Antibiotics (MOA by class)",
"Adverse Drug Reactions: Ototoxicity (aminoglycosides), Nephrotoxicity, QT prolongation drugs, Teratogenic drugs",
"Important Drug Interactions: Warfarin interactions, MAOIs, Serotonin syndrome triggers",
"Newer Drugs: DOACs, SGLT2 inhibitors, GLP-1 agonists, Biologics (TNF-alpha inhibitors)",
]),
("Pathology", [
"Tumour Markers: AFP, CEA, CA-125, PSA, CA 19-9 — which cancer each indicates",
"Haematology: Peripheral smear findings for all anemias, Leukemia classification (FAB), Coagulation cascade & disorders",
"Neoplasia: Benign vs malignant features, Grading vs staging, Metastatic patterns",
"Inflammation: Granuloma types (caseating vs non-caseating), Repair & healing complications",
"Liver Pathology: Hepatitis patterns, Liver cirrhosis (macro/micro), Portal hypertension changes",
]),
("Microbiology", [
"Culture Media: Chocolate agar (Haemophilus), MacConkey (Enterobacteriaceae), TCBS (Vibrio), LJ medium (AFB)",
"Staining: Gram stain, ZN stain, PAS, India ink (Cryptococcus), Giemsa (malaria, trypanosomes)",
"Antibiotic Resistance: MRSA (vancomycin), ESBL organisms, Carbapenem-resistant organisms",
"Viruses: Hepatitis serology interpretation, HIV replication cycle & ARV targets, Herpes viruses",
"Parasites: Life cycles of Plasmodium, Leishmania, Taenia, Echinococcus",
]),
]
for subj, points in hyt_data:
story.append(Paragraph(subj, sH3))
for pt in points:
story.append(Paragraph(f"• {pt}", sBullet))
story.append(sp(6))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════
# SECTION 4 – RECOMMENDED RESOURCES
# ══════════════════════════════════════════════════════════
story.append(section_header("SECTION 4", "Recommended Books & Resources", bg=ACCENT_BLUE))
story.append(sp(10))
story.append(Paragraph("Standard Reading (Primary Sources)", sH3))
story.append(Paragraph(
"These are the standard textbooks from your MBBS — reading them for PG prep means reading selectively, "
"focusing on clinical applications, management protocols, and high-yield data tables.",
sBody
))
story.append(sp(6))
std_books = [
("Medicine", "Davidson's Principles & Practice / Harrison's (selected chapters)",
"Read Davidson's as primary. Use Harrison's for Cardiology, Nephrology, Neurology deep dives only."),
("Surgery", "Bailey & Love's Short Practice of Surgery",
"Cover all clinical chapters. SRB's Manual of Surgery is a great supplementary Q&A book."),
("OBG", "DC Dutta's Textbook of Obstetrics + Dutta's Gynecology",
"Both Dutta books are essential. Sheila Balakrishnan is popular for gynecology."),
("Paediatrics", "OP Ghai's Essential Pediatrics",
"Ghai is sufficient. Nelson only for specific topics (cardiology, neurology)."),
("Pharmacology", "KD Tripathi's Essentials of Medical Pharmacology",
"Make flashcards for DOC list and ADR profiles. Govind Garg for PG-specific MCQs."),
("Pathology", "Harsh Mohan's Textbook of Pathology",
"Harsh Mohan covers everything for PG. Robbins is gold for in-depth understanding."),
("Microbiology", "Ananthanarayan & Paniker's Textbook",
"Standard for all PG exams. Apurba Sastry is more concise for revision."),
("Anatomy", "BD Chaurasia's Human Anatomy (all 4 volumes)",
"For PG, focus on clinical anatomy and nerve/vessel injuries. Snell for specific topics."),
("Physiology", "AK Jain's Textbook of Physiology",
"Good for PG prep. Ganong for deeper understanding of graphs and renal/neuro physiology."),
("PSM", "Park's Textbook of Preventive & Social Medicine",
"Essential for national health programmes, biostatistics. Read selectively."),
]
for sub, book, note in std_books:
row_data = [
[Paragraph(sub, S("bsub", fontName="Helvetica-Bold", fontSize=9, leading=12, textColor=DARK_BLUE)),
Paragraph(book, S("bbook", fontName="Helvetica-Bold", fontSize=9, leading=12, textColor=GREY_DARK)),
Paragraph(f"Note: {note}", S("bnote", fontName="Helvetica-Oblique", fontSize=8, leading=11, textColor=GREY_MED))]
]
t = Table([row_data[0]], colWidths=[CONTENT_W*0.15, CONTENT_W*0.38, CONTENT_W*0.47])
t.setStyle(TableStyle([
("TOPPADDING", (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 7), ("RIGHTPADDING", (0,0),(-1,-1), 7),
("LINEBELOW", (0,0),(-1,-1), 0.3, GREY_LIGHT),
("VALIGN", (0,0),(-1,-1), "TOP"),
]))
story.append(t)
story.append(sp(14))
story.append(Paragraph("PG-Specific MCQ Books & Platforms", sH3))
story.append(sp(4))
pg_resources = [
("MCQ Books", "Across All Subjects",
"PGMEE books by Amit Ashish (all subjects) — concise, exam-focused, frequently updated."),
("MCQ Books", "Subject Compilations",
"Mudit Khanna's books for Surgery & Medicine. Sparsh Gupta for Pharmacology."),
("Online Platform", "PrepLadder",
"Best for video lectures + Q-bank. Strong analytics for weak area identification."),
("Online Platform", "DAMS (Delhi Academy)",
"Comprehensive classroom + online hybrid. Widely used by toppers."),
("Online Platform", "Marrow",
"Excellent Q-bank with detailed solutions. Popular for NEET-PG focused prep."),
("Online Platform", "Surg.io",
"Surgery-specific Q-bank with operative images. Useful for INI-CET visual questions."),
("Previous Papers", "PYQs (5 years)",
"Download and solve last 5 years of INI-CET and NEET-PG papers. Pattern recognition is critical."),
("Revision Notes", "Self-made / Handwritten",
"Make your own one-page subject summaries, DOC lists, and mnemonics. Nothing beats self-notes."),
]
hdr_r = S("hr2", fontName="Helvetica-Bold", fontSize=9, leading=11, textColor=WHITE)
cell_r= S("cr2", fontName="Helvetica", fontSize=8.5, leading=12, textColor=GREY_DARK)
rt_data = [[Paragraph(h, hdr_r) for h in ["Type","Specific Resource","How to Use"]]]
for r in pg_resources:
rt_data.append([Paragraph(c, cell_r) for c in r])
rt = Table(rt_data, colWidths=[CONTENT_W*0.18, CONTENT_W*0.25, CONTENT_W*0.57], repeatRows=1)
rt_s = [
("BACKGROUND", (0,0),(-1, 0), ACCENT_BLUE),
("TOPPADDING", (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 7), ("RIGHTPADDING", (0,0),(-1,-1), 7),
("GRID", (0,0),(-1,-1), 0.4, GREY_LIGHT),
("VALIGN", (0,0),(-1,-1), "TOP"),
]
for i in range(1, len(rt_data)):
rt_s.append(("BACKGROUND", (0,i),(-1,i), LIGHT_BLUE if i%2==0 else WHITE))
rt.setStyle(TableStyle(rt_s))
story.append(rt)
story.append(PageBreak())
# ══════════════════════════════════════════════════════════
# SECTION 5 – 12-MONTH STUDY PLAN
# ══════════════════════════════════════════════════════════
story.append(section_header("SECTION 5", "12-Month Study Plan (First Attempt)", bg=TEAL))
story.append(sp(10))
story.append(Paragraph(
"This plan assumes you are starting from scratch with a target of appearing in INI-CET November 2026 "
"and NEET-PG 2027. Adjust the timeline backward or forward based on your actual exam date.",
sBody
))
story.append(sp(8))
phases = [
("PHASE 1: Foundation (Months 1-3)", GREEN, GREEN_LIGHT, [
("Month 1", [
"Start with Medicine (Cardiology, Respiratory, GI) — 3-4 chapters/day",
"Parallel: Anatomy (Upper limb, Lower limb, Thorax clinical anatomy)",
"Begin Pharmacology alongside Medicine (matching system-wise drugs)",
"Target: 40-50 pages/day total",
"Join a PG prep course or Q-bank (PrepLadder/Marrow)",
"Solve 30-50 MCQs/day from current subject",
]),
("Month 2", [
"Continue Medicine (Nephrology, Neurology, Hematology, Endocrinology)",
"Start Pathology (General pathology + Hematopathology)",
"Anatomy: Head & Neck, Neuro-anatomy",
"Weekly test on covered topics (50 MCQs)",
"Review wrong answers the same day",
]),
("Month 3", [
"Complete Medicine (Infectious diseases, Rheumatology, Skin)",
"Pathology: Systemic pathology (Cardiovascular, Respiratory)",
"Start Physiology (Neurophysiology, CVS, Renal)",
"First full-length subject mock test for Medicine",
"Make revision notes: 1 page per chapter summarizing key values & protocols",
]),
]),
("PHASE 2: Building (Months 4-6)", ACCENT_BLUE, LIGHT_BLUE, [
("Month 4", [
"Surgery: Complete GI, Breast, Thyroid, Peripheral vascular",
"Microbiology: Bacteriology, Virology",
"Physiology: Respiratory, GIT, Endocrine physiology",
"Daily MCQs: 80-100/day (mixed subjects)",
]),
("Month 5", [
"Complete Surgery: Urology, Orthopedics (surgical), Neurosurgery, Trauma",
"Biochemistry: All metabolic pathways, enzymes, genetic disorders",
"Microbiology: Parasitology, Mycology, Immunology",
"Weekly 100-question full-length tests",
]),
("Month 6", [
"OBG: Complete Obstetrics (antenatal through postnatal)",
"PSM: National programs, biostatistics, epidemiology basics",
"Forensic Medicine: Core chapters (wounds, poisons, medicolegal)",
"MID-TERM ASSESSMENT: Full-length mock test (200 Qs). Analyze performance and adjust weak areas.",
]),
]),
("PHASE 3: Clinical Deep-Dive (Months 7-9)", AMBER, AMBER_LIGHT, [
("Month 7", [
"OBG: Complete Gynecology (oncology, infertility, menstrual disorders)",
"Paediatrics: Growth & development, nutrition, neonatology",
"Ophthalmology: Complete subject (high ROI for time invested)",
"Continue daily 100 MCQs; increase image-based questions",
]),
("Month 8", [
"Paediatrics: Complete (systemic pediatrics, infectious diseases)",
"ENT: Complete subject",
"Dermatology: Core topics (rashes, leprosy, STIs)",
"Psychiatry: DSM-5/ICD-11 criteria, drugs of choice",
"Radiology: Common imaging patterns and signs",
"Anaesthesia: Core pharmacology and airway management",
]),
("Month 9", [
"INTEGRATION PHASE: Revise all subjects topic by topic (not chapter by chapter)",
"Focus on cross-subject connections (e.g. drug MOA in Pharma linked to disease in Medicine)",
"Solve previous 3 years of INI-CET and NEET-PG papers",
"Weekly full-length mock tests (simulate exam conditions)",
]),
]),
("PHASE 4: Intensive Revision (Months 10-12)", RED, RED_LIGHT, [
("Month 10", [
"Rapid revision: Tier 1 subjects (Medicine, Surgery, OBG, Paediatrics)",
"Focus on weakest topics identified from mock test analytics",
"Solve 150-200 MCQs/day",
"Review all revision notes and DOC lists",
]),
("Month 11", [
"Rapid revision: Tier 2 & 3 subjects",
"Image-based question practice (INI-CET critical)",
"Previous 5 years' PYQs: Second pass, timed",
"Targeted revision of frequently tested 'one-liners'",
]),
("Month 12 (Final)", [
"No new topics — revision only",
"3 full-length mock tests per week (timed, exam conditions)",
"Last 2 weeks: Only high-yield one-liners, DOC lists, recent guidelines",
"Sleep 7-8 hours, maintain routine, avoid burnout",
"Day before exam: Light revision, early sleep",
]),
]),
]
for phase_title, ph_color, ph_bg, months in phases:
ph_s = S("phs", fontName="Helvetica-Bold", fontSize=11, leading=15, textColor=ph_color, spaceBefore=4)
story.append(Paragraph(phase_title, ph_s))
story.append(hr(ph_color, 1))
story.append(sp(4))
# 2-column layout for months
for i in range(0, len(months), 2):
row_blocks = []
for j in range(2):
if i+j < len(months):
wk, tasks = months[i+j]
row_blocks.append(week_block(wk, tasks, ph_bg))
else:
row_blocks.append(Spacer(1,1))
t = Table([row_blocks], colWidths=[CONTENT_W/2 - 0.15*cm, CONTENT_W/2 - 0.15*cm],
hAlign="LEFT")
t.setStyle(TableStyle([
("TOPPADDING", (0,0),(-1,-1), 0),
("BOTTOMPADDING",(0,0),(-1,-1), 0),
("LEFTPADDING", (0,0),(-1,-1), 0),
("RIGHTPADDING", (0,0),(-1,-1), 0),
("VALIGN", (0,0),(-1,-1), "TOP"),
("INNERGRID", (0,0),(-1,-1), 0, WHITE),
]))
story.append(t)
story.append(sp(6))
story.append(sp(8))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════
# SECTION 6 – DAILY SCHEDULE TEMPLATE
# ══════════════════════════════════════════════════════════
story.append(section_header("SECTION 6", "Sample Daily & Weekly Schedule", bg=MID_BLUE))
story.append(sp(10))
story.append(Paragraph("Sample Daily Schedule (Foundation Phase)", sH3))
story.append(sp(4))
daily = [
("05:30 - 06:00", "Wake up, fresh up, light warm-up / walk"),
("06:00 - 08:00", "Video lecture (PrepLadder / DAMS) — 1 subject, 2 topics"),
("08:00 - 08:30", "Breakfast + short break"),
("08:30 - 11:00", "Textbook reading aligned with lecture topic"),
("11:00 - 11:30", "MCQ practice: 30 questions on morning's topic"),
("11:30 - 13:00", "Second subject: Textbook reading (Tier 2 / Tier 3 subject)"),
("13:00 - 14:00", "Lunch + break (absolutely no studying — rest your brain)"),
("14:00 - 16:00", "Previous subject revision: Review notes from yesterday"),
("16:00 - 18:00", "MCQ practice: 40-60 questions (mixed subjects)"),
("18:00 - 18:30", "Break / light physical activity"),
("18:30 - 20:00", "Wrong answer review + note-making (very important!)"),
("20:00 - 21:00", "Dinner + relaxation"),
("21:00 - 22:30", "Light revision: Flashcards, DOC list, one-liners"),
("22:30", "Sleep (7-8 hours minimum — memory consolidation happens during sleep)"),
]
ds = S("dt", fontName="Helvetica-Bold", fontSize=8.5, leading=12, textColor=DARK_BLUE)
dc = S("dc", fontName="Helvetica", fontSize=8.5, leading=12, textColor=GREY_DARK)
dt_data = [[Paragraph(t, ds), Paragraph(a, dc)] for t,a in daily]
dt = Table(dt_data, colWidths=[CONTENT_W*0.25, CONTENT_W*0.75])
dt_style = [
("TOPPADDING", (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 7), ("RIGHTPADDING", (0,0),(-1,-1), 7),
("GRID", (0,0),(-1,-1), 0.4, GREY_LIGHT),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
("BACKGROUND", (0,0),(0,-1), LIGHT_BLUE),
]
for i in range(0, len(dt_data), 2):
dt_style.append(("BACKGROUND", (1,i),(1,i), GREY_LIGHT))
dt.setStyle(TableStyle(dt_style))
story.append(dt)
story.append(sp(14))
story.append(Paragraph("Weekly Schedule Template", sH3))
story.append(sp(4))
week_sched = [
("Monday", "Medicine (new chapter) + Pharmacology (drug class matching Medicine topic)"),
("Tuesday", "Surgery (new chapter) + Anatomy (region relevant to Surgery chapter)"),
("Wednesday", "OBG (new chapter) + Physiology/Biochemistry (1 topic each)"),
("Thursday", "Paediatrics (new chapter) + Microbiology (organism linked to Paeds topic)"),
("Friday", "Pathology (2 chapters) + Revision of Monday-Thursday topics"),
("Saturday", "Full-length mock test (100 Qs, timed) + Wrong answer analysis"),
("Sunday", "Light day: Flashcard review, DOC list update, plan next week, rest"),
]
wd = S("wd", fontName="Helvetica-Bold", fontSize=8.5, leading=12, textColor=DARK_BLUE)
wc = S("wc", fontName="Helvetica", fontSize=8.5, leading=12, textColor=GREY_DARK)
wk_data = [[Paragraph(d, wd), Paragraph(t, wc)] for d,t in week_sched]
wk_t = Table(wk_data, colWidths=[CONTENT_W*0.17, CONTENT_W*0.83])
wk_ts = [
("TOPPADDING", (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 7), ("RIGHTPADDING", (0,0),(-1,-1), 7),
("GRID", (0,0),(-1,-1), 0.4, GREY_LIGHT),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
("BACKGROUND", (0,0),(0,-1), TEAL_LIGHT),
("BACKGROUND", (0,6),(1,6), AMBER_LIGHT), # Sunday
]
for i in range(0, len(wk_data), 2):
if i != 6:
wk_ts.append(("BACKGROUND", (1,i),(1,i), GREY_LIGHT))
wk_t.setStyle(TableStyle(wk_ts))
story.append(wk_t)
story.append(PageBreak())
# ══════════════════════════════════════════════════════════
# SECTION 7 – EXAM STRATEGY
# ══════════════════════════════════════════════════════════
story.append(section_header("SECTION 7", "Exam Day & Attempt Strategy", bg=AMBER))
story.append(sp(10))
story.append(Paragraph("INI-CET Attempt Strategy (54 seconds per question)", sH3))
strategy_ini = [
"First pass (60 min): Answer all questions you are confident about — skip and flag uncertain ones.",
"Second pass (60 min): Return to flagged questions; use elimination to narrow down to 2 options.",
"Third pass (30 min): Review doubtful questions once more. Do not change confident first-pass answers.",
"Last 30 min: Ensure all questions are attempted (no blanks, especially if you can narrow to 50/50).",
"Negative marking (-0.33): Attempt if you can eliminate at least 2 options. Skip complete guesses.",
"Image-based Qs: Read all 4 options before looking at image details — the options guide what to look for.",
"Clinical scenarios: Identify the 'clinical anchor' (main diagnosis) in the stem before reading options.",
]
for s in strategy_ini:
story.append(Paragraph(f"• {s}", sBullet))
story.append(sp(10))
story.append(Paragraph("NEET-PG Attempt Strategy (63 seconds per question)", sH3))
strategy_neet = [
"First pass (70 min): Complete entire paper once; mark uncertain questions.",
"Second pass (70 min): Focus on marked questions using elimination strategy.",
"Third pass (remaining): Final review of changed answers — changing an answer is usually wrong.",
"Negative marking (-1 per wrong): Attempt if >60% confident. Skip complete guesses.",
"Do not spend more than 90 seconds on any single question.",
"NEET-PG tends to have more recall-based Qs — if you know the fact, answer quickly and move on.",
]
for s in strategy_neet:
story.append(Paragraph(f"• {s}", sBullet))
story.append(sp(10))
story.append(Paragraph("General Exam Performance Tips", sH3))
tips_data = [
("Before Exam", [
"Night before: Light revision only; sleep by 10 PM",
"Morning: Light meal, reach center 1 hr early",
"Carry all documents (Hall ticket, ID proof)",
"No last-minute study on exam morning",
]),
("Answering Technique", [
"Read the question stem fully before options",
"Identify key words: 'MOST common', 'LEAST', 'EXCEPT', 'NEXT step'",
"For clinical Qs: Diagnosis first, then treatment",
"Eliminate obviously wrong options immediately",
]),
("Mental Performance", [
"Stay hydrated; carry water if allowed",
"If blanking on a question, skip and return",
"Deep breathing if anxious — 5 sec in, 5 sec out",
"Trust your preparation; avoid panic guessing",
]),
]
tip_s_title = S("tit", fontName="Helvetica-Bold", fontSize=9.5, leading=13, textColor=AMBER)
tip_s_body = S("tib", fontName="Helvetica", fontSize=8.5, leading=12, textColor=GREY_DARK)
tip_cells = []
for title, pts in tips_data:
cell = [Paragraph(title, tip_s_title), sp(4)]
for p in pts:
cell.append(Paragraph(f"• {p}", tip_s_body))
tip_cells.append(cell)
tip_t = Table([tip_cells], colWidths=[CONTENT_W/3]*3)
tip_t.setStyle(TableStyle([
("TOPPADDING", (0,0),(-1,-1), 10), ("BOTTOMPADDING",(0,0),(-1,-1), 10),
("LEFTPADDING", (0,0),(-1,-1), 10), ("RIGHTPADDING", (0,0),(-1,-1), 10),
("BACKGROUND", (0,0),(-1,-1), AMBER_LIGHT),
("BOX", (0,0),(-1,-1), 0.5, AMBER),
("LINEBEFORE", (1,0),(2,-1), 0.5, AMBER),
("VALIGN", (0,0),(-1,-1), "TOP"),
]))
story.append(tip_t)
story.append(PageBreak())
# ══════════════════════════════════════════════════════════
# SECTION 8 – MNEMONICS & ONE-LINERS
# ══════════════════════════════════════════════════════════
story.append(section_header("SECTION 8", "Key Mnemonics & High-Yield One-Liners", bg=MID_BLUE))
story.append(sp(10))
mnemo_s = S("mn", fontName="Helvetica-Bold", fontSize=9, leading=13, textColor=DARK_BLUE)
mnemo_d = S("md", fontName="Helvetica", fontSize=8.5, leading=13, textColor=GREY_DARK)
mnemo_m = S("mm", fontName="Courier-Bold", fontSize=9, leading=13, textColor=TEAL)
mnemonics = [
("MUDPILES", "Causes of High Anion Gap Metabolic Acidosis",
"Methanol, Uraemia, DKA, Propylene glycol, Isoniazid/Iron, Lactic acidosis, Ethylene glycol, Salicylates"),
("AEIOU TIPS", "Causes of Coma",
"Alcohol, Epilepsy, Insulin (hypoglycemia), Opiates, Uraemia | Trauma, Infection, Psychiatric, Stroke/Shock"),
("SPINE", "Features of Reiter's Syndrome (Reactive Arthritis)",
"Seronegative, Polyarthritis, Iritis, Non-specific urethritis, Erythema nodosum"),
("TRAP", "Features of Hairy Cell Leukemia",
"Tartrate-Resistant Acid Phosphatase positive"),
("VITAMIN C D", "Causes of Hypercalcemia",
"Vitamin D toxicity, Idiopathic, Thyrotoxicosis, Addison's, Milk-alkali, Immobilization, Neoplasm, Cancer, Drugs"),
("ABCDEF (Melanoma)", "ABCDE criteria for skin lesion malignancy",
"Asymmetry, Border irregularity, Color variation, Diameter >6mm, Evolution (change over time)"),
("CAGE", "Screening for Alcohol Dependence",
"Cut down, Annoyed by criticism, Guilty, Eye-opener drink — 2 or more = positive screen"),
]
for mname, mtitle, mdetail in mnemonics:
row = [[
Paragraph(mname, mnemo_m),
[Paragraph(mtitle, mnemo_s), Paragraph(mdetail, mnemo_d)]
]]
t = Table(row, colWidths=[CONTENT_W*0.22, CONTENT_W*0.78])
t.setStyle(TableStyle([
("TOPPADDING", (0,0),(-1,-1), 6), ("BOTTOMPADDING",(0,0),(-1,-1), 6),
("LEFTPADDING", (0,0),(-1,-1), 8), ("RIGHTPADDING", (0,0),(-1,-1), 8),
("LINEBELOW", (0,0),(-1,-1), 0.3, GREY_LIGHT),
("BACKGROUND", (0,0),(0,-1), LIGHT_BLUE),
("VALIGN", (0,0),(-1,-1), "TOP"),
]))
story.append(t)
story.append(sp(12))
story.append(Paragraph("Critical One-Liners (Frequently Tested)", sH3))
story.append(sp(4))
oneliners = [
"DOC for Pneumocystis jirovecii pneumonia (PCP) = Cotrimoxazole (TMP-SMX)",
"Gold standard for diagnosis of pulmonary embolism = CTPA (CT Pulmonary Angiography)",
"Most common cause of secondary hypertension = Renovascular hypertension (in adults); Coarctation of aorta (in children)",
"First line treatment of choice in SIADH (mild) = Fluid restriction",
"Most common site of ectopic pregnancy = Ampulla of fallopian tube (55%)",
"Apgar score: assessed at 1 and 5 minutes; normal = 7-10",
"MI location: ST elevation in V1-V4 = Anterior wall; II, III, aVF = Inferior wall",
"Virchow's triad (DVT): Stasis, Hypercoagulability, Endothelial damage",
"Charcot's triad (Ascending cholangitis): Fever + Jaundice + RUQ pain",
"Reynolds' pentad = Charcot's triad + Hypotension + Altered mental status",
"Most common cause of subarachnoid hemorrhage (non-traumatic) = Ruptured berry aneurysm",
"Drug of choice for Status Epilepticus = IV Lorazepam (1st line); IV Phenytoin/Levetiracetam (2nd line)",
"Tumor marker for hepatocellular carcinoma = AFP (Alpha-fetoprotein)",
"Thumb printing sign on X-ray = Ischaemic colitis",
"Most common cause of community-acquired pneumonia = Streptococcus pneumoniae",
]
for ol in oneliners:
story.append(Paragraph(f"• {ol}", sBullet))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════
# SECTION 9 – SELF-ASSESSMENT TRACKER
# ══════════════════════════════════════════════════════════
story.append(section_header("SECTION 9", "Self-Assessment & Progress Tracker", bg=TEAL))
story.append(sp(10))
story.append(Paragraph(
"Use this tracker to monitor your preparation across all subjects. Rate yourself every 4 weeks.",
sBody
))
story.append(sp(6))
tracker_s = S("trs", fontName="Helvetica-Bold", fontSize=8.5, leading=12, textColor=WHITE)
tracker_c = S("trc", fontName="Helvetica", fontSize=8, leading=11, textColor=GREY_DARK)
tracker_hdrs = ["Subject", "Priority", "1st Read", "1st MCQ\nScore", "2nd Read", "2nd MCQ\nScore", "Final\nRevision", "Confidence\n(1-5)"]
tracker_rows_subjects = [
"Medicine", "Surgery", "OBG", "Paediatrics", "Pharmacology",
"Pathology", "Microbiology", "Anatomy", "Physiology", "Biochemistry",
"PSM", "Orthopaedics", "Ophthalmology", "ENT", "Dermatology",
"Psychiatry", "Anaesthesia", "Radiology", "Forensic Medicine"
]
priority_map = {
"Medicine": "TIER 1", "Surgery": "TIER 1", "OBG": "TIER 1", "Paediatrics": "TIER 1",
"Pharmacology": "TIER 2", "Pathology": "TIER 2", "Microbiology": "TIER 2",
"Anatomy": "TIER 3", "Physiology": "TIER 3", "Biochemistry": "TIER 3",
"PSM": "TIER 2", "Orthopaedics": "TIER 3", "Ophthalmology": "TIER 3",
"ENT": "TIER 3", "Dermatology": "TIER 3", "Psychiatry": "TIER 3",
"Anaesthesia": "TIER 3", "Radiology": "TIER 3", "Forensic Medicine": "TIER 3",
}
tier_colors = {"TIER 1": RED_LIGHT, "TIER 2": AMBER_LIGHT, "TIER 3": GREEN_LIGHT}
tr_data = [[Paragraph(h, tracker_s) for h in tracker_hdrs]]
for subj in tracker_rows_subjects:
pri = priority_map[subj]
tr_data.append([
Paragraph(subj, tracker_c),
Paragraph(pri, tracker_c),
Paragraph("___", tracker_c), Paragraph("___%", tracker_c),
Paragraph("___", tracker_c), Paragraph("___%", tracker_c),
Paragraph("___", tracker_c), Paragraph("__/5", tracker_c),
])
cw_tr = [CONTENT_W*0.18, CONTENT_W*0.1, CONTENT_W*0.1, CONTENT_W*0.1, CONTENT_W*0.1, CONTENT_W*0.1, CONTENT_W*0.1, CONTENT_W*0.12]
tr_t = Table(tr_data, colWidths=cw_tr, repeatRows=1)
tr_ts = [
("BACKGROUND", (0,0),(-1, 0), TEAL),
("TOPPADDING", (0,0),(-1,-1), 4), ("BOTTOMPADDING",(0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 5), ("RIGHTPADDING", (0,0),(-1,-1), 5),
("GRID", (0,0),(-1,-1), 0.4, GREY_LIGHT),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]
for i, subj in enumerate(tracker_rows_subjects, start=1):
pri = priority_map[subj]
bg = tier_colors[pri]
tr_ts.append(("BACKGROUND", (0,i),(1,i), bg))
tr_ts.append(("BACKGROUND", (2,i),(-1,i), WHITE if i%2==0 else GREY_LIGHT))
tr_t.setStyle(TableStyle(tr_ts))
story.append(tr_t)
story.append(sp(10))
story.append(info_box(
"How to Use This Tracker",
[
"1st Read date: Date you complete the first read of the subject.",
"1st MCQ Score: Your percentage on the first subject-wise Q-bank test.",
"2nd Read: After 6-8 weeks, do a rapid revision pass — record date.",
"2nd MCQ Score: Repeat Q-bank test — aim for improvement of 15-20%.",
"Final Revision: Mark date of last revision within 2 weeks of exam.",
"Confidence (1-5): Honest self-rating after final revision. Subjects rated <3 need extra attention.",
],
bg=TEAL_LIGHT, title_color=TEAL
))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════
# SECTION 10 – MOTIVATION & FINAL TIPS
# ══════════════════════════════════════════════════════════
story.append(section_header("SECTION 10", "Motivation, Mindset & Final Checklist", bg=GREEN))
story.append(sp(10))
story.append(Paragraph("Common Mistakes to Avoid", sH3))
mistakes = [
"Reading too many books — pick ONE primary source per subject and stick to it.",
"Studying without MCQ practice — you can read 10 textbooks and still fail without Q-bank practice.",
"Ignoring weak subjects — low-scoring subjects hold the most improvement potential.",
"Not reviewing wrong answers — reviewing mistakes is where the real learning happens.",
"Studying 16 hours/day without breaks — burnout destroys months of preparation.",
"Comparing your progress to others — everyone's baseline and pace is different.",
"Starting mock tests too late — begin full-length mocks by Month 6 at the latest.",
"Skipping image-based practice — INI-CET is 30-40% image/scenario based.",
"Neglecting sleep — memory consolidation happens during sleep; 7+ hours is non-negotiable.",
]
for m in mistakes:
story.append(Paragraph(f"✗ {m}", sBullet))
story.append(sp(12))
story.append(Paragraph("Habits of Top Performers (Rank < 100)", sH3))
habits = [
"Consistent 8-10 hours of focused study every day for at least 10 months.",
"Active recall over passive reading — test yourself constantly.",
"Spaced repetition — review topics at increasing intervals (Day 1, Day 7, Day 30).",
"Physical exercise 30 min/day — proven to improve memory and focus.",
"Daily MCQ practice from Day 1 of prep, not just at the end.",
"Maintaining a 'mistake log' — notebook of wrong answers reviewed every week.",
"Studying with a purpose — before each session, define what you want to know by the end.",
"Joining a study group or peer discussion circle for clinical reasoning practice.",
]
for h in habits:
story.append(Paragraph(f"✓ {h}", S("hab", fontName="Helvetica", fontSize=9, leading=13,
textColor=GREEN, leftIndent=12, firstLineIndent=-10, spaceAfter=2)))
story.append(sp(12))
# Final checklist
story.append(Paragraph("Pre-Exam Final Checklist", sH3))
story.append(sp(4))
checklist = [
("Hall ticket / Admit card printed", "ID proof (Aadhaar / Passport / Driving License)"),
("Stationery ready (pens, pencils, eraser)", "Know the exam center location and route"),
("All 19 subjects revised at least twice", "Revision notes and DOC lists reviewed"),
("5 full-length mock tests completed", "PYQs from last 5 years solved"),
("Image-based Q practice done", "Sleep 7-8 hours two nights before exam"),
]
cl_s = S("cls", fontName="Helvetica", fontSize=8.5, leading=13, textColor=GREY_DARK)
cl_data = []
for c1, c2 in checklist:
cl_data.append([Paragraph(f"☐ {c1}", cl_s), Paragraph(f"☐ {c2}", cl_s)])
cl_t = Table(cl_data, colWidths=[CONTENT_W/2, CONTENT_W/2])
cl_t.setStyle(TableStyle([
("TOPPADDING", (0,0),(-1,-1), 6), ("BOTTOMPADDING",(0,0),(-1,-1), 6),
("LEFTPADDING", (0,0),(-1,-1), 8), ("RIGHTPADDING", (0,0),(-1,-1), 8),
("LINEBELOW", (0,0),(-1,-1), 0.3, GREY_LIGHT),
("BACKGROUND", (0,0),(-1,-1), GREEN_LIGHT),
]))
story.append(cl_t)
story.append(sp(18))
closing = S("closing", fontName="Helvetica-Bold", fontSize=11, leading=18,
textColor=DARK_BLUE, alignment=TA_CENTER)
story.append(Paragraph(
"Consistency beats intelligence. Show up every day, solve MCQs every day, review every day.",
closing
))
story.append(sp(4))
closing2 = S("closing2", fontName="Helvetica-Oblique", fontSize=9, leading=13,
textColor=GREY_MED, alignment=TA_CENTER)
story.append(Paragraph(
"Best of luck with your preparation. The seat is waiting for you.",
closing2
))
# ── Build PDF ──────────────────────────────────────────────────────────────────
def on_page(canvas, doc):
canvas.saveState()
canvas.setFont("Helvetica", 7)
canvas.setFillColor(GREY_MED)
canvas.drawCentredString(A4[0]/2, 1.2*cm, f"INI-CET / NEET-PG Study Guide 2026 | Page {doc.page}")
canvas.restoreState()
doc.build(story, onFirstPage=on_page, onLaterPages=on_page)
print(f"PDF generated: {OUTPUT}")
cd /home/daytona/workspace/inicet-studyguide && python generate_guide.py 2>&1
ls -lh /home/daytona/workspace/inicet-studyguide/INICET_NEET_PG_Study_Guide.pdf
INICET NEET PG Study Guide
PDF Document · PDF
Create a subject-wise question bank tracker (Excel file) to monitor practice test scores
mkdir -p /home/daytona/workspace/inicet-studyguide && python3 -c "import openpyx…
~/inicet-studyguide/build_tracker.py
"""
INI-CET / NEET-PG Subject-wise Question Bank Tracker
Sheets:
1. Dashboard – summary stats + sparklines simulation via conditional formatting
2. Score Log – each practice test entry (date, subject, Qs, correct, %, source, notes)
3. Subject Summary – per-subject aggregated stats pulled from Score Log
4. Topic Drill-Down – per-topic performance within each subject
5. Mock Test Log – full-length mock test tracker
6. Instructions – how to use the workbook
"""
import openpyxl
from openpyxl.styles import (
Font, PatternFill, Alignment, Border, Side, GradientFill
)
from openpyxl.styles.differential import DifferentialStyle
from openpyxl.formatting.rule import ColorScaleRule, DataBarRule, Rule, FormulaRule
from openpyxl.utils import get_column_letter, column_index_from_string
from openpyxl.chart import BarChart, Reference, LineChart
from openpyxl.chart.series import SeriesLabel
from openpyxl.worksheet.datavalidation import DataValidation
from openpyxl.worksheet.table import Table, TableStyleInfo
from openpyxl.drawing.image import Image as XLImage
from datetime import date, timedelta
import random
random.seed(42)
# ── Palette ──────────────────────────────────────────────────────────────────
C_DARK_BLUE = "1A237E"
C_MID_BLUE = "283593"
C_ACCENT_BLUE = "3F51B5"
C_LIGHT_BLUE = "E8EAF6"
C_TEAL = "00695C"
C_TEAL_LT = "E0F2F1"
C_AMBER = "E65100"
C_AMBER_LT = "FFF3E0"
C_GREEN = "2E7D32"
C_GREEN_LT = "E8F5E9"
C_RED = "B71C1C"
C_RED_LT = "FFEBEE"
C_GREY_DK = "37474F"
C_GREY_MD = "78909C"
C_GREY_LT = "ECEFF1"
C_WHITE = "FFFFFF"
C_YELLOW_HL = "FFF9C4"
# ── Style helpers ─────────────────────────────────────────────────────────────
def fill(hex_color):
return PatternFill("solid", fgColor=hex_color)
def font(bold=False, size=10, color="000000", italic=False, name="Arial"):
return Font(name=name, bold=bold, size=size, color=color, italic=italic)
def align(h="left", v="center", wrap=False):
return Alignment(horizontal=h, vertical=v, wrap_text=wrap)
def thin_border(sides="all"):
s = Side(style="thin", color="BDBDBD")
n = Side(style=None)
if sides == "all":
return Border(left=s, right=s, top=s, bottom=s)
b = Border(
left=s if "l" in sides else n,
right=s if "r" in sides else n,
top=s if "t" in sides else n,
bottom=s if "b" in sides else n,
)
return b
def med_border():
s = Side(style="medium", color="9E9E9E")
return Border(left=s, right=s, top=s, bottom=s)
def apply_header_row(ws, row, headers, start_col=1,
bg=C_DARK_BLUE, fg=C_WHITE, size=10, height=22):
ws.row_dimensions[row].height = height
for i, h in enumerate(headers):
c = ws.cell(row=row, column=start_col+i, value=h)
c.font = font(bold=True, size=size, color=fg)
c.fill = fill(bg)
c.alignment = align("center", "center", wrap=True)
c.border = thin_border()
def style_data_row(ws, row, cols, alt=False, height=16):
ws.row_dimensions[row].height = height
bg = C_GREY_LT if alt else C_WHITE
for col in range(cols[0], cols[1]+1):
c = ws.cell(row=row, column=col)
c.fill = fill(bg)
c.border = thin_border()
if c.alignment.horizontal == "general":
c.alignment = align("left", "center")
def set_col_widths(ws, widths):
for col_letter, w in widths.items():
ws.column_dimensions[col_letter].width = w
# ── Subject data ──────────────────────────────────────────────────────────────
SUBJECTS = [
("Medicine", "TIER 1", "Medicine"),
("Surgery", "TIER 1", "Surgery"),
("OBG", "TIER 1", "OBG"),
("Paediatrics", "TIER 1", "Paediatrics"),
("Pharmacology", "TIER 2", "Pharmacology"),
("Pathology", "TIER 2", "Pathology"),
("Microbiology", "TIER 2", "Microbiology"),
("PSM", "TIER 2", "PSM"),
("Anatomy", "TIER 3", "Anatomy"),
("Physiology", "TIER 3", "Physiology"),
("Biochemistry", "TIER 3", "Biochemistry"),
("Orthopaedics", "TIER 3", "Orthopaedics"),
("Ophthalmology", "TIER 3", "Ophthalmology"),
("ENT", "TIER 3", "ENT"),
("Dermatology", "TIER 3", "Dermatology"),
("Psychiatry", "TIER 3", "Psychiatry"),
("Anaesthesia", "TIER 3", "Anaesthesia"),
("Radiology", "TIER 3", "Radiology"),
("Forensic Med", "TIER 3", "Forensic Med"),
]
SUBJ_NAMES = [s[0] for s in SUBJECTS]
TOPICS = {
"Medicine": ["Cardiology","Pulmonology","Gastroenterology","Nephrology","Neurology","Endocrinology","Haematology","Infectious Disease","Rheumatology","Misc Medicine"],
"Surgery": ["GI Surgery","Breast","Thyroid & Parathyroid","Vascular","Urology","Ortho Surgery","Neuro Surgery","Surgical Emergencies","Misc Surgery"],
"OBG": ["Normal Obstetrics","High-Risk Pregnancy","Labour & Delivery","Antepartum Haemorrhage","Gynaec Oncology","Contraception","Infertility","Menstrual Disorders","Misc OBG"],
"Paediatrics": ["Growth & Development","Nutrition","Neonatology","Paeds Infections","Paeds Cardiology","Paeds Neurology","Misc Paediatrics"],
"Pharmacology": ["Autonomic Drugs","Cardiovascular Drugs","CNS Drugs","Antimicrobials","Endocrine Drugs","GI Drugs","Drug of Choice","ADRs & Interactions"],
"Pathology": ["General Pathology","Haematopathology","Neoplasia","Cardiovascular Pathology","Resp Pathology","GI Pathology","Renal Pathology","Misc Pathology"],
"Microbiology": ["Bacteriology","Virology","Parasitology","Mycology","Immunology","Misc Micro"],
"PSM": ["Epidemiology","Biostatistics","National Programmes","Nutrition PSM","Occupational Health","Misc PSM"],
"Anatomy": ["Upper Limb","Lower Limb","Thorax","Abdomen","Head & Neck","Neuroanatomy","Misc Anatomy"],
"Physiology": ["CVS Physiology","Renal Physiology","Respiratory Physiology","Neuro Physiology","Endocrine Physiology","Misc Physiology"],
"Biochemistry": ["Carbohydrate Metabolism","Lipid Metabolism","Protein Metabolism","Enzymes","Genetics","Misc Biochem"],
"Orthopaedics": ["Fractures","Infections","Bone Tumours","Nerve Injuries","Misc Ortho"],
"Ophthalmology": ["Glaucoma","Retina","Cataract","Optic Nerve","Cornea","Misc Ophthalmology"],
"ENT": ["Ear","Nose & Sinuses","Throat","Head & Neck ENT","Misc ENT"],
"Dermatology": ["Infections Skin","Inflammatory","Leprosy","STIs","Misc Derma"],
"Psychiatry": ["Psychosis","Mood Disorders","Anxiety","Substance Use","Misc Psychiatry"],
"Anaesthesia": ["Inhalational Agents","IV Agents","Muscle Relaxants","Airway Management","Misc Anaesthesia"],
"Radiology": ["Chest Radiology","Abdominal Radiology","Neuro Radiology","Misc Radiology"],
"Forensic Med": ["Wounds & Injuries","Toxicology","Medico-legal","Misc Forensic"],
}
SOURCES = ["PrepLadder","Marrow","DAMS","Surg.io","Custom Q-Bank","PYQ INI-CET","PYQ NEET-PG","Textbook MCQs","Mock Test"]
wb = openpyxl.Workbook()
wb.remove(wb.active) # remove default sheet
# ═════════════════════════════════════════════════════════════════════════════
# SHEET 1: INSTRUCTIONS
# ═════════════════════════════════════════════════════════════════════════════
ws_i = wb.create_sheet("📋 Instructions")
ws_i.sheet_view.showGridLines = False
ws_i.sheet_properties.tabColor = C_GREY_MD
set_col_widths(ws_i, {"A":3,"B":28,"C":70,"D":3})
# Title banner
ws_i.merge_cells("B2:C2")
c = ws_i["B2"]
c.value = "INI-CET / NEET-PG Question Bank Tracker — User Guide"
c.font = font(bold=True, size=16, color=C_WHITE)
c.fill = fill(C_DARK_BLUE)
c.alignment = align("center","center")
ws_i.row_dimensions[2].height = 36
ws_i.merge_cells("B3:C3")
c = ws_i["B3"]
c.value = "How to use this workbook"
c.font = font(size=10, color=C_GREY_MD, italic=True)
c.fill = fill(C_LIGHT_BLUE)
c.alignment = align("center","center")
ws_i.row_dimensions[3].height = 20
instructions = [
("", ""),
("SHEET", "PURPOSE"),
("📊 Dashboard", "Auto-calculates your overall progress. No manual entry needed here."),
("📝 Score Log", "Enter every practice test/Q-bank session here — this is your main entry sheet."),
("📈 Subject Summary", "Auto-summary of all sessions per subject. Refresh PivotTable if prompted."),
("🎯 Topic Drill-Down", "Log performance at the topic level for granular weak-area analysis."),
("📋 Mock Test Log", "Log full-length mock tests (200 Qs) separately for exam simulation tracking."),
("", ""),
("HOW TO LOG A SESSION", ""),
("Step 1", "Go to 📝 Score Log sheet"),
("Step 2", "Click the first empty row in the table"),
("Step 3", "Enter: Date | Subject | Topic | Questions Attempted | Correct | Source | Notes"),
("Step 4", "% Score, Status, and Attempt # are calculated automatically"),
("Step 5", "Dashboard updates automatically — check it after each session"),
("", ""),
("SCORE STATUS LABELS", ""),
("🔴 Needs Work", "Score < 50% — priority revision needed"),
("🟡 Developing", "Score 50-65% — improving but not exam-ready"),
("🟢 Good", "Score 65-80% — on track"),
("✅ Excellent", "Score > 80% — maintain and move on"),
("", ""),
("TARGET SCORES", ""),
("INI-CET target", "Aim for >75% average per subject by exam month"),
("NEET-PG target", "Aim for >70% average per subject by exam month"),
("", ""),
("TIPS", ""),
("Color coding", "Blue cells = you enter data. White/grey = auto-calculated. Don't edit grey cells."),
("Filters", "Use column filters (dropdown arrows) to view by subject, date range, or source."),
("Sorting", "Click any column header to sort by that field."),
("Backup", "Save a copy at the end of each week with the date in the filename."),
]
row = 4
for label, desc in instructions:
ws_i.row_dimensions[row].height = 18
if label == "SHEET" or label in ("HOW TO LOG A SESSION","SCORE STATUS LABELS","TARGET SCORES","TIPS","COLOUR CODING"):
ws_i.merge_cells(f"B{row}:C{row}")
c = ws_i[f"B{row}"]
c.value = label if label != "SHEET" else "SHEET → PURPOSE"
c.font = font(bold=True, size=9, color=C_WHITE)
c.fill = fill(C_ACCENT_BLUE)
c.alignment = align("left","center")
ws_i.row_dimensions[row].height = 20
elif label == "":
pass
else:
bl = ws_i[f"B{row}"]
bl.value = label
bl.font = font(bold=True, size=9, color=C_DARK_BLUE)
bl.alignment = align("left","center")
bl.fill = fill(C_LIGHT_BLUE)
bl.border = thin_border()
dc = ws_i[f"C{row}"]
dc.value = desc
dc.font = font(size=9, color=C_GREY_DK)
dc.alignment = align("left","center", wrap=True)
dc.fill = fill(C_WHITE)
dc.border = thin_border()
row += 1
# ═════════════════════════════════════════════════════════════════════════════
# SHEET 2: SCORE LOG (main entry sheet)
# ═════════════════════════════════════════════════════════════════════════════
ws_s = wb.create_sheet("📝 Score Log")
ws_s.sheet_view.showGridLines = False
ws_s.sheet_properties.tabColor = C_ACCENT_BLUE
ws_s.freeze_panes = "A4"
set_col_widths(ws_s, {
"A": 5, # #
"B": 13, # Date
"C": 20, # Subject
"D": 24, # Topic
"E": 14, # Qs Attempted
"F": 14, # Correct
"G": 13, # % Score
"H": 16, # Status
"I": 5, # Attempt #
"J": 18, # Source
"K": 30, # Notes
"L": 4,
})
# Title
ws_s.merge_cells("A1:K1")
c = ws_s["A1"]
c.value = "INI-CET / NEET-PG — Practice Test Score Log"
c.font = font(bold=True, size=14, color=C_WHITE)
c.fill = fill(C_DARK_BLUE)
c.alignment = align("center","center")
ws_s.row_dimensions[1].height = 32
ws_s.merge_cells("A2:K2")
c = ws_s["A2"]
c.value = "Log every Q-bank session. Blue cells = your input. Auto-calculated columns are shaded."
c.font = font(size=9, color=C_GREY_MD, italic=True)
c.fill = fill(C_LIGHT_BLUE)
c.alignment = align("center","center")
ws_s.row_dimensions[2].height = 18
SCORE_HEADERS = ["#","Date","Subject","Topic","Qs\nAttempted","Correct","% Score","Status","Attempt\n#","Source","Notes / Weak Points"]
apply_header_row(ws_s, 3, SCORE_HEADERS, start_col=1, bg=C_DARK_BLUE)
# Data validation
subj_dv = DataValidation(
type="list",
formula1='"' + ",".join(SUBJ_NAMES) + '"',
allow_blank=True, showErrorMessage=True,
errorTitle="Invalid Subject", error="Choose from the dropdown list."
)
ws_s.add_data_validation(subj_dv)
source_dv = DataValidation(
type="list",
formula1='"' + ",".join(SOURCES) + '"',
allow_blank=True
)
ws_s.add_data_validation(source_dv)
# Add sample data rows (15 sessions)
today = date.today()
sample_sessions = [
(today - timedelta(days=20), "Medicine", "Cardiology", 50, 38, "PrepLadder", "Revise ECG patterns"),
(today - timedelta(days=19), "Medicine", "Pulmonology", 40, 28, "Marrow", "COPD staging weak"),
(today - timedelta(days=18), "Surgery", "GI Surgery", 45, 30, "DAMS", "Appendicitis Q types"),
(today - timedelta(days=17), "Pharmacology", "Drug of Choice", 60, 42, "PrepLadder", "DOC list incomplete"),
(today - timedelta(days=16), "OBG", "High-Risk Pregnancy", 50, 35, "Marrow", "Pre-eclampsia criteria"),
(today - timedelta(days=15), "Pathology", "Haematopathology", 55, 40, "Custom Q-Bank", "Leukemia FAB good"),
(today - timedelta(days=14), "Medicine", "Nephrology", 45, 36, "PYQ INI-CET", "CKD staging solid"),
(today - timedelta(days=12), "Surgery", "Breast", 30, 22, "PrepLadder", "BIRADS classification"),
(today - timedelta(days=11), "Microbiology", "Bacteriology", 50, 33, "Marrow", "Culture media weak"),
(today - timedelta(days=10), "Paediatrics", "Growth & Development", 40, 30, "DAMS", "Milestones good"),
(today - timedelta(days=9), "Anatomy", "Upper Limb", 35, 20, "Custom Q-Bank", "Nerve injuries tricky"),
(today - timedelta(days=7), "Medicine", "Cardiology", 60, 50, "Marrow", "Improvement noted"),
(today - timedelta(days=6), "Pharmacology", "Antimicrobials", 50, 40, "PrepLadder", "MOA of abx solid"),
(today - timedelta(days=4), "OBG", "Labour & Delivery", 45, 32, "PYQ NEET-PG", "Partogram revisit"),
(today - timedelta(days=2), "Surgery", "Vascular", 40, 30, "PrepLadder", "DVT algorithm"),
]
# Track attempt counts per subject
attempt_counts = {}
data_start = 4
for idx, (dt, subj, topic, qs, correct, source, notes) in enumerate(sample_sessions):
r = data_start + idx
attempt_counts[subj] = attempt_counts.get(subj, 0) + 1
pct = correct / qs if qs > 0 else 0
ws_s.row_dimensions[r].height = 17
# # (row number formula)
c_num = ws_s.cell(row=r, column=1, value=f'=ROW()-{data_start-1}')
c_num.font = font(size=9, color=C_GREY_MD)
c_num.alignment = align("center","center")
c_num.fill = fill(C_GREY_LT)
c_num.border = thin_border()
c_date = ws_s.cell(row=r, column=2, value=dt)
c_date.number_format = "DD-MMM-YY"
c_date.font = font(size=9, color="000080")
c_date.fill = fill(C_YELLOW_HL) # user input = yellow highlight
c_date.alignment = align("center","center")
c_date.border = thin_border()
c_subj = ws_s.cell(row=r, column=3, value=subj)
c_subj.font = font(bold=True, size=9, color=C_DARK_BLUE)
c_subj.fill = fill(C_YELLOW_HL)
c_subj.alignment = align("left","center")
c_subj.border = thin_border()
subj_dv.add(c_subj)
c_topic = ws_s.cell(row=r, column=4, value=topic)
c_topic.font = font(size=9)
c_topic.fill = fill(C_YELLOW_HL)
c_topic.alignment = align("left","center")
c_topic.border = thin_border()
c_qs = ws_s.cell(row=r, column=5, value=qs)
c_qs.font = font(size=9, color="000080")
c_qs.fill = fill(C_YELLOW_HL)
c_qs.alignment = align("center","center")
c_qs.border = thin_border()
c_cor = ws_s.cell(row=r, column=6, value=correct)
c_cor.font = font(size=9, color="000080")
c_cor.fill = fill(C_YELLOW_HL)
c_cor.alignment = align("center","center")
c_cor.border = thin_border()
# % Score (auto)
c_pct = ws_s.cell(row=r, column=7, value=f"=IF(E{r}>0,F{r}/E{r},\"\")")
c_pct.number_format = "0.0%"
c_pct.font = font(bold=True, size=9)
c_pct.fill = fill(C_GREY_LT)
c_pct.alignment = align("center","center")
c_pct.border = thin_border()
# Status (auto)
c_st = ws_s.cell(row=r, column=8,
value=f'=IF(G{r}="","",IF(G{r}<0.5,"🔴 Needs Work",IF(G{r}<0.65,"🟡 Developing",IF(G{r}<0.8,"🟢 Good","✅ Excellent"))))')
c_st.font = font(size=9)
c_st.fill = fill(C_GREY_LT)
c_st.alignment = align("center","center")
c_st.border = thin_border()
# Attempt # (auto COUNTIF)
c_att = ws_s.cell(row=r, column=9,
value=f'=COUNTIF($C$4:C{r},C{r})')
c_att.font = font(size=9, color=C_GREY_MD)
c_att.fill = fill(C_GREY_LT)
c_att.alignment = align("center","center")
c_att.border = thin_border()
c_src = ws_s.cell(row=r, column=10, value=source)
c_src.font = font(size=9, italic=True)
c_src.fill = fill(C_YELLOW_HL)
c_src.alignment = align("left","center")
c_src.border = thin_border()
source_dv.add(c_src)
c_notes = ws_s.cell(row=r, column=11, value=notes)
c_notes.font = font(size=9, color=C_GREY_DK)
c_notes.fill = fill(C_YELLOW_HL)
c_notes.alignment = align("left","center", wrap=True)
c_notes.border = thin_border()
# Add 30 blank input rows
for idx in range(len(sample_sessions), len(sample_sessions)+30):
r = data_start + idx
ws_s.row_dimensions[r].height = 17
alt = idx % 2 == 0
c_num = ws_s.cell(row=r, column=1, value=f'=IF(E{r}<>"",ROW()-{data_start-1},"")')
c_num.font = font(size=9, color=C_GREY_MD)
c_num.alignment = align("center","center")
c_num.fill = fill(C_GREY_LT)
c_num.border = thin_border()
for col in [2,3,4,5,6,10,11]:
c = ws_s.cell(row=r, column=col)
c.fill = fill(C_YELLOW_HL)
c.font = font(size=9, color="000080")
c.alignment = align("left","center") if col in [3,4,11] else align("center","center")
c.border = thin_border()
if col == 2:
c.number_format = "DD-MMM-YY"
if col in [3]:
subj_dv.add(c)
if col == 10:
source_dv.add(c)
c_pct = ws_s.cell(row=r, column=7, value=f"=IF(E{r}>0,F{r}/E{r},\"\")")
c_pct.number_format = "0.0%"
c_pct.font = font(bold=True, size=9)
c_pct.fill = fill(C_GREY_LT)
c_pct.alignment = align("center","center")
c_pct.border = thin_border()
c_st = ws_s.cell(row=r, column=8,
value=f'=IF(G{r}="","",IF(G{r}<0.5,"🔴 Needs Work",IF(G{r}<0.65,"🟡 Developing",IF(G{r}<0.8,"🟢 Good","✅ Excellent"))))')
c_st.font = font(size=9)
c_st.fill = fill(C_GREY_LT)
c_st.alignment = align("center","center")
c_st.border = thin_border()
c_att = ws_s.cell(row=r, column=9,
value=f'=IF(C{r}<>"",COUNTIF($C$4:C{r},C{r}),"")')
c_att.font = font(size=9, color=C_GREY_MD)
c_att.fill = fill(C_GREY_LT)
c_att.alignment = align("center","center")
c_att.border = thin_border()
# Conditional formatting on % Score column (G)
last_data_row = data_start + len(sample_sessions) + 30 - 1
score_range = f"G{data_start}:G{last_data_row}"
ws_s.conditional_formatting.add(score_range, ColorScaleRule(
start_type="num", start_value=0, start_color="FFCDD2",
mid_type="num", mid_value=0.65, mid_color="FFF9C4",
end_type="num", end_value=1, end_color="C8E6C9",
))
# ═════════════════════════════════════════════════════════════════════════════
# SHEET 3: SUBJECT SUMMARY
# ═════════════════════════════════════════════════════════════════════════════
ws_ss = wb.create_sheet("📈 Subject Summary")
ws_ss.sheet_view.showGridLines = False
ws_ss.sheet_properties.tabColor = C_GREEN
ws_ss.freeze_panes = "A4"
set_col_widths(ws_ss, {
"A": 22, # Subject
"B": 10, # Tier
"C": 12, # Sessions
"D": 14, # Total Qs
"E": 14, # Total Correct
"F": 13, # Avg Score %
"G": 14, # Best Score
"H": 14, # Latest Score
"I": 18, # Status
"J": 16, # Target Met?
"K": 22, # Trend
"L": 4,
})
ws_ss.merge_cells("A1:K1")
c = ws_ss["A1"]
c.value = "Subject Summary — Auto-calculated from Score Log"
c.font = font(bold=True, size=14, color=C_WHITE)
c.fill = fill(C_DARK_BLUE)
c.alignment = align("center","center")
ws_ss.row_dimensions[1].height = 32
ws_ss.merge_cells("A2:K2")
c = ws_ss["A2"]
c.value = "All figures pull from the Score Log automatically. Target: >70% avg for NEET-PG | >75% avg for INI-CET"
c.font = font(size=9, italic=True, color=C_GREY_MD)
c.fill = fill(C_LIGHT_BLUE)
c.alignment = align("center","center")
ws_ss.row_dimensions[2].height = 18
SS_HEADERS = ["Subject","Tier","Sessions","Total Qs\nAttempted","Total\nCorrect","Avg Score\n%","Best\nScore","Latest\nScore","Status","Target\nMet? (70%)","Trend Note"]
apply_header_row(ws_ss, 3, SS_HEADERS, start_col=1, bg=C_TEAL)
TIER_COLORS = {"TIER 1": C_RED_LT, "TIER 2": C_AMBER_LT, "TIER 3": C_GREEN_LT}
TIER_TEXT = {"TIER 1": C_RED, "TIER 2": C_AMBER, "TIER 3": C_GREEN}
score_log_last = data_start + len(sample_sessions) + 30 - 1
SL = "'📝 Score Log'"
for idx, (subj, tier, _) in enumerate(SUBJECTS):
r = 4 + idx
ws_ss.row_dimensions[r].height = 18
tier_bg = TIER_COLORS[tier]
tier_fg = TIER_TEXT[tier]
c_subj = ws_ss.cell(row=r, column=1, value=subj)
c_subj.font = font(bold=True, size=9, color=C_DARK_BLUE)
c_subj.fill = fill(tier_bg)
c_subj.border = thin_border()
c_subj.alignment = align("left","center")
c_tier = ws_ss.cell(row=r, column=2, value=tier)
c_tier.font = font(bold=True, size=8, color=tier_fg)
c_tier.fill = fill(tier_bg)
c_tier.border = thin_border()
c_tier.alignment = align("center","center")
# Sessions
c_ses = ws_ss.cell(row=r, column=3,
value=f'=COUNTIF({SL}!$C${data_start}:$C${score_log_last},A{r})')
c_ses.font = font(size=9)
c_ses.fill = fill(C_WHITE)
c_ses.border = thin_border()
c_ses.alignment = align("center","center")
# Total Qs
c_tqs = ws_ss.cell(row=r, column=4,
value=f'=SUMIF({SL}!$C${data_start}:$C${score_log_last},A{r},{SL}!$E${data_start}:$E${score_log_last})')
c_tqs.font = font(size=9)
c_tqs.fill = fill(C_WHITE)
c_tqs.border = thin_border()
c_tqs.alignment = align("center","center")
# Total Correct
c_tcr = ws_ss.cell(row=r, column=5,
value=f'=SUMIF({SL}!$C${data_start}:$C${score_log_last},A{r},{SL}!$F${data_start}:$F${score_log_last})')
c_tcr.font = font(size=9)
c_tcr.fill = fill(C_WHITE)
c_tcr.border = thin_border()
c_tcr.alignment = align("center","center")
# Avg Score %
c_avg = ws_ss.cell(row=r, column=6,
value=f'=IF(D{r}>0,E{r}/D{r},"")')
c_avg.number_format = "0.0%"
c_avg.font = font(bold=True, size=9)
c_avg.fill = fill(C_GREY_LT)
c_avg.border = thin_border()
c_avg.alignment = align("center","center")
# Best Score (MAXIFS)
c_best = ws_ss.cell(row=r, column=7,
value=f'=IFERROR(MAXIFS({SL}!$G${data_start}:$G${score_log_last},{SL}!$C${data_start}:$C${score_log_last},A{r}),"")')
c_best.number_format = "0.0%"
c_best.font = font(size=9, color=C_GREEN)
c_best.fill = fill(C_WHITE)
c_best.border = thin_border()
c_best.alignment = align("center","center")
# Latest Score (LOOKUP by max date for that subject) — simplified: last matching
c_last = ws_ss.cell(row=r, column=8,
value=f'=IFERROR(LOOKUP(2,1/({SL}!$C${data_start}:$C${score_log_last}=A{r}),{SL}!$G${data_start}:$G${score_log_last}),"")')
c_last.number_format = "0.0%"
c_last.font = font(size=9, color=C_ACCENT_BLUE)
c_last.fill = fill(C_WHITE)
c_last.border = thin_border()
c_last.alignment = align("center","center")
# Status
c_st = ws_ss.cell(row=r, column=9,
value=f'=IF(F{r}="","⚪ Not Started",IF(F{r}<0.5,"🔴 Needs Work",IF(F{r}<0.65,"🟡 Developing",IF(F{r}<0.8,"🟢 Good","✅ Excellent"))))')
c_st.font = font(size=9)
c_st.fill = fill(C_GREY_LT)
c_st.border = thin_border()
c_st.alignment = align("center","center")
# Target Met
c_tgt = ws_ss.cell(row=r, column=10,
value=f'=IF(F{r}="","—",IF(F{r}>=0.7,"✅ YES","❌ No"))')
c_tgt.font = font(size=9)
c_tgt.fill = fill(C_GREY_LT)
c_tgt.border = thin_border()
c_tgt.alignment = align("center","center")
# Trend Note (simple: latest vs avg)
c_trend = ws_ss.cell(row=r, column=11,
value=f'=IF(OR(H{r}="",F{r}=""),"",IF(H{r}>F{r},"📈 Improving",IF(H{r}<F{r},"📉 Declining","➡ Stable")))')
c_trend.font = font(size=9)
c_trend.fill = fill(C_WHITE)
c_trend.border = thin_border()
c_trend.alignment = align("center","center")
# Colour scale on Avg Score
ws_ss.conditional_formatting.add(f"F4:F{4+len(SUBJECTS)-1}", ColorScaleRule(
start_type="num", start_value=0, start_color="FFCDD2",
mid_type="num", mid_value=0.65, mid_color="FFF9C4",
end_type="num", end_value=1, end_color="C8E6C9",
))
# ═════════════════════════════════════════════════════════════════════════════
# SHEET 4: TOPIC DRILL-DOWN
# ═════════════════════════════════════════════════════════════════════════════
ws_td = wb.create_sheet("🎯 Topic Drill-Down")
ws_td.sheet_view.showGridLines = False
ws_td.sheet_properties.tabColor = C_AMBER
set_col_widths(ws_td, {
"A": 20,
"B": 26,
"C": 12,
"D": 14,
"E": 14,
"F": 13,
"G": 18,
"H": 16,
"I": 4,
})
ws_td.merge_cells("A1:H1")
c = ws_td["A1"]
c.value = "Topic-Level Drill-Down — Log Each Topic Session for Fine-Grained Tracking"
c.font = font(bold=True, size=13, color=C_WHITE)
c.fill = fill(C_DARK_BLUE)
c.alignment = align("center","center")
ws_td.row_dimensions[1].height = 30
ws_td.merge_cells("A2:H2")
c = ws_td["A2"]
c.value = "Enter data here just like Score Log but at topic level. Use dropdown for Subject to auto-fill topics."
c.font = font(size=9, italic=True, color=C_GREY_MD)
c.fill = fill(C_AMBER_LT)
c.alignment = align("center","center")
ws_td.row_dimensions[2].height = 18
TD_HEADERS = ["Subject","Topic","Qs\nAttempted","Correct","% Score","Status","Date","Notes"]
apply_header_row(ws_td, 3, TD_HEADERS, bg=C_AMBER)
subj_dv2 = DataValidation(type="list", formula1='"' + ",".join(SUBJ_NAMES) + '"', allow_blank=True)
ws_td.add_data_validation(subj_dv2)
# Pre-fill topic reference rows (one per topic across all subjects)
all_topics = []
for subj, tier, _ in SUBJECTS:
for topic in TOPICS[subj]:
all_topics.append((subj, topic))
td_start = 4
for idx, (subj, topic) in enumerate(all_topics):
r = td_start + idx
ws_td.row_dimensions[r].height = 16
alt = idx % 2 == 0
bg = C_GREY_LT if alt else C_WHITE
c_s = ws_td.cell(row=r, column=1, value=subj)
c_s.font = font(bold=True, size=8.5, color=C_DARK_BLUE)
c_s.fill = fill(C_LIGHT_BLUE if alt else C_WHITE)
c_s.border = thin_border()
c_s.alignment = align("left","center")
subj_dv2.add(c_s)
c_t = ws_td.cell(row=r, column=2, value=topic)
c_t.font = font(size=8.5)
c_t.fill = fill(bg)
c_t.border = thin_border()
c_t.alignment = align("left","center")
for col in [3,4]:
c = ws_td.cell(row=r, column=col)
c.fill = fill(C_YELLOW_HL)
c.border = thin_border()
c.alignment = align("center","center")
c.font = font(size=8.5, color="000080")
c_pct = ws_td.cell(row=r, column=5, value=f"=IF(C{r}>0,D{r}/C{r},\"\")")
c_pct.number_format = "0.0%"
c_pct.font = font(bold=True, size=8.5)
c_pct.fill = fill(C_GREY_LT)
c_pct.border = thin_border()
c_pct.alignment = align("center","center")
c_st = ws_td.cell(row=r, column=6,
value=f'=IF(E{r}="","⚪ Not Done",IF(E{r}<0.5,"🔴 Weak",IF(E{r}<0.65,"🟡 OK",IF(E{r}<0.8,"🟢 Good","✅ Strong"))))')
c_st.font = font(size=8.5)
c_st.fill = fill(C_GREY_LT)
c_st.border = thin_border()
c_st.alignment = align("center","center")
c_dt = ws_td.cell(row=r, column=7)
c_dt.fill = fill(C_YELLOW_HL)
c_dt.number_format = "DD-MMM-YY"
c_dt.font = font(size=8.5, color="000080")
c_dt.border = thin_border()
c_dt.alignment = align("center","center")
c_n = ws_td.cell(row=r, column=8)
c_n.fill = fill(C_YELLOW_HL)
c_n.font = font(size=8.5)
c_n.border = thin_border()
c_n.alignment = align("left","center", wrap=True)
# Colour scale on % Score
ws_td.conditional_formatting.add(f"E{td_start}:E{td_start+len(all_topics)-1}", ColorScaleRule(
start_type="num", start_value=0, start_color="FFCDD2",
mid_type="num", mid_value=0.65, mid_color="FFF9C4",
end_type="num", end_value=1, end_color="C8E6C9",
))
# ═════════════════════════════════════════════════════════════════════════════
# SHEET 5: MOCK TEST LOG
# ═════════════════════════════════════════════════════════════════════════════
ws_mt = wb.create_sheet("📋 Mock Test Log")
ws_mt.sheet_view.showGridLines = False
ws_mt.sheet_properties.tabColor = C_RED
set_col_widths(ws_mt, {
"A": 5,
"B": 13,
"C": 18,
"D": 14,
"E": 14,
"F": 14,
"G": 13,
"H": 16,
"I": 18,
"J": 16,
"K": 14,
"L": 22,
"M": 4,
})
ws_mt.merge_cells("A1:L1")
c = ws_mt["A1"]
c.value = "Full-Length Mock Test Tracker — INI-CET & NEET-PG"
c.font = font(bold=True, size=14, color=C_WHITE)
c.fill = fill(C_DARK_BLUE)
c.alignment = align("center","center")
ws_mt.row_dimensions[1].height = 32
ws_mt.merge_cells("A2:L2")
c = ws_mt["A2"]
c.value = "Log each full-length mock test (200 Qs). Track rank prediction and subject-wise breakdown."
c.font = font(size=9, italic=True, color=C_GREY_MD)
c.fill = fill(C_RED_LT)
c.alignment = align("center","center")
ws_mt.row_dimensions[2].height = 18
MT_HEADERS = ["#","Date","Exam\nType","Platform","Total\nQs","Correct","Wrong","Skipped","% Score","Rank\nPrediction","Time\nTaken (min)","Key Observations"]
apply_header_row(ws_mt, 3, MT_HEADERS, bg=C_RED)
exam_dv = DataValidation(type="list", formula1='"INI-CET,NEET-PG,Mixed"', allow_blank=True)
platform_dv = DataValidation(type="list", formula1='"PrepLadder,Marrow,DAMS,Surg.io,Custom"', allow_blank=True)
ws_mt.add_data_validation(exam_dv)
ws_mt.add_data_validation(platform_dv)
mock_samples = [
(today - timedelta(days=25), "INI-CET", "PrepLadder", 200, 110, 60, 30, 110, "Weak in Pharmacology and Micro"),
(today - timedelta(days=18), "NEET-PG", "Marrow", 200, 122, 50, 28, 122, "Improved Medicine, Surgery still weak"),
(today - timedelta(days=10), "INI-CET", "DAMS", 200, 135, 42, 23, 135, "Best score yet; OBG improved"),
(today - timedelta(days=3), "NEET-PG", "PrepLadder", 200, 148, 38, 14, 148, "Consistent improvement; Paeds weak"),
]
mt_start = 4
for idx, (dt, exam, platform, total, correct, wrong, skipped, _, obs) in enumerate(mock_samples):
r = mt_start + idx
ws_mt.row_dimensions[r].height = 18
alt = idx % 2 == 0
bg = C_GREY_LT if alt else C_WHITE
c = ws_mt.cell(row=r, column=1, value=idx+1)
c.font = font(size=9, color=C_GREY_MD); c.fill = fill(C_GREY_LT); c.border = thin_border(); c.alignment = align("center","center")
c = ws_mt.cell(row=r, column=2, value=dt)
c.number_format = "DD-MMM-YY"; c.font = font(size=9, color="000080"); c.fill = fill(C_YELLOW_HL); c.border = thin_border(); c.alignment = align("center","center")
c = ws_mt.cell(row=r, column=3, value=exam)
c.font = font(bold=True, size=9, color=C_RED); c.fill = fill(C_YELLOW_HL); c.border = thin_border(); c.alignment = align("center","center")
exam_dv.add(c)
c = ws_mt.cell(row=r, column=4, value=platform)
c.font = font(size=9); c.fill = fill(C_YELLOW_HL); c.border = thin_border(); c.alignment = align("left","center")
platform_dv.add(c)
for col, val in zip([5,6,7,8], [total,correct,wrong,skipped]):
c = ws_mt.cell(row=r, column=col, value=val)
c.font = font(size=9, color="000080"); c.fill = fill(C_YELLOW_HL); c.border = thin_border(); c.alignment = align("center","center")
# % Score
c_pct = ws_mt.cell(row=r, column=9, value=f"=IF(E{r}>0,F{r}/E{r},\"\")")
c_pct.number_format = "0.0%"; c_pct.font = font(bold=True, size=9); c_pct.fill = fill(C_GREY_LT); c_pct.border = thin_border(); c_pct.alignment = align("center","center")
# Rank prediction (rough formula)
c_rank = ws_mt.cell(row=r, column=10,
value=f'=IF(I{r}="","",IF(I{r}>=0.9,"Top 1%",IF(I{r}>=0.8,"Top 5%",IF(I{r}>=0.7,"Top 15%",IF(I{r}>=0.6,"Top 30%","Below 50%")))))')
c_rank.font = font(size=9); c_rank.fill = fill(C_GREY_LT); c_rank.border = thin_border(); c_rank.alignment = align("center","center")
# Time taken
c_time = ws_mt.cell(row=r, column=11, value=175 if "INI" in exam else 195)
c_time.font = font(size=9, color="000080"); c_time.fill = fill(C_YELLOW_HL); c_time.border = thin_border(); c_time.alignment = align("center","center")
c_obs = ws_mt.cell(row=r, column=12, value=obs)
c_obs.font = font(size=9); c_obs.fill = fill(C_YELLOW_HL); c_obs.border = thin_border(); c_obs.alignment = align("left","center", wrap=True)
# 10 blank mock rows
for idx in range(len(mock_samples), len(mock_samples)+10):
r = mt_start + idx
ws_mt.row_dimensions[r].height = 18
c = ws_mt.cell(row=r, column=1, value=f'=IF(E{r}<>"",ROW()-{mt_start-1},"")')
c.font = font(size=9, color=C_GREY_MD); c.fill = fill(C_GREY_LT); c.border = thin_border(); c.alignment = align("center","center")
for col in [2,3,4,5,6,7,8,11,12]:
cx = ws_mt.cell(row=r, column=col)
cx.fill = fill(C_YELLOW_HL); cx.border = thin_border()
cx.alignment = align("center","center") if col != 12 else align("left","center",wrap=True)
cx.font = font(size=9, color="000080")
if col == 2: cx.number_format = "DD-MMM-YY"
if col == 3: exam_dv.add(cx)
if col == 4: platform_dv.add(cx)
c_pct = ws_mt.cell(row=r, column=9, value=f"=IF(E{r}>0,F{r}/E{r},\"\")")
c_pct.number_format = "0.0%"; c_pct.font = font(bold=True, size=9); c_pct.fill = fill(C_GREY_LT); c_pct.border = thin_border(); c_pct.alignment = align("center","center")
c_rank = ws_mt.cell(row=r, column=10,
value=f'=IF(I{r}="","",IF(I{r}>=0.9,"Top 1%",IF(I{r}>=0.8,"Top 5%",IF(I{r}>=0.7,"Top 15%",IF(I{r}>=0.6,"Top 30%","Below 50%")))))')
c_rank.font = font(size=9); c_rank.fill = fill(C_GREY_LT); c_rank.border = thin_border(); c_rank.alignment = align("center","center")
# Color scale on % Score
mt_last = mt_start + len(mock_samples) + 10 - 1
ws_mt.conditional_formatting.add(f"I{mt_start}:I{mt_last}", ColorScaleRule(
start_type="num", start_value=0, start_color="FFCDD2",
mid_type="num", mid_value=0.65, mid_color="FFF9C4",
end_type="num", end_value=1, end_color="C8E6C9",
))
# ═════════════════════════════════════════════════════════════════════════════
# SHEET 6: DASHBOARD
# ═════════════════════════════════════════════════════════════════════════════
ws_d = wb.create_sheet("📊 Dashboard", 0)
ws_d.sheet_view.showGridLines = False
ws_d.sheet_properties.tabColor = C_DARK_BLUE
set_col_widths(ws_d, {
"A": 2.5,
"B": 22,
"C": 16,
"D": 16,
"E": 16,
"F": 16,
"G": 18,
"H": 2.5,
"I": 22,
"J": 14,
"K": 14,
"L": 14,
"M": 2.5,
})
# ── Title banner ──
ws_d.merge_cells("B1:L1")
c = ws_d["B1"]
c.value = "INI-CET / NEET-PG — Question Bank Tracker Dashboard"
c.font = font(bold=True, size=16, color=C_WHITE)
c.fill = fill(C_DARK_BLUE)
c.alignment = align("center","center")
ws_d.row_dimensions[1].height = 38
ws_d.merge_cells("B2:L2")
c = ws_d["B2"]
c.value = f"Last Updated: {today.strftime('%d %b %Y')} | All data auto-pulled from Score Log & Mock Test Log"
c.font = font(size=9, italic=True, color=C_GREY_MD)
c.fill = fill(C_LIGHT_BLUE)
c.alignment = align("center","center")
ws_d.row_dimensions[2].height = 18
ws_d.row_dimensions[3].height = 12
# ── KPI CARDS row ──
ws_d.row_dimensions[4].height = 14
ws_d.row_dimensions[5].height = 30
ws_d.row_dimensions[6].height = 22
ws_d.row_dimensions[7].height = 14
SL2 = "'📝 Score Log'"
MT2 = "'📋 Mock Test Log'"
SS2 = "'📈 Subject Summary'"
kpis = [
("Total Sessions", f"=COUNTA({SL2}!C{data_start}:C{score_log_last})", C_ACCENT_BLUE, C_WHITE),
("Total Qs Attempted", f"=SUM({SL2}!E{data_start}:E{score_log_last})", C_TEAL, C_WHITE),
("Overall Avg Score", f'=IFERROR(SUM({SL2}!F{data_start}:F{score_log_last})/SUM({SL2}!E{data_start}:E{score_log_last}),"")', C_GREEN, C_WHITE),
("Mock Tests Done", f"=COUNTA({MT2}!B{mt_start}:B{mt_last})", C_AMBER, C_WHITE),
("Latest Mock Score", f"=IFERROR(LOOKUP(2,1/({MT2}!I{mt_start}:I{mt_last}<>\"\"),{MT2}!I{mt_start}:I{mt_last}),\"\")", C_RED, C_WHITE),
]
kpi_cols = ["B","C","D","E","F","G"] # not used, using merge
kpi_col_pairs = [("B","C"),("C","D"),("D","E"),("E","F"),("F","G")]
# 5 KPI cards in B-L area using individual merges
kpi_positions = [
("B","C"), ("C","D"), ("D","E"), ("E","F"), ("F","G")
]
# Rebuild with exact positions
kpi_cells = [
("B5","B6","B7"), ("C5","C6","C7"), ("D5","D6","D7"), ("E5","E6","E7"), ("F5","F6","F7")
]
# Use a proper grid: 5 cards across B:L split evenly
# B:C=card1, D:E=card2, F:G=card3, H:I=card4 (H is separator...skip), I:J=card4, K:L=card5
kpi_configs = [
(("B","D"), ("B","D"), ("B","D"), C_ACCENT_BLUE, "Total Sessions", f"=COUNTA({SL2}!C{data_start}:C{score_log_last})",""),
(("D","F"), ("D","F"), ("D","F"), C_TEAL, "Total Qs Attempted", f"=SUM({SL2}!E{data_start}:E{score_log_last})",""),
(("F","H"), ("F","H"), ("F","H"), C_GREEN, "Overall Avg Score", f'=IFERROR(SUM({SL2}!F{data_start}:F{score_log_last})/SUM({SL2}!E{data_start}:E{score_log_last}),"")','0.0%'),
(("I","K"), ("I","K"), ("I","K"), C_AMBER, "Mock Tests Done", f"=COUNTA({MT2}!B{mt_start}:B{mt_last})",""),
(("K","M"), ("K","M"), ("K","M"), C_RED, "Latest Mock Score", f'=IFERROR(LOOKUP(2,1/({MT2}!I{mt_start}:I{mt_last}<>""),{MT2}!I{mt_start}:I{mt_last}),"")','0.0%'),
]
for label_rng, val_rng, sub_rng, bg, label_text, val_formula, num_fmt in kpi_configs:
lc1, lc2 = label_rng
vc1, vc2 = val_rng
lbl_range = f"{lc1}4:{lc2}4" if lc1 != lc2 else f"{lc1}4"
val_range = f"{vc1}5:{vc2}5" if vc1 != vc2 else f"{vc1}5"
sub_range = f"{lc1}6:{lc2}6" if lc1 != lc2 else f"{lc1}6"
ws_d.merge_cells(f"{lc1}4:{lc2}4")
c = ws_d[f"{lc1}4"]
c.value = label_text
c.font = font(size=8.5, color="BBDEFB")
c.fill = fill(bg)
c.alignment = align("center","center")
ws_d.merge_cells(f"{vc1}5:{vc2}5")
c = ws_d[f"{vc1}5"]
c.value = val_formula
c.font = font(bold=True, size=20, color=C_WHITE)
c.fill = fill(bg)
c.alignment = align("center","center")
if num_fmt:
c.number_format = num_fmt
ws_d.merge_cells(f"{lc1}6:{lc2}6")
c = ws_d[f"{lc1}6"]
c.value = "▲ auto-updated"
c.font = font(size=7.5, color="BBDEFB", italic=True)
c.fill = fill(bg)
c.alignment = align("center","center")
ws_d.merge_cells(f"{lc1}7:{lc2}7")
c = ws_d[f"{lc1}7"]
c.fill = fill(C_WHITE)
ws_d.row_dimensions[8].height = 10
# ── Subject-wise status table ──
ws_d.row_dimensions[9].height = 14
ws_d.merge_cells("B9:G9")
c = ws_d["B9"]
c.value = "Subject Performance Overview"
c.font = font(bold=True, size=11, color=C_WHITE)
c.fill = fill(C_MID_BLUE)
c.alignment = align("center","center")
ws_d.row_dimensions[9].height = 22
ws_d.merge_cells("I9:L9")
c = ws_d["I9"]
c.value = "Mock Test Progression"
c.font = font(bold=True, size=11, color=C_WHITE)
c.fill = fill(C_RED)
c.alignment = align("center","center")
# Subject status headers
subj_hdrs = ["Subject","Tier","Avg Score","Status","Target?"]
subj_hdr_cols = ["B","C","D","E","F"]
ws_d.row_dimensions[10].height = 20
for col_l, hdr in zip(subj_hdr_cols, subj_hdrs):
c = ws_d[f"{col_l}10"]
c.value = hdr
c.font = font(bold=True, size=9, color=C_WHITE)
c.fill = fill(C_ACCENT_BLUE)
c.border = thin_border()
c.alignment = align("center","center")
# G10 = trend
c = ws_d["G10"]
c.value = "Trend"
c.font = font(bold=True, size=9, color=C_WHITE)
c.fill = fill(C_ACCENT_BLUE)
c.border = thin_border()
c.alignment = align("center","center")
# Pull from Subject Summary (rows 4-22)
for i, (subj, tier, _) in enumerate(SUBJECTS):
r = 11 + i
ws_d.row_dimensions[r].height = 16
ss_r = 4 + i
alt = i % 2 == 0
tier_bg = TIER_COLORS[tier]
c_s = ws_d[f"B{r}"]
c_s.value = f"={SS2}!A{ss_r}"
c_s.font = font(bold=True, size=8.5, color=C_DARK_BLUE)
c_s.fill = fill(tier_bg); c_s.border = thin_border(); c_s.alignment = align("left","center")
c_tier = ws_d[f"C{r}"]
c_tier.value = f"={SS2}!B{ss_r}"
c_tier.font = font(size=8.5, color=TIER_TEXT[tier])
c_tier.fill = fill(tier_bg); c_tier.border = thin_border(); c_tier.alignment = align("center","center")
c_avg = ws_d[f"D{r}"]
c_avg.value = f"={SS2}!F{ss_r}"
c_avg.number_format = "0.0%"
c_avg.font = font(bold=True, size=8.5)
c_avg.fill = fill(C_GREY_LT if alt else C_WHITE); c_avg.border = thin_border(); c_avg.alignment = align("center","center")
c_st = ws_d[f"E{r}"]
c_st.value = f"={SS2}!I{ss_r}"
c_st.font = font(size=8.5)
c_st.fill = fill(C_GREY_LT if alt else C_WHITE); c_st.border = thin_border(); c_st.alignment = align("center","center")
c_tgt = ws_d[f"F{r}"]
c_tgt.value = f"={SS2}!J{ss_r}"
c_tgt.font = font(size=8.5)
c_tgt.fill = fill(C_GREY_LT if alt else C_WHITE); c_tgt.border = thin_border(); c_tgt.alignment = align("center","center")
c_trend = ws_d[f"G{r}"]
c_trend.value = f"={SS2}!K{ss_r}"
c_trend.font = font(size=8.5)
c_trend.fill = fill(C_GREY_LT if alt else C_WHITE); c_trend.border = thin_border(); c_trend.alignment = align("center","center")
ws_d.conditional_formatting.add(f"D11:D{11+len(SUBJECTS)-1}", ColorScaleRule(
start_type="num", start_value=0, start_color="FFCDD2",
mid_type="num", mid_value=0.65, mid_color="FFF9C4",
end_type="num", end_value=1, end_color="C8E6C9",
))
# ── Mock test mini-table ──
mt_hdrs = ["Date","Exam","Score","Rank"]
mt_hdr_cols = ["I","J","K","L"]
ws_d.row_dimensions[10].height = 20
for col_l, hdr in zip(mt_hdr_cols, mt_hdrs):
c = ws_d[f"{col_l}10"]
c.value = hdr
c.font = font(bold=True, size=9, color=C_WHITE)
c.fill = fill(C_RED)
c.border = thin_border()
c.alignment = align("center","center")
for i, (dt, exam, platform, total, correct, wrong, skipped, _, obs) in enumerate(mock_samples):
r = 11 + i
mt_r = mt_start + i
alt = i % 2 == 0
bg = C_GREY_LT if alt else C_WHITE
c = ws_d[f"I{r}"]
c.value = f"={MT2}!B{mt_r}"
c.number_format = "DD-MMM"; c.font = font(size=8.5); c.fill = fill(bg); c.border = thin_border(); c.alignment = align("center","center")
c = ws_d[f"J{r}"]
c.value = f"={MT2}!C{mt_r}"
c.font = font(bold=True, size=8.5, color=C_RED); c.fill = fill(bg); c.border = thin_border(); c.alignment = align("center","center")
c = ws_d[f"K{r}"]
c.value = f"={MT2}!I{mt_r}"
c.number_format = "0.0%"; c.font = font(bold=True, size=8.5); c.fill = fill(bg); c.border = thin_border(); c.alignment = align("center","center")
c = ws_d[f"L{r}"]
c.value = f"={MT2}!J{mt_r}"
c.font = font(size=8.5, color=C_GREEN); c.fill = fill(bg); c.border = thin_border(); c.alignment = align("center","center")
ws_d.conditional_formatting.add(f"K11:K{11+len(mock_samples)-1}", ColorScaleRule(
start_type="num", start_value=0, start_color="FFCDD2",
mid_type="num", mid_value=0.65, mid_color="FFF9C4",
end_type="num", end_value=1, end_color="C8E6C9",
))
# ── Legend ──
legend_row = 11 + len(SUBJECTS) + 1
ws_d.row_dimensions[legend_row] = ws_d.row_dimensions[legend_row]
ws_d.merge_cells(f"B{legend_row}:G{legend_row}")
c = ws_d[f"B{legend_row}"]
c.value = "Legend: 🔴 Needs Work (<50%) | 🟡 Developing (50-65%) | 🟢 Good (65-80%) | ✅ Excellent (>80%) | Target = 70% avg"
c.font = font(size=8.5, italic=True, color=C_GREY_DK)
c.fill = fill(C_LIGHT_BLUE)
c.alignment = align("center","center")
c.border = thin_border()
ws_d.row_dimensions[legend_row].height = 18
# ═════════════════════════════════════════════════════════════════════════════
# REORDER SHEETS: Dashboard first
# ═════════════════════════════════════════════════════════════════════════════
# Already created with index 0
# ── Save ──────────────────────────────────────────────────────────────────────
OUT = "/home/daytona/workspace/inicet-studyguide/INICET_NEETPG_QB_Tracker.xlsx"
wb.save(OUT)
print(f"Saved: {OUT}")
cd /home/daytona/workspace/inicet-studyguide && python3 build_tracker.py 2>&1
~/inicet-studyguide/build_tracker.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/inicet-studyguide/build_tracker.py'
cd /home/daytona/workspace/inicet-studyguide && python3 build_tracker.py 2>&1
~/inicet-studyguide/build_tracker.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/inicet-studyguide/build_tracker.py'
cd /home/daytona/workspace/inicet-studyguide && python3 build_tracker.py 2>&1
~/inicet-studyguide/build_tracker.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/inicet-studyguide/build_tracker.py'
cd /home/daytona/workspace/inicet-studyguide && python3 build_tracker.py 2>&1
~/inicet-studyguide/build_tracker.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/inicet-studyguide/build_tracker.py'
cd /home/daytona/workspace/inicet-studyguide && python3 build_tracker.py 2>&1
INICET NEETPG QB Tracker
Spreadsheet · XLSX
% Score, Status (🔴/🟡/🟢/✅), and Attempt # all auto-calculate from your inputsRank Prediction auto-fills (Top 1%/5%/15%/30%/Below 50%) based on your scoreHey thanks for the job. If I find it useful I'll let u know, try to increase my preparation strategies
"6:00-8:00 AM: Medicine Cardiology video + 30 MCQs. 8:30-11:00 AM: Pathology reading. Done."
| Phase | Primary Strategy | MCQs/Day | Mocks/Month |
|---|---|---|---|
| Month 1-3 | 3-pass reading + Anki setup | 30-50 | 0 |
| Month 4-6 | Interleaved MCQs + error log | 80-100 | 1-2 |
| Month 7-9 | Image bank + protocol cards | 100-150 | 2-3 |
| Month 10-12 | SRS revision only + mocks | 150-200 | 6-8 |