UNPKG

vega-transforms

Version:

Data processing transforms for Vega dataflows.

115 lines (101 loc) 3.49 kB
import {Transform} from 'vega-dataflow'; import {bin} from 'vega-statistics'; import {accessor, accessorFields, accessorName, inherits, toNumber} from 'vega-util'; // epsilon bias to offset floating point error (#1737) const EPSILON = 1e-14; /** * Generates a binning function for discretizing data. * @constructor * @param {object} params - The parameters for this operator. The * provided values should be valid options for the {@link bin} function. * @param {function(object): *} params.field - The data field to bin. */ export default function Bin(params) { Transform.call(this, null, params); } Bin.Definition = { 'type': 'Bin', 'metadata': {'modifies': true}, 'params': [ { 'name': 'field', 'type': 'field', 'required': true }, { 'name': 'interval', 'type': 'boolean', 'default': true }, { 'name': 'anchor', 'type': 'number' }, { 'name': 'maxbins', 'type': 'number', 'default': 20 }, { 'name': 'base', 'type': 'number', 'default': 10 }, { 'name': 'divide', 'type': 'number', 'array': true, 'default': [5, 2] }, { 'name': 'extent', 'type': 'number', 'array': true, 'length': 2, 'required': true }, { 'name': 'span', 'type': 'number' }, { 'name': 'step', 'type': 'number' }, { 'name': 'steps', 'type': 'number', 'array': true }, { 'name': 'minstep', 'type': 'number', 'default': 0 }, { 'name': 'nice', 'type': 'boolean', 'default': true }, { 'name': 'name', 'type': 'string' }, { 'name': 'as', 'type': 'string', 'array': true, 'length': 2, 'default': ['bin0', 'bin1'] } ] }; inherits(Bin, Transform, { transform(_, pulse) { const band = _.interval !== false, bins = this._bins(_), start = bins.start, step = bins.step, as = _.as || ['bin0', 'bin1'], b0 = as[0], b1 = as[1]; let flag; if (_.modified()) { pulse = pulse.reflow(true); flag = pulse.SOURCE; } else { flag = pulse.modified(accessorFields(_.field)) ? pulse.ADD_MOD : pulse.ADD; } pulse.visit(flag, band ? t => { const v = bins(t); // minimum bin value (inclusive) t[b0] = v; // maximum bin value (exclusive) // use convoluted math for better floating point agreement // see https://github.com/vega/vega/issues/830 // infinite values propagate through this formula! #2227 t[b1] = v == null ? null : start + step * (1 + (v - start) / step); } : t => t[b0] = bins(t) ); return pulse.modifies(band ? as : b0); }, _bins(_) { if (this.value && !_.modified()) { return this.value; } const field = _.field, bins = bin(_), step = bins.step; let start = bins.start, stop = start + Math.ceil((bins.stop - start) / step) * step, a, d; if ((a = _.anchor) != null) { d = a - (start + step * Math.floor((a - start) / step)); start += d; stop += d; } const f = function(t) { let v = toNumber(field(t)); return v == null ? null : v < start ? -Infinity : v > stop ? +Infinity : ( v = Math.max(start, Math.min(v, stop - step)), start + step * Math.floor(EPSILON + (v - start) / step) ); }; f.start = start; f.stop = bins.stop; f.step = step; return this.value = accessor( f, accessorFields(field), _.name || 'bin_' + accessorName(field) ); } });