Skip to content

Commit 79ceefe

Browse files
committed
checkpoint docs
1 parent 0775c7e commit 79ceefe

File tree

4 files changed

+118
-19
lines changed

4 files changed

+118
-19
lines changed

docs/.vitepress/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ export default defineConfig({
8888
{text: "Contour", link: "/marks/contour"},
8989
{text: "Delaunay", link: "/marks/delaunay"},
9090
{text: "Density", link: "/marks/density"},
91+
{text: "Difference", link: "/marks/difference"},
9192
{text: "Dot", link: "/marks/dot"},
9293
{text: "Frame", link: "/marks/frame"},
9394
{text: "Geo", link: "/marks/geo"},

docs/marks/difference.md

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<script setup>
2+
3+
import * as Plot from "@observablehq/plot";
4+
import * as d3 from "d3";
5+
import {ref, shallowRef, onMounted} from "vue";
6+
7+
const shift = ref(0);
8+
const aapl = shallowRef([]);
9+
const goog = shallowRef([]);
10+
11+
onMounted(() => {
12+
d3.csv("../data/aapl.csv", d3.autoType).then((data) => (aapl.value = data));
13+
d3.csv("../data/goog.csv", d3.autoType).then((data) => (goog.value = data));
14+
});
15+
16+
const offset = (date) => d3.utcDay.offset(date, shift.value);
17+
18+
</script>
19+
20+
# Difference mark
21+
22+
The **difference mark** compares a primary metric to a secondary metric.
23+
24+
:::plot
25+
```js
26+
Plot.plot({
27+
y: {grid: true},
28+
marks: [
29+
Plot.ruleY([1]),
30+
Plot.differenceY(aapl, Plot.normalizeY({
31+
x: "Date",
32+
y1: "Close",
33+
y2: Plot.valueof(goog, "Close"),
34+
tip: true
35+
}))
36+
]
37+
})
38+
```
39+
:::
40+
41+
:::plot
42+
```js
43+
Plot.plot({
44+
y: {grid: true},
45+
marks: [
46+
Plot.differenceY(aapl, {
47+
x1: "Date",
48+
x2: (d) => d3.utcYear.offset(d.Date),
49+
y: "Close",
50+
tip: true
51+
})
52+
]
53+
})
54+
```
55+
:::
56+
57+
<p>
58+
<label class="label-input" style="display: flex;">
59+
<span style="display: inline-block; width: 7em;">Shift:</span>
60+
<input type="range" v-model.number="shift" min="0" max="1000" step="1">
61+
<span style="font-variant-numeric: tabular-nums;">{{shift}}</span>
62+
</label>
63+
</p>
64+
65+
:::plot
66+
```js
67+
Plot.plot({
68+
x: {label: "Date"},
69+
y: {grid: true},
70+
marks: [
71+
Plot.differenceY(aapl, {
72+
x1: (d, i, data) => d.Date < offset(data[0].Date) ? null : d.Date,
73+
x2: (d, i, data) => data.at(-1).Date < offset(d.Date) ? null : offset(d.Date),
74+
y: "Close"
75+
})
76+
]
77+
})
78+
```
79+
:::
80+
81+
:::plot
82+
```js
83+
Plot.plot({
84+
x: {label: "Date"},
85+
y: {grid: true},
86+
marks: [
87+
Plot.differenceY(aapl, {
88+
x: (d, i) => i < shift ? null : d.Date,
89+
y1: "Close",
90+
y2: (d, i) => aapl[i - shift]?.Close,
91+
tip: true
92+
})
93+
]
94+
})
95+
```
96+
:::

src/marks/difference.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export function differenceY(
3737
y2,
3838
fill: positiveColor,
3939
fillOpacity: positiveOpacity,
40-
render: composeRender(render, renderDifference(true)),
40+
render: composeRender(render, clipDifference(true)),
4141
...options
4242
}),
4343
{ariaLabel: "positive difference"}
@@ -50,7 +50,7 @@ export function differenceY(
5050
y2,
5151
fill: negativeColor,
5252
fillOpacity: negativeOpacity,
53-
render: composeRender(render, renderDifference(false)),
53+
render: composeRender(render, clipDifference(false)),
5454
...options
5555
}),
5656
{ariaLabel: "negative difference"}
@@ -95,7 +95,7 @@ function memo(v) {
9595
return {transform: (data) => V || (V = valueof(data, value)), label};
9696
}
9797

98-
function renderDifference(positive) {
98+
function clipDifference(positive) {
9999
return (index, scales, channels, dimensions, context, next) => {
100100
const clip = getClipId();
101101
const clipPath = create("svg:clipPath", context).attr("id", clip).node();

test/plots/difference.ts

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export async function differenceY() {
99
const x = aapl.map((d) => d.Date);
1010
const y1 = aapl.map((d, i, data) => d.Close / data[0].Close);
1111
const y2 = goog.map((d, i, data) => d.Close / data[0].Close);
12-
return Plot.differenceY(aapl, {x: {value: x, label: "Date"}, y1: {value: y1, label: "Close"}, y2, tip: true}).plot();
12+
return Plot.differenceY(aapl, {x, y1: {value: y1, label: "Close"}, y2, tip: true}).plot();
1313
}
1414

1515
export async function differenceYRandom() {
@@ -48,21 +48,23 @@ export async function differenceYVariable() {
4848
// before and the year after the dataset, x1 and x2 are padded with NaN.
4949
export async function differenceY1() {
5050
const aapl = await d3.csv<any>("data/aapl.csv", d3.autoType);
51-
const interval = d3.utcYear;
52-
const start = interval.offset(aapl[0].Date, 1);
53-
const end = interval.offset(aapl[aapl.length - 1].Date, -1);
54-
const x1 = aapl.map((d) => (d.Date < start ? NaN : d.Date));
55-
const x2 = aapl.map((d) => (d.Date > end ? NaN : interval.offset(d.Date, 1)));
56-
const y = aapl.map((d) => d.Close);
57-
return Plot.differenceY(aapl, {
58-
x1,
59-
x2,
60-
y,
61-
positiveOpacity: 0.2,
62-
positiveColor: "currentColor",
63-
negativeOpacity: 0.8,
64-
negativeColor: "red"
65-
}).plot();
51+
return Plot.differenceY(aapl, shiftX(d3.utcYear, {x: "Date", y: "Close"})).plot({y: {grid: true}});
52+
}
53+
54+
function shiftX(interval, options) {
55+
return Plot.map(
56+
{
57+
x1(D) {
58+
const min = interval.offset(d3.min(D), 1);
59+
return D.map((d) => (d < min ? null : d));
60+
},
61+
x2(D) {
62+
const max = interval.offset(d3.max(D), -1);
63+
return D.map((d) => (max < d ? null : interval.offset(d, 1)));
64+
}
65+
},
66+
options
67+
);
6668
}
6769

6870
export async function differenceFilterX() {

0 commit comments

Comments
 (0)