Converting Date Ranges to Counts

Hello!

I have collected data on the books I have read over the past few years. I want to create a visualization in which I can see how many books I was reading each day of the year. Currently, the data I’ve collected contains the start and stop day of the books, along with the title and author as such:

data = [
	{title: 'War and Peace', author: 'Leo Tolstoy', start: '2021-01-01', stop: '2021-06-15'},
	{title: 'The Great Gatsby', author: 'F. Scott Fitzgerald', start: '2021-02-20', stop: '2021-03-30'},
	{title: 'Moby Dick', author: 'Herman Melville', start: '2021-05-06', stop: '2021-08-10'},
	{title: 'Pride and Prejudice', author: 'Jane Austen', start: '2021-05-25', stop: '2021-10-03'},
	{title: 'Mrs. Dalloway', author: 'Virginia Woolf', start: '2021-06-02', stop: '2021-11-10'},
]

I want to use Plot and the cell mark to show how many books I was reading on any given day. I am unsure how to transform a series of overlapping date ranges into an aggregated count of books by day. Any advice would help.

Thanks!

1 Like

Which chart type or combination of charts to you have envisioned? Would calendar view help?

I envisioned something similar to this:

That calendar view looks interesting :slight_smile:

If your dataset is called books, you can expand it to include all the days you were reading such and such book with a flatMap:

data = books.flatMap((book) =>
  d3.utcDays(d3.isoParse(book.start), d3.isoParse(book.stop))
    .map((date) => ({ ...book, date }))
)

You can then use this structure in a Plot:

Plot.rectY(
  data,
  Plot.stackY({
    x: "date",
    interval: d3.utcDay,
    inset: -0.5,
    fill: "title",
    title: "title",
    order: "appearance",
    reverse: true
  })
).plot({ width: 940, height: 200 })

or in a Calendar:

import { Calendar } from "@observablehq/calendar-component"

Calendar(data, {
  reduce: (d) => ({ value: d.length }),
  color: { scheme: "reds" }
})

notebook: How many books was I reading? / Fil / Observable

2 Likes

Thank you! This is great :slight_smile:

1 Like

Can’t wait to see what it gives with the actual data :slight_smile:

I’ve added a fix for the “degenerate” case of reading a book on a single day (start==end — maybe not War and Peace though); we still want it to show on the chart.

1 Like

@Fil Thanks again for the help! Here is an image with some real data.

I will post the completed notebook here at the end of the year :slight_smile:

2 Likes

Oops in your screenshot the months labels are somehow a bit off… any idea why this might be happening?

This is just what I have in mind for an antibiotic use chart for a patient in ICU! Instead of books, antibiotics.
Medical charts are boring and really hard to interpret, as we, docs, just fill in the dates of antibiotic use. We don’t really have a true image of whats going on with patients, who, sometimes, spend weeks under intensive care, using multiple antibiotics!
Dang! I could use different shades of colors for different classes of antibiotics! Different carbapenems are different shades of orange, different aminoglycosides are different shades of green, and so on!

data = [
  {atb: "Tazocin", begin: "2022-03-02", end: "2022-03-11", stop: "2022-03-05", reason: "failure"},
  {atb: "Meropenem", begin: "2022-03-05", end: "2022-03-18"},
  {atb: "Vancomycin", begin: "2022-03-05", end: "2022-03-18"}
]
                 March       |
                 2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17 18
Tazocin (4d)     ◼︎  ◼︎  ◼︎  ◼︎  -  -  -  -  -  - failure
Meropenem D2/14           ◼︎  ◼︎  ◻︎  ◻︎  ◻︎  ◻︎  ◻︎  ◻︎  ◻︎  ◻︎  ◻︎  ◻︎  ◻︎  ◻︎
Vancomycin D2/14          ◼︎  ◼︎  ◻︎  ◻︎  ◻︎  ◻︎  ◻︎  ◻︎  ◻︎  ◻︎  ◻︎  ◻︎  ◻︎  ◻︎
                             |

I think this notebook is a good place for me to start.

1 Like

@erikneves can you share your notebook?

I’m just new to D3 and Observable. As soon as I get to something remotely presentable, be sure I’ll post it here.