SVG in Power BI – Part 3 – Fill up with Colour
Series
This is the second post in a series of Using SVG within Power BI. The series is to support my session at Power BI Days in Mechelen, Belgium in April 2019. The complete series is listed below :
- Introduction to SVG
- KPI Shapes in Power BI
- Filling up with colour using SVG in Power BI
- Using Text in SVG
- Using SVG Rotate to create a dial in Power BI
- SVG Icons in Conditional Formatting
- Using a Theme to add SVG Icons
- Feb 2023 Update – 5 SVG Stars
In this post we will introduce using icons and filling the icon with colour to show a percentage value.
YouTube Video
If you would prefer a video of this topic:
Getting Icon Code
You can download icons from lots of web sites. Search for SVG icons or ask your marketing teams for company graphics as SVG. If you are using Office 2016 or above the icons in PowerPoint can be saved as SVG files. Icons can be found on the Insert ribbon and once inserted on a slide, right click and save as a picture.
Once you have the icon take a look at the SVG code. There will be an open <SVG> tag with lots of attributes then one or more <PATH …. /> elements and then a closing tag </SVG>. You need to do a search replace the double quotes into single quotes, e.g. <path d=”…. has to become <path d=’…..
What we want is the <PATH …. /> and its long so I save it into a measure.
Draw 2 Elephants
We are going to draw 2 elephants, one grey and one coloured one on top. The coloured one we will clip to size to show it being filled up.
Next task is to create a measure in our report. Inside the measure we create 2 variables, one to store the svg start and one for the svg end. As a quick test we return the concatenation of the variables and the previous created measure to draw our icon.
Elephant Measure =
// svg essentials
var svg_start = "data:image/svg+xml;utf8,<svg
xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'>"
var svg_end = "</svg>"
return
svg_start & [EleSVG] & svg_end
If you use the custom visual Image from Cloud Scope you can add the measure and the icon will be shown in Power BI.
In order to draw a grey and red elephant we will nest the elephant in a <g> group tag and give the <g> element properties that the nested elements will inherit.
I add 2 more variables one for the grey elephant and one for the red one. and tweak the return to use the new elephant variables. It will draw both elephants but they are exactly over each other so you only see the red one.
Elephant Measure =
// svg essentials
var svg_start = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'>"
var svg_end = "</svg>"
// Coloured Elephants
var grey_ele = "<g style='fill:grey;'>" & [EleSVG] & "</g>"
var red_ele = "<g style='fill:red;'>" & [EleSVG] & "</g>"
return
svg_start & grey_ele & red_ele & svg_end
Clip the Red Elephant
We now want to only show a percentage of the red elephant based off a percentage measure, e.g. work complete. For this we need to create a clip-path. A clip-path defines which part of the shape will be visible. So in this case it will be a rectangle starting at 0,0 and will be height = 100 and width = percentage measure * 100.
So we create a variable to calculate the width and then a variable to store the defs tag that contains the clip-path. The red_ele variable is then tweaked to include a reference to the clip-path and the return is changed to include the defs variable.
Elephant Measure =
// svg essentials
var svg_start = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'>"
var svg_end = "</svg>"
// defs
var clip_width = [Work Complete] * 100
var defs = "<defs><clipPath id='eleClip'>
<rect x='0' y='0' width='" & clip_width & "' height='100' />
</clipPath></defs>"
// Coloured Elephants
var grey_ele = "<g style='fill:grey;'>" & [EleSVG] & "</g>"
var red_ele = "<g style='fill:red; clip-path:url(#eleClip)'>" & [EleSVG] & "</g>"
return
svg_start & defs & grey_ele & red_ele & svg_end
Now we have 2 measures, one that calculates a percentage and one that shows that percentage in colour.
Filling from the bottom up
The above example fills from the left. It is the easiest to calculate but if someone was asked to draw this idea they would probably fill in the colour from the bottom up.
Our icon is in a square which goes from 0,0 and is 100 wide and 100 tall. If we wanted to show 25% full the clip path would need to be 0,75 and 100 wide and 25 tall. So 2 values change the height is 25 = 100 * 25% and the starting y is 75 = 100 – height.
So to fill from the bottom I need to change the defs
Elephant Measure =
// svg essentials
var svg_start = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'>"
var svg_end = "</svg>"
// defs
var clip_height = [Work Complete] * 100
var clip_y = 100 - clip_height
var defs = "<defs><clipPath id='eleClip'>
<rect x='0' y='" & clip_y & "' width='100' height='" & clip_height & "' />
</clipPath></defs>"
// Coloured Elephants
var grey_ele = "<g style='fill:grey;'>" & [EleSVG] & "</g>"
var red_ele = "<g style='fill:red; clip-path:url(#eleClip)'>" & [EleSVG] & "</g>"
return
svg_start & defs & grey_ele & red_ele & svg_end
Conclusion
This gives us a quick visual measure to show a percentage.