Embryology of placenta

Reading File
Finding Sources
Finding Sources
Finding Sources
Reading File
Reading File
Reading File
Reading File
Finding Sources
Reading File
Reading File
Reading File
Reading File
Reading File
Finding Sources
Reading File
Finding Sources
Loading Image
Loading Image
Loading Image
I now have all the information needed for a comprehensive, well-illustrated answer. Let me compile it.

Embryology of the Placenta

The placenta is a fetomaternal organ with two components: a fetal part derived from the chorionic sac, and a maternal part derived from the endometrium (decidua). It serves as the organ of respiration, nutrition, excretion, and endocrine secretion for the embryo/fetus throughout pregnancy.

1. Overview and Components

ComponentOriginTissue
Fetal partChorion frondosum (villous chorion)Trophoblast + extraembryonic mesoderm
Maternal partDecidua basalisModified endometrium
The two parts are held together by the cytotrophoblastic shell, which anchors the chorionic sac to the decidua basalis. Endometrial arteries and veins pass through gaps in this shell into the intervillous space.
  • The Developing Human: Clinically Oriented Embryology, p. 336

2. The Decidua

The decidua is the endometrium of the pregnant uterus. Rising progesterone levels cause connective tissue cells to enlarge into decidual cells, accumulating glycogen and lipid - this constitutes the decidual reaction.
Three regions:
  • Decidua basalis - deep to the conceptus; becomes the maternal part of the placenta
  • Decidua capsularis - overlies the conceptus superficially; degenerates by 22-24 weeks as the chorionic sac enlarges
  • Decidua parietalis - the remaining endometrium lining the uterine cavity
Development of the placenta and fetal membranes showing decidua regions, changing relations of fetal membranes from weeks 5-22
Fig. 7.1 - Development of the placenta and fetal membranes. Note the decidua regions (A-B), and changing relations of the membranes as pregnancy advances (C-F). By F (22 weeks), amnion and chorion fuse and obliterate the uterine cavity.

3. Development of Chorionic Villi

The progression from trophoblast to fully vascularized villi is the central event in placental embryology. Three stages:

Primary Chorionic Villi (Days 11-13)

  • Formed by proliferating cytotrophoblast sending cords into the blood-filled trophoblastic lacunae within the syncytiotrophoblast
  • Composition: syncytiotrophoblast (outer) + cytotrophoblast (inner core)

Secondary Chorionic Villi (Day ~16)

  • Extraembryonic mesenchyme (chorionic mesoderm) invades the cytotrophoblastic core
  • Composition: syncytiotrophoblast + cytotrophoblast + mesenchymal core
  • Cover the entire surface of the chorionic sac

Tertiary Chorionic Villi (End of Week 3)

  • Blood vessels differentiate within the mesenchymal core, vascularizing the villi
  • The complex vascular network is established by end of week 4
  • Fetal macrophages (Hofbauer cells) appear in the connective tissue core
Developmental stages of chorionic villi: Primary, Secondary, Tertiary (early and late pregnancy)
Development of chorionic villi. Primary villi = syncytiotrophoblast + cytotrophoblast. Secondary = mesenchyme added. Tertiary = vascularized. Late pregnancy shows syncytial knots and discontinuous cytotrophoblast.

4. Chorion Frondosum vs. Chorion Laeve

  • Until week 8, chorionic villi cover the entire chorionic sac
  • Villi overlying the decidua capsularis lose their blood supply, compress, and degenerate → chorion laeve (smooth chorion, avascular)
  • Villi overlying the decidua basalis proliferate and branch profusely → chorion frondosum (villous chorion; the fetal part of the placenta)
The shape of the placenta is discoid because the persistent chorion frondosum is circular. Homeobox genes (HLX, MSX2, DLX3) and kinase genes (MAP2K1, MAP2K2) regulate trophoblastic invasion and villous branching.

5. Cotyledons and Placental Septa

As chorionic villi invade the decidua basalis, wedge-shaped projections of decidual tissue - placental septa - are created, projecting toward the chorionic plate. These divide the fetal placenta into 15-30 irregular convex units called cotyledons. Each cotyledon contains 2 or more main stem villi and many branch villi.
By the end of the 4th month, the decidua basalis is almost entirely replaced by the fetal part of the placenta.

6. Intervillous Space

  • Derived from lacunae that developed in the syncytiotrophoblast during week 2
  • Initially filled with only maternal plasma (trophoblastic plugs in spiral arteries maintain a low-oxygen environment, protective for early development)
  • From 11-14 weeks, the plugs break down, maternal whole blood begins to flow, and oxygen concentrations rise
  • 80-100 spiral endometrial arteries of the decidua basalis discharge into the intervillous space through gaps in the cytotrophoblastic shell
  • Blood drains via endometrial veins, replenishing the ~150 mL of blood in the mature intervillous space 3-4 times per minute

7. Full-Term Placenta Structure

Full-term placenta cross-section showing fetal and maternal circulations, cotyledons, placental septa, and cytotrophoblastic shell
Transverse section through the full-term placenta. Umbilical arteries carry O2-poor blood to the placenta; the umbilical vein returns O2-rich blood to the fetus. Spiral arteries discharge maternal blood into the intervillous space. Cotyledons are separated by placental septa.

8. Placental Membrane (Placental "Barrier")

The placental membrane separates fetal and maternal blood. It is composed of extrafetal tissues:
Before 20 weeks (4 layers):
  1. Syncytiotrophoblast (outer)
  2. Cytotrophoblast
  3. Connective tissue (mesenchyme) of villi
  4. Endothelium of fetal capillaries
After 20 weeks (3 layers): Cytotrophoblast becomes attenuated and discontinuous; the membrane thins.
At full term: The syncytiotrophoblast may come into direct contact with fetal capillary endothelium - the vasosyncytial membrane - allowing maximal diffusion efficiency.
The term "placental barrier" is a misnomer - most drugs, steroids, small molecules, and IgG antibodies cross freely. Only large/charged molecules (e.g., heparin) are truly excluded.
Syncytial knots: In the 3rd trimester, syncytiotrophoblast nuclei aggregate into multinucleated protrusions that break off into maternal circulation and are destroyed in maternal pulmonary capillaries.

9. Circulation

Fetal Placental Circulation

  • Umbilical arteries (2) carry deoxygenated blood from fetus to placenta
  • Arteries divide into chorionic arteries at the placental insertion site → branch into villi capillaries
  • Oxygenated blood returns via the umbilical vein (1) to the fetus

Maternal Placental Circulation

  • Pulsatile flow from 80-100 spiral endometrial arteries into the intervillous space
  • Blood spurts toward the chorionic plate, then washes over branch villi
  • Drains via endometrial veins back to maternal circulation
Fetal and maternal blood do not normally intermingle. Minor fetomaternal hemorrhage can occur through microscopic membrane defects (clinically relevant for Rh sensitization).

10. Functions of the Placenta

FunctionDetail
RespirationO2/CO2 exchange by simple diffusion
NutritionGlucose (GLUT-1 facilitated diffusion), amino acids (active transport), fatty acids
ExcretionFetal metabolic waste and CO2
EndocrinehCG (rescues corpus luteum, detectable from week 2), progesterone, estrogen, hPL, relaxin
ImmunityIgG crosses via pinocytosis; provides passive fetal immunity
MetabolismSynthesizes glycogen, cholesterol, fatty acids, especially in early pregnancy
hCG is produced by syncytiotrophoblast cells and peaks at weeks 8-10, then falls - its detection forms the basis of pregnancy tests. By week 6, the placenta produces sufficient estrogen and progesterone to assume the role of the corpus luteum.

11. Amniochorionic Membrane

The amniotic sac enlarges faster than the chorionic sac, causing the amnion and smooth chorion (chorion laeve) to fuse, forming the amniochorionic membrane. This fuses with the decidua capsularis and (after its degeneration) adheres to the decidua parietalis. Rupture of this membrane during labor releases amniotic fluid. Preterm rupture (<37 weeks) is the most common trigger of premature labor.

Sources:
  • The Developing Human: Clinically Oriented Embryology (Moore & Persaud), pp. 336-357
  • Histology: A Text and Atlas with Correlated Cell and Molecular Biology (Ross & Pawlina), pp. 2261-2271
  • Creasy & Resnik's Maternal-Fetal Medicine, Chapter 4

Make a chart paper for pathology for the topic invasive breast cancer

Reading File
Finding Sources
Finding Sources
Finding Sources
Reading File
Reading File
Finding Sources
Reading File
Finding Sources
Reading File
Reading File
Reading File
Reading File
Running Command

ls /home/daytona/workspace/ 2>/dev/null && mkdir -p /home/daytona/workspace/brea…

Writing File

~/breast-cancer-chart/chart.js

const pptxgen = require("pptxgenjs");

const pres = new pptxgen();
pres.layout = "LAYOUT_WIDE"; // 13.3" x 7.5" — landscape poster format

// ─── COLOR PALETTE ───────────────────────────────────────────────
const C = {
  bg:       "F8F0F5",   // soft blush white background
  header:   "6B1A3A",   // deep burgundy — dominant
  accent1:  "A63060",   // rose
  accent2:  "D4507A",   // coral pink
  accent3:  "C8547A",   // mid-tone pink
  teal:     "1A6B7A",   // teal for contrast sections
  teal2:    "247B8A",
  amber:    "B05A00",   // amber for warnings/grading
  amber2:   "D4790A",
  green:    "1A6B3A",   // for benign/favorable
  green2:   "2E8B57",
  dark:     "2D1B25",   // near-black
  mid:      "6D4C5E",   // medium text
  light:    "F2D9E8",   // light pink for box fills
  lightTeal:"D9EFF2",
  lightAmb: "FFF0D9",
  white:    "FFFFFF",
  border:   "C090A8",
};

// ─── SINGLE POSTER SLIDE ─────────────────────────────────────────
const s = pres.addSlide();

// === BACKGROUND ===
s.addShape(pres.ShapeType.rect, {
  x: 0, y: 0, w: 13.3, h: 7.5,
  fill: { color: C.bg },
  line: { color: C.bg }
});

// === TOP HEADER BAR ===
s.addShape(pres.ShapeType.rect, {
  x: 0, y: 0, w: 13.3, h: 0.72,
  fill: { color: C.header },
  line: { color: C.header }
});

// Title
s.addText("INVASIVE BREAST CANCER — PATHOLOGY CHART", {
  x: 0.15, y: 0, w: 10.5, h: 0.72,
  fontSize: 20, bold: true, color: C.white,
  fontFace: "Calibri", align: "left", valign: "middle", margin: 0
});

// Sub-label
s.addText("Sabiston Surgery · Robbins Pathology · Schwartz Surgery", {
  x: 9.2, y: 0, w: 4.0, h: 0.72,
  fontSize: 8, color: "F2C0D5", fontFace: "Calibri",
  align: "right", valign: "middle", italic: true, margin: 0
});

// === BOTTOM FOOTER ===
s.addShape(pres.ShapeType.rect, {
  x: 0, y: 7.3, w: 13.3, h: 0.2,
  fill: { color: C.accent1 },
  line: { color: C.accent1 }
});
s.addText("Pathology · Oncology · Surgery  |  Chart Paper: Invasive Breast Cancer  |  July 2026", {
  x: 0, y: 7.32, w: 13.3, h: 0.16,
  fontSize: 6.5, color: C.mid, fontFace: "Calibri",
  align: "center", valign: "middle", italic: true, margin: 0
});


// ═══════════════════════════════════════════════════════════════════
// HELPER: draw a section box
// ═══════════════════════════════════════════════════════════════════
function sectionBox(x, y, w, h, title, fillColor, headerColor, titleColor) {
  // outer border
  s.addShape(pres.ShapeType.rect, {
    x, y, w, h,
    fill: { color: fillColor },
    line: { color: headerColor, pt: 1.5 }
  });
  // title band
  s.addShape(pres.ShapeType.rect, {
    x, y, w, h: 0.27,
    fill: { color: headerColor },
    line: { color: headerColor }
  });
  // title text
  s.addText(title, {
    x: x + 0.06, y: y, w: w - 0.1, h: 0.27,
    fontSize: 8.5, bold: true, color: titleColor || C.white,
    fontFace: "Calibri", valign: "middle", margin: 0
  });
}

function bodyText(textArr, x, y, w, h, size) {
  s.addText(textArr, {
    x, y, w, h,
    fontSize: size || 7.5,
    fontFace: "Calibri",
    color: C.dark,
    valign: "top",
    margin: 4
  });
}

// ═══════════════════════════════════════════════════════════════════
// COLUMN LAYOUT  (3 columns, 5 rows of boxes)
// Y start = 0.78 (just below header)
// ═══════════════════════════════════════════════════════════════════

const GAP = 0.08;
const col1x = 0.08;
const col2x = 4.53;
const col3x = 9.0;
const colW  = 4.2;
const TOP   = 0.78;

// ──────────────────────────────────────────────────────────────────
// ROW 1: Definition | Epidemiology | Risk Factors
// ──────────────────────────────────────────────────────────────────

// BOX 1 — Definition & Basics
sectionBox(col1x, TOP, colW, 1.42, "◆ DEFINITION & OVERVIEW", C.header, C.header);
bodyText([
  { text: "Invasive (Infiltrating) Breast Carcinoma", options: { bold: true, breakLine: true, color: C.accent2 } },
  { text: "• Malignant epithelial tumor breaching the basement membrane and invading breast stroma\n", options: { breakLine: true } },
  { text: "• Lacks overall organized architecture; cells infiltrate stroma haphazardly or form monotonous sheets\n", options: { breakLine: true } },
  { text: "• Most common cancer in women (lifetime risk: 1 in 8)\n", options: { breakLine: true } },
  { text: "• 297,790 new US cases estimated in 2023; 2nd leading cause of cancer death in women\n", options: { breakLine: true } },
], col1x + 0.06, TOP + 0.30, colW - 0.12, 1.06, 7.2);

// BOX 2 — Epidemiology
sectionBox(col2x, TOP, colW, 1.42, "◆ EPIDEMIOLOGY & INCIDENCE", C.teal, C.teal);
bodyText([
  { text: "Age: ", options: { bold: true } },
  { text: "Rare <25 yrs; rises steeply after age 30\n", options: { breakLine: true } },
  { text: "Peak incidence: ", options: { bold: true } },
  { text: "50–70 yrs (luminal subtypes)\n", options: { breakLine: true } },
  { text: "Geography: ", options: { bold: true } },
  { text: "Highest in North America, N/W Europe, Australia\n", options: { breakLine: true } },
  { text: "Hormonal factors: ", options: { bold: true } },
  { text: "Postmenopausal HRT, delayed childbearing, fewer pregnancies\n", options: { breakLine: true } },
  { text: "Mammography: ", options: { bold: true } },
  { text: "Average invasive lesion detected ~1 cm; sensitivity ↑ with age\n", options: { breakLine: true } },
], col2x + 0.06, TOP + 0.30, colW - 0.12, 1.06, 7.2);

// BOX 3 — Risk Factors
sectionBox(col3x, TOP, colW, 1.42, "◆ RISK FACTORS", C.amber, C.amber);
bodyText([
  { text: "Genetic: ", options: { bold: true } },
  { text: "BRCA1 (basal-like/TNBC), BRCA2, PALB2, ATM, CHEK2\n", options: { breakLine: true } },
  { text: "Hormonal: ", options: { bold: true } },
  { text: "Early menarche, late menopause, nulliparity, OCP/HRT use\n", options: { breakLine: true } },
  { text: "Reproductive: ", options: { bold: true } },
  { text: "No breastfeeding, late first pregnancy (>30 yrs)\n", options: { breakLine: true } },
  { text: "Other: ", options: { bold: true } },
  { text: "Dense breast tissue, prior breast biopsy (atypical hyperplasia), alcohol, obesity (post-menopause), radiation exposure\n", options: { breakLine: true } },
], col3x + 0.06, TOP + 0.30, colW - 0.12, 1.06, 7.2);


// ──────────────────────────────────────────────────────────────────
// ROW 2: Histological Types (wide box spanning col1+col2) | Grading
// ──────────────────────────────────────────────────────────────────

const R2Y = TOP + 1.42 + GAP;

// BIG BOX — Histological Types (cols 1+2)
const bigW = col2x + colW - col1x;
sectionBox(col1x, R2Y, bigW, 1.95, "◆ HISTOLOGICAL TYPES OF INVASIVE BREAST CANCER", C.light, C.accent1);

// Sub-table manually: 6 types in 2 columns
const typeData = [
  ["Invasive Ductal Carcinoma (IDC) / No Special Type (NST)", "50–70% of all invasive BC; cohesive mass; discrete on mammogram; haphazard cells in stroma"],
  ["Invasive Lobular Carcinoma (ILC)", "5–15%; single-file (Indian file) pattern; loss of E-cadherin (CDH1 mutation); clinically occult; escapes mammography"],
  ["Tubular Carcinoma", "~2–3%; small glands lined by single bland cell layer; low grade (Grade 1); excellent prognosis"],
  ["Mucinous (Colloid) Carcinoma", "~2–3%; bland cells floating in lakes of mucin; low grade (Grade 1); good prognosis"],
  ["Medullary Carcinoma", "~5%; large bizarre cells, syncytial sheets, lymphocytic infiltrate, pushing margins; high grade; ER/PR/HER2 negative"],
  ["Metaplastic Carcinoma", "Rare; high grade; ER/PR/HER2 negative (TNBC); node negative but high metastatic potential; ~50% relapse"],
];

const typeStartY = R2Y + 0.30;
const typeColW1 = 3.65;
const typeColW2 = bigW - typeColW1 - 0.22;
const rowH = 0.255;

// Header row
s.addShape(pres.ShapeType.rect, {
  x: col1x + 0.06, y: typeStartY, w: typeColW1, h: 0.24,
  fill: { color: C.accent1 }, line: { color: C.accent1 }
});
s.addText("Histological Type", {
  x: col1x + 0.08, y: typeStartY, w: typeColW1, h: 0.24,
  fontSize: 7.5, bold: true, color: C.white, fontFace: "Calibri", valign: "middle", margin: 0
});
s.addShape(pres.ShapeType.rect, {
  x: col1x + 0.06 + typeColW1 + 0.06, y: typeStartY, w: typeColW2, h: 0.24,
  fill: { color: C.accent1 }, line: { color: C.accent1 }
});
s.addText("Key Pathological Features", {
  x: col1x + 0.14 + typeColW1, y: typeStartY, w: typeColW2, h: 0.24,
  fontSize: 7.5, bold: true, color: C.white, fontFace: "Calibri", valign: "middle", margin: 0
});

typeData.forEach((row, i) => {
  const rowY = typeStartY + 0.24 + i * rowH;
  const bg = i % 2 === 0 ? "FFFFFF" : "FAE8F2";
  s.addShape(pres.ShapeType.rect, {
    x: col1x + 0.06, y: rowY, w: typeColW1, h: rowH,
    fill: { color: bg }, line: { color: C.border, pt: 0.5 }
  });
  s.addText(row[0], {
    x: col1x + 0.08, y: rowY, w: typeColW1 - 0.04, h: rowH,
    fontSize: 7, bold: true, color: C.header, fontFace: "Calibri", valign: "middle", margin: 0
  });
  s.addShape(pres.ShapeType.rect, {
    x: col1x + 0.06 + typeColW1 + 0.06, y: rowY, w: typeColW2, h: rowH,
    fill: { color: bg }, line: { color: C.border, pt: 0.5 }
  });
  s.addText(row[1], {
    x: col1x + 0.14 + typeColW1, y: rowY, w: typeColW2 - 0.04, h: rowH,
    fontSize: 6.8, color: C.dark, fontFace: "Calibri", valign: "middle", margin: 0
  });
});

// BOX — Nottingham Grading (col3)
sectionBox(col3x, R2Y, colW, 1.95, "◆ NOTTINGHAM HISTOLOGICAL GRADE (NHG)", C.lightAmb, C.amber);
bodyText([
  { text: "3 components — each scored 1–3:\n", options: { bold: true, breakLine: true, color: C.amber } },
  { text: "1. Tubule/gland formation\n", options: { bold: true, breakLine: true } },
  { text: "   >75% → 1   |   10–75% → 2   |   <10% → 3\n", options: { breakLine: true } },
  { text: "2. Nuclear pleomorphism\n", options: { bold: true, breakLine: true } },
  { text: "   Small uniform → 1   |   Moderate → 2   |   Marked → 3\n", options: { breakLine: true } },
  { text: "3. Mitotic rate  (per 10 HPF)\n", options: { bold: true, breakLine: true } },
  { text: "   Low → 1   |   Moderate → 2   |   High → 3\n\n", options: { breakLine: true } },
  { text: "SCORE  3–5 → Grade 1 (Well differentiated)\n", options: { bold: true, breakLine: true, color: C.green } },
  { text: "SCORE  6–7 → Grade 2 (Moderately differentiated)\n", options: { bold: true, breakLine: true, color: C.amber } },
  { text: "SCORE  8–9 → Grade 3 (Poorly differentiated)", options: { bold: true, color: "C0001A" } },
], col3x + 0.06, R2Y + 0.30, colW - 0.12, 1.59, 7.2);


// ──────────────────────────────────────────────────────────────────
// ROW 3: Molecular Subtypes | Biomarkers | Placental Membrane
// ──────────────────────────────────────────────────────────────────

const R3Y = R2Y + 1.95 + GAP;

// BOX — Molecular Subtypes
sectionBox(col1x, R3Y, colW, 1.75, "◆ MOLECULAR SUBTYPES (Gene Expression Profiling)", C.light, C.accent1);

const molData = [
  ["Luminal A",    "40–60%", "ER+/PR+ high, HER2−, Ki-67 low",    "Low",   "Best"],
  ["Luminal B",    "20–30%", "ER+/PR+ low, HER2−, Ki-67 high",    "Int",   "Good"],
  ["HER2-enriched","10–20%", "ER−/PR−, HER2+, Ki-67 high",        "High",  "Poor (tx-responsive)"],
  ["Basal-like (TNBC)","10–20%","ER−/PR−/HER2−, high grade, BRCA1 assoc.","High","Poor"],
];

const mstartY = R3Y + 0.30;
const mHdr = ["Subtype", "Freq", "Biomarker Profile", "Grade", "Prognosis"];
const mW = [1.42, 0.55, 1.58, 0.43, 0.6];
let mX = col1x + 0.06;
mHdr.forEach((h, i) => {
  s.addShape(pres.ShapeType.rect, { x: mX, y: mstartY, w: mW[i], h: 0.22, fill: { color: C.accent1 }, line: { color: C.accent1 } });
  s.addText(h, { x: mX, y: mstartY, w: mW[i], h: 0.22, fontSize: 7, bold: true, color: C.white, fontFace: "Calibri", valign: "middle", margin: 2 });
  mX += mW[i] + 0.02;
});

molData.forEach((row, ri) => {
  let rxStart = col1x + 0.06;
  const ry = mstartY + 0.22 + ri * 0.3;
  const rbg = ri % 2 === 0 ? C.white : "FAE8F2";
  const progColors = ["1A6B3A","1A6B3A","B05A00","C0001A"];
  row.forEach((cell, ci) => {
    const cc = ci === 4 ? progColors[ri] : C.dark;
    const cb = ci === 4;
    s.addShape(pres.ShapeType.rect, { x: rxStart, y: ry, w: mW[ci], h: 0.295, fill: { color: rbg }, line: { color: C.border, pt: 0.5 } });
    s.addText(cell, { x: rxStart, y: ry, w: mW[ci], h: 0.295, fontSize: 6.8, color: cc, bold: cb, fontFace: "Calibri", valign: "middle", margin: 2 });
    rxStart += mW[ci] + 0.02;
  });
});

// BOX — Biomarkers
sectionBox(col2x, R3Y, colW, 1.75, "◆ BIOMARKERS & IHC TESTING", C.lightTeal, C.teal);
bodyText([
  { text: "ER / PR (Estrogen / Progesterone Receptor)\n", options: { bold: true, breakLine: true, color: C.teal } },
  { text: "• IHC; >1% nuclear staining = positive\n  1–10% = low ER (limited endocrine benefit)\n  Guides hormonal therapy (tamoxifen, aromatase inhibitors)\n\n", options: { breakLine: true } },
  { text: "HER2 (Human EGF Receptor 2)\n", options: { bold: true, breakLine: true, color: C.teal } },
  { text: "• erb-B2 gene amplified in ~20% of BCs\n  IHC: 0/1+ = negative; 3+ = positive; 2+ = equivocal → ISH\n  ISH: <4 copies/cell = neg; ≥6 = positive\n  Guides trastuzumab, pertuzumab therapy\n\n", options: { breakLine: true } },
  { text: "Ki-67 (Proliferation Marker)\n", options: { bold: true, breakLine: true, color: C.teal } },
  { text: "• % of positive nuclei; high = aggressive tumor\n  Key discriminator: Luminal A (<20%) vs Luminal B (≥20%)", options: {} },
], col2x + 0.06, R3Y + 0.30, colW - 0.12, 1.40, 7.0);

// BOX — Spread & Metastasis
sectionBox(col3x, R3Y, colW, 1.75, "◆ ROUTES OF SPREAD & METASTASIS", C.light, C.accent3);
bodyText([
  { text: "Local spread: ", options: { bold: true } },
  { text: "Direct invasion into breast stroma, skin (peau d'orange — blocked lymphatics), nipple\n\n", options: { breakLine: true } },
  { text: "Lymphatic spread: ", options: { bold: true } },
  { text: "Axillary LN (most common) → infraclavicular, supraclavicular\n  Internal mammary nodes (medial tumors)\n  Sentinel LN biopsy is standard staging\n\n", options: { breakLine: true } },
  { text: "Haematogenous spread: ", options: { bold: true } },
  { text: "BONES (most common — lytic) > Liver > Lungs > Brain > Adrenals\n  ILC: predilection for peritoneum, GI, uterus, ovaries\n\n", options: { breakLine: true } },
  { text: "ILC pattern: ", options: { bold: true } },
  { text: "Single-file cells infiltrate widely; often underestimated clinically", options: {} },
], col3x + 0.06, R3Y + 0.30, colW - 0.12, 1.40, 7.0);


// ──────────────────────────────────────────────────────────────────
// ROW 4: TNM Staging | Pathological Features | Genomic Assays
// ──────────────────────────────────────────────────────────────────

const R4Y = R3Y + 1.75 + GAP;

// BOX — TNM Staging
sectionBox(col1x, R4Y, colW, 1.65, "◆ TNM STAGING (AJCC 8th Edition)", C.lightTeal, C.teal);

const tnmData = [
  ["T (Tumor)", "Tx — not assessed | T0 — no evidence\nTis — in situ | T1 — ≤2 cm | T2 — 2–5 cm\nT3 — >5 cm | T4 — chest wall/skin involvement"],
  ["N (Nodes)", "N0 — no regional node mets\nN1 — movable ipsilateral axillary nodes\nN2 — fixed axillary / internal mammary\nN3 — infraclavicular / supraclavicular"],
  ["M (Metastasis)", "M0 — no distant mets  |  M1 — distant mets"],
  ["Stages", "I: T1N0  |  II: T2N0 / T1-2N1  |  III: T3/N2 / T4\nIV: Any T, Any N, M1"],
];

let tnmY = R4Y + 0.30;
tnmData.forEach((row, i) => {
  const rbg = i % 2 === 0 ? C.white : C.lightTeal;
  s.addShape(pres.ShapeType.rect, { x: col1x + 0.06, y: tnmY, w: 0.82, h: 0.31, fill: { color: C.teal }, line: { color: C.teal } });
  s.addText(row[0], { x: col1x + 0.06, y: tnmY, w: 0.82, h: 0.31, fontSize: 7.2, bold: true, color: C.white, fontFace: "Calibri", valign: "middle", margin: 2 });
  s.addShape(pres.ShapeType.rect, { x: col1x + 0.92, y: tnmY, w: colW - 0.98, h: 0.31, fill: { color: rbg }, line: { color: C.border, pt: 0.5 } });
  s.addText(row[1], { x: col1x + 0.94, y: tnmY, w: colW - 1.02, h: 0.31, fontSize: 6.8, color: C.dark, fontFace: "Calibri", valign: "middle", margin: 2 });
  tnmY += 0.32;
});

// BOX — Gross & Micro Pathology
sectionBox(col2x, R4Y, colW, 1.65, "◆ GROSS & MICROSCOPIC PATHOLOGY", C.light, C.accent1);
bodyText([
  { text: "GROSS:\n", options: { bold: true, breakLine: true, color: C.accent1 } },
  { text: "• IDC: Hard, gritty, irregular stellate mass with spiculated edges; chalky white streaks (elastosis)\n", options: { breakLine: true } },
  { text: "• ILC: Rubbery; diffuse ill-defined thickening (no discrete mass); hard to feel and see on imaging\n", options: { breakLine: true } },
  { text: "• Mucinous: Soft, gelatinous, well-circumscribed bluish mass\n", options: { breakLine: true } },
  { text: "• Medullary: Soft, fleshy, well-circumscribed; haemorrhage ± necrosis\n\n", options: { breakLine: true } },
  { text: "MICROSCOPY:\n", options: { bold: true, breakLine: true, color: C.accent1 } },
  { text: "• IDC: Irregular nests/cords/trabeculae; desmoplastic stroma; mitoses; DCIS often coexists\n", options: { breakLine: true } },
  { text: "• ILC: Single-file infiltration; discohesive cells; targetoid periductal pattern; E-cadherin negative\n", options: { breakLine: true } },
  { text: "• Hofbauer-like inflammatory infiltrate in medullary; calcifications common in ductal\n", options: {} },
], col2x + 0.06, R4Y + 0.30, colW - 0.12, 1.30, 7.0);

// BOX — Genomic Assays
sectionBox(col3x, R4Y, colW, 1.65, "◆ GENOMIC ASSAYS & SPECIAL TESTS", C.lightAmb, C.amber);
bodyText([
  { text: "Oncotype DX (21-gene RS)\n", options: { bold: true, breakLine: true, color: C.amber } },
  { text: "Score 1–100 | Low (<26): endocrine alone | High (≥26): add chemo\nFor ER+/HER2−, 0–3 LN positive\n\n", options: { breakLine: true } },
  { text: "MammaPrint (70-gene)\n", options: { bold: true, breakLine: true, color: C.amber } },
  { text: "Low-risk / High-risk readout | ER+ or ER− tumors | Used for distant recurrence risk\n\n", options: { breakLine: true } },
  { text: "PAM50 / Prosigna\n", options: { bold: true, breakLine: true, color: C.amber } },
  { text: "Intrinsic subtype classification + ROR score\n\n", options: { breakLine: true } },
  { text: "BRCA1/2 germline testing: ", options: { bold: true } },
  { text: "BRCA1 → basal-like TNBC; BRCA2 → luminal\nIndicates prophylactic surgery ± PARP inhibitor eligibility", options: {} },
], col3x + 0.06, R4Y + 0.30, colW - 0.12, 1.30, 7.0);


// ──────────────────────────────────────────────────────────────────
// ROW 5: Placental Membrane / Clinical Features | Prognosis | Therapy Overview
// ──────────────────────────────────────────────────────────────────

const R5Y = R4Y + 1.65 + GAP;

// BOX — Clinical Features & Presentation
sectionBox(col1x, R5Y, colW, 1.42, "◆ CLINICAL FEATURES & PRESENTATION", C.light, C.header);
bodyText([
  { text: "Common presentations:\n", options: { bold: true, breakLine: true, color: C.header } },
  { text: "• Painless, hard, irregular, fixed lump (most common)\n", options: { breakLine: true } },
  { text: "• Skin dimpling / retraction (ligament of Cooper involvement)\n", options: { breakLine: true } },
  { text: "• Peau d'orange (lymphatic obstruction → skin edema)\n", options: { breakLine: true } },
  { text: "• Nipple retraction / bloody discharge (ductal involvement)\n", options: { breakLine: true } },
  { text: "• Axillary lymphadenopathy (late sign)\n", options: { breakLine: true } },
  { text: "• Inflammatory BC: Erythema, warmth, rapid enlargement (T4d — poor prognosis)\n", options: { breakLine: true } },
  { text: "Special types: ", options: { bold: true } },
  { text: "Paget's disease = nipple eczema with underlying ductal carcinoma", options: {} },
], col1x + 0.06, R5Y + 0.30, colW - 0.12, 1.06, 7.0);

// BOX — Prognostic Factors
sectionBox(col2x, R5Y, colW, 1.42, "◆ PROGNOSTIC & PREDICTIVE FACTORS", C.lightTeal, C.teal);
bodyText([
  { text: "Favorable (Good Prognosis):\n", options: { bold: true, breakLine: true, color: C.green } },
  { text: "• Small tumor size (T1) | Node-negative | Low grade (G1)\n  ER+/PR+ | Low Ki-67 | Luminal A subtype\n  Tubular or mucinous subtype | High TILs in TNBC\n\n", options: { breakLine: true } },
  { text: "Unfavorable (Poor Prognosis):\n", options: { bold: true, breakLine: true, color: "C0001A" } },
  { text: "• Lymph node positivity (most powerful predictor)\n  High grade (G3) | Large tumor (T3/T4) | HER2+ or TNBC\n  Lymphovascular invasion | High Ki-67\n  Triple-negative / Basal-like | BRCA1 mutation", options: {} },
], col2x + 0.06, R5Y + 0.30, colW - 0.12, 1.06, 7.0);

// BOX — Treatment Overview
sectionBox(col3x, R5Y, colW, 1.42, "◆ TREATMENT OVERVIEW (Pathology-guided)", C.lightAmb, C.amber);
bodyText([
  { text: "Surgery: ", options: { bold: true } },
  { text: "Lumpectomy + RT (early) or Mastectomy ± reconstruction\n", options: { breakLine: true } },
  { text: "Sentinel LN biopsy → axillary dissection if positive\n\n", options: { breakLine: true } },
  { text: "Endocrine Rx (ER+): ", options: { bold: true } },
  { text: "Tamoxifen (pre-menopausal); Aromatase inhibitors (post-menopausal)\n\n", options: { breakLine: true } },
  { text: "Anti-HER2 (HER2+): ", options: { bold: true } },
  { text: "Trastuzumab + Pertuzumab + Chemotherapy\n\n", options: { breakLine: true } },
  { text: "TNBC: ", options: { bold: true } },
  { text: "Neoadjuvant chemo (anthracycline + taxane); Olaparib (BRCA+)\n  Immunotherapy: Pembrolizumab + chemo (PDL-1+)", options: {} },
], col3x + 0.06, R5Y + 0.30, colW - 0.12, 1.06, 7.0);


// === WRITE FILE ===
pres.writeFile({ fileName: "/home/daytona/workspace/breast-cancer-chart/Invasive_Breast_Cancer_Pathology_Chart.pptx" })
  .then(() => console.log("✅ Chart paper created successfully!"))
  .catch(e => console.error("❌ Error:", e));
Running Command

cd /home/daytona/workspace/breast-cancer-chart && node chart.js

Running Command

ls -lh /home/daytona/workspace/breast-cancer-chart/

Your chart paper is ready! Here's the download link:

Invasive Breast Cancer Pathology Chart

Presentation · PPTX


What's on the Chart Paper

The poster is a single wide-format landscape slide (13.3" × 7.5") designed to be printed as an A1/A2 chart paper. It's organized into 5 rows × 3 columns with a deep burgundy/rose color scheme. Here's what each section covers:
RowColumn 1Column 2Column 3
1Definition & OverviewEpidemiology & IncidenceRisk Factors
2Histological Types Table (6 types spanning 2 cols)Nottingham Grading (NHG)
3Molecular Subtypes (Luminal A/B, HER2, TNBC)Biomarkers & IHC (ER/PR/HER2/Ki-67)Routes of Spread & Metastasis
4TNM Staging (AJCC 8th Ed)Gross & Microscopic PathologyGenomic Assays (Oncotype DX, MammaPrint)
5Clinical Features & PresentationPrognostic & Predictive FactorsTreatment Overview (pathology-guided)
Sources used: Sabiston Textbook of Surgery, Robbins & Cotran Pathologic Basis of Disease, Schwartz's Principles of Surgery.

Make the chart in pdf presentable format so that i can print out

Reading File
Running Command

python3 -c "import reportlab; print(reportlab.Version)"

Writing File

~/breast-cancer-chart/chart_pdf.py

from reportlab.lib.pagesizes import A2, landscape
from reportlab.lib import colors
from reportlab.lib.units import mm, cm
from reportlab.pdfgen import canvas
from reportlab.lib.colors import HexColor
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont

# ── OUTPUT ──────────────────────────────────────────────────────────────
OUT = "/home/daytona/workspace/breast-cancer-chart/Invasive_Breast_Cancer_Pathology.pdf"

# ── PAGE SETUP: A2 Landscape ─────────────────────────────────────────────
W, H = landscape(A2)   # 594.0 x 420.0 mm → points: 1683.78 x 1190.55
c = canvas.Canvas(OUT, pagesize=landscape(A2))
c.setTitle("Invasive Breast Cancer — Pathology Chart Paper")

# ── COLOUR PALETTE ────────────────────────────────────────────────────────
BG        = HexColor("#F8F0F5")
HEADER    = HexColor("#6B1A3A")
ACCENT1   = HexColor("#A63060")
ACCENT2   = HexColor("#C8547A")
TEAL      = HexColor("#1A6B7A")
TEAL_LITE = HexColor("#D9EFF2")
AMBER     = HexColor("#B05A00")
AMBER_L   = HexColor("#FFF0D9")
GREEN     = HexColor("#1A6B3A")
RED_DARK  = HexColor("#C0001A")
LIGHT_PNK = HexColor("#F2D9E8")
BORDER    = HexColor("#C090A8")
DARK      = HexColor("#2D1B25")
MID       = HexColor("#6D4C5E")
WHITE     = colors.white
BLACK     = colors.black
ROW_ALT   = HexColor("#FAE8F2")

# ── HELPERS ───────────────────────────────────────────────────────────────
def rect(x, y, w, h, fill, stroke=None, lw=0.5):
    c.saveState()
    c.setFillColor(fill)
    if stroke:
        c.setStrokeColor(stroke)
        c.setLineWidth(lw)
    else:
        c.setStrokeColor(fill)
        c.setLineWidth(0)
    c.rect(x, y, w, h, fill=1, stroke=1 if stroke else 0)
    c.restoreState()

def text(txt, x, y, size=8, color=DARK, bold=False, align="left", maxw=None):
    c.saveState()
    c.setFillColor(color)
    font = "Helvetica-Bold" if bold else "Helvetica"
    c.setFont(font, size)
    if align == "center" and maxw:
        tw = c.stringWidth(txt, font, size)
        x = x + (maxw - tw) / 2
    elif align == "right" and maxw:
        tw = c.stringWidth(txt, font, size)
        x = x + maxw - tw
    c.drawString(x, y, txt)
    c.restoreState()

def section_header(x, y, w, h, title, hdr_color, txt_color=None):
    rect(x, y, w, h, fill=hdr_color)
    tc = txt_color or WHITE
    c.saveState()
    c.setFillColor(tc)
    c.setFont("Helvetica-Bold", 8.5)
    c.drawString(x + 5, y + h/2 - 4, title)
    c.restoreState()

def box(x, y, w, h, fill, border_color, title, title_hdr_color=None):
    """Draw outer box with coloured header strip."""
    HEADER_H = 14
    # border
    rect(x, y, w, h, fill=fill, stroke=border_color, lw=1.0)
    # title band (at TOP of box, ReportLab y=bottom so top = y+h-HEADER_H)
    rect(x, y + h - HEADER_H, w, HEADER_H,
         fill=title_hdr_color or border_color)
    # title text
    c.saveState()
    c.setFillColor(WHITE)
    c.setFont("Helvetica-Bold", 8)
    c.drawString(x + 5, y + h - HEADER_H + 3.5, title)
    c.restoreState()
    return y + h - HEADER_H - 2  # returns inner top-y for content

def wrap_text_block(lines, x, y_top, w, size=7.2, leading=9.5, color=DARK, bold_pairs=None):
    """
    lines: list of (text, bold, color_override)
    Draws downward from y_top. Returns final y.
    """
    cy = y_top
    for (txt, bold, col) in lines:
        if cy < 10:
            break
        c.saveState()
        c.setFillColor(col or color)
        font = "Helvetica-Bold" if bold else "Helvetica"
        c.setFont(font, size)
        # simple word-wrap
        words = txt.split(" ")
        line_buf = ""
        for word in words:
            test = (line_buf + " " + word).strip()
            tw = c.stringWidth(test, font, size)
            if tw > w - 8:
                c.drawString(x + 4, cy, line_buf)
                cy -= leading
                line_buf = word
            else:
                line_buf = test
        if line_buf:
            c.drawString(x + 4, cy, line_buf)
            cy -= leading
        c.restoreState()
    return cy

# ── PAGE BACKGROUND ──────────────────────────────────────────────────────
rect(0, 0, W, H, fill=BG)

# ── TOP HEADER BAR ───────────────────────────────────────────────────────
HDR_H = 28
rect(0, H - HDR_H, W, HDR_H, fill=HEADER)
c.saveState()
c.setFillColor(WHITE)
c.setFont("Helvetica-Bold", 17)
c.drawString(12, H - HDR_H + 8, "INVASIVE BREAST CANCER — PATHOLOGY CHART PAPER")
c.setFont("Helvetica", 7)
c.setFillColor(HexColor("#F2C0D5"))
c.drawRightString(W - 10, H - HDR_H + 9,
    "Sources: Sabiston Surgery · Robbins & Cotran Pathology · Schwartz Surgery")
c.restoreState()

# ── BOTTOM FOOTER ────────────────────────────────────────────────────────
FOOT_H = 10
rect(0, 0, W, FOOT_H, fill=ACCENT1)
c.saveState()
c.setFillColor(WHITE)
c.setFont("Helvetica", 6)
c.drawCentredString(W / 2, 2,
    "Pathology · Oncology · Surgery  |  Invasive Breast Cancer Chart Paper  |  July 2026  |  For Educational Use")
c.restoreState()

# ── LAYOUT CONSTANTS ────────────────────────────────────────────────────
PAD    = 5          # gap between boxes (pts)
MARGIN = 8          # page margin
BODY_Y_TOP = H - HDR_H - MARGIN
BODY_H     = H - HDR_H - FOOT_H - MARGIN * 2
BODY_W     = W - MARGIN * 2

# 3 equal columns
COL_W = (BODY_W - PAD * 2) / 3
COL1X = MARGIN
COL2X = MARGIN + COL_W + PAD
COL3X = MARGIN + (COL_W + PAD) * 2

# Row heights (must sum to BODY_H - 4*PAD)
total_available = BODY_H - 4 * PAD
R1H = total_available * 0.155
R2H = total_available * 0.215
R3H = total_available * 0.205
R4H = total_available * 0.210
R5H = total_available * 0.215

R5Y = FOOT_H + MARGIN
R4Y = R5Y + R5H + PAD
R3Y = R4Y + R4H + PAD
R2Y = R3Y + R3H + PAD
R1Y = R2Y + R2H + PAD

# ═══════════════════════════════════════════════════════════════════════════
# ROW 1 — Definition | Epidemiology | Risk Factors
# ═══════════════════════════════════════════════════════════════════════════
# --- Box 1: Definition ---
inner = box(COL1X, R1Y, COL_W, R1H, LIGHT_PNK, HEADER,
            "◆  DEFINITION & OVERVIEW")
wrap_text_block([
    ("Invasive (Infiltrating) Breast Carcinoma", True, ACCENT1),
    ("Malignant epithelial tumor breaching the basement", False, None),
    ("membrane & invading breast stroma.", False, None),
    ("• Lacks organized architecture; cells infiltrate haphazardly", False, None),
    ("• Most common female cancer — lifetime risk 1 in 8", False, None),
    ("• 297,790 new US cases (2023); 2nd cancer death cause", False, None),
    ("• Divided broadly into ductal & lobular types", False, None),
], COL1X, inner, COL_W, size=7.5, leading=10)

# --- Box 2: Epidemiology ---
inner = box(COL2X, R1Y, COL_W, R1H, TEAL_LITE, TEAL,
            "◆  EPIDEMIOLOGY & INCIDENCE")
wrap_text_block([
    ("Age: Rare <25 yrs; rises steeply after age 30", False, None),
    ("Peak incidence: 50–70 yrs (luminal/ER+ subtypes)", False, None),
    ("Geography: Highest in North America, N/W Europe, Australia", False, None),
    ("Hormonal factors: Postmenopausal HRT, delayed childbearing", False, None),
    ("Mammography detects avg invasive lesion at ~1 cm", False, None),
    ("Sensitivity & specificity of mammography ↑ with age", False, None),
], COL2X, inner, COL_W, size=7.5, leading=10)

# --- Box 3: Risk Factors ---
inner = box(COL3X, R1Y, COL_W, R1H, AMBER_L, AMBER,
            "◆  RISK FACTORS")
wrap_text_block([
    ("Genetic: BRCA1 (→ TNBC/basal-like), BRCA2, PALB2, ATM, CHEK2", False, None),
    ("Hormonal: Early menarche, late menopause, OCP/HRT use", False, None),
    ("Reproductive: Nulliparity, no breastfeeding, late 1st pregnancy", False, None),
    ("Other: Dense breasts, atypical hyperplasia on biopsy, alcohol,", False, None),
    ("obesity (post-menopause), prior chest radiation", False, None),
], COL3X, inner, COL_W, size=7.5, leading=10)


# ═══════════════════════════════════════════════════════════════════════════
# ROW 2 — Histological Types (col1+col2 merged) | Nottingham Grading
# ═══════════════════════════════════════════════════════════════════════════
HIST_W = COL_W * 2 + PAD
inner = box(COL1X, R2Y, HIST_W, R2H, LIGHT_PNK, ACCENT1,
            "◆  HISTOLOGICAL TYPES OF INVASIVE BREAST CANCER")

# Table inside
HDR_ROW_H = 13
DATA_ROW_H = (R2H - 14 - HDR_ROW_H - 8) / 6
TABLE_X = COL1X + 4
TABLE_Y = inner - 2
COL_A = 175   # type name column width
COL_B = HIST_W - COL_A - 12  # description column width

# Header row
rect(TABLE_X, TABLE_Y - HDR_ROW_H, COL_A, HDR_ROW_H, fill=ACCENT1)
rect(TABLE_X + COL_A + 2, TABLE_Y - HDR_ROW_H, COL_B, HDR_ROW_H, fill=ACCENT1)
c.saveState()
c.setFillColor(WHITE); c.setFont("Helvetica-Bold", 7.5)
c.drawString(TABLE_X + 3, TABLE_Y - HDR_ROW_H + 3.5, "Histological Type")
c.drawString(TABLE_X + COL_A + 5, TABLE_Y - HDR_ROW_H + 3.5, "Key Pathological Features")
c.restoreState()

type_data = [
    ("Invasive Ductal Carcinoma (IDC / NST)",
     "50–70% of invasive BC; cohesive mass; discrete stellate on mammogram; haphazard nests/cords in desmoplastic stroma; DCIS often coexists"),
    ("Invasive Lobular Carcinoma (ILC)",
     "5–15%; single-file (Indian file) & targetoid pattern; discohesive cells; CDH1 mutation → E-cadherin loss; clinically & mammographically occult"),
    ("Tubular Carcinoma",
     "~2–3%; small glands lined by single layer of bland cells; low grade (Grade 1); excellent prognosis; angular tubules in fibrous stroma"),
    ("Mucinous (Colloid) Carcinoma",
     "~2–3%; bland tumor cells floating in lakes of mucin; low grade (Grade 1); soft gelatinous mass; good prognosis"),
    ("Medullary Carcinoma",
     "~5%; large bizarre syncytial cells; brisk lymphocytic infiltrate; pushing margins; no DCIS; high grade; uniformly ER/PR/HER2 negative"),
    ("Metaplastic Carcinoma",
     "Rare; high grade; ER/PR/HER2 negative (TNBC); mostly node-negative but high metastatic potential; ~50% local/distant relapse"),
]

for i, (name, desc) in enumerate(type_data):
    ry = TABLE_Y - HDR_ROW_H - (i + 1) * DATA_ROW_H
    bg = WHITE if i % 2 == 0 else ROW_ALT
    rect(TABLE_X, ry, COL_A, DATA_ROW_H, fill=bg, stroke=BORDER, lw=0.4)
    rect(TABLE_X + COL_A + 2, ry, COL_B, DATA_ROW_H, fill=bg, stroke=BORDER, lw=0.4)
    c.saveState()
    c.setFont("Helvetica-Bold", 6.8); c.setFillColor(HEADER)
    c.drawString(TABLE_X + 3, ry + DATA_ROW_H / 2 - 3.5, name)
    c.setFont("Helvetica", 6.6); c.setFillColor(DARK)
    # simple truncate for now
    c.drawString(TABLE_X + COL_A + 5, ry + DATA_ROW_H / 2 - 3.5, desc[:105])
    c.restoreState()

# --- Nottingham Grading ---
inner = box(COL3X, R2Y, COL_W, R2H, AMBER_L, AMBER,
            "◆  NOTTINGHAM HISTOLOGICAL GRADE (NHG)")
GRADE_lines = [
    ("3 criteria — each scored 1 to 3 points:", True, AMBER),
    ("", False, None),
    ("1.  Tubule / Gland Formation", True, DARK),
    ("    >75% of tumour area  =  1 point", False, None),
    ("    10–75%  =  2 points", False, None),
    ("    <10%  =  3 points", False, None),
    ("", False, None),
    ("2.  Nuclear Pleomorphism", True, DARK),
    ("    Small, uniform nuclei  =  1", False, None),
    ("    Moderate variation  =  2", False, None),
    ("    Marked variation  =  3", False, None),
    ("", False, None),
    ("3.  Mitotic Rate  (per 10 HPF)", True, DARK),
    ("    Low  =  1     Moderate  =  2     High  =  3", False, None),
    ("", False, None),
    ("TOTAL SCORE  3–5  =  Grade 1  (Well differentiated)", True, GREEN),
    ("TOTAL SCORE  6–7  =  Grade 2  (Moderately differentiated)", True, AMBER),
    ("TOTAL SCORE  8–9  =  Grade 3  (Poorly differentiated)", True, RED_DARK),
]
wrap_text_block(GRADE_lines, COL3X, inner, COL_W, size=7.5, leading=9.8)


# ═══════════════════════════════════════════════════════════════════════════
# ROW 3 — Molecular Subtypes | Biomarkers | Spread & Metastasis
# ═══════════════════════════════════════════════════════════════════════════
# --- Molecular Subtypes ---
inner = box(COL1X, R3Y, COL_W, R3H, LIGHT_PNK, ACCENT1,
            "◆  MOLECULAR SUBTYPES  (Gene Expression Profiling)")

mol_data = [
    ("Luminal A",          "40–60%", "ER+/PR+ high, HER2−, Ki-67 low",          "Grade 1–2", "BEST"),
    ("Luminal B",          "20–30%", "ER+/PR+ low–mod, HER2−/+, Ki-67 high",    "Grade 2–3", "GOOD"),
    ("HER2-Enriched",      "10–20%", "HER2+, ER−/PR−, Ki-67 high",              "Grade 3",   "POOR*"),
    ("Basal-like (TNBC)",  "10–20%", "ER−/PR−/HER2−, high grade, BRCA1 assoc.", "Grade 3",   "POOR"),
]

mol_headers = ["Subtype", "Freq", "Biomarker Profile", "Grade", "Prognosis"]
mW = [115, 40, 165, 58, 58]
mX_start = COL1X + 4
mHDR_H = 13
mROW_H = (R3H - 14 - mHDR_H - 10) / 4

my = inner - 2
mx = mX_start
for i, (hdr, cw) in enumerate(zip(mol_headers, mW)):
    rect(mx, my - mHDR_H, cw, mHDR_H, fill=ACCENT1)
    c.saveState(); c.setFillColor(WHITE); c.setFont("Helvetica-Bold", 7)
    c.drawString(mx + 2, my - mHDR_H + 3.5, hdr); c.restoreState()
    mx += cw + 2

prog_colors = [GREEN, GREEN, AMBER, RED_DARK]
for ri, row in enumerate(mol_data):
    ry = inner - 2 - mHDR_H - (ri + 1) * mROW_H
    rbg = WHITE if ri % 2 == 0 else ROW_ALT
    mx = mX_start
    for ci, (cell, cw) in enumerate(zip(row, mW)):
        rect(mx, ry, cw, mROW_H, fill=rbg, stroke=BORDER, lw=0.4)
        cc = prog_colors[ri] if ci == 4 else (HEADER if ci == 0 else DARK)
        bold = ci in (0, 4)
        c.saveState()
        c.setFillColor(cc)
        c.setFont("Helvetica-Bold" if bold else "Helvetica", 6.8)
        c.drawString(mx + 3, ry + mROW_H / 2 - 3.5, cell)
        c.restoreState()
        mx += cw + 2

c.saveState(); c.setFillColor(MID); c.setFont("Helvetica", 6)
c.drawString(COL1X + 4, R3Y + 4, "* HER2+ now tx-responsive with trastuzumab/pertuzumab")
c.restoreState()

# --- Biomarkers ---
inner = box(COL2X, R3Y, COL_W, R3H, TEAL_LITE, TEAL,
            "◆  BIOMARKERS & IHC TESTING")
wrap_text_block([
    ("ER / PR (Estrogen / Progesterone Receptors)", True, TEAL),
    ("• IHC; >1% nuclear staining = positive", False, None),
    ("• 1–10% = low ER (limited endocrine benefit)", False, None),
    ("• Guides tamoxifen (pre-menopausal) &", False, None),
    ("  aromatase inhibitors (post-menopausal)", False, None),
    ("", False, None),
    ("HER2  (Human Epidermal Growth Factor Receptor 2)", True, TEAL),
    ("• erb-B2 amplified in ~20% of breast cancers", False, None),
    ("• IHC: 0/1+ neg  |  2+ equivocal → ISH  |  3+ positive", False, None),
    ("• ISH: <4 copies neg  |  ≥6 copies positive", False, None),
    ("• Guides trastuzumab + pertuzumab therapy", False, None),
    ("", False, None),
    ("Ki-67  (Proliferation Marker)", True, TEAL),
    ("• % of Ki-67+ nuclei; ↑Ki-67 = aggressive", False, None),
    ("• Discriminates Luminal A (<20%) vs B (≥20%)", False, None),
], COL2X, inner, COL_W, size=7.3, leading=9.5)

# --- Spread ---
inner = box(COL3X, R3Y, COL_W, R3H, LIGHT_PNK, ACCENT2,
            "◆  ROUTES OF SPREAD & METASTASIS")
wrap_text_block([
    ("Local Spread", True, ACCENT1),
    ("• Direct invasion into stroma, skin, nipple", False, None),
    ("• Peau d'orange = blocked dermal lymphatics", False, None),
    ("• Skin dimpling = Cooper ligament involvement", False, None),
    ("", False, None),
    ("Lymphatic Spread  (most clinically important)", True, ACCENT1),
    ("• Axillary LN (most common) — 3 levels", False, None),
    ("• Internal mammary (medial quadrant tumors)", False, None),
    ("• Infra/Supraclavicular LN (late / advanced)", False, None),
    ("• Sentinel LN biopsy is standard staging tool", False, None),
    ("", False, None),
    ("Haematogenous Spread", True, ACCENT1),
    ("• BONE (lytic, most common) > LIVER > LUNG > BRAIN", False, None),
    ("• ILC special: peritoneum, GI tract, uterus, ovaries", False, None),
], COL3X, inner, COL_W, size=7.3, leading=9.5)


# ═══════════════════════════════════════════════════════════════════════════
# ROW 4 — TNM Staging | Gross & Micro Pathology | Genomic Assays
# ═══════════════════════════════════════════════════════════════════════════
# --- TNM ---
inner = box(COL1X, R4Y, COL_W, R4H, TEAL_LITE, TEAL,
            "◆  TNM STAGING — AJCC 8th EDITION")

tnm_data = [
    ("T  (Tumour)",
     "Tx=not assessed | T0=no evidence | Tis=in situ\nT1=≤2cm | T2=2–5cm | T3=>5cm | T4=chest wall/skin"),
    ("N  (Nodes)",
     "N0=no nodal mets | N1=movable ipsilateral axillary\nN2=fixed axillary / internal mammary | N3=infra/supraclavicular"),
    ("M  (Mets)",
     "M0 = no distant metastasis\nM1 = distant metastasis present"),
    ("STAGE  I",  "T1 N0 M0  —  Excellent prognosis"),
    ("STAGE  II", "T2N0 / T1-2N1  —  Good prognosis"),
    ("STAGE  III","T3/N2 or T4 any N  —  Locally advanced"),
    ("STAGE  IV", "Any T, Any N, M1  —  Distant metastatic disease"),
]

tnm_hdr_w = 90
tnm_val_w = COL_W - tnm_hdr_w - 14
tnm_row_h = (R4H - 14 - 6) / len(tnm_data)
ty = inner - 2
stage_colors = [TEAL, TEAL, TEAL, GREEN, AMBER, HexColor("#C05000"), RED_DARK]

for i, (label, val) in enumerate(tnm_data):
    ry = ty - (i + 1) * tnm_row_h
    rbg = TEAL_LITE if i % 2 == 0 else WHITE
    rect(COL1X + 4, ry, tnm_hdr_w, tnm_row_h, fill=stage_colors[i])
    rect(COL1X + 4 + tnm_hdr_w + 2, ry, tnm_val_w, tnm_row_h,
         fill=rbg, stroke=BORDER, lw=0.4)
    c.saveState()
    c.setFillColor(WHITE); c.setFont("Helvetica-Bold", 7.2)
    c.drawString(COL1X + 7, ry + tnm_row_h / 2 - 3.5, label)
    c.setFillColor(DARK); c.setFont("Helvetica", 6.8)
    c.drawString(COL1X + 4 + tnm_hdr_w + 5, ry + tnm_row_h / 2 - 3.5,
                 val.replace("\n", "  "))
    c.restoreState()

# --- Gross & Micro ---
inner = box(COL2X, R4Y, COL_W, R4H, LIGHT_PNK, ACCENT1,
            "◆  GROSS & MICROSCOPIC PATHOLOGY")
wrap_text_block([
    ("GROSS APPEARANCE:", True, ACCENT1),
    ("IDC: Hard, gritty, irregular stellate mass; spiculated", False, None),
    ("  edges; chalky white streaks (elastosis); gritty cut surface", False, None),
    ("ILC: Rubbery diffuse thickening; no discrete mass;", False, None),
    ("  hard to detect clinically & mammographically", False, None),
    ("Mucinous: Soft, gelatinous, bluish, well-circumscribed", False, None),
    ("Medullary: Soft, fleshy, pushing borders ± haemorrhage", False, None),
    ("", False, None),
    ("MICROSCOPY:", True, ACCENT1),
    ("IDC: Irregular nests/cords/trabeculae in desmoplastic", False, None),
    ("  stroma; mitoses; nuclear pleomorphism; DCIS coexists", False, None),
    ("ILC: Single-file infiltration; targetoid periductal pattern;", False, None),
    ("  E-cadherin loss (IHC negative)", False, None),
    ("Medullary: Syncytial sheets; brisk lymphocytic infiltrate", False, None),
    ("Calcifications common in IDC; Hofbauer cells in villi", False, None),
], COL2X, inner, COL_W, size=7.2, leading=9.3)

# --- Genomic Assays ---
inner = box(COL3X, R4Y, COL_W, R4H, AMBER_L, AMBER,
            "◆  GENOMIC ASSAYS & SPECIAL TESTS")
wrap_text_block([
    ("Oncotype DX — 21-Gene Recurrence Score (RS)", True, AMBER),
    ("Score 1–100 via RT-PCR on paraffin-embedded tissue", False, None),
    ("RS <26: endocrine therapy alone (low recurrence risk)", False, None),
    ("RS ≥26: add chemotherapy to endocrine therapy", False, None),
    ("Best for: ER+/HER2−, 0–3 positive LN (early stage)", False, None),
    ("", False, None),
    ("MammaPrint — 70-Gene Assay", True, AMBER),
    ("Simple Low-risk / High-risk readout", False, None),
    ("Validated for ER+ and ER− tumours", False, None),
    ("", False, None),
    ("Other Assays:", True, AMBER),
    ("PAM50/Prosigna — intrinsic subtype + ROR score", False, None),
    ("EndoPredict — ER+ HER2− breast cancer prognosis", False, None),
    ("", False, None),
    ("BRCA1/2 Germline Testing:", True, AMBER),
    ("BRCA1 → Basal-like TNBC; BRCA2 → Luminal type", False, None),
    ("Eligibility: PARP inhibitors (olaparib, talazoparib)", False, None),
], COL3X, inner, COL_W, size=7.2, leading=9.3)


# ═══════════════════════════════════════════════════════════════════════════
# ROW 5 — Clinical Features | Prognostic Factors | Treatment
# ═══════════════════════════════════════════════════════════════════════════
# --- Clinical Features ---
inner = box(COL1X, R5Y, COL_W, R5H, LIGHT_PNK, HEADER,
            "◆  CLINICAL FEATURES & PRESENTATION")
wrap_text_block([
    ("Common Presentations:", True, HEADER),
    ("• Painless, hard, irregular, fixed lump (most common)", False, None),
    ("• Skin dimpling / retraction (Cooper ligament tethering)", False, None),
    ("• Peau d'orange (dermal lymphatic obstruction)", False, None),
    ("• Nipple retraction or bloody discharge", False, None),
    ("• Axillary lymphadenopathy (advanced disease)", False, None),
    ("", False, None),
    ("Special Presentations:", True, HEADER),
    ("• Inflammatory BC: Erythema, warmth, rapid enlargement", False, None),
    ("  (T4d — dermal lymphatic invasion; worst prognosis)", False, None),
    ("• Paget's disease: Nipple eczema + underlying DCIS/IDC", False, None),
    ("• ILC: Diffuse thickening, often bilateral, late presentation", False, None),
], COL1X, inner, COL_W, size=7.3, leading=9.5)

# --- Prognostic Factors ---
inner = box(COL2X, R5Y, COL_W, R5H, TEAL_LITE, TEAL,
            "◆  PROGNOSTIC & PREDICTIVE FACTORS")
wrap_text_block([
    ("FAVOURABLE (Better Prognosis):", True, GREEN),
    ("• Small size (T1 ≤2cm)", False, None),
    ("• Node-negative (N0) — single strongest predictor", False, None),
    ("• Low grade (Grade 1)", False, None),
    ("• ER+/PR+ strongly positive | Low Ki-67", False, None),
    ("• Luminal A subtype", False, None),
    ("• Tubular or mucinous histological type", False, None),
    ("• High tumour-infiltrating lymphocytes (TNBC)", False, None),
    ("", False, None),
    ("UNFAVOURABLE (Worse Prognosis):", True, RED_DARK),
    ("• Lymph node positivity — strongest adverse predictor", False, None),
    ("• High grade (Grade 3) | Large tumour (T3/T4)", False, None),
    ("• HER2+ or Triple Negative (TNBC) subtype", False, None),
    ("• Lymphovascular invasion | High Ki-67 (≥30%)", False, None),
    ("• BRCA1 mutation | Inflammatory carcinoma (T4d)", False, None),
], COL2X, inner, COL_W, size=7.2, leading=9.3)

# --- Treatment ---
inner = box(COL3X, R5Y, COL_W, R5H, AMBER_L, AMBER,
            "◆  TREATMENT OVERVIEW  (Pathology-Guided)")
wrap_text_block([
    ("SURGERY:", True, AMBER),
    ("• Lumpectomy + RT (breast-conserving, early stage)", False, None),
    ("• Mastectomy ± reconstruction (large / multifocal)", False, None),
    ("• Sentinel LN biopsy → axillary dissection if positive", False, None),
    ("", False, None),
    ("ENDOCRINE  (ER+/PR+):", True, AMBER),
    ("• Pre-menopausal: Tamoxifen (5–10 yrs)", False, None),
    ("• Post-menopausal: Aromatase inhibitors", False, None),
    ("", False, None),
    ("ANTI-HER2  (HER2+):", True, AMBER),
    ("• Trastuzumab + Pertuzumab + Taxane chemotherapy", False, None),
    ("• T-DM1 / T-DXd for residual/metastatic disease", False, None),
    ("", False, None),
    ("TNBC (Triple Negative):", True, AMBER),
    ("• Neoadjuvant: Anthracycline + Taxane ± Carboplatin", False, None),
    ("• BRCA+: Olaparib / Talazoparib (PARP inhibitors)", False, None),
    ("• PDL-1+: Pembrolizumab + Chemotherapy", False, None),
], COL3X, inner, COL_W, size=7.2, leading=9.3)


# ── VERTICAL DIVIDERS (decorative) ──────────────────────────────────────
c.saveState()
c.setStrokeColor(BORDER)
c.setLineWidth(0.5)
c.setDash(3, 3)
c.line(COL2X - PAD/2, H - HDR_H - MARGIN, COL2X - PAD/2, FOOT_H + MARGIN)
c.line(COL3X - PAD/2, H - HDR_H - MARGIN, COL3X - PAD/2, FOOT_H + MARGIN)
c.restoreState()

# ── SAVE ────────────────────────────────────────────────────────────────
c.save()
print(f"✅ PDF saved: {OUT}")
Running Command

cd /home/daytona/workspace/breast-cancer-chart && python3 chart_pdf.py

Running Command

ls -lh /home/daytona/workspace/breast-cancer-chart/

Your print-ready PDF chart paper is ready!

Invasive Breast Cancer Pathology

PDF Document · PDF


Print Instructions

  • Paper size: A2 Landscape (594 × 420 mm) — ideal for chart paper / poster printing
  • If printing on A3: In your printer dialog, choose "Fit to page" or "Scale to fit A3"
  • If printing on A4: Choose "Fit" or scale to 60% — all text remains legible
  • Print quality: 300 DPI or higher recommended; use "Best quality" setting
  • Color: Print in color to get the full color-coded layout

What's on the Chart

The poster has 5 rows × 3 columns of color-coded sections:
ColorSections
🟥 Deep Burgundy/RoseDefinition, Clinical Features, Histological Types, Gross/Micro
🟦 TealEpidemiology, Biomarkers (ER/PR/HER2), TNM Staging, Prognostic Factors
🟧 AmberRisk Factors, Nottingham Grading, Genomic Assays, Treatment
Every section is neatly boxed with a colored header strip, alternating row shading in tables, and color-coded prognosis indicators (green = favorable, red = poor).

Include pictures as well

Finding Sources
Finding Sources
Reading File
Reading File
Reading File
Finding Sources
Reading File
Finding Sources
Reading File
Finding Sources
Running Command

node /home/daytona/skills/shared/scripts/fetch_images.js \ "https://cdn.orris.…

Writing File

~/breast-cancer-chart/chart_pdf_images.py

"""
Invasive Breast Cancer — Pathology Chart Paper (with images)
A2 Landscape, print-ready PDF
"""
import subprocess, json, io, base64, os
from reportlab.lib.pagesizes import landscape, A2
from reportlab.lib.colors import HexColor, white, black
from reportlab.pdfgen import canvas
from reportlab.lib.utils import ImageReader
from PIL import Image as PILImage

# ── FETCH ALL IMAGES VIA NODE HELPER ─────────────────────────────────────
URLS = [
    "https://cdn.orris.care/cdss_images/a7976dc8796d45630b8035ab7b9d9a51d19ab1a1da0a00fe3a1a2be2d02c2b2c.png",  # 0: IDC histo
    "https://cdn.orris.care/cdss_images/aaefa7fa0dcea9ebc4141cc11c208790e0f6056922eb4965653c88eb8ecb41ae.png",  # 1: ILC single-file
    "https://cdn.orris.care/cdss_images/537e98f39fad9dcd00a3efb6981773b84fb05b1cd9ee68523227206e253312b9.png",  # 2: tubular
    "https://cdn.orris.care/cdss_images/0c3a6313c64d0e2d44fc2c95fdc046eb79e58c3ecace88848ebfa9457ea7e556.png",  # 3: mucinous
    "https://cdn.orris.care/cdss_images/7ec93232f952affe9a51828a80bbacb8bad2981e4717078c0202d8fbe12ddd05.png",  # 4: medullary
    "https://cdn.orris.care/cdss_images/90f51bd3b37f5512daef0a02982be1e27828e6224ba01e69c220258689d5655f.png",  # 5: IDC scirrhous x100/200
    "https://cdn.orris.care/cdss_images/8be48acee1c45d0b5f32ee39476dfdb8cdbf608456eb387d806a63765f460454.png",  # 6: ILC Indian file
    "https://cdn.orris.care/cdss_images/c3182e46ed9f6473eb40224eb6404462d78bbde2b74b6941b7d44134662af03a.png",  # 7: mammogram spiculated mass
]

print("Fetching images …")
result = subprocess.run(
    ["node", "/home/daytona/skills/shared/scripts/fetch_images.js"] + URLS,
    capture_output=True, text=True, timeout=90
)
img_data = json.loads(result.stdout)

def b64_to_reader(entry):
    """Convert base64 data URI → PIL ImageReader for ReportLab."""
    raw = entry["base64"].split(",", 1)[1]
    buf = io.BytesIO(base64.b64decode(raw))
    img = PILImage.open(buf).convert("RGB")
    out = io.BytesIO()
    img.save(out, format="PNG")
    out.seek(0)
    return ImageReader(out)

readers = [b64_to_reader(d) for d in img_data]
print("Images ready.")

# ── PAGE SETUP ────────────────────────────────────────────────────────────
OUT = "/home/daytona/workspace/breast-cancer-chart/Invasive_Breast_Cancer_With_Images.pdf"
W, H = landscape(A2)   # 1683.78 × 1190.55 pts
c = canvas.Canvas(OUT, pagesize=landscape(A2))
c.setTitle("Invasive Breast Cancer — Pathology Chart Paper")

# ── COLOUR PALETTE ────────────────────────────────────────────────────────
BG        = HexColor("#F8F0F5")
HEADER    = HexColor("#6B1A3A")
ACCENT1   = HexColor("#A63060")
ACCENT2   = HexColor("#C8547A")
TEAL      = HexColor("#1A6B7A")
TEAL_LITE = HexColor("#D9EFF2")
AMBER     = HexColor("#B05A00")
AMBER_L   = HexColor("#FFF0D9")
GREEN     = HexColor("#1A6B3A")
RED_DARK  = HexColor("#C0001A")
LIGHT_PNK = HexColor("#F2D9E8")
BORDER    = HexColor("#C090A8")
DARK      = HexColor("#2D1B25")
MID       = HexColor("#6D4C5E")
ROW_ALT   = HexColor("#FAE8F2")
IMG_FRAME = HexColor("#D4A0BE")
IMG_BG    = HexColor("#FDF5FA")

# ── DRAWING HELPERS ───────────────────────────────────────────────────────
def rect(x, y, w, h, fill, stroke=None, lw=0.5):
    c.saveState()
    c.setFillColor(fill)
    if stroke:
        c.setStrokeColor(stroke); c.setLineWidth(lw)
    else:
        c.setStrokeColor(fill); c.setLineWidth(0)
    c.rect(x, y, w, h, fill=1, stroke=1 if stroke else 0)
    c.restoreState()

def draw_image(reader, x, y, w, h, caption="", cap_color=None):
    """Draw image with thin border and optional caption below."""
    rect(x, y, w, h, fill=IMG_BG, stroke=IMG_FRAME, lw=1.2)
    # keep aspect
    try:
        iw, ih = reader.getSize()
        scale = min(w / iw, h / ih) * 0.97
        nw, nh = iw * scale, ih * scale
        ox = x + (w - nw) / 2
        oy = y + (h - nh) / 2
        c.drawImage(reader, ox, oy, nw, nh, mask="auto")
    except Exception:
        c.drawImage(reader, x, y, w, h, preserveAspectRatio=True, mask="auto")
    if caption:
        c.saveState()
        c.setFont("Helvetica", 5.5)
        c.setFillColor(cap_color or MID)
        c.drawCentredString(x + w / 2, y - 7, caption)
        c.restoreState()

def box(x, y, w, h, fill, border_color, title, title_hdr_color=None):
    HDR_H = 14
    rect(x, y, w, h, fill=fill, stroke=border_color, lw=1.0)
    rect(x, y + h - HDR_H, w, HDR_H, fill=title_hdr_color or border_color)
    c.saveState()
    c.setFillColor(white); c.setFont("Helvetica-Bold", 8)
    c.drawString(x + 5, y + h - HDR_H + 3.5, title)
    c.restoreState()
    return y + h - HDR_H - 2   # inner top-y

def wrap_lines(lines, x, y_top, w, size=7.2, leading=9.5):
    """lines: list of (text, bold, color_override)  — draws downward."""
    cy = y_top
    for (txt, bold, col) in lines:
        if cy < 8: break
        c.saveState()
        c.setFillColor(col or DARK)
        font = "Helvetica-Bold" if bold else "Helvetica"
        c.setFont(font, size)
        words = txt.split(" ")
        buf = ""
        for w_word in words:
            test = (buf + " " + w_word).strip()
            if c.stringWidth(test, font, size) > w - 8:
                if buf:
                    c.drawString(x + 4, cy, buf)
                    cy -= leading
                buf = w_word
            else:
                buf = test
        if buf:
            c.drawString(x + 4, cy, buf)
            cy -= leading
        c.restoreState()
    return cy

# ── PAGE BACKGROUND ───────────────────────────────────────────────────────
rect(0, 0, W, H, fill=BG)

# ── HEADER BAR ───────────────────────────────────────────────────────────
HDR_H = 30
rect(0, H - HDR_H, W, HDR_H, fill=HEADER)
c.saveState()
c.setFillColor(white); c.setFont("Helvetica-Bold", 18)
c.drawString(12, H - HDR_H + 9, "INVASIVE BREAST CANCER — PATHOLOGY CHART PAPER")
c.setFont("Helvetica", 7); c.setFillColor(HexColor("#F2C0D5"))
c.drawRightString(W - 10, H - HDR_H + 10,
    "Sabiston Surgery · Robbins & Cotran Pathology · Schwartz Surgery")
c.restoreState()

# ── FOOTER ────────────────────────────────────────────────────────────────
FOOT_H = 10
rect(0, 0, W, FOOT_H, fill=ACCENT1)
c.saveState(); c.setFillColor(white); c.setFont("Helvetica", 6)
c.drawCentredString(W / 2, 2,
    "Pathology · Oncology · Surgery  |  Invasive Breast Cancer Chart Paper  |  July 2026  |  For Educational Use")
c.restoreState()

# ── LAYOUT ────────────────────────────────────────────────────────────────
PAD    = 6
MARGIN = 8
BODY_TOP = H - HDR_H - MARGIN
BODY_BOT = FOOT_H + MARGIN
BODY_H   = BODY_TOP - BODY_BOT
BODY_W   = W - MARGIN * 2

COL_W = (BODY_W - PAD * 2) / 3
COL1X = MARGIN
COL2X = MARGIN + COL_W + PAD
COL3X = MARGIN + (COL_W + PAD) * 2

# Row heights — 6 rows now (added image strip)
total = BODY_H - 5 * PAD
R1H = total * 0.120   # Definition / Epi / Risk
R2H = total * 0.163   # Histological types + Grading
R3H = total * 0.152   # Molecular / Biomarkers / Spread
IMG_H = total * 0.148 # IMAGE STRIP
R4H = total * 0.155   # TNM / Gross+Micro / Genomics
R5H = total * 0.162   # Clinical / Prognosis / Treatment
# stack bottom up
R5Y = BODY_BOT
R4Y = R5Y + R5H + PAD
IMG_Y = R4Y + R4H + PAD
R3Y = IMG_Y + IMG_H + PAD
R2Y = R3Y + R3H + PAD
R1Y = R2Y + R2H + PAD

# ══════════════════════════════════════════════════════════════════════════
# ROW 1 — Definition | Epidemiology | Risk Factors
# ══════════════════════════════════════════════════════════════════════════
inner = box(COL1X, R1Y, COL_W, R1H, LIGHT_PNK, HEADER, "◆  DEFINITION & OVERVIEW")
wrap_lines([
    ("Invasive (Infiltrating) Breast Carcinoma", True, ACCENT1),
    ("Malignant epithelial tumour breaching the basement", False, None),
    ("membrane & invading breast stroma.", False, None),
    ("• Lacks organized architecture; infiltrates haphazardly", False, None),
    ("• Most common female cancer — lifetime risk 1 in 8", False, None),
    ("• ~298,000 new US cases (2023); 2nd cancer death cause", False, None),
    ("• Broadly: Ductal (IDC) vs Lobular (ILC) subtypes", False, None),
], COL1X, inner, COL_W, size=7.5, leading=10)

inner = box(COL2X, R1Y, COL_W, R1H, TEAL_LITE, TEAL, "◆  EPIDEMIOLOGY & INCIDENCE")
wrap_lines([
    ("Age: Rare <25 yrs; incidence rises steeply after age 30", False, None),
    ("Peak: 50–70 yrs (luminal/ER+ subtypes)", False, None),
    ("Geography: Highest in N. America, N/W Europe, Australia", False, None),
    ("Hormonal factors: Postmenopausal HRT, delayed childbearing", False, None),
    ("Mammography detects avg invasive lesion at ~1 cm", False, None),
], COL2X, inner, COL_W, size=7.5, leading=10)

inner = box(COL3X, R1Y, COL_W, R1H, AMBER_L, AMBER, "◆  RISK FACTORS")
wrap_lines([
    ("Genetic: BRCA1 (→TNBC/basal-like), BRCA2, PALB2, ATM", False, None),
    ("Hormonal: Early menarche, late menopause, OCP/HRT", False, None),
    ("Reproductive: Nulliparity, no breastfeeding, late pregnancy", False, None),
    ("Other: Dense breasts, atypical hyperplasia, alcohol,", False, None),
    ("obesity (post-menopause), prior chest radiation", False, None),
], COL3X, inner, COL_W, size=7.5, leading=10)

# ══════════════════════════════════════════════════════════════════════════
# ROW 2 — Histological Types (wide) | Nottingham Grading
# ══════════════════════════════════════════════════════════════════════════
HIST_W = COL_W * 2 + PAD
inner = box(COL1X, R2Y, HIST_W, R2H, LIGHT_PNK, ACCENT1,
            "◆  HISTOLOGICAL TYPES OF INVASIVE BREAST CANCER")

HDR_ROW = 13
type_data = [
    ("IDC / NST  (Invasive Ductal Carcinoma)",
     "50–70%; cohesive mass; haphazard nests/cords in desmoplastic stroma; stellate on mammogram; DCIS often coexists"),
    ("ILC  (Invasive Lobular Carcinoma)",
     "5–15%; single-file 'Indian file' pattern; CDH1 mutation → E-cadherin loss; multifocal/bilateral; mammographically occult"),
    ("Tubular Carcinoma",
     "~2–3%; small angular glands, single cell layer; low grade (G1); 10% LN mets; ~100% long-term survival"),
    ("Mucinous / Colloid Carcinoma",
     "~2–3%; bland cells floating in mucin lakes; G1; gelatinous cut surface; >90% ER+; good prognosis"),
    ("Medullary Carcinoma",
     "~5%; syncytial sheets of large bizarre cells; brisk lymphocytic infiltrate; pushing borders; G3; ER/PR/HER2 negative"),
    ("Metaplastic Carcinoma",
     "Rare; G3; TNBC; mostly node-negative but high metastatic risk; ~50% local/distant relapse; poor prognosis"),
]
COL_A = 170
COL_B = HIST_W - COL_A - 14
TX = COL1X + 4
TY = inner - 2
DATA_ROW = (R2H - 14 - HDR_ROW - 8) / len(type_data)

rect(TX, TY - HDR_ROW, COL_A, HDR_ROW, fill=ACCENT1)
rect(TX + COL_A + 2, TY - HDR_ROW, COL_B, HDR_ROW, fill=ACCENT1)
for lbl, hx, ww in [("Histological Type", TX+3, COL_A), ("Key Pathological Features", TX+COL_A+5, COL_B)]:
    c.saveState(); c.setFillColor(white); c.setFont("Helvetica-Bold", 7.5)
    c.drawString(hx, TY - HDR_ROW + 3.5, lbl); c.restoreState()

for i, (name, desc) in enumerate(type_data):
    ry = TY - HDR_ROW - (i+1)*DATA_ROW
    bg = white if i % 2 == 0 else ROW_ALT
    rect(TX, ry, COL_A, DATA_ROW, fill=bg, stroke=BORDER, lw=0.4)
    rect(TX+COL_A+2, ry, COL_B, DATA_ROW, fill=bg, stroke=BORDER, lw=0.4)
    c.saveState()
    c.setFont("Helvetica-Bold", 6.8); c.setFillColor(HEADER)
    c.drawString(TX+3, ry+DATA_ROW/2-3.5, name)
    c.setFont("Helvetica", 6.6); c.setFillColor(DARK)
    c.drawString(TX+COL_A+5, ry+DATA_ROW/2-3.5, desc[:108])
    c.restoreState()

inner = box(COL3X, R2Y, COL_W, R2H, AMBER_L, AMBER, "◆  NOTTINGHAM HISTOLOGICAL GRADE (NHG)")
wrap_lines([
    ("3 criteria — each scored 1–3 points:", True, AMBER),
    ("", False, None),
    ("1.  Tubule / Gland Formation", True, DARK),
    ("    >75% = 1   |   10–75% = 2   |   <10% = 3", False, None),
    ("2.  Nuclear Pleomorphism", True, DARK),
    ("    Small uniform = 1  |  Moderate = 2  |  Marked = 3", False, None),
    ("3.  Mitotic Rate  (per 10 HPF)", True, DARK),
    ("    Low = 1   |   Moderate = 2   |   High = 3", False, None),
    ("", False, None),
    ("SCORE 3–5  =  Grade 1  (Well differentiated)", True, GREEN),
    ("SCORE 6–7  =  Grade 2  (Moderately differentiated)", True, AMBER),
    ("SCORE 8–9  =  Grade 3  (Poorly differentiated)", True, RED_DARK),
], COL3X, inner, COL_W, size=7.5, leading=9.8)

# ══════════════════════════════════════════════════════════════════════════
# ROW 3 — Molecular Subtypes | Biomarkers | Spread
# ══════════════════════════════════════════════════════════════════════════
inner = box(COL1X, R3Y, COL_W, R3H, LIGHT_PNK, ACCENT1,
            "◆  MOLECULAR SUBTYPES  (Gene Expression Profiling)")
mol_data = [
    ("Luminal A",          "40–60%", "ER+/PR+ high, HER2−, Ki-67 low",          "G1–2", "BEST"),
    ("Luminal B",          "20–30%", "ER+/PR+ low, HER2−/+, Ki-67 high",        "G2–3", "GOOD"),
    ("HER2-Enriched",      "10–20%", "HER2+, ER−/PR−, Ki-67 high",              "G3",   "POOR*"),
    ("Basal-like / TNBC",  "10–20%", "ER−/PR−/HER2−, BRCA1 assoc., high grade", "G3",   "POOR"),
]
mW = [115, 42, 157, 40, 58]
mHDR_H = 13
mROW_H  = (R3H - 14 - mHDR_H - 8) / 4
my = inner - 2
mx = COL1X + 4
for h, cw in zip(["Subtype","Freq","Biomarker Profile","Grade","Prog."], mW):
    rect(mx, my-mHDR_H, cw, mHDR_H, fill=ACCENT1)
    c.saveState(); c.setFillColor(white); c.setFont("Helvetica-Bold", 7)
    c.drawString(mx+2, my-mHDR_H+3.5, h); c.restoreState()
    mx += cw + 2
prog_c = [GREEN, GREEN, AMBER, RED_DARK]
for ri, row in enumerate(mol_data):
    ry = inner - 2 - mHDR_H - (ri+1)*mROW_H
    rbg = white if ri % 2 == 0 else ROW_ALT
    mx = COL1X + 4
    for ci, (cell, cw) in enumerate(zip(row, mW)):
        rect(mx, ry, cw, mROW_H, fill=rbg, stroke=BORDER, lw=0.4)
        cc = prog_c[ri] if ci == 4 else (HEADER if ci == 0 else DARK)
        c.saveState(); c.setFillColor(cc)
        c.setFont("Helvetica-Bold" if ci in (0,4) else "Helvetica", 6.8)
        c.drawString(mx+3, ry+mROW_H/2-3.5, cell); c.restoreState()
        mx += cw + 2
c.saveState(); c.setFillColor(MID); c.setFont("Helvetica", 6)
c.drawString(COL1X+4, R3Y+4, "* HER2+ now tx-responsive with trastuzumab/pertuzumab")
c.restoreState()

inner = box(COL2X, R3Y, COL_W, R3H, TEAL_LITE, TEAL, "◆  BIOMARKERS & IHC TESTING")
wrap_lines([
    ("ER / PR (Estrogen / Progesterone Receptors)", True, TEAL),
    ("• IHC; >1% nuclear staining = positive", False, None),
    ("• 1–10% = low ER (limited endocrine benefit)", False, None),
    ("• Guides tamoxifen & aromatase inhibitors", False, None),
    ("", False, None),
    ("HER2  (Human EGF Receptor 2)", True, TEAL),
    ("• Amplified in ~20% of BCs; IHC 0–3+", False, None),
    ("• 3+ = positive; 2+ equivocal → ISH confirmation", False, None),
    ("• Guides trastuzumab + pertuzumab therapy", False, None),
    ("", False, None),
    ("Ki-67  (Proliferation Marker)", True, TEAL),
    ("• % Ki-67+ nuclei; Luminal A <20% vs B ≥20%", False, None),
], COL2X, inner, COL_W, size=7.3, leading=9.5)

inner = box(COL3X, R3Y, COL_W, R3H, LIGHT_PNK, ACCENT2, "◆  ROUTES OF SPREAD & METASTASIS")
wrap_lines([
    ("Local:", True, ACCENT1),
    ("Direct invasion into stroma, skin (peau d'orange),", False, None),
    ("nipple; Cooper ligament tethering → skin dimpling", False, None),
    ("", False, None),
    ("Lymphatic:", True, ACCENT1),
    ("Axillary LN (most common, 3 levels)", False, None),
    ("Internal mammary (medial tumours)", False, None),
    ("Supra/Infraclavicular LN (advanced stage)", False, None),
    ("Sentinel LN biopsy = standard staging", False, None),
    ("", False, None),
    ("Haematogenous:", True, ACCENT1),
    ("BONE (lytic) > Liver > Lung > Brain > Adrenals", False, None),
    ("ILC: peritoneum, GI tract, uterus, ovaries", False, None),
], COL3X, inner, COL_W, size=7.3, leading=9.5)

# ══════════════════════════════════════════════════════════════════════════
# IMAGE STRIP — Full width, 5 histology + mammogram panels
# ══════════════════════════════════════════════════════════════════════════
IMG_FULL_W = BODY_W
IMG_X = MARGIN
IMG_Y_box = IMG_Y

rect(IMG_X, IMG_Y_box, IMG_FULL_W, IMG_H, fill=HexColor("#FDF5FA"), stroke=HEADER, lw=1.5)
# Title band
rect(IMG_X, IMG_Y_box + IMG_H - 14, IMG_FULL_W, 14, fill=HEADER)
c.saveState(); c.setFillColor(white); c.setFont("Helvetica-Bold", 8.5)
c.drawString(IMG_X+6, IMG_Y_box + IMG_H - 14 + 3.5,
    "◆  HISTOPATHOLOGY & IMAGING — Invasive Breast Cancer  (Sabiston Surgery, Fig 68.9 · Schwartz Surgery, Fig 17-16 & 17-17 & 17-21)")
c.restoreState()

INNER_IMG_H = IMG_H - 16 - 18  # minus title + caption space below
IMG_PAD = 5
N_PANELS = 6
panel_w = (IMG_FULL_W - (N_PANELS+1)*IMG_PAD) / N_PANELS
panel_y = IMG_Y_box + 16

# Panel definitions: (reader_index, caption)
panels = [
    (0, "IDC: haphazard malignant cells in stroma"),
    (5, "IDC (scirrhous) — 100× & 200×"),
    (1, "ILC: single-file 'Indian file' pattern"),
    (6, "ILC: lobular cells, 100×"),
    (3, "Mucinous: cells in mucin lakes"),
    (7, "Mammogram: spiculated mass (IDC)"),
]

for i, (ridx, cap) in enumerate(panels):
    px = IMG_X + IMG_PAD + i*(panel_w + IMG_PAD)
    draw_image(readers[ridx], px, panel_y, panel_w, INNER_IMG_H, caption=cap, cap_color=HEADER)

# ══════════════════════════════════════════════════════════════════════════
# ROW 4 — TNM Staging | Gross & Micro | Genomic Assays
# ══════════════════════════════════════════════════════════════════════════
inner = box(COL1X, R4Y, COL_W, R4H, TEAL_LITE, TEAL, "◆  TNM STAGING — AJCC 8th EDITION")
tnm_data = [
    ("T  (Tumour)", "Tx/T0/Tis | T1 ≤2cm | T2 2–5cm | T3 >5cm | T4 chest wall/skin"),
    ("N  (Nodes)",  "N0 no mets | N1 movable axillary | N2 fixed/internal mammary | N3 supra/infraclavicular"),
    ("M  (Mets)",   "M0 = no distant mets  |  M1 = distant metastasis"),
    ("Stage I",     "T1 N0 M0  — Excellent prognosis"),
    ("Stage II",    "T2N0 / T1-2N1  — Good prognosis"),
    ("Stage III",   "T3-4 / N2-3  — Locally advanced"),
    ("Stage IV",    "Any T, Any N, M1  — Metastatic disease"),
]
tnm_hw = 90
tnm_vw = COL_W - tnm_hw - 14
tnm_rh = (R4H - 14 - 4) / len(tnm_data)
ty = inner - 2
stage_c = [TEAL, TEAL, TEAL, GREEN, AMBER, HexColor("#C05000"), RED_DARK]
for i, (lbl, val) in enumerate(tnm_data):
    ry = ty - (i+1)*tnm_rh
    rbg = TEAL_LITE if i%2==0 else white
    rect(COL1X+4, ry, tnm_hw, tnm_rh, fill=stage_c[i])
    rect(COL1X+4+tnm_hw+2, ry, tnm_vw, tnm_rh, fill=rbg, stroke=BORDER, lw=0.4)
    c.saveState()
    c.setFillColor(white); c.setFont("Helvetica-Bold", 7.2)
    c.drawString(COL1X+7, ry+tnm_rh/2-3.5, lbl)
    c.setFillColor(DARK); c.setFont("Helvetica", 6.8)
    c.drawString(COL1X+4+tnm_hw+5, ry+tnm_rh/2-3.5, val)
    c.restoreState()

inner = box(COL2X, R4Y, COL_W, R4H, LIGHT_PNK, ACCENT1, "◆  GROSS & MICROSCOPIC PATHOLOGY")
wrap_lines([
    ("GROSS:", True, ACCENT1),
    ("IDC: Hard, gritty, stellate mass; spiculated edges;", False, None),
    ("chalky white streaks (elastosis); gritty cut surface", False, None),
    ("ILC: Rubbery diffuse thickening; no discrete mass", False, None),
    ("Mucinous: Soft, gelatinous, bluish, well-circumscribed", False, None),
    ("Medullary: Soft, fleshy, pushing borders ± haemorrhage", False, None),
    ("", False, None),
    ("MICROSCOPY:", True, ACCENT1),
    ("IDC: Nests/cords in desmoplastic stroma; mitoses;", False, None),
    ("nuclear pleomorphism; DCIS often at periphery", False, None),
    ("ILC: Single-file infiltration; targetoid periductal;", False, None),
    ("E-cadherin negative (IHC); signet-ring cells possible", False, None),
    ("Medullary: Syncytial sheets; brisk lymphocytic infiltrate", False, None),
], COL2X, inner, COL_W, size=7.2, leading=9.3)

inner = box(COL3X, R4Y, COL_W, R4H, AMBER_L, AMBER, "◆  GENOMIC ASSAYS & SPECIAL TESTS")
wrap_lines([
    ("Oncotype DX — 21-Gene Recurrence Score (RS)", True, AMBER),
    ("RT-PCR on FFPE tissue; score 1–100", False, None),
    ("RS <26: endocrine alone  |  RS ≥26: add chemo", False, None),
    ("For ER+/HER2−, 0–3 positive LN (early stage)", False, None),
    ("", False, None),
    ("MammaPrint — 70-Gene Assay", True, AMBER),
    ("Low-risk / High-risk readout; ER+ or ER− tumours", False, None),
    ("", False, None),
    ("Other Assays:", True, AMBER),
    ("PAM50/Prosigna — intrinsic subtype + ROR score", False, None),
    ("EndoPredict — ER+/HER2− prognosis", False, None),
    ("", False, None),
    ("BRCA1/2 Germline Testing:", True, AMBER),
    ("BRCA1 → TNBC/basal-like; BRCA2 → Luminal type", False, None),
    ("Guides PARP inhibitors (olaparib, talazoparib)", False, None),
], COL3X, inner, COL_W, size=7.2, leading=9.3)

# ══════════════════════════════════════════════════════════════════════════
# ROW 5 — Clinical Features | Prognostic Factors | Treatment
# ══════════════════════════════════════════════════════════════════════════
inner = box(COL1X, R5Y, COL_W, R5H, LIGHT_PNK, HEADER, "◆  CLINICAL FEATURES & PRESENTATION")
wrap_lines([
    ("Common Presentations:", True, HEADER),
    ("• Painless, hard, irregular, fixed lump (most common)", False, None),
    ("• Skin dimpling (Cooper ligament tethering)", False, None),
    ("• Peau d'orange (dermal lymphatic obstruction)", False, None),
    ("• Nipple retraction / bloody discharge", False, None),
    ("• Axillary lymphadenopathy", False, None),
    ("", False, None),
    ("Special Presentations:", True, HEADER),
    ("• Inflammatory BC: Erythema, warmth, rapid enlargement", False, None),
    ("  T4d — worst prognosis; dermal lymphatic invasion", False, None),
    ("• Paget's disease: nipple eczema + underlying DCIS/IDC", False, None),
    ("  Paget cells = large pale vacuolated cells in epithelium", False, None),
    ("• ILC: diffuse thickening, often bilateral, late dx", False, None),
], COL1X, inner, COL_W, size=7.2, leading=9.3)

inner = box(COL2X, R5Y, COL_W, R5H, TEAL_LITE, TEAL, "◆  PROGNOSTIC & PREDICTIVE FACTORS")
wrap_lines([
    ("FAVOURABLE:", True, GREEN),
    ("• Small size T1 ≤2 cm", False, None),
    ("• Node-negative N0 — strongest single predictor", False, None),
    ("• Low grade G1  |  ER+/PR+ strongly positive", False, None),
    ("• Low Ki-67 (<20%)  |  Luminal A subtype", False, None),
    ("• Tubular / mucinous histological type", False, None),
    ("• High TILs (tumour-infiltrating lymphocytes) in TNBC", False, None),
    ("", False, None),
    ("UNFAVOURABLE:", True, RED_DARK),
    ("• LN positivity — single strongest adverse predictor", False, None),
    ("• High grade G3  |  Large tumour T3/T4", False, None),
    ("• HER2+ or TNBC subtype  |  High Ki-67 (≥30%)", False, None),
    ("• Lymphovascular invasion  |  BRCA1 mutation", False, None),
    ("• Inflammatory carcinoma T4d", False, None),
], COL2X, inner, COL_W, size=7.2, leading=9.3)

inner = box(COL3X, R5Y, COL_W, R5H, AMBER_L, AMBER, "◆  TREATMENT OVERVIEW  (Pathology-Guided)")
wrap_lines([
    ("SURGERY:", True, AMBER),
    ("• Lumpectomy + RT (breast-conserving, early stage)", False, None),
    ("• Mastectomy ± reconstruction (large/multifocal)", False, None),
    ("• Sentinel LN biopsy → axillary dissection if positive", False, None),
    ("", False, None),
    ("ENDOCRINE  (ER+/PR+):", True, AMBER),
    ("• Pre-menopausal: Tamoxifen (5–10 yrs)", False, None),
    ("• Post-menopausal: Aromatase inhibitors", False, None),
    ("", False, None),
    ("ANTI-HER2  (HER2+):", True, AMBER),
    ("• Trastuzumab + Pertuzumab + Taxane", False, None),
    ("• T-DM1 / T-DXd for residual/metastatic disease", False, None),
    ("", False, None),
    ("TNBC (Triple Negative):", True, AMBER),
    ("• Anthracycline + Taxane ± Carboplatin (neoadjuvant)", False, None),
    ("• BRCA+: Olaparib / Talazoparib (PARP inhibitors)", False, None),
    ("• PDL-1+: Pembrolizumab + Chemotherapy", False, None),
], COL3X, inner, COL_W, size=7.2, leading=9.3)

# ── VERTICAL DIVIDERS ─────────────────────────────────────────────────────
c.saveState()
c.setStrokeColor(BORDER); c.setLineWidth(0.5); c.setDash(3,3)
c.line(COL2X-PAD/2, H-HDR_H-MARGIN, COL2X-PAD/2, FOOT_H+MARGIN)
c.line(COL3X-PAD/2, H-HDR_H-MARGIN, COL3X-PAD/2, FOOT_H+MARGIN)
c.restoreState()

c.save()
print(f"✅ PDF with images saved: {OUT}")
Running Command

cd /home/daytona/workspace/breast-cancer-chart && python3 chart_pdf_images.py

Running Command

ls -lh /home/daytona/workspace/breast-cancer-chart/Invasive_Breast_Cancer_With_I…

Your updated chart paper with histopathology images is ready:

Invasive Breast Cancer With Images

PDF Document · PDF


What's included in the image strip

A dedicated full-width "Histopathology & Imaging" panel runs across the centre of the chart with 6 labelled images, all sourced directly from Sabiston Surgery and Schwartz Surgery textbooks:
PanelImage
1IDC (histo) — haphazard malignant cells infiltrating stroma
2IDC scirrhous — 100× and 200× (productive fibrosis pattern)
3ILC (histo) — classic single-file "Indian file" pattern
4ILC 100× — small lobular cells, discohesive
5Mucinous carcinoma — tumour cells floating in mucin lakes
6Mammogram — spiculated mass with skin tethering (IDC)
Print tip: The file is A2 landscape (9.2 MB, high resolution). Print at A2 or A1 for best legibility. If your printer only does A3/A4, choose "Fit to page" in the print dialog — all text and images scale cleanly.
This is a shared conversation. Sign in to Orris to start your own chat.