how to layer multiple regression lines without repeating code? - vega-lite

I'm using Vega Lite to chart the times at which I eat my meals, and want a regression (loess) line showing the general time for each. By default, a regression uses the entire dataset and only shows one line; I want three lines, one for each meal (stored in the field extra_data.content).
I've achieved what I want to do my repeating the loess layer three times (screenshot) but am trying to find a solution in which the same layer is written once and repeats itself three times.
Edit after solving! Thanks very much to #jakevdp for the answer! Here is my working code; note that there is both a groupby on the loess and a color channel.
{
"mark": "line",
"transform": [
{
"loess": "hm",
"on": "ymd",
"groupby": ["extra_data.content"]
}
],
"encoding": {
"x": {
"field": "ymd",
"type": "temporal"
},
"y": {
"field": "hm",
"type": "temporal"
},
"color": {
"field": "extra_data.content",
"type": "nominal"
}
}
}

It sounds like you want the groupby argument of the loess transform, along with a color encoding. It might look something like this:
{
"mark": "line",
"transform": [
{
"loess": "hm",
"on": "ymd",
"groupby": ["extradata.content"]
}
],
"encoding": {
"x": {
"field": "ymd",
"type": "temporal"
},
"y": {
"field": "hm",
"type": "temporal"
},
"color": {
"field": "extradata.content",
"type": "nominal"
}
}
}

Related

Force vega-lite to show label when number is 0

I'm still very much a beginner in vega-lite but I'm trying to create a stacked bar chart with different sales channels. Sometimes a sales channel has a 0 and doesn't show up, how can I still show the label?
{
"layer": [
{
"mark": {
"type": "bar",
"cornerRadius": 50,
"color": "#90C290",
"tooltip": true
},
"encoding": {
"x": {
"field": "Number of customers"
}
}
},
{
"mark": {
"type": "text",
"tooltip": true,
"align": "left",
"baseline": "middle",
"x": 10,
"color": "white"
},
"encoding": {
"text": {
"field": "Number of customers",
"type": "text"
}
}
}
],
"encoding": {
"y": {
"field": "Sales channel",
"type": "nominal",
"sort": "descending",
"title": null
},
"x": {
"type": "quantitative",
"title": null,
"axis": null
}
}
}
I tried the code above and looked through documentation but couldn't exactly find what I was looking for
I added sample data to your spec, and there are a few changes I would make.
Around line 29 you have "type": "text" which should be "type": "quantitative".
I think your problem is that the text color is white and the background color is white, so the text is there but you can't see it. A simple fix would be to set the text color to black, or change the background color to something other than white (add "background": "lightgray", before "layer").
It's also possible you don't see the channel at all depending on how you are passing data from Power BI. Check the data tab in the Deneb window to make sure the Channel is there.
If the channel is not there, you'll have to adjust something on the Power BI side. A good practice is to put the data in a table in Power BI first so you know what you are sending into Deneb. If you use an aggregation like SUM on the data field in Power BI, nulls will drop out, but zeros should stay. If you use "Don't summarize" then nulls or errors (text in a number field) will pass in as nulls to Deneb, but you may need to add an "aggregate": "sum" to your encoding.
In any case, here's the spec the way I would write it.
{
"data": {"name": "dataset"},
"layer": [
{
"mark": {
"type": "bar",
"cornerRadius": 50,
"color": "#90C290",
"tooltip": true
}
},
{
"mark": {
"type": "text",
"tooltip": true,
"align": "left",
"baseline": "middle",
"dx": 5,
"color": "black"
},
"encoding": {
"text": {
"field": "Number of customers",
"type": "quantitative"
}
}
}
],
"encoding": {
"y": {
"field": "Sales channel",
"type": "nominal",
"sort": "descending",
"title": null
},
"x": {
"field": "Number of customers",
"type": "quantitative",
"title": null,
"axis": null
}
}
}
Link to sample data in Vega Editor

How to share labels in faceted nested charts of "Vega Lite"?

I want to use "Vega Lite" to achieve the faceted nesting effect similar to tableau. Although "Vega Lite" can also be achieved, the display effect is not satisfactory, which is mainly reflected in that each sub chart has its own coordinate axis label, and the information density is not high. Tableau is much more compact.
This is an example of tableau:
This is an example of vega-lite:
{
"data": {"url": "https://uniplore-source.oss-cn-chengdu.aliyuncs.com/other/orders2.csv"},
"spacing": 0,
"facet": {"row": {"field": "快递方式","type": "nominal",
"header":{"labelExpr": "null"}
}},
"spec": {
"facet": {"column": {"field": "类别","type": "nominal","header":{"labelExpr": "null"}}},
"spacing": 0,
"spec": {
"spacing": 0,
"facet": {
"column": {
"field": "子类别","type": "nominal"
}
},
"spec": {
"facet": {
"column": {
"field": "细分","type": "nominal"
}
},
"spec": {
"mark": "bar",
"spacing": 0,
"encoding": {
"x": {
"field": "细分","type": "nominal"
},
"y": {"aggregate": "sum","field":"销售额"}
}
}
}
}
}
}
You can view my example here.
In fact, the same amount of information can not be displayed on one screen with Vega Lite.
I have tried some configurations, but the effect is not obvious.
I want to know if there is any way Vega Lite can achieve the display effect of tableau.
The most important of these is shared labels.
Thank you.
If you mean shared axes, then you can do this using facet.
https://vega.github.io/vega-lite/docs/facet.html
Edit 1
Editor
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"name": "trellis_barley",
"description": "The Trellis display by Becker et al. helped establish small multiples as a “powerful mechanism for understanding interactions in studies of how a response depends on explanatory variables”. Here we reproduce a trellis of Barley yields from the 1930s, complete with main-effects ordering to facilitate comparison.",
"data": {"url": "data/barley.json"},
"mark": "point",
"height": {"step": 12},
"encoding": {
"facet": {
"spacing": {"row": -40},
"field": "site",
"type": "ordinal",
"columns": 2,
"sort": {"op": "median", "field": "yield"},
"header":{"labelExpr": "null"}
},
"x": {
"aggregate": "median",
"field": "yield",
"type": "quantitative",
"scale": {"zero": false}
},
"y": {"field": "variety", "type": "ordinal", "sort": "-x"},
"color": {"field": "year", "type": "nominal"}
}
}

plot small multiples in vega-lite with gray background

I'm looking for a vega-lite configuration to show small multiples (using the facet operator row or column) with all other data points greyed out in the background.
Here is an example plot using the facet-operator:
facet plot
in vega-editor
"facet": {
"row": {
"field": "group",
"type": "nominal"
}
},
And here is an example using multiple charts with the concat operator and color channel to grey out other groups:
concat-plot
in vega-editor
"color": {"condition": {"test": "datum['group'] != 1", "value": "grey"}, "value": "red"}
I was wondering if there is a combination of transforms and repeat commands to achieve this for an unknown number of groups.
Here is one possible solution:
create an additional layer with new data
"facet": {"row": {"field": "group"}},
"spec": {
"layer": [
{
"data": {"name": "main"},
"mark": "circle",
"encoding": {
"y": {
"field": "y",
"type": "ordinal"
},
"x": {
"field": "x",
"type": "ordinal"
},
"color": {"value": "grey"}
},
"params": []
},
{
"mark": {"type": "circle", "opacity": 1, "color": "red"},
"encoding": {
"y": {
"field": "y",
"type": "ordinal"
},
"x": {
"field": "x",
"type": "ordinal"
}
}
}
]
}
full example in vega editor

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"
}}
]
}

How to add vertical Rule with constant value to Vega Lite chart?

I want to add vertical Rule lines to my chart as date milestone indicators (like the red line in image).
X axis is dates (temportal), and y axis values are numbers.
In image is the closest I could get using explicit values for data property in Rule layer:
{
"mark": "rule",
"data": {
"values": [
"{\"x\":\"2020/04/10\"}"
]
},
"encoding": {
"x": {
"field": "x",
"type": "ordinal",
},
"color": {
"value": "red"
},
"size": {
"value": 1
}
}
}
I have also tried types: "type": "temportal", and "type": "quantitative", "aggregate": "distinct" with no luck.
My goal is to be able to add multiple red vertical Rule lines with explicit/constant x values to the chart.
Datum is meant for specifying literal fixed values. You can add several rules by layering them together with your main data. This approach works with quantitative data encoded in the x channel:
"layer": [
{
"mark": { "type": "line" },
"encoding": { "y": {...}, },
},
{
"mark": { "type": "rule", "color": "red", "size": 1, },
"encoding": {"x": {"datum": 42}},
},
{
"mark": { "type": "rule", "color": "blue", "size": 1, },
"encoding": {"x": {"datum": 100}},
},
]
For dealing with temporal data, you additionally have to specify how it should be parsed. This approach works for me:
"layer": [
{
// First layer: spec of your main linear plot.
},
{
// Second layer: spec of the vertical rulers.
"mark": { "type": "rule", "color": "red", "size": 2, },
"encoding": {
"x": { "field": "date", "type": "temporal", },
},
"data": {
"values": [
{"date": "25 May 2020 14:15:00"},
{"date": "25 May 2020 14:20:59"},
],
"format": {
"parse": {"date": "utc:'%d %b %Y %H:%M:%S'"}
}
},
},
]