Forum Discussion
Deneb / Vega - Variable Width Cummulative Bar Chart
In my dataset, I have capacity and total cost for a list of assets. I need to plot all the assets from lowest cost to highest cost (y-axis) on a cummulative capacity basis (x-axis). To do this, I need to create a variable width bar chart where the bar width represents the asset capacity. I also need a tooltip that shows asset details when I hover over the bar chart. I've tried using Deneb and R Scripts but ran into different issues with both. Any guidance would be much appreciated.
I used R scripts to create the variable width bar chart that I need, but now I can't get the tool tip to work using plotly and ggplotly.
I also used Deneb to create a sorted bar chart with tooltip, but I'm lost on how to make it variable width. I have a sorted CumulativeCapacity column in my dataset, but I think I would need to calculate this column using the Capacity column to implement the variable width feature.
{
"data": {"name": "dataset"},
"mark": {"type": "bar",
"tooltip":true
},
"encoding" : {
"x":{
"field":"CumulativeCapacity",
"type" :"quantitative"
},
"y":{
"field":"TotalCost",
"type" :"quantitative",
"sort": "-y"
}
}
}
9 Replies
- AnonymousNot applicable
I have been working on this problem myself and this that I have found a reasonable solution to creating a variable width bar/column chart where the area of the bar/column is meaningful. The Vega-Lite JSON with a dummy dataset is below.
{ "data": { "values": [ {"vWidth": 10, "vHeight": 1, "vType": "A"}, {"vWidth": 20, "vHeight": 2, "vType": "B"}, {"vWidth": 1, "vHeight": 3, "vType": "C"}, {"vWidth": 5, "vHeight": 4, "vType": "D"} ] }, "transform": [ { "calculate": "datum.vWidth*datum.vHeight", "as": "cArea" }, { "window": [{"op": "sum", "field": "vWidth", "as": "cum_total"}], "sort": [{"field": "cArea", "order": "descending"}], "frame": [null, 0] }, { "window": [{"op": "first_value", "field": "cum_total", "as": "shift"}], "sort": [{"field": "cArea", "order": "descending"}], "frame": [-1, 0] }, { "calculate": "datum.cum_total === datum.shift ? 0 : datum.shift", "as": "leftedge" } ], "mark": {"type": "rect"}, "encoding": { "y": { "field": "vHeight", "type": "quantitative" }, "x": { "field": "cum_total", "type": "quantitative" }, "x2": { "field": "leftedge" }, "color": { "field": "vType" } } }The data is presented as a width and height value with a label.
I made use of 4 transforms.
- Calculate the area (width x height) so I could use if for sorting. I don't think you need this, but could be helpful as a reference.
- Create a cumulative sum (with required sorting) to determine the right edge of each bar ("cum_total").
- Create a window to look at the immediately preceeding value (same sorting) to determine the left edge of each bar ("shift"). This is essentially a rightward shift of the data. However, the first value will be filled in with a duplicate of its own value.
- Since the first value has a zero-width bar, the left edge needs to be moved to the zero of the chart. The last calculation just replaces that left edge with a 0 based on the shifted value and cumulative sum being the same. My method will cause problems if any of your width values are supposed to be zero.
The resultant chart from the above is below.
Hope that helps! I'm just getting into Vega-Lite myself and this is a chart type that I've been trying to create for a while.
- lbendlin
Super User
Anonymous very nice! Just in time for a capacity metrics report visual I am working on. Thank you!
- AnonymousNot applicable
Thank you for the kudos. Glad it could help you out! After refining a bit more, I found that I could come closer to the OP's code and simplify the process by finding the left edge by subtracting the width from the cumulative total. I have also added data labels and tooltips, but that is beyond what might be needed.
{ "data": { "values": [ {"vWidth": 10, "vHeight": 1, "vType": "A"}, {"vWidth": 20, "vHeight": 2, "vType": "B"}, {"vWidth": 1, "vHeight": 3, "vType": "C"}, {"vWidth": 5, "vHeight": 4, "vType": "D"} ] }, "transform": [ { "calculate": "datum.vWidth*datum.vHeight", "as": "cArea" }, { "window": [{"op": "sum", "field": "vWidth", "as": "cum_total"}], "sort": [{"field": "cArea", "order": "descending"}], "frame": [null, 0] }, { "calculate": "datum.cum_total - datum.vWidth", "as": "leftedge" } ], "encoding": { "y": { "field": "vHeight", "type": "quantitative" }, "x": { "field": "cum_total", "type": "quantitative" }, "x2": { "field": "leftedge" }, "color": { "field": "vType" } }, "layer": [ { "mark": { "type": "rect", "tooltip": true } }, { "mark": { "type": "text", "align": "right", "baseline": "bottom", "dx": -5, "dy": -5 }, "encoding": { "text": { "field": "cArea" } } } ] }
- lbendlin
Super User
Have you considered using an area chart instead?
- 13055New Member
Hi, yes. I would consider an area chart if there was a way to show the individual asset bars, but I don't think that's possible. The chart I producted with R script is exactly what we want--except I haven't been able to get the tooltip to work and I don't know how it will perform when published online.
- lbendlin
Super User
R scripts will mandate the use of a personal gateway. Not recommended.
Please provide sample data that covers your issue or question completely, in a usable format (not as a screenshot).
Do not include sensitive information or anything not related to the issue or question.
If you are unsure how to upload data please refer to https://community.fabric.microsoft.com/t5/Community-Blog/How-to-provide-sample-data-in-the-Power-BI-Forum/ba-p/963216
Please show the expected outcome based on the sample data you provided.
Want faster answers? https://community.fabric.microsoft.com/t5/Desktop/How-to-Get-Your-Question-Answered-Quickly/m-p/1447523