# PolarClock (/docs/charts/polar-clock)

PolarClock answers "what's the shape of the day or week cycle — when is it busy?" Each value in the cycle becomes a
radial bar at its fixed angle, growing outward from an inner baseline; longer bars are busier times. Midnight (or your
week-start) sits at 12 o'clock and the cycle runs clockwise, so the rhythm of a metric across the cycle is immediately
legible.

```tsx
<PolarClock
  data={Array.from({ length: 24 }, (_, h) => (h === 14 ? 312 : h === 4 ? 20 : 80 + h))}
  now={14}
  title="Traffic by hour"
  size={72}
/>
```

## Install

```tsx
import { PolarClock } from "@microcharts/react/polar-clock";

<PolarClock data={byHour} now={14} title="Traffic by hour" />
```

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** — the shape of a 24-hour or 7-day cycle, when a metric is busy across the cycle, or a compact seasonal
  read in a KPI card.
- **Avoid for** — exact value comparison (unroll the cycle into a `SparkBar`), a non-cyclic trend (`Sparkline`), or more
  than a few dozen segments.


## Variants

```tsx
const byHour = Array.from({ length: 24 }, (_, h) => (h === 14 ? 312 : h === 4 ? 20 : 80 + h));
const week = [120, 200, 180, 210, 260, 90, 60];

<PolarClock data={byHour} label="max" />
<PolarClock data={week} mode="opacity" />
```

```tsx
const byHour = Array.from({ length: 24 }, (_, h) => (h === 14 ? 312 : h === 4 ? 20 : 80 + h));

<PolarClock data={byHour} labels={false} />
```

```tsx
const byHour = Array.from({ length: 24 }, (_, h) => (h === 14 ? 1240 : h === 4 ? 20 : 80 + h));

<PolarClock data={byHour} label="max" locale="de-DE" />
```

## Why this default

The channel is radial **length from the inner baseline**, not sector area. Equal-value bars at the rim span more area
than ones near the hub, so an area reading would exaggerate the outer segments — the inner radius is nonzero precisely
to curb that distortion, and the docs ask you to compare lengths, not wedges. Bars are always zero-anchored at that
baseline. For very small sizes where length is hard to judge, `mode="opacity"` switches the channel to a five-step fill
— a radial `ActivityGrid` — which is a deliberate, named change of encoding, not a cosmetic one. A `null` segment leaves
a gap (the baseline ring shows the hole) because missing is not the same as zero.

The four cardinal ticks default **on** because a bare ring of bars is rotationally ambiguous — without a mark for "12
o'clock" there is no way to tell where the cycle starts, so "when is it busy" can't be answered from the static frame
alone. The four ticks are merged into one path (a single node), so the orientation cue is free of the usual
label-drop-out tradeoff — set `labels={false}` only when the shape itself is the whole story and the axis genuinely
doesn't matter.

## Edge cases

```tsx
<PolarClock data={Array(24).fill(null)} title="No data yet" />
```

```tsx
<PolarClock data={Array(24).fill(50)} title="Steady" />
```


## Accessibility

The accessible name states the peak and the quiet point of the cycle — **"Peaks at 14:00 (1.240); quietest 04:00."** —
with hour labels for a 24-segment cycle and weekday names for a 7-segment one. The interactive entry lets you arrow
through the segments circularly, each announced with its label and value through a polite live region, and the accented
`now` segment carries position and color, never color alone.

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) | `(number \| null)[]` | One value per cycle division (24 hourly, 7 daily, any n). |
| `now` | `number` | Index of the current segment to accent. |
| `inner` | `number` | Inner radius fraction r0 — the zero baseline bars grow from (default 0.35). |
| `mode` | `"length" \| "opacity"` | Radial bars (default) or fixed-length 5-step fill. |
| `origin` | `number` | Index rendered at 12 o'clock (week-start / midnight). |
| `labels` | `boolean` | Hairline cardinal ticks at 0/¼/½/¾ — the at-rest orientation cue. Default true. |
| `segmentFormat` | `(index, n) => string` | Segment index → label (default: HH:00 for n=24, weekday for n=7, else index). |
| `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).
