Skip to content

Stacked bar chart option for generic assay tracks#5539

Merged
inodb merged 31 commits into
cBioPortal:masterfrom
inodb:oncoprint-stacked-bars
Jul 1, 2026
Merged

Stacked bar chart option for generic assay tracks#5539
inodb merged 31 commits into
cBioPortal:masterfrom
inodb:oncoprint-stacked-bars

Conversation

@inodb

@inodb inodb commented Apr 21, 2026

Copy link
Copy Markdown
Member

Summary

Adds a "Show as stacked barchart" option for generic assay tracks. Composition mode (each bar = 100%) and absolute mode (bars scaled to max total, bottom-anchored) both route through the existing STACKED_BAR rule set used by the Mutational Spectrum clinical track, so rendering follows the existing pattern.

  • Paired profiles that describe the same categories (e.g. relative + absolute cell-type counts) share a color palette and collapse to a single legend
  • Tableau10/20 palette for distinct colors
  • Fixes two pre-existing oncoprintjs crashes surfaced while wiring this up:
    • addTrack cluster-sort path pushing undefined into group_arrays
    • addTracks race where label_view read track_tops before sort() completed

Test study: msk_spectrum_tme_2022 (cell-type relative + absolute counts)

Preview

image

Caveat: note that this surfaced an issue that this study actually uses FACS gating so we need some way to indicate that clearly. Will work on a follow up PR for that.
Closes cBioPortal/cbioportal#10747

🤖 Generated with Claude Code

@netlify

netlify Bot commented Apr 21, 2026

Copy link
Copy Markdown

Deploy Preview for cbioportalfrontend ready!

Name Link
🔨 Latest commit ecf5ed3
🔍 Latest deploy log https://app.netlify.com/projects/cbioportalfrontend/deploys/6a44555c63233500080fa0b2
😎 Deploy Preview https://deploy-preview-5539.preview.cbioportal.org
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

})),
}));

// Fetch each profile's batches in parallel, then concat per profile so

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@inodb this is optimization here right?

@inodb inodb force-pushed the oncoprint-stacked-bars branch from da428e5 to 32ba8aa Compare May 29, 2026 11:03
@inodb inodb marked this pull request as ready for review May 29, 2026 11:03
Copilot AI review requested due to automatic review settings May 29, 2026 11:03
@inodb inodb changed the title Stacked bar chart option for generic assay tracks (#10747) Stacked bar chart option for generic assay tracks May 29, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds generic-assay stacked bar chart rendering to the results-view Oncoprint, including URL-driven chart modes, menu controls, sorting options, shared palettes/legends, and supporting oncoprintjs rendering fixes.

Changes:

  • Adds heatmap, bar, stacked composition, and stacked absolute chart-type flows for generic assay tracks.
  • Extends oncoprintjs stacked-bar rulesets, track menus, move controls, WebGL clipping, and async track-position handling.
  • Adds robustness fixes for generic-assay data fetching/cache errors and targeted unit tests for sorting/prefix trimming.

Reviewed changes

Copilot reviewed 20 out of 21 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/shared/lib/LazyMobXCache.ts Passes an Error object when cached fetches fail.
src/shared/lib/GenericAssayUtils/GenericAssayCommonUtils.ts Batches generic-assay data POSTs by stable ID chunks.
src/shared/components/oncoprint/TooltipUtils.ts Adds stacked-bar tooltip formatting and filters null tooltip data.
src/shared/components/oncoprint/SortUtils.ts Adds stacked-bar sort comparators.
src/shared/components/oncoprint/SortUtils.spec.ts Covers stacked-bar sort comparator behavior.
src/shared/components/oncoprint/ResultsViewOncoprintUtils.tsx Adds generic-assay chart-type entries to track-group menus.
src/shared/components/oncoprint/ResultsViewOncoprint.tsx Wires stacked/bar generic-assay tracks, URL state, and profile reordering.
src/shared/components/oncoprint/OncoprintUtils.ts Builds generic-assay heatmap/bar/stacked tracks, palettes, labels, menus, and aggregation.
src/shared/components/oncoprint/OncoprintUtils.spec.ts Tests shared-prefix trimming.
src/shared/components/oncoprint/Oncoprint.tsx Extends track spec types for bar and stacked-bar variants.
src/shared/components/oncoprint/DeltaUtils.ts Transitions generic-assay bar/stacked tracks and custom options.
src/shared/cache/GenericAssayMolecularDataCache.ts Hardens augmentation against null/non-matching generic-assay results.
src/pages/studyView/addChartButton/genericAssaySelection/GenericAssaySelection.tsx Adds select-all and chart-type selection UI for generic assays.
src/pages/resultsView/ResultsViewURLWrapper.ts Registers new generic-assay chart-mode URL parameters.
src/pages/resultsView/oncoprint/TracksMenu.tsx Enables select-all and chart-type selector for generic assay tracks.
src/AppStore.ts Guards global error handling against undefined errors.
packages/oncoprintjs/src/js/oncoprintwebglcellview.ts Widens WebGL near plane for many stacked shapes.
packages/oncoprintjs/src/js/oncoprinttrackoptionsview.ts Adds submenu, touch handling, and custom move up/down support.
packages/oncoprintjs/src/js/oncoprintruleset.ts Adds absolute scaling support to stacked-bar rulesets.
packages/oncoprintjs/src/js/oncoprintmodel.ts Adds custom track options/move state and fixes track-position/cluster-sort issues.
.gitignore Ignores common-dist/.

Comment on lines +2281 to +2287
if (!anyCatHasAnySample) {
datum.na = true;
datum.attr_val_counts = {};
} else {
datum.attr_val_counts = filled;
datum.attr_val = filled;
}
Comment on lines +1332 to +1347
// If the profile has no entities left, drop it from both stacked sets.
if (entities.length === 0) {
if (this.genericAssayStackedProfiles[molecularProfileId]) {
updates.generic_assay_stacked_profiles = this.serializeStackedProfiles(
_.omit(this.genericAssayStackedProfiles, molecularProfileId)
);
}
if (this.genericAssayStackedAbsoluteProfiles[molecularProfileId]) {
updates.generic_assay_stacked_absolute_profiles = this.serializeStackedProfiles(
_.omit(
this.genericAssayStackedAbsoluteProfiles,
molecularProfileId
)
);
}
}
Comment on lines +282 to +285
export interface IStackedBarTrackSpec extends CategoricalTrackSpecBase {
stackedBar: true;
// Order of categories in each stack (bottom-to-top in rendering terms).
stackedBarCategories: string[];
Comment on lines +2066 to +2069
const genericAssayProfileOrder = _.orderBy(
Object.values(molecularProfileIdToAdditionalTracks),
g => g.trackGroupIndex
).map(g => g.molecularProfileId);
Comment on lines +1829 to +1835
if (prevSortBy !== nextStacked.stackedBarSortByCategory) {
// Category order changed (sort-by moves to the bottom of the
// stack), so rebuild the rule set to match the new visual order.
oncoprint.setRuleSet(
trackId,
getCategoricalTrackRuleSetParams(nextStacked)
);
Comment on lines 1681 to 1693
if (
rulesetTrackId === trackId &&
(nextSpec as any).showAsBar !== (prevSpec as any).showAsBar
) {
oncoprint.setRuleSet(
trackId,
getHeatmapTrackRuleSetParams(
nextSpec,
nextProps.isWhiteBackgroundForGlyphsEnabled
)
);
}
oncoprint.shareRuleSet(rulesetTrackId!, trackId);
inodb and others added 18 commits June 30, 2026 15:49
Adds a "stacked bar chart" visualization for generic assay tracks
(composition + absolute modes), shared palette across paired profiles
that describe the same cell types, a single legend when both paired
tracks are visible, and fixes two pre-existing crashes in oncoprintjs
(cluster-sort undefined length, addTrack race in label_view).

Composition mode (each bar sums to 100%) and absolute mode (bars
scaled to max total, bottom-anchored) reuse the existing STACKED_BAR
rule set used by the Mutational Spectrum clinical track, so rendering
matches the existing stacked-bar track.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The shader packs the shape-list index as gl_Position.z. The ortho
projection's near plane was -5, mapping z_index=6..9 below NDC_z=-1
and getting frustum-clipped. This is only a visible bug for stacked
tracks with 7+ categories — Mutational Spectrum (6 cats) stayed just
inside the frustum, but the new generic-assay stacked-bar track used
10 cell-type categories and rendered at ~60% height (last 4 rects
clipped).

Widen near to -1000 so z_index has ~1000 shapes of headroom.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…p header

- Add "Sort by <category>" items to the stacked-bar track menu. Selecting
  one sets the track as primary sorter with a descending-by-value
  comparator; "Sort by total (default)" clears it. Persists via URL
  param `generic_assay_stacked_sortby=<profileId>:<entityId>`.
- Skip the big track-group section header (and its Cluster / Don't-cluster
  options) when a profile is displayed as a stacked-bar track — it's a
  single-row track that already carries its label, and cluster doesn't
  make sense for a single stacked track.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…adient

Each entity gets its own row (as before) but the heatmap gradient is
replaced by a bar whose height is proportional to the value, using the
BAR rule set (same machinery as the clinical "number" track). Toggle
from the per-row track menu: "Show as bar chart" / "Show as heatmap
gradient". Persists via URL param \`generic_assay_bar_profiles\` (set of
profile IDs, semicolon separated).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previously fractions and counts rendered with a dark-blue-at-zero
gradient (`[darkBlue, lightBlue, lightRed, darkRed]` when pivot in
middle), which left a cold blue sliver at zero and made low values
read as "absence of signal, blue" rather than "absence of signal,
background". When leftBoundaryValue >= 0 we now skip the blue half of
the scale entirely and use `[white, darkRed]` (or `[white, lightRed,
darkRed]` if a pivot falls inside the data range). Negative-valued
tracks (log2 ratios, etc.) still use the blue-to-red scheme.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the 11 flat "Sort by <cat>" items with a single "Sort by ▸"
parent that reveals the category list on hover, unclutters the track
menu. Adds optional \`children?: CustomTrackOption[]\` to
CustomTrackOption; when present the option renders as a hover-
expanding parent instead of a leaf.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Collapse all chart-type toggles (separate heatmap / separate bars /
  stacked composition / stacked absolute) under a single "Chart type ▸"
  hover submenu. Current selection marked with ✓.
- Detect fraction-like profiles (max per-sample total <= 1.01 across
  all entities in the profile) and hide the "Stacked bar (absolute)"
  option for them — absolute mode on fractions produces identical
  100% bars, so it's meaningless.
- Unified setGenericAssayChartType action atomically toggles both
  stacked and bar URL params so transitions between the four view
  types don't leave inconsistent intermediate state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The stacked-bar track menu exposes a "Sort by >" submenu for picking a
category, so the default "Sort a-Z / Sort Z-a / Don't sort" items were
redundant. Added a sort_direction_menu_visible track param in oncoprintjs
to gate rendering of those items while leaving programmatic sort intact.

Also relabeled the default sort option to "Dominant category (default)"
since the comparator sorts by dominant category + proportion, not by a
total (which is always 1 for fraction-like data).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two related issues surfaced when using the generic-assay stacked-bar
track menu on a phone:

1. Sort-by category never applied. Root cause: the MobxPromise that
   builds the stacked-bar track specs read oncoprint.genericAssayStackedSortBy
   after an `await`, so MobX stopped tracking it and the promise never
   re-invoked when URL state changed. Snapshot the observable before the
   first await to restore reactivity.

2. Menu items (Move up, Move down, Sort by submenu children, etc.) did
   not respond to taps on touch devices. Native click often doesn't fire
   on <li> elements on iOS Safari unless touch-action is explicit. Added
   touch-action: manipulation to remove the 300ms delay, and attached a
   touchend fallback alongside click with per-handler debounce. Also
   closes the outer dropdown when a submenu child is selected so the
   effect is visible.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When a user picks a category to sort by, they're asking to compare that
dimension across samples. Leaving the category mid-stack makes comparison
hard because each bar's top edge drifts. Reorder the stack so the picked
category renders at the bottom — every bar shares the same baseline, and
the visual gradient reads cleanly.

Delta detection also rebuilds the rule set on sort-by change so the new
visual order takes effect without a full track re-add.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two small additions to the oncoprint UI:

- GenericAssaySelection gains an optional selectAllThreshold prop.
  When set (TracksMenu passes 25), a "Select all" button appears next to
  the submit button — but only if the profile has few enough entities to
  make a one-click bulk-add reasonable. Larger profiles (hundreds of
  entities) keep the old behavior so users aren't one tap away from
  flooding the oncoprint.

- Stacked-bar tracks in absolute mode get a "Total" entry in the
  Sort by submenu, above the per-category list. It orders samples by
  the sum of all category values descending. Intentionally hidden in
  composition mode, where every bar totals 1 and a total-sort is a
  no-op. Uses the sentinel "__total__" for stackedBarSortByCategory.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previously, Move up/Move down in the track menu only reordered tracks
within their containing group. That's fine when a group has siblings,
but stacked-bar generic-assay tracks render as a single-track group
without a header — so the user sees a track sitting next to genes and
clinical rows and expects Move up/Down to reorder it past them, only to
find the buttons were no-ops.

Added a swapTrackGroups(i, j) pair on the model + Oncoprint. When the
track has no siblings in its group, Move up/Down now swaps the whole
(single-track) group with its neighbor. Within-group behavior is
unchanged when siblings exist.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previously hidden because the new "Sort by" submenu looked like enough,
but a-Z/Z-a actually flips the direction of whichever comparator is
active (including the Sort-by-category one) — useful and distinct from
picking the sort key. Removed the now-unused sort_direction_menu_visible
flag introduced earlier in this branch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sort-direction fix: the category/total comparators were written descending
(largest first) with init_direction=1, which flipped the cbioportal a-Z
= ascending convention. Sort a-Z ended up showing largest values first
and Sort Z-a showed smallest — inverted from what the labels imply.

Now the comparators sort ascending and the picked-category default uses
direction=-1, so:
- Sort a-Z → smallest value first (matches label)
- Sort Z-a → largest value first (matches label)
- Picked category default → largest first (what the UI wants initially)

Menu reorder: Chart type ▸ moves to the bottom of the stacked-bar track
menu with a separator above it. Everything else is sort-related; the
separator groups them visually and puts the less-frequently-used
rendering-mode toggle out of the way.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Move up/down were disabled whenever the track's group was flagged as
clustered, even for groups with a single track — where clustering is a
no-op and the grayed items just look broken. Require > 1 tracks in the
group before considering the clustered flag a reason to disable moves.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…space

Move up/down on a stacked-bar track is now a real reorder: the two
generic-assay profiles' track-group indexes swap via a new
swapGenericAssayProfileOrder action. The track spec keys include the
current trackGroupIndex so the delta layer remove/re-adds tracks in the
new groups, keeping React state and the oncoprintjs model in sync — no
more desync on a later unstack.

Items gray out at the limits: Move up is disabled when the profile is
already at the top of the generic-assay section, Move down when it's at
the bottom. Crossing into the hardcoded gene (1) or clinical (0) group
is still out of scope; swap is limited to profiles that share the
dynamic generic-assay index space, which keeps the change local.

Plumbing: oncoprintjs gains on_move_up / on_move_down callback overrides
and move_up_disabled / move_down_disabled flags on the track spec;
ICategoricalTrackSpec gains the same (onMoveUp / onMoveDown /
moveUpDisabled / moveDownDisabled); molecularProfileIdToTrackGroupIndex
is now @observable so swaps propagate.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The bulk-select button now sits to the left of the primary submit button
and flips between "Select all" and "Clear all" based on whether anything
is selected, so it's a one-tap toggle instead of two separate buttons.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
inodb and others added 9 commits June 30, 2026 15:49
Covers profiles like the 48-signature mutational-signature set on
msk_impact_50k_2026 where a one-click "Select all" is genuinely useful.
Still well below the 100-option search cap, so the button never appears
when the dropdown is paginated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
onClickAddGenericAssays in ResultsViewOncoprint reached info[0].profileId
with no prior length check, so submitting an empty track selection (now
easier to trigger via "Clear all" + Add Track) threw. Bail out when
info is empty.

AppStore's global service-error handler assumed the error argument was
always defined and would crash on `error.status` when a promise rejected
with `undefined` — which then masked whatever failure triggered the
reject. Guard the access so the handler survives undefined.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…abel prefix

Scale fixes triggered by adding all 30 mutational signatures to the
oncoprint on msk_impact_50k_2026 (~50k samples):

- fetchGenericAssayData now chunks stableIds into batches of 5 per POST.
  A single request for all 30 signatures produced ~750 MB of row-per-
  datum JSON, which V8 couldn't parse and quietly returned null.
  Backend-side fix tracked separately: cBioPortal/cbioportal#12131.
- augmentQueryResults skips null / non-iterable responses instead of
  throwing a TypeError that cascaded into a cache error state.
- LazyMobXCache.tryTrigger now passes a real Error to the promise's
  error callback; previously called it with no arg, so every downstream
  handler saw `undefined` and could crash on `error.status`.

UX fix for generic-assay split-mode labels:

- Track labels from the same profile share the same long prefix
  ("mutational_signatures_contribution_v2_Signature1", etc.). Under the
  label-column truncation every row rendered as "mutational_sign...".
  Strip the common prefix per profile, cut at the last separator
  (_, -, ., :, whitespace) so a meaningful token stays. Labels become
  "Signature1", "Signature2", ..., "Signature30".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Users previously had to add tracks, then drill into each track's menu to
switch Chart type ▸. Adds a radio row above the submit button (Separate
rows heatmap / Separate rows bar chart / Stacked bar composition /
Stacked bar absolute) that maps the selection into the URL's stacked /
bar profile params via setGenericAssayChartType, so the tracks appear in
the chosen form on the first render.

Gated behind showChartTypeSelector so the study-view AddChart surface —
which shares GenericAssaySelection — stays unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…eader

Tests:
- SortUtils.spec: covers makeStackedBarTrackSortComparatorByCategory
  (ascending by picked category, NA-to-end, missing category treated as 0)
  and makeStackedBarTrackSortComparatorByTotal (sum ordering, NaN handling,
  NA-to-end).
- OncoprintUtils.spec: covers commonPrefixLength — no-strip when shared
  prefix has no separator, cut at last separator within the common prefix,
  support for _ - . : and whitespace separators, prefix-of-another case.
  Exported the helper for this.

UX:
- Chart type options now appear in the generic-assay track-group header
  menu (Heatmap / Bar chart / Stacked bar (composition / absolute)),
  not just inside each per-row track's menu. Switching to a stacked
  mode swaps to the single-row render path; the header disappears as
  expected once the profile is stacked.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Restructure the Add Tracks dialog so the elements stack by purpose:
- Row 1: entity search + Select all / Clear all
- Row 2: "Chart type:" radios (flex-wrap row below the dropdown)
- Row 3: full-width Add Track button

The radios were cramped inline on the same row as the dropdown; dropping
them to their own row gives them breathing room and keeps the primary
Add Track CTA visually distinct as the final commit step.

btn-block / inline width:100% wouldn't take effect here (something in the
global CSS is pinning .btn width to content), so the button is flex: 1
inside a flex container which reliably stretches it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…inner

ICategoricalTrackSpec is now a union of ISingleCategoricalTrackSpec (the
classic single-value track) and IStackedBarTrackSpec (where the datum's
attr_val is a category->number map and stackedBarCategories +
stackedBarFills are required). Consumers narrow via `if (spec.stackedBar)`
and drop the redundant `&& spec.stackedBarCategories` guards.

Loading spinner on chart-type switch:

- Include genericAssayStackedBarTracks in the isLoading check so the
  spinner shows while the stacked-bar promise is fetching.
- setGenericAssayChartType now flips renderingComplete to false so the
  spinner also shows during the React re-render of the track set —
  swapping 30 per-entity tracks for 1 stacked track (or vice versa)
  takes long enough on large studies to look like a hang. The Oncoprint
  lifecycle calls onReleaseRendering once the new tracks are on screen,
  flipping the flag back.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A CPU-profile of a chart-type swap on msk_impact_50k_2026 (50k samples,
30 mutational signatures) showed 95s in exporter.trim — all reached via
the core-js polyfills for parseInt and parseFloat. Two hot paths:

1. OncoprintModel.getRuleSets dedup'd numeric rule-set ids through a
   number → toString → arrayUnique → parseInt roundtrip. Replaced with
   Array.from(new Set(ids)) so numbers stay numbers. Cuts ~95s.
2. StackedBarRuleSet's per-shape height/y functions called parseFloat
   on every category's value for every sample, every render. Each call
   went through the polyfill's trim(). Replaced with the unary-plus
   coercion (`+d[...][...]`) — same result, no polyfill, ~5x faster on
   its own plus no trim overhead. Cuts ~93s (48s + 45s across height
   and y).

Chart-type swap on that study goes from ~153s to ~61s end-to-end. More
cleanup possible in the remaining WebGL vertex/shape loop (still the
top post-fix hotspot at ~7.6s), but this is the big win.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Same polyfill-avoidance fix as the stacked-bar shape functions: every
parseFloat call goes through core-js's polyfill which trims its input.
In the heatmap track build path we map every datum with
{...d, value: parseFloat(d.value)}, which for 30 signatures × 50k
samples on msk_impact_50k_2026 = 1.5M parseFloat calls per render.
Also two isFractionLikeByProfile loops that parseFloat every datum
value. All converted to +d.value — same behaviour, ~5s saved.

Also gitignore the common-dist/ build artifacts that rspack drops at
the repo root during dev; accidentally committing them dwarfs the
actual diff.

Note: the dominant remaining cost on that URL is seamless-immutable
deep-freezing the generic-assay data cache in LazyMobXCache.updateCache
(~30s in addPropertyTo + Immutable + the resulting GC). That's a
structural change to the shared cache implementation and not in
scope for this PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@inodb inodb force-pushed the oncoprint-stacked-bars branch from 32ba8aa to f464045 Compare June 30, 2026 15:50
@inodb inodb added the feature label Jun 30, 2026
miccheck12 and others added 4 commits June 30, 2026 22:55
Condense over-verbose comment blocks and drop change-history narration and
comments that merely restate the code, keeping the non-obvious rationale
(MobX await-tracking, sync track_tops, frustum near-plane, fraction
detection, etc.). Comments only; no logic changes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JEbP4a7tGv74r3RtNYt7Jw
Nothing in the build config, scripts, or templates produces or references a
common-dist/ directory; the entry was unrelated to the stacked-bar work.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JEbP4a7tGv74r3RtNYt7Jw
- All-zero stacked rows render as N/A instead of NaN bar heights (builder
  marks zero-total rows NA; ruleset guards a zero denominator)
- Clear generic_assay_bar_profiles when a profile's last entity is removed,
  so it doesn't reappear as a bar chart on re-add
- Move up/down on stacked tracks stays within generic-assay profiles
- Rebuild the stacked rule set when the entity set or absolute-mode max
  changes, not only on sort-by change
- Rebuild the shared heatmap/bar rule set order-independently so all rows
  switch chart type on a heatmap<->bar toggle
- Fix reversed top/bottom category-order doc comment

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JEbP4a7tGv74r3RtNYt7Jw
Match the prominent Add Track button so the two heatmap-add actions are
styled consistently.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JEbP4a7tGv74r3RtNYt7Jw
@inodb inodb merged commit 0b17d19 into cBioPortal:master Jul 1, 2026
20 of 22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Stacked Bar Chart for Generic Assay to Oncoprint

4 participants