Skip to content

Commit 9508295

Browse files
committed
no shortcuts!
1 parent 8ece034 commit 9508295

File tree

7 files changed

+419
-344
lines changed

7 files changed

+419
-344
lines changed

src/transforms/bin.js

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1-
import {bin as binner, extent, thresholdFreedmanDiaconis, thresholdScott, thresholdSturges, utcTickInterval} from "d3";
1+
import {
2+
bin as binner,
3+
extent,
4+
sum,
5+
thresholdFreedmanDiaconis,
6+
thresholdScott,
7+
thresholdSturges,
8+
utcTickInterval
9+
} from "d3";
210
import {
311
valueof,
4-
range,
512
identity,
613
maybeColumn,
714
maybeTuple,
@@ -29,7 +36,7 @@ import {
2936
} from "./group.js";
3037
import {maybeInsetX, maybeInsetY} from "./inset.js";
3138
import {maybeInterval} from "./interval.js";
32-
import {originals} from "../facet.js";
39+
import {expander, getter, originals} from "../facet.js";
3340

3441
/**
3542
* ```js
@@ -173,35 +180,42 @@ function binn(
173180
const GZ = Z && setGZ([]);
174181
const GF = F && setGF([]);
175182
const GS = S && setGS([]);
176-
const BX = bx ? bx(data) : [[, , (I) => I]];
177-
const BY = by ? by(data) : [[, , (I) => I]];
183+
const BX = bx ? bx(data, facets) : [[, , (I) => I]];
184+
const BY = by ? by(data, facets) : [[, , (I) => I]];
178185
const BX1 = bx && setBX1([]);
179186
const BX2 = bx && setBX2([]);
180187
const BY1 = by && setBY1([]);
181188
const BY2 = by && setBY2([]);
189+
190+
const eG = getter(facets, G);
191+
const eK = getter(facets, K);
192+
const gZ = getter(facets, Z);
193+
const gF = getter(facets, F);
194+
const gS = getter(facets, S);
195+
182196
let i = 0;
183197
for (const o of outputs) o.initialize(data);
184198
if (sort) sort.initialize(data);
185199
if (filter) filter.initialize(data);
186-
for (const facet of originals(facets)) {
200+
for (const facet of facets) {
187201
const groupFacet = [];
188202
for (const o of outputs) o.scope("facet", facet);
189203
if (sort) sort.scope("facet", facet);
190204
if (filter) filter.scope("facet", facet);
191-
for (const [f, I] of maybeGroup(facet, G)) {
192-
for (const [k, g] of maybeGroup(I, K)) {
205+
for (const [f, I] of maybeGroup(facet, eG)) {
206+
for (const [k, g] of maybeGroup(I, eK)) {
193207
for (const [x1, x2, fx] of BX) {
194208
const bb = fx(g);
195209
for (const [y1, y2, fy] of BY) {
196210
const extent = {x1, x2, y1, y2};
197211
const b = fy(bb);
198212
if (filter && !filter.reduce(b, extent)) continue;
199213
groupFacet.push(i++);
200-
groupData.push(reduceData.reduce(b, data, extent));
214+
groupData.push(reduceData.reduce(originals(b), data, extent));
201215
if (K) GK.push(k);
202-
if (Z) GZ.push(G === Z ? f : Z[b[0]]);
203-
if (F) GF.push(G === F ? f : F[b[0]]);
204-
if (S) GS.push(G === S ? f : S[b[0]]);
216+
if (Z) GZ.push(G === Z ? f : gZ(b[0]));
217+
if (F) GF.push(G === F ? f : gF(b[0]));
218+
if (S) GS.push(G === S ? f : gS(b[0]));
205219
if (BX1) BX1.push(x1), BX2.push(x2);
206220
if (BY1) BY1.push(y1), BY2.push(y2);
207221
for (const o of outputs) o.reduce(b, extent);
@@ -249,8 +263,8 @@ function maybeBinValueTuple(options) {
249263
function maybeBin(options) {
250264
if (options == null) return;
251265
const {value, cumulative, domain = extent, thresholds} = options;
252-
const bin = (data) => {
253-
let V = valueof(data, value, Array); // d3.bin prefers Array input
266+
const bin = (data, facets) => {
267+
let V = expander(facets, valueof(data, value, Array)); // d3.bin prefers Array input
254268
const bin = binner().value((i) => V[i]);
255269
if (isTemporal(V) || isTimeThresholds(thresholds)) {
256270
V = V.map(coerceDate);
@@ -280,7 +294,7 @@ function maybeBin(options) {
280294
}
281295
bin.thresholds(t).domain(d);
282296
}
283-
let bins = bin(range(data)).map(binset);
297+
let bins = bin(union(facets)).map(binset);
284298
if (cumulative) bins = (cumulative < 0 ? bins.reverse() : bins).map(bincumset);
285299
return bins.map(binfilter);
286300
};
@@ -366,3 +380,10 @@ function binfilter([{x0, x1}, set]) {
366380
function binempty() {
367381
return new Uint32Array(0);
368382
}
383+
384+
function union(facets) {
385+
const U = new Uint32Array(sum(facets, (d) => d.length));
386+
let c = 0;
387+
for (const facet of facets) for (const i of facet) U[c++] = i;
388+
return U;
389+
}

src/transforms/group.js

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import {
3131
percentile
3232
} from "../options.js";
3333
import {basic} from "./basic.js";
34-
import {originals} from "../facet.js";
34+
import {getter, originals} from "../facet.js";
3535

3636
/**
3737
* ```js
@@ -159,26 +159,34 @@ function groupn(
159159
const GZ = Z && setGZ([]);
160160
const GF = F && setGF([]);
161161
const GS = S && setGS([]);
162+
163+
const eG = getter(facets, G);
164+
const eX = getter(facets, X);
165+
const eY = getter(facets, Y);
166+
const gZ = getter(facets, Z);
167+
const gF = getter(facets, F);
168+
const gS = getter(facets, S);
169+
162170
let i = 0;
163171
for (const o of outputs) o.initialize(data);
164172
if (sort) sort.initialize(data);
165173
if (filter) filter.initialize(data);
166-
for (const facet of originals(facets)) {
174+
for (const facet of facets) {
167175
const groupFacet = [];
168176
for (const o of outputs) o.scope("facet", facet);
169177
if (sort) sort.scope("facet", facet);
170178
if (filter) filter.scope("facet", facet);
171-
for (const [f, I] of maybeGroup(facet, G)) {
172-
for (const [y, gg] of maybeGroup(I, Y)) {
173-
for (const [x, g] of maybeGroup(gg, X)) {
179+
for (const [f, I] of maybeGroup(facet, eG)) {
180+
for (const [y, gg] of maybeGroup(I, eY)) {
181+
for (const [x, g] of maybeGroup(gg, eX)) {
174182
if (filter && !filter.reduce(g)) continue;
175183
groupFacet.push(i++);
176-
groupData.push(reduceData.reduce(g, data));
184+
groupData.push(reduceData.reduce(originals(g), data));
177185
if (X) GX.push(x);
178186
if (Y) GY.push(y);
179-
if (Z) GZ.push(G === Z ? f : Z[g[0]]);
180-
if (F) GF.push(G === F ? f : F[g[0]]);
181-
if (S) GS.push(G === S ? f : S[g[0]]);
187+
if (Z) GZ.push(G === Z ? f : gZ(g[0]));
188+
if (F) GF.push(G === F ? f : gF(g[0]));
189+
if (S) GS.push(G === S ? f : gS(g[0]));
182190
for (const o of outputs) o.reduce(g);
183191
if (sort) sort.reduce(g);
184192
}
@@ -257,10 +265,10 @@ export function maybeEvaluator(name, reduce, inputs) {
257265
};
258266
}
259267

260-
export function maybeGroup(I, X) {
261-
return X
268+
export function maybeGroup(I, x) {
269+
return x
262270
? sort(
263-
grouper(I, (i) => X[i]),
271+
grouper(I, (i) => x(i)),
264272
first
265273
)
266274
: [[, I]];

src/transforms/hexbin.js

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {sqrt3} from "../symbols.js";
33
import {identity, isNoneish, number, valueof} from "../options.js";
44
import {initializer} from "./basic.js";
55
import {hasOutput, maybeGroup, maybeOutputs, maybeSubgroup} from "./group.js";
6-
import {originals} from "../facet.js";
6+
import {getter} from "../facet.js";
77

88
// We don’t want the hexagons to align with the edges of the plot frame, as that
99
// would cause extreme x-values (the upper bound of the default x-scale domain)
@@ -101,19 +101,28 @@ export function hexbin(outputs = {fill: "count"}, options = {}) {
101101
const BX = [];
102102
const BY = [];
103103
let i = -1;
104+
105+
// Mind reindexed facets
106+
const eG = getter(facets, G);
107+
const gX = getter(facets, X);
108+
const gY = getter(facets, Y);
109+
const gZ = getter(facets, Z);
110+
const gF = getter(facets, F);
111+
const gS = getter(facets, S);
112+
const gQ = getter(facets, Q);
104113
for (const o of outputs) o.initialize(data);
105-
for (const facet of originals(facets)) {
114+
for (const facet of facets) {
106115
const binFacet = [];
107116
for (const o of outputs) o.scope("facet", facet);
108-
for (const [f, I] of maybeGroup(facet, G)) {
109-
for (const bin of hbin(I, X, Y, binWidth)) {
117+
for (const [f, I] of maybeGroup(facet, eG)) {
118+
for (const bin of hbin(I, gX, gY, binWidth)) {
110119
binFacet.push(++i);
111120
BX.push(bin.x);
112121
BY.push(bin.y);
113-
if (Z) GZ.push(G === Z ? f : Z[bin[0]]);
114-
if (F) GF.push(G === F ? f : F[bin[0]]);
115-
if (S) GS.push(G === S ? f : S[bin[0]]);
116-
if (Q) GQ.push(G === Q ? f : Q[bin[0]]);
122+
if (Z) GZ.push(G === Z ? f : gZ(bin[0]));
123+
if (F) GF.push(G === F ? f : gF(bin[0]));
124+
if (S) GS.push(G === S ? f : gS(bin[0]));
125+
if (Q) GQ.push(G === Q ? f : gQ(bin[0]));
117126
for (const o of outputs) o.reduce(bin);
118127
}
119128
}
@@ -140,12 +149,12 @@ export function hexbin(outputs = {fill: "count"}, options = {}) {
140149
});
141150
}
142151

143-
function hbin(I, X, Y, dx) {
152+
function hbin(I, x, y, dx) {
144153
const dy = dx * (1.5 / sqrt3);
145154
const bins = new Map();
146155
for (const i of I) {
147-
let px = X[i],
148-
py = Y[i];
156+
let px = x(i),
157+
py = y(i);
149158
if (isNaN(px) || isNaN(py)) continue;
150159
let pj = Math.round((py = (py - oy) / dy)),
151160
pi = Math.round((px = (px - ox) / dx - (pj & 1) / 2)),

src/transforms/tree.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {stratify, tree} from "d3";
22
import {ascendingDefined} from "../defined.js";
33
import {column, identity, isObject, one, valueof} from "../options.js";
44
import {basic} from "./basic.js";
5-
import {originals} from "../facet.js";
5+
import {getter} from "../facet.js";
66

77
/**
88
* Based on the tree options described above, populates the **x** and **y**
@@ -51,20 +51,20 @@ export function treeNode(options = {}) {
5151
y: Y,
5252
frameAnchor,
5353
...basic(remainingOptions, (data, facets) => {
54-
const P = normalize(valueof(data, path));
54+
const gP = getter(facets, normalize(valueof(data, path)));
5555
const X = setX([]);
5656
const Y = setY([]);
5757
let treeIndex = -1;
5858
const treeData = [];
5959
const treeFacets = [];
60-
const rootof = stratify().path((i) => P[i]);
60+
const rootof = stratify().path(gP);
6161
const layout = treeLayout();
6262
if (layout.nodeSize) layout.nodeSize([1, 1]);
6363
if (layout.separation && treeSeparation !== undefined) layout.separation(treeSeparation ?? one);
6464
for (const o of outputs) o[output_values] = o[output_setValues]([]);
6565
for (const facet of facets) {
6666
const treeFacet = [];
67-
const root = rootof(facet.filter((i) => P[i] != null)).each((node) => (node.data = data[node.data]));
67+
const root = rootof(facet.filter((i) => gP(i) != null)).each((node) => (node.data = data[node.data]));
6868
if (treeSort != null) root.sort(treeSort);
6969
layout(root);
7070
for (const node of root.descendants()) {
@@ -156,7 +156,7 @@ export function treeLink(options = {}) {
156156
if (layout.nodeSize) layout.nodeSize([1, 1]);
157157
if (layout.separation && treeSeparation !== undefined) layout.separation(treeSeparation ?? one);
158158
for (const o of outputs) o[output_values] = o[output_setValues]([]);
159-
for (const facet of originals(facets)) {
159+
for (const facet of facets) {
160160
const treeFacet = [];
161161
const root = rootof(facet.filter((i) => P[i] != null)).each((node) => (node.data = data[node.data]));
162162
if (treeSort != null) root.sort(treeSort);

0 commit comments

Comments
 (0)