@uwdata/mosaic-plot 0.13.0 → 0.14.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uwdata/mosaic-plot",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "A Mosaic-powered plotting framework based on Observable Plot.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"data",
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@observablehq/plot": "^0.6.17",
|
|
29
|
-
"@uwdata/mosaic-core": "^0.
|
|
30
|
-
"@uwdata/mosaic-sql": "^0.
|
|
29
|
+
"@uwdata/mosaic-core": "^0.14.0",
|
|
30
|
+
"@uwdata/mosaic-sql": "^0.14.0",
|
|
31
31
|
"d3": "^7.9.0",
|
|
32
32
|
"isoformat": "^0.2.1"
|
|
33
33
|
},
|
|
34
|
-
"gitHead": "
|
|
34
|
+
"gitHead": "a882aab60867e4e9d9738bc950aa9de32729a806"
|
|
35
35
|
}
|
package/src/transforms/bin.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import { ExprNode,
|
|
1
|
+
import { ExprNode, binDate, binHistogram } from '@uwdata/mosaic-sql';
|
|
2
2
|
import { Transform } from '../symbols.js';
|
|
3
3
|
import { channelScale } from '../marks/util/channel-scale.js';
|
|
4
|
-
import { bins } from './bin-step.js';
|
|
5
|
-
import { timeInterval } from './time-interval.js';
|
|
6
4
|
|
|
7
5
|
const EXTENT = new Set([
|
|
8
6
|
'rectY-x', 'rectX-y', 'rect-x', 'rect-y', 'ruleY-x', 'ruleX-y'
|
|
@@ -54,29 +52,12 @@ class BinTransformNode extends ExprNode {
|
|
|
54
52
|
toString() {
|
|
55
53
|
const { mark, channel, column, options } = this;
|
|
56
54
|
const { type, min, max } = mark.channelField(channel);
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (ival === 'number') {
|
|
64
|
-
// perform number binning
|
|
65
|
-
const { apply, sqlApply, sqlInvert } = channelScale(mark, channel);
|
|
66
|
-
const b = bins(apply(min), apply(max), options);
|
|
67
|
-
const col = sqlApply(column);
|
|
68
|
-
const alpha = float64((b.max - b.min) / b.steps);
|
|
69
|
-
const bin = floor(div(b.min === 0 ? col : sub(col, b.min), alpha));
|
|
70
|
-
const expr = add(b.min, mul(alpha, offset ? add(offset, bin) : bin));
|
|
71
|
-
result = sqlInvert(expr);
|
|
72
|
-
} else {
|
|
73
|
-
// perform date/time binning
|
|
74
|
-
const { interval: unit, step = 1 } = ival === 'date'
|
|
75
|
-
? timeInterval(min, max, steps || 40)
|
|
76
|
-
: options;
|
|
77
|
-
const bin = dateBin(column, unit, step);
|
|
78
|
-
result = offset ? add(bin, interval(unit, offset * step)) : bin;
|
|
79
|
-
}
|
|
55
|
+
const isDate = options.interval
|
|
56
|
+
|| type === 'date'
|
|
57
|
+
|| hasTimeScale(mark, channel);
|
|
58
|
+
const result = isDate
|
|
59
|
+
? binDate(column, [min, max], options)
|
|
60
|
+
: binHistogram(column, [min, max], options, channelScale(mark, channel));
|
|
80
61
|
return `${result}`;
|
|
81
62
|
}
|
|
82
63
|
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
export function binStep(span, steps, minstep = 0, logb = Math.LN10) {
|
|
2
|
-
let v;
|
|
3
|
-
|
|
4
|
-
const level = Math.ceil(Math.log(steps) / logb);
|
|
5
|
-
let step = Math.max(
|
|
6
|
-
minstep,
|
|
7
|
-
Math.pow(10, Math.round(Math.log(span) / logb) - level)
|
|
8
|
-
);
|
|
9
|
-
|
|
10
|
-
// increase step size if too many bins
|
|
11
|
-
while (Math.ceil(span / step) > steps) { step *= 10; }
|
|
12
|
-
|
|
13
|
-
// decrease step size if allowed
|
|
14
|
-
const div = [5, 2];
|
|
15
|
-
for (let i = 0, n = div.length; i < n; ++i) {
|
|
16
|
-
v = step / div[i];
|
|
17
|
-
if (v >= minstep && span / v <= steps) step = v;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return step;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function bins(min, max, options) {
|
|
24
|
-
let { step, steps, minstep = 0, nice = true } = options;
|
|
25
|
-
|
|
26
|
-
if (nice !== false) {
|
|
27
|
-
// use span to determine step size
|
|
28
|
-
const span = max - min;
|
|
29
|
-
const logb = Math.LN10;
|
|
30
|
-
step = step || binStep(span, steps || 25, minstep, logb);
|
|
31
|
-
|
|
32
|
-
// adjust min/max relative to step
|
|
33
|
-
let v = Math.log(step);
|
|
34
|
-
const precision = v >= 0 ? 0 : ~~(-v / logb) + 1;
|
|
35
|
-
const eps = Math.pow(10, -precision - 1);
|
|
36
|
-
v = Math.floor(min / step + eps) * step;
|
|
37
|
-
min = min < v ? v - step : v;
|
|
38
|
-
max = Math.ceil(max / step) * step;
|
|
39
|
-
steps = Math.round((max - min) / step);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return { min, max, steps };
|
|
43
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { bisector } from 'd3';
|
|
2
|
-
import { binStep } from './bin-step.js';
|
|
3
|
-
|
|
4
|
-
const YEAR = 'year';
|
|
5
|
-
const MONTH = 'month';
|
|
6
|
-
const DAY = 'day';
|
|
7
|
-
const HOUR = 'hour';
|
|
8
|
-
const MINUTE = 'minute';
|
|
9
|
-
const SECOND = 'second';
|
|
10
|
-
const MILLISECOND = 'millisecond';
|
|
11
|
-
|
|
12
|
-
const durationSecond = 1000;
|
|
13
|
-
const durationMinute = durationSecond * 60;
|
|
14
|
-
const durationHour = durationMinute * 60;
|
|
15
|
-
const durationDay = durationHour * 24;
|
|
16
|
-
const durationWeek = durationDay * 7;
|
|
17
|
-
const durationMonth = durationDay * 30;
|
|
18
|
-
const durationYear = durationDay * 365;
|
|
19
|
-
|
|
20
|
-
/** @type {[string, number, number][]} */
|
|
21
|
-
const intervals = [
|
|
22
|
-
[SECOND, 1, durationSecond],
|
|
23
|
-
[SECOND, 5, 5 * durationSecond],
|
|
24
|
-
[SECOND, 15, 15 * durationSecond],
|
|
25
|
-
[SECOND, 30, 30 * durationSecond],
|
|
26
|
-
[MINUTE, 1, durationMinute],
|
|
27
|
-
[MINUTE, 5, 5 * durationMinute],
|
|
28
|
-
[MINUTE, 15, 15 * durationMinute],
|
|
29
|
-
[MINUTE, 30, 30 * durationMinute],
|
|
30
|
-
[ HOUR, 1, durationHour ],
|
|
31
|
-
[ HOUR, 3, 3 * durationHour ],
|
|
32
|
-
[ HOUR, 6, 6 * durationHour ],
|
|
33
|
-
[ HOUR, 12, 12 * durationHour ],
|
|
34
|
-
[ DAY, 1, durationDay ],
|
|
35
|
-
[ DAY, 7, durationWeek ],
|
|
36
|
-
[ MONTH, 1, durationMonth ],
|
|
37
|
-
[ MONTH, 3, 3 * durationMonth ],
|
|
38
|
-
[ YEAR, 1, durationYear ]
|
|
39
|
-
];
|
|
40
|
-
|
|
41
|
-
export function timeInterval(min, max, steps) {
|
|
42
|
-
const span = max - min;
|
|
43
|
-
const target = span / steps;
|
|
44
|
-
let i = bisector(i => i[2]).right(intervals, target);
|
|
45
|
-
if (i === intervals.length) {
|
|
46
|
-
return { interval: YEAR, step: binStep(span / durationYear, steps) };
|
|
47
|
-
} else if (i) {
|
|
48
|
-
i = intervals[target / intervals[i - 1][2] < intervals[i][2] / target ? i - 1 : i];
|
|
49
|
-
return { interval: i[0], step: i[1] };
|
|
50
|
-
} else {
|
|
51
|
-
return { interval: MILLISECOND, step: binStep(span, steps, 1) };
|
|
52
|
-
}
|
|
53
|
-
}
|