Skip to content

Commit 3d86d4a

Browse files
committed
transforms *almost* work now
1 parent a68f332 commit 3d86d4a

File tree

4 files changed

+93
-2
lines changed

4 files changed

+93
-2
lines changed

src/plot.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {Context, create} from "./context.js";
55
import {defined} from "./defined.js";
66
import {Dimensions} from "./dimensions.js";
77
import {Legends, exposeLegends} from "./legends.js";
8-
import {arrayify, isDomainSort, isScaleOptions, keyword, map, maybeNamed, range, second, where, yes} from "./options.js";
8+
import {arrayify, isDomainSort, isScaleOptions, keyword, map, maybeNamed, range, second, valueof, where, yes} from "./options.js";
99
import {Scales, ScaleFunctions, autoScaleRange, exposeScales, coerceNumbers} from "./scales.js";
1010
import {position, registry as scaleRegistry} from "./scales/index.js";
1111
import {inferDomain} from "./scales/quantitative.js";
@@ -366,7 +366,29 @@ export class Mark {
366366
initialize(facets, facetChannels) {
367367
let data = arrayify(this.data);
368368
if (facets === undefined && data != null) facets = [range(data)];
369-
if (this.transform != null) ({facets, data} = this.transform(data, facets)), data = arrayify(data);
369+
if (this.transform != null) {
370+
if (this.channels.time) {
371+
// Split facets by keyframe, transform
372+
const {value} = this.channels.time;
373+
const T = valueof(data, value);
374+
const times = [...new Set(T)];
375+
const n = facets.length;
376+
facets = facets.flatMap(facet => times.map(time => facet.filter(i => T[i] === time)));
377+
({data, facets} = this.transform(data, facets));
378+
379+
// and reassemble
380+
const TT = []; // keyframes for the new indices
381+
this.channels.time.value = { transform: () => TT};
382+
for (let i = 0; i < facets.length; ++i) {
383+
const time = times[i % times.length];
384+
for (const j of facets[i]) TT[j] = time;
385+
}
386+
facets = Array.from({length: n}, (_, i) => facets.filter((_, j) => j % n === i).flat());
387+
} else {
388+
({facets, data} = this.transform(data, facets));
389+
}
390+
data = arrayify(data);
391+
}
370392
const channels = Channels(this.channels, data);
371393
if (this.sort != null) channelDomain(channels, facetChannels, data, this.sort);
372394
return {data, facets, channels};

test/plots/gapminder-box.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import * as Plot from "@observablehq/plot";
2+
import * as d3 from "d3";
3+
4+
export default async function () {
5+
const gapminder = await d3.tsv("data/gapminder.tsv", d3.autoType);
6+
return Plot.plot({
7+
marginLeft: 70,
8+
inset: 10,
9+
grid: true,
10+
// facet:{ data: gapminder, y: "continent"},
11+
x: {
12+
type: "log",
13+
transform: d => Math.pow(10, d)
14+
},
15+
marks: [
16+
Plot.boxX(gapminder, {
17+
x: d => Math.log10(d.gdpPercap),
18+
sort: null,
19+
y: "continent",
20+
stroke: "continent",
21+
strokeWidth: 0.5,
22+
time: "year",
23+
timeFilter: "lte"
24+
})
25+
]
26+
});
27+
}

test/plots/gapminder-dodge.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import * as Plot from "@observablehq/plot";
2+
import * as d3 from "d3";
3+
4+
export default async function () {
5+
let gapminder = await d3.tsv("data/gapminder.tsv", d3.autoType);
6+
gapminder = gapminder.filter(d => d.continent === "Europe");
7+
return Plot.plot({
8+
height: 400,
9+
marginLeft: 75,
10+
inset: 10,
11+
grid: true,
12+
x: {
13+
type: "log",
14+
transform: d => Math.pow(10, d)
15+
},
16+
marks: [
17+
Plot.dot(gapminder, Plot.dodgeY({
18+
x: d => Math.log10(d.gdpPercap),
19+
z: d => `${d.year} & ${d.continent}`,
20+
r: "pop",
21+
stroke: "continent",
22+
sort: null
23+
// time: "year"
24+
})),
25+
Plot.dot(gapminder, Plot.dodgeY({
26+
x: d => Math.log10(d.gdpPercap),
27+
z: d => `${d.year} & ${d.continent}`,
28+
r: "pop",
29+
fill: "continent",
30+
sort: null,
31+
fillOpacity: 0.3,
32+
strokeWidth: 0.5,
33+
time: "year"
34+
})),
35+
void Plot.text(gapminder, {frameAnchor: "top-left", text: "year", time: "year"})
36+
// Plot.text(gapminder, Plot.selectFirst({frameAnchor: "top-left", text: "year", time: "year"}))
37+
38+
]
39+
});
40+
}

test/plots/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ export {default as frameCorners} from "./frame-corners.js";
7676
export {default as fruitSales} from "./fruit-sales.js";
7777
export {default as fruitSalesDate} from "./fruit-sales-date.js";
7878
export {default as gapminder} from "./gapminder.js";
79+
export {default as gapminderBox} from "./gapminder-box.js";
80+
export {default as gapminderDodge} from "./gapminder-dodge.js";
7981
export {default as gapminderContinent} from "./gapminder-continent.js";
8082
export {default as gistempAnomaly} from "./gistemp-anomaly.js";
8183
export {default as gistempAnomalyMoving} from "./gistemp-anomaly-moving.js";

0 commit comments

Comments
 (0)