export function indataVisitor(name, args, scope, params) { if (args[0].type !== Literal) error('First argument to indata must be a string literal.'); if (args[1].type !== Literal) error('Second argument to indata must be a string literal.'); var data = args[0].value, field = args[1].value, indexName = indexPrefix + field; if (!params.hasOwnProperty(indexName)) { params[indexName] = scope.getData(data).indataRef(scope, field); } }
export default function(data, format) { var method, object, property; data = json(data, format); method = (format && (property = format.feature)) ? feature : (format && (property = format.mesh)) ? mesh : error('Missing TopoJSON feature or mesh parameter.'); object = (object = data.objects[property]) ? method(data, object) : error('Invalid TopoJSON object: ' + property); return object && object.features || [object]; }
function parseSort(sort, multidomain) { if (sort) { if (!sort.field && !sort.op) { if (isObject(sort)) sort.field = 'key'; else sort = {field: 'key'}; } else if (!sort.field && sort.op !== 'count') { error('No field provided for sort aggregate op: ' + sort.op); } else if (multidomain && sort.field) { error('Multiple domain scales can not sort by field.'); } else if (multidomain && sort.op && sort.op !== 'count') { error('Multiple domain scales support op count only.'); } } return sort; }
function dataref(view, name) { var data = view._runtime.data; if (!data.hasOwnProperty(name)) { error('Unrecognized data set: ' + name); } return data[name]; }
prototype.transform = function(_, pulse) { var sx = _.sourceX || sourceX, sy = _.sourceY || sourceY, tx = _.targetX || targetX, ty = _.targetY || targetY, orient = _.orient || 'vertical', shape = _.shape || 'line', path = PATHS.get(shape + '-' + orient) || PATHS.get(shape); if (!path) { error('LinkPath unsupported type: ' + _.shape + '-' + _.orient); } function set(t) { t.path = path(sx(t), sy(t), tx(t), ty(t)); } if (_.modified()) { pulse.visit(pulse.SOURCE, set).reflow(); } else { pulse.visit(pulse.ALL, set); } return pulse.modifies('path'); };
/** * Parse a parameter object for a probability distribution. * @param {object} def - The distribution parameter object. * @param {function():Array<object>} - A method for requesting * source data. Used for distributions (such as KDE) that * require sample data points. This method will only be * invoked if the 'from' parameter for a target data source * is not provided. Typically this method returns backing * source data for a Pulse object. * @return {object} - The output distribution object. */ export default function parse(def, data) { var func = def[FUNCTION]; if (!Distributions.hasOwnProperty(func)) { error('Unknown distribution function: ' + func); } var d = Distributions[func](); for (var name in def) { // if data field, extract values if (name === FIELD) { d.data((def.from || data()).map(def[name])); } // if distribution mixture, recurse to parse each definition else if (name === DISTRIBUTIONS) { d[name](def[name].map(function(_) { return parse(_, data); })); } // otherwise, simply set the parameter else if (typeof d[name] === FUNCTION) { d[name](def[name]); } } return d; }
function getForce(_) { var f, p; if (!FORCE_MAP.has(_.force)) error('Unrecognized force: ' + _.force); f = FORCE_MAP.get(_.force)(); for (p in _) if (isFunction(f[p])) f[p](_[p]); return f; }
prototype.transform = function(_, pulse) { if (!pulse.source) { error('Stratify transform requires an upstream data source.'); } var tree = this.value, mod = _.modified(), out = pulse.fork(pulse.ALL).materialize(pulse.SOURCE), run = !this.value || mod || pulse.changed(pulse.ADD_REM) || pulse.modified(_.key.fields) || pulse.modified(_.parentKey.fields); // prevent upstream source pollution out.source = out.source.slice(); if (run) { if (out.source.length) { tree = lookup( stratify().id(_.key).parentId(_.parentKey)(out.source) , _.key, truthy); } else { tree = lookup(stratify()([{}]), _.key, _.key); } } out.source.root = this.value = tree; return out; };
prototype.transform = function(_, pulse) { if (!pulse.source) { error('Rank transform requires an upstream data source.'); } var norm = _.normalize, field = _.field, ranks = {}, n = -1, rank; if (field) { // If we have a field accessor, first compile distinct keys. pulse.visit(pulse.SOURCE, function(t) { var v = field(t); if (ranks[v] == null) ranks[v] = ++n; }); pulse.visit(pulse.SOURCE, norm && --n ? function(t) { t.rank = ranks[field(t)] / n; } : function(t) { t.rank = ranks[field(t)]; } ); } else { n += pulse.source.length; rank = -1; // Otherwise rank all the tuples together. pulse.visit(pulse.SOURCE, norm && n ? function(t) { t.rank = ++rank / n; } : function(t) { t.rank = ++rank; } ); } return pulse.reflow().modifies('rank'); };
array(value).forEach(function(op) { if (!(op instanceof Operator)) { error('Pulse parameters must be operator instances.'); } else if (op !== self) { op.targets().add(self); deps.push(op); } });
export default function parseStream(stream, scope) { var method = stream.merge ? mergeStream : stream.stream ? nestedStream : stream.type ? eventStream : error('Invalid stream specification: ' + stringValue(stream)); return method(stream, scope); }
export function change(name, changes) { if (!isChangeSet(changes)) { error('Second argument to changes must be a changeset.'); } var dataset = dataref(this, name); dataset.modified = true; return this.pulse(dataset.input, changes); }
export function intersect(scene, bounds, filter) { const hits = [], // intersection results box = new Bounds().union(bounds), // defensive copy type = scene.marktype; return type ? intersectMark(scene, box, filter, hits) : type === 'group' ? intersectGroup(scene, box, filter, hits) : error('Intersect scene must be mark node or group item.'); }
prototype.renderer = function(type) { if (!arguments.length) return this._renderType; if (!renderModule(type)) error('Unrecognized renderer type: ' + type); if (type !== this._renderType) { this._renderType = type; this._resetRenderer(); } return this; };
/** * Render the current scene in a headless fashion. * This method is asynchronous, returning a Promise instance. * @return {Promise} - A Promise that resolves to a renderer. */ export default async function(view, type, scaleFactor, opt) { const module = renderModule(type), ctr = module && module.headless; if (!ctr) error('Unrecognized renderer type: ' + type); await view.runAsync(); return initializeRenderer(view, null, null, ctr, scaleFactor, opt) .renderAsync(view._scenegraph.root); }
spec.transform.forEach(function(_) { const tx = parseTransform(_, scope), md = tx.metadata; if (md.generates || md.changes) { error('Mark transforms should not generate new data.'); } if (!md.nomod) enc.params.mod = true; // update encode mod handling tx.params.pulse = ref(op); scope.add(op = tx); });
prototype.transform = function(_, pulse) { if (!pulse.source || !pulse.source.root) { error('TreeLinks transform requires a backing tree data source.'); } var root = pulse.source.root, nodes = root.lookup, links = this.value, key = _.key || tupleid, mods = {}, out = pulse.fork(); function modify(id) { var link = links[id]; if (link) { mods[id] = 1; out.mod.push(link); } } // process removed tuples // assumes that if a parent node is removed the child will be, too. pulse.visit(pulse.REM, function(t) { var id = key(t), link = links[id]; if (link) { delete links[id]; out.rem.push(link); } }); // create new link instances for added nodes with valid parents pulse.visit(pulse.ADD, function(t) { var id = key(t), p; if (p = parentTuple(nodes[id])) { out.add.push(links[id] = ingest({source: p, target: t})); mods[id] = 1; } }); // process modified nodes and their children pulse.visit(pulse.MOD, function(t) { var id = key(t), node = nodes[id], kids = node.children; modify(id); if (kids) for (var i=0, n=kids.length; i<n; ++i) { if (!mods[(id=key(kids[i].data))]) modify(id); } }); return out; };
function configureRangeStep(type, _, count) { if (type !== Band && type !== Point) { error('Only band and point scales support rangeStep.'); } // calculate full range based on requested step size and padding var outer = (_.paddingOuter != null ? _.paddingOuter : _.padding) || 0, inner = type === Point ? 1 : ((_.paddingInner != null ? _.paddingInner : _.padding) || 0); return [0, _.rangeStep * bandSpace(count, inner, outer)]; }
export function dataVisitor(name, args, scope, params) { if (args[0].type !== Literal) { error('First argument to data functions must be a string literal.'); } var data = args[0].value, dataName = dataPrefix + data; if (!params.hasOwnProperty(dataName)) { params[dataName] = scope.getData(data).tuplesRef(); } }
export default function topojson(data, format) { let method, object, property, filter; data = json(data, format); if (format && format.feature) { method = feature; property = format.feature; } else if (format && format.mesh) { method = mesh; property = format.mesh; filter = filters[format.filter]; } else { error('Missing TopoJSON feature or mesh parameter.'); } object = (object = data.objects[property]) ? method(data, object, filter) : error('Invalid TopoJSON object: ' + property); return object && object.features || [object]; }
export function initScale(spec, scope) { var type = spec.type || 'linear'; if (!allTypes.hasOwnProperty(type)) { error('Unrecognized scale type: ' + stringValue(type)); } scope.addScale(spec.name, { type: type, domain: undefined }); }
prototype.transform = function(_, pulse) { if (!pulse.source || !pulse.source.root) { error(this.constructor.name + ' transform requires a backing tree data source.'); } var layout = this.layout(_.method), root = pulse.source.root; if (_.field) root.sum(_.field); if (_.sort) root.sort(_.sort); this.setParams(layout, _); try { this.value = layout(root); } catch (err) { error(err); } root.each(this.setFields); return pulse.reflow().modifies(this.setParams.fields); // fork? };
export default function(data, schema, dateParse) { schema = schema || {}; var reader = formats(schema.type || 'json'); if (!reader) error('Unknown data format type: ' + schema.type); data = reader(data, schema); if (schema.parse) parse(data, schema.parse, dateParse); if (data.hasOwnProperty('columns')) delete data.columns; return data; }
function parseScaleDomain(domain, spec, scope) { if (!domain) { if (spec.domainMin != null || spec.domainMax != null) { error('No scale domain defined for domainMin/domainMax to override.'); } return; // default domain } return domain.signal ? scope.signalRef(domain.signal) : (isArray(domain) ? explicitDomain : domain.fields ? multipleDomain : singularDomain)(domain, spec, scope); }
export function vlSelectionVisitor(name, args, scope, params) { if (args[0].type !== Literal) error('First argument to indata must be a string literal.'); var data = args[0].value, op = args.length >= 2 && args[args.length-1].value, field = 'unit', indexName = indexPrefix + field; if (op === INTERSECT && !params.hasOwnProperty(indexName)) { params[indexName] = scope.getData(data).indataRef(scope, field); } dataVisitor(name, args, scope, params); }
export function rerank(op) { var queue = [op], cur, list, i; while (queue.length) { this.rank(cur = queue.pop()); if (list = cur._targets) { for (i=list.length; --i >= 0;) { queue.push(cur = list[i]); if (cur === op) error('Cycle detected in dataflow graph.'); } } } }
function parseScaleRange(spec, scope, params) { var range = spec.range, config = scope.config.range; if (range.signal) { return scope.signalRef(range.signal); } else if (isString(range)) { if (config && config.hasOwnProperty(range)) { spec = extend({}, spec, {range: config[range]}); return parseScaleRange(spec, scope, params); } else if (range === 'width') { range = [0, {signal: 'width'}] } else if (range === 'height') { range = isOrdinal(spec.type) ? [0, {signal: 'height'}] : [{signal: 'height'}, 0] } else { error('Unrecognized scale range value: ' + stringValue(range)); } } else if (range.scheme) { params.scheme = parseLiteral(range.scheme, scope); if (range.extent) params.schemeExtent = parseArray(range.extent, scope); if (range.count) params.schemeCount = parseLiteral(range.count, scope); return; } else if (range.step) { params.rangeStep = parseLiteral(range.step, scope); return; } else if (isOrdinal(spec.type) && !isArray(range)) { return parseScaleDomain(range, spec, scope); } else if (!isArray(range)) { error('Unsupported range type: ' + stringValue(range)); } return range.map(function(v) { return parseLiteral(v, scope); }); }
prototype.transform = function(_, pulse) { if (!pulse.source || !pulse.source.root) { error(this.constructor.name + ' transform requires a backing tree data source.'); } var layout = this.layout(_.method), fields = this.fields, root = pulse.source.root, as = _.as || fields; if (_.field) root.sum(_.field); if (_.sort) root.sort(_.sort); setParams(layout, this.params, _); try { this.value = layout(root); } catch (err) { error(err); } root.each(function(node) { setFields(node, fields, as); }); return pulse.reflow(_.modified()).modifies(as).modifies('leaf'); };
prototype.transform = function(_, pulse) { if (!pulse.source) { error('Nest transform requires an upstream data source.'); } var key = _.key || tupleid, gen = _.generate, mod = _.modified(), out = pulse.clone(), root, tree, map; if (!this.value || mod || pulse.changed()) { // collect nodes to remove if (gen && this.value) { this.value.each(function(node) { if (node.children) out.rem.push(node); }); } // generate new tree structure root = array(_.keys) .reduce(function(n, k) { n.key(k); return n; }, nest()) .entries(out.source); this.value = tree = hierarchy({values: root}, children); // collect nodes to add if (gen) { tree.each(function(node) { if (node.children) { node = ingest(node.data); out.add.push(node); out.source.push(node); } }); } // build lookup table map = tree.lookup = {}; tree.each(function(node) { if (tupleid(node.data) != null) { map[key(node.data)] = node; } }); } out.source.root = this.value; return out; };
export function tickCount(scale, count) { var step; if (isObject(count)) { step = count.step; count = count.interval; } if (isString(count)) { count = scale.type === 'time' ? timeInterval(count) : scale.type === 'utc' ? utcInterval(count) : error('Only time and utc scales accept interval strings.'); if (step) count = count.every(step); } return count; }