Skip to content

Commit 9049e81

Browse files
authored
non-strict window by default (#993)
1 parent 3ef622f commit 9049e81

10 files changed

+117
-113
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1890,9 +1890,9 @@ The Plot.windowX and Plot.windowY transforms compute a moving window around each
18901890
* **k** - the window size (the number of elements in the window)
18911891
* **anchor** - how to align the window: *start*, *middle*, or *end*
18921892
* **reduce** - the aggregation method (window reducer)
1893-
* **extend** - whether to extend output values by truncating the window; defaults to false
1893+
* **strict** - if true, disallow window truncation; defaults to false
18941894
1895-
If the **extend** option is true, note that the resulting start values or end values or both (depending on the **anchor**) of each series may be noisy, as the window size will be truncated. For example, if **k** is 24 and **anchor** is *middle*, then the initial 11 values have effective window sizes of 13, 14, 15, … 23, and likewise the last 12 values have effective window sizes of 23, 22, 21, … 12. On the other hand, if the **extend** option is false, then some start values or end values will be undefined if **k** is greater than one.
1895+
If the **strict** option is true, the resulting start values or end values or both (depending on the **anchor**) of each series may be undefined since there are not enough elements to create a window of size **k**. If the **strict** option is false (the default), the window will be automatically truncated as needed. For example, if **k** is 24 and **anchor** is *middle*, then the initial 11 values have effective window sizes of 13, 14, 15, … 23, and likewise the last 12 values have effective window sizes of 23, 22, 21, … 12. Values computed with a truncated window may be noiser; if you would prefer to not show this data, set the **strict** option to true.
18961896
18971897
The following window reducers are supported:
18981898

src/transforms/window.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ export function windowY(windowOptions = {}, options) {
1515

1616
export function window(options = {}) {
1717
if (typeof options === "number") options = {k: options};
18-
let {k, reduce, shift, anchor, extend} = options;
18+
let {k, reduce, shift, anchor, strict} = options;
1919
if (anchor === undefined && shift !== undefined) {
2020
anchor = maybeShift(shift);
2121
warn(`Warning: the shift option is deprecated; please use anchor "${anchor}" instead.`);
2222
}
2323
if (!((k = Math.floor(k)) > 0)) throw new Error(`invalid k: ${k}`);
2424
const r = maybeReduce(reduce);
2525
const s = maybeAnchor(anchor, k);
26-
return (extend ? extendReducer(r) : r)(k, s);
26+
return (strict ? r : looseReducer(r))(k, s);
2727
}
2828

2929
function maybeAnchor(anchor = "middle", k) {
@@ -66,7 +66,7 @@ function maybeReduce(reduce = "mean") {
6666
return reduceSubarray(reduce);
6767
}
6868

69-
function extendReducer(reducer) {
69+
function looseReducer(reducer) {
7070
return (k, s) => {
7171
const reduce = reducer(k, s);
7272
return {
@@ -75,17 +75,21 @@ function extendReducer(reducer) {
7575
reduce.map(I, S, T);
7676
for (let i = 0; i < s; ++i) {
7777
const j = Math.min(n, i + k - s);
78-
reducer(j, i).map(I.subarray(0, j), S, T);
78+
reducer(j, i).map(slice(I, 0, j), S, T);
7979
}
8080
for (let i = n - k + s + 1; i < n; ++i) {
8181
const j = Math.max(0, i - s);
82-
reducer(n - j, i - j).map(I.subarray(j, n), S, T);
82+
reducer(n - j, i - j).map(slice(I, j, n), S, T);
8383
}
8484
}
8585
};
8686
};
8787
}
8888

89+
function slice(I, i, j) {
90+
return I.subarray ? I.subarray(i, j) : I.slice(i, j);
91+
}
92+
8993
function reduceSubarray(f) {
9094
return (k, s) => ({
9195
map(I, S, T) {

test/output/metroUnemploymentMoving.svg

Lines changed: 45 additions & 45 deletions
Loading

test/plots/aapl-bollinger.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ export default async function() {
1616
}
1717

1818
function bollinger(N, K) {
19-
return Plot.window({k: N, reduce: Y => d3.mean(Y) + K * d3.deviation(Y), anchor: "end"});
19+
return Plot.window({k: N, reduce: Y => d3.mean(Y) + K * d3.deviation(Y), strict: true, anchor: "end"});
2020
}

test/plots/gistemp-anomaly-moving.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export default async function() {
1616
marks: [
1717
Plot.ruleY([0]),
1818
Plot.dot(data, {x: "Date", y: "Anomaly", stroke: "Anomaly"}),
19-
Plot.line(data, Plot.windowY({k: 24, extend: true}, {x: "Date", y: "Anomaly"}))
19+
Plot.line(data, Plot.windowY({k: 24}, {x: "Date", y: "Anomaly"}))
2020
]
2121
});
2222
}

test/plots/seattle-precipitation-sum.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import * as d3 from "d3";
33

44
export default async function() {
55
const weather = (await d3.csv("data/seattle-weather.csv", d3.autoType)).slice(-28);
6-
const y = Plot.window({k: 7, reduce: "sum", anchor: "end"});
7-
const text = Plot.window({k: 7, reduce: V => Math.round(d3.sum(V)), anchor: "end"});
6+
const y = Plot.window({k: 7, strict: true, reduce: "sum", anchor: "end"});
7+
const text = Plot.window({k: 7, strict: true, reduce: V => Math.round(d3.sum(V)), anchor: "end"});
88
return Plot.plot({
99
marks: [
1010
Plot.rectY(weather, Plot.map({y}, {x: "date", y: "precipitation", interval: d3.utcDay})),

test/plots/sf-temperature-band-area.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ export default async function() {
99
label: "↑ Daily temperature range (°F)"
1010
},
1111
marks: [
12-
Plot.areaY(temperatures, Plot.windowY({k: 7, x: "date", y1: "low", y2: "high", curve: "step", fill: "#ccc"})),
13-
Plot.line(temperatures, Plot.windowY({k: 7, x: "date", y: d => (d.low + d.high) / 2, curve: "step"}))
12+
Plot.areaY(temperatures, Plot.windowY({k: 7, strict: true, x: "date", y1: "low", y2: "high", curve: "step", fill: "#ccc"})),
13+
Plot.line(temperatures, Plot.windowY({k: 7, strict: true, x: "date", y: d => (d.low + d.high) / 2, curve: "step"}))
1414
],
1515
width: 960
1616
});

test/plots/sf-temperature-band.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ export default async function() {
1010
},
1111
marks: [
1212
Plot.areaY(temperatures, {x: "date", y1: "low", y2: "high", curve: "step", fill: "#ccc"}),
13-
Plot.line(temperatures, Plot.windowY({x: "date", y: "low", k: 7, curve: "step", stroke: "blue"})),
14-
Plot.line(temperatures, Plot.windowY({x: "date", y: "high", k: 7, curve: "step", stroke: "red"}))
13+
Plot.line(temperatures, Plot.windowY({x: "date", y: "low", k: 7, strict: true, curve: "step", stroke: "blue"})),
14+
Plot.line(temperatures, Plot.windowY({x: "date", y: "high", k: 7, strict: true, curve: "step", stroke: "red"}))
1515
],
1616
width: 960
1717
});

test/plots/travelers-covid-drop.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export default async function() {
1313
},
1414
marks: [
1515
Plot.lineY(travelers, {x: "date", y: d => d.current / d.previous - 1, strokeWidth: 0.25, curve: "step"}),
16-
Plot.lineY(travelers, Plot.windowY({x: "date", y: d => d.current / d.previous - 1, k: 7, stroke: "steelblue"}))
16+
Plot.lineY(travelers, Plot.windowY({x: "date", y: d => d.current / d.previous - 1, k: 7, strict: true, stroke: "steelblue"}))
1717
]
1818
});
1919
}

test/transforms/window-test.js

Lines changed: 52 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -28,130 +28,130 @@ it(`windowX(k, options) is equivalent to windowX({k, anchor: "middle", reduce: "
2828
assert.deepStrictEqual(m1.x.transform(), m2.x.transform());
2929
});
3030

31-
it(`windowX(k, options) computes a moving average of window size k`, () => {
31+
it(`windowX({k, strict: true}, options) computes a moving average of window size k`, () => {
3232
const data = range(6);
33-
const m1 = applyTransform(Plot.windowX(1, {x: d => d}), data);
33+
const m1 = applyTransform(Plot.windowX({k: 1, strict: true}, {x: d => d}), data);
3434
assert.deepStrictEqual(m1.x.transform(), [0, 1, 2, 3, 4, 5]);
35-
const m2 = applyTransform(Plot.windowX(2, {x: d => d}), data);
35+
const m2 = applyTransform(Plot.windowX({k: 2, strict: true}, {x: d => d}), data);
3636
assert.deepStrictEqual(m2.x.transform(), [0.5, 1.5, 2.5, 3.5, 4.5,, ]);
37-
const m3 = applyTransform(Plot.windowX(3, {x: d => d}), data);
37+
const m3 = applyTransform(Plot.windowX({k: 3, strict: true}, {x: d => d}), data);
3838
assert.deepStrictEqual(m3.x.transform(), [, 1, 2, 3, 4,, ]);
39-
const m4 = applyTransform(Plot.windowX(4, {x: d => d}), data);
39+
const m4 = applyTransform(Plot.windowX({k: 4, strict: true}, {x: d => d}), data);
4040
assert.deepStrictEqual(m4.x.transform(), [, 1.5, 2.5, 3.5,,, ]);
4141
});
4242

43-
it(`windowX({reduce: "mean"}) produces NaN if the current window contains NaN`, () => {
43+
it(`windowX({k, strict: true}) produces NaN if the current window contains NaN`, () => {
4444
const data = [1, 1, 1, null, 1, 1, 1, 1, 1, NaN, 1, 1, 1];
45-
const m1 = applyTransform(Plot.windowX({reduce: "mean", k: 1, x: d => d}), data);
45+
const m1 = applyTransform(Plot.windowX({k: 1, strict: true, x: d => d}), data);
4646
assert.deepStrictEqual(m1.x.transform(), [1, 1, 1, NaN, 1, 1, 1, 1, 1, NaN, 1, 1, 1]);
47-
const m2 = applyTransform(Plot.windowX({reduce: "mean", k: 2, x: d => d}), data);
47+
const m2 = applyTransform(Plot.windowX({k: 2, strict: true, x: d => d}), data);
4848
assert.deepStrictEqual(m2.x.transform(), [1, 1, NaN, NaN, 1, 1, 1, 1, NaN, NaN, 1, 1,, ]);
49-
const m3 = applyTransform(Plot.windowX({reduce: "mean", k: 3, x: d => d}), data);
49+
const m3 = applyTransform(Plot.windowX({k: 3, strict: true, x: d => d}), data);
5050
assert.deepStrictEqual(m3.x.transform(), [, 1, NaN, NaN, NaN, 1, 1, 1, NaN, NaN, NaN, 1,, ]);
5151
});
5252

53-
it(`windowX({reduce: "mean"}) treats null as NaN`, () => {
53+
it(`windowX({k, strict: true}) treats null as NaN`, () => {
5454
const data = [1, 1, 1, null, 1, 1, 1, 1, 1, null, 1, 1, 1];
55-
const m3 = applyTransform(Plot.windowX({reduce: "mean", k: 3, x: d => d}), data);
55+
const m3 = applyTransform(Plot.windowX({k: 3, strict: true, x: d => d}), data);
5656
assert.deepStrictEqual(m3.x.transform(), [, 1, NaN, NaN, NaN, 1, 1, 1, NaN, NaN, NaN, 1,, ]);
5757
});
5858

59-
it(`windowX({reduce: "mean", anchor}) respects the given anchor`, () => {
59+
it(`windowX({k, strict: true, anchor}) respects the given anchor`, () => {
6060
const data = [0, 1, 2, 3, 4, 5];
61-
const mc = applyTransform(Plot.windowX({reduce: "mean", k: 3, anchor: "middle", x: d => d}), data);
61+
const mc = applyTransform(Plot.windowX({k: 3, strict: true, anchor: "middle", x: d => d}), data);
6262
assert.deepStrictEqual(mc.x.transform(), [, 1, 2, 3, 4,, ]);
63-
const ml = applyTransform(Plot.windowX({reduce: "mean", k: 3, anchor: "start", x: d => d}), data);
63+
const ml = applyTransform(Plot.windowX({k: 3, strict: true, anchor: "start", x: d => d}), data);
6464
assert.deepStrictEqual(ml.x.transform(), [1, 2, 3, 4,,, ]);
65-
const mt = applyTransform(Plot.windowX({reduce: "mean", k: 3, anchor: "end", x: d => d}), data);
65+
const mt = applyTransform(Plot.windowX({k: 3, strict: true, anchor: "end", x: d => d}), data);
6666
assert.deepStrictEqual(mt.x.transform(), [,, 1, 2, 3, 4]);
6767
});
6868

69-
it(`windowX({reduce: "mean", k, extend: true}) truncates the window at the start and end`, () => {
69+
it(`windowX(k) truncates the window at the start and end`, () => {
7070
const data = range(6);
71-
const m1 = applyTransform(Plot.windowX({k: 1, extend: true}, {x: d => d}), data);
71+
const m1 = applyTransform(Plot.windowX(1, {x: d => d}), data);
7272
assert.deepStrictEqual(m1.x.transform(), [0, 1, 2, 3, 4, 5]);
73-
const m2 = applyTransform(Plot.windowX({k: 2, extend: true}, {x: d => d}), data);
73+
const m2 = applyTransform(Plot.windowX(2, {x: d => d}), data);
7474
assert.deepStrictEqual(m2.x.transform(), [0.5, 1.5, 2.5, 3.5, 4.5, 5]);
75-
const m3 = applyTransform(Plot.windowX({k: 3, extend: true}, {x: d => d}), data);
75+
const m3 = applyTransform(Plot.windowX(3, {x: d => d}), data);
7676
assert.deepStrictEqual(m3.x.transform(), [0.5, 1, 2, 3, 4, 4.5]);
77-
const m4 = applyTransform(Plot.windowX({k: 4, extend: true}, {x: d => d}), data);
77+
const m4 = applyTransform(Plot.windowX(4, {x: d => d}), data);
7878
assert.deepStrictEqual(m4.x.transform(), [1, 1.5, 2.5, 3.5, 4, 4.5]);
7979
});
8080

81-
it(`windowX({reduce: "mean", k, extend: true, anchor: "start"}) truncates the window at the end`, () => {
81+
it(`windowX({k, anchor: "start"}) truncates the window at the end`, () => {
8282
const data = range(6);
83-
const m1 = applyTransform(Plot.windowX({k: 1, extend: true, anchor: "start"}, {x: d => d}), data);
83+
const m1 = applyTransform(Plot.windowX({k: 1, anchor: "start"}, {x: d => d}), data);
8484
assert.deepStrictEqual(m1.x.transform(), [0, 1, 2, 3, 4, 5]);
85-
const m2 = applyTransform(Plot.windowX({k: 2, extend: true, anchor: "start"}, {x: d => d}), data);
85+
const m2 = applyTransform(Plot.windowX({k: 2, anchor: "start"}, {x: d => d}), data);
8686
assert.deepStrictEqual(m2.x.transform(), [0.5, 1.5, 2.5, 3.5, 4.5, 5]);
87-
const m3 = applyTransform(Plot.windowX({k: 3, extend: true, anchor: "start"}, {x: d => d}), data);
87+
const m3 = applyTransform(Plot.windowX({k: 3, anchor: "start"}, {x: d => d}), data);
8888
assert.deepStrictEqual(m3.x.transform(), [1, 2, 3, 4, 4.5, 5]);
89-
const m4 = applyTransform(Plot.windowX({k: 4, extend: true, anchor: "start"}, {x: d => d}), data);
89+
const m4 = applyTransform(Plot.windowX({k: 4, anchor: "start"}, {x: d => d}), data);
9090
assert.deepStrictEqual(m4.x.transform(), [1.5, 2.5, 3.5, 4, 4.5, 5]);
9191
});
9292

93-
it(`windowX({reduce: "mean", k, extend: true, anchor: "end"}) truncates the window at the start`, () => {
93+
it(`windowX({k, anchor: "end"}) truncates the window at the start`, () => {
9494
const data = range(6);
95-
const m1 = applyTransform(Plot.windowX({k: 1, extend: true, anchor: "end"}, {x: d => d}), data);
95+
const m1 = applyTransform(Plot.windowX({k: 1, anchor: "end"}, {x: d => d}), data);
9696
assert.deepStrictEqual(m1.x.transform(), [0, 1, 2, 3, 4, 5]);
97-
const m2 = applyTransform(Plot.windowX({k: 2, extend: true, anchor: "end"}, {x: d => d}), data);
97+
const m2 = applyTransform(Plot.windowX({k: 2, anchor: "end"}, {x: d => d}), data);
9898
assert.deepStrictEqual(m2.x.transform(), [0, 0.5, 1.5, 2.5, 3.5, 4.5]);
99-
const m3 = applyTransform(Plot.windowX({k: 3, extend: true, anchor: "end"}, {x: d => d}), data);
99+
const m3 = applyTransform(Plot.windowX({k: 3, anchor: "end"}, {x: d => d}), data);
100100
assert.deepStrictEqual(m3.x.transform(), [0, 0.5, 1, 2, 3, 4]);
101-
const m4 = applyTransform(Plot.windowX({k: 4, extend: true, anchor: "end"}, {x: d => d}), data);
101+
const m4 = applyTransform(Plot.windowX({k: 4, anchor: "end"}, {x: d => d}), data);
102102
assert.deepStrictEqual(m4.x.transform(), [0, 0.5, 1, 1.5, 2.5, 3.5]);
103103
});
104104

105-
it(`windowX({reduce: "mean", k, extend: true}) handles k being bigger than the data size`, () => {
105+
it(`windowX(k) handles k being bigger than the data size`, () => {
106106
const data = range(6);
107-
const m3 = applyTransform(Plot.windowX({k: 3, extend: true}, {x: d => d}), data);
107+
const m3 = applyTransform(Plot.windowX(3, {x: d => d}), data);
108108
assert.deepStrictEqual(m3.x.transform(), [0.5, 1, 2, 3, 4, 4.5]);
109-
const m5 = applyTransform(Plot.windowX({k: 5, extend: true}, {x: d => d}), data);
109+
const m5 = applyTransform(Plot.windowX(5, {x: d => d}), data);
110110
assert.deepStrictEqual(m5.x.transform(), [1, 1.5, 2, 3, 3.5, 4]);
111-
const m6 = applyTransform(Plot.windowX({k: 6, extend: true}, {x: d => d}), data);
111+
const m6 = applyTransform(Plot.windowX(6, {x: d => d}), data);
112112
assert.deepStrictEqual(m6.x.transform(), [1.5, 2, 2.5, 3, 3.5, 4]);
113-
const m7 = applyTransform(Plot.windowX({k: 7, extend: true}, {x: d => d}), data);
113+
const m7 = applyTransform(Plot.windowX(7, {x: d => d}), data);
114114
assert.deepStrictEqual(m7.x.transform(), [1.5, 2, 2.5, 2.5, 3, 3.5]);
115-
const m8 = applyTransform(Plot.windowX({k: 8, extend: true}, {x: d => d}), data);
115+
const m8 = applyTransform(Plot.windowX(8, {x: d => d}), data);
116116
assert.deepStrictEqual(m8.x.transform(), [2, 2.5, 2.5, 2.5, 3, 3.5]);
117-
const m9 = applyTransform(Plot.windowX({k: 9, extend: true}, {x: d => d}), data);
117+
const m9 = applyTransform(Plot.windowX(9, {x: d => d}), data);
118118
assert.deepStrictEqual(m9.x.transform(), [2, 2.5, 2.5, 2.5, 2.5, 3]);
119-
const m10 = applyTransform(Plot.windowX({k: 10, extend: true}, {x: d => d}), data);
119+
const m10 = applyTransform(Plot.windowX(10, {x: d => d}), data);
120120
assert.deepStrictEqual(m10.x.transform(), [2.5, 2.5, 2.5, 2.5, 2.5, 3]);
121-
const m11 = applyTransform(Plot.windowX({k: 11, extend: true}, {x: d => d}), data);
121+
const m11 = applyTransform(Plot.windowX(11, {x: d => d}), data);
122122
assert.deepStrictEqual(m11.x.transform(), [2.5, 2.5, 2.5, 2.5, 2.5, 2.5]);
123123
});
124124

125-
it(`windowX({reduce: "max", k}) computes a moving maximum of window size k`, () => {
125+
it(`windowX({reduce: "max", k, strict: true}) computes a moving maximum of window size k`, () => {
126126
const data = [0, 1, 2, 3, 4, 5];
127-
const m1 = applyTransform(Plot.windowX({reduce: "max", k: 1, x: d => d}), data);
127+
const m1 = applyTransform(Plot.windowX({reduce: "max", k: 1, strict: true, x: d => d}), data);
128128
assert.deepStrictEqual(m1.x.transform(), [0, 1, 2, 3, 4, 5]);
129-
const m2 = applyTransform(Plot.windowX({reduce: "max", k: 2, x: d => d}), data);
129+
const m2 = applyTransform(Plot.windowX({reduce: "max", k: 2, strict: true, x: d => d}), data);
130130
assert.deepStrictEqual(m2.x.transform(), [1, 2, 3, 4, 5,, ]);
131-
const m3 = applyTransform(Plot.windowX({reduce: "max", k: 3, x: d => d}), data);
131+
const m3 = applyTransform(Plot.windowX({reduce: "max", k: 3, strict: true, x: d => d}), data);
132132
assert.deepStrictEqual(m3.x.transform(), [, 2, 3, 4, 5,, ]);
133-
const m4 = applyTransform(Plot.windowX({reduce: "max", k: 4, x: d => d}), data);
133+
const m4 = applyTransform(Plot.windowX({reduce: "max", k: 4, strict: true, x: d => d}), data);
134134
assert.deepStrictEqual(m4.x.transform(), [, 3, 4, 5,,, ]);
135135
});
136136

137-
it(`windowX({reduce: "max"}) produces NaN if the current window contains NaN`, () => {
137+
it(`windowX({reduce: "max", k, strict: true}) produces NaN if the current window contains NaN`, () => {
138138
const data = [1, 1, 1, NaN, 1, 1, 1, 1, 1, NaN, NaN, NaN, NaN, 1];
139-
const m3 = applyTransform(Plot.windowX({reduce: "max", k: 3, x: d => d}), data);
139+
const m3 = applyTransform(Plot.windowX({reduce: "max", k: 3, strict: true, x: d => d}), data);
140140
assert.deepStrictEqual(m3.x.transform(), [, 1, NaN, NaN, NaN, 1, 1, 1, NaN, NaN, NaN, NaN, NaN,, ]);
141141
});
142142

143-
it(`windowX({reduce: "max"}) treats null as NaN`, () => {
143+
it(`windowX({reduce: "max", k, strict: true}) treats null as NaN`, () => {
144144
const data = [1, 1, 1, null, 1, 1, 1, 1, 1, null, null, null, null, 1];
145-
const m3 = applyTransform(Plot.windowX({reduce: "max", k: 3, x: d => d}), data);
145+
const m3 = applyTransform(Plot.windowX({reduce: "max", k: 3, strict: true, x: d => d}), data);
146146
assert.deepStrictEqual(m3.x.transform(), [, 1, NaN, NaN, NaN, 1, 1, 1, NaN, NaN, NaN, NaN, NaN,, ]);
147147
});
148148

149-
it(`windowX({reduce: "max", anchor}) respects the given anchor`, () => {
149+
it(`windowX({reduce: "max", k, strict: true, anchor}) respects the given anchor`, () => {
150150
const data = [0, 1, 2, 3, 4, 5];
151-
const mc = applyTransform(Plot.windowX({reduce: "max", k: 3, anchor: "middle", x: d => d}), data);
151+
const mc = applyTransform(Plot.windowX({reduce: "max", k: 3, strict: true, anchor: "middle", x: d => d}), data);
152152
assert.deepStrictEqual(mc.x.transform(), [, 2, 3, 4, 5,, ]);
153-
const ml = applyTransform(Plot.windowX({reduce: "max", k: 3, anchor: "start", x: d => d}), data);
153+
const ml = applyTransform(Plot.windowX({reduce: "max", k: 3, strict: true, anchor: "start", x: d => d}), data);
154154
assert.deepStrictEqual(ml.x.transform(), [2, 3, 4, 5,,, ]);
155-
const mt = applyTransform(Plot.windowX({reduce: "max", k: 3, anchor: "end", x: d => d}), data);
155+
const mt = applyTransform(Plot.windowX({reduce: "max", k: 3, strict: true, anchor: "end", x: d => d}), data);
156156
assert.deepStrictEqual(mt.x.transform(), [,, 2, 3, 4, 5]);
157157
});

0 commit comments

Comments
 (0)