Milestone trend analysis visual in Power BI with Deneb

Context

If you are reading this blog post, I assume that you already know what a milestone trend analysis is and its benefits to track progress in project management. Therefore, I will not cover it here and if you want to know more about the theory behind it you can just google it or ask ChatGPT :)

This blog post is about how to develop a milestone trend analysis in Power BI with Deneb.

Deneb and Vega-Lite code

I developed this milestone trend analysis visual with Deneb using Vega-Lite. Before we talk about how to develop the visual, let’s take a look what we want to achieve. See below the Power BI report:

You can find below the complete code used to create the chart. But don’t worry, we are going to go through the code. Just to be clear, I am not an expert in Deneb Vega-Lite, so there might be more efficient ways to write the code below.

1{
2  "data": {"name": "dataset"},
3  "layer": [
4    {
5      "mark": {"type": "line"},
6      "encoding": {
7        "x": {
8          "aggregate": "min",
9          "field": "Reporting Date",
10          "type": "temporal"
11        },
12        "x2": {
13          "aggregate": "max",
14          "field": "Max Forecast"
15        },
16        "y": {
17          "aggregate": "min",
18          "field": "Reporting Date",
19          "type": "temporal"
20        },
21        "y2": {
22          "aggregate": "max",
23          "field": "Max Forecast"
24        }
25      }
26    },
27    {
28      "params": [
29        {
30          "name": "Category",
31          "select": {
32            "type": "point",
33            "fields": [
34              "Milestone MTA visual"
35            ]
36          },
37          "bind": "legend"
38        }
39      ],
40      "mark": {
41        "type": "line",
42        "point": true
43      },
44      "encoding": {
45        "x": {
46          "field": "Reporting Date",
47          "type": "temporal",
48          "title": "Reporting date",
49          "axis": {
50            "format": "%b %Y",
51            "grid": true,
52            "orient": "top"
53          }
54        },
55        "y": {
56          "field": "Filtered Milestones Forecast",
57          "type": "temporal",
58          "title": "Forecast date",
59          "axis": {
60            "format": "%b %Y",
61            "grid": true
62          }
63        },
64        "color": {
65          "field": "Milestone MTA visual",
66          "type": "nominal",
67          "scale": {
68            "scheme": "pbiColorNominal"
69          }
70        },
71        "opacity": {
72          "condition": {
73            "param": "Category",
74            "value": 1
75          },
76          "value": 0.05
77        },
78        "tooltip": [
79          {"field": "Project Name"},
80          {"field": "Milestone Name"},
81          {"field": "Reporting Date"},
82          {"field": "Max Forecast"}
83        ]
84      }
85    }
86  ]
87}

Let’s break down the code into 4 sections:

Section 1: Create a dynamic line to calculate the min value for reporting date and max value for the forecast date for the selected milestones

See below the explanation about the following section of the code:

As we can see from the code, I created the dynamic line inside a layer. It is important to create this layer, because we want to create two different visuals on top of each other. For more details about layer in Vega-Lite refer to the documentation here.

Section 2: Create a parameter to be used later to have an interactive legend

See below the explanation about creating the parameter. As you can see below, I created a measure called “Filtered Milestone”, this measure checks if any milestone is selected from the slicer. In this case, if the user doesn’t select any milestone from the slicer, the legend of the visual returns nothing in order to avoid visual clutter. I got this idea from a great blog post from Nikola Ilic, for more details refer to his blog post here.

Section 3: Create a line chart with “Reporting Date” and milestone forecast

See below the code and the explanation to create the line chart with the reporting date and with the DAX measure with the milestone forecast.

Section 4: Create the interactive legend and tooltip

This is the final step to create the milestone trend analysis visual. See below the explanation of the final section of the code:

Configuration properties of the visual

It is possible to add configuration properties for a visual to create a consistent theme. See below the configuration properties used to create this milestone trend analysis visual:

1{
2  "view": {"stroke": "transparent"},
3  "font": "Segoe UI",
4  "arc": {},
5  "area": {
6    "line": true,
7    "opacity": 0.6
8  },
9  "bar": {},
10  "line": {
11    "strokeWidth": 3,
12    "strokeCap": "round",
13    "strokeJoin": "round"
14  },
15  "path": {},
16  "point": {"filled": true, "size": 75},
17  "rect": {},
18  "shape": {},
19  "symbol": {
20    "strokeWidth": 1.5,
21    "size": 50
22  },
23  "text": {
24    "font": "Segoe UI",
25    "fontSize": 12,
26    "fill": "#605E5C"
27  },
28  "axis": {
29    "ticks": false,
30    "grid": false,
31    "domain": false,
32    "labelColor": "#605E5C",
33    "labelFontSize": 12,
34    "titleFont": "Segoe UI",
35    "titleColor": "#252423",
36    "titleFontSize": 16,
37    "titleFontWeight": "normal"
38  },
39  "axisQuantitative": {
40    "tickCount": 3,
41    "grid": true,
42    "gridColor": "#C8C6C4",
43    "gridDash": [1, 5],
44    "labelFlush": false
45  },
46  "axisX": {"labelPadding": 5},
47  "axisY": {"labelPadding": 10},
48  "header": {
49    "titleFont": "Segoe UI",
50    "titleFontSize": 16,
51    "titleColor": "#252423",
52    "labelFont": "Segoe UI",
53    "labelFontSize": 12,
54    "labelColor": "#605E5C"
55  },
56  "legend": {
57    "titleFont": "Segoe UI",
58    "title": null,
59    "titleFontWeight": "bold",
60    "titleColor": "#605E5C",
61    "labelFont": "Segoe UI",
62    "labelFontSize": 14,
63    "labelColor": "#605E5C",
64    "symbolType": "circle",
65    "symbolSize": 150,
66    "orient": "bottom",
67    "columns": 4,
68    "labelLimit": 300
69  }
70}
    

Last updated on December 24, 2023

Previous
Previous

How to optimize PySpark pivot operations

Next
Next

Pro tips to optimize Power BI data modeling: automating manual tasks