Circles and shapes · expressive()
Dots, curves and areas
Four charts drawn by other code: a scatter, a curved line and an area drawn with D3, and a dot chart drawn with Observable Plot. expressive() reads each <circle> as a point and each <path> as a shape, so each chart is attached with a key and only what it needs, and the same effects play on all four. Pick a hover effect, then hover or Tab into a chart.
Goals from shots, on a D3 scatter
Drawn the way D3 code often draws a scatter: a group for each player, moved into place, with a <circle> and the player's name. expressive() reads each circle as a point, through its group's move, given a key, the goals as its value and a name for each dot (markLabel). Tab reaches the dots, and the arrow keys go through them in the order D3 drew them.
Goals and assists, on an Observable Plot dot chart
Plot draws its own <svg>, with a <circle> for each dot, bound to its row's index. The page gives expressive() each dot's row (datum), and the rest as for the D3 scatter. A resize draws a new <svg>, and refresh() follows it.
Form, on a D3 curved line
Goals and expected goals per match, each averaged over the last five, drawn with d3.line() and curveMonotoneX, which writes Béziers. expressive() reads each path's own data as an open shape, a line it can walk, so the goals line turns red below xG and a ball rides its tip, as on the line page. The page gives each curve its series (segment) and its values along it (samples), which threshold compares week by week.
Shots, on a D3 area
Shots on target and off target per match, each averaged over the last five, drawn with d3.area(), one stacked on the other. Each path ends where it began, so expressive() reads it as a closed shape: an area, with no direction. A pulse or a flash rings its outline, and hovering one area dims the other.
Design notes
- No chart here describes its marks:
expressive()reads a<rect>as a bar, a<circle>as a point, and a<path>,<line>,<polyline>,<polygon>or<ellipse>as a shape, open or closed. - A closed shape, such as an area, has no direction, so
travelandtracedo nothing on it, as on a dot. Its outline has no start or end of its own: any the library chose would be made up, and a ball rolling round an area, or a trace drawing it, would seem to say something about the data that it doesn't. Pulse, flash and wiggle need only the outline, so they play. - A wiggle turns a mark a few pixels about its pivot. A dot's pivot is its centre, and a circle turned about its centre looks the same, so on the dots Wiggle shows only the emphasis and the dimming. An area rocks about its middle, and a curve about its first point.
- The picker swaps each chart's hover effect with
update({ on }). Nothing is attached again, so focus and each chart's tab stop stay where they were, and a hover that's held plays the new effect. The curve's red and its ball are the same effect each time, so they keep running. - The names beside the dots are the page's own text, hidden from screen readers: each dot's name says who it is and its values.
Things to try
- Pick Pulse, Flash or Wiggle, then hover a dot, a curve and an area: the same effect plays on all four charts.
- Tab into the scatter and use the arrow keys: focus goes through the dots in the order D3 drew them, top scorer first. Then Shift+Tab to the picker, pick another effect, and Tab back: focus is on the dot you left.
- Pick Wiggle and hover a dot, then an area: the dot doesn't move, and the area rocks.
- Turn on reduced motion and reload: the ball is at the tip at once, with the red drawn, and a pulse or a flash shows nothing, since its end state is nothing.