1 | import {Transform} from 'vega-dataflow';
|
2 | import {bin} from 'vega-statistics';
|
3 | import {accessor, accessorFields, accessorName, inherits} from 'vega-util';
|
4 |
|
5 |
|
6 | const EPSILON = 1e-14;
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 | export default function Bin(params) {
|
16 | Transform.call(this, null, params);
|
17 | }
|
18 |
|
19 | Bin.Definition = {
|
20 | 'type': 'Bin',
|
21 | 'metadata': {'modifies': true},
|
22 | 'params': [
|
23 | { 'name': 'field', 'type': 'field', 'required': true },
|
24 | { 'name': 'interval', 'type': 'boolean', 'default': true },
|
25 | { 'name': 'anchor', 'type': 'number' },
|
26 | { 'name': 'maxbins', 'type': 'number', 'default': 20 },
|
27 | { 'name': 'base', 'type': 'number', 'default': 10 },
|
28 | { 'name': 'divide', 'type': 'number', 'array': true, 'default': [5, 2] },
|
29 | { 'name': 'extent', 'type': 'number', 'array': true, 'length': 2, 'required': true },
|
30 | { 'name': 'span', 'type': 'number' },
|
31 | { 'name': 'step', 'type': 'number' },
|
32 | { 'name': 'steps', 'type': 'number', 'array': true },
|
33 | { 'name': 'minstep', 'type': 'number', 'default': 0 },
|
34 | { 'name': 'nice', 'type': 'boolean', 'default': true },
|
35 | { 'name': 'name', 'type': 'string' },
|
36 | { 'name': 'as', 'type': 'string', 'array': true, 'length': 2, 'default': ['bin0', 'bin1'] }
|
37 | ]
|
38 | };
|
39 |
|
40 | var prototype = inherits(Bin, Transform);
|
41 |
|
42 | prototype.transform = function(_, pulse) {
|
43 | var band = _.interval !== false,
|
44 | bins = this._bins(_),
|
45 | start = bins.start,
|
46 | step = bins.step,
|
47 | as = _.as || ['bin0', 'bin1'],
|
48 | b0 = as[0],
|
49 | b1 = as[1],
|
50 | flag;
|
51 |
|
52 | if (_.modified()) {
|
53 | pulse = pulse.reflow(true);
|
54 | flag = pulse.SOURCE;
|
55 | } else {
|
56 | flag = pulse.modified(accessorFields(_.field)) ? pulse.ADD_MOD : pulse.ADD;
|
57 | }
|
58 |
|
59 | pulse.visit(flag, band
|
60 | ? function(t) {
|
61 | var v = bins(t);
|
62 |
|
63 | t[b0] = v;
|
64 |
|
65 |
|
66 |
|
67 |
|
68 | t[b1] = v == null ? null : start + step * (1 + (v - start) / step);
|
69 | }
|
70 | : function(t) { t[b0] = bins(t); }
|
71 | );
|
72 |
|
73 | return pulse.modifies(band ? as : b0);
|
74 | };
|
75 |
|
76 | prototype._bins = function(_) {
|
77 | if (this.value && !_.modified()) {
|
78 | return this.value;
|
79 | }
|
80 |
|
81 | var field = _.field,
|
82 | bins = bin(_),
|
83 | step = bins.step,
|
84 | start = bins.start,
|
85 | stop = start + Math.ceil((bins.stop - start) / step) * step,
|
86 | a, d;
|
87 |
|
88 | if ((a = _.anchor) != null) {
|
89 | d = a - (start + step * Math.floor((a - start) / step));
|
90 | start += d;
|
91 | stop += d;
|
92 | }
|
93 |
|
94 | var f = function(t) {
|
95 | var v = field(t);
|
96 | return v == null ? null
|
97 | : v < start ? -Infinity
|
98 | : v > stop ? +Infinity
|
99 | : (
|
100 | v = Math.max(start, Math.min(+v, stop - step)),
|
101 | start + step * Math.floor(EPSILON + (v - start) / step)
|
102 | );
|
103 | };
|
104 |
|
105 | f.start = start;
|
106 | f.stop = bins.stop;
|
107 | f.step = step;
|
108 |
|
109 | return this.value = accessor(
|
110 | f,
|
111 | accessorFields(field),
|
112 | _.name || 'bin_' + accessorName(field)
|
113 | );
|
114 | };
|