Skip to main content
A mapping binds data columns to aesthetics: the visual properties a chart draws with, such as horizontal position, vertical position and color. It links a row of data to what is drawn on screen.
This reads: put month on the x-axis, revenue on the y-axis, and give each product its own color. The strings are column keys.

Built-in aesthetics

The built-in aesthetics: Not every geom reads every aesthetic: size means something to geom.point() and nothing to geom.line(). Each geom lists the aesthetics it reads. lineType takes only a text column; a numeric one fails to compile. A custom geom can declare position channels of its own, such as a candlestick’s open / high / low / close, and the engine scales them like the built-in ones.

What splits data into groups

Grouping follows one rule:
  • If group is mapped, it is the only thing that groups.
  • Otherwise, every mapped visual aesthetic that points at a text column — color, size, alpha, strokeWidth, lineType — groups, one group per unique combination. A lone lineType: 'scenario' mapping splits one line into several, with no color involved.
Position aesthetics never group. A visual aesthetic that points at the same column as x or y is left out too, since position already splits the data by it. color and group differ in what else they do. color splits and also paints: a hue per value, with a legend. group only splits. Use group for one line per value in a single color.

Variables and constants

An aesthetic can be bound to a variable (a column, read per row) or a constant (one literal value applied to every observation):
  • 'revenue' — string shorthand for a variable mapping.
  • { variable: 'revenue' } — the explicit variable form.
  • { value: 'red' } — a constant. The value still flows through the aesthetic’s scale, so { value: 'Pro' } on color gets whatever color the scale assigns to Pro.

Where a mapping lives

A mapping can sit at two levels: Spec-level — shared by every layer. Set it with createSpec({ ... }):
Layer-level — merged over the spec-level mapping for one geom only, via a geom’s aes option. This is how combos give each layer a different y:
A layer mapping decides where the two overlap; anything it leaves unset comes from the spec-level mapping. Two metrics on one chart need more than a second mapping. Set yScaleType: 'secondary' on the layer that belongs to the right-hand axis. Without it the layer is placed against the primary domain, which draws a plausible but wrong chart. The scale.ySecondary() above is optional: the engine infers one as soon as a layer asks for it. Declaring it lets you give that axis its own options.
A layer’s aes option is named mapping in the serialized spec: geom.line({ aes: { y: 'profit' } }) becomes { "type": "layer", "geom": "line", "mapping": { "y": "profit" } }. This matters when you hand-write the JSON.

Every mapped position needs a scale

Mapping a column to x or y is half the job. You must also declare the scale that turns the values into positions. scale.x() and scale.y() are never created automatically.
A mapped position aesthetic with no matching scale.*() gets no position. The compile succeeds with no warning and the chart draws nothing. If a chart renders blank, check for a missing scale first.

Next

  • Scales — turn mapped values into positions and colors
  • Geoms & layers — which aesthetics each geom reads