Force order of painting, in non-stacked area chart - vega-lite

While working with Vega Lite, I'm unable to force the same order for painting non-stacked areas.
For example, see what happens here:
In the rows picture above, I expect light-blue to always be behind dark-blue. However this is not true for the 3rd, 4th, and 6th row.
I've tried several combinations of order, sort, and zrank — with no success. Any idea on how to force this?
See the sample full viz in the editor — I can't get India, Israel, or Japan to display the dark-blue area on top of the light-blue.

I don't think there is currently a way to control the z order of area charts from the chart spec, but you can control it via the order of the data source: the colors are stacked in the order that they appear. For example, here in row 0, color 1 comes first, and in row 1, color 0 comes first:
{
"data": {
"values": [
{"x": 0, "y": 2, "row": 0, "color": 1},
{"x": 1, "y": 1, "row": 0, "color": 1},
{"x": 0, "y": 1, "row": 0, "color": 0},
{"x": 1, "y": 2, "row": 0, "color": 0},
{"x": 0, "y": 2, "row": 1, "color": 0},
{"x": 1, "y": 1, "row": 1, "color": 0},
{"x": 0, "y": 1, "row": 1, "color": 1},
{"x": 1, "y": 2, "row": 1, "color": 1}
]
},
"mark": "area",
"encoding": {
"x": {"field": "x", "type": "temporal"},
"y": {"field": "y", "type": "quantitative", "stack": false},
"color": {"field": "color", "type": "ordinal"},
"row": {"field": "row", "type": "ordinal"}
},
"height": 50
}
If you rearrange the rows so that color 0 appears before color 1 in both cases, the stack order on the chart will be consistent:
{
"data": {
"values": [
{"x": 0, "y": 1, "row": 0, "color": 0},
{"x": 1, "y": 2, "row": 0, "color": 0},
{"x": 0, "y": 2, "row": 0, "color": 1},
{"x": 1, "y": 1, "row": 0, "color": 1},
{"x": 0, "y": 2, "row": 1, "color": 0},
{"x": 1, "y": 1, "row": 1, "color": 0},
{"x": 0, "y": 1, "row": 1, "color": 1},
{"x": 1, "y": 2, "row": 1, "color": 1}
]
},
"mark": "area",
"encoding": {
"x": {"field": "x", "type": "temporal"},
"y": {"field": "y", "type": "quantitative", "stack": false},
"color": {"field": "color", "type": "ordinal"},
"row": {"field": "row", "type": "ordinal"}
},
"height": 50
}
If you re-order the rows your input data by year (so all 2019 entries come before all 2020 entries), the stack order should be the same in each panel.

Related

How to position text at the top edge of a VegaLite chart?

I am trying to create a VegaLite chart with labelled highlighted areas which are specified in a separate dataset using [min_x, max_x] coordinates.
I've managed to highlight the area itself using a rect mark, but I'm struggling to properly position the label at the top edge of the chart.
This is the end result I'm trying to achieve. In this example I'm using the dy property of the text mark to position the label. Unfortunately this only works when the chart height is known in advance, which doesn't work for my use case.
If there is a better way to achieve the result I want, please let me know. This is the Vegalite specification for the chart above, without previously mentioned dy property:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"datasets": {
"test_data": [
{"x": 0, "y": 1.5},
{"x": 5, "y": 2},
{"x": 9, "y": 4},
{"x": 14, "y": 0}
],
"highlight_data": [
{"from_x": 2.3, "to_x": 3, "label": "AAA"},
{"from_x": 6.3, "to_x": 8, "label": "BBB"}
]
},
"data": {"name": "test_data"},
"layer": [
{
"data": {"name": "highlight_data"},
"transform": [
{"calculate": "(datum.from_x + datum.to_x) / 2", "as": "mean_x"}
],
"layer": [
{
"mark": {"type": "rect", "opacity": 0.3},
"encoding": {
"x": {"field": "from_x", "type": "quantitative"},
"x2": {"field": "to_x"},
"color": {"value": "#fcfc00"}
}
},
{
"mark": {"type": "text"},
"encoding": {
"text": {"field": "label"},
"x": {"field": "mean_x", "type": "quantitative"}
}
}
]
},
{
"mark": {"type": "line"},
"encoding": {
"x": {"field": "x", "type": "quantitative", "title": "X Label"},
"y": {"field": "y", "type": "quantitative", "title": "Y Label"}
}
}
],
"title": "Title",
"width": 800,
"height": 500
}
You can reference height inside an expression to make it dynamic.
"dy": { "expr": "-height + (height/2) -10"}
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"datasets": {
"test_data": [
{"x": 0, "y": 1.5},
{"x": 5, "y": 2},
{"x": 9, "y": 4},
{"x": 14, "y": 0}
],
"highlight_data": [
{"from_x": 2.3, "to_x": 3, "label": "AAA"},
{"from_x": 6.3, "to_x": 8, "label": "BBB"}
]
},
"data": {"name": "test_data"},
"layer": [
{
"data": {"name": "highlight_data"},
"transform": [
{"calculate": "(datum.from_x + datum.to_x) / 2", "as": "mean_x"}
],
"layer": [
{
"mark": {"type": "rect", "opacity": 0.3},
"encoding": {
"x": {"field": "from_x", "type": "quantitative"},
"x2": {"field": "to_x"},
"color": {"value": "#fcfc00"}
}
},
{
"mark": {"type": "text", "dy": { "expr": "-height + (height/2) -10"}},
"encoding": {
"text": {"field": "label"},
"x": {"field": "mean_x", "type": "quantitative"}
}
}
]
},
{
"mark": {"type": "line"},
"encoding": {
"x": {"field": "x", "type": "quantitative", "title": "X Label"},
"y": {"field": "y", "type": "quantitative", "title": "Y Label"}
}
}
],
"title": "Title",
"width": 800,
"height": 500
}

Adding Axis padding/inner margin to Vega-Lite chart

I have a created a vega-lite scatterplot chart. The data for this chart will always be positive, however it is often zero. In this application, it would be helpful for the user for points who's x or y are zero to not overlap with the lines for the axis
The straightforward solution is to try and manually adjust the domain and range to start before 0 and after the maximum value. However, I'd like to know if there is a way to do this in the configuration instead. I have read through the documentation and, to my knowledge and ability, I have not yet found such a solution.
If you want to ensure that the lowest point does not overlap the axis, one way to do so is to use the axis "offset" property, which allows you to specify the horizontal offset of the y-axis in pixels. For example (open in editor):
{
"data": {
"values": [
{"x": 0, "y": 2},
{"x": 1, "y": 4},
{"x": 2, "y": 3},
{"x": 3, "y": 5},
{"x": 4, "y": 4}
]
},
"mark": "point",
"encoding": {
"x": {"field": "x", "type": "quantitative"},
"y": {"field": "y", "type": "quantitative", "axis": {"offset": 20}}
}
}
In addition to adjusting the domain and adding an axis offset, you can use the scale config properties to add padding for all scales of a certain type. This will add some whitespace between the axis lines and the location of the closest data points:
{
"config": {
"scale": {"continuousPadding": 5}
},
"data": {
"values": [
{"x": 0, "y": 2},
{"x": 1, "y": 4},
{"x": 2, "y": 3},
{"x": 3, "y": 5},
{"x": 4, "y": 4}
]
},
"mark": "point",
"encoding": {
"x": {"field": "x", "type": "quantitative"},
"y": {"field": "y", "type": "quantitative"}
}
}

Vega Lite: symlog scale with more tick marks

Is there a way to use the symlog scale, but with tick marks placed on many orders of magnitude?
To explain, the log scale has tick marks on many orders of magnitude, but cannot show ≤ 1 values (last bar is hidden in this example):
On the other hand, symlog scale can represent negative, zero, and one-valued data, but by default only has tick marks for the largest order of magnitude:
You can specify a list of desired tick values using the axis.values specification. For example:
{
"mark": "point",
"data": {
"values": [
{"x": 0, "y": 1},
{"x": 1, "y": 10},
{"x": 2, "y": 100},
{"x": 3, "y": 1000},
{"x": 4, "y": 10000},
{"x": 5, "y": 100000},
{"x": 6, "y": 1000000},
{"x": 7, "y": 10000000}
]
},
"encoding": {
"x": {"field": "x", "type": "quantitative"},
"y": {
"field": "y",
"axis": {"values": [10, 100, 1000, 10000, 100000, 1000000, 10000000]},
"scale": {"type": "symlog", "constant": 1}
}
}
}

How do I create a legend for a layered line plot

Basically what I have is a line graph that is layered from several line graphs. Since each graph has only one line, there is no legend automatically generated, so what is the best way to get a legend for the chart? I have been considering trying to transform my dataset. This is weekly deaths total from the cdc from 2019-June 2020. The way the csv is arranged is each date for each state has a record with each disease type as it's own column and integers as the column values. So there isn't one field to chart, there are many, hence the layering. Any insights into how to solve this problem would be much appreciated! Here is my work so far:
https://observablehq.com/#justin-krohn/covid-excess-deaths
You can create a legend for a layered chart by setting the color encoding for each layer to a datum specifying what label you would like it to have. For example (vega editor):
{
"data": {
"values": [
{"x": 1, "y1": 1, "y2": 2},
{"x": 2, "y1": 3, "y2": 1},
{"x": 3, "y1": 2, "y2": 4},
{"x": 4, "y1": 4, "y2": 3},
{"x": 5, "y1": 3, "y2": 5}
]
},
"encoding": {"x": {"field": "x", "type": "quantitative"}},
"layer": [
{
"mark": "line",
"encoding": {
"y": {"field": "y1", "type": "quantitative"},
"color": {"datum": "y1"}
}
},
{
"mark": "line",
"encoding": {
"y": {"field": "y2", "type": "quantitative"},
"color": {"datum": "y2"}
}
}
]
}
Alternatively, you can use a Fold Transform to pivot your data so that instead of manual layers, you can plot the multiple lines with a simple color encoding. For example (vega editor):
{
"data": {
"values": [
{"x": 1, "y1": 1, "y2": 2},
{"x": 2, "y1": 3, "y2": 1},
{"x": 3, "y1": 2, "y2": 4},
{"x": 4, "y1": 4, "y2": 3},
{"x": 5, "y1": 3, "y2": 5}
]
},
"transform": [{"fold": ["y1", "y2"], "as": ["name", "y"]}],
"mark": "line",
"encoding": {
"x": {"field": "x", "type": "quantitative"},
"y": {"field": "y", "type": "quantitative"},
"color": {"field": "name", "type": "nominal"}
}
}

Why are tooltip values rounded?

For some reason my tooltips are rounded to the nearest integer?
Any help is appreciated.
Here is the link to chart in the VL editor (version 3.0.0-rc14).
(vega editor link)
{
"width": 300,
"height": 300,
"config": {
"title": {"fontSize": 15},
"numberFormat": ".0f",
"style": {
"bar": {"size": 20},
"guide-title": {"value": "asdf", "fontSize": 15},
"guide-label": {"fontSize": 15}
},
"scale": {"bandPaddingInner": 0.5, "bandPaddingOuter": 0.5},
"legend": {"symbolSize": 100, "titleFontSize": 15, "labelFontSize": 15},
"axis": {"titleFontSize": 15, "labelFontSize": 15, "labelLimit": 1000}
},
"data": {"name": "data-dba50c8bae540866b10e6763560b8ec9"},
"mark": "circle",
"encoding": {
"tooltip": [
{"type": "quantitative", "field": "expressiveness"},
{"type": "quantitative", "field": "customization"}
],
"x": {"type": "quantitative", "field": "expressiveness"},
"y": {"type": "quantitative", "field": "customization"}
},
"$schema": "https://vega.github.io/schema/vega-lite/v2.6.0.json",
"datasets": {
"data-dba50c8bae540866b10e6763560b8ec9": [
{"library": "A", "expressiveness": 0, "customization": 1},
{"library": "B", "expressiveness": 0.4, "customization": 0.7},
{"library": "C", "expressiveness": 1, "customization": 0.7},
{"library": "D", "expressiveness": 0.6, "customization": 0.7},
{"library": "E", "expressiveness": 0, "customization": 1}
]
}
}
Because you set "numberFormat": ".0f" in the config, and that's applied to the tooltip too.