Grammar of graphics
A chart is a spec, not a sequence of drawing calls. You declare what the data
means — which columns map to which visual channels, which marks to draw, how the
axes look — and insomni-plot compiles that into insomni
layers on each frame.
The immutable Chart builder
Section titled “The immutable Chart builder”plot(spec) returns a Chart<T>. Every builder method returns a new
Chart with the addition recorded; the original is untouched. This means specs
are cheap to fork, share, and re-derive.
import { plot, point, line } from "insomni-plot";
const base = plot<Row>({ data }).axes({ x: { title: "t" } });
const withPoints = base.layer(point({ x: "t", y: "v" }));const withBoth = withPoints.layer(line({ x: "t", y: "v" }));// `base` and `withPoints` are unchanged.Builder methods
Section titled “Builder methods”| Method | Purpose |
|---|---|
.layer(geom) | Add one geom layer. |
.layers(geoms) | Add several geom layers at once. |
.scale(channel, options) | Configure a scale ("x", "y", "color", "size", "alpha", "shape", "borderStyle", "overlayGlyph"). |
.axes(spec) | Per-axis options: { x?, y? }. |
.title(spec) | Title / subtitle. Accepts a string or { title?, subtitle? }. |
.legend(spec | false) | Configure or disable the auto-legend. |
.annotate(spec) | Add a free-form text / arrow / callout overlay. Accumulates. |
.facet(spec) | Split into a grid of panels by a key. Replaces any prior facet. |
.coord(coord) | Set the coordinate system (default coordCartesian()). |
.theme(theme) | Replace the active theme. |
.mount(canvas, opts?) | Bind to a canvas → MountedPlot. |
.render(target) | Compile + emit into externally owned layers. |
.toSVG(opts?) | Static SVGSVGElement export. |
The three terminal methods — .mount(), .render(), .toSVG() — are the only
ones that produce output. See Mount, render & export.
PlotSpec — the chart container
Section titled “PlotSpec — the chart container”plot<T>(spec) accepts:
| Field | Type | Notes |
|---|---|---|
data | readonly T[] | Signal<readonly T[]> | Required. A reactive signal re-renders on change. |
width / height | number | CSS pixels. Auto-resize otherwise. |
background | Color | Canvas background. |
padding | number | { all?, top?, right?, bottom?, left? } | { ratio: number } | Outer canvas inset before axes / legend / title. |
framePadding | number | { top?, right?, bottom?, left? } | Inner slack between axes and data. |
device | GPUDevice | Can also be passed to .mount(). |
theme | Theme | Initial theme; replaceable via .theme(). |
The frame pipeline
Section titled “The frame pipeline”Each frame, the chart compiles the spec into three insomni Layers. The
sequence — implemented in pipeline.ts and shared by both the GPU mount loop
and the SVG export — is:
data ─▶ aes ─▶ scales ─▶ coord ─▶ geoms ─▶ layers- aes — each geom’s channel mappings are resolved (
Aes<T, V>→ an accessor + metadata viaresolveAes). Column / accessor / constant all normalize to(row, index) => value. - scales — domains are inferred from the materialized channel values
(unless you pass an explicit
domainto.scale()), and each channel gets a scale functionvalue → pixel(positions) orvalue → Color(color). Scale type is picked from the data type (numbers → linear, strings → band, dates → time) unless overridden. - coord — the active
Coorddecides how scaled plot-frame pixels map to layer pixels.coordCartesian()is the identity;coordPolar/coordRadialproject(θ, r). See Axes & coordinates. - geoms — each geom’s
compile(ctx)emits insomni mark builders (rects, point clouds, polylines, glyphs) into the marks layer; axes / legend / title go to the axis and hud layers. - layers — the three layers (
axis,marks,hud) are rendered byRenderer2D.
The three layers map onto the RenderTarget you pass to .render(), and onto
the axisLayer / marksLayer / hudLayer escape hatches on MountedPlot.
Compilation context
Section titled “Compilation context”Each geom is compiled against a CompileContext that carries the resolved
scales, the active theme, the panel’s plot frame, the glyph atlas, and
interaction state (hovered, selected, hidden, the active transition).
Geoms read this to produce their marks and, optionally, hit-tests for tooltips
and selection. This contract is internal — you author charts by composing geoms,
not by implementing compile yourself — but it explains why a single
declarative spec can drive hover, selection, transitions, and SVG export from
one source.
- Geoms — the mark vocabulary and each geom’s aesthetics.
- Scales & aesthetics — channels, scale types, domains, and legends.