Skip to content

Commit d4b0685

Browse files
committed
more difference docs
1 parent 94a48ee commit d4b0685

File tree

4 files changed

+446
-37
lines changed

4 files changed

+446
-37
lines changed

docs/data/tsa.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../test/data/tsa.csv

docs/marks/difference.md

Lines changed: 76 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,63 +2,114 @@
22

33
import * as Plot from "@observablehq/plot";
44
import * as d3 from "d3";
5-
import {ref, shallowRef, onMounted} from "vue";
5+
import {computed, ref, shallowRef, onMounted} from "vue";
66

77
const shift = ref(365);
88
const aapl = shallowRef([]);
9-
const goog = shallowRef([]);
9+
const gistemp = shallowRef([]);
10+
const tsa = shallowRef([{Date: new Date("2020-01-01")}]);
1011
const temperature = shallowRef([{date: new Date("2020-01-01")}]);
1112

1213
onMounted(() => {
1314
d3.csv("../data/aapl.csv", d3.autoType).then((data) => (aapl.value = data));
14-
d3.csv("../data/goog.csv", d3.autoType).then((data) => (goog.value = data));
15+
d3.csv("../data/gistemp.csv", d3.autoType).then((data) => (gistemp.value = data));
16+
d3.csv("../data/tsa.csv",d3.autoType).then((data) => (tsa.value = data));
1517
d3.csv("../data/sf-sj-temperatures.csv", d3.autoType).then((data) => (temperature.value = data.filter((d) => d.date.getUTCFullYear() === 2020)));
1618
});
1719

18-
const offset = (date) => d3.utcDay.offset(date, shift.value);
19-
2020
</script>
2121

2222
# Difference mark
2323

24-
The **difference mark** compares a metric to another metric.
24+
The **difference mark** compares a metric. Like the [area mark](./area.md), the region between two lines is filled; unlike the area mark, alternating color shows when the primary metric is above or below the secondary metric.
25+
26+
In the simplest case, the difference mark compares a metric to a constant, often zero. For example, the plot below shows the [global surface temperature anomaly](https://data.giss.nasa.gov/gistemp/) from 1880–2016; 0° represents the 1951–1980 average; above-average temperatures are in <span style="border-bottom: solid var(--vp-c-red) 3px;">red</span>, while below-average temperatures are in <span style="border-bottom: solid var(--vp-c-blue) 3px;">blue</span>.
27+
28+
:::plot
29+
```js
30+
Plot.differenceY(gistemp, {
31+
x: "Date",
32+
y: "Anomaly",
33+
positiveFill: "red",
34+
negativeFill: "blue",
35+
tip: true
36+
}).plot({y: {grid: true}})
37+
```
38+
:::
39+
40+
Applying a 24-month [moving average](../transforms/window.md) improves readability by smoothing the noise.
41+
42+
:::plot
43+
```js
44+
Plot.differenceY(
45+
gistemp,
46+
Plot.windowY(12 * 2, {
47+
x: "Date",
48+
y: "Anomaly",
49+
positiveFill: "red",
50+
negativeFill: "blue",
51+
tip: true
52+
})
53+
).plot({y: {grid: true}})
54+
```
55+
:::
56+
57+
More powerfully, the difference mark compares two metrics.
58+
59+
Comparing metrics is most convenient when the data has a column for each. For example, the plot below shows the number of daily travelers through TSA checkpoints in 2020 compared to 2019. In the first two months of 2020, there were on average <span style="border-bottom: solid #01ab63 3px;">more travelers</span> per day than 2019; yet when COVID-19 hit, there were many <span style="border-bottom: solid #4269d0 3px;">fewer travelers</span> per day, dropping almost to zero.
2560

2661
:::plot
2762
```js
2863
Plot.plot({
2964
x: {tickFormat: "%b"},
30-
y: {grid: true},
65+
y: {grid: true, label: "Travelers"},
3166
marks: [
32-
Plot.ruleY([32]),
33-
Plot.differenceY(temperature, Plot.windowY(14, {
34-
filter: (d) => d.station === "SF",
35-
x: "date",
36-
y: "tmin",
37-
y1: (d, i) => temperature[i + 1]?.tmin,
38-
tip: true
39-
}))
67+
Plot.axisY({label: "Daily travelers (thousands, 2020 vs. 2019)", tickFormat: (d) => d / 1000}),
68+
Plot.ruleY([0]),
69+
Plot.differenceY(tsa, {
70+
x: "Date",
71+
y1: "2019",
72+
y2: "2020",
73+
tip: {format: {x: "%B %-d"}}
74+
})
4075
]
4176
})
4277
```
4378
:::
4479

80+
If the data is “tall” rather than “wide” — TK explain what this means — you can use the [group transform](../transforms/group.md) with the [find reducer](../transforms/group.md#find): group the rows by date, and then for the two output columns **y1** and **y2**, find the desired corresponding row. The plot below shows daily minimum temperature for San Francisco compared to San Jose. The insulating effect of the fog keeps San Francisco warmer in winter and cooler in summer, reducing seasonal variation.
81+
4582
:::plot
4683
```js
4784
Plot.plot({
85+
x: {tickFormat: "%b"},
4886
y: {grid: true},
4987
marks: [
50-
Plot.ruleY([1]),
51-
Plot.differenceY(aapl, Plot.normalizeY({
52-
x: "Date",
53-
y: "Close",
54-
y1: Plot.valueof(goog, "Close"),
55-
tip: true
56-
}))
88+
Plot.ruleY([32]),
89+
Plot.differenceY(
90+
temperature,
91+
Plot.windowY(
92+
14,
93+
Plot.groupX(
94+
{
95+
y1: Plot.find((d) => d.station === "SJ"),
96+
y2: Plot.find((d) => d.station === "SF")
97+
},
98+
{
99+
x: "date",
100+
y: "tmin",
101+
tip: true
102+
}
103+
)
104+
)
105+
)
57106
]
58107
})
59108
```
60109
:::
61110

111+
The difference mark can also be used to compare a metric *to itself* using the [shift transform](../transforms/shift.md). This is especially useful for time series that exhibit [periodicity](https://en.wikipedia.org/wiki/Seasonality) — which is most of them, and certainly ones that involve human behavior. In this way a difference mark can show week-over-week or year-over-year growth.
112+
62113
<p>
63114
<label class="label-input" style="display: flex;">
64115
<span style="display: inline-block; width: 7em;">Shift:</span>
@@ -67,25 +118,13 @@ Plot.plot({
67118
</label>
68119
</p>
69120

70-
:::plot hidden
121+
:::plot
71122
```js
72-
Plot.plot({
73-
y: {grid: true},
74-
marks: [
75-
Plot.differenceY(aapl, {x: "Date", y: "Close", shift: `${shift} days`})
76-
]
77-
})
123+
Plot.differenceY(aapl, Plot.shiftX(`${shift} days`, {x: "Date", y: "Close"})).plot({y: {grid: true}})
78124
```
79125
:::
80126

81-
```js-vue
82-
Plot.plot({
83-
y: {grid: true},
84-
marks: [
85-
Plot.differenceY(aapl, {x: "Date", y: "Close", shift: "{{ shift }} days"})
86-
]
87-
})
88-
```
127+
TK Something about if you sold Apple stock after holding it for a year, you’d tend to do pretty well. But if you hold it for less time, you see more blue. And even if you held it for a year, you could have still lost money if you sold in most of 2016. Even the unluckiest person would have made money if they held Apple stock for 780+ days (in 2015–2018).
89128

90129
## Difference options
91130

test/data/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@ https://gist.github.com/chrtze/c74efb46cadb6a908bbbf5227934bfea
186186
TSA
187187
https://www.tsa.gov/coronavirus/passenger-throughput
188188

189+
## tsa.csv
190+
TSA
191+
https://www.tsa.gov/travel/passenger-volumes
192+
189193
## us-congress-2023.csv
190194
Members of U.S. Congress, April 2023
191195
https://github.com/unitedstates/congress-legislators

0 commit comments

Comments
 (0)