Skip to content

Commit 4bc2405

Browse files
committed
exclusiveFacets
1 parent 6adee12 commit 4bc2405

File tree

2 files changed

+41
-0
lines changed

2 files changed

+41
-0
lines changed

src/transforms/exclusiveFacets.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import {slice} from "../options.js";
2+
3+
// TODO How to reindex channels supplied as arrays? I don’t want to inspect
4+
// arbitrary values on the options; maybe we could use this.channels?
5+
export function exclusiveFacets(data, facets) {
6+
if (facets.length === 1) return {data, facets}; // only one facet; trivially exclusive
7+
8+
const n = data.length;
9+
const O = new Uint8Array(n);
10+
let overlaps = 0;
11+
12+
// Count the number of overlapping indexes across facets.
13+
for (const facet of facets) {
14+
for (const i of facet) {
15+
if (O[i]) ++overlaps;
16+
O[i] = 1;
17+
}
18+
}
19+
20+
// Do nothing if the facets are already exclusive.
21+
if (overlaps === 0) return {data, facets}; // facets are exclusive
22+
23+
// For each overlapping index (duplicate), assign a new unique index at the
24+
// end of the existing array. For example, [[0, 1, 2], [2, 1, 3]] would become
25+
// [[0, 1, 2], [4, 5, 3]]. Attach a plan to the facets array, to be able to
26+
// read the values associated with the old index in unaffected channels.
27+
facets = facets.map((facet) => slice(facet, Uint32Array));
28+
let j = n;
29+
O.fill(0);
30+
for (const facet of facets) {
31+
for (let k = 0, m = facet.length; k < m; ++k) {
32+
const i = facet[k];
33+
if (O[i]) facet[k] = j++;
34+
O[i] = 1;
35+
}
36+
}
37+
38+
return {data, facets};
39+
}

src/transforms/stack.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {withTip} from "../mark.js";
44
import {maybeApplyInterval, maybeColumn, maybeZ, maybeZero} from "../options.js";
55
import {column, field, mid, one, range, valueof} from "../options.js";
66
import {basic} from "./basic.js";
7+
import {exclusiveFacets} from "./exclusiveFacets.js";
78

89
export function stackX(stackOptions = {}, options = {}) {
910
if (arguments.length === 1) [stackOptions, options] = mergeOptions(stackOptions);
@@ -85,6 +86,7 @@ function stack(x, y = one, kx, ky, {offset, order, reverse}, options) {
8586
order = maybeOrder(order, offset, ky);
8687
return [
8788
basic(options, (data, facets, plotOptions) => {
89+
({data, facets} = exclusiveFacets(data, facets));
8890
const X = x == null ? undefined : setX(maybeApplyInterval(valueof(data, x), plotOptions?.[kx]));
8991
const Y = valueof(data, y, Float64Array);
9092
const Z = valueof(data, z);

0 commit comments

Comments
 (0)