UNPKG

vega-transforms

Version:

Data processing transforms for Vega dataflows.

149 lines (141 loc) 3.29 kB
import {error, zero} from 'vega-util'; export function WindowOp(op, field, param, as) { const fn = WindowOps[op](field, param); return { init: fn.init || zero, update: function(w, t) { t[as] = fn.next(w); } }; } export const WindowOps = { row_number: function() { return { next: w => w.index + 1 }; }, rank: function() { let rank; return { init: () => rank = 1, next: w => { const i = w.index, data = w.data; return (i && w.compare(data[i - 1], data[i])) ? (rank = i + 1) : rank; } }; }, dense_rank: function() { let drank; return { init: () => drank = 1, next: w => { const i = w.index, d = w.data; return (i && w.compare(d[i - 1], d[i])) ? ++drank : drank; } }; }, percent_rank: function() { const rank = WindowOps.rank(), next = rank.next; return { init: rank.init, next: w => (next(w) - 1) / (w.data.length - 1) }; }, cume_dist: function() { let cume; return { init: () => cume = 0, next: w => { const d = w.data, c = w.compare; let i = w.index; if (cume < i) { while (i + 1 < d.length && !c(d[i], d[i + 1])) ++i; cume = i; } return (1 + cume) / d.length; } }; }, ntile: function(field, num) { num = +num; if (!(num > 0)) error('ntile num must be greater than zero.'); const cume = WindowOps.cume_dist(), next = cume.next; return { init: cume.init, next: w => Math.ceil(num * next(w)) }; }, lag: function(field, offset) { offset = +offset || 1; return { next: w => { const i = w.index - offset; return i >= 0 ? field(w.data[i]) : null; } }; }, lead: function(field, offset) { offset = +offset || 1; return { next: w => { const i = w.index + offset, d = w.data; return i < d.length ? field(d[i]) : null; } }; }, first_value: function(field) { return { next: w => field(w.data[w.i0]) }; }, last_value: function(field) { return { next: w => field(w.data[w.i1 - 1]) }; }, nth_value: function(field, nth) { nth = +nth; if (!(nth > 0)) error('nth_value nth must be greater than zero.'); return { next: w => { const i = w.i0 + (nth - 1); return i < w.i1 ? field(w.data[i]) : null; } }; }, prev_value: function(field) { let prev; return { init: () => prev = null, next: w => { const v = field(w.data[w.index]); return v != null ? (prev = v) : prev; } }; }, next_value: function(field) { let v, i; return { init: () => (v = null, i = -1), next: w => { const d = w.data; return w.index <= i ? v : (i = find(field, d, w.index)) < 0 ? (i = d.length, v = null) : (v = field(d[i])); } }; } }; function find(field, data, index) { for (let n = data.length; index < n; ++index) { const v = field(data[index]); if (v != null) return index; } return -1; } export const ValidWindowOps = Object.keys(WindowOps);