'Responsive duration curve in Power BI
I am not experienced with DAX, but want to create a duration curve in Power BI which is responsive to the user's selections (slicers):
I am working with time series for electricity production for several countries and several energy sources, all with hourly resolution. The user interacts by applying slicers, she or he might for example be interested in wind power (slicer "type") in France (slicer "area") during the last year (time slicer). Then, the corresponding slicer settings will filter the original data set to only include the user's choice. This chosen subset of the original data should then be ranked descending according to electricity production. Finally, the ranked data should be plotted with the rank on the x-axis and the respective production values on the y-axis. That's it!
The overall goal is to study how often the observed levels (e.g. for generation, load or price) have been met or exceeded, see https://en.wikipedia.org/wiki/Load_duration_curve. The y-axis shows the observed levels and the x-axis their respective duration (e.g. in hours or percent).
Here, an example: first, the original time series, in this case electricity production hour for hour:
Second, the corresponding duration curve with all values of the original time series sorted descending hour for hour:
(The last values up to 8760 hours [1 year = 8760 h] should be zero but are not plotted because the last rank includes
k
values, therefore, the value zero
is plotted at 8760 - k
on the x-axis, but that is a minor issue.)
To produce the plots above, I simply added a calculated column showing the rank of each row and a second one to count the number of hours for every rank. The latter one is important because the production levels data[point_value]
are not necessarily unique due to rounding:
order = RANK.EQ(data[point_value],data[point_value],DESC)
count = CALCULATE(COUNTROWS(data),ALLEXCEPT(data,data[order]))
Finally, I need to divide the production level of each rank by the number of hours in each respective rank because Power BI directly sums data[point_value]
for each rank which leads to higher values as soon as there are more than one hour included in a rank (if, for example, rank no. 2 includes hours t1 and t2, both having a production level of 57 MWh/h, the value displayed should be 57 MWh/h and not 114 MWh/h):
value = data[point_value]/data[count]
Now, I plotted order
on the x-axis and value
on the y-axis resulting in the plot above.
The problem: What I created above is not responsive to the user's selections. As the data includes production levels for different production types, regions, years etc., the user should be able to visualise the corresponding duration curve for whichever production type, region, year etc. she or he is interested in. Therefore, I somehow have to use a measure which ranks the original data after the user's slicer/filter settings have been applied. This is where I struggle. How can that be done in Power BI?
Finally, it should also be possible to select several regions and to inspect their total duration curve. For example, the duration curve C
needs to be calculated based on the sum of both time series A
and B
:
In the end, the result should be something like this, but with working slicers and not just being sorted manually by me beforehand:
To facilitate, here two days of (fictive) example data which you simply can paste into Power BI as new calculated table to get a minimal working example:
data = DATATABLE
(
"id", INTEGER,
"datetimestamp", DATETIME,
"area", INTEGER,
"type", INTEGER,
"point_value", INTEGER,
{
{1001,"21-01-01 00:00",1,1,47},
{1002,"21-01-01 01:00",1,1,51},
{1003,"21-01-01 02:00",1,1,50},
{1004,"21-01-01 03:00",1,1,50},
{1005,"21-01-01 04:00",1,1,51},
{1006,"21-01-01 05:00",1,1,50},
{1007,"21-01-01 06:00",1,1,51},
{1008,"21-01-01 07:00",1,1,51},
{1009,"21-01-01 08:00",1,1,46},
{1010,"21-01-01 09:00",1,1,51},
{1011,"21-01-01 10:00",1,1,46},
{1012,"21-01-01 11:00",1,1,47},
{1013,"21-01-01 12:00",1,1,51},
{1014,"21-01-01 13:00",1,1,48},
{1015,"21-01-01 14:00",1,1,46},
{1016,"21-01-01 15:00",1,1,47},
{1017,"21-01-01 16:00",1,1,48},
{1018,"21-01-01 17:00",1,1,45},
{1019,"21-01-01 18:00",1,1,43},
{1020,"21-01-01 19:00",1,1,45},
{1021,"21-01-01 20:00",1,1,43},
{1022,"21-01-01 21:00",1,1,36},
{1023,"21-01-01 22:00",1,1,36},
{1024,"21-01-01 23:00",1,1,37},
{1025,"21-01-02 00:00",1,1,38},
{1026,"21-01-02 01:00",1,1,36},
{1027,"21-01-02 02:00",1,1,33},
{1028,"21-01-02 03:00",1,1,35},
{1029,"21-01-02 04:00",1,1,42},
{1030,"21-01-02 05:00",1,1,38},
{1031,"21-01-02 06:00",1,1,38},
{1032,"21-01-02 07:00",1,1,37},
{1033,"21-01-02 08:00",1,1,37},
{1034,"21-01-02 09:00",1,1,37},
{1035,"21-01-02 10:00",1,1,35},
{1036,"21-01-02 11:00",1,1,36},
{1037,"21-01-02 12:00",1,1,37},
{1038,"21-01-02 13:00",1,1,37},
{1039,"21-01-02 14:00",1,1,37},
{1040,"21-01-02 15:00",1,1,37},
{1041,"21-01-02 16:00",1,1,40},
{1042,"21-01-02 17:00",1,1,45},
{1043,"21-01-02 18:00",1,1,40},
{1044,"21-01-02 19:00",1,1,37},
{1045,"21-01-02 20:00",1,1,37},
{1046,"21-01-02 21:00",1,1,37},
{1047,"21-01-02 22:00",1,1,37},
{1048,"21-01-02 23:00",1,1,35},
{2001,"21-01-01 00:00",1,2,40},
{2002,"21-01-01 01:00",1,2,41},
{2003,"21-01-01 02:00",1,2,42},
{2004,"21-01-01 03:00",1,2,42},
{2005,"21-01-01 04:00",1,2,42},
{2006,"21-01-01 05:00",1,2,42},
{2007,"21-01-01 06:00",1,2,42},
{2008,"21-01-01 07:00",1,2,43},
{2009,"21-01-01 08:00",1,2,45},
{2010,"21-01-01 09:00",1,2,44},
{2011,"21-01-01 10:00",1,2,43},
{2012,"21-01-01 11:00",1,2,42},
{2013,"21-01-01 12:00",1,2,43},
{2014,"21-01-01 13:00",1,2,44},
{2015,"21-01-01 14:00",1,2,44},
{2016,"21-01-01 15:00",1,2,40},
{2017,"21-01-01 16:00",1,2,40},
{2018,"21-01-01 17:00",1,2,41},
{2019,"21-01-01 18:00",1,2,45},
{2020,"21-01-01 19:00",1,2,44},
{2021,"21-01-01 20:00",1,2,44},
{2022,"21-01-01 21:00",1,2,42},
{2023,"21-01-01 22:00",1,2,42},
{2024,"21-01-01 23:00",1,2,41},
{2025,"21-01-02 00:00",1,2,41},
{2026,"21-01-02 01:00",1,2,42},
{2027,"21-01-02 02:00",1,2,42},
{2028,"21-01-02 03:00",1,2,42},
{2029,"21-01-02 04:00",1,2,41},
{2030,"21-01-02 05:00",1,2,41},
{2031,"21-01-02 06:00",1,2,42},
{2032,"21-01-02 07:00",1,2,42},
{2033,"21-01-02 08:00",1,2,41},
{2034,"21-01-02 09:00",1,2,39},
{2035,"21-01-02 10:00",1,2,41},
{2036,"21-01-02 11:00",1,2,40},
{2037,"21-01-02 12:00",1,2,41},
{2038,"21-01-02 13:00",1,2,42},
{2039,"21-01-02 14:00",1,2,41},
{2040,"21-01-02 15:00",1,2,40},
{2041,"21-01-02 16:00",1,2,39},
{2042,"21-01-02 17:00",1,2,41},
{2043,"21-01-02 18:00",1,2,41},
{2044,"21-01-02 19:00",1,2,42},
{2045,"21-01-02 20:00",1,2,41},
{2046,"21-01-02 21:00",1,2,42},
{2047,"21-01-02 22:00",1,2,41},
{2048,"21-01-02 23:00",1,2,40},
{3001,"21-01-01 00:00",2,1,37},
{3002,"21-01-01 01:00",2,1,38},
{3003,"21-01-01 02:00",2,1,38},
{3004,"21-01-01 03:00",2,1,38},
{3005,"21-01-01 04:00",2,1,39},
{3006,"21-01-01 05:00",2,1,41},
{3007,"21-01-01 06:00",2,1,41},
{3008,"21-01-01 07:00",2,1,43},
{3009,"21-01-01 08:00",2,1,43},
{3010,"21-01-01 09:00",2,1,43},
{3011,"21-01-01 10:00",2,1,45},
{3012,"21-01-01 11:00",2,1,46},
{3013,"21-01-01 12:00",2,1,48},
{3014,"21-01-01 13:00",2,1,48},
{3015,"21-01-01 14:00",2,1,47},
{3016,"21-01-01 15:00",2,1,47},
{3017,"21-01-01 16:00",2,1,47},
{3018,"21-01-01 17:00",2,1,46},
{3019,"21-01-01 18:00",2,1,46},
{3020,"21-01-01 19:00",2,1,46},
{3021,"21-01-01 20:00",2,1,46},
{3022,"21-01-01 21:00",2,1,41},
{3023,"21-01-01 22:00",2,1,41},
{3024,"21-01-01 23:00",2,1,41},
{3025,"21-01-02 00:00",2,1,41},
{3026,"21-01-02 01:00",2,1,40},
{3027,"21-01-02 02:00",2,1,40},
{3028,"21-01-02 03:00",2,1,39},
{3029,"21-01-02 04:00",2,1,39},
{3030,"21-01-02 05:00",2,1,41},
{3031,"21-01-02 06:00",2,1,40},
{3032,"21-01-02 07:00",2,1,40},
{3033,"21-01-02 08:00",2,1,40},
{3034,"21-01-02 09:00",2,1,42},
{3035,"21-01-02 10:00",2,1,41},
{3036,"21-01-02 11:00",2,1,41},
{3037,"21-01-02 12:00",2,1,41},
{3038,"21-01-02 13:00",2,1,43},
{3039,"21-01-02 14:00",2,1,44},
{3040,"21-01-02 15:00",2,1,45},
{3041,"21-01-02 16:00",2,1,46},
{3042,"21-01-02 17:00",2,1,47},
{3043,"21-01-02 18:00",2,1,47},
{3044,"21-01-02 19:00",2,1,47},
{3045,"21-01-02 20:00",2,1,46},
{3046,"21-01-02 21:00",2,1,43},
{3047,"21-01-02 22:00",2,1,41},
{3048,"21-01-02 23:00",2,1,40},
{4001,"21-01-01 00:00",2,2,37},
{4002,"21-01-01 01:00",2,2,33},
{4003,"21-01-01 02:00",2,2,35},
{4004,"21-01-01 03:00",2,2,33},
{4005,"21-01-01 04:00",2,2,35},
{4006,"21-01-01 05:00",2,2,25},
{4007,"21-01-01 06:00",2,2,27},
{4008,"21-01-01 07:00",2,2,30},
{4009,"21-01-01 08:00",2,2,35},
{4010,"21-01-01 09:00",2,2,35},
{4011,"21-01-01 10:00",2,2,32},
{4012,"21-01-01 11:00",2,2,37},
{4013,"21-01-01 12:00",2,2,37},
{4014,"21-01-01 13:00",2,2,35},
{4015,"21-01-01 14:00",2,2,37},
{4016,"21-01-01 15:00",2,2,36},
{4017,"21-01-01 16:00",2,2,33},
{4018,"21-01-01 17:00",2,2,30},
{4019,"21-01-01 18:00",2,2,31},
{4020,"21-01-01 19:00",2,2,28},
{4021,"21-01-01 20:00",2,2,25},
{4022,"21-01-01 21:00",2,2,22},
{4023,"21-01-01 22:00",2,2,24},
{4024,"21-01-01 23:00",2,2,26},
{4025,"21-01-02 00:00",2,2,24},
{4026,"21-01-02 01:00",2,2,23},
{4027,"21-01-02 02:00",2,2,26},
{4028,"21-01-02 03:00",2,2,25},
{4029,"21-01-02 04:00",2,2,25},
{4030,"21-01-02 05:00",2,2,26},
{4031,"21-01-02 06:00",2,2,30},
{4032,"21-01-02 07:00",2,2,26},
{4033,"21-01-02 08:00",2,2,21},
{4034,"21-01-02 09:00",2,2,23},
{4035,"21-01-02 10:00",2,2,32},
{4036,"21-01-02 11:00",2,2,25},
{4037,"21-01-02 12:00",2,2,25},
{4038,"21-01-02 13:00",2,2,25},
{4039,"21-01-02 14:00",2,2,26},
{4040,"21-01-02 15:00",2,2,26},
{4041,"21-01-02 16:00",2,2,25},
{4042,"21-01-02 17:00",2,2,26},
{4043,"21-01-02 18:00",2,2,26},
{4044,"21-01-02 19:00",2,2,25},
{4045,"21-01-02 20:00",2,2,25},
{4046,"21-01-02 21:00",2,2,24},
{4047,"21-01-02 22:00",2,2,23},
{4048,"21-01-02 23:00",2,2,24}
}
)
Thanks for your help, all hints are welcome!
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|