@uwdata/vgplot 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/vgplot.js +5643 -5842
- package/dist/vgplot.min.js +14 -35
- package/package.json +8 -10
- package/src/api.js +292 -0
- package/src/connect.js +14 -0
- package/src/context.js +20 -0
- package/src/index.js +14 -303
- package/src/inputs.js +24 -0
- package/src/{directives → plot}/attributes.js +14 -5
- package/src/{directives → plot}/interactors.js +8 -6
- package/src/{directives → plot}/legends.js +14 -6
- package/src/{directives → plot}/marks.js +16 -13
- package/src/plot/named-plots.js +49 -0
- package/src/plot/plot.js +9 -0
- package/src/directives/plot.js +0 -39
- package/src/interactors/Highlight.js +0 -101
- package/src/interactors/Interval1D.js +0 -90
- package/src/interactors/Interval2D.js +0 -102
- package/src/interactors/Nearest.js +0 -66
- package/src/interactors/PanZoom.js +0 -121
- package/src/interactors/Toggle.js +0 -111
- package/src/interactors/util/brush.js +0 -45
- package/src/interactors/util/close-to.js +0 -9
- package/src/interactors/util/get-field.js +0 -4
- package/src/interactors/util/invert.js +0 -3
- package/src/interactors/util/patchScreenCTM.js +0 -13
- package/src/interactors/util/sanitize-styles.js +0 -9
- package/src/interactors/util/to-kebab-case.js +0 -9
- package/src/layout/index.js +0 -2
- package/src/legend.js +0 -64
- package/src/marks/ConnectedMark.js +0 -63
- package/src/marks/ContourMark.js +0 -89
- package/src/marks/DenseLineMark.js +0 -146
- package/src/marks/Density1DMark.js +0 -104
- package/src/marks/Density2DMark.js +0 -69
- package/src/marks/Grid2DMark.js +0 -191
- package/src/marks/HexbinMark.js +0 -88
- package/src/marks/Mark.js +0 -195
- package/src/marks/RasterMark.js +0 -122
- package/src/marks/RasterTileMark.js +0 -332
- package/src/marks/RegressionMark.js +0 -117
- package/src/marks/util/bin-field.js +0 -17
- package/src/marks/util/density.js +0 -226
- package/src/marks/util/extent.js +0 -56
- package/src/marks/util/grid.js +0 -57
- package/src/marks/util/handle-param.js +0 -14
- package/src/marks/util/is-arrow-table.js +0 -3
- package/src/marks/util/is-color.js +0 -18
- package/src/marks/util/is-constant-option.js +0 -40
- package/src/marks/util/is-symbol.js +0 -20
- package/src/marks/util/raster.js +0 -44
- package/src/marks/util/stats.js +0 -133
- package/src/marks/util/to-data-array.js +0 -58
- package/src/plot-attributes.js +0 -211
- package/src/plot-renderer.js +0 -161
- package/src/plot.js +0 -136
- package/src/spec/parse-data.js +0 -69
- package/src/spec/parse-spec.js +0 -422
- package/src/spec/to-module.js +0 -465
- package/src/spec/util.js +0 -43
- package/src/symbols.js +0 -3
- package/src/transforms/bin.js +0 -81
- package/src/transforms/index.js +0 -3
- /package/src/{directives → plot}/data.js +0 -0
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import { range } from 'd3';
|
|
2
|
-
import {
|
|
3
|
-
Query, max, min, castDouble, isNotNull,
|
|
4
|
-
regrIntercept, regrSlope, regrCount,
|
|
5
|
-
regrSYY, regrSXX, regrAvgX
|
|
6
|
-
} from '@uwdata/mosaic-sql';
|
|
7
|
-
import { qt } from './util/stats.js';
|
|
8
|
-
import { Mark, channelOption } from './Mark.js';
|
|
9
|
-
import { handleParam } from './util/handle-param.js';
|
|
10
|
-
import { toDataArray } from './util/to-data-array.js';
|
|
11
|
-
|
|
12
|
-
export class RegressionMark extends Mark {
|
|
13
|
-
constructor(source, options) {
|
|
14
|
-
const { ci = 0.95, precision = 4, ...channels } = options;
|
|
15
|
-
super('line', source, channels);
|
|
16
|
-
const update = () => {
|
|
17
|
-
return this.modelFit ? this.confidenceBand().update() : null
|
|
18
|
-
};
|
|
19
|
-
handleParam(this, 'ci', ci, update);
|
|
20
|
-
handleParam(this, 'precision', precision, update);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
query(filter = []) {
|
|
24
|
-
const x = this.channelField('x').as;
|
|
25
|
-
const y = this.channelField('y').as;
|
|
26
|
-
const groupby = Array.from(new Set(
|
|
27
|
-
['stroke', 'z', 'fx', 'fy'].flatMap(c => this.channelField(c)?.as || [])
|
|
28
|
-
));
|
|
29
|
-
|
|
30
|
-
return Query
|
|
31
|
-
.from(super.query(filter))
|
|
32
|
-
.select({
|
|
33
|
-
intercept: regrIntercept(y, x),
|
|
34
|
-
slope: regrSlope(y, x),
|
|
35
|
-
n: regrCount(y, x),
|
|
36
|
-
ssy: regrSYY(y, x),
|
|
37
|
-
ssx: regrSXX(y, x),
|
|
38
|
-
xm: regrAvgX(y, x),
|
|
39
|
-
x0: castDouble(min(x).where(isNotNull(y))),
|
|
40
|
-
x1: castDouble(max(x).where(isNotNull(y)))
|
|
41
|
-
})
|
|
42
|
-
.select(groupby)
|
|
43
|
-
.groupby(groupby);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
queryResult(data) {
|
|
47
|
-
this.modelFit = toDataArray(data);
|
|
48
|
-
|
|
49
|
-
// regression line
|
|
50
|
-
this.lineData = this.modelFit.flatMap(m => linePoints(m));
|
|
51
|
-
|
|
52
|
-
// prepare confidence band
|
|
53
|
-
return this.confidenceBand();
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
confidenceBand() {
|
|
57
|
-
// regression ci area
|
|
58
|
-
const { ci, modelFit, precision, plot } = this;
|
|
59
|
-
const w = plot.innerWidth();
|
|
60
|
-
this.areaData = ci ? modelFit.flatMap(m => areaPoints(ci, precision, m, w)) : null;
|
|
61
|
-
return this;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
plotSpecs() {
|
|
65
|
-
const { lineData, areaData, channels, ci } = this;
|
|
66
|
-
const lopt = { x: 'x', y: 'y' };
|
|
67
|
-
const aopt = { x: 'x', y1: 'y1', y2: 'y2', fillOpacity: 0.1 };
|
|
68
|
-
|
|
69
|
-
for (const c of channels) {
|
|
70
|
-
switch (c.channel) {
|
|
71
|
-
case 'x':
|
|
72
|
-
case 'y':
|
|
73
|
-
case 'fill':
|
|
74
|
-
break;
|
|
75
|
-
case 'stroke':
|
|
76
|
-
lopt.stroke = aopt.fill = channelOption(c);
|
|
77
|
-
break;
|
|
78
|
-
case 'strokeOpacity':
|
|
79
|
-
lopt.strokeOpacity = channelOption(c);
|
|
80
|
-
break;
|
|
81
|
-
case 'fillOpacity':
|
|
82
|
-
aopt.fillOpacity = channelOption(c);
|
|
83
|
-
break;
|
|
84
|
-
default:
|
|
85
|
-
lopt[c.channel] = aopt[c.channel] = channelOption(c);
|
|
86
|
-
break;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return [
|
|
91
|
-
...(ci ? [{ type: 'areaY', data: areaData, options: aopt }] : []),
|
|
92
|
-
{ type: 'line', data: lineData, options: lopt }
|
|
93
|
-
];
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function linePoints(model) {
|
|
98
|
-
// eslint-disable-next-line no-unused-vars
|
|
99
|
-
const { x0, x1, xm, intercept, slope, n, ssx, ssy, ...rest } = model;
|
|
100
|
-
return [
|
|
101
|
-
{ x: x0, y: intercept + x0 * slope, ...rest },
|
|
102
|
-
{ x: x1, y: intercept + x1 * slope, ...rest }
|
|
103
|
-
];
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function areaPoints(ci, precision, model, width) {
|
|
107
|
-
const { x0, x1, xm, intercept, slope, n, ssx, ssy, ...rest } = model;
|
|
108
|
-
const pp = precision * (x1 - x0) / width;
|
|
109
|
-
const t_sy = qt((1 - ci) / 2, n - 2) * Math.sqrt(ssy / (n - 2));
|
|
110
|
-
return range(x0, x1 - pp / 2, pp)
|
|
111
|
-
.concat(x1)
|
|
112
|
-
.map(x => {
|
|
113
|
-
const y = intercept + x * slope;
|
|
114
|
-
const ye = t_sy * Math.sqrt(1 / n + (x - xm) ** 2 / ssx);
|
|
115
|
-
return { x, y1: y - ye, y2: y + ye, ...rest };
|
|
116
|
-
});
|
|
117
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { epoch_ms, sql } from '@uwdata/mosaic-sql';
|
|
2
|
-
|
|
3
|
-
export function binField(mark, channel, expr) {
|
|
4
|
-
if (!mark.stats) return field;
|
|
5
|
-
const { field } = mark.channelField(channel);
|
|
6
|
-
const { type } = mark.stats[field.column];
|
|
7
|
-
expr = expr ?? field;
|
|
8
|
-
return type === 'date' ? epoch_ms(expr) : expr;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function bin1d(x, x0, x1, n, reverse = false, pad = 1) {
|
|
12
|
-
const d = (n - pad) / (x1 - x0);
|
|
13
|
-
const f = d !== 1 ? ` * ${d}::DOUBLE` : '';
|
|
14
|
-
return reverse
|
|
15
|
-
? sql`(${+x1} - ${x}::DOUBLE)${f}`
|
|
16
|
-
: sql`(${x}::DOUBLE - ${+x0})${f}`;
|
|
17
|
-
}
|
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
// Deriche's approximation of Gaussian smoothing
|
|
2
|
-
// Adapted from Getreuer's C implementation (BSD license)
|
|
3
|
-
// https://www.ipol.im/pub/art/2013/87/gaussian_20131215.tgz
|
|
4
|
-
// http://dev.ipol.im/~getreuer/code/doc/gaussian_20131215_doc/gaussian__conv__deriche_8c.html
|
|
5
|
-
|
|
6
|
-
export function dericheConfig(sigma, negative = false) {
|
|
7
|
-
// compute causal filter coefficients
|
|
8
|
-
const a = new Float64Array(5);
|
|
9
|
-
const bc = new Float64Array(4);
|
|
10
|
-
dericheCausalCoeff(a, bc, sigma);
|
|
11
|
-
|
|
12
|
-
// numerator coefficients of the anticausal filter
|
|
13
|
-
const ba = Float64Array.of(
|
|
14
|
-
0,
|
|
15
|
-
bc[1] - a[1] * bc[0],
|
|
16
|
-
bc[2] - a[2] * bc[0],
|
|
17
|
-
bc[3] - a[3] * bc[0],
|
|
18
|
-
-a[4] * bc[0]
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
// impulse response sums
|
|
22
|
-
const accum_denom = 1.0 + a[1] + a[2] + a[3] + a[4];
|
|
23
|
-
const sum_causal = (bc[0] + bc[1] + bc[2] + bc[3]) / accum_denom;
|
|
24
|
-
const sum_anticausal = (ba[1] + ba[2] + ba[3] + ba[4]) / accum_denom;
|
|
25
|
-
|
|
26
|
-
// coefficients object
|
|
27
|
-
return {
|
|
28
|
-
sigma,
|
|
29
|
-
negative,
|
|
30
|
-
a,
|
|
31
|
-
b_causal: bc,
|
|
32
|
-
b_anticausal: ba,
|
|
33
|
-
sum_causal,
|
|
34
|
-
sum_anticausal
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function dericheCausalCoeff(a_out, b_out, sigma) {
|
|
39
|
-
const K = 4;
|
|
40
|
-
|
|
41
|
-
const alpha = Float64Array.of(
|
|
42
|
-
0.84, 1.8675,
|
|
43
|
-
0.84, -1.8675,
|
|
44
|
-
-0.34015, -0.1299,
|
|
45
|
-
-0.34015, 0.1299
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
const x1 = Math.exp(-1.783 / sigma);
|
|
49
|
-
const x2 = Math.exp(-1.723 / sigma);
|
|
50
|
-
const y1 = 0.6318 / sigma;
|
|
51
|
-
const y2 = 1.997 / sigma;
|
|
52
|
-
const beta = Float64Array.of(
|
|
53
|
-
-x1 * Math.cos( y1), x1 * Math.sin( y1),
|
|
54
|
-
-x1 * Math.cos(-y1), x1 * Math.sin(-y1),
|
|
55
|
-
-x2 * Math.cos( y2), x2 * Math.sin( y2),
|
|
56
|
-
-x2 * Math.cos(-y2), x2 * Math.sin(-y2)
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
const denom = sigma * 2.5066282746310007;
|
|
60
|
-
|
|
61
|
-
// initialize b/a = alpha[0] / (1 + beta[0] z^-1)
|
|
62
|
-
const b = Float64Array.of(alpha[0], alpha[1], 0, 0, 0, 0, 0, 0);
|
|
63
|
-
const a = Float64Array.of(1, 0, beta[0], beta[1], 0, 0, 0, 0, 0, 0);
|
|
64
|
-
|
|
65
|
-
let j, k;
|
|
66
|
-
|
|
67
|
-
for (k = 2; k < 8; k += 2) {
|
|
68
|
-
// add kth term, b/a += alpha[k] / (1 + beta[k] z^-1)
|
|
69
|
-
b[k] = beta[k] * b[k - 2] - beta[k + 1] * b[k - 1];
|
|
70
|
-
b[k + 1] = beta[k] * b[k - 1] + beta[k + 1] * b[k - 2];
|
|
71
|
-
for (j = k - 2; j > 0; j -= 2) {
|
|
72
|
-
b[j] += beta[k] * b[j - 2] - beta[k + 1] * b[j - 1];
|
|
73
|
-
b[j + 1] += beta[k] * b[j - 1] + beta[k + 1] * b[j - 2];
|
|
74
|
-
}
|
|
75
|
-
for (j = 0; j <= k; j += 2) {
|
|
76
|
-
b[j] += alpha[k] * a[j] - alpha[k + 1] * a[j + 1];
|
|
77
|
-
b[j + 1] += alpha[k] * a[j + 1] + alpha[k + 1] * a[j];
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
a[k + 2] = beta[k] * a[k] - beta[k + 1] * a[k + 1];
|
|
81
|
-
a[k + 3] = beta[k] * a[k + 1] + beta[k + 1] * a[k];
|
|
82
|
-
for (j = k; j > 0; j -= 2) {
|
|
83
|
-
a[j] += beta[k] * a[j - 2] - beta[k + 1] * a[j - 1];
|
|
84
|
-
a[j + 1] += beta[k] * a[j - 1] + beta[k + 1] * a[j - 2];
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
for (k = 0; k < K; ++k) {
|
|
89
|
-
j = k << 1;
|
|
90
|
-
b_out[k] = b[j] / denom;
|
|
91
|
-
a_out[k + 1] = a[j + 2];
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export function dericheConv2d(cx, cy, grid, [nx, ny]) {
|
|
96
|
-
// allocate buffers
|
|
97
|
-
const yc = new Float64Array(Math.max(nx, ny)); // causal
|
|
98
|
-
const ya = new Float64Array(Math.max(nx, ny)); // anticausal
|
|
99
|
-
const h = new Float64Array(5);
|
|
100
|
-
const d = new Float64Array(grid.length);
|
|
101
|
-
|
|
102
|
-
// convolve rows
|
|
103
|
-
for (let row = 0, r0 = 0; row < ny; ++row, r0 += nx) {
|
|
104
|
-
const dx = d.subarray(r0);
|
|
105
|
-
dericheConv1d(cx, grid.subarray(r0), nx, 1, yc, ya, h, dx);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// convolve columns
|
|
109
|
-
for (let c0 = 0; c0 < nx; ++c0) {
|
|
110
|
-
const dy = d.subarray(c0);
|
|
111
|
-
dericheConv1d(cy, dy, ny, nx, yc, ya, h, dy);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return d;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export function dericheConv1d(
|
|
118
|
-
c, src, N,
|
|
119
|
-
stride = 1,
|
|
120
|
-
y_causal = new Float64Array(N),
|
|
121
|
-
y_anticausal = new Float64Array(N),
|
|
122
|
-
h = new Float64Array(5),
|
|
123
|
-
d = y_causal,
|
|
124
|
-
init = dericheInitZeroPad
|
|
125
|
-
) {
|
|
126
|
-
const stride_2 = stride * 2;
|
|
127
|
-
const stride_3 = stride * 3;
|
|
128
|
-
const stride_4 = stride * 4;
|
|
129
|
-
const stride_N = stride * N;
|
|
130
|
-
let i, n;
|
|
131
|
-
|
|
132
|
-
// initialize causal filter on the left boundary
|
|
133
|
-
init(
|
|
134
|
-
y_causal, src, N, stride,
|
|
135
|
-
c.b_causal, 3, c.a, 4, c.sum_causal, h, c.sigma
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
// filter the interior samples using a 4th order filter. Implements:
|
|
139
|
-
// for n = K, ..., N - 1,
|
|
140
|
-
// y^+(n) = \sum_{k=0}^{K-1} b^+_k src(n - k)
|
|
141
|
-
// - \sum_{k=1}^K a_k y^+(n - k)
|
|
142
|
-
// variable i tracks the offset to the nth sample of src, it is
|
|
143
|
-
// updated together with n such that i = stride * n.
|
|
144
|
-
for (n = 4, i = stride_4; n < N; ++n, i += stride) {
|
|
145
|
-
y_causal[n] = c.b_causal[0] * src[i]
|
|
146
|
-
+ c.b_causal[1] * src[i - stride]
|
|
147
|
-
+ c.b_causal[2] * src[i - stride_2]
|
|
148
|
-
+ c.b_causal[3] * src[i - stride_3]
|
|
149
|
-
- c.a[1] * y_causal[n - 1]
|
|
150
|
-
- c.a[2] * y_causal[n - 2]
|
|
151
|
-
- c.a[3] * y_causal[n - 3]
|
|
152
|
-
- c.a[4] * y_causal[n - 4];
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// initialize the anticausal filter on the right boundary
|
|
156
|
-
init(
|
|
157
|
-
y_anticausal, src, N, -stride,
|
|
158
|
-
c.b_anticausal, 4, c.a, 4, c.sum_anticausal, h, c.sigma
|
|
159
|
-
);
|
|
160
|
-
|
|
161
|
-
// similar to the causal filter above, the following implements:
|
|
162
|
-
// for n = K, ..., N - 1,
|
|
163
|
-
// y^-(n) = \sum_{k=1}^K b^-_k src(N - n - 1 - k)
|
|
164
|
-
// - \sum_{k=1}^K a_k y^-(n - k)
|
|
165
|
-
// variable i is updated such that i = stride * (N - n - 1).
|
|
166
|
-
for (n = 4, i = stride_N - stride * 5; n < N; ++n, i -= stride) {
|
|
167
|
-
y_anticausal[n] = c.b_anticausal[1] * src[i + stride]
|
|
168
|
-
+ c.b_anticausal[2] * src[i + stride_2]
|
|
169
|
-
+ c.b_anticausal[3] * src[i + stride_3]
|
|
170
|
-
+ c.b_anticausal[4] * src[i + stride_4]
|
|
171
|
-
- c.a[1] * y_anticausal[n - 1]
|
|
172
|
-
- c.a[2] * y_anticausal[n - 2]
|
|
173
|
-
- c.a[3] * y_anticausal[n - 3]
|
|
174
|
-
- c.a[4] * y_anticausal[n - 4];
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// sum the causal and anticausal responses to obtain the final result
|
|
178
|
-
if (c.negative) {
|
|
179
|
-
// do not threshold if the input grid includes negatively weighted values
|
|
180
|
-
for (n = 0, i = 0; n < N; ++n, i += stride) {
|
|
181
|
-
d[i] = y_causal[n] + y_anticausal[N - n - 1];
|
|
182
|
-
}
|
|
183
|
-
} else {
|
|
184
|
-
// threshold to prevent small negative values due to floating point error
|
|
185
|
-
for (n = 0, i = 0; n < N; ++n, i += stride) {
|
|
186
|
-
d[i] = Math.max(0, y_causal[n] + y_anticausal[N - n - 1]);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return d;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
export function dericheInitZeroPad(dest, src, N, stride, b, p, a, q, sum, h) {
|
|
194
|
-
const stride_N = Math.abs(stride) * N;
|
|
195
|
-
const off = stride < 0 ? stride_N + stride : 0;
|
|
196
|
-
let i, n, m;
|
|
197
|
-
|
|
198
|
-
// compute the first q taps of the impulse response, h_0, ..., h_{q-1}
|
|
199
|
-
for (n = 0; n < q; ++n) {
|
|
200
|
-
h[n] = (n <= p) ? b[n] : 0;
|
|
201
|
-
for (m = 1; m <= q && m <= n; ++m) {
|
|
202
|
-
h[n] -= a[m] * h[n - m];
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// compute dest_m = sum_{n=1}^m h_{m-n} src_n, m = 0, ..., q-1
|
|
207
|
-
// note: q == 4
|
|
208
|
-
for (m = 0; m < q; ++m) {
|
|
209
|
-
for (dest[m] = 0, n = 1; n <= m; ++n) {
|
|
210
|
-
i = off + stride * n;
|
|
211
|
-
if (i >= 0 && i < stride_N) {
|
|
212
|
-
dest[m] += h[m - n] * src[i];
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// dest_m = dest_m + h_{n+m} src_{-n}
|
|
218
|
-
const cur = src[off];
|
|
219
|
-
if (cur > 0) {
|
|
220
|
-
for (m = 0; m < q; ++m) {
|
|
221
|
-
dest[m] += h[m] * cur;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
return;
|
|
226
|
-
}
|
package/src/marks/util/extent.js
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { scaleLinear } from 'd3';
|
|
2
|
-
import { Fixed, Transient } from '../../symbols.js';
|
|
3
|
-
|
|
4
|
-
export const xext = { x: ['min', 'max'] };
|
|
5
|
-
export const yext = { y: ['min', 'max'] };
|
|
6
|
-
export const xyext = { ...xext, ...yext };
|
|
7
|
-
|
|
8
|
-
export function plotExtent(mark, filter, channel, domainAttr, niceAttr) {
|
|
9
|
-
const { plot, stats } = mark;
|
|
10
|
-
const domain = plot.getAttribute(domainAttr);
|
|
11
|
-
const nice = plot.getAttribute(niceAttr);
|
|
12
|
-
|
|
13
|
-
if (Array.isArray(domain) && !domain[Transient]) {
|
|
14
|
-
return domain;
|
|
15
|
-
} else {
|
|
16
|
-
const { field } = mark.channelField(channel);
|
|
17
|
-
const { column } = field;
|
|
18
|
-
const { min, max } = stats[column];
|
|
19
|
-
const dom = filteredExtent(filter, column) || (nice
|
|
20
|
-
? scaleLinear().domain([min, max]).nice().domain()
|
|
21
|
-
: [min, max]);
|
|
22
|
-
if (domain !== Fixed) dom[Transient] = true;
|
|
23
|
-
plot.setAttribute(domainAttr, dom, { silent: true });
|
|
24
|
-
return dom;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function extentX(mark, filter) {
|
|
29
|
-
return plotExtent(mark, filter, 'x', 'xDomain', 'xNice');
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function extentY(mark, filter) {
|
|
33
|
-
return plotExtent(mark, filter, 'y', 'yDomain', 'yNice');
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function filteredExtent(filter, column) {
|
|
37
|
-
if (!filter) return;
|
|
38
|
-
|
|
39
|
-
let lo;
|
|
40
|
-
let hi;
|
|
41
|
-
const visitor = (type, clause) => {
|
|
42
|
-
if (type === 'BETWEEN' && clause.field.column === column) {
|
|
43
|
-
const { range } = clause;
|
|
44
|
-
if (range && (lo == null || range[0] < lo)) lo = range[0];
|
|
45
|
-
if (range && (hi == null || range[1] > hi)) hi = range[1];
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
if (Array.isArray(filter)) {
|
|
50
|
-
filter.forEach(p => p.visit?.(visitor));
|
|
51
|
-
} else if (filter.visit) {
|
|
52
|
-
filter.visit(visitor);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return lo != null && hi != null && lo !== hi ? [lo, hi] : undefined;
|
|
56
|
-
}
|
package/src/marks/util/grid.js
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { isArrowTable } from './is-arrow-table.js';
|
|
2
|
-
|
|
3
|
-
export function grid1d(n, values) {
|
|
4
|
-
return valuesToGrid(new Float64Array(n), values);
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function grid2d(m, n, values, groupby = []) {
|
|
8
|
-
return groupby.length
|
|
9
|
-
? Object.values(groupedValuesToGrids(m * n, values, groupby))
|
|
10
|
-
: [{ grid: valuesToGrid(new Float64Array(m * n), values) }];
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function valuesToGrid(grid, values) {
|
|
14
|
-
if (isArrowTable(values)) {
|
|
15
|
-
// optimize access for Arrow tables
|
|
16
|
-
const numRows = values.numRows;
|
|
17
|
-
if (numRows === 0) return grid;
|
|
18
|
-
const index = values.getChild('index').toArray();
|
|
19
|
-
const value = values.getChild('value').toArray();
|
|
20
|
-
for (let row = 0; row < numRows; ++row) {
|
|
21
|
-
grid[index[row]] = value[row];
|
|
22
|
-
}
|
|
23
|
-
} else {
|
|
24
|
-
// fallback to iterable data
|
|
25
|
-
for (const row of values) {
|
|
26
|
-
grid[row.index] = row.value;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
return grid;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function groupedValuesToGrids(size, values, groupby) {
|
|
33
|
-
const grids = {};
|
|
34
|
-
const getGrid = key => {
|
|
35
|
-
const cell = grids[key] || (grids[key] = { key, grid: new Float64Array(size) });
|
|
36
|
-
return cell.grid;
|
|
37
|
-
};
|
|
38
|
-
if (isArrowTable(values)) {
|
|
39
|
-
// optimize access for Arrow tables
|
|
40
|
-
const numRows = values.numRows;
|
|
41
|
-
if (numRows === 0) return grids;
|
|
42
|
-
const index = values.getChild('index').toArray();
|
|
43
|
-
const value = values.getChild('value').toArray();
|
|
44
|
-
const groups = groupby.map(name => values.getChild(name));
|
|
45
|
-
for (let row = 0; row < numRows; ++row) {
|
|
46
|
-
const key = groups.map(vec => vec.get(row));
|
|
47
|
-
getGrid(key)[index[row]] = value[row];
|
|
48
|
-
}
|
|
49
|
-
} else {
|
|
50
|
-
// fallback to iterable data
|
|
51
|
-
for (const row of values) {
|
|
52
|
-
const key = groupby.map(col => row[col]);
|
|
53
|
-
getGrid(key)[row.index] = row.value;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return grids;
|
|
57
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { isParam } from '@uwdata/mosaic-core';
|
|
2
|
-
|
|
3
|
-
export function handleParam(client, key, param, update) {
|
|
4
|
-
if (isParam(param)) {
|
|
5
|
-
update = update || (() => client.requestUpdate());
|
|
6
|
-
param.addEventListener('value', value => {
|
|
7
|
-
client[key] = value;
|
|
8
|
-
return update();
|
|
9
|
-
});
|
|
10
|
-
client[key] = param.value;
|
|
11
|
-
} else {
|
|
12
|
-
client[key] = param;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { color } from 'd3';
|
|
2
|
-
|
|
3
|
-
// Mostly relies on d3-color, with a few extra color keywords. Currently this
|
|
4
|
-
// strictly requires that the value be a string; we might want to apply string
|
|
5
|
-
// coercion here, though note that d3-color instances would need to support
|
|
6
|
-
// valueOf to work correctly with InternMap.
|
|
7
|
-
// https://www.w3.org/TR/SVG11/painting.html#SpecifyingPaint
|
|
8
|
-
export function isColor(value) {
|
|
9
|
-
if (typeof value !== "string") return false;
|
|
10
|
-
value = value.toLowerCase().trim();
|
|
11
|
-
return (
|
|
12
|
-
value === "none" ||
|
|
13
|
-
value === "currentcolor" ||
|
|
14
|
-
(value.startsWith("url(") && value.endsWith(")")) || // <funciri>, e.g. pattern or gradient
|
|
15
|
-
(value.startsWith("var(") && value.endsWith(")")) || // CSS variable
|
|
16
|
-
color(value) !== null
|
|
17
|
-
);
|
|
18
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
const constantOptions = new Set([
|
|
2
|
-
'order',
|
|
3
|
-
'sort',
|
|
4
|
-
'label',
|
|
5
|
-
'anchor',
|
|
6
|
-
'curve',
|
|
7
|
-
'tension',
|
|
8
|
-
'marker',
|
|
9
|
-
'markerStart',
|
|
10
|
-
'markerMid',
|
|
11
|
-
'markerEnd',
|
|
12
|
-
'textAnchor',
|
|
13
|
-
'lineAnchor',
|
|
14
|
-
'lineHeight',
|
|
15
|
-
'textOverflow',
|
|
16
|
-
'monospace',
|
|
17
|
-
'fontFamily',
|
|
18
|
-
'fontSize',
|
|
19
|
-
'fontStyle',
|
|
20
|
-
'fontVariant',
|
|
21
|
-
'fontWeight',
|
|
22
|
-
'frameAnchor',
|
|
23
|
-
'strokeLinejoin',
|
|
24
|
-
'strokeLinecap',
|
|
25
|
-
'strokeMiterlimit',
|
|
26
|
-
'strokeDasharray',
|
|
27
|
-
'strokeDashoffset',
|
|
28
|
-
'mixBlendMode',
|
|
29
|
-
'shapeRendering',
|
|
30
|
-
'imageRendering',
|
|
31
|
-
'preserveAspectRatio',
|
|
32
|
-
'interpolate',
|
|
33
|
-
'crossOrigin',
|
|
34
|
-
'paintOrder',
|
|
35
|
-
'pointerEvents'
|
|
36
|
-
]);
|
|
37
|
-
|
|
38
|
-
export function isConstantOption(value) {
|
|
39
|
-
return constantOptions.has(value);
|
|
40
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
const symbols = new Set([
|
|
2
|
-
'asterisk',
|
|
3
|
-
'circle',
|
|
4
|
-
'cross',
|
|
5
|
-
'diamond',
|
|
6
|
-
'diamond2',
|
|
7
|
-
'hexagon',
|
|
8
|
-
'plus',
|
|
9
|
-
'square',
|
|
10
|
-
'square2',
|
|
11
|
-
'star',
|
|
12
|
-
'times',
|
|
13
|
-
'triangle',
|
|
14
|
-
'triangle2',
|
|
15
|
-
'wye'
|
|
16
|
-
]);
|
|
17
|
-
|
|
18
|
-
export function isSymbol(value) {
|
|
19
|
-
return symbols.has(`${value}`.toLowerCase());
|
|
20
|
-
}
|
package/src/marks/util/raster.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { rgb } from 'd3';
|
|
2
|
-
|
|
3
|
-
export function raster(grid, data, w, h, scale, scheme) {
|
|
4
|
-
const n = (scheme.length >> 2) - 1;
|
|
5
|
-
for (let j = 0, k = 0; j < h; ++j) {
|
|
6
|
-
for (let i = 0, row = (h - j - 1) * w; i < w; ++i, k += 4) {
|
|
7
|
-
const c = (n * scale(grid[i + row])) << 2;
|
|
8
|
-
data[k + 0] = scheme[c + 0];
|
|
9
|
-
data[k + 1] = scheme[c + 1];
|
|
10
|
-
data[k + 2] = scheme[c + 2];
|
|
11
|
-
data[k + 3] = scheme[c + 3];
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function palette(size, interp) {
|
|
17
|
-
const p = new Uint8ClampedArray(4 * size);
|
|
18
|
-
const n = size - 1;
|
|
19
|
-
for (let i = 0; i <= n; ++i) {
|
|
20
|
-
const v = interp(i / n);
|
|
21
|
-
const { r, g, b, opacity = 1 } = typeof v === 'string' ? rgb(v) : v;
|
|
22
|
-
const k = i << 2;
|
|
23
|
-
p[k + 0] = r;
|
|
24
|
-
p[k + 1] = g;
|
|
25
|
-
p[k + 2] = b;
|
|
26
|
-
p[k + 3] = (255 * opacity) | 0;
|
|
27
|
-
}
|
|
28
|
-
return p;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function createCanvas(w, h) {
|
|
32
|
-
if (typeof document !== 'undefined') {
|
|
33
|
-
const c = document.createElement('canvas');
|
|
34
|
-
c.setAttribute('width', w);
|
|
35
|
-
c.setAttribute('height', h);
|
|
36
|
-
return c;
|
|
37
|
-
}
|
|
38
|
-
throw new Error('Can not create a canvas instance.');
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function opacityMap(color = 'black') {
|
|
42
|
-
const { r, g, b } = rgb(color);
|
|
43
|
-
return opacity => ({ r, g, b, opacity });
|
|
44
|
-
}
|