Skip to content
microcharts
ReferenceExpressiveSpiralYear

SpiralYear

SpiralYear winds a year of daily or weekly values onto a spiral and encodes each value as a five-step opacity.

encodes
5-step opacity of marks along a calendar spiral
precision
low
nodes
≤ 6 (merged month-tick path + ≤ 5 step paths)

SpiralYear winds a calendar series onto an Archimedean spiral. The angle is the position in the year (January at 12 o'clock, running clockwise) and each turn outward is the next year, so the radius encodes time only, never value: an outer mark is a later date, not a bigger number. The value becomes a five-step opacity, and busy stretches render as darker arcs. Two adjacent turns place different years at the same angle; read that radial adjacency as calendar alignment. This is a pattern instrument: opacity is the weakest ordered channel, so for an exact day's value reach for ActivityGrid or HeatStrip.

SpiralYear
interactive · 5.46 kB · static · 2.98 kB

Install

Import & usereact/spiral-year
import { SpiralYear } from "@microcharts/react/spiral-year";// byWeek — real values under “Sample data” below<SpiralYear data={byWeek} title="Seasonality" />
Sample data
// 52 weekly values, a summer peak in week 30const byWeek = [  85, 95, 107, 120, 135, 150, 166, 183, 200, 217, 234, 250, 265, 280, 293, 305, 315, 324, 331, 336,  339, 340, 339, 336, 331, 324, 315, 305, 293, 480, 265, 250, 234, 217, 200, 183, 166, 150, 135,  120, 107, 95, 85, 76, 69, 64, 61, 60, 61, 64, 69, 76,];
Needs package + stylesheetSet up with AI

Try it

When to use it

Use it for the seasonal shape of a year, for spotting a busy season or a quiet stretch, or as a compact "the year in one square". For an exact day's value use ActivityGrid or HeatStrip, and for a non-cyclic trend use Sparkline. Past about three years the turns pack too tightly to read.

Sizing

Variants

Month ticks are on by default: without a temporal anchor the spiral is texture, and the ticks are what make "when" readable. Five opacity steps is the ceiling, since ordered opacity supports about five discriminable levels; steps={3} drops to three for tiny sizes.

arc marks, or three steps for tiny sizes

locale changes no in-chart mark, since opacity steps carry the value and no number is printed. It does localize the peak and low values named in the accessible summary:

locale — the accessible summary follows it (no visible mark changes)

Edge cases

a gap — a null week leaves a hole, not a low mark
no data yet

A null day or week leaves a gap in the spiral, distinct from a faint step-one mark, because missing is not the same as low.

Four homes

Accessibility

The accessible name states the count, the peak, and the low: "52 weeks; peak 1.480 in week 30, low in week 48." (the de-DE localized demo). The interactive entry lets you arrow along the spiral chronologically, and announces each mark with its period and value through a polite live region.

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 day or week (cadence inferred from length).
cadence"day" | "week"Data cadence; inferred from length (≈52 → week, else day) when omitted.
startDatestringISO date anchoring index 0 to a calendar angle.
steps3 | 5Opacity quantization (default 5).
monthTicksbooleanFaint radial month ticks (default true).
mark"dot" | "arc"Dots (default) or short arc segments.
sizenumberSpiral box edge in viewBox units (default 24).
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