Forum Discussion
How to apply color gradient for bubble inside custom visualization developed using Deneb
- 3 years ago
Hey Junato47, because of the limited clippath settings available, I could not figure out a way to have the gradient be confined to just the circles. However, I was able to calaculate a single color for each bubble with a close match of the gradient based on the position in the matrix. Let me know if the following will suffice.
If this is enough to get you going please consider liking this reply and choosing it as the solution. Otherwise, I'm happy to help further.
Interactive gist
spec:{ "$schema": "https://vega.github.io/schema/vega-lite/v5.json", "width": 800, "height": 800, "transform": [ { "aggregate": [{"op": "count", "as": "count_of_risk_id"}], "groupby": ["Residual Impact", "Residual Probability"] }, {"window": [{"op": "row_number", "as": "index"}]}, { "calculate": "indexof(x_domain, datum['Residual Probability'])", "as": "x_index" }, { "calculate": "indexof(y_domain, datum['Residual Impact'])", "as": "y_index" }, {"calculate": "datum['y_index']+datum['x_index']", "as": "gradient_index"}, { "joinaggregate": [ {"op": "min", "field": "gradient_index", "as": "min_gradient_index"}, {"op": "max", "field": "gradient_index", "as": "max_gradient_index"} ] }, { "calculate": "datum['gradient_index']/(gradient_index_domain_max-gradient_index_domain_min)", "as": "color_percentage" }, { "calculate": "datum['gradient_index']===gradient_index_domain_min ? 0 : datum['gradient_index'] === gradient_index_domain_max ? length(color_domain) - 1 : datum['color_percentage'] <= 0.25 ? 1 : datum['color_percentage'] >= 0.75 ? length(color_domain) - 2 : 2", "as": "color_index" }, {"calculate": "color_range[datum['color_index']]", "as": "color"} ], "params": [ { "name": "x_domain", "value": ["Very Low", "Low", "Medium", "High", "Very High"] }, { "name": "y_domain", "value": ["Very Low", "Low", "Medium", "High", "Very High"] }, {"name": "gradient_index_domain_min", "value": 0}, { "name": "gradient_index_domain_max", "expr": "length(x_domain) + length(y_domain) - 2" }, { "name": "color_range", "value": [ "rgb(0,255,0)", "rgb(165,255,0)", "rgb(255,255,0)", "rgb(255,165,0)", "rgb(255,0,0)" ] }, {"name": "color_domain", "expr": "sequence(0,length(color_range), 1)"} ], "encoding": { "x": { "field": "Residual Probability", "type": "ordinal", "axis": {"labelAngle": 0}, "scale": {"domain": {"expr": "x_domain"}} }, "y": { "field": "Residual Impact", "type": "nominal", "scale": {"domain": {"expr": "y_domain"}, "reverse": true} } }, "layer": [ { "mark": {"type": "point", "size": 1000, "tooltip": true, "filled": true}, "encoding": { "size": { "field": "count_of_risk_id", "legend": null, "scale": {"rangeMax": 15000}, "type": "quantitative" }, "color": {"field": "color", "legend": null, "scale": null} } }, { "mark": { "type": "text", "fontSize": 16, "fontWeight": 400, "color": "black" }, "encoding": { "text": {"field": "count_of_risk_id", "type": "quantitative"} } } ], "data": { "name": "dataset", "values": [ { "Risk ID": "1", "Residual Impact": "Low", "Residual Probability": "High" }, { "Risk ID": "2", "Residual Impact": "Very High", "Residual Probability": "High" }, { "Risk ID": "3", "Residual Impact": "Medium", "Residual Probability": "Very Low" }, { "Risk ID": "4", "Residual Impact": "Medium", "Residual Probability": "Very Low" }, { "Risk ID": "5", "Residual Impact": "High", "Residual Probability": "Low" }, { "Risk ID": "6", "Residual Impact": "Medium", "Residual Probability": "Medium" }, { "Risk ID": "7", "Residual Impact": "High", "Residual Probability": "Low" }, { "Risk ID": "8", "Residual Impact": "High", "Residual Probability": "Medium" }, { "Risk ID": "9", "Residual Impact": "High", "Residual Probability": "Low" }, { "Risk ID": "10", "Residual Impact": "High", "Residual Probability": "Low" }, { "Risk ID": "11", "Residual Impact": "Low", "Residual Probability": "High" }, { "Risk ID": "12", "Residual Impact": "High", "Residual Probability": "Medium" }, { "Risk ID": "13", "Residual Impact": "High", "Residual Probability": "Medium" }, { "Risk ID": "14", "Residual Impact": "High", "Residual Probability": "Medium" }, { "Risk ID": "15", "Residual Impact": "High", "Residual Probability": "Medium" }, { "Risk ID": "16", "Residual Impact": "High", "Residual Probability": "Medium" }, { "Risk ID": "17", "Residual Impact": "Medium", "Residual Probability": "Medium" }, { "Risk ID": "18", "Residual Impact": "High", "Residual Probability": "Low" }, { "Risk ID": "19", "Residual Impact": "High", "Residual Probability": "Medium" }, { "Risk ID": "20", "Residual Impact": "High", "Residual Probability": "Medium" }, { "Risk ID": "21", "Residual Impact": "High", "Residual Probability": "Medium" }, { "Risk ID": "22", "Residual Impact": "High", "Residual Probability": "Medium" }, { "Risk ID": "23", "Residual Impact": "High", "Residual Probability": "Low" }, { "Risk ID": "24", "Residual Impact": "High", "Residual Probability": "Medium" }, { "Risk ID": "25", "Residual Impact": "High", "Residual Probability": "Low" }, { "Risk ID": "26", "Residual Impact": "High", "Residual Probability": "Medium" }, { "Risk ID": "27", "Residual Impact": "High", "Residual Probability": "Medium" }, { "Risk ID": "28", "Residual Impact": "High", "Residual Probability": "Medium" }, { "Risk ID": "29", "Residual Impact": "High", "Residual Probability": "Medium" }, { "Risk ID": "30", "Residual Impact": "High", "Residual Probability": "Medium" }, { "Risk ID": "31", "Residual Impact": "High", "Residual Probability": "Medium" }, { "Risk ID": "32", "Residual Impact": "High", "Residual Probability": "Medium" }, { "Risk ID": "33", "Residual Impact": "High", "Residual Probability": "Medium" }, { "Risk ID": "34", "Residual Impact": "High", "Residual Probability": "Medium" }, { "Risk ID": "35", "Residual Impact": "High", "Residual Probability": "Low" }, { "Risk ID": "36", "Residual Impact": "High", "Residual Probability": "Medium" }, { "Risk ID": "37", "Residual Impact": "High", "Residual Probability": "Medium" }, { "Risk ID": "38", "Residual Impact": "High", "Residual Probability": "Medium" }, { "Risk ID": "39", "Residual Impact": "High", "Residual Probability": "Medium" }, { "Risk ID": "40", "Residual Impact": "Medium", "Residual Probability": "High" }, { "Risk ID": "41", "Residual Impact": "Medium", "Residual Probability": "High" }, { "Risk ID": "42", "Residual Impact": "Low", "Residual Probability": "Low" }, { "Risk ID": "43", "Residual Impact": "Medium", "Residual Probability": "Low" }, { "Risk ID": "44", "Residual Impact": "Medium", "Residual Probability": "Very High" }, { "Risk ID": "45", "Residual Impact": "Medium", "Residual Probability": "High" }, { "Risk ID": "46", "Residual Impact": "Medium", "Residual Probability": "High" }, { "Risk ID": "47", "Residual Impact": "Medium", "Residual Probability": "High" }, { "Risk ID": "48", "Residual Impact": "Very High", "Residual Probability": "Very High" }, { "Risk ID": "49", "Residual Impact": "Very Low", "Residual Probability": "Very Low" } ] } }
Hey Junato47, because of the limited clippath settings available, I could not figure out a way to have the gradient be confined to just the circles. However, I was able to calaculate a single color for each bubble with a close match of the gradient based on the position in the matrix. Let me know if the following will suffice.
If this is enough to get you going please consider liking this reply and choosing it as the solution. Otherwise, I'm happy to help further.
Interactive gist
spec:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"width": 800,
"height": 800,
"transform": [
{
"aggregate": [{"op": "count", "as": "count_of_risk_id"}],
"groupby": ["Residual Impact", "Residual Probability"]
},
{"window": [{"op": "row_number", "as": "index"}]},
{
"calculate": "indexof(x_domain, datum['Residual Probability'])",
"as": "x_index"
},
{
"calculate": "indexof(y_domain, datum['Residual Impact'])",
"as": "y_index"
},
{"calculate": "datum['y_index']+datum['x_index']", "as": "gradient_index"},
{
"joinaggregate": [
{"op": "min", "field": "gradient_index", "as": "min_gradient_index"},
{"op": "max", "field": "gradient_index", "as": "max_gradient_index"}
]
},
{
"calculate": "datum['gradient_index']/(gradient_index_domain_max-gradient_index_domain_min)",
"as": "color_percentage"
},
{
"calculate": "datum['gradient_index']===gradient_index_domain_min ? 0 : datum['gradient_index'] === gradient_index_domain_max ? length(color_domain) - 1 : datum['color_percentage'] <= 0.25 ? 1 : datum['color_percentage'] >= 0.75 ? length(color_domain) - 2 : 2",
"as": "color_index"
},
{"calculate": "color_range[datum['color_index']]", "as": "color"}
],
"params": [
{
"name": "x_domain",
"value": ["Very Low", "Low", "Medium", "High", "Very High"]
},
{
"name": "y_domain",
"value": ["Very Low", "Low", "Medium", "High", "Very High"]
},
{"name": "gradient_index_domain_min", "value": 0},
{
"name": "gradient_index_domain_max",
"expr": "length(x_domain) + length(y_domain) - 2"
},
{
"name": "color_range",
"value": [
"rgb(0,255,0)",
"rgb(165,255,0)",
"rgb(255,255,0)",
"rgb(255,165,0)",
"rgb(255,0,0)"
]
},
{"name": "color_domain", "expr": "sequence(0,length(color_range), 1)"}
],
"encoding": {
"x": {
"field": "Residual Probability",
"type": "ordinal",
"axis": {"labelAngle": 0},
"scale": {"domain": {"expr": "x_domain"}}
},
"y": {
"field": "Residual Impact",
"type": "nominal",
"scale": {"domain": {"expr": "y_domain"}, "reverse": true}
}
},
"layer": [
{
"mark": {"type": "point", "size": 1000, "tooltip": true, "filled": true},
"encoding": {
"size": {
"field": "count_of_risk_id",
"legend": null,
"scale": {"rangeMax": 15000},
"type": "quantitative"
},
"color": {"field": "color", "legend": null, "scale": null}
}
},
{
"mark": {
"type": "text",
"fontSize": 16,
"fontWeight": 400,
"color": "black"
},
"encoding": {
"text": {"field": "count_of_risk_id", "type": "quantitative"}
}
}
],
"data": {
"name": "dataset",
"values": [
{
"Risk ID": "1",
"Residual Impact": "Low",
"Residual Probability": "High"
},
{
"Risk ID": "2",
"Residual Impact": "Very High",
"Residual Probability": "High"
},
{
"Risk ID": "3",
"Residual Impact": "Medium",
"Residual Probability": "Very Low"
},
{
"Risk ID": "4",
"Residual Impact": "Medium",
"Residual Probability": "Very Low"
},
{
"Risk ID": "5",
"Residual Impact": "High",
"Residual Probability": "Low"
},
{
"Risk ID": "6",
"Residual Impact": "Medium",
"Residual Probability": "Medium"
},
{
"Risk ID": "7",
"Residual Impact": "High",
"Residual Probability": "Low"
},
{
"Risk ID": "8",
"Residual Impact": "High",
"Residual Probability": "Medium"
},
{
"Risk ID": "9",
"Residual Impact": "High",
"Residual Probability": "Low"
},
{
"Risk ID": "10",
"Residual Impact": "High",
"Residual Probability": "Low"
},
{
"Risk ID": "11",
"Residual Impact": "Low",
"Residual Probability": "High"
},
{
"Risk ID": "12",
"Residual Impact": "High",
"Residual Probability": "Medium"
},
{
"Risk ID": "13",
"Residual Impact": "High",
"Residual Probability": "Medium"
},
{
"Risk ID": "14",
"Residual Impact": "High",
"Residual Probability": "Medium"
},
{
"Risk ID": "15",
"Residual Impact": "High",
"Residual Probability": "Medium"
},
{
"Risk ID": "16",
"Residual Impact": "High",
"Residual Probability": "Medium"
},
{
"Risk ID": "17",
"Residual Impact": "Medium",
"Residual Probability": "Medium"
},
{
"Risk ID": "18",
"Residual Impact": "High",
"Residual Probability": "Low"
},
{
"Risk ID": "19",
"Residual Impact": "High",
"Residual Probability": "Medium"
},
{
"Risk ID": "20",
"Residual Impact": "High",
"Residual Probability": "Medium"
},
{
"Risk ID": "21",
"Residual Impact": "High",
"Residual Probability": "Medium"
},
{
"Risk ID": "22",
"Residual Impact": "High",
"Residual Probability": "Medium"
},
{
"Risk ID": "23",
"Residual Impact": "High",
"Residual Probability": "Low"
},
{
"Risk ID": "24",
"Residual Impact": "High",
"Residual Probability": "Medium"
},
{
"Risk ID": "25",
"Residual Impact": "High",
"Residual Probability": "Low"
},
{
"Risk ID": "26",
"Residual Impact": "High",
"Residual Probability": "Medium"
},
{
"Risk ID": "27",
"Residual Impact": "High",
"Residual Probability": "Medium"
},
{
"Risk ID": "28",
"Residual Impact": "High",
"Residual Probability": "Medium"
},
{
"Risk ID": "29",
"Residual Impact": "High",
"Residual Probability": "Medium"
},
{
"Risk ID": "30",
"Residual Impact": "High",
"Residual Probability": "Medium"
},
{
"Risk ID": "31",
"Residual Impact": "High",
"Residual Probability": "Medium"
},
{
"Risk ID": "32",
"Residual Impact": "High",
"Residual Probability": "Medium"
},
{
"Risk ID": "33",
"Residual Impact": "High",
"Residual Probability": "Medium"
},
{
"Risk ID": "34",
"Residual Impact": "High",
"Residual Probability": "Medium"
},
{
"Risk ID": "35",
"Residual Impact": "High",
"Residual Probability": "Low"
},
{
"Risk ID": "36",
"Residual Impact": "High",
"Residual Probability": "Medium"
},
{
"Risk ID": "37",
"Residual Impact": "High",
"Residual Probability": "Medium"
},
{
"Risk ID": "38",
"Residual Impact": "High",
"Residual Probability": "Medium"
},
{
"Risk ID": "39",
"Residual Impact": "High",
"Residual Probability": "Medium"
},
{
"Risk ID": "40",
"Residual Impact": "Medium",
"Residual Probability": "High"
},
{
"Risk ID": "41",
"Residual Impact": "Medium",
"Residual Probability": "High"
},
{
"Risk ID": "42",
"Residual Impact": "Low",
"Residual Probability": "Low"
},
{
"Risk ID": "43",
"Residual Impact": "Medium",
"Residual Probability": "Low"
},
{
"Risk ID": "44",
"Residual Impact": "Medium",
"Residual Probability": "Very High"
},
{
"Risk ID": "45",
"Residual Impact": "Medium",
"Residual Probability": "High"
},
{
"Risk ID": "46",
"Residual Impact": "Medium",
"Residual Probability": "High"
},
{
"Risk ID": "47",
"Residual Impact": "Medium",
"Residual Probability": "High"
},
{
"Risk ID": "48",
"Residual Impact": "Very High",
"Residual Probability": "Very High"
},
{
"Risk ID": "49",
"Residual Impact": "Very Low",
"Residual Probability": "Very Low"
}
]
}
}
Thanks giammariam This would work fine for me