Skip to content
microcharts
ReferenceDecisionEnsembleGhosts

EnsembleGhosts

React ensemble ghosts chart — faint ensemble paths with an emphasised median-like member. Tiny accessible SVG microchart; RSC-safe static or /interactive.

EnsembleGhosts answers "what could happen, across the simulated futures?". It draws a faint bundle of member paths with one emphasized representative — because a mean line hides that futures disagree in shape, not just endpoint. Ghost selection is fully deterministic (evenly spaced endpoint-rank quantiles), so the same input renders identically every time.

EnsembleGhosts
interactive · 6.38 kB · static · 3.28 kB

Install

Import & usereact/ensemble-ghosts
import { EnsembleGhosts } from "@microcharts/react/ensemble-ghosts";// futures — real values under “Sample data” below<EnsembleGhosts data={futures} title="Simulated futures" />
Sample data
// 24 simulated futures — a fan of walks with diverse shapesconst futures = Array.from({ length: 24 }, (_m, i) =>  Array.from({ length: 10 }, (_, t) =>    Math.round(40 + (i - 12) * 0.55 * t * 0.4 + 3 * Math.sin(i + t) + t * 0.5),  ),);
Needs package + stylesheetSet up with AI

Try it

When to use it

  • Good for — a KPI card that shows the futures, not the average; Monte-Carlo / simulation output where paths disagree in shape; showing that outcomes fan out.
  • Avoid for — interval precision (ForecastCone) or a single path (Sparkline).

Sizing

Variants

endpoint dots + synthetic median

Edge cases

single member
locale

With one member, there is no bundle to show — the chart draws that single path as the representative, and the summary states its ending value rather than a spread. A member that contains a non-finite value (NaN, Infinity) is excluded entirely from ghost selection and the median, not gapped mid-path — a dev-only console warning flags it, since a partially invalid future usually means bad simulation output.

Four homes

Why this default

A few faint paths and one emphasized, because a mean line hides that futures disagree in shape, not just endpoint — two ensembles can share an average and a final range while telling completely different stories along the way. The emphasized path defaults to the real member closest to the pointwise median, so the representative is an outcome that actually happened in the simulation, not a synthetic average of paths that never occurred (emphasis="median" draws that synthetic path instead). Selection and emphasis are deterministic — nothing about this chart varies between renders of the same data. label="end" (default) states the emphasized path's landing value in a right gutter; pass label="none" to drop it.

The static frame is not a hypothetical-outcome plot. The loop — flipping through the members one at a time on hover — is the HOP, and it lives only in the interactive entry, gated on reduced motion with arrow-key stepping as the non-animated equivalent.

Accessibility

The accessible name states the endpoint spread and the typical path — "5 simulated paths end between 28 and 61; typical path ends near 50." The interactive entry flips through the members (the HOP loop) on hover; with reduced motion, ←/→ step them discretely, and each member is announced with its endpoint.

The interactive entry follows the shared interaction contract: arrow keys rove between units on both axes, Home and End jump to the ends, and a click, tap, Enter or Space selects a unit — pinning its readout so it survives blur, until you select it again or press Escape. On touch, a tap pins and a drag scrubs.

Props

PropTypeNotes
data*number[][]Ensemble members — 2–50 simulated paths.
ghostsnumberRendered member count (deterministic endpoint-rank selection). Default 8, cap 12.
emphasis"nearest-median" | "median" | numberA real median-like member, the synthetic median, or a pinned member.
endpointsbooleanGhost endpoint dots — makes the final-value spread countable.
label"end" | "none"Emphasised path endpoint in a right gutter (default end).
animatebooleaninteractiveOpt-in entrance motion when the chart mounts client-side — add import "@microcharts/react/motion" once. Inert on the server, on hydrated server HTML, and under prefers-reduced-motion.

Plus the shared grammar — data, domain, color, title, summary, format — and the layout props (width, height, className, style) that every chart accepts. Interactive entries also share animate and live, and — wherever a chart has more than one navigable unit — onActive, onSelect, selectedIndex and defaultSelectedIndex; and — wherever the chart shows a hover value — readout. See the shared grammar.

Related charts