Skip to content

Commit

Permalink
Correctly generate as for nested fields. Note that in Vega as can…
Browse files Browse the repository at this point in the history
…not be nested so you have to provide a field name, not a field accessor. Fixes #3744 (#4023)
  • Loading branch information
kanitw authored Jul 15, 2018
1 parent 31ea661 commit 2085ac0
Show file tree
Hide file tree
Showing 16 changed files with 257 additions and 39 deletions.
1 change: 1 addition & 0 deletions examples/compiled/test_aggregate_nested.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
166 changes: 166 additions & 0 deletions examples/compiled/test_aggregate_nested.vg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
{
"$schema": "https://vega.github.io/schema/vega/v4.json",
"autosize": "pad",
"padding": 5,
"width": 200,
"style": "cell",
"data": [
{
"name": "source_0",
"values": {
"features": [
{
"properties": {
"variety": "Manchuria",
"yield": 27,
"site": "University Farm"
}
},
{
"properties": {
"variety": "Wisconsin No. 38",
"yield": 29.33333,
"site": "Duluth"
}
}
],
"type": "FeatureCollection"
},
"format": {"type": "json", "property": "features"}
},
{
"name": "data_0",
"source": "source_0",
"transform": [
{
"type": "formula",
"expr": "datum[\"properties\"] && datum[\"properties\"][\"variety\"]",
"as": "properties.variety"
},
{
"type": "formula",
"expr": "toNumber(datum[\"properties\"] && datum[\"properties\"][\"yield\"])",
"as": "properties.yield"
},
{
"type": "formula",
"expr": "datum[\"properties\"] && datum[\"properties\"][\"site\"]",
"as": "properties.site"
},
{
"type": "aggregate",
"groupby": ["properties\\.variety", "properties\\.site"],
"ops": ["sum"],
"fields": ["properties\\.yield"],
"as": ["sum_properties.yield"]
},
{
"type": "stack",
"groupby": ["properties\\.variety"],
"field": "sum_properties\\.yield",
"sort": {"field": ["properties\\.site"], "order": ["descending"]},
"as": ["sum_properties.yield_start", "sum_properties.yield_end"],
"offset": "zero"
}
]
}
],
"signals": [
{"name": "y_step", "value": 21},
{
"name": "height",
"update": "bandspace(domain('y').length, 0.1, 0.05) * y_step"
}
],
"marks": [
{
"name": "marks",
"type": "rect",
"style": ["bar"],
"from": {"data": "data_0"},
"encode": {
"update": {
"fill": {"scale": "color", "field": "properties\\.site"},
"tooltip": {
"signal": "{\"Sum of properties.yield\": format(datum[\"sum_properties.yield\"], \"\"), \"properties.variety\": ''+datum[\"properties.variety\"], \"site\": ''+datum[\"properties.site\"]}"
},
"x": {"scale": "x", "field": "sum_properties\\.yield_end"},
"x2": {"scale": "x", "field": "sum_properties\\.yield_start"},
"y": {"scale": "y", "field": "properties\\.variety"},
"height": {"scale": "y", "band": true}
}
}
}
],
"scales": [
{
"name": "x",
"type": "linear",
"domain": {
"data": "data_0",
"fields": ["sum_properties\\.yield_start", "sum_properties\\.yield_end"]
},
"range": [0, {"signal": "width"}],
"nice": true,
"zero": true
},
{
"name": "y",
"type": "band",
"domain": {
"data": "data_0",
"field": "properties\\.variety",
"sort": true
},
"range": {"step": {"signal": "y_step"}},
"paddingInner": 0.1,
"paddingOuter": 0.05
},
{
"name": "color",
"type": "ordinal",
"domain": {"data": "data_0", "field": "properties\\.site", "sort": true},
"range": "category"
}
],
"axes": [
{
"scale": "x",
"orient": "bottom",
"grid": false,
"title": "Sum of properties.yield",
"labelFlush": true,
"labelOverlap": true,
"tickCount": {"signal": "ceil(width/40)"},
"zindex": 1
},
{
"scale": "x",
"orient": "bottom",
"grid": true,
"gridScale": "y",
"tickCount": {"signal": "ceil(width/40)"},
"domain": false,
"labels": false,
"maxExtent": 0,
"minExtent": 0,
"ticks": false,
"zindex": 0
},
{
"scale": "y",
"orient": "left",
"grid": false,
"title": "properties.variety",
"zindex": 1
}
],
"legends": [
{
"title": "site",
"fill": "color",
"encode": {"symbols": {"update": {"shape": {"value": "square"}}}}
}
],
"config": {"axisY": {"minExtent": 30}}
}
36 changes: 36 additions & 0 deletions examples/specs/test_aggregate_nested.vl.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{

"$schema": "https://vega.github.io/schema/vega-lite/v2.json",
"mark": "bar",
"encoding": {
"y": { "field": "properties.variety", "type": "nominal"},
"x": {
"aggregate": "sum",
"field": "properties.yield",
"type": "quantitative"
},
"color": {"title": "site", "field": "properties.site", "type": "nominal"}
},
"data": {
"values": {
"features": [
{
"properties": {
"variety": "Manchuria",
"yield": 27,
"site": "University Farm"
}
},
{
"properties": {
"variety": "Wisconsin No. 38",
"yield": 29.33333,
"site": "Duluth"
}
}
],
"type": "FeatureCollection"
},
"format": {"type": "json", "property": "features"}
}
}
16 changes: 8 additions & 8 deletions src/compile/data/aggregate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {Channel, isScaleChannel} from '../../channel';
import {FieldDef, vgField} from '../../fielddef';
import * as log from '../../log';
import {AggregateTransform} from '../../transform';
import {Dict, differ, duplicate, keys, StringSet} from '../../util';
import {Dict, differ, duplicate, keys, replacePathInField, StringSet} from '../../util';
import {VgAggregateTransform} from '../../vega.schema';
import {binRequiresRange} from '../common';
import {UnitModel} from './../unit';
Expand Down Expand Up @@ -81,15 +81,15 @@ export class AggregateNode extends DataFlowNode {
if (aggregate) {
if (aggregate === 'count') {
meas['*'] = meas['*'] || {};
meas['*']['count'] = vgField(fieldDef);
meas['*']['count'] = vgField(fieldDef, {forAs: true});
} else {
meas[field] = meas[field] || {};
meas[field][aggregate] = vgField(fieldDef);
meas[field][aggregate] = vgField(fieldDef, {forAs: true});

// For scale channel with domain === 'unaggregated', add min/max so we can use their union as unaggregated domain
if (isScaleChannel(channel) && model.scaleDomain(channel) === 'unaggregated') {
meas[field]['min'] = vgField({field, aggregate: 'min'});
meas[field]['max'] = vgField({field, aggregate: 'max'});
meas[field]['min'] = vgField({field, aggregate: 'min'}, {forAs: true});
meas[field]['max'] = vgField({field, aggregate: 'max'}, {forAs: true});
}
}
} else {
Expand All @@ -113,10 +113,10 @@ export class AggregateNode extends DataFlowNode {
if (op) {
if (op === 'count') {
meas['*'] = meas['*'] || {};
meas['*']['count'] = as || vgField(s);
meas['*']['count'] = as || vgField(s, {forAs: true});
} else {
meas[field] = meas[field] || {};
meas[field][op] = as || vgField(s);
meas[field][op] = as || vgField(s, {forAs: true});
}
}
}
Expand Down Expand Up @@ -175,7 +175,7 @@ export class AggregateNode extends DataFlowNode {
for (const op of keys(this.measures[field])) {
as.push(this.measures[field][op]);
ops.push(op);
fields.push(field);
fields.push(replacePathInField(field));
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/compile/data/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function rangeFormula(model: ModelWithField, fieldDef: FieldDef<string>, channel
const endField = vgField(fieldDef, {expr: 'datum', binSuffix: 'end'});

return {
formulaAs: vgField(fieldDef, {binSuffix: 'range'}),
formulaAs: vgField(fieldDef, {binSuffix: 'range', forAs: true}),
formula: binFormatExpression(startField, endField, guide.format, config)
};
}
Expand Down Expand Up @@ -48,7 +48,7 @@ function createBinComponent(t: FieldDef<string> | BinTransform, bin: boolean | B
if (isBinTransform(t)) {
as = isString(t.as) ? [t.as, `${t.as}_end`] : [t.as[0], t.as[1]];
} else {
as = [vgField(t, {}), vgField(t, {binSuffix: 'end'})];
as = [vgField(t, {forAs: true}), vgField(t, {binSuffix: 'end', forAs: true})];
}

const normalizedBin = normalizeBin(bin, undefined) || {};
Expand Down
7 changes: 4 additions & 3 deletions src/compile/data/calculate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {duplicate} from '../../util';
import {VgFormulaTransform} from '../../vega.schema';
import {ModelWithField} from '../model';
import {SingleDefChannel} from './../../channel';
import {FieldRefOption} from './../../fielddef';
import {CalculateTransform} from './../../transform';
import {DataFlowNode} from './dataflow';

Expand Down Expand Up @@ -40,7 +41,7 @@ export class CalculateNode extends DataFlowNode {

parent = new CalculateNode(parent, {
calculate,
as: sortArrayIndexField(fieldDef, channel)
as: sortArrayIndexField(fieldDef, channel, {forAs: true})
});
}
});
Expand All @@ -62,6 +63,6 @@ export class CalculateNode extends DataFlowNode {
}
}

export function sortArrayIndexField(fieldDef: FieldDef<string>, channel: SingleDefChannel, expr?: 'datum') {
return vgField(fieldDef, {prefix: channel, suffix: 'sort_index', expr});
export function sortArrayIndexField(fieldDef: FieldDef<string>, channel: SingleDefChannel, opt?: FieldRefOption) {
return vgField(fieldDef, {prefix: channel, suffix: 'sort_index', ...(opt || {})});
}
2 changes: 1 addition & 1 deletion src/compile/data/facet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export class FacetNode extends DataFlowNode {
const {op, field} = sortField;
fields.push(field);
ops.push(op);
as.push(vgField(sortField));
as.push(vgField(sortField, {forAs: true}));
} else if (sortIndexField) {
fields.push(sortIndexField);
ops.push('max');
Expand Down
16 changes: 7 additions & 9 deletions src/compile/data/stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,19 +147,19 @@ export class StackNode extends DataFlowNode {
{field: [], order: []}
);
}
// Refactored to add "as" in the make phase so that we can get producedFields
// from the as property
const field = model.vgField(stackProperties.fieldChannel);

return new StackNode(parent, {
dimensionFieldDef,
stackField: field,
stackField: model.vgField(stackProperties.fieldChannel),
facetby: [],
stackby,
sort,
offset: stackProperties.offset,
impute: stackProperties.impute,
as: [field + '_start', field + '_end']
as: [
model.vgField(stackProperties.fieldChannel, {suffix: 'start', forAs: true}),
model.vgField(stackProperties.fieldChannel, {suffix: 'end', forAs: true})
]
});
}

Expand Down Expand Up @@ -217,8 +217,6 @@ export class StackNode extends DataFlowNode {

// Impute
if (impute && dimensionFieldDef) {
const dimensionField = dimensionFieldDef ? vgField(dimensionFieldDef, {binSuffix: 'mid'}) : undefined;

if (dimensionFieldDef.bin) {
// As we can only impute one field at a time, we need to calculate
// mid point for a binned field
Expand All @@ -230,15 +228,15 @@ export class StackNode extends DataFlowNode {
'+' +
vgField(dimensionFieldDef, {expr: 'datum', binSuffix: 'end'}) +
')/2',
as: dimensionField
as: vgField(dimensionFieldDef, {binSuffix: 'mid', forAs: true})
});
}

transform.push({
type: 'impute',
field,
groupby: stackby,
key: dimensionField,
key: vgField(dimensionFieldDef, {binSuffix: 'mid'}),
method: 'value',
value: 0
});
Expand Down
2 changes: 1 addition & 1 deletion src/compile/data/timeunit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export class TimeUnitNode extends DataFlowNode {
const formula = model.reduceFieldDef(
(timeUnitComponent: TimeUnitComponent, fieldDef) => {
if (fieldDef.timeUnit) {
const f = vgField(fieldDef);
const f = vgField(fieldDef, {forAs: true});
timeUnitComponent[f] = {
as: f,
timeUnit: fieldDef.timeUnit,
Expand Down
2 changes: 1 addition & 1 deletion src/compile/data/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export class WindowTransformNode extends DataFlowNode {
{
op,
field,
as: facetSortFieldName(fieldDef, fieldDef.sort)
as: facetSortFieldName(fieldDef, fieldDef.sort, {forAs: true})
}
],
groupby: [vgField(fieldDef)],
Expand Down
Loading

0 comments on commit 2085ac0

Please sign in to comment.