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

Cross-posting from javascript - How to create one line plot per color series in Observable Plot? - Stack Overflow.


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 see below snippet or run it on Stack Overflow 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!

<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>
    <script type="module">
		import * as Plot from "https://cdn.skypack.dev/@observablehq/plot@0.4";

		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 ${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" })
				],				
			}));
		}
		
		
		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
			},
		])
    </script>
</body>

</html>

Thank you!

I think what you want is

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

(answer also cross-posted :wink: )

2 Likes

Hello Fil, thank you very much!
Do you have any link where I can learn more about z?

Thanks!

1 Like

It’s documented in https://github.com/observablehq/plot#area and https://github.com/observablehq/plot#line

z is used to separate series; it defaults to stroke or fill when then are channels, which is why most of the time you don’t need to specify it explicitly.

1 Like

Oh, now I feel stupid seeing it so clearly in the API documentation.

Thanks again!

No reason to feel bad, it’s a lot to process!

1 Like