# CalibrationStrip (/docs/charts/calibration-strip)

CalibrationStrip answers "when this model says 70%, does it happen 70% of the time — and where is there enough data to
even ask?". Each bin is a dot at its predicted probability and its observed frequency, read against the identity
diagonal, with a quiet support lane underneath. Bins with too little data render open and faded, so a confident-looking
dot is never backed by three samples.

```tsx
<CalibrationStrip
  data={[
    { predicted: 0.05, observed: 0.05, count: 100 },
    { predicted: 0.15, observed: 0.16, count: 90 },
    { predicted: 0.25, observed: 0.24, count: 80 },
    { predicted: 0.35, observed: 0.36, count: 70 },
    { predicted: 0.45, observed: 0.44, count: 60 },
    { predicted: 0.55, observed: 0.56, count: 50 },
    { predicted: 0.65, observed: 0.63, count: 40 },
    { predicted: 0.7, observed: 0.52, count: 30 },
    { predicted: 0.85, observed: 0.83, count: 8 },
    { predicted: 0.95, observed: 0.9, count: 5 },
  ]}
  title="Model calibration"
  width={300}
  height={44}
/>
```

## Install

```tsx
import { CalibrationStrip } from "@microcharts/react/calibration-strip";

<CalibrationStrip data={reliability} title="Model calibration" />
```

Setup (package + stylesheet): [Quickstart](/docs/quickstart#set-up-with-an-ai-agent) or paste [`/agent-setup.md`](/agent-setup.md) into your agent.


## When to use it

- **Good for** — classifier reliability / trust, probability-forecast auditing.
- **Avoid for** — a single accuracy number (Delta) or where the errors go
  ([ConfusionGrid](/docs/charts/confusion-grid)).


## Variants

```tsx
<CalibrationStrip
  data={[
    { predicted: 0.1, observed: 0.08, count: 90 },
    { predicted: 0.3, observed: 0.36, count: 70 },
    { predicted: 0.5, observed: 0.44, count: 55 },
    { predicted: 0.7, observed: 0.52, count: 30 },
    { predicted: 0.9, observed: 0.85, count: 8 },
  ]}
  mode="bars"
/>
```

```tsx
<CalibrationStrip
  data={[
    { predicted: 0.2, observed: 0.21, count: 40 },
    { predicted: 0.5, observed: 0.44, count: 30 },
    { predicted: 0.7, observed: 0.52, count: 30 },
  ]}
  locale="de-DE"
/>
```

Nothing visible changes with `locale` — this chart draws no numerals. It localizes the announced numbers: with
`locale="de-DE"` the accessible name above reads "3 bins; largest gap at 0,7 predicted (observed 0,52); 0 low-support
bins." — the locale's own decimal mark, not "0.7".

## Edge cases

```tsx
<CalibrationStrip
  data={[
    { predicted: 0.2, observed: 0.21, count: 25 },
    { predicted: 0.4, observed: 0.39, count: 25 },
    { predicted: 0.6, observed: 0.63, count: 25 },
    { predicted: 0.8, observed: 0.79, count: 25 },
  ]}
/>
```

```tsx
// each bin's count sits under the default minSupport (max(10, 2% of total))
<CalibrationStrip
  data={[
    { predicted: 0.3, observed: 0.2, count: 3 },
    { predicted: 0.6, observed: 0.7, count: 4 },
    { predicted: 0.9, observed: 0.6, count: 3 },
  ]}
/>
```


## Why this default

Dots plus an always-on support lane because "how sure" and "based on how much" must travel together — a reliability read
without support disclosure is exactly the failure this chart exists to prevent. Low-support bins are drawn open and
faded and the count is never disableable. There is deliberately no single-number calibration score (ECE) rendered or
announced: one number would hide precisely the per-bin structure the chart exists to show.

## Accessibility

The accessible name reports the worst miscalibration and the support gaps — **"5 bins; largest gap at 0.7 predicted
(observed 0.52); 1 low-support bin."** The interactive entry roves the bins with ←/→, announcing each bin's predicted
and observed probability and its sample support.

The interactive entry follows the shared [interaction contract](/docs/accessibility#one-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

| Prop | Type | Description |
| --- | --- | --- |
| `data` (required) | `RawPair[] \| BinnedRow[]` | Raw pairs or pre-binned reliability rows. |
| `bins` | `number` | Uniform bin count for raw input. |
| `minSupport` | `number` | Below this a bin renders low-confidence. |
| `mode` | `"dots" \| "bars"` | Bars draw signed deviation columns. |
| `color` | `string` | Accent stroke/fill override. |
| `animate` | `boolean` | (interactive) Opt-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](/docs/quickstart#the-shared-grammar).
