how to control the order of groups in a vega-lite stacked bar chart - vega-lite

Given a stacked bar chart such as in this example: https://vega.github.io/editor/?#/examples/vega-lite/stacked_bar_weather
I want to control the order of the items in the aggregation so that, for example, 'fog' comes at the bottom, with 'sun' next etc. Is that possible?
The reason for this is I have one type that is much larger than the others. I want this to appear at the bottom, then control the domain to 'cut off' most of that section.
Thanks

You can control the stack order via the order encoding: see https://vega.github.io/vega-lite/docs/stack.html#sorting-stack-order
Unfortunately, this only allows sorting by field value, rather than by an explicit order as you want here. The workaround is to use a calculate transform to turn your explicit order into a field (view in editor):
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"data": {"url": "data/seattle-weather.csv"},
"transform": [
{
"calculate": "indexof(['sun', 'fog', 'drizzle', 'rain', 'snow'], datum.weather)",
"as": "order"
}
],
"mark": "bar",
"encoding": {
"x": {
"timeUnit": "month",
"field": "date",
"type": "ordinal",
"axis": {"title": "Month of the year"}
},
"y": {"aggregate": "count", "type": "quantitative"},
"color": {
"field": "weather",
"type": "nominal",
"scale": {
"domain": ["sun", "fog", "drizzle", "rain", "snow"],
"range": ["#e7ba52", "#c7c7c7", "#aec7e8", "#1f77b4", "#9467bd"]
},
"legend": {"title": "Weather type"}
},
"order": {"field": "order", "type": "ordinal"}
}
}

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

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

Dynamic text mark as title in vega-lite

I have a concat view in vega-lite (kibana) where the first bar plot serves as a selection for the other plots. So if I click in one bar of the bar plot, all other visualizations change accordingly.I also have a dropdown with the same goal.
I would like to have a dynamic title (or text mark) that shows the y label of the bar that I just clicked (or the name in the dropdown). So far I managed to do so, however if there are no selections for the bar, all labels will appear in the same title, which is not great.
I thought that maybe initializing the parameter with a certain value would solve the issue, but if I click in between bars, all values appear and I have the same issue with the title. Furthermore, I would like all bars to be always visible, and just change the opacity of the bar that is clicked.
Below you can find a simplified version of what I mean,
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"description": "Two horizonally concatenated charts that show a histogram of precipitation in Seattle and the relationship between min and max temperature.",
"data": {"url": "data/weather.csv"},
"hconcat": [
{
"mark": "bar",
"encoding": {
"y": {"field": "location", "type": "nominal"},
"x": {"aggregate": "mean", "field": "precipitation"},
"opacity":{"condition":{"param":"click","value":0.2},"value":0.7}
},
"params":[{
"name":"click",
"select":{"type":"point","encodings":["y"], "on":"click"},
"bind":{"input":"select","options":["New York", "Seattle"]},
"value":{"y":"Seattle"}
},
{
"name":"highlight",
"select":{"type":"point"}
}
],
"transform":[{"filter":{"param":"click"}}]
},
{"layer":[{
"transform":[{"filter":{"param":"click"}}],
"mark":"bar",
"mark":{"type":"text","dy":-50, "dx":30, "fontSize":20},
"encoding":{"text":{"field":"location","type":"nominal"}}
}]},
{
"mark": "point",
"encoding": {
"x": {"field": "temp_min", "bin": true},
"y": {"field": "temp_max", "bin": true},
"size": {"aggregate": "count"}
},
"transform":[{"filter":{"param":"click"}}]
}
]
}
vega editor
As usual, any help will be more than welcome!
Following are the changes required:
To show both the bars, remove the filter transform from bar chart.
Added some changes in click params like if someone clicks on empty space, then nearest bar will be selected and changed values for opacity.
Refer the editor or the below code:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"description": "Two horizonally concatenated charts that show a histogram of precipitation in Seattle and the relationship between min and max temperature.",
"data": {"url": "data/weather.csv"},
"hconcat": [
{
"mark": "bar",
"encoding": {
"y": {"field": "location", "type": "nominal"},
"x": {"aggregate": "mean", "field": "precipitation"},
"opacity": {
"condition": {"param": "click", "value": 0.7, "empty": false},
"value": 0.2
}
},
"params": [
{
"name": "click",
"select": {
"type": "point",
"encodings": ["y"],
"on": "click",
"clear": false,
"nearest": true
},
"bind": {"input": "select", "options": ["New York", "Seattle"]},
"value": "Seattle"
},
{"name": "highlight", "select": {"type": "point"}}
]
},
{
"mark": "point",
"title": {"text": {"expr": "click_location"}},
"encoding": {
"x": {"field": "temp_min", "bin": true},
"y": {"field": "temp_max", "bin": true},
"size": {"aggregate": "count"}
},
"transform": [{"filter": {"param": "click"}}]
}
]
}

Dynamic scale domain in vega-lite

I would like to define my x-axis:
minimum value should be now()
maximum value should be automatically determined (just as if the domain of the scale would have not been defined)
"encoding": {
"y": {
"field": "Reference",
"type": "nominal",
},
"x":{
"field": "Date",
"type": "temporal",
"scale": {"domain": [now(), 1618000000000]}}
I also tried to use an expression to set-up now(), to no success:
"scale": {"domain": ["expr":"now()", 1618000000000]
You were quite close with the second attempt; you just need to put braces around the expression statement:
"scale": {"domain": [{"expr": "now()"}, "2021-05-01T00:00:00"]}
Here's a full example (open in editor):
{
"data": {
"values": [
{"date": "2021-03-01T00:00:00", "value": 1},
{"date": "2021-04-01T00:00:00", "value": 3},
{"date": "2021-05-01T00:00:00", "value": 2}
]
},
"mark": "line",
"encoding": {
"x": {
"field": "date",
"type": "temporal",
"scale": {"domain": [{"expr": "now()"}, "2021-05-01T00:00:00"]}
},
"y": {"field": "value", "type": "quantitative"}
}
}
If instead of setting the domain limits, you just want to ensure that now() appears as part of the domain, you can use a domain unionWith statement:
"scale": {"domain": {"unionWith": [{"expr": "now()"}]}}
This will create an automatically calculated domain that contains the current date.

Points only in the central line

I am using this example named "Line Chart with Point Markers" as reference, but not see other example or any clues about conditional or "selected by symbol" points.
The illustration shows a typical case (see also SPC) where I need only the blue central line with dots.
You can do this by layering filtered versions of the dataset. Modifying the example you linked to, it might look something like this (vega editor):
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"description": "Stock prices of 5 Tech Companies over Time.",
"data": {"url": "data/stocks.csv"},
"encoding": {
"x": {"timeUnit": "year", "field": "date", "type": "temporal"},
"y": {"aggregate": "mean", "field": "price", "type": "quantitative"},
"color": {"field": "symbol", "type": "nominal"}
},
"layer": [
{
"mark": {"type": "line", "point": true},
"transform": [{"filter": "datum.symbol == 'GOOG'"}]
},
{
"mark": {"type": "line"},
"transform": [{"filter": "datum.symbol != 'GOOG'"}]
}
]
}