Plot.ruleX not accepting "new Date()"

Used inside Plot

Plot.ruleX(today, { stroke: "red" })

Today defined with new Date() - DOES NOT WORK

today = [new Date()];

Today defined with new Date(2022,2,21) - WORKS

today = [new Date(2022,2,21)];

Reference code:

The issue is that you’re implicitly defining an ordinal (point) scale because you’ve specified a domain with more than two values. Since the domain doesn’t include the rule’s date (today), the plot is invalid. I suspect that you want to define the domain as domain: [start, end] instead so that you get a continuous (utc) scale.

Thanks a lot for the analysis. It means a lot coming from you.

When I switch the domain to domain: [start, end], the scale shows only months Jan, Feb, Mar.
What would be the right way to display every day always on x-axis?

@mbostock I tried this

let start = new Date(2022, 0, 1);
let end = new Date(2022, 2, 1);
let rangeCount = d3.timeDay.count(start, end);

 Plot.plot({
          .....
          grid: true,
          x: {
            axis: "top",
            domain: [start, end],
            range: [0, rangeCount],
            tickFormat: (d) => formatDay(d)
          },


It does not render every date on x-axis, only displays `Jan, Mar`

Thanks in advance.

Using the ticks option. Something like

          x: {
            axis: "top",
            domain: [start, end],
            ticks: d3.utcDay,
            tickSize: 0,
            tickFormat: formatDay
          },

It worked! But When I add data

Plot.cell(data, {
              y: "name",
              x: (d) => d.date,
              fill: (d) => d.country,
              title: (d) => `${d.name}\n${d.country}`
            })

x-axis resets back to Jan, Mar.
Updated - Plot now / hashg / Observable

I’m in process of building a gantt-calendar similar to this,

  • What would be your recommendation to realise this?
  • Me choosing Plot, is it a good choice?
  • Should I use pure d3?

It resets because Plot.cell implies that both x and y are ordinal scales, so you’re back to where you started. :grimacing: (If you specify x: {type: "utc"} you’ll see an error when you try to use Plot.cell.)

You want a Plot.barX, not a Plot.cell here, because x is continuous (representing a time interval with a start and stop) and y is ordinal. And you’ll typically want to specify the start and stop time of each period of work, something like

    Plot.barX(data, {
      y: "name",
      x1: (d) => d.startDate,
      x2: (d) => d.endDate,
      fill: (d) => d.country,
      title: (d) => `${d.name}\n${d.country}`
    })

If you don’t have a start and stop date, and instead you have periodic sampling (like, every day), you could use the interval option instead:

    Plot.barX(data, {
      y: "name",
      x: (d) => d.date,
      interval: d3.utcDay,
      fill: (d) => d.country,
      title: (d) => `${d.name}\n${d.country}`
    })

I’ll also note that your notebook is currently using local time. That’s fine if all of your viewers are in the same time zone, but if your viewers might be in different time zones, then you’ll want to use UTC instead. And also note that Plot defaults to UTC with temporal data, so you’ll need to say x: {type: "time"} (rather than x: {type: "utc"}, or not specifying the scale type).

(You’ll also want to avoid the mutation you’re currently doing by calling setHours as this leads to unpredictable behavior with Observable dataflow.)

I’d probably do something like this:

Plot.plot({
  width,
  height: 200,
  label: null,
  x: {
    axis: "top",
    domain: [start, end]
  },
  y: {
    grid: true
  },
  marks: [
    Plot.ruleX(d3.utcDay.range(start, end), { strokeOpacity: 0.1 }),
    Plot.ruleX([today], { stroke: "red" }),
    Plot.barX(data, {
      y: "NAME",
      x: "DATE",
      interval: d3.utcDay,
      inset: 0, // no gaps between days
      fill: "COUNTRY",
      title: (d) => `${d.NAME}\n${d.COUNTRY}`
    })
  ]
})

Live notebook: Plot now / Mike Bostock / Observable

1 Like

Thanks again.
I learnt lot more about ordinal scales, utc, choosing right plot type. Highly valued feedback. :pray:

1 Like