Skip to main content
A reference line marks a constant value the rest of the chart is read against: a sales target, a capacity ceiling, a zero baseline. It is a geom like any other, geom.rule(), added to the spec with its own value and style.

A horizontal goal line

Bind the rule to a constant y with aes: { y: { value } }. The { value } form is a constant mapping: it pins the aesthetic to a literal instead of a column.
The rule value takes part in the y-scale’s auto-domain. Set a target above the tallest bar and the axis grows to fit it, so the line is never clipped off the top. A rule is not interactive by default: it answers no hover and shows no tooltip.

The label

A rule’s params carry its label and nothing else:
string
Optional inline text drawn alongside the line. Omit to draw a bare line.
'start' | 'end'
default:"start"
Anchors the label at the start or end of the line.
Under coord.flip() a rule runs vertically, and 'end' puts the label at the top of the line rather than at its foot. ToggleGoalLineCommand and SetStatLineCommand pick that end for you when they build a line under a flipped coord.

Painting the line

Stroke and label type come from the stylesheet, like every other geom. style.geom.rule() takes stroke, strokeWidth, dashArray, strokeAlpha, lineCap, lineJoin, shadow and blendMode; style.geom.rule.label() takes fontFamily, fontSize, fontWeight, lineHeight, textColor and the other text properties. Both take a { layer } option, so one rule can be painted without touching the others. Leave textColor undeclared and the label’s text color is picked to read against the pill.
The built-in stylesheet paints every rule dashed, 1px wide, in the ruleLine token, so a bare geom.rule() draws a dashed line. Redefine ruleLine through styles({ tokens: { ruleLine } }) to recolour every rule, goal line and average line at once.

Vertical lines

Mark a constant along the x-axis with aes: { x: { value } } instead:
A vertical rule needs a numeric x-axis: it marks a constant x-value, which only has meaning when x is continuous. Band and date x-axes support horizontal rules only. A rule reads one value from exactly one axis, so supplying both x and y is an INVALID_RULE_MAPPING error, as is supplying neither.

Multiple rules

Rules compose like any other layer and paint in spec order: a rule added after geom.bar() draws in front of the bars. Add as many as you need:
Name the rules you want painted apart: a { layer } entry addresses the layer’s id.

Flipped and secondary axes

A rule tracks the data space, not the screen. Under coord.flip() a { y: { value } } rule still marks a constant y; the renderer paints it as a vertical line because the y-axis now runs horizontally. To pin a rule to a secondary axis, add yScaleType: 'secondary':

An average line

A rule’s value can also be computed. Give it stat.mean() instead of a constant and the line sits at the layer’s average:

Editing a rule at runtime

Four commands cover reference lines in an editing UI: