Reference line

A rule across the whole plot at one value — today, a target, the week a definition changed — with a caption beside it and a note the tooltip reads.

referenceLine is the one mark that isn't a reading. Every other mark takes rows and draws what they say; this one is a statement about the plot — where today is, where the target sits, when the way a number was calculated changed.

It has no rows, so it spans the plot whatever the marks under it reach. A Today marker on a chart of bars is the full height of the plot rather than the height of today's bar, which is what makes it read as a marker rather than as one more series.

marks={[
	bar({ data: rows, x: 'day', y: 'sent' }),
	referenceLine({ x: today, label: 'Today' }),
]}

Name x for a rule down the plot at a position along the horizontal axis, and y for one across it at a value on the vertical axis — which is where a target or a threshold goes. Marks paint in order, so a rule declared after the bars is drawn over them and one declared before is drawn under.

The caption

label writes a few words beside the rule, inside the plot. Inside rather than out in the margin, which is what makes the caption belong to the rule it names: a caption beyond the plot's edge is a second axis label, and a chart with two annotations would have two of them with nothing saying which is which.

labelPlacement moves it to the other end — the foot of a rule down the plot, the right of one across it — for when the top of the plot is where the data is.

labelOrientation: 'vertical' turns the caption of a rule down the plot so it runs along the rule, reading top to bottom. Use it when rules sit close together and captions across the plot would overlap. labelPlacement still picks the end: the caption starts at the top, or finishes at the foot. A caption longer than the rule is cut with an ellipsis, so put the full text in note.

referenceLine({ x: startedAt, label: 'Trigger 1 - 12:44:12 pm', labelOrientation: 'vertical', labelPlacement: 'end' })

Keep it short. The plot is the data's room, and the caption is a guest in it.

color paints the rule, and the caption follows it. A data-viz color from @customerio/pluma-components/data-viz writes the caption in its hue's readable text color, its tokenText, rather than in the step drawn as the rule: a step picked to read as a line can be too light to read as text. The pair belongs to the hue rather than the step, so two rules on different steps of one ramp share a caption color. A data-viz color without a tokenText writes the caption in its token, like the rule. A plain CSS color string paints rule and caption alike.

referenceLine({ y: 150, label: 'Target', color: semantic('success', 1)[0] })

The note

note is the sentence the caption was too small to hold, read by the tooltip at the position the rule marks:

referenceLine({
	x: new Date('2021-06-24T00:00:00Z'),
	label: 'Definition changed',
	note: 'Open rates before this date are not comparable.',
})

Pointing at the rule, or within a few pixels of it, reads the column the rule crosses with the note under that column's values, so the rule is easy to hover even on a dense time series. Focusing that column any other way, from the keyboard for one, reads the same note. A rule without a note is not a pointer target.

The rule does not have to sit exactly on a row. On a time or number axis the note belongs to the position the rule is nearest — the column the reader sees it crossing — so a change date picked by a human reads fine against buckets it never exactly matches. On a category axis a rule is on a category or it is nowhere, so the match is that category.

A note needs a position the reader can focus. A rule down the plot has one: the column it crosses. A rule across the plot marks a height rather than a position, and the chart focuses no height — so put what it has to say in its label.

Staying in view

On a time or number axis a rule widens the axis so it is visible, the way a mark's own values do. A Today marker on a chart whose last bucket is yesterday has to be somewhere, and a marker the reader cannot see is worse than one that moved the axis a little.

withDomain: false turns that off, for a rule that would distort the plot to be shown — a target ten times the largest value would flatten every bar under it to nothing. The rule is then drawn only when the data happens to reach it.

On a category axis — which is what a chart of bars has — a rule sits on a category the chart already draws, or it draws nothing. There is no range to widen: such an axis covers the categories it was given, so a value that is not one of them has nowhere to be. withDomain does nothing there, and a Today marker for a day the chart has no column for is a marker with no column to mark.

A marker on a chart of days

Apple's closing price with the day of its 2018 high ruled and captioned, and the note read by pointing at that day:

Loading editor

Accessibility

A rule is drawn into the scene, and the scene is one role="img" named by the chart's ariaLabel — so nothing inside it is announced on its own. What a marker means has to be in the chart's own description: give a chart carrying one an ariaDescription that says what is marked and why, as the example above does. The caption and the note are for readers who can see the plot.