accepted

Heatmap colour ramp is invariant across `valueMode`; only labels change

`valueMode: "count" | "intensity" | "share"` only changes the scale-bar copy and tooltip phrasing. Cell fills are always driven by intensity (`count / maxCount`). Switching mode never repaints the surface — so two heatmaps in different modes remain visually comparable.

Heatmap apivisual-encodingdata-integrity

Context

Three legitimate ways to answer “how hot was this cell?”:

  • count — raw event count. Honest but not normalised — dense matches swamp sparse matches.
  • intensitycount / maxCount. Relative within the chart.
  • sharecount / totalEvents. Normalised against the whole dataset (useful when the chart is cropped).

The trap: if cell fill depends on mode, then the same cell in the same dataset renders differently under share vs count, breaking pattern recognition. Consumers comparing two heatmaps side-by-side can’t tell whether a darker cell means more events or a different mode selection.

Decision

Fill is always intensity. valueMode only retitles the scale bar and tooltip rows — “3 events” vs “50% intensity” vs “12% share”. The underlying colour scale domain is [0, maxCount] computed once and shared across all modes.

Consequences

  • Visual comparability is preserved across modes. A cell that reads “dark red” is the local maximum regardless of whether the user is looking at counts, shares, or intensities.
  • Consumers who genuinely want a share-driven fill (e.g. for cross-chart normalisation) override with a custom colorScale keyed to share values.
  • The tooltip label is the user-facing vocabulary switch; the scale bar caption follows the same rule (see metricLabel prop).
  • share mode’s denominator is the filtered event total, not the raw input. Filters like teamFilter apply upstream; the denominator matches what’s actually rendered.
← All decisions