| Current Path : /etc/kibana/node_modules/vega-transforms/src/ |
| Current File : //etc/kibana/node_modules/vega-transforms/src/Pivot.js |
import Aggregate from './Aggregate';
import {ValidAggregateOps} from './util/AggregateOps';
import {accessor, accessorFields, inherits} from 'vega-util';
/**
* Aggregate and pivot selected field values to become new fields.
* This operator is useful to construction cross-tabulations.
* @constructor
* @param {Array<function(object): *>} [params.groupby] - An array of accessors
* to groupby. These fields act just like groupby fields of an Aggregate transform.
* @param {function(object): *} params.field - The field to pivot on. The unique
* values of this field become new field names in the output stream.
* @param {function(object): *} params.value - The field to populate pivoted fields.
* The aggregate values of this field become the values of the new pivoted fields.
* @param {string} [params.op] - The aggregation operation for the value field,
* applied per cell in the output stream. The default is "sum".
* @param {number} [params.limit] - An optional parameter indicating the maximum
* number of pivoted fields to generate. The pivoted field names are sorted in
* ascending order prior to enforcing the limit.
*/
export default function Pivot(params) {
Aggregate.call(this, params);
}
Pivot.Definition = {
"type": "Pivot",
"metadata": {"generates": true, "changes": true},
"params": [
{ "name": "groupby", "type": "field", "array": true },
{ "name": "field", "type": "field", "required": true },
{ "name": "value", "type": "field", "required": true },
{ "name": "op", "type": "enum", "values": ValidAggregateOps, "default": "sum" },
{ "name": "limit", "type": "number", "default": 0 },
{ "name": "key", "type": "field" }
]
};
var prototype = inherits(Pivot, Aggregate);
prototype._transform = prototype.transform;
prototype.transform = function(_, pulse) {
return this._transform(aggregateParams(_, pulse), pulse);
};
// Shoehorn a pivot transform into an aggregate transform!
// First collect all unique pivot field values.
// Then generate aggregate fields for each output pivot field.
function aggregateParams(_, pulse) {
var key = _.field,
value = _.value,
op = (_.op === 'count' ? '__count__' : _.op) || 'sum',
fields = accessorFields(key).concat(accessorFields(value)),
keys = pivotKeys(key, _.limit || 0, pulse);
return {
key: _.key,
groupby: _.groupby,
ops: keys.map(function() { return op; }),
fields: keys.map(function(k) { return get(k, key, value, fields); }),
as: keys.map(function(k) { return k + ''; }),
modified: _.modified.bind(_)
};
}
// Generate aggregate field accessor.
// Output NaN for non-existent values; aggregator will ignore!
function get(k, key, value, fields) {
return accessor(
function(d) { return key(d) === k ? value(d) : NaN; },
fields,
k + ''
);
}
// Collect (and optionally limit) all unique pivot values.
function pivotKeys(key, limit, pulse) {
var map = {},
list = [];
pulse.visit(pulse.SOURCE, function(t) {
var k = key(t);
if (!map[k]) {
map[k] = 1;
list.push(k);
}
});
// TODO? Move this comparator to vega-util?
list.sort(function(u, v) {
return (u<v||u==null) && v!=null ? -1
: (u>v||v==null) && u!=null ? 1
: ((v=v instanceof Date?+v:v),(u=u instanceof Date?+u:u))!==u && v===v ? -1
: v!==v && u===u ? 1 : 0;
});
return limit ? list.slice(0, limit) : list;
}