UNPKG

vega-geo

Version:

Geographic data transforms for Vega dataflows.

88 lines (79 loc) 3.97 kB
import {Transform, ingest} from 'vega-dataflow'; import {inherits, isArray} from 'vega-util'; import {transform} from './Isocontour.js'; import {params} from './KDE2D.js'; import contours from './util/contours.js'; import density2D from './util/density2D.js'; import quantize from './util/quantize.js'; /** * Generate contours based on kernel-density estimation of point data. * @constructor * @param {object} params - The parameters for this operator. * @param {Array<number>} params.size - The dimensions [width, height] over which to compute contours. * If the values parameter is provided, this must be the dimensions of the input data. * If density estimation is performed, this is the output view dimensions in pixels. * @param {Array<number>} [params.values] - An array of numeric values representing an * width x height grid of values over which to compute contours. If unspecified, this * transform will instead attempt to compute contours for the kernel density estimate * using values drawn from data tuples in the input pulse. * @param {function(object): number} [params.x] - The pixel x-coordinate accessor for density estimation. * @param {function(object): number} [params.y] - The pixel y-coordinate accessor for density estimation. * @param {function(object): number} [params.weight] - The data point weight accessor for density estimation. * @param {number} [params.cellSize] - Contour density calculation cell size. * @param {number} [params.bandwidth] - Kernel density estimation bandwidth. * @param {Array<number>} [params.thresholds] - Contour threshold array. If * this parameter is set, the count and nice parameters will be ignored. * @param {number} [params.count] - The desired number of contours. * @param {boolean} [params.nice] - Boolean flag indicating if the contour * threshold values should be automatically aligned to "nice" * human-friendly values. Setting this flag may cause the number of * thresholds to deviate from the specified count. * @param {boolean} [params.smooth] - Boolean flag indicating if the contour * polygons should be smoothed using linear interpolation. The default is * true. The parameter is ignored when using density estimation. */ export default function Contour(params) { Transform.call(this, null, params); } Contour.Definition = { 'type': 'Contour', 'metadata': {'generates': true}, 'params': [ { 'name': 'size', 'type': 'number', 'array': true, 'length': 2, 'required': true }, { 'name': 'values', 'type': 'number', 'array': true }, { 'name': 'x', 'type': 'field' }, { 'name': 'y', 'type': 'field' }, { 'name': 'weight', 'type': 'field' }, { 'name': 'cellSize', 'type': 'number' }, { 'name': 'bandwidth', 'type': 'number' }, { 'name': 'count', 'type': 'number' }, { 'name': 'nice', 'type': 'boolean', 'default': false }, { 'name': 'thresholds', 'type': 'number', 'array': true }, { 'name': 'smooth', 'type': 'boolean', 'default': true } ] }; inherits(Contour, Transform, { transform(_, pulse) { if (this.value && !pulse.changed() && !_.modified()) { return pulse.StopPropagation; } var out = pulse.fork(pulse.NO_SOURCE | pulse.NO_FIELDS), contour = contours().smooth(_.smooth !== false), values = _.values, thresh = _.thresholds || quantize(_.count || 10, _.nice, !!values), size = _.size, grid, post; if (!values) { values = pulse.materialize(pulse.SOURCE).source; grid = params(density2D(), _)(values, true); post = transform(grid, grid.scale || 1, grid.scale || 1, 0, 0); size = [grid.width, grid.height]; values = grid.values; } thresh = isArray(thresh) ? thresh : thresh(values); values = contour.size(size)(values, thresh); if (post) values.forEach(post); if (this.value) out.rem = this.value; this.value = out.source = out.add = (values || []).map(ingest); return out; } });