Skip to main content
A combo chart layers two geoms with different y-scales, typically bars for one metric and a line for another on a second axis. It shows two measures whose units or magnitudes do not share a scale.

Dual-axis example

Give each geom its own y through a layer-local mapping, and bind the line to the secondary axis with yScaleType: 'secondary'. Each layer also needs something to map to color; otherwise both take the built-in geom color and neither gets a legend entry. A per-layer transform.constant adds a categorical column holding the layer’s name. Mapping it to color gives the layer its own palette color and legend item:
Each scale trains only on the layers bound to it, so the two metrics keep independent ranges. A layer’s transforms run after any spec-level transforms and apply to that layer alone. Use them whenever one geom needs the data in a different shape from its siblings. scale.ySecondary() is optional: the compiler infers one as soon as a layer declares yScaleType: 'secondary'. Declare it to control the domain, as with any other scale.

Configuring the second axis

The secondary axis is keyed ySecondary under axes. It is a sparse override: every field you leave out is inherited. position is the side opposite y; visible, grid and ticks come from y:

Styling one layer

Give a layer an id and a stylesheet entry can scope to it with { layer }. This is what makes an overlay line read as an overlay rather than another group:
overrides outranks a mapped aesthetic; defaults does not. None of these properties is mapped, so defaults would work here too, but an entry that recolours a layer whose color is mapped has to be an override. See Styling for the full cascade.

When to share the axis instead

A second axis is right when the two layers measure different things. When they measure the same thing (an average, a target, a running total over the bars it summarizes), omit yScaleType and let the line sit on the primary scale. A dual axis there quietly detaches the line from the bars it annotates:
For a flat reference line at a constant value, use geom.rule(). It is non-interactive by default and draws a 1px dashed line, painted through style.geom.rule({ stroke, strokeWidth, dashArray }). label prints inline text at the line’s start, or at its end with labelPosition: 'end':