Skip to main content
Every chart is a spec: a plain, immutable object you build by folding parts together.

The builder pipeline

You start a spec with createSpec and fold parts onto it with pipe. Each part is a small tagged object produced by a builder (geom.*, scale.*, coord.*, config, …):
pipe(spec, ...parts) returns a new spec with each part folded in, left to right. It never mutates. Each kind folds in its own way: Two of those deserve a second look. coord overwrites: piping coord.polar({ innerRadius: 0.5 }) after coord.polar({ theta: 'y' }) leaves the inner radius and no theta, so pass both params in one call. A piped styles(...) sits above everything piped before it, so where two stylesheets declare the same property the later one decides. Because a spec is a plain object, you can build it up conditionally, share fragments across charts, and store or serialize it.

The parts of a spec

A spec brings together these parts. Each has its own page: Plus configuration (config) for chart chrome — titles, axes, legend, layout.

Compile, then render

A spec is a description, not pixels. Turning it into a chart takes two stages, one per package:
  1. Compile (@graphysdk/viz-engine). The engine takes your spec and data and produces a Scene. Scales get concrete domains, statistics run, every observation is placed in a normalized [0,1] position space, the stylesheet is validated with its token() references inlined, and guides (axes, legend) are worked out. This stage is pure data in, data out, with no DOM. It is also what keeps a styled spec serializable: paint comes out as plain values.
  2. Render (@graphysdk/react-renderer). The renderer takes the Scene and paints it: it lays out pixel rectangles, formats numbers and dates for the locale, picks the light or dark half of every color pair, and wires up hover and animation.
In a React app you do not call the compiler yourself. <GraphProvider> does, and recompiles when the spec, data or colorScheme change. The scheme reaches both stages: the compiler picks the default palette’s tones for it, and the renderer picks the light or dark half of every color pair as it reads:

Why the split matters

The split between the two packages shapes how you use the SDK:
  • Data lives outside the spec. A spec references columns by name; the rows are passed to <GraphProvider> separately. One spec can draw many datasets.
  • The compiler never formats. It emits raw values and descriptors; the renderer turns them into text for the locale. That is why formattingLocale is a provider prop, not part of the spec.
  • Scales are resolved once, at compile time. This is why you declare scales explicitly in the spec — the engine can’t place a value it was never told how to scale.
Authoring — mapping, geoms, scales, stats, and the stylesheet that paints the geoms — lives in the engine. Presentation — layout, formatting, interactivity and animation — lives in the renderer. Both are imported from @graphysdk/react.

Next

  • Scales — the one part you must always declare
  • Serializable spec — a spec is plain JSON you can persist and reload