Sort bars of Stacked Bar Chart - vega-lite

For a Stacked Bar Chart, can you sort the bars by the size of one of the segments?
E.g., take this Stacked Bar Chart from the examples (Open Editor):
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {"url": "data/barley.json"},
"mark": "bar",
"encoding": {
"x": {"aggregate": "sum", "field": "yield"},
"y": {"field": "variety"},
"color": {"field": "site"}
}
}
Now I would like to sort the y-axis based on the yield in Crookston. Is that possible?

Sorting by the total of another field is relatively easy; you can do so with the "sort" entry of the desired encoding (sort docs):
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {"url": "data/barley.json"},
"mark": "bar",
"encoding": {
"x": {"aggregate": "sum", "field": "yield"},
"y": {"field": "variety", "sort": {"op": "sum", "field": "yield"}},
"color": {"field": "site"}
}
}
If you want to sort just by the value when site == "Crookston", you can do so by first applying a calculate transform to select just that value:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {"url": "data/barley.json"},
"transform": [
{
"calculate": "datum.site == 'Crookston' ? datum.yield : 0",
"as": "crookston"
}
],
"mark": "bar",
"encoding": {
"x": {"aggregate": "sum", "field": "yield"},
"y": {"field": "variety", "sort": {"op": "sum", "field": "crookston"}},
"color": {"field": "site"}
}
}

Related

How to Annotate a Line in line Chart in Vega-Lite?

How to annotate a line in line chart in vega-lite
For the below code https://vega.github.io/editor/#/
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"layer": [
{
"data": {"url": "data/stocks.csv"},
"mark": "line",
"encoding": {
"x": {"field": "date", "type": "temporal"},
"y": {"field": "price", "type": "quantitative"},
"color": {"field": "symbol", "type": "nominal"}
}
},
{
"data": {"values": [{}]},
"mark": {"type": "rule", "strokeDash": [2, 2], "size": 2},
"encoding": {"x": {"datum": {"year": 2006}}}
}
]
}
We get plot
If I want to annotate the line at a specific position like (2004,400)
I tried this, it is working, but I don't want to pass hardcoded values like "a": 2004, "b": 400,
{
"data": {
"values": [
{"a": 2004, "b": 400}
]
},
"mark": {"type": "text", "fontSize" : 16, "fontWeight":"bold", "align" : "left"},
"encoding": {
"text": {"value": "Optimum"},
"x": {"field": "a", "type": "quantitative", "title":""},
"y": {"field": "b", "type": "quantitative", "title":""}
}
},
How to pass specific values from the data like average value of date (say:2004) and average value of price (say:400)?
or
just next to the line in the middle of y-axis
Transform and Aggregate Worked, I needed only for Y axis average position, so below code worked good. For another axis we can use same transform.
{
"mark": {"type": "text", "fontSize" : 16, "fontWeight":"bold", "align" : "left"},
"transform": [
{
"aggregate": [{
"op": "mean",
"field": "price",
"as": "mean_y_axis"
}],
"groupby": ["date"]
}
],
"encoding": {
"text": {"value": "Optimum"},
"x": {"field": "date",
"type": "quantitative"},
"y": {"field": "mean_y_axis",
"type": "quantitative"}
}
}

vega: filter nth of each group

If I were to group by date, how would I filter the nth entry of each group?
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"data": {"url": "https://cdn.jsdelivr.net/npm/vega-datasets#v1.29.0/data/seattle-temps.csv"},
"mark": "point",
"encoding": {
"x": {"field": "date", "type": "temporal"},
"y": {"field": "temp", "type": "quantitative"}
}
}
edit
Let's keep this data-agnostic as my data has many columns and I would like rows in their entirety.
Transforms overview:
Convert times to dates for grouping.
Group by date and number each row within the groups.
Filter on nth row.
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"data": {"url": "https://cdn.jsdelivr.net/npm/vega-datasets#v1.29.0/data/seattle-temps.csv"},
"transform": [
{"timeUnit": "yearmonthdate", "field": "date", "as": "date"},
{
"window": [{"op": "row_number", "as": "row"}],
"groupby": ["date"]
},
{"calculate": "datum.index", "as":"newnew"},
{"filter": "datum['row'] == 1"}
],
"mark": "point",
"encoding": {
"x": {"field": "date", "type": "temporal"},
"y": {"field": "temp", "type": "quantitative"}
}
}
The downside is that the vega editor becomes very slow after adding the window transform.

How to zoom only on a specific axis when mouse over it?

Starting from this concrete example where 2 plots are linked on their horizontal axis and free on their vertical axis, is there a way to zoom only on a specific axis when the mouse is over it ?
The zoom actually set is common to both axis.
If you want scrolling to be independent in each panel, you need to do two things:
set resolve.scale.x and resolve.scale.y to "independent", so the scales will not be linked.
use a different name for the bound selection in each panel, so the selectors will not be linked.
For example (vega editor):
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"data": {"url": "data/stocks.csv"},
"vconcat": [
{
"transform": [{"filter": "datum.symbol==='IBM'"}],
"mark": "line",
"encoding": {
"x": {"field": "date", "type": "temporal"},
"y": {"field": "price", "type": "quantitative"}
},
"selection": {"scroll_1": {"type": "interval", "bind": "scales"}}
},
{
"transform": [{"filter": "datum.symbol==='GOOG'"}],
"mark": "line",
"encoding": {
"x": {"field": "date", "type": "temporal"},
"y": {"field": "price", "type": "quantitative"}
},
"selection": {"scroll_2": {"type": "interval", "bind": "scales"}}
}
],
"resolve": {"scale": {"x": "independent", "y": "independent"}}
}

Vega-Lite layered chart: how to get tick marks and tick labels to span the entire axis?

I am working on a layered chart where I have both bars and rule lines. The issue I'm having is that on the x-axis, the tick marks and tick labels only appear under the bars and do not span the entire axis, making it so that there are no tick marks and labels underneath where the rule lines are located. Here is an example of what I'm seeing (link to Vega editor):
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"data": {"url": "data/movies.json"},
"transform": [
{"calculate": "2*datum.IMDB_Rating", "as": "UpperLimit"}
],
"layer": [
{
"mark": "bar",
"encoding": {
"x": {"bin": true, "field": "IMDB_Rating", "type": "quantitative"},
"y": {"aggregate": "count", "type": "quantitative"}
}
},
{
"mark": "rule",
"encoding": {
"x": {
"aggregate": "max",
"field": "UpperLimit",
"type": "quantitative"
},
"color": {"value": "red"},
"size": {"value": 5}
}
}
]
}
Image of issue
How do I get the tick marks and labels to span the entire axis? Thanks in advance for the help!
When you use a bin transform within an encoding, Vega-Lite adjusts the default axis properties to match the binning. You can re-adjust these manually via the encoding's scale and axis properties, but I think a simpler way is to move the bin transform to the chart's transform specification. Here is an example (Vega Editor):
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"data": {"url": "data/movies.json"},
"transform": [
{"calculate": "2*datum.IMDB_Rating", "as": "UpperLimit"},
{
"bin": true,
"field": "IMDB_Rating",
"as": ["IMDB_Rating_0", "IMDB_Rating_1"]
}
],
"layer": [
{
"mark": "bar",
"encoding": {
"x": {
"field": "IMDB_Rating_0",
"type": "quantitative",
"bin": "binned"
},
"x2": {"field": "IMDB_Rating_1"},
"y": {"aggregate": "count", "type": "quantitative"}
}
},
{
"mark": "rule",
"encoding": {
"x": {
"aggregate": "max",
"field": "UpperLimit",
"type": "quantitative"
},
"color": {"value": "red"},
"size": {"value": 5}
}
}
]
}

Is there a way to add a line break between the plot and X axis (vega-lite)

I am not sure if it makes sense but will it be possible to add a line break between the start of the plot and the X-axis.
For e.g.
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"width": {"step": 10},
"height": 120,
"data": {"url": "data/cars.json"},
"mark": "area",
"encoding": {
"x": {"field": "Name", "type": "nominal", "scale": {"round": false}},
"y": {"aggregate": "count", "type": "quantitative"}
}
}
Hopeful output:
One way to do this is by adding a scale.domain argument:
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"width": {"step": 10},
"height": 120,
"data": {"url": "data/cars.json"},
"mark": "area",
"encoding": {
"x": {"field": "Name", "type": "nominal", "scale": {"round": false}},
"y": {"aggregate": "count", "type": "quantitative", "scale": {"domain": [-0.5, 6]}}
}
}
Another way to do this is to use the y and y2 encodings to set a bottom value for the area chart:
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"width": {"step": 10},
"height": 120,
"data": {"url": "data/cars.json"},
"mark": "area",
"transform": [{"calculate": "0.1", "as": "bottom"}],
"encoding": {
"x": {"field": "Name", "type": "nominal", "scale": {"round": false}},
"y": {"aggregate": "count", "type": "quantitative"},
"y2": {"field": "bottom"}
}
}
Another way to do something similar, adding it as another answer to make it convenient for others.
offset property of axis shifts the axis line by fixed pixels, independent of the data. Using offset adds a gap between the x and y axis lines though.
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"width": {"step": 10},
"height": 120,
"data": {"url": "data/cars.json"},
"mark": "area",
"encoding": {
"x": {"field": "Name", "type": "nominal", "scale": {"round": false}, "axis": {"offset": 5}},
"y": {"aggregate": "count", "type": "quantitative"}
}
}