From 1f003720e013375c2bebfd292078b9dbb0490c1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Rivi=C3=A8re?= Date: Mon, 5 Aug 2024 11:04:05 -0400 Subject: [PATCH] fix tree.js and add various tests --- src/transforms/tree.js | 6 +- test/output/arrowTestCustomOrder.svg | 134 +++++++++++++++++++++++++++ test/output/arrowTestDifferenceY.svg | 78 ++++++++++++++++ test/output/arrowTestSort.svg | 50 ++++++++++ test/output/arrowTestTree.svg | 47 ++++++++++ test/plots/arrow.ts | 97 +++++++++++++++++++ 6 files changed, 410 insertions(+), 2 deletions(-) create mode 100644 test/output/arrowTestCustomOrder.svg create mode 100644 test/output/arrowTestDifferenceY.svg create mode 100644 test/output/arrowTestSort.svg create mode 100644 test/output/arrowTestTree.svg diff --git a/src/transforms/tree.js b/src/transforms/tree.js index 067fc03229..ae88a76592 100644 --- a/src/transforms/tree.js +++ b/src/transforms/tree.js @@ -1,6 +1,6 @@ import {stratify, tree} from "d3"; import {ascendingDefined} from "../defined.js"; -import {column, identity, isObject, one, valueof} from "../options.js"; +import {column, identity, isArray, isObject, one, valueof} from "../options.js"; import {basic} from "./basic.js"; export function treeNode({ @@ -40,7 +40,9 @@ export function treeNode({ for (const o of outputs) o[output_values] = o[output_setValues]([]); for (const facet of facets) { const treeFacet = []; - const root = rootof(facet.filter((i) => P[i] != null)).each((node) => (node.data = data[node.data])); + const root = rootof(facet.filter((i) => P[i] != null)).each( + isArray(data) ? (node) => (node.data = data[node.data]) : (node) => (node.data = data.get(node.data)) + ); if (treeSort != null) root.sort(treeSort); layout(root); for (const node of root.descendants()) { diff --git a/test/output/arrowTestCustomOrder.svg b/test/output/arrowTestCustomOrder.svg new file mode 100644 index 0000000000..0729686f1d --- /dev/null +++ b/test/output/arrowTestCustomOrder.svg @@ -0,0 +1,134 @@ + + + + + + 0 + 2 + 4 + 6 + 8 + 10 + 12 + 14 + 16 + 18 + 20 + 22 + + + ↑ Annual revenue (billions, adj.) + + + + 1975 + 1980 + 1985 + 1990 + 1995 + 2000 + 2005 + 2010 + 2015 + + + 8 - Track + Tape + CD + Disc + CD Single + Disc + Cassette + Tape + Cassette Single + Tape + DVD Audio + Other + Download Album + Download + Download Music Video + Download + Download Single + Download + Kiosk + Other + LP/EP + Vinyl + Limited Tier Paid Subscription + Streaming + Music Video (Physical) + Other + On-Demand Streaming (Ad-Supported) + Streaming + Other Ad-Supported Streaming + Streaming + Other Digital + Download + Other Tapes + Tape + Paid Subscription + Streaming + Ringtones & Ringbacks + Download + SACD + Disc + SoundExchange Distributions + Streaming + Synchronization + Other + Vinyl Single + Vinyl + + + + + \ No newline at end of file diff --git a/test/output/arrowTestDifferenceY.svg b/test/output/arrowTestDifferenceY.svg new file mode 100644 index 0000000000..0ae2fbf577 --- /dev/null +++ b/test/output/arrowTestDifferenceY.svg @@ -0,0 +1,78 @@ + + + + + 1.0 + 1.2 + 1.4 + 1.6 + 1.8 + 2.0 + 2.2 + 2.4 + 2.6 + 2.8 + + + ↑ Close + + + + 2014 + 2015 + 2016 + 2017 + 2018 + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/output/arrowTestSort.svg b/test/output/arrowTestSort.svg new file mode 100644 index 0000000000..2dd19e56c0 --- /dev/null +++ b/test/output/arrowTestSort.svg @@ -0,0 +1,50 @@ + + + + + 0 + 10 + 20 + 30 + 40 + 50 + 60 + 70 + 80 + 90 + 100 + + + age → + + + + + + + \ No newline at end of file diff --git a/test/output/arrowTestTree.svg b/test/output/arrowTestTree.svg new file mode 100644 index 0000000000..2ad47dc9c1 --- /dev/null +++ b/test/output/arrowTestTree.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + /Chaos + /Chaos/Eros + /Chaos/Erebus + /Chaos/Tartarus + /Chaos/Gaia + /Chaos/Gaia/Mountains + /Chaos/Gaia/Pontus + /Chaos/Gaia/Uranus + + + Eros/Chaos/Eros + Erebus/Chaos/Erebus + Tartarus/Chaos/Tartarus + Mountains/Chaos/Gaia/Mountains + Pontus/Chaos/Gaia/Pontus + Uranus/Chaos/Gaia/Uranus + + + Chaos/Chaos + Gaia/Chaos/Gaia + + \ No newline at end of file diff --git a/test/plots/arrow.ts b/test/plots/arrow.ts index 5699e765fc..97b3c98e6f 100644 --- a/test/plots/arrow.ts +++ b/test/plots/arrow.ts @@ -50,3 +50,100 @@ export async function arrowTestGroup() { const data = Arrow.tableFromArrays({category, vector}); return Plot.barY(data, Plot.groupX({y: "count"}, {x: "vector", fill: "category"})).plot({marginLeft: 60}); } + +/** + * An arrow table dataset supports sorting with a comparator. + */ +export async function arrowTestSort() { + const data = Arrow.tableFromArrays({ + id: [1, 2, 3], + name: ["Alice", "Bob", "Charlie"], + age: [35, 25, 45] + }); + return Plot.barX(data, {x: "age", fill: "name", sort: (a: {age: number}, b: {age: number}) => b.age - a.age}).plot(); +} + +/** + * An arrow table dataset supports accessing the node's datum. + */ +export async function arrowTestTree() { + const gods = Arrow.tableFromArrays({ + branch: `Chaos Gaia Mountains +Chaos Gaia Pontus +Chaos Gaia Uranus +Chaos Eros +Chaos Erebus +Chaos Tartarus` + .split("\n") + .map((d) => d.replace(/\s+/g, "/")) + }); + return Plot.plot({ + axis: null, + insetLeft: 35, + insetTop: 20, + insetBottom: 20, + insetRight: 120, + marks: [Plot.tree(gods, {path: "branch", fill: (d) => d?.branch})] + }); +} + +/** + * An arrow table dataset supports Plot.find. + */ +export async function arrowTestDifferenceY() { + const stocks = Arrow.tableFromJSON(await readStocks()); + return Plot.plot({ + marks: [ + Plot.differenceY( + stocks, + Plot.normalizeY( + Plot.groupX( + {y1: Plot.find((d) => d.Symbol === "GOOG"), y2: Plot.find((d) => d.Symbol === "AAPL")}, + {x: "Date", y: "Close", tip: true} + ) + ) + ) + ] + }); +} + +async function readStocks(start = 0, end = Infinity) { + return ( + await Promise.all( + ["AAPL", "GOOG"].map((symbol) => + d3.csv(`data/${symbol.toLowerCase()}.csv`, (d, i) => + start <= i && i < end ? ((d.Symbol = symbol), d3.autoType(d)) : null + ) + ) + ) + ).flat(); +} + +/** + * An arrow table dataset supports stack custom order. + */ +export async function arrowTestCustomOrder() { + const riaa = Arrow.tableFromJSON(await d3.csv("data/riaa-us-revenue.csv", d3.autoType)); + return Plot.plot({ + y: { + grid: true, + label: "Annual revenue (billions, adj.)", + transform: (d) => d / 1000 + }, + marks: [ + Plot.areaY( + riaa, + Plot.stackY({ + x: "year", + y: "revenue", + z: "format", + order: (a, b) => d3.ascending(a.group, b.group) || d3.descending(a.revenue, b.revenue), + fill: "group", + stroke: "white", + title: (d) => `${d.format}\n${d.group}` + }) + ), + Plot.ruleY([0]) + ] + }); +}