What is meant by "strength of evidence" and "quality of evidence" in a clinical trial? what is the Method of calculation of sample size for a therapeutic trial ?-from standard literature like sabiston/bailey , if possible in an easy memorable format/Table in a downloadable one/two page pdf/image.
mkdir -p /tmp/workspace/evidence-pdf && ls /tmp/workspace/evidence-pdf/
~/evidence-pdf/generate_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm
from reportlab.lib import colors
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.lib.colors import HexColor
OUTPUT = "/tmp/workspace/evidence-pdf/Evidence_SampleSize_ClinicalTrials.pdf"
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
leftMargin=1.5*cm,
rightMargin=1.5*cm,
topMargin=1.5*cm,
bottomMargin=1.5*cm
)
# ── Colour palette ────────────────────────────────────────────────────────────
NAVY = HexColor("#1a3a5c")
TEAL = HexColor("#0d7377")
LTBLUE = HexColor("#d6eaf8")
LTGREY = HexColor("#f2f3f4")
RED = HexColor("#c0392b")
GREEN = HexColor("#1e8449")
AMBER = HexColor("#d68910")
WHITE = colors.white
BLACK = colors.black
ORANGE = HexColor("#e67e22")
styles = getSampleStyleSheet()
def h1(text):
return Paragraph(text, ParagraphStyle(
"H1", fontSize=13, textColor=WHITE, backColor=NAVY,
spaceAfter=4, spaceBefore=6, leftIndent=4, rightIndent=4,
leading=16, fontName="Helvetica-Bold", alignment=TA_CENTER
))
def h2(text):
return Paragraph(text, ParagraphStyle(
"H2", fontSize=10.5, textColor=WHITE, backColor=TEAL,
spaceAfter=3, spaceBefore=5, leftIndent=3,
leading=14, fontName="Helvetica-Bold"
))
def body(text, size=8.5):
return Paragraph(text, ParagraphStyle(
"Body", fontSize=size, leading=12, spaceAfter=2,
fontName="Helvetica", textColor=BLACK
))
def small(text):
return Paragraph(text, ParagraphStyle(
"Small", fontSize=7.5, leading=10, spaceAfter=2,
fontName="Helvetica-Oblique", textColor=HexColor("#555555")
))
def bold(text, size=8.5):
return Paragraph(f"<b>{text}</b>", ParagraphStyle(
"Bold", fontSize=size, leading=12, spaceAfter=1,
fontName="Helvetica-Bold", textColor=NAVY
))
def cell(text, bold=False, bg=None, size=8, color=BLACK):
style = ParagraphStyle(
"Cell", fontSize=size, leading=11,
fontName="Helvetica-Bold" if bold else "Helvetica",
textColor=color
)
return Paragraph(text, style)
# ─────────────────────────────────────────────────────────────────────────────
story = []
# ══════════════════════════════════════════════════════════════════
# PAGE 1 — STRENGTH / QUALITY OF EVIDENCE
# ══════════════════════════════════════════════════════════════════
story.append(h1("STRENGTH & QUALITY OF EVIDENCE | SAMPLE SIZE IN CLINICAL TRIALS"))
story.append(small(" Sources: Sabiston Textbook of Surgery 21e (Ch 6) · Schwartz's Principles of Surgery 11e (Ch 51) · Barash's Clinical Anesthesia 9e · Cecil Medicine"))
story.append(Spacer(1, 3))
# ── Section 1 ─────────────────────────────────────────────────────
story.append(h2("1. KEY DEFINITIONS"))
def_data = [
[cell("Term", bold=True, bg=NAVY, color=WHITE),
cell("Definition", bold=True, bg=NAVY, color=WHITE)],
[cell("Quality of Evidence\n(Certainty of Evidence)", bold=True),
cell("Confidence that the true effect lies close to the estimated effect.\nReflects study design, risk of bias, consistency, directness, and precision.")],
[cell("Strength of a\nRecommendation", bold=True),
cell("How confident we are that following the recommendation will do more good than harm.\nDepends on quality of evidence PLUS values, preferences, costs, feasibility.")],
[cell("Internal Validity", bold=True),
cell("Observed outcome is truly due to the intervention (not bias/confounding).")],
[cell("External Validity\n(Generalisability)", bold=True),
cell("Study results apply to real-world clinical practice outside the study.")],
]
def_table = Table(def_data, colWidths=[4.5*cm, 13.5*cm])
def_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("BACKGROUND", (0,1), (-1,1), LTBLUE),
("BACKGROUND", (0,2), (-1,2), LTGREY),
("BACKGROUND", (0,3), (-1,3), LTBLUE),
("BACKGROUND", (0,4), (-1,4), LTGREY),
("VALIGN", (0,0), (-1,-1), "TOP"),
("GRID", (0,0), (-1,-1), 0.5, colors.grey),
("ROWBACKGROUND",(0,0), (-1,0), NAVY),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
]))
story.append(def_table)
story.append(Spacer(1, 5))
# ── Section 2: Evidence Hierarchy ─────────────────────────────────
story.append(h2("2. EVIDENCE HIERARCHY (Oxford CEBM / USPSTF Levels)"))
hier_data = [
[cell("Level", bold=True, color=WHITE), cell("Study Type", bold=True, color=WHITE),
cell("Typical RCT Features", bold=True, color=WHITE)],
[cell("1 ★★★★", bold=True, color=GREEN),
cell("Systematic review / Meta-analysis of RCTs"),
cell("Multiple large RCTs pooled; highest certainty")],
[cell("2 ★★★☆", bold=True, color=GREEN),
cell("Single well-designed RCT (adequate size)"),
cell("Randomisation, allocation concealment, blinding, ITT")],
[cell("3 ★★☆☆", bold=True, color=AMBER),
cell("Cohort study / Non-randomised controlled trial"),
cell("Prospective; large n; propensity matching")],
[cell("4 ★☆☆☆", bold=True, color=ORANGE),
cell("Case-control study / Case series"),
cell("Retrospective; selection bias possible")],
[cell("5 ☆☆☆☆", bold=True, color=RED),
cell("Expert opinion / Mechanism-based reasoning"),
cell("No direct patient-level data")],
]
hier_table = Table(hier_data, colWidths=[2.8*cm, 7.5*cm, 7.7*cm])
hier_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("BACKGROUND", (0,1), (-1,2), HexColor("#d5f5e3")),
("BACKGROUND", (0,3), (-1,3), HexColor("#fef9e7")),
("BACKGROUND", (0,4), (-1,4), HexColor("#fdebd0")),
("BACKGROUND", (0,5), (-1,5), HexColor("#fadbd8")),
("GRID", (0,0), (-1,-1), 0.5, colors.grey),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
]))
story.append(hier_table)
story.append(Spacer(1, 5))
# ── Section 3: GRADE ───────────────────────────────────────────────
story.append(h2("3. GRADE SYSTEM — Quality of Evidence & Strength of Recommendation (Sabiston Table 6.3)"))
grade_data = [
[cell("Quality", bold=True, color=WHITE), cell("Definition (Confidence in Effect Estimate)", bold=True, color=WHITE),
cell("Strength of\nRecommendation", bold=True, color=WHITE), cell("Starting Design", bold=True, color=WHITE)],
[cell("HIGH\n⬆⬆⬆⬆", bold=True, color=GREEN),
cell("Very confident — true effect close to estimated effect; further research unlikely to change confidence."),
cell("STRONG", bold=True, color=GREEN),
cell("RCT")],
[cell("MODERATE\n⬆⬆⬆", bold=True, color=HexColor("#1a9e60")),
cell("Moderately confident — true effect likely close, but possibility of substantial difference."),
cell("CONDITIONAL", bold=True, color=AMBER),
cell("RCT (downgraded)\nor Obs. (upgraded)")],
[cell("LOW\n⬆⬆", bold=True, color=AMBER),
cell("Limited confidence — true effect may be substantially different."),
cell("CONDITIONAL", bold=True, color=AMBER),
cell("Observational")],
[cell("VERY LOW\n⬆", bold=True, color=RED),
cell("Very little confidence — true effect likely substantially different from estimate."),
cell("CONDITIONAL", bold=True, color=RED),
cell("Case series /\nExpert opinion")],
]
grade_table = Table(grade_data, colWidths=[2.5*cm, 8.5*cm, 2.8*cm, 4.2*cm])
grade_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("BACKGROUND", (0,1), (-1,1), HexColor("#d5f5e3")),
("BACKGROUND", (0,2), (-1,2), HexColor("#eafaf1")),
("BACKGROUND", (0,3), (-1,3), HexColor("#fef9e7")),
("BACKGROUND", (0,4), (-1,4), HexColor("#fadbd8")),
("GRID", (0,0), (-1,-1), 0.5, colors.grey),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
]))
story.append(grade_table)
story.append(Spacer(1, 4))
# ── Section 4: Upgrade / Downgrade ────────────────────────────────
story.append(h2("4. FACTORS THAT UPGRADE OR DOWNGRADE QUALITY (Sabiston Table 6.4 / GRADE)"))
updown_data = [
[cell("DOWNGRADE — Lower Quality If:", bold=True, color=WHITE),
cell("UPGRADE — Higher Quality If:", bold=True, color=WHITE)],
[cell("• Risk of bias (poor allocation concealment,\n no blinding, high attrition, ITT violation)"),
cell("• Large magnitude of effect")],
[cell("• Inconsistency (heterogeneous results\n across studies)"),
cell("• Dose-response gradient present")],
[cell("• Indirectness (surrogate endpoints,\n different population)"),
cell("• All plausible confounders would reduce\n the observed effect (conservative estimate)")],
[cell("• Imprecision (wide CIs, small n)"),
cell("• Consistency across multiple independent\n studies")],
[cell("• Publication bias (positive results\n preferentially published)"),
cell("• Representative / generalisable\n patient population")],
]
updown_table = Table(updown_data, colWidths=[9*cm, 9*cm])
updown_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), RED),
("BACKGROUND", (1,0), (1,0), GREEN),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("BACKGROUND", (0,1), (0,-1), HexColor("#fdedec")),
("BACKGROUND", (1,1), (1,-1), HexColor("#e9f7ef")),
("GRID", (0,0), (-1,-1), 0.5, colors.grey),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
]))
story.append(updown_table)
story.append(Spacer(1, 4))
# ── Section 5: Strong vs Weak ──────────────────────────────────────
story.append(h2("5. STRONG vs WEAK RECOMMENDATION (Schwartz Table 51)"))
sw_data = [
[cell("Factor", bold=True, color=WHITE),
cell("STRONG Recommendation Example", bold=True, color=WHITE),
cell("WEAK Recommendation Example", bold=True, color=WHITE)],
[cell("Quality of Evidence"),
cell("Many high-quality RCTs: inhaled steroids in asthma"),
cell("Only case series: pleurodesis in pneumothorax")],
[cell("Balance of Effects"),
cell("Aspirin in MI: reduces mortality, minimal toxicity"),
cell("Warfarin in low-risk AF: small stroke benefit vs bleeding risk")],
[cell("Patient Values"),
cell("Outcomes consistently valued the same by patients"),
cell("Significant patient-to-patient variability in values")],
[cell("Resources / Cost"),
cell("Low cost, widely available"),
cell("High cost, resource-limited settings")],
]
sw_table = Table(sw_data, colWidths=[3.5*cm, 7.5*cm, 7*cm])
sw_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("BACKGROUND", (0,1), (0,-1), LTBLUE),
("ROWBACKGROUND",(0,1), (-1,-1), [LTGREY, LTBLUE, LTGREY, LTBLUE]),
("GRID", (0,0), (-1,-1), 0.5, colors.grey),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
]))
story.append(sw_table)
# ═════════════════ PAGE BREAK ════════════════════════════════════
from reportlab.platypus import PageBreak
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════
# PAGE 2 — SAMPLE SIZE CALCULATION
# ══════════════════════════════════════════════════════════════════
story.append(h1("SAMPLE SIZE CALCULATION FOR A THERAPEUTIC (CLINICAL) TRIAL"))
story.append(small(" Sources: Creasy & Resnik's Maternal-Fetal Medicine 9e · Barash's Clinical Anesthesia 9e · Goldman-Cecil Medicine"))
story.append(Spacer(1, 4))
# ── Error Types ────────────────────────────────────────────────────
story.append(h2("1. ERROR TYPES IN HYPOTHESIS TESTING — The 2×2 Truth Table"))
err_data = [
[cell("", bold=True), cell("H₀ TRUE\n(No real difference)", bold=True, color=WHITE),
cell("H₀ FALSE\n(Real difference exists)", bold=True, color=WHITE)],
[cell("Reject H₀\n(Test says: DIFFERENCE)", bold=True),
cell("❌ TYPE I ERROR (α)\nFalse Positive\n\"We said there was a difference\nbut there wasn't.\""),
cell("✅ CORRECT\nTrue Positive\n(Power = 1 - β)")],
[cell("Fail to Reject H₀\n(Test says: NO DIFFERENCE)", bold=True),
cell("✅ CORRECT\nTrue Negative"),
cell("❌ TYPE II ERROR (β)\nFalse Negative\n\"We missed a real difference.\"\n(Underpowered study)")],
]
err_table = Table(err_data, colWidths=[4.5*cm, 7.25*cm, 6.25*cm])
err_table.setStyle(TableStyle([
("BACKGROUND", (1,0), (-1,0), NAVY),
("TEXTCOLOR", (1,0), (-1,0), WHITE),
("BACKGROUND", (0,0), (0,-1), TEAL),
("TEXTCOLOR", (0,0), (0,-1), WHITE),
("BACKGROUND", (0,0), (0,0), HexColor("#0a2540")),
("BACKGROUND", (1,1), (1,1), HexColor("#fadbd8")),
("BACKGROUND", (2,1), (2,1), HexColor("#d5f5e3")),
("BACKGROUND", (1,2), (1,2), HexColor("#d5f5e3")),
("BACKGROUND", (2,2), (2,2), HexColor("#fadbd8")),
("GRID", (0,0), (-1,-1), 0.5, colors.grey),
("VALIGN", (0,0), (-1,-1), "TOP"),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 5),
]))
story.append(err_table)
story.append(Spacer(1, 5))
# ── Key Parameters ─────────────────────────────────────────────────
story.append(h2("2. KEY PARAMETERS NEEDED BEFORE CALCULATING SAMPLE SIZE"))
param_data = [
[cell("Parameter", bold=True, color=WHITE), cell("Symbol", bold=True, color=WHITE),
cell("Conventional Value", bold=True, color=WHITE), cell("Meaning", bold=True, color=WHITE)],
[cell("Alpha (Type I error)"), cell("α"), cell("0.05 (5%)"),
cell("Chance of a false-positive result. By convention ≤ 5%.")],
[cell("Beta (Type II error)"), cell("β"), cell("0.10–0.20 (10–20%)"),
cell("Chance of a false-negative result. Accepted up to 20%.")],
[cell("Power"), cell("1–β"), cell("80%–90%"),
cell("Probability of detecting a true difference when it exists.")],
[cell("Significance level (p-value)"),cell("p"), cell("< 0.05"),
cell("Threshold below which H₀ is rejected.")],
[cell("Effect size / Minimum\nDetectable Difference"), cell("Δ / MDD"), cell("Clinically meaningful\ndifference"),
cell("Smallest difference that matters clinically. Smaller Δ → larger n.")],
[cell("Baseline event rate\n(Control group incidence)"), cell("P₁"), cell("From literature\nor pilot data"),
cell("Incidence of outcome in unexposed/control group.")],
[cell("Expected event rate\n(Treatment group)"), cell("P₂"), cell("P₁ ± Δ"),
cell("Anticipated incidence in treated group.")],
[cell("Standard Deviation"), cell("σ"), cell("Continuous data only"),
cell("Variability in the outcome measure (from pilot study / literature).")],
[cell("Ratio of groups"), cell("r"), cell("Usually 1:1"),
cell("Ratio of exposed to unexposed (or cases to controls). Affects n per arm.")],
[cell("Side of test\n(Tails)"), cell("—"), cell("Two-tailed (usual)"),
cell("One-tailed only when direction of effect is known a priori.")],
]
param_table = Table(param_data, colWidths=[4.5*cm, 1.5*cm, 3.5*cm, 8.5*cm])
param_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("ROWBACKGROUND",(0,1), (-1,-1), [LTGREY, LTBLUE]*10),
("GRID", (0,0), (-1,-1), 0.5, colors.grey),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
]))
story.append(param_table)
story.append(Spacer(1, 5))
# ── Formulas ───────────────────────────────────────────────────────
story.append(h2("3. SAMPLE SIZE FORMULAS (per group)"))
formula_data = [
[cell("Trial Type", bold=True, color=WHITE),
cell("Formula", bold=True, color=WHITE),
cell("Components / Notes", bold=True, color=WHITE)],
[cell("Comparing TWO MEANS\n(Continuous outcome\ne.g. blood pressure)", bold=True),
cell("n = 2 × [(Zα/2 + Zβ) × σ / Δ]²\n\n= 2 × [(Zα + Zβ) × σ / (μ₁ − μ₂)]²"),
cell("Zα/2 = 1.96 (α=0.05, two-tail)\nZβ = 0.84 (power 80%) or 1.28 (power 90%)\nσ = pooled SD\nΔ = μ₁ − μ₂ (minimum detectable difference)\nLarger σ or smaller Δ → more patients needed")],
[cell("Comparing TWO PROPORTIONS\n(Binary outcome\ne.g. mortality, cure rate)", bold=True),
cell("n = (Zα/2 + Zβ)² × [P₁(1−P₁) + P₂(1−P₂)] / (P₁−P₂)²\n\nOR use:\nn ≈ (Zα/2 + Zβ)² × 2P̄(1−P̄) / (P₁−P₂)²\nwhere P̄ = (P₁+P₂)/2"),
cell("P₁ = event rate in control group\nP₂ = expected event rate in treatment group\nSmaller absolute difference → larger n\nThis is the most common formula in surgical trials")],
[cell("Cohort Study /\nClinical Trial\n(general template)", bold=True),
cell("Components needed:\n① α error (Type I)\n② β error (Type II)\n③ Incidence in unexposed (P₁)\n④ Ratio of exposed:unexposed (r)\n⑤ Minimum detectable RR"),
cell("Use free tools: OpenEpi.com,\nG*Power software,\nor PASS (NCSS)\nAlways consult a biostatistician\nbefore finalising the protocol")],
[cell("Case-Control Study\n(template)", bold=True),
cell("Components needed:\n① α error\n② β error\n③ Prevalence of exposure in controls\n④ Ratio of controls:cases\n⑤ Minimum detectable OR"),
cell("Not a therapeutic trial but listed\nfor completeness\n(Creasy & Resnik 9e, p. 311)")],
]
formula_table = Table(formula_data, colWidths=[4*cm, 7.5*cm, 6.5*cm])
formula_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("BACKGROUND", (0,1), (-1,1), LTBLUE),
("BACKGROUND", (0,2), (-1,2), LTGREY),
("BACKGROUND", (0,3), (-1,3), LTBLUE),
("BACKGROUND", (0,4), (-1,4), LTGREY),
("GRID", (0,0), (-1,-1), 0.5, colors.grey),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 5),
]))
story.append(formula_table)
story.append(Spacer(1, 5))
# ── Z-value table ──────────────────────────────────────────────────
story.append(h2("4. QUICK REFERENCE — Z-VALUES & POWER"))
zval_data = [
[cell("α (significance level)", bold=True, color=WHITE),
cell("Zα/2 (two-tailed)", bold=True, color=WHITE),
cell("Power (1−β)", bold=True, color=WHITE),
cell("Zβ", bold=True, color=WHITE),
cell("Common Combination", bold=True, color=WHITE)],
[cell("0.05 (5%)"), cell("1.96"), cell("80%"), cell("0.84"),
cell("α=0.05, Power=80% → (1.96+0.84)² = 7.84")],
[cell("0.05 (5%)"), cell("1.96"), cell("90%"), cell("1.28"),
cell("α=0.05, Power=90% → (1.96+1.28)² = 10.5")],
[cell("0.01 (1%)"), cell("2.58"), cell("80%"), cell("0.84"),
cell("α=0.01, Power=80% → (2.58+0.84)² = 11.7")],
[cell("0.01 (1%)"), cell("2.58"), cell("90%"), cell("1.28"),
cell("α=0.01, Power=90% → (2.58+1.28)² = 14.9")],
]
zval_table = Table(zval_data, colWidths=[3.5*cm, 3.5*cm, 3*cm, 2.5*cm, 5.5*cm])
zval_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("ROWBACKGROUND",(0,1), (-1,-1), [LTGREY, LTBLUE]*5),
("GRID", (0,0), (-1,-1), 0.5, colors.grey),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0), (-1,-1), 4),
]))
story.append(zval_table)
story.append(Spacer(1, 5))
# ── Memory Aid ─────────────────────────────────────────────────────
story.append(h2("5. MEMORABLE MNEMONIC — \"A BIDE\" (What you need to calculate n)"))
mnemonic_data = [
[cell("A", bold=True, size=14, color=NAVY), cell("Alpha error (α)", bold=True), cell("Type I — False Positive — Set at 0.05")],
[cell("B", bold=True, size=14, color=TEAL), cell("Beta error (β) / Power (1−β)", bold=True), cell("Type II — False Negative — Set at 0.20 → 80% power")],
[cell("I", bold=True, size=14, color=ORANGE), cell("Incidence / Event rate in control (P₁)", bold=True), cell("Baseline rate from literature or pilot study")],
[cell("D", bold=True, size=14, color=RED), cell("Delta (Δ) — Minimum detectable difference", bold=True), cell("Smallest clinically meaningful difference (P₁−P₂ or μ₁−μ₂)")],
[cell("E", bold=True, size=14, color=GREEN), cell("Effect size & SD (σ) for continuous data", bold=True), cell("Variability of measurement; determines width of the formula")],
]
mnem_table = Table(mnemonic_data, colWidths=[1*cm, 7*cm, 10*cm])
mnem_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,-1), LTBLUE),
("ROWBACKGROUND",(0,0), (-1,-1), [LTGREY, LTBLUE]*5),
("GRID", (0,0), (-1,-1), 0.5, colors.grey),
("ALIGN", (0,0), (0,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 5),
]))
story.append(mnem_table)
story.append(Spacer(1, 4))
# ── Footer note ────────────────────────────────────────────────────
story.append(small(
"Key rule: Sample size should always be calculated BEFORE the study begins and reported as part of the study design. "
"In a NEGATIVE study, always check if the study was adequately powered (look for β and power reporting). "
"Practical tools: OpenEpi.com (free, browser-based) · G*Power (free software) · PASS (commercial)."
))
story.append(HRFlowable(width="100%", thickness=0.5, color=NAVY))
story.append(small(
"References: Sabiston Textbook of Surgery 21e — Ch 6 (Outcomes Research) | "
"Schwartz's Principles of Surgery 11e — Ch 51 (Evidence-Based Surgery) | "
"Barash's Clinical Anesthesia 9e — Ch 7 (Statistics) | "
"Creasy & Resnik Maternal-Fetal Medicine 9e — p.311 | "
"Goldman-Cecil Medicine — Ch 8 (Epidemiology)"
))
# ── Build ──────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF saved to {OUTPUT}")
python /tmp/workspace/evidence-pdf/generate_pdf.py 2>&1
python -c "import pdfplumber; pdf=pdfplumber.open('/tmp/workspace/evidence-pdf/Evidence_SampleSize_ClinicalTrials.pdf'); print(f'Pages: {len(pdf.pages)}'); [print(f'Page {i+1}: {len(p.extract_text())} chars') for i,p in enumerate(pdf.pages)]"
Evidence SampleSize ClinicalTrials
PDF Document · PDF
| Quality | Meaning |
|---|---|
| High | Very confident; true effect close to estimated effect; further research very unlikely to change confidence |
| Moderate | Moderately confident; true effect likely close, but possible substantial difference; further research likely to have impact |
| Low | Limited confidence; true effect may be substantially different; further research very likely needed |
| Very Low | Very little confidence; true effect likely substantially different from estimate |
| Factor | Strong Recommendation | Weak Recommendation |
|---|---|---|
| Quality | Many high-quality RCTs (e.g., inhaled steroids in asthma) | Only case series (e.g., pleurodesis in pneumothorax) |
| Balance | Clear benefit, minimal harm (e.g., aspirin in MI) | Small benefit vs significant harm (e.g., warfarin in low-risk AF) |
| Patient values | Uniformly valued outcome | High variability in patient preferences |
[Systematic Review / Meta-analysis] ← Level 1 (top)
[Single well-designed RCT] ← Level 1-2
[Cohort / Controlled study] ← Level 3
[Case-control / Case series] ← Level 4
[Expert opinion] ← Level 5 (base)
| H₀ TRUE (no real difference) | H₀ FALSE (real difference exists) | |
|---|---|---|
| Test says: DIFFERENCE | ❌ Type I error (α) - False Positive | ✅ Correct (Power = 1-β) |
| Test says: NO DIFFERENCE | ✅ Correct | ❌ Type II error (β) - False Negative |
| Letter | Parameter | Conventional Value |
|---|---|---|
| A | Alpha (α) - Type I error | 0.05 (5%) |
| B | Beta (β) / Power (1-β) | β = 0.20 → Power = 80% |
| I | Incidence in control group (P₁) | From literature or pilot study |
| D | Delta (Δ) - Minimum detectable difference | Smallest clinically meaningful difference |
| E | Effect size / SD (σ) | From pilot data; for continuous outcomes |
n per group = 2 × [ (Z_α/2 + Z_β) × σ / Δ ]²
n per group = (Z_α/2 + Z_β)² × [P₁(1-P₁) + P₂(1-P₂)] / (P₁-P₂)²
| α | Z_α/2 | Power | Z_β | Combined (Z_α + Z_β)² |
|---|---|---|---|---|
| 0.05 | 1.96 | 80% | 0.84 | 7.84 |
| 0.05 | 1.96 | 90% | 1.28 | 10.5 |
| 0.01 | 2.58 | 80% | 0.84 | 11.7 |
| 0.01 | 2.58 | 90% | 1.28 | 14.9 |