Skip to content
microcharts
ReferenceExpressivePolarClock

PolarClock

PolarClock draws a 24-hour or 7-day cycle as radial bars at fixed angles, growing from an inner baseline.

encodes
radial bar length at a fixed cycle angle
precision
medium
nodes
4

PolarClock turns each value in a cycle into a radial bar at its fixed angle, growing outward from an inner baseline and zero-anchored there. Longer bars are busier times. Midnight (or your week start) sits at 12 o'clock and the cycle runs clockwise. The channel is length, not sector area: equal-value bars at the rim cover more area than ones near the hub, which is why the inner radius is nonzero. Compare lengths, not wedges.

PolarClock
interactive · 5.76 kB · static · 3.32 kB

Install

Import & usereact/polar-clock
import { PolarClock } from "@microcharts/react/polar-clock";// byHour — real values under “Sample data” below<PolarClock data={byHour} now={14} title="Traffic by hour" />
Sample data
// 24 hourly values, midnight → 23:00const byHour = [  80, 81, 82, 83, 20, 85, 86, 87, 88, 89, 90, 91, 92, 93, 312, 95, 96, 97, 98, 99, 100, 101, 102,  103,];
Needs package + stylesheetSet up with AI

Try it

When to use it

Use it for the shape of a 24-hour or 7-day cycle, for when a metric is busy across that cycle, and for a compact seasonal read in a KPI card. For exact value comparison unroll the cycle into a SparkBar; for a non-cyclic trend use Sparkline. Keep it under a few dozen segments.

Sizing

Variants

the peak numeral, or opacity mode for tiny sizes

At very small sizes, where length is hard to judge, mode="opacity" switches the channel to a five-step fill — a radial ActivityGrid. That is a named change of encoding, not a cosmetic one.

ticks off — pattern-only reads where the axis doesn't matter

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. They are merged into one path, so the orientation cue costs a single node. Set labels={false} only when the shape itself is the whole story and the axis genuinely doesn't matter.

locale — the peak numeral and the summary both follow it

Edge cases

all-null cycle
flat cycle — every hour equal

A null segment leaves a gap and the baseline ring shows the hole, because missing is not the same as zero. A cycle where every value is equal draws every bar at the same length.

Four homes

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: 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 | null)[]One value per cycle division (24 hourly, 7 daily, any n).
nownumberIndex of the current segment to accent.
innernumberInner radius fraction r0 — the zero baseline bars grow from (default 0.35).
mode"length" | "opacity"Radial bars (default) or fixed-length 5-step fill.
originnumberIndex rendered at 12 o'clock (week-start / midnight).
labelsbooleanHairline cardinal ticks at 0/¼/½/¾ — the at-rest orientation cue. Default true.
segmentFormat(index, n) => stringSegment index → label (default: HH:00 for n=24, weekday for n=7, else index).
sizenumberDial box edge in viewBox units (default 24).
fontSizenumberType size of the peak label under the dial, in viewBox units. Defaults from `size`.
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