Skip to content

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.

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

plot<T>(spec) accepts:

FieldTypeNotes
datareadonly T[] | Signal<readonly T[]>Required. A reactive signal re-renders on change.
width / heightnumberCSS pixels. Auto-resize otherwise.
backgroundColorCanvas background.
paddingnumber | { all?, top?, right?, bottom?, left? } | { ratio: number }Outer canvas inset before axes / legend / title.
framePaddingnumber | { top?, right?, bottom?, left? }Inner slack between axes and data.
deviceGPUDeviceCan also be passed to .mount().
themeThemeInitial theme; replaceable via .theme().

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
  1. aes — each geom’s channel mappings are resolved (Aes<T, V> → an accessor + metadata via resolveAes). Column / accessor / constant all normalize to (row, index) => value.
  2. scales — domains are inferred from the materialized channel values (unless you pass an explicit domain to .scale()), and each channel gets a scale function value → pixel (positions) or value → Color (color). Scale type is picked from the data type (numbers → linear, strings → band, dates → time) unless overridden.
  3. coord — the active Coord decides how scaled plot-frame pixels map to layer pixels. coordCartesian() is the identity; coordPolar / coordRadial project (θ, r). See Axes & coordinates.
  4. 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.
  5. layers — the three layers (axis, marks, hud) are rendered by Renderer2D.

The three layers map onto the RenderTarget you pass to .render(), and onto the axisLayer / marksLayer / hudLayer escape hatches on MountedPlot.

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.