Skip to content

Commit

Permalink
add sma to encoding and update transform schema
Browse files Browse the repository at this point in the history
  • Loading branch information
julieg18 committed Feb 13, 2024
1 parent 3b60571 commit 8f56013
Show file tree
Hide file tree
Showing 15 changed files with 411 additions and 41 deletions.
61 changes: 55 additions & 6 deletions build/vega-lite-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@
},
{
"$ref": "#/definitions/ArgminDef"
},
{
"$ref": "#/definitions/ExponentialDef"
}
]
},
"AggregateFieldOp": {
"anyOf": [
{
"$ref": "#/definitions/NonArgAggregateFieldOp"
},
{
"$ref": "#/definitions/ExponentialDef"
}
]
},
Expand Down Expand Up @@ -71,10 +84,6 @@
"AggregatedFieldDef": {
"additionalProperties": false,
"properties": {
"aggregate_param": {
"description": "A parameter that can be passed to aggregation functions. The aggregation operation `\"exponential\"` requires it.",
"type": "number"
},
"as": {
"$ref": "#/definitions/FieldName",
"description": "The output field names to use for each aggregated field."
Expand All @@ -84,7 +93,7 @@
"description": "The data field for which to compute aggregate function. This is required for all aggregation operations except `\"count\"`."
},
"op": {
"$ref": "#/definitions/AggregateOp",
"$ref": "#/definitions/AggregateFieldOp",
"description": "The aggregation operation to apply to the fields (e.g., `\"sum\"`, `\"average\"`, or `\"count\"`). See the [full list of supported aggregation operations](https://vega.github.io/vega-lite/docs/aggregate.html#ops) for more information."
}
},
Expand Down Expand Up @@ -8801,6 +8810,18 @@
],
"type": "string"
},
"ExponentialDef": {
"additionalProperties": false,
"properties": {
"exponential": {
"type": "number"
}
},
"required": [
"exponential"
],
"type": "object"
},
"Expr": {
"type": "string"
},
Expand Down Expand Up @@ -17866,6 +17887,35 @@
],
"type": "object"
},
"NonArgAggregateFieldOp": {
"enum": [
"argmax",
"argmin",
"average",
"count",
"distinct",
"max",
"mean",
"median",
"min",
"missing",
"product",
"q1",
"q3",
"ci0",
"ci1",
"stderr",
"stdev",
"stdevp",
"sum",
"valid",
"values",
"variance",
"variancep",
"exponentialb"
],
"type": "string"
},
"NonArgAggregateOp": {
"enum": [
"average",
Expand All @@ -17889,7 +17939,6 @@
"values",
"variance",
"variancep",
"exponential",
"exponentialb"
],
"type": "string"
Expand Down
Binary file added examples/compiled/layer_line_exponential.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions examples/compiled/layer_line_exponential.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
137 changes: 137 additions & 0 deletions examples/compiled/layer_line_exponential.vg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"background": "white",
"padding": 5,
"width": 400,
"height": 200,
"style": "cell",
"data": [
{
"name": "source_0",
"values": [
{"price": 9.2, "year": 2020},
{"price": 10.76, "year": 2020},
{"price": 36.88, "year": 2021},
{"price": 3.44, "year": 2021},
{"price": 10.55, "year": 2022},
{"price": 9.65, "year": 2022},
{"price": 7.15, "year": 2023},
{"price": 15, "year": 2023},
{"price": 10.19, "year": 2024},
{"price": 8.86, "year": 2024}
]
},
{
"name": "data_0",
"source": "source_0",
"transform": [
{
"type": "aggregate",
"groupby": ["year"],
"ops": ["exponential", "mean"],
"fields": ["price", "price"],
"as": ["exponential_price", "mean_price"],
"aggregate_params": [0.5, null]
}
]
}
],
"marks": [
{
"name": "layer_0_marks",
"type": "line",
"style": ["line"],
"sort": {"field": "datum[\"year\"]"},
"from": {"data": "data_0"},
"encode": {
"update": {
"stroke": {"value": "#4c78a8"},
"description": {
"signal": "\"year: \" + (isValid(datum[\"year\"]) ? datum[\"year\"] : \"\"+datum[\"year\"]) + \"; Avg Price: \" + (format(datum[\"mean_price\"], \"\"))"
},
"x": {"scale": "x", "field": "year"},
"y": {"scale": "y", "field": "mean_price"},
"defined": {
"signal": "isValid(datum[\"mean_price\"]) && isFinite(+datum[\"mean_price\"])"
}
}
}
},
{
"name": "layer_1_marks",
"type": "line",
"style": ["line"],
"sort": {"field": "datum[\"year\"]"},
"from": {"data": "data_0"},
"encode": {
"update": {
"opacity": {"value": 0.5},
"stroke": {"value": "#4c78a8"},
"description": {
"signal": "\"year: \" + (isValid(datum[\"year\"]) ? datum[\"year\"] : \"\"+datum[\"year\"]) + \"; Exponential of price: \" + (format(datum[\"exponential_price\"], \"\"))"
},
"x": {"scale": "x", "field": "year"},
"y": {"scale": "y", "field": "exponential_price"},
"defined": {
"signal": "isValid(datum[\"exponential_price\"]) && isFinite(+datum[\"exponential_price\"])"
}
}
}
}
],
"scales": [
{
"name": "x",
"type": "point",
"domain": {"data": "data_0", "field": "year", "sort": true},
"range": [0, {"signal": "width"}],
"padding": 0.5
},
{
"name": "y",
"type": "linear",
"domain": {
"data": "data_0",
"fields": ["mean_price", "exponential_price"]
},
"range": [{"signal": "height"}, 0],
"nice": true,
"zero": true
}
],
"axes": [
{
"scale": "y",
"orient": "left",
"gridScale": "x",
"grid": true,
"tickCount": {"signal": "ceil(height/40)"},
"domain": false,
"labels": false,
"aria": false,
"maxExtent": 0,
"minExtent": 0,
"ticks": false,
"zindex": 0
},
{
"scale": "x",
"orient": "bottom",
"grid": false,
"title": "year",
"labelAlign": "right",
"labelAngle": 270,
"labelBaseline": "middle",
"zindex": 0
},
{
"scale": "y",
"orient": "left",
"grid": false,
"title": "Avg Price",
"labelOverlap": true,
"tickCount": {"signal": "ceil(height/40)"},
"zindex": 0
}
]
}
52 changes: 52 additions & 0 deletions examples/specs/layer_line_exponential.vl.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"width": 400,
"data": {
"values": [
{"price": 9.2, "year": 2020},
{"price": 10.76, "year": 2020},
{"price": 36.88, "year": 2021},
{"price": 3.44, "year": 2021},
{"price": 10.55, "year": 2022},
{"price": 9.65, "year": 2022},
{"price": 7.15, "year": 2023},
{"price": 15.0, "year": 2023},
{"price": 10.19, "year": 2024},
{"price": 8.86, "year": 2024}
]
},
"layer": [
{
"mark": "line",
"encoding": {
"x": {
"field": "year"
},
"y": {
"field": "price",
"aggregate": "mean",
"type": "quantitative",
"title": "Avg Price"
}
}
},
{
"mark": {
"type": "line",
"opacity": 0.5
},
"encoding": {
"x": {
"field": "year"
},
"y": {
"field": "price",
"aggregate": {
"exponential": 0.5
},
"type": "quantitative"
}
}
}
]
}
12 changes: 10 additions & 2 deletions site/docs/transform/aggregate.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ An `aggregate` transform in the [`transform`](transform.html) array has the foll

### Aggregated Field Definition for Aggregate Transform

{% include table.html props="op,field,as,aggregate_param" source="AggregatedFieldDef" %}
{% include table.html props="op,field,as" source="AggregatedFieldDef" %}

Note: It is important you [`parse`](data.html#format) your data types explicitly, especially if you are likely to have `null` values in your dataset and automatic type inference will fail.

Expand Down Expand Up @@ -121,7 +121,7 @@ The supported **aggregation operations** are:
| max | The maximum field value. |
| argmin | An input data object containing the minimum field value. <br/> **Note:** When used inside encoding, `argmin` must be specified as an object. (See below for an example.) |
| argmax | An input data object containing the maximum field value. <br/> **Note:** When used inside encoding, `argmax` must be specified as an object. (See below for an example.) |
| exponential | The exponential moving average of field values. Set the required weight (a number between `0` and `1`) with [`aggregate_param`](#aggregate-op-def). <br/> **Note:** Cannot be used inside encoding. |
| exponential | The exponential moving average of field values. <br/> **Note:** `exponential` must be specified as an object. (See below for an example.) |

{:#argmax}

Expand All @@ -142,3 +142,11 @@ This is equivalent to specifying argmax in an aggregate transform and encode its
`argmax` can be useful for getting the last value in a line for label placement.

<span class="vl-example" data-name="line_color_label"></span>

## Exponential

You can use the exponential aggregate to get the exponential moving average of a field, which forms a smooth alternative to a simple moving average. It is commonly used when you want to more heavily weigh recent values, but don't want a discontinuous drop-off when numbers drop out of an averaging window.

The exponential operation can be specified by setting it to an object with `exponential` describing the weight (a number between 0 and 1) to use in the transformation.

<div class="vl-example" data-name="layer_line_exponential"></div>
14 changes: 11 additions & 3 deletions src/aggregate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,13 @@ export interface ArgmaxDef {
argmax: FieldName;
}

export type NonArgAggregateOp = Exclude<AggregateOp, 'argmin' | 'argmax'>;
export interface ExponentialDef {
exponential: number;
}

export type NonArgAggregateOp = Exclude<AggregateOp, 'argmin' | 'argmax' | 'exponential'>;

export type Aggregate = NonArgAggregateOp | ArgmaxDef | ArgminDef;
export type Aggregate = NonArgAggregateOp | ArgmaxDef | ArgminDef | ExponentialDef;

export function isArgminDef(a: Aggregate | string): a is ArgminDef {
return !!a && !!a['argmin'];
Expand All @@ -57,7 +61,11 @@ export function isArgmaxDef(a: Aggregate | string): a is ArgmaxDef {
return !!a && !!a['argmax'];
}

export function isAggregateOp(a: string | ArgminDef | ArgmaxDef): a is AggregateOp {
export function isExponentialDef(a: Aggregate | string): a is ExponentialDef {
return !!a && !!a['exponential'];
}

export function isAggregateOp(a: string | ArgminDef | ArgmaxDef | ExponentialDef): a is AggregateOp {
return isString(a) && !!AGGREGATE_OP_INDEX[a];
}

Expand Down
Loading

0 comments on commit 8f56013

Please sign in to comment.