Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add extent transform #8940

Merged
merged 19 commits into from
Jun 20, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions build/vega-lite-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -8744,6 +8744,23 @@
],
"type": "object"
},
"ExtentTransform": {
"additionalProperties": false,
"properties": {
"extent": {
"$ref": "#/definitions/FieldName",
"description": "The field of which to get the extent."
},
"param": {
"$ref": "#/definitions/ParameterName",
"description": "The output parameter produced by the extent transform. __Default value:__ `\"extent\"`"
}
},
"required": [
"extent"
],
"type": "object"
},
"FacetEncodingFieldDef": {
"additionalProperties": false,
"properties": {
Expand Down Expand Up @@ -30190,6 +30207,9 @@
{
"$ref": "#/definitions/DensityTransform"
},
{
"$ref": "#/definitions/ExtentTransform"
},
{
"$ref": "#/definitions/FilterTransform"
},
Expand Down
Binary file added examples/compiled/bar_simple_extent.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/bar_simple_extent.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
151 changes: 151 additions & 0 deletions examples/compiled/bar_simple_extent.vg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"background": "white",
"padding": 5,
"width": 200,
"title": {
"text": "A Simple Bar Chart with Lines at Extents",
"frame": "group"
},
"style": "cell",
"data": [
{
"name": "source_0",
"values": [
{"a": "A", "b": 28},
{"a": "B", "b": 55},
{"a": "C", "b": 43},
{"a": "D", "b": 91},
{"a": "E", "b": 81},
{"a": "F", "b": 53},
{"a": "G", "b": 19},
{"a": "H", "b": 87},
{"a": "I", "b": 52}
]
},
{
"name": "data_0",
"source": "source_0",
"transform": [{"type": "extent", "field": "b", "signal": "extent"}]
},
{
"name": "data_1",
"source": "data_0",
"transform": [
{
"type": "stack",
"groupby": ["a"],
"field": "b",
"sort": {"field": [], "order": []},
"as": ["b_start", "b_end"],
"offset": "zero"
},
{
"type": "filter",
"expr": "isValid(datum[\"b\"]) && isFinite(+datum[\"b\"])"
}
]
}
],
"signals": [
{"name": "y_step", "value": 20},
{
"name": "height",
"update": "bandspace(domain('y').length, 0.1, 0.05) * y_step"
}
],
"marks": [
{
"name": "layer_0_marks",
"type": "rect",
"style": ["bar"],
"from": {"data": "data_1"},
"encode": {
"update": {
"fill": {"value": "#4c78a8"},
"ariaRoleDescription": {"value": "bar"},
"description": {
"signal": "\"b: \" + (format(datum[\"b\"], \"\")) + \"; a: \" + (isValid(datum[\"a\"]) ? datum[\"a\"] : \"\"+datum[\"a\"])"
},
"x": {"scale": "x", "field": "b_end"},
"x2": {"scale": "x", "field": "b_start"},
"y": {"scale": "y", "field": "a"},
"height": {"signal": "max(0.25, bandwidth('y'))"}
}
}
},
{
"name": "layer_1_marks",
"type": "rule",
"style": ["rule"],
"from": {"data": "data_0"},
"encode": {
"update": {
"stroke": {"value": "firebrick"},
"x": {"signal": "scale('x', extent[0])"},
"y": {"value": 0},
"y2": {"field": {"group": "height"}}
}
}
},
{
"name": "layer_2_marks",
"type": "rule",
"style": ["rule"],
"from": {"data": "data_0"},
"encode": {
"update": {
"stroke": {"value": "#ca8861"},
"x": {"signal": "scale('x', extent[1])"},
"y": {"value": 0},
"y2": {"field": {"group": "height"}}
}
}
}
],
"scales": [
{
"name": "x",
"type": "linear",
"domain": {"data": "data_1", "fields": ["b_start", "b_end"]},
"range": [0, {"signal": "width"}],
"nice": true,
"zero": true
},
{
"name": "y",
"type": "band",
"domain": {"data": "data_1", "field": "a", "sort": true},
"range": {"step": {"signal": "y_step"}},
"paddingInner": 0.1,
"paddingOuter": 0.05
}
],
"axes": [
{
"scale": "x",
"orient": "bottom",
"gridScale": "y",
"grid": true,
"tickCount": {"signal": "ceil(width/40)"},
"domain": false,
"labels": false,
"aria": false,
"maxExtent": 0,
"minExtent": 0,
"ticks": false,
"zindex": 0
},
{
"scale": "x",
"orient": "bottom",
"grid": false,
"title": "b",
"labelFlush": true,
"labelOverlap": true,
"tickCount": {"signal": "ceil(width/40)"},
"zindex": 0
},
{"scale": "y", "orient": "left", "grid": false, "title": "a", "zindex": 0}
]
}
33 changes: 33 additions & 0 deletions examples/specs/bar_simple_extent.vl.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"title": "A Simple Bar Chart with Lines at Extents",
"data": {
"values": [
{"a": "A", "b": 28}, {"a": "B", "b": 55}, {"a": "C", "b": 43},
{"a": "D", "b": 91}, {"a": "E", "b": 81}, {"a": "F", "b": 53},
{"a": "G", "b": 19}, {"a": "H", "b": 87}, {"a": "I", "b": 52}
]
},
"transform": [{"extent": "b"}],
"layer": [
{
"mark": "bar",
"encoding": {
"y": {"field": "a", "type": "nominal"},
"x": {"field": "b", "type": "quantitative"}
}
},
{
"mark": {"type": "rule", "stroke": "firebrick"},
"encoding": {
"x": {"value": {"expr": "scale('x', extent[0])"}}
}
},
{
"mark": {"type": "rule", "stroke": "#ca8861"},
"encoding": {
"x": {"value": {"expr": "scale('x', extent[1])"}}
}
}
]
}
59 changes: 59 additions & 0 deletions site/docs/transform/extent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
layout: docs
menu: docs
title: Extent
permalink: /docs/extent.html
---

The extent transform finds the extent of a field and stores the result in a [parameter]({{site.baseurl}}/docs/parameter.html).

```js
// Any View Specification
{
...
"transform": [
{"extent": ...} // Fold Transform
...
],
...
}
```

## Fold Transform Definition
lsh marked this conversation as resolved.
Show resolved Hide resolved

{% include table.html props="extent,param" source="ExtentTransform" %}

## Usage

Given the following data:

```json
"data": {
"values": [
{"a": "A", "b": 28}, {"a": "B", "b": 55}, {"a": "C", "b": 43},
{"a": "D", "b": 91}, {"a": "E", "b": 81}, {"a": "F", "b": 53},
{"a": "G", "b": 19}, {"a": "H", "b": 87}, {"a": "I", "b": 52}
]
}
```

And the transform:

```json
"transform": [
{"extent": "b"}
]
```

this example produces the output `param` will look like:
lsh marked this conversation as resolved.
Show resolved Hide resolved

```json
{
"name": "extent",
"value": [19, 91]
}
```

## Example

<div class="vl-example" data-name="bar_simple_extent"></div>
1 change: 1 addition & 0 deletions site/docs/transform/transform.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ The View-level `transform` object is an array of objects describing transformati
- [Bin](bin.html#transform)
- [Calculate](calculate.html)
- [Density](density.html)
- [Extent](extent.html)
- [Filter](filter.html)
- [Flatten](flatten.html)
- [Fold](fold.html)
Expand Down
4 changes: 3 additions & 1 deletion src/compile/data/assemble.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {BinNode} from './bin';
import {CalculateNode} from './calculate';
import {DataFlowNode, OutputNode} from './dataflow';
import {DensityTransformNode} from './density';
import {ExtentTransformNode} from './extent';
import {FacetNode} from './facet';
import {FilterNode} from './filter';
import {FilterInvalidNode} from './filterinvalid';
Expand Down Expand Up @@ -106,7 +107,8 @@ function makeWalkTree(data: VgData[]) {
node instanceof RegressionTransformNode ||
node instanceof IdentifierNode ||
node instanceof SampleTransformNode ||
node instanceof PivotTransformNode
node instanceof PivotTransformNode ||
node instanceof ExtentTransformNode
) {
dataSource.transform.push(node.assemble());
}
Expand Down
42 changes: 42 additions & 0 deletions src/compile/data/extent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {ExtentTransform as VgExtentTransform} from 'vega';
import {ExtentTransform} from '../../transform';
import {duplicate, hash} from '../../util';
import {DataFlowNode} from './dataflow';

/**
* A class for flatten transform nodes
lsh marked this conversation as resolved.
Show resolved Hide resolved
*/
export class ExtentTransformNode extends DataFlowNode {
public clone() {
return new ExtentTransformNode(null, duplicate(this.transform));
}

constructor(parent: DataFlowNode, private transform: ExtentTransform) {
super(parent);
this.transform = duplicate(transform); // duplicate to prevent side effects
const specifiedParam = this.transform.param;
this.transform.param = specifiedParam ?? 'extent';
}

public dependentFields() {
return new Set([this.transform.extent]);
}

public producedFields() {
return new Set([this.transform.param]);
lsh marked this conversation as resolved.
Show resolved Hide resolved
}

public hash() {
return `ExtentTransform ${hash(this.transform)}`;
}

public assemble(): VgExtentTransform {
const {extent, param} = this.transform;
const result: VgExtentTransform = {
type: 'extent',
field: extent,
signal: param
};
return result;
}
}
5 changes: 5 additions & 0 deletions src/compile/data/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
isBin,
isCalculate,
isDensity,
isExtent,
isFilter,
isFlatten,
isFold,
Expand All @@ -40,6 +41,7 @@ import {BinNode} from './bin';
import {CalculateNode} from './calculate';
import {DataFlowNode, OutputNode} from './dataflow';
import {DensityTransformNode} from './density';
import {ExtentTransformNode} from './extent';
import {FacetNode} from './facet';
import {FilterNode} from './filter';
import {FilterInvalidNode} from './filterinvalid';
Expand Down Expand Up @@ -203,6 +205,9 @@ export function parseTransformArray(head: DataFlowNode, model: Model, ancestorPa
} else if (isFold(t)) {
transformNode = head = new FoldTransformNode(head, t);
derivedType = 'derived';
} else if (isExtent(t)) {
transformNode = head = new ExtentTransformNode(head, t);
derivedType = 'derived';
} else if (isFlatten(t)) {
transformNode = head = new FlattenTransformNode(head, t);
derivedType = 'derived';
Expand Down
Loading