I have the chart on the left, code provided below, and would like to get the chart on the right. The chart on the right has the bars highlighted that correspond to a selected tier; the tier selected comes from a slicer. (The right chart shows Tier 1; however, the user may prefer a different tier.) I feel like this can be accomplished using fillOpacity. How do I get the highlighting?
{
"data": {
"values": [
{"name": "A", "group": "High", "tier": "Tier 3"},
{"name": "B", "group": "Med", "tier": "Tier 1"},
{"name": "C", "group": "High", "tier": "Tier 1"},
{"name": "D", "group": "High", "tier": "Tier 2"},
{"name": "E", "group": "Low", "tier": "Tier 3"},
{"name": "F", "group": "Low", "tier": "Tier 1"}
]
},
"transform": [
{
"aggregate": [
{
"field": "name",
"op": "count",
"as": "numProj"
}
],
"groupby": [
"name",
"group"
]
},
{
"stack": "numProj",
"groupby": ["group"],
"sort": [
{
"field": "name",
"order": "descending"
}
],
"as": "barTop"
}
],
"layer": [
{
"mark": {
"type": "bar",
"stroke": "black",
"strokeWidth": 1,
"tooltip": true
},
"encoding": {
"y": {
"field": "numProj",
"type": "quantitative",
"axis": {
"title": "Number of Projects",
"tickMinStep": 1
}
},
"fill": {
"field": "group",
"type": "nominal",
"scale": {
"domain": [
"Low",
"Med",
"High"
],
"range": [
"#e15759",
"#ffff00",
"#59a14f"
]
},
"legend": null
}
}
},
{
"mark": {
"type": "text",
"color": "black",
"dy": -10
},
"encoding": {
"y": {
"field": "barTop",
"type": "quantitative"
},
"text": {
"field": "name"
}
}
}
],
"encoding": {
"x": {
"field": "group",
"type": "nominal",
"axis": {
"title": null,
"labelAngle": 0
}
}
}
}
Highlighting in Deneb is quite involved and can be read about here. Having said that, I have a working example.
Code
{
"data": {"name": "dataset"},
"layer": [
{
"mark": {
"type": "bar",
"stroke": "black",
"strokeWidth": 1,
"tooltip": true,
"opacity": 0.3
},
"encoding": {
"y": {
"field": "test",
"type": "quantitative",
"axis": {
"title": "Number of Projects",
"tickMinStep": 1
}
},
"fill": {
"field": "group",
"type": "nominal",
"scale": {
"domain": [
"Low",
"Med",
"High"
],
"range": [
"#e15759",
"#ffff00",
"#59a14f"
]
},
"legend": null
}
}
},
{
"mark": {
"type": "bar",
"stroke": "black",
"strokeWidth": 1,
"tooltip": true,
"opacity": 1
},
"encoding": {
"y": {
"field": "test__highlight",
"type": "quantitative",
"axis": {
"title": "Number of Projects",
"tickMinStep": 1
}
},
"fill": {
"field": "group",
"type": "nominal",
"scale": {
"domain": [
"Low",
"Med",
"High"
],
"range": [
"#e15759",
"#ffff00",
"#59a14f"
]
},
"legend": null
}
}
},
{
"mark": {
"type": "text",
"color": "black",
"dy": 70
},
"encoding": {
"y": {
"field": "test__highlight",
"stack": true,
"type": "quantitative"
},
"text": {
"field": "name"
}
}
}
],
"encoding": {
"x": {
"field": "group",
"type": "nominal",
"axis": {
"title": null,
"labelAngle": 0
}
}
}
}
Things to keep in mind.
You need a measure (Deneb docs state highlighting doesn't work without a measure). The measure named test is simply test = COUNT('Table'[name])
You can't highlight from a slicer unless it is disconnected as slicers filter instead of highlight
You can't highlight stacks in position. The highlighted stacks naturally fall to the bottom as a result of how the data is being passed. There may be a way around this but it will involve further investigation which is probably not worth it.
Edit 1
Highlighting in place.
{
"data": {"name": "dataset"},
"layer": [
{
"mark": {
"type": "bar",
"stroke": "black",
"strokeWidth": 1,
"tooltip": true,
"opacity": 0.3
},
"encoding": {
"y": {
"field": "test",
"type": "quantitative",
"axis": {
"title": "Number of Projects",
"tickMinStep": 1
}
},
"fill": {
"field": "group",
"type": "nominal",
"scale": {
"domain": [
"Low",
"Med",
"High"
],
"range": [
"#e15759",
"#ffff00",
"#59a14f"
]
},
"legend": null
}
}
},
{
"mark": {
"type": "bar",
"stroke": "black",
"strokeWidth": 1,
"tooltip": true
},
"encoding": {
"y": {
"field": "test",
"type": "quantitative",
"axis": {
"title": "Number of Projects",
"tickMinStep": 1
}
},
"opacity": {
"condition": {
"test": "datum['test__highlight']!=null"
,
"value": 1
},
"value": 0
},
"fill": {
"field": "group",
"type": "nominal",
"scale": {
"domain": [
"Low",
"Med",
"High"
],
"range": [
"#e15759",
"#ffff00",
"#59a14f"
]
},
"legend": null
}
}
},
{
"mark": {
"type": "text",
"color": "black",
"dy": 70
},
"encoding": {
"y": {
"field": "test",
"stack": true,
"type": "quantitative"
},
"text": {
"field": "name"
}
}
}
],
"encoding": {
"x": {
"field": "group",
"type": "nominal",
"axis": {
"title": null,
"labelAngle": 0
}
}
}
}
Related
could anyone please help with my issue? I´ve created couple of DENEB visuals which seem to be working fine both in PBI Desktop and service however the one I´m sharing doesn´t work in PBI service, it shows as blank.
Do you know by chance what might be the problem?
Here is the JSON that I´m using:
{
"data": {"name": "dataset"},
"transform": [
{
"joinaggregate": [
{
"op": "sum",
"field": "NrOfSfhifts",
"as": "TotalOrigin"
}
]
},
{
"joinaggregate": [
{
"op": "sum",
"field": "NrOfSfhifts",
"as": "TotalOriginGrouped"
}
],
"groupby": ["NrOfSfhifts"]
},
{
"calculate": "round(datum.TotalOriginGrouped/datum.TotalOrigin * 100)",
"as": "PercentOfTotal"
},
{
"aggregate": [
{
"op": "average",
"field": "PercentOfTotal",
"as": "Percento"
}
],
"groupby": ["Dispatcher"]
},
{
"calculate": "sequence(1,datum.Percento+1)",
"as": "S"
},
{"flatten": ["S"]},
{
"window": [
{"op": "row_number", "as": "id"}
],
"sort": [
{
"op": "sum",
"field": "TotalOriginGrouped",
"order": "ascending"
}
]
},
{
"calculate": "ceil (datum.id / 10)",
"as": "row"
},
{
"calculate": "datum.id - datum.row * 10",
"as": "col"
}
],
"mark": {
"type": "circle",
"filled": true,
"tooltip": true,
"stroke": "black",
"strokeWidth": 2
},
"encoding": {
"x": {
"field": "col",
"type": "ordinal",
"axis": null,
"sort": "x"
},
"y": {
"field": "row",
"type": "ordinal",
"axis": null,
"sort": "y"
},
"color": {
"field": "Dispatcher",
"type": "nominal",
"sort": [
{
"op": "sum",
"field": "TotalOriginGrouped",
"order": "descending"
}
],
"scale": {
"range": [
"#FFD300",
"#ed3419",
"lightgray",
"white",
"black",
"olive",
"lightblue"
]
},
"legend": {
"orient": "right",
"offset": 10,
"labelOffset": 3,
"titlePadding": 5,
"titleFontSize": 10
}
},
"size": {"value": 330},
"tooltip": [
{
"field": "Dispatcher",
"type": "nominal"
},
{
"field": "Percento",
"type": "quantitative",
"format": "0",
"formatType": "pbiFormat"
}
]
}
}
Thank you!
That is my code :).
If this is working in the desktop but not the service, then your admin has probably disabled non-native visuals. You should ask them to enable certified visuals at the very least as there is no danger from those.
I am trying to create a Gantt chart and I want to color a single task with two colors, based on a percentage complete. Say, make the complete part green and the remaining part orange.
How can I achieve this?
Below is a sample code, also available in the editor here.
{
"data": {
"values": [
{"Description": "Task 1", "Start": "2023-01-05", "End": "2023-01-10", "Percentage complete": 0},
{"Description": "Task 2", "Start": "2023-01-01", "End": "2023-01-15", "Percentage complete": 75},
{"Description": "Task 3", "Start": "2023-01-01", "End": "2023-01-03", "Percentage complete": 100}
]
},
"layer": [
{
"mark": "bar",
"encoding": {
"y": {
"field": "Description",
"type": "ordinal",
"stack": null
},
"x": {
"field": "Start",
"type": "temporal"
},
"x2": {
"field": "End",
"type": "temporal"
}
}
}
]
}
The expected result should look like this.
I tried looking at folding, transforming, and scale. But as I am new to Vega-lite, to no avail.
You have two options.
Reshape your data upstream. Your partially coloured bars should be rendered as two bars stacked - one for incomplete and one for complete.
Use Reactive Geometry as described here. This may need Vega rather than VL.
Here it is using reactive geometry.
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"background": "white",
"padding": 5,
"width": 200,
"style": "cell",
"data": [
{
"name": "source_0",
"values": [
{
"Description": "Task 1",
"Start": "2023-01-05",
"End": "2023-01-10",
"Percentatecomplete": 0
},
{
"Description": "Task 2",
"Start": "2023-01-01",
"End": "2023-01-15",
"Percentatecomplete": 0.75
},
{
"Description": "Task 3",
"Start": "2023-01-01",
"End": "2023-01-03",
"Percentatecomplete": 1
}
]
},
{
"name": "data_0",
"source": "source_0",
"transform": [
{"type": "formula", "expr": "toDate(datum[\"Start\"])", "as": "Start"},
{"type": "formula", "expr": "toDate(datum[\"End\"])", "as": "End"},
{
"type": "filter",
"expr": "(isDate(datum[\"Start\"]) || (isValid(datum[\"Start\"]) && isFinite(+datum[\"Start\"])))"
}
]
}
],
"signals": [
{"name": "y_step", "value": 20},
{
"name": "height",
"update": "bandspace(domain('y').length, 0.1, 0.05) * y_step"
}
],
"marks": [
{
"name": "layer_0_marks",
"type": "rect",
"style": ["bar"],
"from": {"data": "data_0"},
"encode": {
"update": {
"fill": {"value": "#4c78a8"},
"x": {"scale": "x", "field": "Start"},
"x2": {"scale": "x", "field": "End"},
"y": {"scale": "y", "field": "Description"},
"height": {"signal": "max(0.25, bandwidth('y'))"}
}
}
},
{
"type": "rect",
"from": {"data": "layer_0_marks"},
"encode": {
"update": {
"x": {"field": "x"},
"y": {"field": "y"},
"fill": {"value": "red"},
"width": {"signal": "(datum.x2 - datum.x) * datum.datum.Percentatecomplete"},
"height": {"signal": "max(0.25, bandwidth('y'))"}
}
}
}
],
"scales": [
{
"name": "x",
"type": "time",
"domain": {"data": "data_0", "fields": ["Start", "End"]},
"range": [0, {"signal": "width"}]
},
{
"name": "y",
"type": "band",
"domain": {"data": "data_0", "field": "Description", "sort": true},
"range": {"step": {"signal": "y_step"}},
"paddingInner": 0.1,
"paddingOuter": 0.05
}
],
"axes": [
{
"scale": "x",
"orient": "bottom",
"gridScale": "y",
"grid": true,
"tickCount": {"signal": "ceil(width/40)"},
"domain": false,
"labels": false,
"aria": false,
"maxExtent": 0,
"minExtent": 0,
"ticks": false,
"zindex": 0
},
{
"scale": "x",
"orient": "bottom",
"grid": false,
"title": "Start, End",
"labelFlush": true,
"labelOverlap": true,
"tickCount": {"signal": "ceil(width/40)"},
"zindex": 0
},
{
"scale": "y",
"orient": "left",
"grid": false,
"title": "Description",
"zindex": 0
}
]
}
I have a text field ['Region'] with four values {Global, AMER, APAC, EMEA}. I have a simple bar chart and want the label to be bold only for 'Global' but have been unable to do so.
I tried:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": { "values": [
{"Region": "Global", "Months": 1, "RegionRank":1},
{"Region": "AMER", "Months": -1, "RegionRank":2},
{"Region": "APAC", "Months": 3, "RegionRank":3}, {"Region": "EMEA", "Months": 2, "RegionRank":4}
]},
"layer": [
{
"mark": {
"type": "bar",
"filled": false,
"stroke": "gray",
"strokeDash": [3.6],
"strokeWidth": 3
}
},
{
"mark": {
"type": "text",
"fontSize": 14,
"xOffset": {
"expr": "datum['Months']<0 ? -15:15"
}
},
"encoding": {
"text": {
"field": "Months",
"format": "+.0f"
}
}
}
],
"encoding": {
"y": {
"field": "Region",
"type": "nominal",
"axis": {
"offset": 10,
"title": null,
// problem section
"labelFontWeight": {
"condition": {"test": "datum['Region'] == 'Global'","value":"bold"},
"value":"normal"
}
},
"sort": {
"op": "min",
"field": "RegionRank",
"order": "ascending"
}
},
"x": {
"field": "Months",
"type": "quantitative",
"axis": {"title": null}
}
}
}
but there is no change to the label font weight.
What is interesting is that I switched the result conditions, making the '==Global' result "normal" and the else "bold" and it changed font weight on all the labels to bold. That leads me to believe that my condition is never being evaluated as true. Any ideas why? Is what I want to do - changing a signal value in an axis label - possible?
You mean like this?
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {
"values": [
{"Region": "Global", "Months": 1, "RegionRank": 1},
{"Region": "AMER", "Months": -1, "RegionRank": 2},
{"Region": "APAC", "Months": 3, "RegionRank": 3},
{"Region": "EMEA", "Months": 2, "RegionRank": 4}
]
},
"layer": [
{
"mark": {
"type": "bar",
"filled": false,
"stroke": "gray",
"strokeDash": [3.6],
"strokeWidth": 3
}
},
{
"mark": {
"type": "text",
"fontSize": 14,
"xOffset": {"expr": "datum['Months']<0 ? -15:15"}
},
"encoding": {"text": {"field": "Months", "format": "+.0f"}}
}
],
"encoding": {
"y": {
"field": "Region",
"type": "nominal",
"axis": {
"offset": 10,
"title": null,
"labelFontWeight": {
"condition": {"test": "datum.label == 'Global'", "value": "bold"},
"value": "normal"
}
},
"sort": {"op": "min", "field": "RegionRank", "order": "ascending"}
},
"x": {"field": "Months", "type": "quantitative", "axis": {"title": null}}
}
}
I Have been given a project to produce a european parliament seating arrangement visual. I have tried to seart on the net without luck.
Can anyone sugest any custom visual that look like below?
You're in luck!. I have literally just produced something like this in Deneb.
Full code:
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"width": 550,
"height": 300,
"signals": [
{"name": "dataLength", "update": "length(data('penguins'))"},
{"name": "row0Radius", "value": 280},
{"name": "row1Radius", "value": 260},
{"name": "row2Radius", "value": 240},
{"name": "row3Radius", "value": 220},
{"name": "row4Radius", "value": 200},
{"name": "row5Radius", "value": 180},
{"name": "row6Radius", "value": 160},
{"name": "row0Circ", "update": "PI*row0Radius"},
{"name": "row1Circ", "update": "PI*row1Radius"},
{"name": "row2Circ", "update": "PI*row2Radius"},
{"name": "row3Circ", "update": "PI*row3Radius"},
{"name": "row4Circ", "update": "PI*row4Radius"},
{"name": "row5Circ", "update": "PI*row5Radius"},
{"name": "row6Circ", "update": "PI*row6Radius"},
{
"name": "totalLength",
"update": "row0Circ+row1Circ+row2Circ+row3Circ+row4Circ+row5Circ+row6Circ "
}
],
"data": [
{
"name": "penguins",
"url": "data/penguins.json",
"transform": [
{"type": "project", "fields": ["Species", "Island"]},
{
"type": "window",
"ops": ["row_number"],
"fields": [null],
"as": ["index"],
"sort": {"field": "Island", "order": "ascending"}
}
]
},
{
"name": "placement",
"transform": [
{
"type": "sequence",
"start": 1,
"stop": {"signal": "dataLength+1"},
"as": "index"
},
{
"type": "formula",
"as": "wholeCirc",
"expr": "totalLength/dataLength"
},
{
"type": "window",
"ops": ["sum"],
"fields": ["wholeCirc"],
"as": ["cumWholeCirc"]
},
{
"type": "formula",
"as": "row",
"expr": "datum.cumWholeCirc <row0Circ?0:datum.cumWholeCirc <row0Circ+row1Circ?1:datum.cumWholeCirc <row0Circ+row1Circ+row2Circ?2:datum.cumWholeCirc <row0Circ+row1Circ+row2Circ+row3Circ?3:datum.cumWholeCirc <row0Circ+row1Circ+row2Circ+row3Circ+row4Circ?4:datum.cumWholeCirc <row0Circ+row1Circ+row2Circ+row3Circ+row4Circ+row5Circ?5:6 "
},
{
"type": "joinaggregate",
"fields": ["Species"],
"ops": ["count"],
"groupby": ["row"],
"as": ["rowCount"]
},
{
"type": "formula",
"as": "rowCirc",
"expr": "datum.row==0?(row0Circ/(datum.rowCount-1)):datum.row==1?(row1Circ/(datum.rowCount-1)):datum.row==2?(row2Circ/(datum.rowCount-1)):datum.row==3?(row3Circ/(datum.rowCount-1)):datum.row==4?(row4Circ/(datum.rowCount-1)):datum.row==5?(row5Circ/(datum.rowCount-1)):datum.row==6?(row6Circ/(datum.rowCount-1)):0"
},
{
"type": "window",
"ops": ["sum"],
"fields": ["rowCirc"],
"groupby": ["row"],
"sort": {"field": "index", "order": "descending"},
"as": ["cumRowCirc"]
},
{
"type": "formula",
"as": "cumRowCircAct",
"expr": "datum.cumRowCirc - datum.rowCirc "
},
{
"type": "formula",
"as": "theta",
"expr": "datum.cumRowCircAct==0?0:datum.row==0?(datum.cumRowCircAct/row0Radius):datum.row==1?(datum.cumRowCircAct/row1Radius):datum.row==2?datum.cumRowCircAct/row2Radius:datum.row==3?datum.cumRowCircAct/row3Radius:datum.row==4?datum.cumRowCircAct/row4Radius:datum.row==5?datum.cumRowCircAct/row5Radius:datum.row==6?datum.cumRowCircAct/row6Radius:0"
},
{
"type": "formula",
"as": "x",
"expr": "datum.row==0?row0Radius*cos(datum.theta):datum.row==1?row1Radius*cos(datum.theta):datum.row==2?row2Radius*cos(datum.theta):datum.row==3?row3Radius*cos(datum.theta):datum.row==4?row4Radius*cos(datum.theta):datum.row==5?row5Radius*cos(datum.theta):datum.row==6?row6Radius*cos(datum.theta):0"
},
{
"type": "formula",
"as": "y",
"expr": "datum.row==0?row0Radius*sin(datum.theta):datum.row==1?row1Radius*sin(datum.theta):datum.row==2?row2Radius*sin(datum.theta):datum.row==3?row3Radius*sin(datum.theta):datum.row==4?row4Radius*sin(datum.theta):datum.row==5?row5Radius*sin(datum.theta):datum.row==6?row6Radius*sin(datum.theta):0"
},
{
"type": "window",
"sort": {"field": "theta", "order": "ascending"},
"ops": ["row_number"],
"fields": ["row_number"],
"as": ["lookup"]
},
{
"type": "lookup",
"from": "penguins",
"key": "index",
"fields": ["lookup"],
"values": ["Island"],
"as": ["finalIsland"]
}
]
}
],
"scales": [
{
"name": "x",
"type": "linear",
"round": true,
"nice": true,
"zero": true,
"domain": {"field": "x", "data": "placement"},
"range": "width"
},
{
"name": "y",
"type": "linear",
"round": true,
"nice": true,
"zero": true,
"domain": {"field": "y", "data": "placement"},
"range": "height"
},
{
"name": "color",
"type": "ordinal",
"domain": {"data": "placement", "field": "finalIsland"},
"range": {"scheme": "category10"}
}
],
"marks": [
{
"name": "marks",
"type": "symbol",
"from": {"data": "placement"},
"encode": {
"update": {
"x": {"scale": "x", "field": "x"},
"y": {"scale": "y", "field": "y"},
"shape": {"value": "circle"},
"size": {"value": 130},
"stroke": {"value": "#4682b4"},
"tooltip": {"signal": "datum"},
"fill": {"scale": "color", "field": "finalIsland"}
}
}
}
]
}
I've created a simple stacked bar chart in Deneb where the user can highlight in place: x-axis is group, highlight is tiers. I've also created a tooltip that should show the name for each bar and should match the label on the bar. What's strange is that the tooltip shows in reverse order: pointing to A shows D, F shows E, etc. (See this pbix file.) I've attempted to insert sorting to the bars; that didn't work. My preference is to have the bars remain as they are and the tooltips show to match; however, it would be ok (less desirable) to reverse the order of the bars. How can I get the tooltip to match the label?
This cleaned up spec works.
Don't forget to accept the answer if this solves your problem.
{
"data": {"name": "dataset"},
"transform": [
{
"stack": "test2",
"as": ["a", "b"],
"groupby": ["group"]
}
],
"layer": [
{
"mark": {
"type": "bar",
"stroke": "black",
"strokeWidth": 1,
"opacity": 0.3
},
"encoding": {
"color": {
"field": "group",
"type": "nominal",
"scale": {
"domain": [
"Low",
"Med",
"High"
],
"range": [
"#e15759",
"#ffff00",
"#59a14f"
]
},
"legend": null
}
}
},
{
"mark": {
"type": "bar",
"stroke": "black",
"strokeWidth": 1,
"tooltip": true
},
"encoding": {
"color": {
"field": "group",
"type": "nominal",
"scale": {
"domain": [
"Low",
"Med",
"High"
],
"range": [
"#e15759",
"#ffff00",
"#59a14f"
]
},
"legend": null
},
"opacity": {
"condition": {
"test": "datum['test2__highlight']!=null",
"value": 1
},
"value": 0
}
}
},
{
"mark": {
"type": "text",
"color": "black",
"dy": -90
},
"encoding": {
"text": {"field": "name"}
}
}
],
"encoding": {
"y": {
"field": "a",
"type": "quantitative",
"axis": {
"title": "Number of Projects",
"tickMinStep": 1
}
},
"y2": {"field": "b"},
"x": {
"field": "group",
"type": "nominal",
"axis": {
"title": null,
"labelAngle": 0
}
}
}
}