How to avoid zoom conflict in a line chart with layer? - vega-lite

VEGA-lite is not perfect, but is very good, and in general for something that looks like a bug, there are a workaround... So I supposing that in this "bug" we have a workaround.
((edit after answer: it is not a real bug, is a "semantic bug" on the specification language))
The strange behaviour, a "semantic bug": I was using selection: { "grid": {"type":"interval", "bind":"scales"} } for zoom, in a trivial context, with simple mark: 'line'. When I add layer, it stopts to work.
{
title: "Número de registros por minuto (n_count normalizado)",
$schema: vglVers,
data: { "url":"mySQLtable" },
selection: { "grid": {"type":"interval", "bind":"scales"} }, // was working with simple mark
//mark: 'line',
width:340,
encoding: {
x: {"field": "instant", "type": "temporal"},
y: {"field": "n_pmin", "type": "quantitative"},
color: {"field": "symbol", "type": "nominal"}
},
layer: [
{
"mark": {"type": "line", "point": true},
"transform": [{"filter": "datum.symbol == 'n_pmin'"}]
},
{ "mark": {"type": "line"}, "transform": [{"filter": "datum.symbol != 'n_pmin'"}] }
]
}
The workaround: as #jakevdp commented here,
"the interval selection must be added to one of the layers". But
How to do this "interval selection"?
The data on my chart is not static, I need a interval that changes with it, so, not make sense to set a interval.

The "interval selection" I referred to is the interval selection definition within your chart:
selection: { "grid": {"type":"interval", "bind":"scales"} }
You cannot declare it in the top-level chart; you must declare it in one of the layers:
{
title: "Número de registros por minuto (n_count normalizado)",
$schema: vglVers,
data: { "url":"mySQLtable" },
width:340,
encoding: {
x: {"field": "instant", "type": "temporal"},
y: {"field": "n_pmin", "type": "quantitative"},
color: {"field": "symbol", "type": "nominal"}
},
layer: [
{
"mark": {"type": "line", "point": true},
"transform": [{"filter": "datum.symbol == 'n_pmin'"}],
"selection": {"grid": {"type":"interval", "bind":"scales"}},
},
{
"mark": {"type": "line"},
"transform": [{"filter": "datum.symbol != 'n_pmin'"}]
}
]
}
Your issue is not a bug, nor is my solution a workaround: the vega-lite schema specifies that selections must be declared within a unit spec (i.e. an individual layer).

Related

Make vega-lite selection only take effect on mouseup

I would like to have an interval selection in a Vega-lite in which other data is filtered in response to the selection, but only after the user releases the mouse. For instance, consider this example where the user can filter the dates in a time series plot by selecting a range on another chart. As the user drags the selection in the bottom chart the top chart filters in real-time. What I would like to do is instead have the top chart only filter once the user has updated the selection in the bottom chart and released the mouse button.
Try this. It seems a bit awkward to me but does what you ask.
Editor
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {"url": "data/sp500.csv"},
"vconcat": [
{
"width": 480,
"mark": "area",
"encoding": {
"x": {
"field": "date",
"type": "temporal",
"scale": {"domain": {"param": "brush"}},
"axis": {"title": ""}
},
"y": {"field": "price", "type": "quantitative"}
}
},
{
"width": 480,
"height": 60,
"mark": "area",
"params": [
{
"name": "brush",
"select": {
"type": "interval",
"encodings": ["x"],
"on": {
"type": "mousemove",
"between": [{"type": "mouseup"}, {"type": "mousedown"}]
}
}
}
],
"encoding": {
"x": {"field": "date", "type": "temporal"},
"y": {
"field": "price",
"type": "quantitative",
"axis": {"tickCount": 3, "grid": false}
}
}
}
]
}

theta and theta2 chanel encoding by field

I want to create arcs using vega-lite, here you will find a working example: enter link description here
but this does not work: enter link description here
The difference is only that I use this in the working example
"encoding": {
"theta": {"value": {"expr": "datum.thta"}},
"theta2": {"value": {"expr": "datum.thta2"}} }
And this is the code that does not work:
"encoding": {
"theta": {"field": "thta"},
"theta2": {"field": "thta2"}} }
Can someone explain why using the "fields" creates a half circle (not wanted) and "value" creates the quarter circle (wanted)?
Many thanks in advance
When you specify values via encodings, the scale is automatically adjusted based on the content of the data. You can fix this by specifying that the scale should be from 0 to 2pi (open in editor):
{
"width": 80,
"height": 80,
"params": [{"name": "radius", "value": 0}, {"name": "radius2", "value": 50}],
"data": {
"values": [{"name": "arc1", "quadrant": "TopRight", "ring": "Hold"}]
},
"transform": [
{
"calculate": "if(datum.quadrant === 'TopRight' , PI*0.5 , null)",
"as": "thta2"
},
{"calculate": "if(datum.quadrant === 'TopRight' , 0 , null)", "as": "thta"}
],
"mark": {
"type": "arc",
"radius": {"expr": "radius"},
"radius2": {"expr": "radius2"}
},
"encoding": {
"theta": {"field": "thta", "scale": {"domain": [0, "2*PI"]}},
"theta2": {"field": "thta2"}
}
}

Creating custom bar chart in Vega-Lite

I am a newbie to Vega-Lite and I am trying to replicate a chart similar to this
Following is my code and it does not generate what I need.
{
"$schema":"https://vega.github.io/schema/vega-lite/v5.json",
"width":800,
"height":600,
"autosize":{
"type":"fit",
"contains":"padding"
},
"data":{
"url":"data/cars.json"
},
"mark":{
"type":"rect",
"tooltip":true,
"strokeWidth":0.1,
"stroke":"white"
},
"encoding":{
"x":{
"field":"Horsepower",
"type":"quantitative",
"bin":{
"maxbins":100
},
"axis":{
"labelAngle":0
}
},
"y":{
"aggregate":"count",
"field":"Horsepower",
"type":"quantitative"
}
}
}
Here is what it does
What do I need to do to be able to get my desired output? There is a question here already asked on the topic How to reproduce the Unsub histogram in Altair? but it was done in python altair, which I am not trying to do. I want to generate that using solely Vega-Lite.
Thank you in advance.
You can use a bin transform followed by a window transform to generate the fields required to create this kind of chart. For example (open in editor):
{
"data": {"url": "data/cars.json"},
"transform": [
{"bin": {"maxbins": 50}, "field": "Horsepower", "as": "Horsepower"},
{"window": [{"op": "count", "as": "index"}], "groupby": ["Horsepower"]}
],
"mark": {
"type": "rect",
"tooltip": true,
"strokeWidth": 0.3,
"stroke": "white"
},
"encoding": {
"x": {"field": "Horsepower", "type": "quantitative", "bin": "binned"},
"x2": {"field": "Horsepower_end"},
"y": {
"field": "index",
"type": "ordinal",
"scale": {"reverse": true},
"title": "count"
}
},
"width": 400,
"height": 300
}

Can you have facets & layers in single Vegalite plot?

I am struggling to understand why a layer spec like the below:
"layer": [
{"encoding": {
"facet": {"field": "FEATURE_VALUE"},
"x": {
"field": "DATE",
"type": "temporal"
},
"y": {
"field": "VALUE",
"type": "quantitative"
}
},
"mark": {
"type": "line"
}}
]
Throws an error to the effect of: Cannot read property 'push' of undefined
Meanwhile, the unit spec:
"encoding": {
"facet": {"field": "FEATURE_VALUE"},
"x": {
"field": "DATE",
"type": "temporal"
},
"y": {
"field": "VALUE",
"type": "quantitative"
}
},
"mark": {
"type": "line"
}
}
works just fine.
I can tell this has something to do with: Altair: Can't facet layered plots
However, can't quite seem to answer the principle question: can I have a trellis plot using facet as well as have layers on top of that (for say tooltips, rulers, etc.)
Thank you!
Vega-Lite provides two ways to specify facets: as an encoding (See Facet, Row, and Column Encoding Channels) and as an operator (See Facet Operator).
A layer chart is not allowed to contain a facet encoding, however a facet operator can contain a layer chart (the reason for this is that the semantics of layers containing incompatible facets is unclear).
So, instead of something like this:
"layer": [
{"encoding": {
"facet": {"field": "FEATURE_VALUE"},
"x": {
"field": "DATE",
"type": "temporal"
},
"y": {
"field": "VALUE",
"type": "quantitative"
}
},
"mark": {
"type": "line"
}}
]
you can do something like this:
"facet": {"field": "FEATURE_VALUE"},
"spec": {
"layer": [
{"encoding": {
"x": {
"field": "DATE",
"type": "temporal"
},
"y": {
"field": "VALUE",
"type": "quantitative"
}
},
"mark": {
"type": "line"
}}
]
}

Vega-lite interactive legend and bar chart

I'm fairly new to vega-lite. I'd really like to get the following interactive bar chart working:
Legend for the bar chart that can be clicked on to highlight one or more bars
Click on one or more bars to highlight and reflect that it legend
When highlighed, show text value above the bar.
My strategy for building this is to have two layers, one layer for the bars, and one for the text. Then one selection that is in 'multi' mode on mousedown, and also bound to the legend.
My question is two-fold:
Is it possible to have a selection bound to the legend but also utilize mousedown?
I'm having a hard time understanding how selections work in layered graphs/charts. If I define the selection outside of the layers I get a warning saying selection can't be found, and the selection only works as expected if I put it in the definition of the first layer. Additionally, the legend binding seems to work if I don't have layers, but stops working when I do have layers. Is this a limitation of the library or am I doing something wrong.
Here is my schema, thanks for any help in advance!
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"description": "A simple bar chart with embedded data.",
"title": "test",
"data": {
"values": [
["Lateral", 630.666127],
["Basal", 413.211154],
["Accessory", 257.842981],
["Anterior", 48.735523],
["Central", 45.797799],
["Medial", 30.314856],
["Cortical", 27.697457],
["Corticoamygdaloid", 169.707268],
["Paralaminar", 46.216784],
["Whole_amygdala", 1670.189948]
],
"name": "data"
},
"width": "600",
"height": "400",
"encoding": {
"x": {"field": "0", "type": "nominal", "sort": "-y"},
"y": {"field": "1", "type": "quantitative"}
},
"layer": [
{
"mark": "bar",
"encoding": {
"color": {
"field": "0"
},
"opacity": {
"condition": {"selection": "series", "value": 1},
"value": 0.2
}
},
"selection": {
"series": {"type": "multi", "bind": "legend"}
}
},
{
"transform": [{"filter": {"selection":"series"}}],
"mark": {"type": "text", "dy": -5},
"encoding": {"text": {"field": "1"}}
}
]
}
You were quite close. When you bind a selection to a legend, by default it deactivates other ways of interacting. But as mentioned briefly in the Legend Binding docs, you can re-enable this by specifying the "on" attribute. Here is the result (Open in editor):
{
"title": "test",
"data": {
"values": [
["Lateral", 630.666127],
["Basal", 413.211154],
["Accessory", 257.842981],
["Anterior", 48.735523],
["Central", 45.797799],
["Medial", 30.314856],
["Cortical", 27.697457],
["Corticoamygdaloid", 169.707268],
["Paralaminar", 46.216784],
["Whole_amygdala", 1670.189948]
],
"name": "data"
},
"width": "600",
"height": "400",
"encoding": {
"x": {"field": "0", "type": "nominal", "sort": "-y"},
"y": {"field": "1", "type": "quantitative"}
},
"layer": [
{
"mark": "bar",
"encoding": {
"color": {"field": "0"},
"opacity": {
"condition": {"selection": "series", "value": 1},
"value": 0.2
}
},
"selection": {
"series": {
"type": "multi",
"encodings": ["color"],
"on": "click",
"bind": "legend"
}
}
},
{
"transform": [{"filter": {"selection": "series"}}],
"mark": {"type": "text", "dy": -5},
"encoding": {"text": {"field": "1"}}
}
]
}
Regarding your second question: currently selections must be defined within the layers they are bound to, but this will likely change in future Vega-Lite versions; see https://github.com/vega/vega-lite/pull/6919.