How to plot time ranged data?

I got csv or tsv data and I want to plot it into some simple line graph but the problem the data is time ranged like this:

begin	end	flowrate
00:02:07	00:03:33	0.000000000000003552713678800501
00:03:33	00:03:35	27.411446
00:03:35	00:03:45	27.129249
00:03:45	00:03:46	134.570356
00:03:46	00:04:12	135.911525
00:04:12	00:04:14	113.602685
00:04:14	00:04:16	27.129400000000004
00:04:16	00:04:17	13.564667000000004
00:04:17	00:08:32	0.000000000000003552713678800501
00:08:32	00:08:33	27.273192000000005
00:08:33	00:08:43	27.129239000000002
00:08:43	00:08:44	134.548651
00:08:44	00:09:11	135.91146
00:09:11	00:09:13	112.875284
00:09:13	00:09:15	27.129207000000008
00:09:15	00:09:16	6.7823060000000055
00:09:16	00:13:31	0.000000000000005329070518200751
00:13:31	00:13:33	27.200278000000004
00:13:33	00:13:42	27.129345000000004
00:13:42	00:13:43	107.106682
00:13:43	00:14:11	135.911483
00:14:11	00:14:12	31.837013
00:14:12	00:14:13	27.129293
00:14:13	00:14:15	13.564652
00:14:15	00:18:30	0
00:18:30	00:18:31	27.273108

What is the simplest way to do it?
I once grok d3.js a long time ago but I see new plot lib so either libs is fine to me, just show me the way.

Assuming that there are no gaps in the data, a simple way to do it would be to use the step-after curve, and then plot x = begin and y = flowrate.

Plot.plot({
  y: {grid: true},
  marks: [
    Plot.ruleY([0]),
    Plot.lineY(data, {x: "begin", y: "flowrate", curve: "step-after"})
  ]
})

Another way to do this would be to create a series of horizontal segments using array.flatMap:

Plot.plot({
  y: { grid: true },
  marks: [
    Plot.ruleY([0]),
    Plot.lineY(
      data.flatMap((d) => [
        { date: d.begin, flowrate: d.flowrate },
        { date: d.end, flowrate: d.flowrate }
      ]),
      { x: "date", y: "flowrate" }
    )
  ]
})

If you have gaps between segments, you’d need to break up the segments with an undefined flowrate to show discontinuities, like this (which I simulated by dropping a few rows of the data):

Plot.plot({
  y: { grid: true },
  marks: [
    Plot.ruleY([0]),
    Plot.lineY(
      [...data.slice(0, 16), ...data.slice(18)].flatMap((d, i, data) => [
        { date: d.begin, flowrate: d.begin <= data[i - 1]?.end ? d.flowrate : NaN },
        { date: d.begin, flowrate: d.flowrate },
        { date: d.end, flowrate: d.flowrate }
      ]),
      { x: "date", y: "flowrate" }
    )
  ]
})

Notebook: Plot: Time-ranged data / Observable | Observable

1 Like

Thanks, I think I get the idea. Will try to code some d3 cause the graph is too noisy so it need some zoom plus a live update is good to have.