Plot Label and Tick Issues

Two reasons.

First, philosophically, having the margins computed automatically based on data can give unpredictable or inconsistent results. Say you have several time series and you want to compare them with small multiple charts with a shared x-axis (how did these signals vary over time?); if the default margins depend on the data because the data affects the ticks, then you could end up with a slightly different x-axis on each chart because the margins varied, making it harder to compare. Or say you’re using Plot to visualize a dynamic dataset that changes sixty times a second; if the margins depend on data, the scales could change every time the data updates. Whereas with Plot’s design, the margins are strongly predictable because they don’t depend on the values. We recommend that authors adjust the margins to some reasonable value so they are consistent (and maybe set the lineWidth axis option to control how long ticks are displayed).

Second, pragmatically, it’s hard and slow to compute text metrics accurately. When rendering SVG, the SVG must be inserted into the DOM because its appearance is affected by stylesheets. But for convenience Plot is designed to render detached SVG elements which you then insert wherever you want them. (In fact, even if Plot were to compute text metrics synchronously on rendering, it wouldn’t be correct if you had dynamic styles — to really be “correct”, Plot would have to continuously observe changes to styles and re-rendering the chart, which is an implementation nightmare!) So when Plot does need to compute text metrics, as with the lineWidth option on the text mark, we use approximate metrics that are much faster to compute even though they aren’t guaranteed to match the actual text metrics.

I could maybe see Plot doing something smarter here in the future. But the fact that it’s both hard to do (especially if you want rendering to be fast) and not always desirable means we haven’t been especially motivated to work on it. In practice, where I feel the pain most often here is large y values (say tens of thousands, or millions) — exactly the case described above; these ticks tend to get cut off by default because they overflow the bounds of the SVG with the default margins. But I find the best solution for this is not to increase the margins, but to set the transform option on the y scale to change the units (say to thousands or millions), which eliminates the need for larger margins and is more readable to boot. Say like this:

Plot.plot({
  y: {
    label: "Value (thousands)",
    transform: (y) => y / 1000
  },
  marks: [
    Plot.ruleY([0]),
    Plot.line({length: 365}, {x: d3.utcDays(new Date("2021-01-01"), new Date("2022-01-01")), y: (_, i) => i ** 2})
  ]
})

I want Plot to automatically detect a suitable power-of-ten unit for large values #1816 even more than I want automatic margins based on text metrics.

2 Likes