diff --git a/src/transforms/bin.js b/src/transforms/bin.js index 02321a3345..e051ac98a1 100644 --- a/src/transforms/bin.js +++ b/src/transforms/bin.js @@ -67,22 +67,24 @@ export function bin(outputs = {fill: "count"}, options = {}) { return binn(x, y, null, null, outputs, maybeInsetX(maybeInsetY(options))); } -function maybeDenseInterval(bin, k, options = {}) { - if (options?.interval == null) return options; +function maybeDenseInterval(x, options) { + options = withTip(options, x); + if (options.interval == null) return options; const {reduce = reduceFirst} = options; - const outputs = {filter: null}; - if (options[k] != null) outputs[k] = reduce; - if (options[`${k}1`] != null) outputs[`${k}1`] = reduce; - if (options[`${k}2`] != null) outputs[`${k}2`] = reduce; - return bin(outputs, options); + const outputs = {filter: null, [x]: `${x}1`}; + const y = x === "x" ? "y" : "x"; + if (options[y] != null) outputs[y] = reduce; + if (options[`${y}1`] != null) outputs[`${y}1`] = reduce; + if (options[`${y}2`] != null) outputs[`${y}2`] = reduce; + return (x === "x" ? binX : binY)(outputs, options); } export function maybeDenseIntervalX(options = {}) { - return maybeDenseInterval(binX, "y", withTip(options, "x")); + return maybeDenseInterval("x", options); } export function maybeDenseIntervalY(options = {}) { - return maybeDenseInterval(binY, "x", withTip(options, "y")); + return maybeDenseInterval("y", options); } function binn( diff --git a/test/output/aaplInterval.svg b/test/output/aaplInterval.svg index 8287a1e7fd..5e76b5099f 100644 --- a/test/output/aaplInterval.svg +++ b/test/output/aaplInterval.svg @@ -14,38 +14,38 @@ } - 56 - 58 - 60 - 62 - 64 - 66 - 68 - 70 - 72 + 56 + 58 + 60 + 62 + 64 + 66 + 68 + 70 + 72 - Jun2013 - Jul - Aug - Sep + Jun2013 + Jul + Aug + Sep diff --git a/test/output/availability.svg b/test/output/availability.svg index 2727bef159..28db7454f8 100644 --- a/test/output/availability.svg +++ b/test/output/availability.svg @@ -18,7 +18,7 @@ - + @@ -26,27 +26,27 @@ 1 2 3 - 4 + 4 5 ↑ value - Jan2020 - Apr - Jul - Oct - Jan2021 - Apr + Jan2020 + Apr + Jul + Oct + Jan2021 + Apr diff --git a/test/output/downloads.svg b/test/output/downloads.svg index 4b0fb6d555..ab1a534643 100644 --- a/test/output/downloads.svg +++ b/test/output/downloads.svg @@ -15,50 +15,50 @@ 0 - 2 + 2 4 6 - 8 + 8 10 12 - 14 + 14 16 18 - 20 + 20 22 - 24 + 24 ↑ downloads - 2018 - 2019 - 2020 - 2021 - 2022 + 2018 + 2019 + 2020 + 2021 + 2022 diff --git a/test/output/integerIntervalArea.html b/test/output/integerIntervalArea.html index d7073c9069..382bcee5c1 100644 --- a/test/output/integerIntervalArea.html +++ b/test/output/integerIntervalArea.html @@ -70,28 +70,30 @@ ↑ y - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 x → diff --git a/test/output/lineInterval.svg b/test/output/lineInterval.svg new file mode 100644 index 0000000000..c08693f3bc --- /dev/null +++ b/test/output/lineInterval.svg @@ -0,0 +1,127 @@ + + + + + 0 + 1 + 2 + 3 + 4 + 5 + + + + 2Jan + 4 + 6 + 8 + 10 + 12 + 14 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/plots/index.ts b/test/plots/index.ts index 3c019e678f..3bcc3426d4 100644 --- a/test/plots/index.ts +++ b/test/plots/index.ts @@ -157,6 +157,7 @@ export * from "./likert-survey.js"; export * from "./linear-regression-cars.js"; export * from "./linear-regression-mtcars.js"; export * from "./linear-regression-penguins.js"; +export * from "./line-interval.js"; export * from "./log-degenerate.js"; export * from "./log-tick-format.js"; export * from "./long-labels.js"; diff --git a/test/plots/line-interval.ts b/test/plots/line-interval.ts new file mode 100644 index 0000000000..628ac15d0d --- /dev/null +++ b/test/plots/line-interval.ts @@ -0,0 +1,29 @@ +import * as Plot from "@observablehq/plot"; +import * as d3 from "d3"; + +export async function lineInterval() { + const random = d3.randomLcg(42); + const logins = ["Alice", "Bob", "Carol", "Dave", "Eve"]; + const dates = d3.utcDays(new Date("2024-01-01"), new Date("2024-01-15")); + const activity = dates.flatMap((date) => logins.filter(() => random() > 0.15).map((login) => ({date, login}))); + return Plot.plot({ + height: 200, + marks: [ + Plot.ruleY([0]), + Plot.areaY(activity, { + x: "date", + interval: "day", + fill: "login", + order: "-sum", + fillOpacity: 0.3, + y: 1, + curve: "catmull-rom" + }), + Plot.lineY( + activity, + Plot.stackY({x: "date", interval: "day", stroke: "login", order: "-sum", curve: "catmull-rom"}) + ), + Plot.dot(activity, Plot.stackY({x: "date", interval: "day", z: "login", fill: "login", order: "-sum"})) + ] + }); +}