javascriptd3.jsobservablehqobservable-plot

How to create one line plot per color series in Observable Plot?


Description:

I am playing around with Observable Plot an really like how easy it is to set up simple plots.

Now I have a little "more advanced" chart that I want to plot and need help.

In my data, I have multiple temp (temperature) readings recorded at a certain timestamp. Each reading comes from a sensor, and each sensor is attached to a certain device (multiple sensors (e.g., 1-3) can be attached to a single device (e.g., 2)). Thus, one data point might look like the following (see bottom script for a full minimal workabel example):

{
  timestamp: 1,
  device: 1,
  sensor: 1,
  temp: 20
}

Currently, I dot plot this data, facet it based on the sensor, and give a color the each (device, sensor) pair series (just run below snippet to get a better feeling).

Problem:

I now would like to connect all dots of the same color with a black line. I marked the problematic line with // HERE I NEED HELP in the snippet. I assume that I somehow have to group data based on device and sensor to achieve a similar grouping to the color, but I sadly have no idea how to achieve this and hope that you can help!

const plotTestTemperatures = function(data) {
  const div = document.getElementById('temp-chart-test')
  div.appendChild(Plot.plot({
    color: {
      type: "ordinal",
      scheme: "category10",
      legend: true
    },
    facet: { data: data, x: "device", grid: true,}, 
    grid: true,
    marks: [
      Plot.frame(),
      Plot.dot(data, {x: "timestamp", y: "temp", r: 4, opacity: 0.8, fill: d => `Sensor ${d.sensor} of device ${d.device}` }),
      // HERE I NEED HELP
      // does not yet work, connects all dots independent of color
      // Plot.line(data, {x: "timestamp", y: "temp", opacity: 0.8, stroke: "black" })
    ],              
  }));
}

// call with test data
plotTestTemperatures([
  {
    timestamp: 1,
    device: 1,
    sensor: 1,
    temp: 20
  },
  {
    timestamp: 2,
    device: 1,
    sensor: 1,
    temp: 21
  },
  {
    timestamp: 3,
    device: 1,
    sensor: 1,
    temp: 22
  },
  {
    timestamp: 1,
    device: 1,
    sensor: 2,
    temp: 20.1
  },
  {
    timestamp: 2,
    device: 1,
    sensor: 2,
    temp: 21.3
  },
  {
    timestamp: 3,
    device: 1,
    sensor: 2,
    temp: 22.5
  },
  {
    timestamp: 1,
    device: 2,
    sensor: 1,
    temp: 18
  },
  {
    timestamp: 2,
    device: 2,
    sensor: 1,
    temp: 19
  },
  {
    timestamp: 3,
    device: 2,
    sensor: 1,
    temp: 20
  },
  {
    timestamp: 1,
    device: 2,
    sensor: 2,
    temp: 17.8
  },
  {
    timestamp: 2,
    device: 2,
    sensor: 2,
    temp: 19.1
  },
  {
    timestamp: 3,
    device: 2,
    sensor: 2,
    temp: 20.1
  },
])
<html>

<head>
    <meta name=”robots” content=”noindex”>
    <meta charset="UTF-8">
    <title>Home Automation</title>
    <script src="https://d3js.org/d3.v7.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@observablehq/plot@0.4"></script>
</head>

<body>
    <div id="app">
        <h1>Home Automation</h1>
        <div id="temp-chart-test"></div>
    </div>
</body>
</html>

(cross-posted to the ObservableHQ forum)


Solution

  • I think what you want is

    z: (d) => `Sensor ${d.sensor} of device ${d.device}`,