Forum Discussion
Extending Deneb/Vega-Lite Toggle Switch from 2-State to 3-State (Working Day / Non-Working Day / All
Hi everyone,
In my dataset, I have a flag column called “Is Working Day”, which contains values of either 0 or 1.
I’ve created a toggle switch in Deneb using Vega-Lite, allowing users to switch between viewing only working days (1) and showing all records (no filter applied). This is achieved with the following condition in the calculate property:
{
"calculate": "datum['IsWorkingDay'] == 1 ? 'Working Day' : 'All'",
"as": "Option_Name"
}
Now, I’d like to extend this functionality to support a 3-state toggle switch with the following behavior:
First click: Show records where datum['IsWorkingDay'] == 1 (Working Days)
Second click: Show records where datum['IsWorkingDay'] == 0 (Non-Working Days)
Third click: Show All records (no filter)
Does anyone have suggestions or examples of how this 3-click toggle logic could be implemented in Vega-Lite within Deneb?
Thanks in advance for your help!
3 Replies
- BeaBF
Super User
y5famfnatudu Hi! I suggest you this workaround that I had implemented a time:
Setup the cycles between 3 filter modes with this code:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {"name": "dataset"},
"params": [
{
"name": "viewMode",
"value": 2,
"select": {"type": "point", "on": "click"},
"bind": {
"input": "none"
},
"update": "viewMode === 2 ? 0 : viewMode + 1"
}
],
"transform": [
{
"filter": "viewMode == 2 ? true : datum.IsWorkingDay == viewMode"
}
],
"mark": "bar",
"encoding": {
"x": {"field": "Category", "type": "nominal"},
"y": {"aggregate": "count"}
}
}It requires a click target in your chart.
Otherwise you can use a Dropdown and a bound input param:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {"name": "dataset"},
"params": [
{
"name": "dayFilter",
"value": "All",
"bind": {
"input": "select",
"options": ["Working", "Non-working", "All"],
"labels": ["Working Days", "Non-working Days", "All Days"]
}
}
],
"transform": [
{
"filter": "dayFilter == 'All' ? true : (dayFilter == 'Working' ? datum.IsWorkingDay == 1 : datum.IsWorkingDay == 0)"
}
],
"mark": "bar",
"encoding": {
"x": {"field": "Category", "type": "nominal"},
"y": {"aggregate": "count"}
}
}BBF
💡 Did I answer your question? Mark my post as a solution!
👍 Kudos are appreciated
🔥 Proud to be a Super User!
- y5famfnatudu
Resolver I
Dear BeaBF,
Thanks for the suggestions! I appreciate the help.
Unfortunately, those approaches would pull me too far from the visual style I'm aiming for. I need the toggle to match a specific design aesthetic, so I'll need to find a solution that stays closer to that direction.
Thanks again for taking the time to respond, so much appreciated!
Best regards,
Simon
- Ahmed-Elfeel
Super User
Hi y5famfnatudu,
I hope you are doing well ☺️❤️
To implement a 3 state toggle switch in Deneb/Vega-Lite you need to use a parameter (signal) with a cyclic update expression. Here is a couple of Approaches:
First Approach: Complete Deneb/Vega-Lite Specification
{ "$schema": "https://vega.github.io/schema/vega-lite/v5.json", "params": [ { "name": "filterToggle", "value": 0, "bind": { "input": "radio", "options": [0, 1, 2], "labels": ["Working Days (1)", "Non-Working Days (0)", "All Records"] } } ], "data": {"name": "dataset"}, "transform": [ { "filter": { "condition": { "param": "filterToggle", "value": 2, "empty": false }, "value": { "field": "IsWorkingDay", "equal": { "signal": "filterToggle == 0 ? 1 : 0" } } } }, { "calculate": "datum.IsWorkingDay == 1 ? 'Working Day' : 'Non-Working Day'", "as": "Day_Type" } ], "mark": "bar", // or your preferred mark type "encoding": { // Your encoding here "x": {"field": "SomeField", "type": "nominal"}, "y": {"aggregate": "count", "type": "quantitative"}, "color": {"field": "Day_Type", "type": "nominal"} } }Alternative Approach: ClickCycling Button
If you want a single button that cycles through states on each click:
{ "$schema": "https://vega.github.io/schema/vega-lite/v5.json", "data": {"name": "dataset"}, "signals": [ { "name": "toggleState", "value": 0, "on": [ { "events": {"type": "click", "markname": "toggleButton"}, "update": "(toggleState + 1) % 3" } ] } ], "marks": [ { "type": "rect", "name": "toggleButton", "encode": { "enter": { "x": {"value": 0}, "y": {"value": 0}, "width": {"value": 120}, "height": {"value": 30}, "fill": {"value": "lightgray"}, "cornerRadius": {"value": 15} }, "update": { "fill": { "signal": "toggleState == 0 ? '#4CAF50' : toggleState == 1 ? '#F44336' : '#2196F3'" } } } }, { "type": "text", "name": "toggleLabel", "encode": { "enter": { "x": {"value": 60}, "y": {"value": 18}, "align": {"value": "center"}, "baseline": {"value": "middle"}, "fontSize": {"value": 12}, "fill": {"value": "white"} }, "update": { "text": { "signal": "toggleState == 0 ? 'Working Days' : toggleState == 1 ? 'Non-Working Days' : 'All Days'" } } } } ], "transform": [ { "filter": { "condition": {"signal": "toggleState == 2"}, "value": { "field": "IsWorkingDay", "equal": {"signal": "toggleState == 0 ? 1 : 0"} } } } ], "layer": [ // Your visualization layers here { "mark": "bar", "encoding": { "x": {"field": "SomeField", "type": "nominal"}, "y": {"aggregate": "count", "type": "quantitative"}, "color": { "field": "IsWorkingDay", "type": "nominal", "scale": { "domain": [0, 1], "range": ["#F44336", "#4CAF50"] }, "legend": { "title": "Day Type", "labelExpr": "datum.value == 1 ? 'Working Day' : 'Non-Working Day'" } } } } ] }Bonus Approach: Simple Radio Button Version
- If you prefer a simpler radio button
{ "params": [ { "name": "dayFilter", "value": 2, "bind": { "input": "select", "options": [0, 1, 2], "labels": ["Working Days Only", "Non-Working Days Only", "All Days"], "name": "Filter: " } } ], "transform": [ { "filter": { "condition": {"param": "dayFilter", "value": 2}, "value": {"field": "IsWorkingDay", "equal": {"param": "dayFilter"}} } } ] }Choose the Approach that best fits your visualization needs. The first approach with a cycling button is more interactive while the radio/select approaches are more explicit for users
if this post helps, then I would appreciate a thumbs up and mark it as the solution to help the other members find it more quickly.