1 | import Aggregate from './Aggregate';
|
2 | import {ValidAggregateOps} from './util/AggregateOps';
|
3 | import {accessor, accessorFields, ascending, inherits} from 'vega-util';
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 | export default function Pivot(params) {
|
22 | Aggregate.call(this, params);
|
23 | }
|
24 |
|
25 | Pivot.Definition = {
|
26 | 'type': 'Pivot',
|
27 | 'metadata': {'generates': true, 'changes': true},
|
28 | 'params': [
|
29 | { 'name': 'groupby', 'type': 'field', 'array': true },
|
30 | { 'name': 'field', 'type': 'field', 'required': true },
|
31 | { 'name': 'value', 'type': 'field', 'required': true },
|
32 | { 'name': 'op', 'type': 'enum', 'values': ValidAggregateOps, 'default': 'sum' },
|
33 | { 'name': 'limit', 'type': 'number', 'default': 0 },
|
34 | { 'name': 'key', 'type': 'field' }
|
35 | ]
|
36 | };
|
37 |
|
38 | inherits(Pivot, Aggregate, {
|
39 | _transform: Aggregate.prototype.transform,
|
40 | transform(_, pulse) {
|
41 | return this._transform(aggregateParams(_, pulse), pulse);
|
42 | }
|
43 | });
|
44 |
|
45 |
|
46 |
|
47 |
|
48 | function aggregateParams(_, pulse) {
|
49 | const key = _.field,
|
50 | value = _.value,
|
51 | op = (_.op === 'count' ? '__count__' : _.op) || 'sum',
|
52 | fields = accessorFields(key).concat(accessorFields(value)),
|
53 | keys = pivotKeys(key, _.limit || 0, pulse);
|
54 |
|
55 |
|
56 |
|
57 | if (pulse.changed()) _.set('__pivot__', null, null, true);
|
58 |
|
59 | return {
|
60 | key: _.key,
|
61 | groupby: _.groupby,
|
62 | ops: keys.map(() => op),
|
63 | fields: keys.map(k => get(k, key, value, fields)),
|
64 | as: keys.map(k => k + ''),
|
65 | modified: _.modified.bind(_)
|
66 | };
|
67 | }
|
68 |
|
69 | // Generate aggregate field accessor.
|
70 | // Output NaN for non-existent values; aggregator will ignore!
|
71 | function get(k, key, value, fields) {
|
72 | return accessor(
|
73 | d => key(d) === k ? value(d) : NaN,
|
74 | fields,
|
75 | k + ''
|
76 | );
|
77 | }
|
78 |
|
79 |
|
80 | function pivotKeys(key, limit, pulse) {
|
81 | const map = {},
|
82 | list = [];
|
83 |
|
84 | pulse.visit(pulse.SOURCE, t => {
|
85 | const k = key(t);
|
86 | if (!map[k]) {
|
87 | map[k] = 1;
|
88 | list.push(k);
|
89 | }
|
90 | });
|
91 |
|
92 | list.sort(ascending);
|
93 |
|
94 | return limit ? list.slice(0, limit) : list;
|
95 | }
|