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

CalibrationStrip draws one dot per bin at its predicted probability and its observed frequency, read against the
identity diagonal, with a support lane underneath. Bins with too little data render open and faded, so a
confident-looking dot is never backed by three samples. The support lane is always on and the count can't be disabled: a
reliability read without support disclosure is the failure this chart exists to prevent. There is deliberately no
single-number calibration score (ECE) rendered or announced, because one number would hide the per-bin structure.

```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.

## Try it

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

<CalibrationStrip
  data={reliability}
/>
```

## When to use it

Use it for classifier reliability and trust, and for probability-forecast auditing. For a single accuracy number use
Delta; for where the errors go use [ConfusionGrid](/docs/charts/confusion-grid).

## Sizing

**eval-table cell**

```tsx
<CalibrationStrip data={row.reliability} width={80} height={24} />
```

**deviation bars**

```tsx
<CalibrationStrip data={reliability} mode="bars" />
```

## 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 },
  ]}
/>
```

`minSupport` defaults to `max(10, 2% of total)`. Bins below it render open and faded, and the summary counts them, so a
strip where every bin is sparse reads as one with no reliable bins rather than as a calibrated model.

## Four homes

**In a sentence**

```tsx
<p>
  Model calibration{" "}
  <span className="mc-inline">
    <CalibrationStrip data={reliability} summary={false} />
  </span>{" "}
  — well-calibrated above 0.6 predicted probability.
</p>
```

**In a table cell**

```tsx
<td>
  <CalibrationStrip data={reliability} />
</td>
```

**In a KPI card**

```tsx
<div className="kpi">
  <span className="figure">0.92</span>
  <span className="unit">ECE score</span>
  <CalibrationStrip data={reliability} />
</div>
```

**In a tab header**

```tsx
<button className="tab">
  v2.1 <CalibrationStrip data={reliability} />
</button>
```

## 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, press `Escape`, or
press outside the chart. 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).
