Waterfall Chart

WaterfallChart renders a local (single-prediction) explanation: it shows how each feature moved a model's output away from the average base value E[f(x)] toward the final prediction f(x). It matches the look of shap.waterfall_plot — arrow bars, sign colors, and a feature-labeled axis.

  • Takes a single ShapExplanation object ({ features, fx, efx, otherFactorsProb?, otherFactorsValue?, text? }) with no transform — it maps 1:1 to the model output.
  • Bars accumulate from efx (E[f(x)]) to the top; the prediction marker is drawn at fx (f(x)).
  • Features are sorted by |prob| (largest first) and sign-colored: blue pushes the prediction higher, red pushes it lower. Both are overridable via colors.
  • The pre-aggregated otherFactors bucket renders as a single "N other features" row, always pinned to the bottom — matching the native SHAP layout.
  • maxFeatures further collapses the tail into one "N other features" row — the dropped count is surfaced, never silently truncated.
  • compact swaps long axis labels for letter codes (324 = A) plus an expandable legend; it defaults on for narrow screens.
  • Base E[f(x)] and prediction f(x) are marked on the x-axis with dashed reference lines.

Import

import { WaterfallChart } from "h2o-library/charts";

Usage

Structured object

The recommended shape: a ShapExplanation object with nested features[] (each { name, prob, value }), fx, efx, and an optional pre-aggregated otherFactorsProb / otherFactorsValue bucket. It maps 1:1 — no client-side reshaping. The other-factors bucket renders as a pinned "N other features" row.

Deterioration risk — structured explanation

const explanation = {
  fx: 0.678, // f(x)
  efx: 0.367, // E(f(x))
  otherFactorsProb: 0.13,
  otherFactorsValue: 415,
  features: [
    {
      name: "maximum daily general orders since admission",
      prob: 0.05,
      value: 85,
    },
    { name: "fall risk score in last 24 hours", prob: 0.05, value: 6 },
    // …up to 10, sorted by |prob| desc…
  ],
};

<WaterfallChart data={explanation} />;

Net-negative explanation

When fx < efx, most drivers push the prediction lower — the bars run down and to the left from the base. Nothing special to configure; the same ShapExplanation shape handles it.

Deterioration risk — net negative

const explanation = {
  fx: 0.006, // f(x) below the base…
  efx: 0.021, // …E(f(x))
  otherFactorsProb: -0.36,
  otherFactorsValue: 388,
  features: [
    {
      name: "service in last 24 hours (Vascular Surgery)",
      prob: 0.26,
      value: 1,
    },
    {
      name: "number of unique order types in last 24 hours",
      prob: -0.09,
      value: 1,
    },
    // …
  ],
};

<WaterfallChart data={explanation} />;

Collapsing the tail

maxFeatures keeps the strongest N features and aggregates the rest into one "N other features" row.

Top 4 drivers

<WaterfallChart data={explanation} maxFeatures={4} />;

Compact mode

compact replaces feature names on the axis with short letter codes and lists A = feature name in an expandable legend below the chart — useful on narrow layouts. It defaults to true on screens ≤ 640px and false above; pass an explicit value to force it.

Compact — letter codes + legend

Feature legend
A
maximum daily general orders since admission
B
fall risk score in last 24 hours
C
age at admission
D
change in AHFS28 medication count in last 24 hours
E
maximum daily order type count since admission
F
days since last surgery date
G
IPA difficulty ambulating assessment in last 24 hours
H
IPA independent activities in last 24 hours
I
cumulative consultation orders since admission
J
415 other features
<WaterfallChart data={explanation} compact />;

Custom colors

Override the sign colors with any CSS color. Each key is independently optional.

Custom sign colors

<WaterfallChart
  data={explanation}
  colors={{
    positive: "hsl(var(--success))",
    negative: "hsl(var(--muted-200))",
  }}
/>;

Click events

Pass onBarClick to make each feature bar interactive. The handler receives the feature datum ({ feature, code, value, contribution }), its row index, and the native mouse event — bars only become pointer-interactive when a handler is provided.

Click a feature bar

No feature selected yet.

<WaterfallChart
  data={explanation}
  onBarClick={(datum, index, e) => {
    e.stopPropagation();
    console.log(datum.feature, datum.contribution);
  }}
/>;

WaterfallChart is also reachable through the high-level Chart wrapper with type="waterfall" — see that page for the wrapped version with title, info tooltip, and legend.

Data shape

The chart maps the model output 1:1 with no transform layer — serialize the ShapExplanation to JSON and pass it straight to data:

{
  "fx": 0.678,
  "efx": 0.367,
  "otherFactorsProb": 0.13,
  "otherFactorsValue": 415,
  "text": "…optional explanation…",
  "features": [
    { "name": "fall risk score in last 24 hours", "prob": 0.05, "value": 6 }
  ]
}
  • prob / value must be numbers, not strings.
  • features should be sorted by |prob| descending (the chart re-sorts anyway) and capped to the top ~10; put the rest in the otherFactors* bucket.
  • Contributions (Σ prob + otherFactorsProb) should sum to fx − efx.
  • text is ignored by the chart — render it beside the chart yourself.

Playground

Loading playground…

Props

WaterfallChart

PropTypeDefaultDescription
data*ShapExplanationThe SHAP explanation object: { features, fx, efx, otherFactorsProb?, otherFactorsValue?, text? }.
maxFeaturesnumberundefinedKeep the top-N features by |prob| and aggregate the rest into one "N other features" row.
compactbooleantrue on ≤640px, else falseReplace axis feature names with letter codes and show an expandable legend below the chart.
colors{ positive?: string; negative?: string }{ positive: primary, negative: destructive }Override the sign colors. positive = pushes prediction higher, negative = pushes it lower.
heightnumber400Height of the chart in pixels.
classNamestringundefinedAdditional CSS class for the container div.
onBarClick(datum: WaterfallBarDatum, index, event) => voidundefinedFired when a feature bar is clicked. Receives { feature, code, value, contribution }, the row index, and the native mouse event. Bars become pointer-interactive only when provided.

* Required

ShapExplanation

PropTypeDefaultDescription
features*ShapFeature[]Top influencing features ({ name, prob, value }), sorted by |prob| desc (max 10).
fx*numberf(x) — the model output probability. Marks the prediction reference line.
efx*numberE(f(x)) — the baseline (expected) probability the bars start from.
otherFactorsProbnumberundefinedSummed contribution of all features not individually listed. Renders as a pinned bottom row.
otherFactorsValuenumberundefinedCount of features grouped into otherFactors — used to label the "N other features" row.
textstringundefinedHuman-readable model explanation. Ignored by the chart — render it alongside.
recordId / losRecordId / probabilityDischargeNext2DaysnumberundefinedPassthrough identifiers/metadata; not used for rendering.

* Required

ShapFeature

PropTypeDefaultDescription
name*stringFeature name shown on the axis label and tooltip.
prob*numberSigned SHAP contribution. Positive pushes the prediction higher, negative lower.
valuenumber | stringundefinedThe feature's raw clinical value, shown in the row label and tooltip.

* Required

Design Guidelines

  • Use a waterfall to explain one prediction (local explanation) — not global feature importance across a dataset.
  • Keep the visible feature count readable; use maxFeatures (or the model's own "other factors" row) to collapse the tail.
  • Render the model's Text summary next to the chart, not inside it.
  • Prefer the Chart wrapper when you want the title, info tooltip, and legend for free.

Accessibility

  • Tooltips appear on hover and are not keyboard-accessible; for critical data provide a companion table.
  • Compact mode's legend is a native <details> element — fully keyboard-operable.
  • Sign is encoded by both color and arrow direction, so the chart does not rely on color alone.