How to label a boxplot with dates, format axis

I have a boxplot using years as the categorical values. I want to format the axis so that I don’t see all of the years bunching up against each other. How can I format the axis to just label a few of the years?

1 Like

You could try the following:

Plot.plot({
  width,
  x: {ticks: d3.range(1975,2030,5), tickFormat: d3.format('d')},
  marks: [
    Plot.boxY(data, {
      y: "value",
      x: "year"
    })
  ]
})

There might be a better way to deal with the ordinal axis, though.

1 Like

Nice I like it! So since ticks can accept an array of values, simply list out the values you want. Any further insight into why simply stating the tick number doesn’t work? Is it because our x variable is ordinal?

The fundamental problem here is that the boxY mark forces the x scale to be a band scale because it uses the groupX transform and barY/tickX mark under the hood. Since the x values here are numeric, it would be more appropriate to use the binX transform with the rectY/ruleY mark instead.

Perhaps the box mark could provide an option to guess which would be appropriate based on the data, similar to what the new Plot.auto mark does. I filed #1330 to track this idea.

In the meantime you’ll have to copy the implementation, like so:

Plot.plot({
  width,
  marks: [
    Plot.ruleX(data, Plot.binX({y1: loqr1, y2: hiqr2}, {x: "year", y: "value", interval: 2})),
    Plot.rectY(data, Plot.binX({y1: "p25", y2: "p75"}, {x: "year", y: "value", fill: "#ccc", interval: 2})),
    Plot.ruleY(data, Plot.binX({y: "p50"}, {x: "year", y: "value", strokeWidth: 2, interval: 2})),
    Plot.dot(data, Plot.map({y: oqr}, {x: "year", y: "value", z: (d) => Math.floor(d.year * 2)}))
  ]
})

Full implementation:

I couldn’t quite figure out how to compute the per-bin outliers using the map transform, like the box mark currently does, so I had to hard-code a bin interval of 2 above. Maybe someone else can figure out a way. :sweat_smile:

My suggestion would be:

  x: {
    interval: 1,
    tickSize: 1,
    tickFormat: (d) => (d % 5 === 0 ? `${d}` : "")
  },

interval sort-of bins the data by year, and makes sure that even if a year is missing from the data, it will create a blank space on the axis instead of “forgetting” it; and tickFormat only renders labels (years) that are a multiple of 5. tickSize is only aesthetic.