diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e74b7bfcba..a45dc8c871 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,7 +22,7 @@ You can find [tasks with the "Help wanted" label in the issue tracker](https://g ### Help Create New Examples -To submit a new example, fork our [example Block](https://bl.ocks.org/domoritz/455e1c7872c4b38a58b90df0c3d7b1b9) and send us a [pull request to add a link](https://github.com/vega/vega-lite/edit/master/site/examples/gallery.md) to it to our [example gallery](https://vega.github.io/vega-lite/examples/). +To submit a new example, fork our [example Block](https://bl.ocks.org/domoritz/455e1c7872c4b38a58b90df0c3d7b1b9) and send us a [pull request to add a link](https://github.com/vega/vega-lite/edit/master/site/examples/index.md) to it to our [example gallery](https://vega.github.io/vega-lite/examples/). ## Documentation and Website diff --git a/_data/link.yml b/_data/link.yml index 75e11b111c..c19c3f6d07 100644 --- a/_data/link.yml +++ b/_data/link.yml @@ -50,6 +50,8 @@ TimeUnit: link: timeunit.html LookupData: link: "lookup.html#lookup-data" +Window: + link: window.html # Transform - Time Unit Month: @@ -57,6 +59,14 @@ Month: Day: name: Number +# Transform - Window +WindowFieldDef: + link: window.html#field-def +WindowSortField: + link: window.html#sort-field-def +WindowOnlyOp: + link: window.html#ops + # Mark AnyMark: name: Mark diff --git a/_includes/docs_toc.md b/_includes/docs_toc.md index 44879bf926..a136b2e511 100644 --- a/_includes/docs_toc.md +++ b/_includes/docs_toc.md @@ -52,6 +52,12 @@ - [Time Unit in Encoding Field Definition]({{site.baseurl}}/docs/timeunit.html#encoding) - [Time Unit Transform]({{site.baseurl}}/docs/timeunit.html#transform) - [UTC time]({{site.baseurl}}/docs/timeunit.html#utc) + - [Window]({{site.baseurl}}/docs/window.html) + - [Window Field Definition]({{site.baseurl}}/docs/window.html#window-field-definition) + - [Window Transform Definition]({{site.baseurl}}/docs/window.html#window-transform-definition) + - [ + Window Only Operation Reference]({{site.baseurl}}/docs/window.html#-window-only-operation-reference) + - [Examples]({{site.baseurl}}/docs/window.html#examples) - [Mark]({{site.baseurl}}/docs/mark.html) - [Documentation Overview]({{site.baseurl}}/docs/mark.html#documentation-overview) - [Mark Definition Object]({{site.baseurl}}/docs/mark.html#mark-def) @@ -59,64 +65,51 @@ - [Mark Style Config]({{site.baseurl}}/docs/mark.html#style-config) - [Area]({{site.baseurl}}/docs/area.html) - [Documentation Overview]({{site.baseurl}}/docs/area.html#documentation-overview) - - [Area Chart]({{site.baseurl}}/docs/area.html#area-chart) - - [Stacked Area Chart]({{site.baseurl}}/docs/area.html#stacked-area-chart) - - [Normalized Stacked Area Chart]({{site.baseurl}}/docs/area.html#normalized-stacked-area-chart) - - [Streamgraph]({{site.baseurl}}/docs/area.html#streamgraph) - - [Ranged Area]({{site.baseurl}}/docs/area.html#ranged) + - [Area Mark Properties]({{site.baseurl}}/docs/area.html#properties) + - [Examples]({{site.baseurl}}/docs/area.html#examples) - [Area Config]({{site.baseurl}}/docs/area.html#config) - [Bar]({{site.baseurl}}/docs/bar.html) - [Documentation Overview]({{site.baseurl}}/docs/bar.html#documentation-overview) - - [Single Bar Chart]({{site.baseurl}}/docs/bar.html#single-bar-chart) - - [Bar Chart]({{site.baseurl}}/docs/bar.html#bar-chart) - - [Histogram]({{site.baseurl}}/docs/bar.html#histogram) - - [Stacked Bar Chart]({{site.baseurl}}/docs/bar.html#stack) - - [Layered Bar Chart]({{site.baseurl}}/docs/bar.html#layered-bar-chart) - - [Normalized Stacked Bar Chart]({{site.baseurl}}/docs/bar.html#normalized-stacked-bar-chart) - - [Grouped Bar Chart]({{site.baseurl}}/docs/bar.html#grouped-bar-chart) - - [Ranged Bars]({{site.baseurl}}/docs/bar.html#ranged) + - [Bar Mark Properties]({{site.baseurl}}/docs/bar.html#properties) + - [Examples]({{site.baseurl}}/docs/bar.html#examples) - [Bar Config]({{site.baseurl}}/docs/bar.html#config) - [Circle]({{site.baseurl}}/docs/circle.html) - - [Scatterplot with Circle]({{site.baseurl}}/docs/circle.html#scatterplot-with-circle) + - [Circle Mark Properties]({{site.baseurl}}/docs/circle.html#properties) + - [Examples]({{site.baseurl}}/docs/circle.html#examples) - [Circle Config]({{site.baseurl}}/docs/circle.html#config) - [Line]({{site.baseurl}}/docs/line.html) - [Documentation Overview]({{site.baseurl}}/docs/line.html#documentation-overview) - - [Line Chart]({{site.baseurl}}/docs/line.html#line-chart) - - [Multi-series Line Chart with the Detail Channel]({{site.baseurl}}/docs/line.html#line-detail) - - [Connected Scatter Plot (Line Chart with Custom Path)]({{site.baseurl}}/docs/line.html#connected-scatter-plot) - - [Line interpolation]({{site.baseurl}}/docs/line.html#line-interpolation) - - [Geo Line]({{site.baseurl}}/docs/line.html#geo-line) + - [Line Mark Properties]({{site.baseurl}}/docs/line.html#properties) + - [Examples]({{site.baseurl}}/docs/line.html#examples) - [Line Config]({{site.baseurl}}/docs/line.html#config) - [Point]({{site.baseurl}}/docs/point.html) - [Documentation Overview]({{site.baseurl}}/docs/point.html#documentation-overview) - - [Dot Plot]({{site.baseurl}}/docs/point.html#dot-plot) - - [Scatter Plot]({{site.baseurl}}/docs/point.html#scatter-plot) - - [Bubble Plot]({{site.baseurl}}/docs/point.html#bubble-plot) - - [Scatter Plot with Color and/or Shape]({{site.baseurl}}/docs/point.html#color) - - [Geo Point]({{site.baseurl}}/docs/point.html#geo-point) + - [Point Mark Properties]({{site.baseurl}}/docs/point.html#properties) + - [Examples]({{site.baseurl}}/docs/point.html#examples) - [Point Config]({{site.baseurl}}/docs/point.html#config) - [Rect]({{site.baseurl}}/docs/rect.html) - [Documentation Overview]({{site.baseurl}}/docs/rect.html#documentation-overview) + - [Rect Mark Properties]({{site.baseurl}}/docs/rect.html#rect-mark-properties) + - [Examples]({{site.baseurl}}/docs/rect.html#examples) - [Rect Config]({{site.baseurl}}/docs/rect.html#config) - [Rule]({{site.baseurl}}/docs/rule.html) - [Documentation Overview]({{site.baseurl}}/docs/rule.html#documentation-overview) - - [Width/Height-Spanning Rules]({{site.baseurl}}/docs/rule.html#widthheight-spanning-rules) - - [Ranged Rules]({{site.baseurl}}/docs/rule.html#ranged) + - [Rule Mark Properties]({{site.baseurl}}/docs/rule.html#properties) + - [Examples]({{site.baseurl}}/docs/rule.html#examples) - [Rule Config]({{site.baseurl}}/docs/rule.html#config) - [Square]({{site.baseurl}}/docs/square.html) - - [Scatterplot with Square]({{site.baseurl}}/docs/square.html#scatterplot-with-square) + - [Square Mark Properties]({{site.baseurl}}/docs/square.html#properties) + - [Example: Scatterplot with Square]({{site.baseurl}}/docs/square.html#example-scatterplot-with-square) - [Square Config]({{site.baseurl}}/docs/square.html#config) - [Text]({{site.baseurl}}/docs/text.html) - [Documentation Overview]({{site.baseurl}}/docs/text.html#documentation-overview) - - [Text Table Heatmap]({{site.baseurl}}/docs/text.html#text-table-heatmap) - - [Labels]({{site.baseurl}}/docs/text.html#labels) - - [Scatterplot with Text]({{site.baseurl}}/docs/text.html#scatterplot-with-text) - - [Geo Text]({{site.baseurl}}/docs/text.html#geo-text) + - [Text Mark Properties]({{site.baseurl}}/docs/text.html#properties) + - [Examples]({{site.baseurl}}/docs/text.html#examples) - [Text Config]({{site.baseurl}}/docs/text.html#config) - [Tick]({{site.baseurl}}/docs/tick.html) - [Documentation Overview]({{site.baseurl}}/docs/tick.html#documentation-overview) - - [Dot Plot]({{site.baseurl}}/docs/tick.html#dot-plot) - - [Strip Plot]({{site.baseurl}}/docs/tick.html#strip-plot) + - [Tick Mark Properties]({{site.baseurl}}/docs/tick.html#properties) + - [Examples]({{site.baseurl}}/docs/tick.html#examples) - [Tick Config]({{site.baseurl}}/docs/tick.html#config) - [Geoshape]({{site.baseurl}}/docs/geoshape.html) - [Geoshape Config]({{site.baseurl}}/docs/geoshape.html#config) diff --git a/_layouts/docs.html b/_layouts/docs.html index 0534fd144a..790a9b0e4f 100644 --- a/_layouts/docs.html +++ b/_layouts/docs.html @@ -30,6 +30,8 @@ url: lookup - text: Time Unit url: timeunit + - text: Window + url: window - text: Mark url: mark sub-sidebar: diff --git a/build/vega-lite-schema.json b/build/vega-lite-schema.json index ddbb87b4e4..4762a93060 100644 --- a/build/vega-lite-schema.json +++ b/build/vega-lite-schema.json @@ -7314,11 +7314,11 @@ "additionalProperties": false, "properties": { "as": { - "description": "The output name for each field. If none is defined will use the format op_field. For example, count_field for count,\n and sum_field for sum.", + "description": "The output name for each field.", "type": "string" }, "field": { - "description": "The data fields for which to compute aggregate or window functions. Field can be omitted for operations that do not\noperate over a specific data field, including count, rank, and dense_rank.", + "description": "The data field for which to compute the aggregate or window function. This can be omitted for functions that do not operate over a field such as `count`, `rank`, `dense_rank`.", "type": "string" }, "op": { @@ -7330,15 +7330,16 @@ "$ref": "#/definitions/WindowOnlyOp" } ], - "description": "The operations supported for the window aggregation. See the list of supported operations here:\n https://vega.github.io/vega-lite/docs/transforms/window.html" + "description": "The window or aggregation operations to apply within a window, including `rank`, `lead`, `sum`, `average` or `count`. See the list of all supported operations [here](https://vega.github.io/vega-lite/docs/transforms/window.html)." }, "param": { - "description": "Parameter values for the window functions. Parameter value can be null for operations that do not accept a\nparameter.", + "description": "Parameter values for the window functions. Parameter values can be omitted for operations that do not accept a parameter.\n\nSee the list of all supported operations and their parameters [here](https://vega.github.io/vega-lite/docs/transforms/window.html).", "type": "number" } }, "required": [ - "op" + "op", + "as" ], "type": "object" }, @@ -7363,9 +7364,11 @@ "description": "A compartor for fields within the window transform", "properties": { "field": { + "description": "The name of the field to sort.", "type": "string" }, "order": { + "description": "Whether to sort the field in ascending or descending order.", "enum": [ "ascending", "descending" @@ -7382,7 +7385,7 @@ "additionalProperties": false, "properties": { "frame": { - "description": "The frame for the window, if none is set the default is `[null, 0]` everything before the\ncurrent item.", + "description": "A frame specification as a two-element array indicating how the sliding window should proceed. The array entries should either be a number indicating the offset from the current data object, or null to indicate unbounded rows preceding or following the current data object. The default value is `[null, 0]`, indicating that the sliding window includes the current object and all preceding objects. The value `[-5, 5]` indicates that the window should include five objects preceding and five objects following the current object. Finally, `[null, null]` indicates that the window frame should always include all data objects.\n\n__Default value:__: `[null, 0]` (includes the current object and all preceding objects)", "items": { "type": [ "null", @@ -7392,18 +7395,18 @@ "type": "array" }, "groupby": { - "description": "The fields to group by.", + "description": "The data fields for partitioning the data objects into separate windows. If unspecified, all data points will be a single group.", "items": { "type": "string" }, "type": "array" }, "ignorePeers": { - "description": "Will indicate whether to ignore peer values (items with the same rank) in the window. The default value is `False`.", + "description": "Indicates if the sliding window frame should ignore peer values. (Peer values are those considered identical by the sort criteria). The default is false, causing the window frame to expand to include all peer values. If set to true, the window frame will be defined by offset values only. This setting only affects those operations that depend on the window frame, namely aggregation operations and the first_value, last_value, and nth_value window operations.\n\n__Default value:__ `false`", "type": "boolean" }, "sort": { - "description": "The definitions of how to sort each of the fields in the window.", + "description": "A comparator definition for sorting data objects within a window. If two data objects are considered equal by the comparator, they are considered “peer” values of equal rank. If sort is not specified, the order is undefined: data objects are processed in the order they are observed and none are considered peers (the ignorePeers parameter is ignored and treated as if set to `true`).", "items": { "$ref": "#/definitions/WindowSortField" }, diff --git a/examples/compiled/area_horizon.vg.json b/examples/compiled/area_horizon.vg.json index 07fc64b07b..fc8725269c 100644 --- a/examples/compiled/area_horizon.vg.json +++ b/examples/compiled/area_horizon.vg.json @@ -168,9 +168,8 @@ "field": "y" }, "y2": { - "field": { - "group": "height" - } + "scale": "y", + "value": 0 } } } @@ -209,9 +208,8 @@ "field": "ny" }, "y2": { - "field": { - "group": "height" - } + "scale": "y", + "value": 0 } } } diff --git a/examples/compiled/circle_natural_disasters.vg.json b/examples/compiled/circle_natural_disasters.vg.json index 5bc51449d2..948295e0c6 100644 --- a/examples/compiled/circle_natural_disasters.vg.json +++ b/examples/compiled/circle_natural_disasters.vg.json @@ -134,7 +134,6 @@ "scale": "x", "orient": "bottom", "title": "Year", - "labelOverlap": true, "encode": { "labels": { "update": { @@ -147,6 +146,7 @@ } } }, + "labelOverlap": true, "zindex": 1 }, { diff --git a/examples/compiled/layer_bar_annotations.vg.json b/examples/compiled/layer_bar_annotations.vg.json index 093f591cff..c65b3035bf 100644 --- a/examples/compiled/layer_bar_annotations.vg.json +++ b/examples/compiled/layer_bar_annotations.vg.json @@ -360,7 +360,6 @@ "scale": "x", "orient": "bottom", "title": "Day", - "labelOverlap": true, "encode": { "labels": { "update": { @@ -373,6 +372,7 @@ } } }, + "labelOverlap": true, "zindex": 1 }, { diff --git a/examples/compiled/window_activities.svg b/examples/compiled/window_activities.svg new file mode 100644 index 0000000000..0f017c3c72 --- /dev/null +++ b/examples/compiled/window_activities.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/compiled/window_activities.vg.json b/examples/compiled/window_activities.vg.json new file mode 100644 index 0000000000..a0c4bd2ccb --- /dev/null +++ b/examples/compiled/window_activities.vg.json @@ -0,0 +1,191 @@ +{ + "$schema": "https://vega.github.io/schema/vega/v3.0.json", + "description": "A bar graph showing what activites consume what percentage of the day.", + "autosize": "pad", + "padding": 5, + "width": 200, + "style": "cell", + "data": [ + { + "name": "source_0", + "values": [ + { + "Activity": "Sleeping", + "Time": 8 + }, + { + "Activity": "Eating", + "Time": 2 + }, + { + "Activity": "TV", + "Time": 4 + }, + { + "Activity": "Work", + "Time": 8 + }, + { + "Activity": "Exercise", + "Time": 2 + } + ] + }, + { + "name": "data_0", + "source": "source_0", + "transform": [ + { + "type": "window", + "params": [ + null + ], + "as": [ + "TotalTime" + ], + "ops": [ + "sum" + ], + "fields": [ + "Time" + ], + "sort": { + "field": [], + "order": [] + }, + "frame": [ + null, + null + ] + }, + { + "type": "formula", + "expr": "datum.Time/datum.TotalTime * 100", + "as": "PercentOfTotal" + }, + { + "type": "filter", + "expr": "datum[\"PercentOfTotal\"] !== null && !isNaN(datum[\"PercentOfTotal\"])" + } + ] + } + ], + "signals": [ + { + "name": "y_step", + "value": 12 + }, + { + "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": { + "value": "#4c78a8" + }, + "x": { + "scale": "x", + "field": "PercentOfTotal" + }, + "x2": { + "scale": "x", + "value": 0 + }, + "y": { + "scale": "y", + "field": "Activity" + }, + "height": { + "scale": "y", + "band": true + } + } + } + } + ], + "scales": [ + { + "name": "x", + "type": "linear", + "domain": { + "data": "data_0", + "field": "PercentOfTotal" + }, + "range": [ + 0, + { + "signal": "width" + } + ], + "nice": true, + "zero": true + }, + { + "name": "y", + "type": "band", + "domain": { + "data": "data_0", + "field": "Activity", + "sort": true + }, + "range": { + "step": { + "signal": "y_step" + } + }, + "paddingInner": 0.1, + "paddingOuter": 0.05 + } + ], + "axes": [ + { + "scale": "x", + "orient": "bottom", + "title": "% of total Time", + "labelFlush": true, + "labelOverlap": true, + "tickCount": { + "signal": "ceil(width/40)" + }, + "zindex": 1 + }, + { + "scale": "x", + "orient": "bottom", + "grid": true, + "tickCount": { + "signal": "ceil(width/40)" + }, + "gridScale": "y", + "domain": false, + "labels": false, + "maxExtent": 0, + "minExtent": 0, + "ticks": false, + "zindex": 0 + }, + { + "scale": "y", + "orient": "left", + "title": "Activity", + "zindex": 1 + } + ], + "config": { + "axisY": { + "minExtent": 30 + } + } +} diff --git a/examples/compiled/window_mean_difference.svg b/examples/compiled/window_mean_difference.svg new file mode 100644 index 0000000000..256e171c36 --- /dev/null +++ b/examples/compiled/window_mean_difference.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/compiled/window_mean_difference.vg.json b/examples/compiled/window_mean_difference.vg.json new file mode 100644 index 0000000000..e8ddf2840e --- /dev/null +++ b/examples/compiled/window_mean_difference.vg.json @@ -0,0 +1,240 @@ +{ + "$schema": "https://vega.github.io/schema/vega/v3.0.json", + "autosize": "pad", + "padding": 5, + "width": 200, + "style": "cell", + "data": [ + { + "name": "source_0", + "url": "data/movies.json", + "format": { + "type": "json" + }, + "transform": [ + { + "type": "window", + "params": [ + null + ], + "as": [ + "AverageRating" + ], + "ops": [ + "mean" + ], + "fields": [ + "IMDB_Rating" + ], + "sort": { + "field": [], + "order": [] + }, + "frame": [ + null, + null + ] + }, + { + "type": "filter", + "expr": "(datum.IMDB_Rating - datum.AverageRating) > 2.5" + } + ] + }, + { + "name": "data_0", + "source": "source_0", + "transform": [ + { + "type": "formula", + "expr": "toNumber(datum[\"IMDB_Rating\"])", + "as": "IMDB_Rating" + }, + { + "type": "filter", + "expr": "datum[\"IMDB_Rating\"] !== null && !isNaN(datum[\"IMDB_Rating\"])" + } + ] + }, + { + "name": "data_1", + "source": "source_0", + "transform": [ + { + "type": "formula", + "expr": "toNumber(datum[\"AverageRating\"])", + "as": "AverageRating" + }, + { + "type": "aggregate", + "groupby": [], + "ops": [ + "average" + ], + "fields": [ + "AverageRating" + ], + "as": [ + "average_AverageRating" + ] + } + ] + } + ], + "signals": [ + { + "name": "y_step", + "value": 21 + }, + { + "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_0" + }, + "encode": { + "update": { + "fill": { + "value": "#4c78a8" + }, + "x": { + "scale": "x", + "field": "IMDB_Rating" + }, + "x2": { + "scale": "x", + "value": 0 + }, + "y": { + "scale": "y", + "field": "Title" + }, + "height": { + "scale": "y", + "band": true + } + } + } + }, + { + "name": "layer_1_marks", + "type": "rule", + "style": [ + "rule" + ], + "from": { + "data": "data_1" + }, + "encode": { + "update": { + "stroke": { + "value": "red" + }, + "x": { + "scale": "x", + "field": "average_AverageRating" + }, + "y": { + "field": { + "group": "height" + } + }, + "y2": { + "value": 0 + } + } + } + } + ], + "scales": [ + { + "name": "x", + "type": "linear", + "domain": { + "fields": [ + { + "data": "data_0", + "field": "IMDB_Rating" + }, + { + "data": "data_1", + "field": "average_AverageRating" + } + ] + }, + "range": [ + 0, + { + "signal": "width" + } + ], + "nice": true, + "zero": true + }, + { + "name": "y", + "type": "band", + "domain": { + "data": "data_0", + "field": "Title", + "sort": true + }, + "range": { + "step": { + "signal": "y_step" + } + }, + "paddingInner": 0.1, + "paddingOuter": 0.05 + } + ], + "axes": [ + { + "scale": "x", + "orient": "bottom", + "title": "IMDB Rating", + "labelFlush": true, + "labelOverlap": true, + "tickCount": { + "signal": "ceil(width/40)" + }, + "zindex": 1 + }, + { + "scale": "x", + "orient": "bottom", + "grid": true, + "tickCount": { + "signal": "ceil(width/40)" + }, + "gridScale": "y", + "domain": false, + "labels": false, + "maxExtent": 0, + "minExtent": 0, + "ticks": false, + "zindex": 0 + }, + { + "scale": "y", + "orient": "left", + "title": "Title", + "labelOverlap": true, + "zindex": 1 + } + ], + "config": { + "axisY": { + "minExtent": 30 + } + } +} diff --git a/examples/compiled/window_mean_difference_by_year.svg b/examples/compiled/window_mean_difference_by_year.svg new file mode 100644 index 0000000000..72592fa41d --- /dev/null +++ b/examples/compiled/window_mean_difference_by_year.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/compiled/window_mean_difference_by_year.vg.json b/examples/compiled/window_mean_difference_by_year.vg.json new file mode 100644 index 0000000000..ff80077494 --- /dev/null +++ b/examples/compiled/window_mean_difference_by_year.vg.json @@ -0,0 +1,259 @@ +{ + "$schema": "https://vega.github.io/schema/vega/v3.0.json", + "description": "Bar graph showing the best films for the year they were produced, where best is defined by at least 2.5 points above average for that year. The red point shows the average rating for a film in that year, and the bar is the rating that the film recieved.", + "autosize": "pad", + "padding": 5, + "width": 200, + "style": "cell", + "data": [ + { + "name": "source_0", + "url": "data/movies.json", + "format": { + "type": "json", + "parse": { + "Release_Date": "date:'%d-%b-%y'" + } + }, + "transform": [ + { + "type": "formula", + "as": "year", + "expr": "datetime(year(datum[\"Release_Date\"]), 0, 1, 0, 0, 0, 0)" + }, + { + "type": "window", + "params": [ + null + ], + "as": [ + "AverageYearRating" + ], + "ops": [ + "mean" + ], + "fields": [ + "IMDB_Rating" + ], + "sort": { + "field": [], + "order": [] + }, + "groupby": [ + "year" + ], + "frame": [ + null, + null + ] + }, + { + "type": "filter", + "expr": "(datum.IMDB_Rating - datum.AverageYearRating) > 2.5" + } + ] + }, + { + "name": "data_0", + "source": "source_0", + "transform": [ + { + "type": "formula", + "expr": "toNumber(datum[\"IMDB_Rating\"])", + "as": "IMDB_Rating" + }, + { + "type": "filter", + "expr": "datum[\"IMDB_Rating\"] !== null && !isNaN(datum[\"IMDB_Rating\"])" + } + ] + }, + { + "name": "data_1", + "source": "source_0", + "transform": [ + { + "type": "formula", + "expr": "toNumber(datum[\"AverageYearRating\"])", + "as": "AverageYearRating" + }, + { + "type": "filter", + "expr": "datum[\"AverageYearRating\"] !== null && !isNaN(datum[\"AverageYearRating\"])" + } + ] + } + ], + "signals": [ + { + "name": "y_step", + "value": 21 + }, + { + "name": "height", + "update": "bandspace(domain('y').length, 0.1, 0.05) * y_step" + } + ], + "marks": [ + { + "name": "layer_0_marks", + "type": "rect", + "clip": true, + "style": [ + "bar" + ], + "from": { + "data": "data_0" + }, + "encode": { + "update": { + "fill": { + "value": "#4c78a8" + }, + "x": { + "scale": "x", + "field": "IMDB_Rating" + }, + "x2": { + "scale": "x", + "value": 0 + }, + "y": { + "scale": "y", + "field": "Title" + }, + "height": { + "scale": "y", + "band": true + } + } + } + }, + { + "name": "layer_1_marks", + "type": "rect", + "clip": true, + "style": [ + "tick" + ], + "from": { + "data": "data_1" + }, + "encode": { + "update": { + "opacity": { + "value": 0.7 + }, + "fill": { + "value": "red" + }, + "xc": { + "scale": "x", + "field": "AverageYearRating" + }, + "yc": { + "scale": "y", + "field": "Title", + "band": 0.5 + }, + "height": { + "value": 14 + }, + "width": { + "value": 1 + } + } + } + } + ], + "scales": [ + { + "name": "x", + "type": "linear", + "domain": { + "fields": [ + { + "data": "data_0", + "field": "IMDB_Rating" + }, + { + "data": "data_1", + "field": "AverageYearRating" + } + ] + }, + "range": [ + 0, + { + "signal": "width" + } + ], + "nice": true, + "zero": true + }, + { + "name": "y", + "type": "band", + "domain": { + "fields": [ + { + "data": "data_0", + "field": "Title" + }, + { + "data": "data_1", + "field": "Title" + } + ], + "sort": true + }, + "range": { + "step": { + "signal": "y_step" + } + }, + "paddingInner": 0.1, + "paddingOuter": 0.05 + } + ], + "axes": [ + { + "scale": "x", + "orient": "bottom", + "title": "IMDB Rating", + "labelFlush": true, + "labelOverlap": true, + "tickCount": { + "signal": "ceil(width/40)" + }, + "zindex": 1 + }, + { + "scale": "x", + "orient": "bottom", + "grid": true, + "tickCount": { + "signal": "ceil(width/40)" + }, + "gridScale": "y", + "domain": false, + "labels": false, + "maxExtent": 0, + "minExtent": 0, + "ticks": false, + "zindex": 0 + }, + { + "scale": "y", + "orient": "left", + "title": "Title", + "labelOverlap": true, + "zindex": 1 + } + ], + "config": { + "axisY": { + "minExtent": 30 + } + } +} diff --git a/examples/compiled/window_residual_graph.svg b/examples/compiled/window_residual_graph.svg new file mode 100644 index 0000000000..f1a3b4d23e --- /dev/null +++ b/examples/compiled/window_residual_graph.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/compiled/window_residual_graph.vg.json b/examples/compiled/window_residual_graph.vg.json new file mode 100644 index 0000000000..7b732f0b5f --- /dev/null +++ b/examples/compiled/window_residual_graph.vg.json @@ -0,0 +1,196 @@ +{ + "$schema": "https://vega.github.io/schema/vega/v3.0.json", + "description": "A dot plot showing each movie in the database, and the difference from the average movie rating. The display is sorted by year to visualize everything in sequential order. The graph is for all Movies before 2019.", + "autosize": "pad", + "padding": 5, + "width": 200, + "height": 200, + "style": "cell", + "data": [ + { + "name": "source_0", + "url": "data/movies.json", + "format": { + "type": "json", + "parse": { + "Release_Date": "date:'%d-%b-%y'" + } + }, + "transform": [ + { + "type": "filter", + "expr": "datum.IMDB_Rating != null" + }, + { + "type": "filter", + "expr": "time(datetime(year(datum[\"Release_Date\"]), 0, 1, 0, 0, 0, 0)) <= time(datetime(2019, 0, 1, 0, 0, 0, 0))" + }, + { + "type": "window", + "params": [ + null + ], + "as": [ + "AverageRating" + ], + "ops": [ + "mean" + ], + "fields": [ + "IMDB_Rating" + ], + "sort": { + "field": [], + "order": [] + }, + "frame": [ + null, + null + ] + }, + { + "type": "formula", + "expr": "datum.IMDB_Rating - datum.AverageRating", + "as": "RatingDelta" + }, + { + "type": "filter", + "expr": "datum[\"Release_Date\"] !== null && !isNaN(datum[\"Release_Date\"]) && datum[\"RatingDelta\"] !== null && !isNaN(datum[\"RatingDelta\"])" + } + ] + } + ], + "marks": [ + { + "name": "marks", + "type": "symbol", + "clip": true, + "style": [ + "point" + ], + "from": { + "data": "source_0" + }, + "encode": { + "update": { + "opacity": { + "value": 0.7 + }, + "fill": { + "value": "transparent" + }, + "stroke": { + "value": "#4c78a8" + }, + "x": { + "scale": "x", + "field": "Release_Date" + }, + "y": { + "scale": "y", + "field": "RatingDelta" + } + } + } + } + ], + "scales": [ + { + "name": "x", + "type": "time", + "domain": { + "data": "source_0", + "field": "Release_Date" + }, + "range": [ + 0, + { + "signal": "width" + } + ] + }, + { + "name": "y", + "type": "linear", + "domain": { + "data": "source_0", + "field": "RatingDelta" + }, + "range": [ + { + "signal": "height" + }, + 0 + ], + "nice": true, + "zero": true + } + ], + "axes": [ + { + "scale": "x", + "orient": "bottom", + "title": "Release_Date", + "labelFlush": true, + "labelOverlap": true, + "tickCount": { + "signal": "ceil(width/40)" + }, + "encode": { + "labels": { + "update": { + "text": { + "signal": "timeFormat(datum.value, '%b %d, %Y')" + } + } + } + }, + "zindex": 1 + }, + { + "scale": "x", + "orient": "bottom", + "grid": true, + "tickCount": { + "signal": "ceil(width/40)" + }, + "gridScale": "y", + "domain": false, + "labels": false, + "maxExtent": 0, + "minExtent": 0, + "ticks": false, + "zindex": 0 + }, + { + "scale": "y", + "orient": "left", + "title": "Rating Delta", + "labelOverlap": true, + "tickCount": { + "signal": "ceil(height/40)" + }, + "zindex": 1 + }, + { + "scale": "y", + "orient": "left", + "grid": true, + "tickCount": { + "signal": "ceil(height/40)" + }, + "gridScale": "x", + "domain": false, + "labels": false, + "maxExtent": 0, + "minExtent": 0, + "ticks": false, + "zindex": 0 + } + ], + "config": { + "axisY": { + "minExtent": 30 + } + } +} diff --git a/examples/compiled/window_student_rank.svg b/examples/compiled/window_student_rank.svg new file mode 100644 index 0000000000..77d8326c09 --- /dev/null +++ b/examples/compiled/window_student_rank.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/compiled/window_student_rank.vg.json b/examples/compiled/window_student_rank.vg.json new file mode 100644 index 0000000000..0fa9533e5c --- /dev/null +++ b/examples/compiled/window_student_rank.vg.json @@ -0,0 +1,302 @@ +{ + "$schema": "https://vega.github.io/schema/vega/v3.0.json", + "description": "A bar graph showing the scores of the top 5 students. This shows an example of the window transform, for how the top X can be filtered, and also how a rank can be computed for each student.", + "autosize": "pad", + "padding": 5, + "width": 300, + "height": 50, + "style": "cell", + "data": [ + { + "name": "source_0", + "values": [ + { + "student": "A", + "score": 100 + }, + { + "student": "B", + "score": 56 + }, + { + "student": "C", + "score": 88 + }, + { + "student": "D", + "score": 65 + }, + { + "student": "E", + "score": 45 + }, + { + "student": "F", + "score": 23 + }, + { + "student": "G", + "score": 66 + }, + { + "student": "H", + "score": 67 + }, + { + "student": "I", + "score": 13 + }, + { + "student": "J", + "score": 12 + }, + { + "student": "K", + "score": 50 + }, + { + "student": "L", + "score": 78 + }, + { + "student": "M", + "score": 66 + }, + { + "student": "N", + "score": 30 + }, + { + "student": "O", + "score": 97 + }, + { + "student": "P", + "score": 75 + }, + { + "student": "Q", + "score": 24 + }, + { + "student": "R", + "score": 42 + }, + { + "student": "S", + "score": 76 + }, + { + "student": "T", + "score": 78 + }, + { + "student": "U", + "score": 21 + }, + { + "student": "V", + "score": 46 + } + ] + }, + { + "name": "data_0", + "source": "source_0", + "transform": [ + { + "type": "formula", + "expr": "toNumber(datum[\"Score\"])", + "as": "Score" + }, + { + "type": "window", + "params": [ + null + ], + "as": [ + "rank" + ], + "ops": [ + "rank" + ], + "fields": [ + "score" + ], + "sort": { + "field": [ + "score" + ], + "order": [ + "ascending" + ] + }, + "groupby": [ + "Student" + ], + "frame": [ + null, + 0 + ] + }, + { + "type": "window", + "params": [ + null + ], + "as": [ + "totalStudents" + ], + "ops": [ + "count" + ], + "fields": [ + "score" + ], + "sort": { + "field": [ + "score" + ], + "order": [ + "ascending" + ] + }, + "groupby": [ + "Student" + ], + "frame": [ + null, + null + ] + }, + { + "type": "filter", + "expr": "datum.totalStudents - datum.rank > 5" + }, + { + "type": "filter", + "expr": "datum[\"Score\"] !== null && !isNaN(datum[\"Score\"])" + } + ] + } + ], + "marks": [ + { + "name": "marks", + "type": "rect", + "style": [ + "bar" + ], + "from": { + "data": "data_0" + }, + "encode": { + "update": { + "fill": { + "scale": "color", + "field": "student" + }, + "x": { + "scale": "x", + "field": "Score" + }, + "x2": { + "scale": "x", + "value": 0 + }, + "y": { + "scale": "y", + "field": "student" + }, + "height": { + "scale": "y", + "band": true + } + } + } + } + ], + "scales": [ + { + "name": "x", + "type": "linear", + "domain": { + "data": "data_0", + "field": "Score" + }, + "range": [ + 0, + { + "signal": "width" + } + ], + "nice": true, + "zero": true + }, + { + "name": "y", + "type": "band", + "domain": { + "data": "data_0", + "field": "student", + "sort": true + }, + "range": [ + 0, + { + "signal": "height" + } + ], + "paddingInner": 0.1, + "paddingOuter": 0.05 + }, + { + "name": "color", + "type": "ordinal", + "domain": { + "data": "data_0", + "field": "student", + "sort": true + }, + "range": "category" + } + ], + "axes": [ + { + "scale": "x", + "orient": "bottom", + "title": "Score", + "labelFlush": true, + "labelOverlap": true, + "tickCount": { + "signal": "ceil(width/40)" + }, + "zindex": 1 + }, + { + "scale": "y", + "orient": "left", + "zindex": 1 + } + ], + "legends": [ + { + "fill": "color", + "title": "student", + "encode": { + "symbols": { + "update": { + "shape": { + "value": "square" + } + } + } + } + } + ], + "config": { + "axisY": { + "minExtent": 30 + } + } +} diff --git a/examples/specs/window_activities.vl.json b/examples/specs/window_activities.vl.json new file mode 100644 index 0000000000..ac73fa0eca --- /dev/null +++ b/examples/specs/window_activities.vl.json @@ -0,0 +1,42 @@ +{ + "$schema": "https://vega.github.io/schema/vega-lite/v2.json", + "description": "A bar graph showing what activites consume what percentage of the day.", + "data": { + "values": [ + {"Activity": "Sleeping","Time": 8}, + {"Activity": "Eating","Time": 2}, + {"Activity": "TV","Time": 4}, + {"Activity": "Work","Time": 8}, + {"Activity": "Exercise","Time": 2} + ] + }, + "transform": [{ + "window": [{ + "op": "sum", + "field": "Time", + "as": "TotalTime" + }], + "frame": [null, null] + }, + { + "calculate": "datum.Time/datum.TotalTime * 100", + "as": "PercentOfTotal" + }], + "mark": "bar", + "encoding": { + "x": { + "field": "PercentOfTotal", + "type": "quantitative", + "axis": { + "title": "% of total Time" + } + }, + "y": { + "field": "Activity", + "type": "nominal", + "scale": { + "rangeStep": 12 + } + } + } +} diff --git a/examples/specs/window_mean_difference.vl.json b/examples/specs/window_mean_difference.vl.json new file mode 100644 index 0000000000..c8ce507c1b --- /dev/null +++ b/examples/specs/window_mean_difference.vl.json @@ -0,0 +1,41 @@ +{ + "data": { + "url": "data/movies.json" + }, + "transform": [{ + "window": [{ + "op": "mean", + "field": "IMDB_Rating", + "as": "AverageRating" + }], + "frame": [ + null, + null + ] + }, + { + "filter": "(datum.IMDB_Rating - datum.AverageRating) > 2.5" + }], + "layer": [ + { + "mark": "bar", + "encoding": { + "x": { + "field": "IMDB_Rating", "type": "quantitative", + "axis": {"title": "IMDB Rating"} + }, + "y": {"field": "Title", "type": "ordinal"} + } + }, + { + "mark": {"type": "rule", "color": "red"}, + "encoding": { + "x": { + "aggregate": "average", + "field": "AverageRating", + "type": "quantitative" + } + } + } + ] +} diff --git a/examples/specs/window_mean_difference_by_year.vl.json b/examples/specs/window_mean_difference_by_year.vl.json new file mode 100644 index 0000000000..104f3f7b72 --- /dev/null +++ b/examples/specs/window_mean_difference_by_year.vl.json @@ -0,0 +1,57 @@ +{ + "$schema": "https://vega.github.io/schema/vega-lite/v2.json", + "description": "Bar graph showing the best films for the year they were produced, where best is defined by at least 2.5 points above average for that year. The red point shows the average rating for a film in that year, and the bar is the rating that the film recieved.", + "data": { + "url": "data/movies.json", + "format": { + "parse": {"Release_Date": "date:'%d-%b-%y'"} + } + }, + "transform": [ + {"timeUnit": "year", "field": "Release_Date", "as": "year"}, + { + "window": [{ + "op": "mean", + "field": "IMDB_Rating", + "as": "AverageYearRating" + }], + "groupby": [ + "year" + ], + "frame": [null, null] + }, + { + "filter": "(datum.IMDB_Rating - datum.AverageYearRating) > 2.5" + } + ], + "layer": [{ + "mark": {"type": "bar", "clip": true}, + "encoding": { + "x": { + "field": "IMDB_Rating", + "type": "quantitative", + "axis": {"title": "IMDB Rating"} + }, + "y": { + "field": "Title", + "type": "ordinal", + "sort": {"field": "IMDB_Rating", "order": "ascending"} + } + } + }, + { + "mark": "tick", + "encoding": { + "x": { + "field": "AverageYearRating", + "type": "quantitative" + }, + "y": { + "field": "Title", + "type": "ordinal" + }, + "color": {"value": "red"} + } + } + ] +} diff --git a/examples/specs/window_residual_graph.vl.json b/examples/specs/window_residual_graph.vl.json new file mode 100644 index 0000000000..d56dec3ed8 --- /dev/null +++ b/examples/specs/window_residual_graph.vl.json @@ -0,0 +1,39 @@ +{ + "$schema": "https://vega.github.io/schema/vega-lite/v2.json", + "description": "A dot plot showing each movie in the database, and the difference from the average movie rating. The display is sorted by year to visualize everything in sequential order. The graph is for all Movies before 2019.", + "data": { + "url": "data/movies.json", + "format": { + "parse": {"Release_Date": "date:'%d-%b-%y'"} + } + }, + "transform": [ + {"filter": "datum.IMDB_Rating != null"}, + {"filter": {"timeUnit": "year", "field": "Release_Date", "range": [null, 2019]}}, + { + "window": [{ + "op": "mean", + "field": "IMDB_Rating", + "as": "AverageRating" + }], + "frame": [null, null] + }, + { + "calculate": "datum.IMDB_Rating - datum.AverageRating", + "as": "RatingDelta" + } + ], + "mark": "point", + "encoding": { + "x": { + "field": "Release_Date", + "type": "temporal", + "sort": {"field": "Release_Date", "order": "ascending"} + }, + "y": { + "field": "RatingDelta", + "type": "quantitative", + "axis": {"title": "Rating Delta"} + } + } +} diff --git a/examples/specs/window_student_rank.vl.json b/examples/specs/window_student_rank.vl.json new file mode 100644 index 0000000000..190a916ba8 --- /dev/null +++ b/examples/specs/window_student_rank.vl.json @@ -0,0 +1,66 @@ +{ + "$schema": "https://vega.github.io/schema/vega-lite/v2.json", + "description": "A bar graph showing the scores of the top 5 students. This shows an example of the window transform, for how the top X can be filtered, and also how a rank can be computed for each student.", + "width": 300, + "height": 50, + "data": { + "values": [ + {"student": "A", "score": 100}, {"student": "B", "score": 56}, + {"student": "C", "score": 88}, {"student": "D", "score": 65}, + {"student": "E", "score": 45}, {"student": "F", "score": 23}, + {"student": "G", "score": 66}, {"student": "H", "score": 67}, + {"student": "I", "score": 13}, {"student": "J", "score": 12}, + {"student": "K", "score": 50}, {"student": "L", "score": 78}, + {"student": "M", "score": 66}, {"student": "N", "score": 30}, + {"student": "O", "score": 97}, {"student": "P", "score": 75}, + {"student": "Q", "score": 24}, {"student": "R", "score": 42}, + {"student": "S", "score": 76}, {"student": "T", "score": 78}, + {"student": "U", "score": 21}, {"student": "V", "score": 46} + ] + }, + "transform": [{ + "window": [{ + "op": "rank", + "field": "score", + "as": "rank" + }], + "sort": [{ "field": "score", "order": "ascending" }], + "groupby": [ + "Student" + ], + "frame": [null, 0] + }, + { + "window": [{ + "op": "count", + "field": "score", + "as": "totalStudents" + }], + "sort": [{ "field": "score", "order": "ascending" }], + "groupby": [ + "Student" + ], + "frame": [null, null] + }, + { + "filter": "datum.totalStudents - datum.rank > 5" + }], + "mark": "bar", + "encoding": { + "x": { + "field": "Score", + "type": "quantitative", + "axis": { "title": "Score", "grid": false } + }, + "y": { + "field": "student", + "type": "nominal", + "scale": { "rangeStep": 12 }, + "axis": { "title": "" } + }, + "color": { + "field": "student", + "type": "nominal" + } + } +} \ No newline at end of file diff --git a/site/docs/encoding/scale.md b/site/docs/encoding/scale.md index 6f240b5447..c068ccb8fc 100644 --- a/site/docs/encoding/scale.md +++ b/site/docs/encoding/scale.md @@ -124,15 +124,15 @@ Color schemes provide a set of named color palettes as a scale range for the `co By default, Vega-Lite assigns different [default color schemes](#range-config) based on the types of the encoded fields: -- _Nominal_ fields use the `"categorical"` [pre-defined named range](#range-config) (the `"category20"` scheme by default). +- _Nominal_ fields use the `"categorical"` [pre-defined named range](#range-config) (the [`"tableau10"`](https://vega.github.io/vega/docs/schemes/#tableau10) scheme by default).
-- _Ordinal_ fields use the `"ordinal"` [pre-defined named color range](#range-config) (the `"blues"` color scheme by default). +- _Ordinal_ fields use the `"ordinal"` [pre-defined named color range](#range-config) (the [`"blues"`](https://vega.github.io/vega/docs/schemes/#blues) color scheme by default). -- _Quantitative_ and _temporal_ fields use the [pre-defined named color range](#range-config) `"heatmap"` (the `"viridis"` scheme by default) for rect marks and `"ramp"` (the `"blues"` scheme by default) for other marks. +- _Quantitative_ and _temporal_ fields use the [pre-defined named color range](#range-config) `"heatmap"` (the [`"viridis"`](https://vega.github.io/vega/docs/schemes/#viridis) scheme by default) for rect marks and `"ramp"` (the [`"blues"`](https://vega.github.io/vega/docs/schemes/#blues) scheme by default) for other marks. diff --git a/site/docs/transform/transform.md b/site/docs/transform/transform.md index 0a78d99371..3601a117a5 100644 --- a/site/docs/transform/transform.md +++ b/site/docs/transform/transform.md @@ -32,3 +32,4 @@ Vega-Lite's `transform` supports the following types of transformations: - [Calculate](calculate.html) - [Filter](filter.html) - [TimeUnit](timeunit.html#transform) +- [Window](window.html) diff --git a/site/docs/transform/window.md b/site/docs/transform/window.md new file mode 100644 index 0000000000..0333b89192 --- /dev/null +++ b/site/docs/transform/window.md @@ -0,0 +1,91 @@ +--- +layout: docs +menu: docs +title: Window +permalink: /docs/window.html +--- + +The window transform performs calculations over sorted groups of data objects. These calculations including ranking, lead/lag analysis, and aggregates such as running sums and averages. Calculated values are written back to the input data stream. + +## Window Field Definition + +{: .suppress-error} +```json +// A View Specification +{ + ... + "transform": [ + { + // Window Transform + "window": [{ + "op": "...", + "field": "...", + "as": "..." + }], + "groupby": [ + "..." + ], + "frame": "..." + } + ... + ], + ... +} +``` + +## Window Transform Definition + +{% include table.html props="window,frame,ignorePeers,groupby,sort" source="WindowTransform" %} + +{:#field-def} +### Window Transform Field Definition + +{% include table.html props="op,param,field,as" source="WindowFieldDef" %} + +{:#sort-field-def} +### Window Sort Field Definition + +{% include table.html props="field,order" source="WindowSortField" %} + +{:#ops} +## Window Only Operation Reference + +The valid operations include all [valid aggregate operations](../aggregate/#ops) plus the following window operations. + +| Operation | Parameter | Description | +| :----------- | :-------: | :------------| +| row_number | _None_ | Assigns each data object a consecutive row number, starting from 1.| +| rank | _None_ | Assigns a rank order value to each data object in a window, starting from 1. Peer values are assigned the same rank. Subsequent rank scores incorporate the number of prior values. For example, if the first two values tie for rank 1, the third value is assigned rank 3.| +| dense_rank | _None_ | Assigns dense rank order values to each data object in a window, starting from 1. Peer values are assigned the same rank. Subsequent rank scores do not incorporate the number of prior values. For example, if the first two values tie for rank 1, the third value is assigned rank 2.| +| percent_rank | _None_ | Assigns a percentage rank order value to each data object in a window. The percent is calculated as _(rank - 1) / (group_size - 1)_. | +| cume_dist | _None_ | Assigns a cumulative distribution value between 0 and 1 to each data object in a window.| +| ntile | Number | Assigns a quantile (e.g., percentile) value to each data object in a window. Accepts an integer parameter indicating the number of buckets to use (e.g., 100 for percentiles, 5 for quintiles).| +| lag | Number | Assigns a value from the data object that precedes the current object by a specified number of positions. If no such object exists, assigns `null`. Accepts an offset parameter (default `1`) that indicates the number of positions. This operation must have a corresponding entry in the _fields_ parameter array.| +| lead | Number | Assigns a value from the data object that follows the current object by a specified number of positions. If no such object exists, assigns `null`. Accepts an offset parameter (default `1`) that indicates the number of positions. This operation must have a corresponding entry in the _fields_ parameter array.| +| first_value | _None_ | Assigns a value from the first data object in the current sliding window frame. This operation must have a corresponding entry in the _fields_ parameter array.| +| last_value | _None_ | Assigns a value from the last data object in the current sliding window frame. This operation must have a corresponding entry in the _fields_ parameter array.| +| nth_value | Number | Assigns a value from the nth data object in the current sliding window frame. If no such object exists, assigns `null`. Requires a non-negative integer parameter that indicates the offset from the start of the window frame. This operation must have a corresponding entry in the _fields_ parameter array.| + +## Examples + +Below are some common use cases for the window transform. Shown are the examples along side the Vega Lite spec. + +### Percent of Total + + + +### Difference from Mean + + + +Another example is to show the best movies for the year they were released. Here best is defined by having a score that is 2.5 points higher than the average for the year it was released in. + + + +Rather than filtering the above two examples we can also show a residual graph using the window transform. + + + +To replace any of the examples from total to `mean`, the operation just needs to be changed from `sum` to `mean`. + +To replace any of the examples from total to `mean`, the operation just needs to be changed from `sum` to `mean`. \ No newline at end of file diff --git a/src/compile/axis/parse.ts b/src/compile/axis/parse.ts index 9a9af05dea..3936a20722 100644 --- a/src/compile/axis/parse.ts +++ b/src/compile/axis/parse.ts @@ -199,7 +199,7 @@ function parseAxis(channel: PositionScaleChannel, model: UnitModel): AxisCompone // FIXME: By having encode as one property, we won't have fine grained encode merging. if (keys(axisEncode).length > 0) { - axisComponent.set('encode', axisEncode, !!axis.encoding || !!axis.labelAngle); + axisComponent.set('encode', axisEncode, !!axis.encoding || axis.labelAngle !== undefined); } return axisComponent; diff --git a/src/compile/data/window.ts b/src/compile/data/window.ts index fc9ef907ea..1833b5c07d 100644 --- a/src/compile/data/window.ts +++ b/src/compile/data/window.ts @@ -1,8 +1,7 @@ import {AggregateOp} from 'vega'; -import {WindowFieldDef, WindowTransform} from '../../transform'; +import {WindowFieldDef, WindowOnlyOp, WindowTransform} from '../../transform'; import {duplicate} from '../../util'; import {VgComparator, VgComparatorOrder, VgWindowTransform} from '../../vega.schema'; -import {WindowOnlyOp} from '../../window'; import {DataFlowNode} from './dataflow'; /** @@ -19,15 +18,15 @@ export class WindowTransformNode extends DataFlowNode { public producedFields() { const out = {}; - this.transform.window.forEach(element => { - out[this.getDefaultName(element)] = true; + this.transform.window.forEach(windowFieldDef => { + out[this.getDefaultName(windowFieldDef)] = true; }); return out; } - private getDefaultName(window: WindowFieldDef): string { - return window.as === undefined ? String(window.op) + '_field' : window.as; + private getDefaultName(windowFieldDef: WindowFieldDef): string { + return windowFieldDef.as === undefined ? String(windowFieldDef.op) + '_field' : windowFieldDef.as; } public assemble(): VgWindowTransform { @@ -47,9 +46,9 @@ export class WindowTransformNode extends DataFlowNode { const sortFields: string[] = []; const sortOrder: VgComparatorOrder[] = []; if (this.transform.sort !== undefined) { - for (const compField of this.transform.sort) { - sortFields.push(compField.field); - sortOrder.push(compField.order === undefined ? null : compField.order as VgComparatorOrder); + for (const sortField of this.transform.sort) { + sortFields.push(sortField.field); + sortOrder.push(sortField.order === undefined ? null : sortField.order as VgComparatorOrder); } } const sort: VgComparator = { diff --git a/src/compile/layoutsize/parse.ts b/src/compile/layoutsize/parse.ts index a9b488d94d..ab13730e3c 100644 --- a/src/compile/layoutsize/parse.ts +++ b/src/compile/layoutsize/parse.ts @@ -107,7 +107,7 @@ function defaultUnitSize(model: UnitModel, sizeType: 'width' | 'height'): Layout } } else { // No scale - set default size - if (sizeType === 'width' && model.mark() === 'text') { + if (sizeType === 'width' && model.mark === 'text') { // width for text mark without x-field is a bit wider than typical range step return config.scale.textXRangeStep; } diff --git a/src/compile/legend/encode.ts b/src/compile/legend/encode.ts index 89db975e52..44359bd1e3 100644 --- a/src/compile/legend/encode.ts +++ b/src/compile/legend/encode.ts @@ -25,13 +25,12 @@ export function symbols(fieldDef: FieldDef