From b3446cea816a3f157a641f8e1fb345361f6bd03f Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Thu, 22 Jun 2023 10:26:45 -0700 Subject: [PATCH] fix non-faceted pointer --- src/options.js | 5 + src/plot.js | 6 +- src/transforms/window.js | 20 +- test/output/pointerNonFaceted.svg | 2623 +++++++++++++++++++++++++++++ test/plots/pointer.ts | 11 + 5 files changed, 2651 insertions(+), 14 deletions(-) create mode 100644 test/output/pointerNonFaceted.svg diff --git a/src/options.js b/src/options.js index 0a1603eaa7..f70a118ef8 100644 --- a/src/options.js +++ b/src/options.js @@ -231,6 +231,11 @@ export function taker(f) { return f.length === 1 ? (index, values) => f(take(values, index)) : f; } +// Uses subarray if available, and otherwise slice. +export function subarray(I, i, j) { + return I.subarray ? I.subarray(i, j) : I.slice(i, j); +} + // Based on InternMap (d3.group). export function keyof(value) { return value !== null && typeof value === "object" ? value.valueOf() : value; diff --git a/src/plot.js b/src/plot.js index 6862ebf42d..2d3795fc17 100644 --- a/src/plot.js +++ b/src/plot.js @@ -9,7 +9,8 @@ import {Mark} from "./mark.js"; import {axisFx, axisFy, axisX, axisY, gridFx, gridFy, gridX, gridY} from "./marks/axis.js"; import {frame} from "./marks/frame.js"; import {tip} from "./marks/tip.js"; -import {arrayify, isColor, isIterable, isNone, isScaleOptions, map, yes, maybeIntervalTransform} from "./options.js"; +import {isColor, isIterable, isNone, isScaleOptions} from "./options.js"; +import {arrayify, map, yes, maybeIntervalTransform, subarray} from "./options.js"; import {createProjection, getGeometryChannels, hasProjection} from "./projection.js"; import {createScales, createScaleFunctions, autoScaleRange, exposeScales} from "./scales.js"; import {innerDimensions, outerDimensions} from "./scales.js"; @@ -298,7 +299,8 @@ export function plot(options = {}) { index = indexes[faceted ? f.i : 0]; index = mark.filter(index, channels, values); if (index.length === 0) continue; - if (faceted) (index.fx = f.x), (index.fy = f.y), (index.fi = f.i); + if (!faceted && index === indexes[0]) index = subarray(index); // copy before assigning fx, fy, fi + (index.fx = f.x), (index.fy = f.y), (index.fi = f.i); } const node = mark.render(index, scales, values, subdimensions, context); if (node == null) continue; diff --git a/src/transforms/window.js b/src/transforms/window.js index 7e4c7096a3..a9a918927a 100644 --- a/src/transforms/window.js +++ b/src/transforms/window.js @@ -1,6 +1,6 @@ -import {deviation, max, min, median, mode, variance} from "d3"; +import {deviation, max, median, min, mode, variance} from "d3"; import {defined} from "../defined.js"; -import {percentile, taker} from "../options.js"; +import {percentile, subarray, taker} from "../options.js"; import {warn} from "../warnings.js"; import {mapX, mapY} from "./map.js"; @@ -83,10 +83,6 @@ function maybeReduce(reduce = "mean") { return reduceArray(taker(reduce)); } -function slice(I, i, j) { - return I.subarray ? I.subarray(i, j) : I.slice(i, j); -} - // Note that the subarray may include NaN in the non-strict case; we expect the // function f to handle that itself (e.g., by filtering as needed). The D3 // reducers (e.g., min, max, mean, median) do, and it’s faster to avoid @@ -101,7 +97,7 @@ function reduceAccessor(f) { for (let i = 0; i < k - 1; ++i) if (isNaN(v(i))) ++nans; for (let i = 0, n = I.length - k + 1; i < n; ++i) { if (isNaN(v(i + k - 1))) ++nans; - T[I[i + s]] = nans === 0 ? f(slice(I, i, i + k), v) : NaN; + T[I[i + s]] = nans === 0 ? f(subarray(I, i, i + k), v) : NaN; if (isNaN(v(i))) --nans; } } @@ -110,10 +106,10 @@ function reduceAccessor(f) { mapIndex(I, S, T) { const v = (i) => (S[i] == null ? NaN : +S[i]); for (let i = -s; i < 0; ++i) { - T[I[i + s]] = f(slice(I, 0, i + k), v); + T[I[i + s]] = f(subarray(I, 0, i + k), v); } for (let i = 0, n = I.length - s; i < n; ++i) { - T[I[i + s]] = f(slice(I, i, i + k), v); + T[I[i + s]] = f(subarray(I, i, i + k), v); } } }; @@ -128,7 +124,7 @@ function reduceArray(f) { for (let i = 0; i < k - 1; ++i) count += defined(S[I[i]]); for (let i = 0, n = I.length - k + 1; i < n; ++i) { count += defined(S[I[i + k - 1]]); - if (count === k) T[I[i + s]] = f(slice(I, i, i + k), S); + if (count === k) T[I[i + s]] = f(subarray(I, i, i + k), S); count -= defined(S[I[i]]); } } @@ -136,10 +132,10 @@ function reduceArray(f) { : { mapIndex(I, S, T) { for (let i = -s; i < 0; ++i) { - T[I[i + s]] = f(slice(I, 0, i + k), S); + T[I[i + s]] = f(subarray(I, 0, i + k), S); } for (let i = 0, n = I.length - s; i < n; ++i) { - T[I[i + s]] = f(slice(I, i, i + k), S); + T[I[i + s]] = f(subarray(I, i, i + k), S); } } }; diff --git a/test/output/pointerNonFaceted.svg b/test/output/pointerNonFaceted.svg new file mode 100644 index 0000000000..e3c7e45bdd --- /dev/null +++ b/test/output/pointerNonFaceted.svg @@ -0,0 +1,2623 @@ + + + + + false + + + true + + + + + + + + + + + + + + + + + + + + + + + + + 60 + 80 + 100 + 120 + 140 + 160 + 180 + + + 60 + 80 + 100 + 120 + 140 + 160 + 180 + + + + ↑ Close + + + + + + + + + + + + + 2014 + 2015 + 2016 + 2017 + 2018 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/plots/pointer.ts b/test/plots/pointer.ts index d6ea70904a..1e9df45067 100644 --- a/test/plots/pointer.ts +++ b/test/plots/pointer.ts @@ -34,3 +34,14 @@ export async function pointerViewof() { plot.oninput = oninput; // update during interaction return html`
${plot}${textarea}
`; } + +export async function pointerNonFaceted() { + const aapl = await d3.csv("data/aapl.csv", d3.autoType); + return Plot.plot({ + marks: [ + Plot.lineY(aapl, {x: "Date", y: "Close", fy: (d) => d.Close % 2 === 0}), + Plot.ruleX(aapl, {x: "Date", strokeOpacity: 0.1}), + Plot.ruleX(aapl, Plot.pointerX({x: "Date", stroke: "red"})) + ] + }); +}