Chemotherapy drugs used in ent head and neck and their mechanism of action

Reading File
Finding Sources
Finding Sources
Searching PubMed

"head and neck squamous cell carcinoma" AND chemotherapy

Reading File
Reading File
Reading File
Reading File

Chemotherapy Drugs in ENT/Head & Neck Cancer and Their Mechanisms

Chemotherapy in head and neck squamous cell carcinoma (HNSCC) is used mainly for organ preservation (combined with radiotherapy), induction/neoadjuvant shrinkage of bulky disease, and palliation in recurrent/metastatic disease. It has not been shown to significantly improve overall cure rates on its own, but improves locoregional control and reduces distant metastasis when combined with radiotherapy (Scott-Brown's Otorhinolaryngology Head & Neck Surgery, Vol 1, p. ~89-90).

1. Platinum agents (heavy metals) - the backbone of H&N chemo

  • Cisplatin: loses chloride ions intracellularly, then cross-links with DNA (mostly at guanine bases), forming intra- and inter-strand DNA cross-links -> inhibits DNA, RNA, and protein synthesis. It is one of the most active single agents against squamous H&N cancer and is the core drug in nearly all combination regimens (concurrent chemoradiotherapy, induction, and palliative regimens).
  • Carboplatin: same platinum moiety as cisplatin but bonded to an organic carboxylate group - similar DNA cross-linking mechanism, better tolerated (less nephrotoxic/emetogenic), often substituted when cisplatin is contraindicated.
  • Oxaliplatin: platinum complexed with oxalate and a bulky diaminocyclohexane (DACH) group; forms reactive platinum complexes causing inter- and intra-strand DNA cross-links - less commonly used in H&N than in GI cancers.

2. Antimetabolites

  • 5-Fluorouracil (5-FU): converted to its active metabolite 5-FdUMP, which binds and inactivates thymidylate synthetase, blocking DNA synthesis (folinic acid can stabilize this binding). Classically paired with cisplatin (the "PF" regimen) for induction chemotherapy in H&N cancer.
  • Methotrexate: competitively inhibits dihydrofolate reductase, blocking conversion of dihydrofolate to tetrahydrofolate, which is needed for purine, thymidylate, methionine, and glycine synthesis - ultimately halting DNA/RNA synthesis. Used historically as a single agent, particularly in palliative/recurrent settings.

3. Taxanes (spindle poisons)

  • Paclitaxel and Docetaxel: bind tubulin and stabilize microtubules, preventing their normal depolymerization - this arrests cells in mitosis (M phase) and triggers apoptosis. Now commonly added to cisplatin/5-FU as triplet induction regimens (TPF: docetaxel, cisplatin, 5-FU), improving response and organ preservation rates compared to PF alone.

4. Vinca alkaloids (spindle poisons)

  • Vincristine, Vinblastine: bind tubulin building blocks of microtubules, inhibiting microtubule assembly (opposite effect to taxanes but same net result - mitotic arrest). Less central to modern H&N regimens but historically used.

5. Cytotoxic antibiotics

  • Bleomycin: a mixture of glycopeptides that causes direct DNA strand fragmentation - one of the older active single agents in squamous H&N cancer (part of historic regimens).
  • Mitomycin C: inhibits DNA synthesis by cross-linking DNA, acting like an alkylating agent.
  • Anthracyclines (doxorubicin, epirubicin): intercalate into DNA and stabilize the topoisomerase II-DNA complex, preventing re-ligation of DNA strands after cleavage - not a mainstay in H&N but used in some sarcoma/salivary gland protocols.

6. Other agents used

  • Ifosfamide (alkylating agent - forms DNA cross-links via bipolar reactive groups, causing strand breaks and apoptosis, particularly damaging in S phase) and Gemcitabine (pyrimidine antimetabolite) are gaining use in trials, particularly in nasopharyngeal and salivary gland cancers.

Clinical strategy context

  • Induction/neoadjuvant chemotherapy (e.g., TPF or PF) - shrinks tumor bulk before definitive surgery/RT to improve organ preservation, though survival benefit in phase III trials has been inconsistent.
  • Concurrent chemoradiotherapy - typically cisplatin-based, used for locally advanced disease to improve locoregional control.
  • Adjuvant chemotherapy - given post-operatively in high-risk patients; randomized trials show no significant survival benefit (Level 1 evidence).
  • Palliative chemotherapy for recurrent/metastatic disease - median survival ~6-12 months; choice depends on performance status and symptom burden, and now increasingly combined with immune checkpoint inhibitors (pembrolizumab, nivolumab) rather than cytotoxics alone.
Source: Scott-Brown's Otorhinolaryngology Head & Neck Surgery, Vol 1 (Chemotherapy in Head and Neck Cancer, p. 89-91); Scott-Brown's Otorhinolaryngology Head & Neck Surgery (Chemotherapy for Recurrent or Metastatic Head and Neck Cancer, p. 439-440).

Note on evolving evidence

Recent systematic reviews (2025) indicate the field is shifting toward immunotherapy (checkpoint inhibitors) in recurrent/metastatic and even resectable HNSCC, increasingly combined with or replacing traditional cytotoxics [PMID: 41385149, PMID: 40784281]. There's also emerging interest in oral metronomic chemotherapy (low-dose, continuous cytotoxic dosing, e.g., low-dose methotrexate/celecoxib) as a less toxic option in resource-limited or palliative settings [PMID: 40809955]. These don't overturn the platinum/taxane/5-FU backbone described above but reflect where current research is heading - worth flagging if you need the latest management paradigm rather than classic mechanism-of-action teaching.

1,2,3,4

Finding Sources
Finding Sources
Finding Sources
Finding Sources

Deep Dive: Platinum Agents, Antimetabolites, Taxanes, and Vinca Alkaloids

1. Platinum Agents (Heavy Metals)

Cisplatin
  • Mechanism: Once inside the cell, chloride ions are displaced from the molecule, generating a reactive, positively charged platinum complex. This binds covalently to DNA, mostly at the N7 position of guanine, forming both intra-strand and inter-strand cross-links. These cross-links distort the DNA helix and block replication and transcription, ultimately triggering apoptosis (largely p53-dependent).
  • Cell cycle: Not strictly phase-specific, but cells are most vulnerable during S phase when DNA is being copied.
  • Toxicity: Dose-limiting nephrotoxicity (damage to distal convoluted tubule/collecting ducts, mitigated by aggressive hydration), ototoxicity (high-frequency sensorineural hearing loss, tinnitus), peripheral neurotoxicity, and significant nausea/vomiting - Cummings Otolaryngology Head and Neck Surgery, p. ~ (Cisplatin section).
  • Resistance: Increased DNA repair (nucleotide excision repair), increased glutathione/metallothionein detoxification, and reduced drug uptake.
  • H&N role: Backbone of concurrent chemoradiotherapy and induction regimens (PF, TPF); single most active cytotoxic drug in HNSCC.
Carboplatin
  • Mechanism: Same platinum-DNA cross-linking mechanism as cisplatin, but the platinum is bonded to an organic carboxylate (cyclobutanedicarboxylate) group instead of chloride, making it more chemically stable and slower to react with DNA.
  • Toxicity: Dose-limiting toxicity is myelosuppression (especially thrombocytopenia) rather than nephro/ototoxicity - substantially better tolerated than cisplatin, with less nausea, neurotoxicity, and no mandatory pre/post-hydration (Goodman & Gilman's Pharmacological Basis of Therapeutics, "Adverse Effects").
  • H&N role: Substituted for cisplatin in patients with renal impairment, hearing loss, or poor performance status, though generally considered slightly less active against squamous H&N tumors.
Oxaliplatin
  • Platinum complexed with oxalate and a diaminocyclohexane (DACH) group; forms similar inter/intra-strand DNA cross-links. Rarely used in H&N; more relevant to GI malignancies.

2. Antimetabolites

5-Fluorouracil (5-FU)
  • Mechanism: A pyrimidine analogue converted intracellularly to its active form 5-fluoro-2'-deoxyuridine monophosphate (5-FdUMP), which binds and inactivates thymidylate synthetase - the enzyme that converts dUMP to dTMP. This starves the cell of thymidine needed for DNA synthesis ("thymineless death"). Folinic acid (leucovorin) stabilizes this inhibitory complex, potentiating the effect.
  • Cell cycle: S-phase specific, which is why it's usually given as a continuous infusion (rather than a bolus) in H&N regimens to maximize exposure during S phase.
  • H&N role: Combined with cisplatin (PF regimen) as classic induction/concurrent chemotherapy; also used topically/regionally in some skin and mucosal head and neck lesions.
Methotrexate
  • Mechanism: Competitively and reversibly inhibits dihydrofolate reductase (DHFR), blocking regeneration of tetrahydrofolate from dihydrofolate. This starves the cell of one-carbon donors needed for purine synthesis, thymidylate synthesis, and methionine/glycine synthesis - halting DNA and RNA synthesis.
  • Toxicity: Myelosuppression, hepatotoxicity, mucositis/stomatitis, renal toxicity at high doses (crystallizes in renal tubules - requires hydration and urine alkalinization), and pulmonary toxicity. Genetic polymorphisms in MTHFR (C677T, A1298C) increase toxicity risk (Quick Compendium of Clinical Pathology).
  • H&N role: One of the oldest agents with proven single-agent activity in H&N cancer (15-40% response rates); now mainly used in palliative/recurrent settings, often at low weekly doses, and increasingly explored in metronomic (low-dose continuous) protocols.

3. Taxanes (Microtubule Stabilizers)

Paclitaxel and Docetaxel
  • Mechanism: Bind to beta-tubulin and stabilize microtubules against depolymerization. Unlike vinca alkaloids (which prevent microtubule assembly), taxanes lock microtubules in an over-stabilized, non-functional state. This blocks the mitotic spindle from properly segregating chromosomes, arresting cells in the G2/M phase and triggering apoptosis (Fishman's Pulmonary Diseases and Disorders, "Taxanes").
  • Toxicity: Myelosuppression (especially neutropenia), peripheral sensory neuropathy, hypersensitivity reactions (particularly paclitaxel due to its Cremophor vehicle), alopecia, and less commonly pulmonary hypersensitivity toxicity (docetaxel).
  • H&N role: Adding a taxane to cisplatin/5-FU (TPF vs. PF) improved survival in induction chemotherapy trials, but at the cost of significantly higher hematologic and mucosal toxicity - Scott-Brown's Otorhinolaryngology, "Chemotherapy Regimens Used in Induction Chemotherapy," p. ~438. TPF is now a standard induction option in appropriately fit patients with locally advanced disease.

4. Vinca Alkaloids (Microtubule Assembly Inhibitors)

Vincristine and Vinblastine
  • Mechanism: Bind tubulin dimers and inhibit their polymerization into microtubules, preventing mitotic spindle formation and arresting cells in metaphase (M phase), which triggers apoptosis. The same tubulin-binding mechanism also disrupts axonal microtubules in neurons, which underlies their signature neurotoxicity (Bradley and Daroff's Neurology in Clinical Practice, "Vinca Alkaloids").
  • Toxicity: Vincristine is notable for potent, dose-dependent peripheral neurotoxicity (paresthesias progressing to motor weakness, autonomic neuropathy, occasionally cranial neuropathies and ototoxicity) but has minimal myelosuppression. Vinblastine, conversely, is more myelosuppressive but less neurotoxic.
  • H&N role: Historically included in some combination protocols, but their use in modern H&N chemotherapy is limited compared to platinum/taxane/5-FU combinations; more relevant in H&N sarcomas or pediatric H&N malignancies (e.g., rhabdomyosarcoma) than squamous cell carcinoma.

Quick comparison table

Drug classKey mechanismCell cycle specificityDose-limiting toxicityTypical H&N role
CisplatinDNA cross-linking (guanine adducts)Non-specific, S-phase sensitiveNephro/ototoxicityBackbone of chemoRT/induction
CarboplatinSame as cisplatin, less reactiveNon-specificMyelosuppressionSubstitute when cisplatin contraindicated
5-FUThymidylate synthetase inhibitionS-phase specificMucositis, myelosuppressionPaired with cisplatin (PF)
MethotrexateDHFR inhibitionS-phase specificMyelosuppression, hepatotoxicity, mucositisPalliative/recurrent, metronomic
Paclitaxel/DocetaxelMicrotubule stabilizationG2/M arrestNeuropathy, neutropeniaAdded to PF (TPF induction)
Vincristine/VinblastineMicrotubule assembly inhibitionM-phase arrestNeurotoxicity (vincristine), myelosuppression (vinblastine)Sarcomas, limited use in SCC
All mechanism and toxicity details above are drawn from Scott-Brown's Otorhinolaryngology Head & Neck Surgery, Cummings Otolaryngology Head and Neck Surgery, and Goodman & Gilman's Pharmacological Basis of Therapeutics.

Create a comparison table of H&N chemotherapy regimens (PF vs TPF vs concurrent)

Finding Sources
Finding Sources
Searching PubMed

"induction chemotherapy" AND "head and neck" AND TPF

H&N Chemotherapy Regimens: PF vs TPF vs Concurrent Chemoradiotherapy

FeaturePF (Induction)TPF (Induction)Concurrent Chemoradiotherapy
DrugsCisplatin + 5-FluorouracilDocetaxel (or Paclitaxel) + Cisplatin + 5-FluorouracilCisplatin (high-dose q3wk or weekly low-dose) or Carboplatin, given alongside radiotherapy
Typical dosingCisplatin 100 mg/m² day 1; 5-FU continuous infusion (~1000 mg/m²/day) days 1-4/5, repeated q3wk for 2-3 cyclesDocetaxel 75 mg/m² day 1 + Cisplatin 75-100 mg/m² day 1 + 5-FU continuous infusion, q3wk x 3 cycles (TAX 324 / PARADIGM / GORTEC dosing)Cisplatin 100 mg/m² every 21 days x 3 cycles (standard high-dose) OR weekly cisplatin/carboplatin at lower doses, concurrent with daily RT over 6-7 weeks
Mechanism basis5-FU blocks thymidylate synthetase (S-phase); cisplatin forms DNA cross-links (non-phase-specific)Adds taxane (microtubule stabilization, G2/M arrest) on top of PF's mechanisms - broader cell-kill across cycle phasesCisplatin's radiosensitizing effect (impairs DNA repair of radiation-induced damage) combined with direct cytotoxicity
Setting/goalInduction before definitive RT/surgery - cytoreduction, organ preservation, assess chemosensitivityInduction before definitive RT/surgery - more potent cytoreduction than PFDefinitive or adjuvant treatment - given as primary curative-intent therapy or post-op in high-risk patients
Response rates~59% overall response in GORTEC trial~80% overall response (GORTEC); superior to PFN/A (not primarily measured by induction response; measured by locoregional control/survival)
Survival outcomeInferior to TPF (5-yr survival ~42% in GORTEC-type trial)Superior to PF: 5-yr survival ~52% vs 42% (GORTEC); improved larynx preservation ratesConfirmed absolute survival benefit of ~6.5% at 5 years when added to RT (meta-analysis level evidence) - current standard of care for locally advanced unresectable disease
Organ preservationEffective, but less than TPFSuperior larynx/hypopharynx preservation vs PF, without increased rates of feeding tubes or tracheostomyAlso achieves organ preservation but as primary approach (avoids surgery altogether in many larynx/hypopharynx protocols)
Toxicity profileSignificant myelosuppression, mucositis, nausea; better tolerated than TPFHigher toxicity than PF - increased hematologic toxicity (neutropenia, febrile neutropenia) and mucositis; requires growth factor support in many protocolsHigh-dose cisplatin: nephro/ototoxicity, severe mucositis, requires hydration; weekly regimens better tolerated but may sacrifice some efficacy
SequencingFollowed by RT alone, surgery, or concurrent chemoRTFollowed by concurrent chemoRT (usually with weekly carboplatin) or RT aloneGiven as single continuous course; no separate induction phase
Key supporting trialsGORTEC comparator arm; classic regimen predating taxane eraTAX 324, GORTEC, PARADIGM trialsMeta-analysis of chemoradiotherapy trials (MACH-NC); multiple RTOG trials establishing cisplatin-RT as standard
Current roleLargely superseded by TPF where induction is chosen; still used when taxane toxicity is a concernPreferred induction regimen in fit patients considered for organ preservation, though with careful selection given added toxicityStandard of care for locally advanced, unresectable HNSCC and as adjuvant treatment in high-risk post-surgical patients

Key clinical takeaways

  • TPF outperforms PF as an induction regimen: the GORTEC randomized trial in laryngeal/hypopharyngeal cancer showed TPF achieved higher response rates (80% vs 59%) and superior 5-year survival (52% vs 42%) compared to PF, without increasing feeding-tube or tracheostomy rates - Scott-Brown's Otorhinolaryngology Head & Neck Surgery, p. ~437-438. The TAX 324 trial corroborated this survival advantage in a broader locally advanced population - Cummings Otolaryngology Head and Neck Surgery, "Induction Chemotherapy."
  • Concurrent chemoradiotherapy remains the overall standard of care for locally advanced, unresectable HNSCC, with a confirmed absolute survival benefit of about 6.5% at 5 years - Scott-Brown's Otorhinolaryngology Head & Neck Surgery, "Key Points," p. 442.
  • Sequential therapy (induction TPF -> concurrent chemoRT) vs. concurrent chemoRT alone: The PARADIGM trial tested this head-to-head and found no significant survival difference between the two strategies, suggesting induction chemotherapy adds toxicity without a clear survival edge over chemoRT alone in unselected patients - Cummings Otolaryngology Head and Neck Surgery, "Induction Chemotherapy," p. ~ (PARADIGM trial discussion).
  • Toxicity trade-off: Adding docetaxel to PF (making TPF) meaningfully increases hematologic toxicity and mucositis, which is the main reason TPF hasn't universally replaced PF or concurrent chemoRT as first-line therapy - patient selection (performance status, organ function, ability to tolerate triplet therapy) is critical.

Recent evidence signal (2025)

A 2025 systematic review/meta-analysis specifically comparing TPF vs. PF induction (both followed by concurrent cisplatin chemoradiotherapy) in locoregionally advanced nasopharyngeal carcinoma is available and may refine site-specific conclusions beyond the laryngeal/hypopharyngeal data cited above [PMID: 39833074]. If you're focusing on nasopharyngeal disease specifically, this paper is worth a closer look since NPC has a different chemosensitivity profile than oral cavity/laryngeal SCC.

Make a comparison poster: organ preservation outcomes across all three regimens

Finding Sources
Finding Sources
Generating Image

A medical education poster titled "Organ Preservation Outcomes in Head & Neck Cancer Chemotherapy Regimens: PF vs TPF vs Concurrent Chemoradiotherapy". The poster should present a clear comparison table/infographic with these regimens as columns: "PF (Induction: Cisplatin + 5-FU)", "TPF (Induction: Docetaxel + Cisplatin + 5-FU)", and "Concurrent Chemoradiotherapy (Cisplatin + RT)". Include rows comparing: Larynx/Organ Preservation Rate (RTOG 91-11 trial: RT alone 70%, Induction PF 75%, Concurrent CRT 88%; EORTC/GORTEC TPF vs PF trial: PF 60%, TPF 80%), Overall Response Rate (PF 61%, TPF 83%), Locoregional Control Rate (Induction PF 61%, Concurrent CRT 78%), 5-Year Overall Survival (PF 42-54%, TPF 52%, Concurrent CRT 54-56%), and Severe/High-Grade Toxicity Rate (Concurrent CRT 82%, higher hematologic toxicity with TPF, moderate toxicity with PF). Include a bar chart visualizing the larynx preservation percentages across the three regimens. Add small citation notes referencing RTOG 91-11 trial and EORTC 24971/TAX 324 trial. Include a brief text box summarizing key takeaway: concurrent chemoradiotherapy achieves the highest organ preservation and locoregional control but with the highest toxicity, while TPF induction improves outcomes over PF induction alone. Use head and neck anatomy icons (larynx, throat) as visual accents.

Here's the comparison poster on organ preservation outcomes across the three head & neck chemotherapy regimens:
Organ Preservation Outcomes Poster

Key data behind the poster

MetricPF (Induction)TPF (Induction)Concurrent Chemoradiotherapy
Larynx/organ preservation rate~60-75% (RTOG 91-11 induction arm: 75%; EORTC/GORTEC comparator: lower than TPF)~80% (superior to PF in head-to-head trials)~88% (highest among the three - RTOG 91-11)
Overall response rate~61%~83%N/A (not an induction endpoint)
Locoregional control~61%Improved vs PF~78% (highest)
5-year overall survival~42-54%~52%~54-56% (similar across RTOG 91-11 arms)
Severe/high-grade toxicityModerate (myelosuppression, mucositis)Higher (added neutropenia/mucositis from taxane)Highest (~82%) - trade-off for best organ preservation

Interpretation

The RTOG 91-11 trial (RT alone vs. induction PF + RT vs. concurrent cisplatin-chemoradiotherapy) established that concurrent chemoradiotherapy gives the best larynx preservation and locoregional control, but at the cost of the highest rate of severe acute/late toxicity (82%) - Cummings Otolaryngology Head and Neck Surgery, "Nonsurgical Treatment of Advanced Laryngeal Cancer," p. ~ and "Laryngeal Trials and Concomitant Chemoradiation," p. ~.
Separately, when comparing induction regimens head-to-head, TPF outperforms PF on response rate, larynx preservation, and 5-year survival, making TPF the preferred induction choice when induction is selected as the strategy (before either RT alone or concurrent chemoRT) - Cummings Otolaryngology Head and Neck Surgery, "Laryngeal Trials and Concomitant Chemoradiation," p. ~199.
Overall survival tends to converge across strategies (~54-56% at 5 years), meaning the real differentiator between regimens is the trade-off between organ preservation/locoregional control and toxicity burden, not overall survival itself - this is the central teaching point of RTOG 91-11 and subsequent trials.

Create a quick reference PDF guide for H&N chemotherapy regimens

Reading File
Reading File
Browsing Directory

/tmp/skills/pdf

Running Command

mkdir -p /tmp/workspace/hn-chemo-guide && ls -la /tmp/workspace/

Writing File

~/hn-chemo-guide/build_guide.py

#!/usr/bin/env python3
"""
Quick Reference PDF Guide: Head & Neck Chemotherapy Regimens
"""
from reportlab.lib.pagesizes import letter
from reportlab.lib import colors
from reportlab.lib.units import inch
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    PageBreak, HRFlowable, ListFlowable, ListItem
)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT

OUT = "/tmp/workspace/hn-chemo-guide/HN_Chemotherapy_Quick_Reference_Guide.pdf"

doc = SimpleDocTemplate(
    OUT, pagesize=letter,
    topMargin=0.55*inch, bottomMargin=0.55*inch,
    leftMargin=0.55*inch, rightMargin=0.55*inch,
    title="H&N Chemotherapy Quick Reference Guide"
)

styles = getSampleStyleSheet()

title_style = ParagraphStyle('TitleC', parent=styles['Title'], fontSize=20, textColor=colors.HexColor('#0B3D66'), spaceAfter=4, alignment=TA_CENTER)
subtitle_style = ParagraphStyle('Subtitle', parent=styles['Normal'], fontSize=11, textColor=colors.HexColor('#555555'), alignment=TA_CENTER, spaceAfter=14)
h1 = ParagraphStyle('H1', parent=styles['Heading1'], fontSize=14, textColor=colors.white, backColor=colors.HexColor('#0B3D66'), spaceBefore=10, spaceAfter=8, leftIndent=6, borderPadding=(4,4,4,4))
h2 = ParagraphStyle('H2', parent=styles['Heading2'], fontSize=11.5, textColor=colors.HexColor('#0B3D66'), spaceBefore=8, spaceAfter=4)
body = ParagraphStyle('Body', parent=styles['Normal'], fontSize=9, leading=12)
small = ParagraphStyle('Small', parent=styles['Normal'], fontSize=8, leading=10, textColor=colors.HexColor('#444444'))
cite = ParagraphStyle('Cite', parent=styles['Normal'], fontSize=7.5, leading=9.5, textColor=colors.HexColor('#666666'), spaceBefore=4)
takeaway_style = ParagraphStyle('Takeaway', parent=styles['Normal'], fontSize=9, leading=12, textColor=colors.HexColor('#0B3D66'))

def section_header(text):
    return Paragraph(text, h1)

def make_table(data, col_widths=None, header_bg='#0B3D66', font_size=8, align_first_left=True, zebra=True):
    t = Table(data, colWidths=col_widths, repeatRows=1)
    style_cmds = [
        ('BACKGROUND', (0,0), (-1,0), colors.HexColor(header_bg)),
        ('TEXTCOLOR', (0,0), (-1,0), colors.white),
        ('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE', (0,0), (-1,-1), font_size),
        ('GRID', (0,0), (-1,-1), 0.5, colors.HexColor('#BBBBBB')),
        ('VALIGN', (0,0), (-1,-1), 'TOP'),
        ('LEFTPADDING', (0,0), (-1,-1), 4),
        ('RIGHTPADDING', (0,0), (-1,-1), 4),
        ('TOPPADDING', (0,0), (-1,-1), 3),
        ('BOTTOMPADDING', (0,0), (-1,-1), 3),
    ]
    if align_first_left:
        style_cmds.append(('ALIGN', (0,1), (0,-1), 'LEFT'))
        style_cmds.append(('FONTNAME', (0,1), (0,-1), 'Helvetica-Bold'))
    if zebra:
        for i in range(1, len(data)):
            if i % 2 == 0:
                style_cmds.append(('BACKGROUND', (0,i), (-1,i), colors.HexColor('#F2F6FA')))
    t.setStyle(TableStyle(style_cmds))
    return t

story = []

# ===== TITLE =====
story.append(Paragraph("Head & Neck Chemotherapy", title_style))
story.append(Paragraph("Quick Reference Guide", title_style))
story.append(Paragraph("Drug Mechanisms  |  Regimen Comparison  |  Organ Preservation Outcomes  |  Toxicity", subtitle_style))
story.append(HRFlowable(width="100%", thickness=1, color=colors.HexColor('#0B3D66')))
story.append(Spacer(1, 10))

# ===== SECTION 1: DRUG CLASSES =====
story.append(section_header("1. Core Chemotherapy Drug Classes & Mechanisms"))
drug_data = [
    ["Class", "Key Agents", "Mechanism of Action", "Dose-Limiting Toxicity"],
    ["Platinum agents", "Cisplatin, Carboplatin",
     "DNA cross-linking (guanine N7 adducts) -> blocks DNA/RNA/protein synthesis",
     "Cisplatin: nephro-/ototoxicity. Carboplatin: myelosuppression"],
    ["Antimetabolites", "5-Fluorouracil (5-FU), Methotrexate",
     "5-FU: inhibits thymidylate synthetase (S-phase). MTX: inhibits dihydrofolate reductase, blocks folate-dependent DNA/RNA synthesis",
     "Mucositis, myelosuppression, hepatotoxicity (MTX)"],
    ["Taxanes", "Docetaxel, Paclitaxel",
     "Stabilize microtubules against depolymerization -> G2/M mitotic arrest",
     "Neutropenia, peripheral neuropathy, hypersensitivity"],
    ["Vinca alkaloids", "Vincristine, Vinblastine",
     "Inhibit tubulin polymerization -> block microtubule assembly -> M-phase arrest",
     "Vincristine: neurotoxicity. Vinblastine: myelosuppression"],
    ["Cytotoxic antibiotics", "Bleomycin, Mitomycin C",
     "Bleomycin: DNA strand fragmentation. Mitomycin C: DNA cross-linking",
     "Pulmonary fibrosis (bleomycin), myelosuppression"],
]
story.append(make_table(drug_data, col_widths=[1.1*inch, 1.3*inch, 3.0*inch, 1.7*inch]))
story.append(Spacer(1, 10))

# ===== SECTION 2: REGIMEN COMPARISON =====
story.append(section_header("2. Regimen Comparison: PF vs TPF vs Concurrent Chemoradiotherapy"))
regimen_data = [
    ["Feature", "PF (Induction)", "TPF (Induction)", "Concurrent Chemoradiotherapy"],
    ["Drugs", "Cisplatin + 5-FU", "Docetaxel + Cisplatin + 5-FU", "Cisplatin (high-dose q3wk or weekly) +/- Carboplatin, with RT"],
    ["Typical dosing", "Cisplatin 100 mg/m2 D1; 5-FU CI ~1000 mg/m2/d D1-4/5; q3wk x2-3 cycles",
     "Docetaxel 75 mg/m2 D1 + Cisplatin 75-100 mg/m2 D1 + 5-FU CI; q3wk x3 cycles",
     "Cisplatin 100 mg/m2 q21d x3 cycles OR weekly low-dose; concurrent with daily RT x6-7 wks"],
    ["Goal / setting", "Cytoreduction before RT/surgery; organ preservation",
     "More potent cytoreduction than PF before definitive RT/surgery",
     "Primary curative-intent or adjuvant treatment (definitive or post-op high-risk)"],
    ["Response rate", "~61%", "~83% (superior to PF)", "N/A (not an induction endpoint)"],
    ["Larynx / organ preservation", "~75% (RTOG 91-11 induction arm)", "~80% (superior to PF)", "~88% (highest; RTOG 91-11)"],
    ["Locoregional control", "~61%", "Improved vs PF", "~78% (highest)"],
    ["5-year overall survival", "~42-54%", "~52%", "~54-56%"],
    ["Severe/high-grade toxicity", "Moderate (myelosuppression, mucositis)", "Higher (added neutropenia/mucositis)", "Highest (~82%) - trade-off for best preservation"],
    ["Current role", "Superseded by TPF where induction chosen; used if taxane risk high",
     "Preferred induction in fit patients selected for organ preservation",
     "Standard of care for locally advanced unresectable HNSCC; adjuvant in high-risk post-op"],
]
story.append(make_table(regimen_data, col_widths=[1.3*inch, 1.7*inch, 1.9*inch, 2.2*inch], font_size=7.6))
story.append(Paragraph(
    "Sources: GORTEC (TPF vs PF, laryngeal/hypopharyngeal), TAX 324/EORTC 24971, RTOG 91-11 (3-arm laryngeal preservation trial), "
    "Cummings Otolaryngology Head and Neck Surgery; Scott-Brown's Otorhinolaryngology Head & Neck Surgery.", cite))
story.append(Spacer(1, 8))

story.append(PageBreak())

# ===== SECTION 3: ORGAN PRESERVATION DEEP DIVE (RTOG 91-11) =====
story.append(section_header("3. Organ Preservation Outcomes - RTOG 91-11 (3-Arm Laryngeal Trial)"))
rtog_data = [
    ["Arm", "Larynx Preservation", "Locoregional Control", "5-yr Overall Survival", "Severe Toxicity"],
    ["RT alone", "70%", "56%", "54-56%", "Lowest of the three"],
    ["Induction PF -> RT", "75%", "61%", "54-56%", "Moderate"],
    ["Concurrent Cisplatin + RT", "88% (highest)", "78% (highest)", "54-56% (similar across arms)", "82% (highest)"],
]
story.append(make_table(rtog_data, col_widths=[1.7*inch, 1.5*inch, 1.5*inch, 1.6*inch, 1.6*inch], font_size=8))
story.append(Spacer(1, 8))

story.append(section_header("4. TPF vs PF - Induction Head-to-Head (GORTEC / TAX 324)"))
tpf_pf_data = [
    ["Endpoint", "PF", "TPF"],
    ["Overall response rate", "59-61%", "80-83%"],
    ["Larynx preservation rate", "~57-60%", "~80%"],
    ["5-year overall survival", "42%", "52%"],
    ["Feeding tube / tracheostomy rate", "Baseline", "Not increased vs PF despite higher response"],
]
story.append(make_table(tpf_pf_data, col_widths=[2.5*inch, 2.4*inch, 2.4*inch], font_size=8.5))
story.append(Spacer(1, 10))

# ===== SECTION 5: KEY TAKEAWAYS =====
story.append(section_header("5. Key Clinical Takeaways"))
takeaways = [
    "Concurrent cisplatin-chemoradiotherapy gives the highest larynx preservation (88%) and locoregional control (78%) of any single strategy, but carries the highest toxicity burden (82% severe acute/late effects) - RTOG 91-11.",
    "5-year overall survival is similar across RT alone, induction PF, and concurrent CRT (~54-56%) - the real differentiator between strategies is organ preservation and toxicity, not survival.",
    "When induction chemotherapy is chosen as the strategy, TPF is superior to PF: higher response rate (83% vs 61%), better larynx preservation (~80% vs ~60%), and improved 5-year survival (52% vs 42%) - without increasing feeding-tube or tracheostomy rates.",
    "TPF carries greater hematologic toxicity (neutropenia, febrile neutropenia) and mucositis than PF - patient selection (performance status, renal/hearing function, ability to tolerate triplet chemo) is critical.",
    "Sequential therapy (induction TPF followed by concurrent chemoRT) has not shown a clear survival advantage over concurrent chemoRT alone in randomized comparison (PARADIGM trial) - added toxicity without proven benefit in unselected patients.",
    "Carboplatin is substituted for cisplatin when renal impairment, hearing loss, or poor tolerance is a concern, at the cost of somewhat reduced radiosensitizing potency.",
]
bullets = ListFlowable(
    [ListItem(Paragraph(t, body), bulletColor=colors.HexColor('#0B3D66')) for t in takeaways],
    bulletType='bullet', start='circle', leftIndent=14
)
story.append(bullets)
story.append(Spacer(1, 10))

# ===== SECTION 6: TOXICITY QUICK-CHECK =====
story.append(section_header("6. Toxicity Quick-Check by Agent"))
tox_data = [
    ["Agent", "Watch For", "Monitoring"],
    ["Cisplatin", "Nephrotoxicity, ototoxicity, peripheral neuropathy, severe nausea", "Creatinine/CrCl, audiology, Mg/electrolytes, aggressive hydration"],
    ["Carboplatin", "Myelosuppression (thrombocytopenia), hypersensitivity", "CBC, platelet count"],
    ["5-Fluorouracil", "Mucositis, diarrhea, myelosuppression, cardiotoxicity (rare)", "Oral exam, CBC, DPD deficiency screen if available"],
    ["Methotrexate", "Myelosuppression, hepatotoxicity, mucositis, renal toxicity (high dose)", "CBC, LFTs monthly, hydration/urine alkalinization for high dose"],
    ["Docetaxel/Paclitaxel", "Neutropenia, peripheral neuropathy, hypersensitivity, fluid retention (docetaxel)", "CBC with differential, neuro exam, premedication for hypersensitivity"],
]
story.append(make_table(tox_data, col_widths=[1.6*inch, 3.1*inch, 2.4*inch], font_size=8))
story.append(Spacer(1, 8))

story.append(HRFlowable(width="100%", thickness=0.7, color=colors.HexColor('#0B3D66')))
story.append(Paragraph(
    "This guide is a teaching summary compiled from Scott-Brown's Otorhinolaryngology Head & Neck Surgery, "
    "Cummings Otolaryngology Head and Neck Surgery, K J Lee's Essential Otolaryngology, and Goodman & Gilman's "
    "Pharmacological Basis of Therapeutics, supplemented by RTOG 91-11, GORTEC, and TAX 324/EORTC 24971 trial data. "
    "Not a substitute for institutional protocols or current oncology guidelines - verify dosing and eligibility "
    "against up-to-date clinical trial/NCCN sources before clinical use.", cite))

doc.build(story)
print("PDF created at", OUT)
Running Command

cd /tmp/workspace/hn-chemo-guide && python3 build_guide.py

Running Command

cd /tmp/workspace/hn-chemo-guide && python3 -c " from pypdf import PdfReader r = PdfReader('HN_Chemotherapy_Quick_Reference_Guide.pdf') print('Pages:', len(r.pages)) for i,p in enumerate(r.pages): print(f'--- page {i+1} ---') print(p.extract_text()[:300]) " ls -la /tmp/workspace/hn-chemo-guide/

The quick reference PDF guide is ready:

HN Chemotherapy Quick Reference Guide

PDF Document · PDF

Contents (2 pages):
  1. Core Drug Classes & Mechanisms - platinum agents, antimetabolites, taxanes, vinca alkaloids, cytotoxic antibiotics with mechanism and dose-limiting toxicity for each
  2. PF vs TPF vs Concurrent Chemoradiotherapy comparison table - drugs, dosing, response rates, organ preservation, locoregional control, 5-yr survival, toxicity, current clinical role
  3. RTOG 91-11 breakdown - the 3-arm trial (RT alone vs induction PF vs concurrent cisplatin-RT) with exact larynx preservation/locoregional control/survival/toxicity figures
  4. TPF vs PF head-to-head (GORTEC/TAX 324 data)
  5. Key clinical takeaways - bulleted high-yield points (e.g., survival is similar across strategies, so organ preservation/toxicity is the true differentiator)
  6. Toxicity quick-check table by agent with monitoring parameters
All content is sourced from Scott-Brown's Otorhinolaryngology Head & Neck Surgery, Cummings Otolaryngology Head and Neck Surgery, K J Lee's Essential Otolaryngology, and Goodman & Gilman's Pharmacological Basis of Therapeutics, plus RTOG 91-11 / GORTEC / TAX 324 trial data referenced earlier in our conversation. A disclaimer note is included recommending verification against current institutional/NCCN protocols before clinical use.

Pdf is not created nicely

Writing File

~/hn-chemo-guide/build_guide.py

#!/usr/bin/env python3
"""
Quick Reference PDF Guide: Head & Neck Chemotherapy Regimens
Redesigned for clean, consistent, non-overflowing layout.
"""
from reportlab.lib.pagesizes import letter
from reportlab.lib import colors
from reportlab.lib.units import inch
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    PageBreak, HRFlowable, ListFlowable, ListItem, Frame, BaseDocTemplate,
    PageTemplate
)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT

OUT = "/tmp/workspace/hn-chemo-guide/HN_Chemotherapy_Quick_Reference_Guide.pdf"

PAGE_W, PAGE_H = letter
MARGIN = 0.6 * inch
USABLE_W = PAGE_W - 2 * MARGIN  # ~7.3in

NAVY = colors.HexColor('#0B3D66')
NAVY_LIGHT = colors.HexColor('#E7EEF5')
ACCENT = colors.HexColor('#C0392B')
GREY = colors.HexColor('#555555')
ROW_ALT = colors.HexColor('#F4F7FA')
GRID_COLOR = colors.HexColor('#C9D3DC')

styles = getSampleStyleSheet()

title_style = ParagraphStyle('TitleC', parent=styles['Title'], fontName='Helvetica-Bold',
                              fontSize=22, textColor=NAVY, alignment=TA_CENTER, spaceAfter=2)
subtitle_style = ParagraphStyle('Subtitle', parent=styles['Normal'], fontName='Helvetica',
                                 fontSize=10.5, textColor=GREY, alignment=TA_CENTER, spaceAfter=2)
banner_text_style = ParagraphStyle('BannerText', parent=styles['Normal'], fontName='Helvetica-Bold',
                                    fontSize=12.5, textColor=colors.white, leading=15)
body = ParagraphStyle('Body', parent=styles['Normal'], fontName='Helvetica', fontSize=8.6, leading=11.2)
body_bold = ParagraphStyle('BodyBold', parent=body, fontName='Helvetica-Bold', textColor=NAVY)
head_cell = ParagraphStyle('HeadCell', parent=styles['Normal'], fontName='Helvetica-Bold',
                            fontSize=8.6, leading=11, textColor=colors.white)
cite = ParagraphStyle('Cite', parent=styles['Normal'], fontName='Helvetica-Oblique', fontSize=7.6,
                       leading=10, textColor=GREY, spaceBefore=6)
takeaway_body = ParagraphStyle('TakeawayBody', parent=body, fontSize=9, leading=12.5)
footer_style = ParagraphStyle('Footer', parent=styles['Normal'], fontSize=7.5, textColor=GREY)


def banner(text):
    """Full-width colored section banner using a 1x1 table (reliable background rendering)."""
    p = Paragraph(text, banner_text_style)
    t = Table([[p]], colWidths=[USABLE_W])
    t.setStyle(TableStyle([
        ('BACKGROUND', (0, 0), (-1, -1), NAVY),
        ('LEFTPADDING', (0, 0), (-1, -1), 8),
        ('RIGHTPADDING', (0, 0), (-1, -1), 8),
        ('TOPPADDING', (0, 0), (-1, -1), 5),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 5),
    ]))
    return t


def cell(text, style=body):
    return Paragraph(text, style)


def make_table(rows, col_widths, header_style=head_cell, body_style=body,
               first_col_bold=True, font_size=None):
    """Build a table where every cell is a Paragraph (reliable wrapping, no overflow)."""
    assert abs(sum(col_widths) - USABLE_W) < 0.05 * inch, \
        f"Column widths sum {sum(col_widths)/inch:.2f}in != usable width {USABLE_W/inch:.2f}in"

    data = []
    header_row = [Paragraph(h, header_style) for h in rows[0]]
    data.append(header_row)
    for r in rows[1:]:
        row_cells = []
        for idx, val in enumerate(r):
            if idx == 0 and first_col_bold:
                row_cells.append(Paragraph(val, body_bold))
            else:
                row_cells.append(Paragraph(val, body_style))
        data.append(row_cells)

    t = Table(data, colWidths=col_widths, repeatRows=1)
    style_cmds = [
        ('BACKGROUND', (0, 0), (-1, 0), NAVY),
        ('GRID', (0, 0), (-1, -1), 0.6, GRID_COLOR),
        ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
        ('LEFTPADDING', (0, 0), (-1, -1), 5),
        ('RIGHTPADDING', (0, 0), (-1, -1), 5),
        ('TOPPADDING', (0, 0), (-1, -1), 4),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 4),
    ]
    for i in range(1, len(data)):
        if i % 2 == 0:
            style_cmds.append(('BACKGROUND', (0, i), (-1, i), ROW_ALT))
    t.setStyle(TableStyle(style_cmds))
    return t


# ---------- Page decoration (header rule + footer with page number) ----------
def draw_page_decoration(canvas, doc_):
    canvas.saveState()
    # Footer rule
    canvas.setStrokeColor(GRID_COLOR)
    canvas.setLineWidth(0.5)
    canvas.line(MARGIN, 0.5 * inch, PAGE_W - MARGIN, 0.5 * inch)
    # Footer text
    canvas.setFont('Helvetica', 7.5)
    canvas.setFillColor(GREY)
    canvas.drawString(MARGIN, 0.34 * inch, "H&N Chemotherapy Quick Reference Guide")
    canvas.drawRightString(PAGE_W - MARGIN, 0.34 * inch, f"Page {doc_.page}")
    canvas.restoreState()


doc = BaseDocTemplate(
    OUT, pagesize=letter,
    topMargin=MARGIN, bottomMargin=0.7 * inch,
    leftMargin=MARGIN, rightMargin=MARGIN,
    title="H&N Chemotherapy Quick Reference Guide"
)
frame = Frame(MARGIN, 0.7 * inch, USABLE_W, PAGE_H - MARGIN - 0.7 * inch, id='normal')
doc.addPageTemplates([PageTemplate(id='main', frames=[frame], onPage=draw_page_decoration)])

story = []

# ===== TITLE BLOCK =====
story.append(Spacer(1, 4))
story.append(Paragraph("Head &amp; Neck Chemotherapy", title_style))
story.append(Paragraph("Quick Reference Guide", title_style))
story.append(Spacer(1, 4))
story.append(Paragraph(
    "Drug Mechanisms&nbsp;&nbsp;|&nbsp;&nbsp;Regimen Comparison&nbsp;&nbsp;|&nbsp;&nbsp;"
    "Organ Preservation Outcomes&nbsp;&nbsp;|&nbsp;&nbsp;Toxicity", subtitle_style))
story.append(Spacer(1, 6))
story.append(HRFlowable(width="100%", thickness=1.4, color=NAVY))
story.append(Spacer(1, 12))

# ===== SECTION 1: DRUG CLASSES =====
story.append(banner("1. Core Chemotherapy Drug Classes &amp; Mechanisms"))
story.append(Spacer(1, 6))
drug_rows = [
    ["Class", "Key Agents", "Mechanism of Action", "Dose-Limiting Toxicity"],
    ["Platinum agents", "Cisplatin, Carboplatin",
     "DNA cross-linking at guanine N7 &#8594; blocks DNA/RNA/protein synthesis",
     "Cisplatin: nephro-/ototoxicity. Carboplatin: myelosuppression"],
    ["Antimetabolites", "5-Fluorouracil, Methotrexate",
     "5-FU inhibits thymidylate synthetase (S-phase). Methotrexate inhibits dihydrofolate reductase, blocking folate-dependent DNA/RNA synthesis",
     "Mucositis, myelosuppression, hepatotoxicity (MTX)"],
    ["Taxanes", "Docetaxel, Paclitaxel",
     "Stabilize microtubules against depolymerization &#8594; G2/M mitotic arrest",
     "Neutropenia, peripheral neuropathy, hypersensitivity"],
    ["Vinca alkaloids", "Vincristine, Vinblastine",
     "Inhibit tubulin polymerization &#8594; block microtubule assembly &#8594; M-phase arrest",
     "Vincristine: neurotoxicity. Vinblastine: myelosuppression"],
    ["Cytotoxic antibiotics", "Bleomycin, Mitomycin C",
     "Bleomycin causes DNA strand fragmentation; Mitomycin C cross-links DNA",
     "Pulmonary fibrosis (bleomycin), myelosuppression"],
]
story.append(make_table(drug_rows, col_widths=[1.1*inch, 1.35*inch, 3.15*inch, 1.7*inch]))
story.append(Spacer(1, 14))

# ===== SECTION 2: REGIMEN COMPARISON =====
story.append(banner("2. Regimen Comparison: PF vs TPF vs Concurrent Chemoradiotherapy"))
story.append(Spacer(1, 6))
regimen_rows = [
    ["Feature", "PF (Induction)", "TPF (Induction)", "Concurrent CRT"],
    ["Drugs", "Cisplatin + 5-FU",
     "Docetaxel + Cisplatin + 5-FU",
     "Cisplatin (or carboplatin) given with radiotherapy"],
    ["Typical dosing", "Cisplatin 100 mg/m&#178; D1; 5-FU CI ~1000 mg/m&#178;/day D1-4/5; q3wk x2-3 cycles",
     "Docetaxel 75 mg/m&#178; D1 + Cisplatin 75-100 mg/m&#178; D1 + 5-FU CI; q3wk x3 cycles",
     "Cisplatin 100 mg/m&#178; q21d x3 cycles, or weekly low-dose, concurrent with daily RT x6-7 wks"],
    ["Goal / setting", "Cytoreduction before RT/surgery; organ preservation",
     "More potent cytoreduction than PF before definitive RT/surgery",
     "Primary curative-intent or adjuvant treatment"],
    ["Response rate", "~61%", "~83% (superior to PF)", "N/A (not an induction endpoint)"],
    ["Organ preservation", "~75% (RTOG 91-11 induction arm)", "~80% (superior to PF)", "~88% (highest)"],
    ["Locoregional control", "~61%", "Improved vs PF", "~78% (highest)"],
    ["5-yr overall survival", "~42-54%", "~52%", "~54-56%"],
    ["Severe toxicity", "Moderate", "Higher than PF", "Highest (~82%)"],
]
story.append(make_table(regimen_rows, col_widths=[1.3*inch, 1.9*inch, 1.95*inch, 2.15*inch], font_size=7.8))
story.append(Spacer(1, 6))
story.append(Paragraph(
    "Sources: GORTEC (TPF vs PF), TAX 324 / EORTC 24971, RTOG 91-11; Cummings Otolaryngology Head and Neck "
    "Surgery; Scott-Brown's Otorhinolaryngology Head &amp; Neck Surgery.", cite))

story.append(PageBreak())

# ===== SECTION 3: RTOG 91-11 =====
story.append(banner("3. Organ Preservation Outcomes &#8212; RTOG 91-11 (3-Arm Laryngeal Trial)"))
story.append(Spacer(1, 6))
rtog_rows = [
    ["Arm", "Organ (Larynx) Preservation", "Locoregional Control", "5-yr Overall Survival", "Severe Toxicity"],
    ["RT alone", "70%", "56%", "54-56%", "Lowest of the three arms"],
    ["Induction PF &#8594; RT", "75%", "61%", "54-56%", "Moderate"],
    ["Concurrent Cisplatin + RT", "88% (highest)", "78% (highest)", "54-56% (similar across arms)", "82% (highest)"],
]
story.append(make_table(rtog_rows, col_widths=[1.55*inch, 1.55*inch, 1.4*inch, 1.5*inch, 1.3*inch], font_size=7.6))
story.append(Spacer(1, 4))
story.append(Paragraph(
    "Key point: overall survival is statistically similar across all three arms &#8212; concurrent chemoradiotherapy "
    "wins on organ preservation and locoregional control, not on survival, and this benefit comes at the cost of "
    "the highest toxicity.", cite))
story.append(Spacer(1, 14))

# ===== SECTION 4: TPF vs PF =====
story.append(banner("4. TPF vs PF &#8212; Induction Head-to-Head (GORTEC / TAX 324)"))
story.append(Spacer(1, 6))
tpf_pf_rows = [
    ["Endpoint", "PF", "TPF"],
    ["Overall response rate", "59-61%", "80-83%"],
    ["Larynx preservation rate", "~57-60%", "~80%"],
    ["5-year overall survival", "42%", "52%"],
    ["Feeding tube / tracheostomy rate", "Baseline", "Not increased vs PF despite higher response"],
]
story.append(make_table(tpf_pf_rows, col_widths=[2.7*inch, 2.3*inch, 2.3*inch]))
story.append(Spacer(1, 16))

# ===== SECTION 5: KEY TAKEAWAYS =====
story.append(banner("5. Key Clinical Takeaways"))
story.append(Spacer(1, 8))
takeaways = [
    "Concurrent cisplatin-chemoradiotherapy gives the highest larynx preservation (88%) and locoregional control "
    "(78%) of any single strategy, but carries the highest toxicity burden (82% severe acute/late effects) &#8212; RTOG 91-11.",
    "5-year overall survival is similar across RT alone, induction PF, and concurrent CRT (~54-56%). The real "
    "differentiator between strategies is organ preservation and toxicity, not survival.",
    "When induction chemotherapy is chosen, TPF is superior to PF: higher response rate (83% vs 61%), better "
    "larynx preservation (~80% vs ~60%), and improved 5-year survival (52% vs 42%) &#8212; without increasing "
    "feeding-tube or tracheostomy rates.",
    "TPF carries greater hematologic toxicity (neutropenia, febrile neutropenia) and mucositis than PF &#8212; "
    "patient selection (performance status, renal/hearing function, ability to tolerate triplet chemo) is critical.",
    "Sequential therapy (induction TPF followed by concurrent chemoRT) has not shown a clear survival advantage "
    "over concurrent chemoRT alone (PARADIGM trial) &#8212; added toxicity without proven benefit in unselected patients.",
    "Carboplatin is substituted for cisplatin when renal impairment, hearing loss, or poor tolerance is a concern, "
    "at the cost of somewhat reduced radiosensitizing potency.",
]
bullets = ListFlowable(
    [ListItem(Paragraph(t, takeaway_body), spaceBefore=4) for t in takeaways],
    bulletType='bullet', start='&#9679;', bulletColor=NAVY, bulletFontSize=8, leftIndent=16
)
story.append(bullets)
story.append(Spacer(1, 16))

# ===== SECTION 6: TOXICITY QUICK-CHECK =====
story.append(banner("6. Toxicity Quick-Check by Agent"))
story.append(Spacer(1, 6))
tox_rows = [
    ["Agent", "Watch For", "Monitoring"],
    ["Cisplatin", "Nephrotoxicity, ototoxicity, peripheral neuropathy, severe nausea",
     "Creatinine/CrCl, audiology, Mg/electrolytes, aggressive hydration"],
    ["Carboplatin", "Myelosuppression (thrombocytopenia), hypersensitivity", "CBC, platelet count"],
    ["5-Fluorouracil", "Mucositis, diarrhea, myelosuppression, rare cardiotoxicity",
     "Oral exam, CBC, DPD deficiency screen where available"],
    ["Methotrexate", "Myelosuppression, hepatotoxicity, mucositis, renal toxicity (high dose)",
     "CBC, LFTs monthly, hydration/urine alkalinization for high-dose regimens"],
    ["Docetaxel / Paclitaxel", "Neutropenia, peripheral neuropathy, hypersensitivity, fluid retention (docetaxel)",
     "CBC with differential, neuro exam, premedication for hypersensitivity"],
]
story.append(make_table(tox_rows, col_widths=[1.6*inch, 3.15*inch, 2.55*inch]))
story.append(Spacer(1, 12))

story.append(HRFlowable(width="100%", thickness=0.8, color=GRID_COLOR))
story.append(Spacer(1, 4))
story.append(Paragraph(
    "This guide is a teaching summary compiled from Scott-Brown's Otorhinolaryngology Head &amp; Neck Surgery, "
    "Cummings Otolaryngology Head and Neck Surgery, K J Lee's Essential Otolaryngology, and Goodman &amp; "
    "Gilman's Pharmacological Basis of Therapeutics, supplemented by RTOG 91-11, GORTEC, and TAX 324 / EORTC "
    "24971 trial data. Not a substitute for institutional protocols or current oncology guidelines &#8212; verify "
    "dosing and eligibility against up-to-date clinical trial/NCCN sources before clinical use.", cite))

doc.build(story)
print("PDF created at", OUT)
Editing File

~/hn-chemo-guide/build_guide.py

Successfully replaced 1 instance(s) of the string in '/tmp/workspace/hn-chemo-guide/build_guide.py'
Running Command

rm -f /tmp/workspace/hn-chemo-guide/build_guide.py

Writing File

~/hn-chemo-guide/build_guide.py

#!/usr/bin/env python3
"""
Quick Reference PDF Guide: Head & Neck Chemotherapy Regimens
Redesigned for clean, consistent, non-overflowing layout.
"""
from reportlab.lib.pagesizes import letter
from reportlab.lib import colors
from reportlab.lib.units import inch
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    PageBreak, HRFlowable, ListFlowable, ListItem, Frame, BaseDocTemplate,
    PageTemplate
)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT

OUT = "/tmp/workspace/hn-chemo-guide/HN_Chemotherapy_Quick_Reference_Guide.pdf"

PAGE_W, PAGE_H = letter
MARGIN = 0.6 * inch
USABLE_W = PAGE_W - 2 * MARGIN  # ~7.3in

NAVY = colors.HexColor('#0B3D66')
NAVY_LIGHT = colors.HexColor('#E7EEF5')
ACCENT = colors.HexColor('#C0392B')
GREY = colors.HexColor('#555555')
ROW_ALT = colors.HexColor('#F4F7FA')
GRID_COLOR = colors.HexColor('#C9D3DC')

styles = getSampleStyleSheet()

title_style = ParagraphStyle('TitleC', parent=styles['Title'], fontName='Helvetica-Bold',
                              fontSize=22, textColor=NAVY, alignment=TA_CENTER, spaceAfter=2)
subtitle_style = ParagraphStyle('Subtitle', parent=styles['Normal'], fontName='Helvetica',
                                 fontSize=10.5, textColor=GREY, alignment=TA_CENTER, spaceAfter=2)
banner_text_style = ParagraphStyle('BannerText', parent=styles['Normal'], fontName='Helvetica-Bold',
                                    fontSize=12.5, textColor=colors.white, leading=15)
body = ParagraphStyle('Body', parent=styles['Normal'], fontName='Helvetica', fontSize=8.6, leading=11.2)
body_bold = ParagraphStyle('BodyBold', parent=body, fontName='Helvetica-Bold', textColor=NAVY)
head_cell = ParagraphStyle('HeadCell', parent=styles['Normal'], fontName='Helvetica-Bold',
                            fontSize=8.6, leading=11, textColor=colors.white)
cite = ParagraphStyle('Cite', parent=styles['Normal'], fontName='Helvetica-Oblique', fontSize=7.6,
                       leading=10, textColor=GREY, spaceBefore=6)
takeaway_body = ParagraphStyle('TakeawayBody', parent=body, fontSize=9, leading=12.5)
footer_style = ParagraphStyle('Footer', parent=styles['Normal'], fontSize=7.5, textColor=GREY)


def banner(text):
    """Full-width colored section banner using a 1x1 table (reliable background rendering)."""
    p = Paragraph(text, banner_text_style)
    t = Table([[p]], colWidths=[USABLE_W])
    t.setStyle(TableStyle([
        ('BACKGROUND', (0, 0), (-1, -1), NAVY),
        ('LEFTPADDING', (0, 0), (-1, -1), 8),
        ('RIGHTPADDING', (0, 0), (-1, -1), 8),
        ('TOPPADDING', (0, 0), (-1, -1), 5),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 5),
    ]))
    return t


def make_table(rows, col_widths, header_style=head_cell, body_style=body, first_col_bold=True):
    """Build a table where every cell is a Paragraph (reliable wrapping, no overflow)."""
    assert abs(sum(col_widths) - USABLE_W) < 0.05 * inch, \
        f"Column widths sum {sum(col_widths)/inch:.2f}in != usable width {USABLE_W/inch:.2f}in"

    data = []
    header_row = [Paragraph(h, header_style) for h in rows[0]]
    data.append(header_row)
    for r in rows[1:]:
        row_cells = []
        for idx, val in enumerate(r):
            if idx == 0 and first_col_bold:
                row_cells.append(Paragraph(val, body_bold))
            else:
                row_cells.append(Paragraph(val, body_style))
        data.append(row_cells)

    t = Table(data, colWidths=col_widths, repeatRows=1)
    style_cmds = [
        ('BACKGROUND', (0, 0), (-1, 0), NAVY),
        ('GRID', (0, 0), (-1, -1), 0.6, GRID_COLOR),
        ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
        ('LEFTPADDING', (0, 0), (-1, -1), 5),
        ('RIGHTPADDING', (0, 0), (-1, -1), 5),
        ('TOPPADDING', (0, 0), (-1, -1), 4),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 4),
    ]
    for i in range(1, len(data)):
        if i % 2 == 0:
            style_cmds.append(('BACKGROUND', (0, i), (-1, i), ROW_ALT))
    t.setStyle(TableStyle(style_cmds))
    return t


def draw_page_decoration(canvas, doc_):
    canvas.saveState()
    canvas.setStrokeColor(GRID_COLOR)
    canvas.setLineWidth(0.5)
    canvas.line(MARGIN, 0.5 * inch, PAGE_W - MARGIN, 0.5 * inch)
    canvas.setFont('Helvetica', 7.5)
    canvas.setFillColor(GREY)
    canvas.drawString(MARGIN, 0.34 * inch, "H&N Chemotherapy Quick Reference Guide")
    canvas.drawRightString(PAGE_W - MARGIN, 0.34 * inch, f"Page {doc_.page}")
    canvas.restoreState()


doc = BaseDocTemplate(
    OUT, pagesize=letter,
    topMargin=MARGIN, bottomMargin=0.7 * inch,
    leftMargin=MARGIN, rightMargin=MARGIN,
    title="H&N Chemotherapy Quick Reference Guide"
)
frame = Frame(MARGIN, 0.7 * inch, USABLE_W, PAGE_H - MARGIN - 0.7 * inch, id='normal')
doc.addPageTemplates([PageTemplate(id='main', frames=[frame], onPage=draw_page_decoration)])

story = []

# ===== TITLE BLOCK =====
story.append(Spacer(1, 4))
story.append(Paragraph("Head &amp; Neck Chemotherapy", title_style))
story.append(Paragraph("Quick Reference Guide", title_style))
story.append(Spacer(1, 4))
story.append(Paragraph(
    "Drug Mechanisms&nbsp;&nbsp;|&nbsp;&nbsp;Regimen Comparison&nbsp;&nbsp;|&nbsp;&nbsp;"
    "Organ Preservation Outcomes&nbsp;&nbsp;|&nbsp;&nbsp;Toxicity", subtitle_style))
story.append(Spacer(1, 6))
story.append(HRFlowable(width="100%", thickness=1.4, color=NAVY))
story.append(Spacer(1, 12))

# ===== SECTION 1: DRUG CLASSES =====
story.append(banner("1. Core Chemotherapy Drug Classes &amp; Mechanisms"))
story.append(Spacer(1, 6))
drug_rows = [
    ["Class", "Key Agents", "Mechanism of Action", "Dose-Limiting Toxicity"],
    ["Platinum agents", "Cisplatin, Carboplatin",
     "DNA cross-linking at guanine N7 &#8594; blocks DNA/RNA/protein synthesis",
     "Cisplatin: nephro-/ototoxicity. Carboplatin: myelosuppression"],
    ["Antimetabolites", "5-Fluorouracil, Methotrexate",
     "5-FU inhibits thymidylate synthetase (S-phase). Methotrexate inhibits dihydrofolate reductase, blocking folate-dependent DNA/RNA synthesis",
     "Mucositis, myelosuppression, hepatotoxicity (MTX)"],
    ["Taxanes", "Docetaxel, Paclitaxel",
     "Stabilize microtubules against depolymerization &#8594; G2/M mitotic arrest",
     "Neutropenia, peripheral neuropathy, hypersensitivity"],
    ["Vinca alkaloids", "Vincristine, Vinblastine",
     "Inhibit tubulin polymerization &#8594; block microtubule assembly &#8594; M-phase arrest",
     "Vincristine: neurotoxicity. Vinblastine: myelosuppression"],
    ["Cytotoxic antibiotics", "Bleomycin, Mitomycin C",
     "Bleomycin causes DNA strand fragmentation; Mitomycin C cross-links DNA",
     "Pulmonary fibrosis (bleomycin), myelosuppression"],
]
story.append(make_table(drug_rows, col_widths=[1.1*inch, 1.35*inch, 3.15*inch, 1.7*inch]))
story.append(Spacer(1, 14))

# ===== SECTION 2: REGIMEN COMPARISON =====
story.append(banner("2. Regimen Comparison: PF vs TPF vs Concurrent Chemoradiotherapy"))
story.append(Spacer(1, 6))
regimen_rows = [
    ["Feature", "PF (Induction)", "TPF (Induction)", "Concurrent CRT"],
    ["Drugs", "Cisplatin + 5-FU",
     "Docetaxel + Cisplatin + 5-FU",
     "Cisplatin (or carboplatin) given with radiotherapy"],
    ["Typical dosing", "Cisplatin 100 mg/m&#178; D1; 5-FU CI ~1000 mg/m&#178;/day D1-4/5; q3wk x2-3 cycles",
     "Docetaxel 75 mg/m&#178; D1 + Cisplatin 75-100 mg/m&#178; D1 + 5-FU CI; q3wk x3 cycles",
     "Cisplatin 100 mg/m&#178; q21d x3 cycles, or weekly low-dose, concurrent with daily RT x6-7 wks"],
    ["Goal / setting", "Cytoreduction before RT/surgery; organ preservation",
     "More potent cytoreduction than PF before definitive RT/surgery",
     "Primary curative-intent or adjuvant treatment"],
    ["Response rate", "~61%", "~83% (superior to PF)", "N/A (not an induction endpoint)"],
    ["Organ preservation", "~75% (RTOG 91-11 induction arm)", "~80% (superior to PF)", "~88% (highest)"],
    ["Locoregional control", "~61%", "Improved vs PF", "~78% (highest)"],
    ["5-yr overall survival", "~42-54%", "~52%", "~54-56%"],
    ["Severe toxicity", "Moderate", "Higher than PF", "Highest (~82%)"],
]
story.append(make_table(regimen_rows, col_widths=[1.3*inch, 1.9*inch, 1.95*inch, 2.15*inch]))
story.append(Spacer(1, 6))
story.append(Paragraph(
    "Sources: GORTEC (TPF vs PF), TAX 324 / EORTC 24971, RTOG 91-11; Cummings Otolaryngology Head and Neck "
    "Surgery; Scott-Brown's Otorhinolaryngology Head &amp; Neck Surgery.", cite))

story.append(PageBreak())

# ===== SECTION 3: RTOG 91-11 =====
story.append(banner("3. Organ Preservation Outcomes &#8212; RTOG 91-11 (3-Arm Laryngeal Trial)"))
story.append(Spacer(1, 6))
rtog_rows = [
    ["Arm", "Organ (Larynx) Preservation", "Locoregional Control", "5-yr Overall Survival", "Severe Toxicity"],
    ["RT alone", "70%", "56%", "54-56%", "Lowest of the three arms"],
    ["Induction PF &#8594; RT", "75%", "61%", "54-56%", "Moderate"],
    ["Concurrent Cisplatin + RT", "88% (highest)", "78% (highest)", "54-56% (similar across arms)", "82% (highest)"],
]
story.append(make_table(rtog_rows, col_widths=[1.55*inch, 1.55*inch, 1.4*inch, 1.5*inch, 1.3*inch]))
story.append(Spacer(1, 4))
story.append(Paragraph(
    "Key point: overall survival is statistically similar across all three arms &#8212; concurrent chemoradiotherapy "
    "wins on organ preservation and locoregional control, not on survival, and this benefit comes at the cost of "
    "the highest toxicity.", cite))
story.append(Spacer(1, 14))

# ===== SECTION 4: TPF vs PF =====
story.append(banner("4. TPF vs PF &#8212; Induction Head-to-Head (GORTEC / TAX 324)"))
story.append(Spacer(1, 6))
tpf_pf_rows = [
    ["Endpoint", "PF", "TPF"],
    ["Overall response rate", "59-61%", "80-83%"],
    ["Larynx preservation rate", "~57-60%", "~80%"],
    ["5-year overall survival", "42%", "52%"],
    ["Feeding tube / tracheostomy rate", "Baseline", "Not increased vs PF despite higher response"],
]
story.append(make_table(tpf_pf_rows, col_widths=[2.7*inch, 2.3*inch, 2.3*inch]))
story.append(Spacer(1, 16))

# ===== SECTION 5: KEY TAKEAWAYS =====
story.append(banner("5. Key Clinical Takeaways"))
story.append(Spacer(1, 8))
takeaways = [
    "Concurrent cisplatin-chemoradiotherapy gives the highest larynx preservation (88%) and locoregional control "
    "(78%) of any single strategy, but carries the highest toxicity burden (82% severe acute/late effects) &#8212; RTOG 91-11.",
    "5-year overall survival is similar across RT alone, induction PF, and concurrent CRT (~54-56%). The real "
    "differentiator between strategies is organ preservation and toxicity, not survival.",
    "When induction chemotherapy is chosen, TPF is superior to PF: higher response rate (83% vs 61%), better "
    "larynx preservation (~80% vs ~60%), and improved 5-year survival (52% vs 42%) &#8212; without increasing "
    "feeding-tube or tracheostomy rates.",
    "TPF carries greater hematologic toxicity (neutropenia, febrile neutropenia) and mucositis than PF &#8212; "
    "patient selection (performance status, renal/hearing function, ability to tolerate triplet chemo) is critical.",
    "Sequential therapy (induction TPF followed by concurrent chemoRT) has not shown a clear survival advantage "
    "over concurrent chemoRT alone (PARADIGM trial) &#8212; added toxicity without proven benefit in unselected patients.",
    "Carboplatin is substituted for cisplatin when renal impairment, hearing loss, or poor tolerance is a concern, "
    "at the cost of somewhat reduced radiosensitizing potency.",
]
bullets = ListFlowable(
    [ListItem(Paragraph(t, takeaway_body), spaceBefore=4) for t in takeaways],
    bulletType='bullet', start='circle', bulletColor=NAVY, bulletFontSize=6, leftIndent=16
)
story.append(bullets)
story.append(Spacer(1, 16))

# ===== SECTION 6: TOXICITY QUICK-CHECK =====
story.append(banner("6. Toxicity Quick-Check by Agent"))
story.append(Spacer(1, 6))
tox_rows = [
    ["Agent", "Watch For", "Monitoring"],
    ["Cisplatin", "Nephrotoxicity, ototoxicity, peripheral neuropathy, severe nausea",
     "Creatinine/CrCl, audiology, Mg/electrolytes, aggressive hydration"],
    ["Carboplatin", "Myelosuppression (thrombocytopenia), hypersensitivity", "CBC, platelet count"],
    ["5-Fluorouracil", "Mucositis, diarrhea, myelosuppression, rare cardiotoxicity",
     "Oral exam, CBC, DPD deficiency screen where available"],
    ["Methotrexate", "Myelosuppression, hepatotoxicity, mucositis, renal toxicity (high dose)",
     "CBC, LFTs monthly, hydration/urine alkalinization for high-dose regimens"],
    ["Docetaxel / Paclitaxel", "Neutropenia, peripheral neuropathy, hypersensitivity, fluid retention (docetaxel)",
     "CBC with differential, neuro exam, premedication for hypersensitivity"],
]
story.append(make_table(tox_rows, col_widths=[1.6*inch, 3.15*inch, 2.55*inch]))
story.append(Spacer(1, 12))

story.append(HRFlowable(width="100%", thickness=0.8, color=GRID_COLOR))
story.append(Spacer(1, 4))
story.append(Paragraph(
    "This guide is a teaching summary compiled from Scott-Brown's Otorhinolaryngology Head &amp; Neck Surgery, "
    "Cummings Otolaryngology Head and Neck Surgery, K J Lee's Essential Otolaryngology, and Goodman &amp; "
    "Gilman's Pharmacological Basis of Therapeutics, supplemented by RTOG 91-11, GORTEC, and TAX 324 / EORTC "
    "24971 trial data. Not a substitute for institutional protocols or current oncology guidelines &#8212; verify "
    "dosing and eligibility against up-to-date clinical trial/NCCN sources before clinical use.", cite))

doc.build(story)
print("PDF created at", OUT)
Running Command

cd /tmp/workspace/hn-chemo-guide && python3 build_guide.py

Running Command

cd /tmp/workspace/hn-chemo-guide && python3 -c " import pdfplumber with pdfplumber.open('HN_Chemotherapy_Quick_Reference_Guide.pdf') as pdf: print('Pages:', len(pdf.pages)) for i, page in enumerate(pdf.pages): print(f'--- Page {i+1}: width={page.width}, height={page.height} ---') # check for any content exceeding page width for word in page.extract_words(): if word['x1'] > page.width + 1: print('OVERFLOW WORD:', word) tables = page.find_tables() for t in tables: x0,y0,x1,y1 = t.bbox status = 'OK' if x1 <= page.width+1 and x0>=-1 else 'OVERFLOW' print(f'table bbox x0={x0:.1f} x1={x1:.1f} width={x1-x0:.1f} status={status}') " ls -la /tmp/workspace/hn-chemo-guide/HN_Chemotherapy_Quick_Reference_Guide.pdf

All tables now fit cleanly within the page margins (no overflow), and every cell uses proper text wrapping. The redesigned PDF is ready with a cleaner layout, consistent navy color scheme, full-width section banners, zebra-striped rows, and page numbers/footer.

HN Chemotherapy Quick Reference Guide

PDF Document · PDF

What changed from the first version:
  • Fixed table overflow (the RTOG 91-11 table previously exceeded the page width by ~0.5in) - all columns now sized to fit exactly within margins
  • Every table cell is now a properly wrapped Paragraph instead of a raw string, so long mechanism/toxicity descriptions flow cleanly instead of getting cramped or cut off
  • Added full-width navy section banners for clear visual hierarchy
  • Added zebra-striped rows for readability
  • Added a running footer with page numbers and document title on every page
  • Better spacing throughout (title block, section spacing, citation notes in italics)
Structure (3 pages):
  1. Title block + Section 1 (Drug Classes & Mechanisms) + Section 2 (PF vs TPF vs Concurrent comparison table)
  2. Section 3 (RTOG 91-11 breakdown) + Section 4 (TPF vs PF head-to-head) + Section 5 (Key Clinical Takeaways, start of bullets)
  3. Section 6 (Toxicity Quick-Check table) + source disclaimer
Let me know if you'd like it as a single-page landscape "cheat sheet" instead, or with a different color scheme.
This is a shared conversation. Sign in to Orris to start your own chat.