Documentation

Small multiples

Partition any chart into panels with .repeat(), in one SVG with one transition controller.

.repeat(field, options) partitions a chart into small multiples. The x and y bindings keep their meaning, each panel gets its own coordinate frame, and one transition controller drives the whole chart.

Preparing transition
0.00
Data & runnable transition code
const rows = [{"label":"A","part":"Core","value":90},{"label":"A","part":"Growth","value":20},{"label":"A","part":"Services","value":10},{"label":"A","part":"Support","value":30},{"label":"B","part":"Core","value":80},{"label":"B","part":"Growth","value":25},{"label":"B","part":"Services","value":10},{"label":"B","part":"Support","value":30},{"label":"C","part":"Core","value":70},{"label":"C","part":"Growth","value":30},{"label":"C","part":"Services","value":10},{"label":"C","part":"Support","value":30},{"label":"D","part":"Core","value":80},{"label":"D","part":"Growth","value":35},{"label":"D","part":"Services","value":10},{"label":"D","part":"Support","value":30}];

const a = bar(rows).x("label").y("value", { label: "Units" })
  .key(["label", "part"]).breakdown("part")
  .color("part", { domain: ["Core","Growth","Services","Support"],
    range: ["#176078","#19a4c5","#2ce5b4","#00b59c"] });
const b = a.repeat("part", { direction: "y", scales: "shared", minWidth: 180 });

const motion = await transition(a, b, { target: "#chart", height: 640 });
motion.play({ from: 0, to: 1, duration: 1200 });
const repeated = chart.repeat('component', {
  direction: 'y',
  scales: 'shared',
});

smallMultiples(chart, field, options) from visdelta/facet is the functional form of the same operation.

Options

OptionDefaultMeaning
direction'grid''y' places panels in rows, 'x' in columns, 'grid' responsively
scales'shared''independent' derives numeric domains per panel
columns2Maximum columns for a grid
gap24Pixels between panels
minWidth240Minimum panel width; narrow containers reduce the column count
autoHeightfalseGrow the canvas to fit every panel row
minHeight240Minimum complete panel height, used with autoHeight

Shared scales compute numeric domains from all transformed rows. Independent scales help inspect patterns within a panel, but lengths can no longer be compared across panels, and Bars emit a non-blocking warning. Explicit domains always take priority. Categorical domains and colours stay consistent across panels.

Calling .repeat() again replaces the panel binding instead of nesting panels. Missing, null or non-scalar facet values are rejected.

Size and resize

Repeat keeps the outer canvas height by default; the container width controls the layout, and panels are laid out again rather than scaled. With autoHeight: true, the canvas grows to fit the panel rows. An explicit chart or transition height takes priority. During a transition the canvas reserves the largest height its route needs, so playback never changes the outer size.

State changes

ChangeCategory
Binding, removing or changing the fieldEncoding (bind, unbind, remap)
Direction, columns, gap or minimum widthLayout (rearrange)
Shared vs independent numeric scalesCoordinate (rescale)

Supported transitions

ChartFlat ↔ repeatedRepeated ↔ repeated
BarSupported, with unchanged membership and grain and globally unique keysSupported
LineSupported for an existing breakdown field, with unchanged observations and bindingsSupported
Area, Point, UnitNot supportedSupported

When existing panels change arrangement, each keyed panel first moves as a container in separate x/width and y/height stages; then the chart inside reflows using its own transition. Reverse replays both levels backward.

Combining expansion or rearrangement with a flip in one leg is unsupported; use a sequence to separate them. Nested small multiples are unsupported.

On this page