# Plot: Display events using rect mark

**URL:** <https://talk.observablehq.com/t/plot-display-events-using-rect-mark/6440>\
**Category:** Help\
**Created:** [April 11, 2022, 11:50am UTC](https://talk.observablehq.com/t/plot-display-events-using-rect-mark/6440 "2022-04-11T11:50:33Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![chrispahm](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/chrispahm/32/4203_2.png) [@chrispahm](https://talk.observablehq.com/u/chrispahm)\
**Post date:** [April 11, 2022, 11:50am UTC](https://talk.observablehq.com/t/plot-display-events-using-rect-mark/6440/1 "2022-04-11T11:50:33Z")

</div>

Hi everyone 👋 ,

I’d like to show events or “time blocks” on a plot. Very similar to a calendar view. The x-axis shows the date, while the y-axis shows the time of the day.

However, I can’t get the blocks to render using the rect mark.  
Would really appreciate any help/guidance on how I could accomplish this!

Best  
Chris

Notebook:

> **[Plot - Display time 'blocks' using rect mark](https://observablehq.com/@chrispahm/plot-display-time-blocks-using-rect-mark)**
>
> I'd like to show events or "time blocks" on a plot. Very similar to a calendar view. The x-axis shows the date, while the y-axis shows the time of the day. Using the tick mark Here's a rendering of the data using the \\\`tick\\\` mark. However, it's...

---

<div class="post-metadata">

**Author:** ![mootari](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mootari/32/581_2.png) [@mootari](https://talk.observablehq.com/u/mootari)\
**Post date:** [April 11, 2022, 12:47pm UTC](https://talk.observablehq.com/t/plot-display-events-using-rect-mark/6440/2 "2022-04-11T12:47:20Z")

</div>

I think there are a few problems:

- Your fill is white, so you won’t see anything.
- You use d3.utcDay, which means that for sessions that start and end on the same day the start and end value will be the same, resulting in a width of zero.
- For the time scale you force the date to 1970-01-01. This will likely have side effects. Instead I’d recommend to use `+d3.utcFormat('%H%M')(date)` so that you end up with zero-padded HHMM converted to int.
- If your sessions span multiple days you’ll likely have to preprocess them and split them into multiple data times. Perhaps Plot has already some binning options for this.
- Nitpick: You may want to preprocess your data anyway, so that you don’t have to instantiate a Date over and over again.

---

<div class="post-metadata">

**Author:** ![mbostock](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mbostock/32/9_2.png) [@mbostock](https://talk.observablehq.com/u/mbostock)\
**Post date:** [April 12, 2022, 3:31am UTC](https://talk.observablehq.com/t/plot-display-events-using-rect-mark/6440/3 "2022-04-12T03:31:10Z")

</div>

Like @mootari said, it’s tricky if you have sessions which span multiple days: you’d need to create multiple elements to display such sessions. Your data doesn’t appear to have any such sessions, at least in UTC time, but, here’s how you could do it:

```nohighlight
sessions = (await FileAttachment("sessions.json").json())
  .map(({start, end}) => ({
    start: new Date(start),
    end: new Date(end)
  }))
  .flatMap(({start, end}) => {
    const days = d3.utcDay.range(d3.utcDay(start), end);
    return days.map((day, i) => ({
      start: i === 0 ? start : day,
      end: i === days.length - 1 ? end : days[i + 1]
    }));
  })
  .map(({start, end}) => ({
    start,
    end: new Date(end - 1) // convert to inclusive upper bound
  }))

```

I did a slightly tricky thing which is that I subtracted one millisecond from the end dates. This is mainly so that when you have sessions that span multiple days, the sessions end at 23:59:59.999Z on the same day rather than on 0:0:0.000Z on the next day.

Then, if you want the intraday time on the _y_ scale, you can map all the dates to the same day 1970-01-01 like you may have been doing before, like so:

```nohighlight
new Date(d.start - d3.utcDay(d.start))

```

`d3.utcDay(d.start)` returns the UTC midnight preceding or equal to `d.start`, so by subtracting the two, you count the number of milliseconds since UTC midnight. If you pass that to the Date constructor, it’ll give you the equivalent UTC time on January 1, 1970. You probably also want to _reverse_ the _y_ scale so that time goes down ↓ like in a typical calendar.

Likewise if you want the _x_ scale to show the start and end day, you can use `d3.utcDay` to round `d.start` down, and `d3.utcDay.ceil` to round `d.end` up. All together that might look like this:

 ![untitled (28)](https://canada1.discourse-cdn.com/flex030/uploads/observablehq/original/2X/5/5f456e2da7b8abf17badbf47e898a0c8068bc862.png)

```nohighlight
Plot.plot({
  x: {
    tickFormat: "%d.%m",
    round: true
  },
  y: {
    grid: true,
    tickFormat: "%I %p",
    reverse: true,
    nice: true
  },
  marks: [
    Plot.rect(sessions, {
      x1: d => d3.utcDay(d.start),
      x2: d => d3.utcDay.ceil(d.end),
      y1: d => new Date(d.start - d3.utcDay(d.start)),
      y2: d => new Date(d.end - d3.utcDay(d.end)),
      insetLeft: 0.5,
      insetRight: 0.5
    }),
    Plot.ruleY([new Date("1970-01-01"), new Date("1970-01-01T23:59:59.999Z")])
  ]
})

```

> **[Plot - Display time 'blocks' using rect mark](https://observablehq.com/d/dd5cc147c66942a7)**

---

<div class="post-metadata">

**Author:** ![chrispahm](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/chrispahm/32/4203_2.png) [@chrispahm](https://talk.observablehq.com/u/chrispahm)\
**Post date:** [April 19, 2022, 9:00am UTC](https://talk.observablehq.com/t/plot-display-events-using-rect-mark/6440/4 "2022-04-19T09:00:43Z")

</div>

Awesome! Thanks so much @mbostock for your answer!
