Skip to content

OncoPrint generic-assay heatmaps: the portal's range and colours, with pivot and sort order (ONC-TT-8) - #217

Merged
alisman merged 3 commits into
masterfrom
session/oncoprint-assay-colours
Nov 14, 2026
Merged

alisman merged 3 commits into
masterfrom
session/oncoprint-assay-colours

Conversation

@alisman

@alisman alisman commented Nov 14, 2026

Copy link
Copy Markdown
Contributor

Stacked on #215 and #216. Until they merge, their commits show here too; this PR's own change is the top commit.

A generic-assay heatmap now uses the portal's range and colours, including the profile's pivot threshold and sort order (ONC-TT-8).

Case table (legacy: OncoprintUtils getGenericAssayTrackRuleSetParams 376-470, DeltaUtils 720-749, oncoprintruleset gradient)

# Case Portal Before
G1 values [1, 4] [0, 4], white → dark red [1, 4], blue-white-red
G2 [−1, 4] [−1, 4], dark → light blue [−4, 4] symmetric
G3 [−4, −1] [−4, 0], dark → light blue [−4, −1]
G4 [1, 4], pivot 2 stops [0, 2, 4]: white, light red, dark red no pivot
G5 [1, 4], pivot 0 white → dark red —
G6 [−4, −1], pivot −1 dark → light blue over [−4, 0] —
G7 [−4, 3], pivot −4 light → dark red —
G8 [−4, 3], pivot 1 [−4, 1, 1, 3]: dark blue, light blue, light red, dark red —
G9 [−4, −2], pivot 5 the pivot widens the range to [−4, 5] —
G10, G11 sort order DESC colours reversed —
G12 two entities, [1, 2] and [5, 8] both scaled to the profile's [0, 8] each its own
G13 no value the no-value cell as before
G14 (the test writer showed this is dead code in legacy) a pivot at or past an end is case 2 or 3 —
G15 legend the track's own gradient blue-white-red
G16 a molecular (non-assay) heatmap unchanged —

Checked on cbioportal.org

chl_sccc_2023, mutational signature contributions SBS1 and SBS13 (sort order DESC). The portal's gradient rule set holds value_range [0, 0.3188], colors [[213,94,0],[255,255,255]] and value_stop_points [0, 0.3188] for both rows. buildContract on the warehouse gives the same.

gbm_cptac_2021, cell type fractions (pivot 0.001, ASC): stops [0, 0.001, 0.9532], coloured white, light red, dark red. The pivot is stored as a float32, and we read it at its seven digits.

Warehouse: 34 of the 165 generic-assay profiles have a pivot, and most have a sort order: DESC for mutational signatures and methylation, ASC for cell counts and fractions.

Known, recorded in PORTAL-PARITY: a cell carries its value as one of 256 codes, so a value exactly at a pivot can take the colour on the pivot's other side. The gradient itself, through rampColor, puts it on the light-red side, as oncoprintjs does.

Tests and planted bugs

  • An agent wrote the tests from the table without seeing the change: test/oncoprint-assay-colours.test.ts covers the engine, the server SVG and the canvas, and python/tests/test_assay_colours.py covers the Python port. They failed before the change.
  • The heatmaps audit's E3, E4 and E4b, which were marked todo for this gap, now pass.
  • Planted bugs, all caught:
    • assay-range-without-zero
    • assay-pivot-ignored
    • assay-desc-not-reversed
    • assay-range-per-entity
    • ramp-repeated-stop-before
    • In Python, four equivalent bugs planted by hand were also caught.
  • npm test: 4,290 pass. The Python unittest suite passes.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Q3ezTZRWoR5xpTndPddHAe

alisman and others added 3 commits November 14, 2026 20:39
A merged row or a patient column can hold several copy-number calls. The portal counts them by
kind — driver amplification, VUS amplification, driver deep deletion, VUS deep deletion, each
apart (DataUtils fillGeneticTrackDatum) — and shows and sorts by the kind with the most calls:
its render priorities tie for amplification and deep deletion and are missing for the driver
kinds, so every comparison in selectDisplayValue comes down to the count. The cell's copy number
is a driver only when that kind is. Ours OR'd every call into the cell, so it kept both glyphs,
drew and sorted the amplification, and called the copy number a driver if any call was.

In the warehouse 40,845 patient–gene pairs in 28 studies hold both an amplification and a deep
deletion; in 563 the deletions outnumber the amplifications.

Ours alone, recorded in PORTAL-PARITY: on equal counts the portal takes the first call's kind, in
an order we do not have; ours takes a driver before a VUS, then an amplification. A driver call
that loses on count still makes the column driver-altered for the gutter's driver %.

Tests from a case table of the legacy source, written by an agent that did not see the change
(test/oncoprint-cna-calls.test.ts, python/tests/test_cna_calls.py: engine, browser re-sort,
drawing, Python), seen failing first; the staircase audit's D8 and D9, marked todo for this, now
pass. Three planted bugs caught, and the same three by hand in Python. npm test 4256 pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q3ezTZRWoR5xpTndPddHAe
…ta" last, signed number key

A clinical track's legend listed its values in the order they take colours (most frequent first).
oncoprintjs sorts the rules it shows by localeCompare of their labels (oncoprintlegendrenderer
103-157), lists only the values the drawn columns use, and puts "No data" — the NA rule, order
+Infinity — last when a drawn column has no value (oncoprintruleset 700-709). A bar track's key
is green when its range is not negative, red when not positive, both when it spans 0
(getValueRangeType 866-876, legend 257-305), its ends to 2 decimals; ours was always green.

One rule, clinicalLegend in lib/oncoprint-style.ts, draws both the server SVG's legend and the
page's (which passes the drawn columns, so Show unaltered off drops a value only hidden columns
have). A value keeps its colour; only the order changes. Ours alone: at most 8 values, "+N more".

The golden SVG's legend changes accordingly (CANCER_TYPE Breast, Colon, Lung; STAGE I, II, III,
IV, No data); its cells do not.

Tests from a case table of the legacy source, written by an agent that did not see the change
(test/oncoprint-clinical-legend.test.ts), seen failing first. Four planted bugs caught. The page
legend looked at on msk_impact_2017 with SAMPLE_TYPE and SEX: Metastasis, Mixed, Primary;
Female, Male; no page errors. npm test 4270 pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q3ezTZRWoR5xpTndPddHAe
…h pivot and sort order (ONC-TT-8)

A generic-assay heatmap row was scaled to its own data, made symmetric when it spanned 0, and
drawn on the generic blue-white-red ramp. The portal (OncoprintUtils
getGenericAssayTrackRuleSetParams, DeltaUtils 720-749) scales every row of a profile to the min
and max of all of them, widened to the profile's pivot threshold and to 0, and picks the
colours by the range and the pivot: white to dark red with no negative value (light red at a
pivot inside), else dark to light blue, light to dark red when the pivot is the minimum, or all
four with a jump at a pivot inside; a sort order of DESC reverses the colours.

assayScale (lib/oncoprint-style.ts, ported to Python) computes the range and the gradient; a
track carries its own stops and colours and heatColor draws them, so the engine, the server SVG,
the canvas and its legend all follow. The pivot and sort order come from genetic_profile, for a
peer through its share; a pivot is stored as a float32 and read at its seven digits (0.001).
rampColor puts a value on a repeated stop on the colour after it, as oncoprintjs's binary search
does.

Checked on cbioportal.org: chl_sccc_2023, mutational signature contributions SBS1 and SBS13 (DESC):
the portal's gradient rule set holds range [0, 0.3188], colours dark red → white, stops
[0, 0.3188] for both rows; buildContract on the warehouse gives the same. gbm_cptac_2021's cell
type fractions (pivot 0.001, ASC): stops [0, 0.001, 0.9532], white, light red, dark red.

Known, in PORTAL-PARITY: a value exactly at a pivot can take the colour on the pivot's other
side, because a cell carries its value as one of 256 codes.

Tests from a case table of the legacy source, written by an agent that did not see the change
(test/oncoprint-assay-colours.test.ts, python/tests/test_assay_colours.py), seen failing first;
the heatmaps audit's E3, E4 and E4b, todo for this, now pass. Five planted bugs caught, and four
by hand in Python. npm test 4290 pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q3ezTZRWoR5xpTndPddHAe
@vercel

vercel Bot commented Nov 14, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
cbiolab-genie Ready Ready Preview Nov 14, 2026 9:30pm UTC
cbiolab-new Ready Ready Preview Nov 14, 2026 9:30pm UTC
cohort-lab Ready Ready Preview Nov 14, 2026 9:30pm UTC

Request Review

@alisman
alisman merged commit 0a73464 into master Nov 14, 2026
12 checks passed
@alisman
alisman deleted the session/oncoprint-assay-colours branch November 14, 2026 23:08

This branch was successfully deployed

1 active deployment
Preview – cohort-lab — 0fb841b8 Deployed Nov 14, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant