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
These are the built-in aesthetics you can map:
Not every geom reads every aesthetic — a
size mapping means something to geom.point() but nothing to geom.line(). Each geom documents the aesthetics it uses. A custom geom can declare positional channels of its own — a candlestick’s open / high / low / close, say — and the engine trains and scales them exactly like the built-in ones.
What splits data into series
Grouping follows one rule:- If
groupis mapped, it is the only thing that groups. Nothing else splits the data. - Otherwise, a series is formed per unique combination of every categorical visual aesthetic that is mapped —
color,size,alpha,strokeWidthandlineType. A lonelineType: 'scenario'mapping splits one line into several, with no colour involved.
x or y is left out of the grouping — position has already partitioned the data by it.
color and group differ in what else they do: color assigns a visual (a hue per category, with a legend) as well as splitting; group only separates the observations. Use group when you want, say, one line per category but a single color for all of them.
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' }oncolorresolves to whatever color the scale assigns theProcategory.
Where a mapping lives
A mapping can sit at two levels: Spec-level — shared by every layer. Set it withcreateSpec({ ... }):
aes option. This is how combos give each layer a different y:
yScaleType: 'secondary' on the layer that belongs to the right-hand axis. Without it the layer is positioned against the primary domain, which draws a plausible-looking but wrong chart. The scale.ySecondary() above is optional — the engine adds an inferred secondary scale as soon as a layer asks for one — but 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" } }. Worth knowing if you
hand-write the JSON.Every mapped position needs a scale
Mapping a column tox or y is only half the story — you must also declare the scale that turns those values into positions. scale.x() and scale.y() are never created automatically.
Next
- Scales — turn mapped values into positions and colors
- Geoms & layers — which aesthetics each geom reads

