Skip to content

Commit 947917f

Browse files
committed
Merge branch 'main' of github.com:InteractiveDataVis/Interactive-Data-Vis-Spring2026 into class
2 parents ceba025 + 96d81b8 commit 947917f

File tree

2 files changed

+184
-1
lines changed

2 files changed

+184
-1
lines changed

observablehq.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export default {
1515
{ name: "Working in Cursor", path: "/lessons/2_working_in_cursor" },
1616
{ name: "Intro to Observable Framework", path: "/lessons/3_intro_to_observable_framework" },
1717
{ name: "Confirming Spring Upstream", path: "/lessons/4_confirming_spring_upstream" },
18-
// { name: "Intro to Observable Plot", path: "/lessons/4_intro_to_observable_plot" },
18+
{ name: "Intro to Observable Plot", path: "/lessons/5_intro_to_observable_plot" },
1919
]
2020
},
2121
{
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
---
2+
title: "Intro to Observable Plot"
3+
toc: true
4+
---
5+
6+
# Intro to Observable Plot
7+
8+
---
9+
10+
## What is Observable Plot?
11+
12+
**Observable Plot** is a declarative JavaScript library for data visualization. In this course we use it for all charts. Unlike “chart type” libraries, but similar to the many recomendations of our readings, Plot is **marks-based**. That means you build a chart by combining **marks** (dots, bars, lines, areas, etc.) and binding them to data. There is no separate “scatter template” or “bar template”—you choose the marks and the scales do the rest.
13+
14+
Note on using Plot in Framwork: Plot, similar to d3.js, is available globally in `.md` pages; you do not import it.
15+
16+
---
17+
18+
## Plot.plot()
19+
20+
Every chart is created with `Plot.plot(options)`. Even without options, an SVG is rendered. You may not see anything here, but there is an SVG rendered from the `Plot.plot()` code below. You can inspect the window and see an svg.
21+
22+
```js echo
23+
Plot.plot()
24+
```
25+
26+
The most important option is **`marks`**: an array of marks drawn in order (last on top). Marks include things like dots, bars, lines, etc.
27+
28+
Let's say our data is the following:
29+
```js echo
30+
const sample = [
31+
{ name: "A", value: 10, color: "blue" },
32+
{ name: "B", value: 25, color: "green" },
33+
{ name: "C", value: 15, color: "orange" },
34+
{ name: "D", value: 30, color: "red" }
35+
];
36+
```
37+
38+
```js echo
39+
Plot.plot({
40+
marginLeft: 50,
41+
title: "Sample Bar Chart",
42+
marks: [
43+
Plot.barY(sample, {
44+
x: "name",
45+
y: "value",
46+
fill: "steelblue",
47+
tip: true
48+
})
49+
]
50+
})
51+
```
52+
53+
Common top-level options include **`title`**, **`width`**, **`height`**, **`marginLeft`** (and other margins), **`grid: true`**, and **`marks`**. In Framework, you can pass the built-in **`width`** variable so the chart resizes with the page.
54+
55+
---
56+
57+
## Marks
58+
59+
Common helpful marks include:
60+
61+
| Mark | Typical use |
62+
|------|-------------|
63+
| `Plot.dot()` | Scatter (one point per row) |
64+
| `Plot.barY()` / `Plot.barX()` | Bar charts |
65+
| `Plot.lineY()` / `Plot.lineX()` | Line / time series |
66+
| `Plot.areaY()` | Area under a line |
67+
| `Plot.rectY()` | Histograms (with a bin transform) |
68+
| `Plot.ruleY()` / `Plot.ruleX()` | Reference lines (e.g. at zero) |
69+
| `Plot.frame()` | Border around the plot |
70+
71+
Marks take **data** and **options**. The structure is something like this:
72+
73+
``` echo
74+
Plot.plot({
75+
marks: [
76+
Plot.[MARK]([DATA], [OPTIONS])
77+
]
78+
})
79+
```
80+
Each argument serves a specific purpose:
81+
1. Data - the data to be used to render the marks (e.g. `Plot.dot(sample, {...})`).
82+
2. Options - options about this specific mark, including channels and/or constants about how to tie the data to the mark.
83+
84+
### Data join
85+
86+
Marks within Plot leverage something we can call a **data join**: in many instances, one row in your data array becomes one graphical element (one dot, one bar, etc.). The mark function takes two arguments:
87+
88+
The **channels** in the options tell Plot how to read each row, i.e., `x: "name"` means “use this row’s `name` for the x position,” and `y: "value"` means “use this row’s `value` for the y position.”
89+
90+
So for `sample` with 4 rows, `Plot.dot(sample, { x: "name", y: "value" })` draws **4 dots**—one per row—with positions coming from those fields.
91+
92+
Constants (e.g. `r: 6`) apply the same to every mark; channel names (e.g. `fill: "color"`) directly render the data points color as the background.
93+
94+
```js echo
95+
Plot.plot({
96+
grid: true,
97+
marks: [
98+
Plot.ruleY([0], { stroke: "gray", strokeDasharray: "2 2" }),
99+
Plot.dot(sample, {
100+
x: "name", // ← which key to read for x positioning
101+
y: "value", // ← which key to read for y positioning
102+
r: 6, // ← set value for radius
103+
fill: "color", // ← which key to read for fill
104+
tip: true
105+
})
106+
]
107+
})
108+
```
109+
110+
You can also use functions to pass values to the marks options. When using functions, it will run the function on the associated data that it is making a mark for. This allows you to manipulate values and how they should be rendered.
111+
112+
```js echo
113+
Plot.plot({
114+
grid: true,
115+
marks: [
116+
Plot.ruleY([0], { stroke: "gray", strokeDasharray: "2 2" }),
117+
Plot.dot(sample, {
118+
x: (d, i) => d["name"] + " element",
119+
y: (d, i) => d["value"] * 100,
120+
r: (d, i) => 10 + i * 15,
121+
fill: (d, i) => ["red", "orange", "yellow", "green"][i],
122+
tip: true
123+
})
124+
]
125+
})
126+
```
127+
128+
---
129+
130+
## Transforms
131+
132+
Sometimes, data is not in the exact format that we may want when considering a visual. Let's take the (preloaded) penguins dataset. Say you want to count times a penguin is listed as each of the species. The dataset looks like this:
133+
134+
```js
135+
Inputs.table(penguins)
136+
```
137+
138+
There is no column for "count". Each row is a penguin, with its own species designation, along with other metrics. We need to run a transformation on the data to determine how many penguins fit into each species. This could be done with Javascript, which we will get into more in future classes, but it also can be done within the Plot arguments with a **transform**.
139+
140+
When simply counting rows to then plot into a bar chart, we transform with `groupX` within the `barY` mark. That is because we are transforming based on the x axis to some reduction which will be applied to the y axis.
141+
142+
```js echo
143+
Plot.plot({
144+
marks: [
145+
Plot.barY(penguins,
146+
Plot.groupX(
147+
{ y: "count" }, // ← this is the "reducer", or, what aggregation/function/etc to apply
148+
{ x: "species" } // ← this is the pivot point for the reducer -- what are we counting on?
149+
)
150+
)
151+
]
152+
})
153+
```
154+
155+
There are a great many transforms you can do to the data, but the transform you use depends a lot on the data, the scales, and the intended marks. For a histogram, you **bin** the data and then draw **rects**. Use the **`Plot.binX()`** transform: it groups values into bins and can reduce with `y: "count"` (or `"sum"`, `"mean"`, etc.).
156+
157+
```js echo
158+
const values = [3, 5, 2, 7, 4, 5, 4, 4, 6, 4, 5, 8, 4, 6];
159+
const raw = values.map((v, i) => ({ id: i, value: v }));
160+
```
161+
162+
```js echo
163+
Plot.plot({
164+
y: { grid: true },
165+
marks: [
166+
Plot.rectY(raw, Plot.binX(
167+
{ y: "count" },
168+
{ x: "value", thresholds: 6 }
169+
)),
170+
Plot.ruleY([0])
171+
]
172+
})
173+
```
174+
175+
---
176+
177+
## Plot tips
178+
179+
- You can put `Plot.plot({...})` inside a **`${ ... }`** expression in your markdown or HTML so it renders inline (as in the examples above). If you use a code block, and create something else in the code block, don't forget to use `display` or `view` around your plot.
180+
- You can place plots inside **cards** or **grids** as in the [Intro to Observable Framework](/lessons/3_intro_to_observable_framework) lesson.
181+
- Use **`view()`** and **Inputs** to drive reactive variables (e.g. a selected category); use those variables in your data pipeline or in Plot options so the chart updates when the input changes.
182+
183+
For more marks, options, and transforms, see the [Observable Plot documentation](https://observablehq.com/plot).

0 commit comments

Comments
 (0)