Deneb Workout 03 - KPI Donut Chart

Difficulty Rating: 2 out of 5

Deneb Workout 03 - KPI Donut Chart

One of the main benefits of using Deneb in Power BI is that multiple marks can be layered.

Goals
Using the simple supplied dataset, produce a circular chart Deneb visual in Power BI that:
• consists of 4 overlapping marks (2 arc, 2 text)
• includes a transform block with in-visual calculations to extend the dataset
• includes a parameters block to create non-dataset values and calculations for reuse
• includes an input widget for interactive colour selection
• includes a title block with subtitle

Submission
Load the supplied data file into a new Power BI file, create your solution, and reply to this post. Upload a screenshot of your solution along with the Deneb/Vega-Lite JSON code used. Please format your JSON code and blur it or place it in a hidden section.

Period
This workout will be released on April 3, 2023, and the author’s solution will be posted on April 9, 2023.

Greg
Deneb Workout 03 - Data - Actual vs Budget.xlsx (9.0 KB)

2 Likes

Hi everyone,
Finally, I found the solution to this workout! For me, the hardest part was the color selection. It took me more than 4 hours to find the solution.

Here is my solution:

Deneb Workout 003_AA

Json

Deneb Workout 003_AA.json (4.5 KB)

1 Like

Hi All,

I used for this workout ideas from:
@Greg Template: Deneb Template - Donut KPI Chart - Deneb Showcase - Enterprise DNA Forum
@Greg solution for workout 001 and his option 2: Deneb Workout 01 - Line Chart with Smoothing - Workouts / Deneb - Enterprise DNA Forum

My solution:

Code:

{
  "width": 260,
  "height": 200,
  "title": {
    "text": "Deneb Workout 03",
    "subtitle": "KPI Donut Chart",
    "subtitleFontStyle": "italic",
    "anchor": "start",
    "align": "left",
    "font": "Verdana",
    "fontSize": 16,
    "fontWeight": "bold",
    "offset": 20
  },
  "data": {"name": "dataset"},
  "transform": [
    {
      "calculate": "2*PI*datum['Percentage Actual vs Budget']",
      "as": "Ring1_Theta2"
    }
  ],
  "params": [
    {
      "name": "_colour",
      "value": "#0F4C81",
      "bind": {
        "input": "color",
        "name": "colour: "
      }
    },
    {
      "name": "_RingOuterRadius",
      "value": 80
    },
    {
      "name": "_RingInnerRadius",
      "value": 100
    }
  ],
  "layer": [
    {
      "name": "RING OPAQUE BACKGROUND",
      "mark": {
        "type": "arc",
        "outerRadius": {
          "expr": "_RingOuterRadius"
        },
        "innerRadius": {
          "expr": "_RingInnerRadius"
        },
        "theta": 0,
        "theta2": {"expr": "2 * PI"}
      },
      "encoding": {
        "color": {
          "value": {"expr": "_colour"}
        },
        "opacity": {"value": 0.3}
      }
    },
    {
      "name": "RING",
      "mark": {
        "type": "arc",
        "tooltip": true,
        "outerRadius": {
          "expr": "_RingOuterRadius"
        },
        "innerRadius": {
          "expr": "_RingInnerRadius"
        },
        "theta": 0,
        "theta2": {
          "expr": "datum.Ring1_Theta2"
        },
        "cornerRadius": 10
      },
      "encoding": {
        "color": {
          "value": {"expr": "_colour"}
        },
        "tooltip": [
          {
            "field": "Percentage Actual vs Budget",
            "title": "Actual vs Budget",
            "format": "#%",
            "formatType": "pbiFormat"
          }
        ]
      }
    },
    {
      "name": "VALUE",
      "mark": {
        "type": "text",
        "fontSize": 24
      },
      "encoding": {
        "text": {
          "field": "Percentage Actual vs Budget",
          "type": "nominal",
          "format": "#%",
          "formatType": "pbiFormat"
        },
        "color": {"value": "#000000"}
      }
    },
    {
      "name": "LABEL",
      "mark": {
        "type": "text",
        "fontSize": 12,
        "dx": 0,
        "dy": 20
      },
      "encoding": {
        "text": {
          "field": "Percentage Description",
          "type": "nominal"
        },
        "color": {"value": "#000000"}
      }
    }
  ]
}

Here’s my solution to this workout, where I used several Deneb/Vega-Lite features, including:
• title block complete with subtitle
• used a transform block to extend the dataset by performing in-visual calculations to convert the percent value to radians
• used a params block to enhance the dataset with size and position settings and calculations and to house the colour: input widget
• used a layer block with 4 marks (in background-to-foreground order):
- donut background (arc mark, 100% size, colour as selected from the colour widget, opacity = 0.3
- donut foreground (arc mark, percent size, colour as selected from the colour widget, corner radius 1/2 of the donut width)
- percent value (text mark, Power BI formatting)
- percent label (text mark, Y-position lowered by 20 pixels)

Here’s the code:

{
  "title": {
    "anchor": "start",
    "align": "left",
    "offset": 10,
    "text": "Deneb Workout 03",
    "font": "Verdana",
    "fontSize": 16,
    "fontWeight": "bold",
    "fontStyle": "normal",
    "subtitle": "KPI Donut Chart",
    "subtitleFont": "Verdana",
    "subtitleFontSize": 12,
    "subtitleFontWeight": "normal",
    "subtitleFontStyle": "italic"
  },
  "data": {"name": "dataset"},
  "height": 300,
  "width": 300,
  "transform": [
    {
      "calculate": "'Actual vs. Budget'",
      "as": "_ratio_label"
    },
    {
      "calculate": "datum['Actual'] / datum['Budget']",
      "as": "_ratio_percent"
    },
    {
      "calculate": "2*PI*datum['_ratio_percent']",
      "as": "_ratio_radians"
    }
  ],
  "params": [
    {"name": "_ring_max", "value": 120},
    {
      "name": "_ring_width",
      "value": 20
    },
    {
      "name": "_ring_outer",
      "expr": "_ring_max+2"
    },
    {
      "name": "_ring_inner",
      "expr": "_ring_outer-_ring_width"
    },
    {
      "name": "_color",
      "value": "#0000FF",
      "bind": {
        "input": "color",
        "name": "colour: "
      }
    }
  ],
  "layer": [
    {
      "name": "BACKGROUND",
      "mark": {
        "type": "arc",
        "radius": {
          "expr": "_ring_outer"
        },
        "radius2": {
          "expr": "_ring_inner"
        },
        "theta": 0,
        "theta2": {"expr": "2 * PI"},
        "color": {"expr": "_color"},
        "opacity": 0.3
      }
    },
    {
      "name": "RING",
      "mark": {
        "type": "arc",
        "radius": {
          "expr": "_ring_outer"
        },
        "radius2": {
          "expr": "_ring_inner"
        },
        "theta": 0,
        "theta2": {
          "expr": "datum['_ratio_radians']"
        },
        "color": {"expr": "_color"},
        "cornerRadius": 10
      }
    },
    {
      "name": "VALUE",
      "mark": {
        "type": "text",
        "fontSize": 24,
        "color": "black"
      },
      "encoding": {
        "text": {
          "field": "_ratio_percent",
          "type": "quantitative",
          "formatType": "pbiFormat",
          "format": "#%"
        }
      }
    },
    {
      "name": "LABEL",
      "mark": {
        "type": "text",
        "align": "center",
        "fontSize": 12,
        "color": "black",
        "dy": 20
      },
      "encoding": {
        "text": {
          "field": "_ratio_label",
          "type": "nominal"
        }
      }
    }
  ]
}

Congratulations to all who participated, and good luck.
Greg
Deneb Workout 03 - KPI Donut Chart.pbix (1.4 MB)

1 Like