Forum

DAX: calculate move...
 
Notifications
Clear all

DAX: calculate movement from fact(balances data) for dynamic date granularity

6 Posts
2 Users
0 Reactions
188 Views
(@austris)
Posts: 20
Eminent Member
Topic starter
 

Hi all,

I'm not a DAX expert by any means - hence, my approach might demonstrate lack of basic fundamentals but I'd still hope you could guide me to the right solution.

I've got fact table 'trs smf' and it's joined to date table 'Calendar'. The join is [trs smf][dt_smf]<-[Calendar][dt].

The fact table are BALANCES (as opposed to movements), i.e., I cannot total differnt dates together to get the monhtly amount, for instance - I have to pick a pre-defined date (dt_smf) that would hold the balance for that entire month. So, the point is to pick the right [dt_smf] transactions to display on the visual. What is 'right' is determined by a user by selecting date granularity, e.g., daily, weekly, monhtly etc.

I've managed to get the right values displayed but I'm struggling to calculate&display the movement, e.g., if user opts to see 'monthly' values - I can get visual to display the balance for June & July correctly, but I cannot figure out how to calculate the movement between the two, i.e., how to get 'previous' month balance if user opted to have 'monthly' and then subrtract it from 'next' month, or how to get 'previous' week balance, if user opted to view data 'weekly' etc.

This is what I've done:

The date granularities are:

Daily, Weekly, Monthly, Quarterly, Yearly

The [trs smf] has columns that contain date IF they're to be used for the selected granularity otherwise they're blank. These are the columns:

dt_day

dt_we

dt_m

dt_q

dt_y

e.g., if the row IS TO BE USED for 'weekly' granularity, then dt_we would have a date otherwise it would be blank.

I've also created a calculation group with according items, e.g.:

========================

Yearly =

CALCULATE(

SELECTEDMEASURE(),

FILTER(

'trs SMF',

not ISBLANK(('trs SMF'[DT_Y]))

)

)

Weekly =

CALCULATE(

SELECTEDMEASURE(),

FILTER(

'trs SMF',

not ISBLANK(('trs SMF'[DT_WE]))

)

)

... and the same for daily, monthly, quarterly

========================

This works to display the actual balances for the chosen granularity BUT how would I get to display the movement from previous year/quarter/month/week/day - depending on the date granularity chosen by the iuser?

I don't think I can use 'visual calculations' as I need to use 'fields' parameter.

I hope it makes snese what I'm after and you could point me in the right direction...

 
Posted : 17/08/2024 5:58 am
(@catalinb)
Posts: 1937
Member Admin
 

you're heading in the right direction. You’re leveraging a calculation group to filter your fact table (

trs smf

) based on the selected granularity, which is correct. Now, to calculate the movement (difference) between periods, you need to reference the previous period's balance dynamically based on the selected granularity.

Here's how you can achieve that:

1. Create a Calculation Group for the Movement Calculation

In addition to the calculation group you’ve created for filtering by date granularity, you should create another calculation group (or extend the existing one) to handle the movement calculation. This will allow you to calculate the difference between the current period's balance and the previous period's balance.

2. Using

PREVIOUSMONTH, PREVIOUSWEEK, PREVIOUSMONTH, PREVIOUSWEEK, PREVIOUSDAY, etc., in combination with CALCULATE to get the balance of the previous period.

Here’s how you can do it:

dax

Copy code
Movement Calculation =
SWITCH (
SELECTEDVALUE ( 'Granularity'[Granularity] ),
"Yearly",
CALCULATE (
SELECTEDMEASURE (),
FILTER (
'trs SMF',
'trs SMF'[dt_y] = PREVIOUSYEAR ( 'Calendar'[Date] )
)
) - SELECTEDMEASURE(),

"Quarterly",
CALCULATE (
SELECTEDMEASURE (),
FILTER (
'trs SMF',
'trs SMF'[dt_q] = PREVIOUSQUARTER ( 'Calendar'[Date] )
)
) - SELECTEDMEASURE(),


"Monthly",
CALCULATE (
SELECTEDMEASURE (),
FILTER (
'trs SMF',
'trs SMF'[dt_m] = PREVIOUSMONTH ( 'Calendar'[Date] )
)
) - SELECTEDMEASURE(),


"Weekly",
CALCULATE (
SELECTEDMEASURE (),
FILTER (
'trs SMF',
'trs SMF'[dt_we] = DATEADD ( 'Calendar'[Date], -7, DAY )
)
) - SELECTEDMEASURE(),


"Daily",
CALCULATE (
SELECTEDMEASURE (),
FILTER (
'trs SMF',
'trs SMF'[dt_day] = PREVIOUSDAY ( 'Calendar'[Date] )
)
) - SELECTEDMEASURE()
)

3. Understanding the Calculation

  • Yearly: Subtracts the previous year's balance from the current year's balance.
  • Quarterly: Subtracts the previous quarter's balance from the current quarter's balance.
  • Monthly: Subtracts the previous month's balance from the current month's balance.
  • Weekly: Subtracts the balance 7 days ago (previous week) from the current week's balance.
  • Daily: Subtracts the previous day's balance from the current day's balance.

4. Implementing the Calculation Group

You should include this logic within your calculation group. This allows the movement calculation to dynamically adjust based on the user's selected granularity.

5. Handling Edge Cases

You might need to handle cases where the previous period doesn't exist (e.g., the first day of the year, the first week of the year, etc.). You can include a conditional check to return

BLANK()

or

0

in such cases.

6. Displaying the Result

Finally, ensure that your visual is set up to use this calculation. When a user selects a granularity (Yearly, Quarterly, Monthly, etc.), the

Movement Calculation

measure will compute the difference accordingly and display it.

Final Notes:

  • Date Table: Ensure that your
    Calendar

    table is complete and has the necessary relationships established with your fact table (

    trs smf

    ).

  • Performance: Depending on the data size, this approach might have performance implications. Consider optimizing the model or using
    SUMMARIZE

    or

    ADDCOLUMNS

    to pre-aggregate data where possible.

This solution should give you the ability to dynamically calculate and display the movement between periods based on the user-selected granularity.

 
Posted : 20/08/2024 1:09 am
(@austris)
Posts: 20
Eminent Member
Topic starter
 

Great - thank you Catalin!

Not only it provides scripts but also explanations, pointers - highly useful!

I'm half-way there as in I created another calculation group to calculate the movements and it seems to be working and then I realised that I might have a fundamental flaw with this approach - I mean: is it possible to put on a single visual (table and/or matrix) both - the balances and the movements?

Because when I try to do it in a table visual - once I add the movements calc group - only movements show (but not balances anymore), if I put in the matrix - then they're always nested, i.e., i cannot put them in 2 columns one next to each other - one would display balances and the other would display the movements.

Am I right in thinking that with this approach I cannot achieve that (because the 'movement calc group'  by default always pushes the calculated measure to display only movement but not the balances)?

 
Posted : 20/08/2024 7:31 am
(@catalinb)
Posts: 1937
Member Admin
 

You're correct in your observation: when you create a calculation group in Power BI, the calculation group essentially replaces the default measure with the logic defined in the selected calculation item. This makes it difficult to display both the original measure (e.g., balances) and the calculated value (e.g., movements) side by side in a single visual using only calculation groups.

Approach and Potential Solutions

To achieve your goal of displaying both balances and movements in two columns side by side, here are a few potential approaches:

1. Duplicate Measures for Balances and Movements

You can create separate measures for balances and movements instead of relying solely on the calculation group. This way, you have control over where each measure is placed in your visual.

  • Balance Measure:
     
    Balance = SUM('YourTable'[BalanceColumn])
  • Movement Measure:
     
    Movement =
    CALCULATE(
    [Balance],
    DATEADD('Date'[Date], -1, MONTH) // Adjust the period based on your granularity
    ) - [Balance]

Then, in your table or matrix, you can place both the Balance measure and the Movement measure side by side.

2. Using Calculation Groups with Separate Measures

You can use two calculation groups, but you need to create two separate base measures:

  • Base Measure for Balance:
    Balance = SUM('YourTable'[BalanceColumn])
  • Base Measure for Movement:
    Movement Calculation =
    VAR PreviousPeriod =
    CALCULATE(
    [Balance],
    PREVIOUSMONTH('Date'[Date]) // or PREVIOUSDAY, PREVIOUSQUARTER, etc., based on granularity
    )
    RETURN
    [Balance] - PreviousPeriod

In this case, when you use the calculation groups, you apply one to the Balance measure and another to the Movement Calculation measure. The calculation group should now be used to adjust for different granularities rather than handling the entire calculation.

3. Use Two Different Calculation Groups with SWITCH Function

You can create two separate calculation groups, one for balances and one for movements, and use a SWITCH function within your measures to toggle between the two. Here’s a general idea:

  • Balance Calculation Group: Adjusts for granularity (daily, weekly, monthly, etc.)
  • Movement Calculation Group: Handles the calculation of the difference between periods.

In your visual, use measures that check the selected calculation group item and apply the appropriate calculation.

  • Combined Measure:
    Combined Measure =
    SWITCH(
    SELECTEDVALUE('CalculationGroup'[CalculationItem]),
    "Balance", [Balance],
    "Movement", [Movement Calculation],
    BLANK()
    )

However, this approach can get complex and might still not allow the clean separation into columns that you're looking for.

Conclusion

The most straightforward approach, given the limitations of calculation groups, is to create separate measures for balances and movements. This allows you to place both measures side by side in your visuals without conflicts. Calculation groups are powerful, but they work by replacing measures, so they aren't inherently designed to show multiple calculated results in separate columns simultaneously.

If you decide to go the route of using separate measures, you'll have the flexibility to display both the balance and the movement side by side in any visual without the issues you're currently encountering.

 
Posted : 21/08/2024 12:23 am
(@austris)
Posts: 20
Eminent Member
Topic starter
 

Thanks Cataling again - you're right - it looks like having the 2 measures (balance & movement) is the way to go - thanks for pointing that out!

I marked your initial answer as the answer for the post because it elegantly answered exactly what I asked for in my initial post (I just didn't realize what my faulty assumption were).

 
Posted : 24/08/2024 1:23 pm
(@catalinb)
Posts: 1937
Member Admin
 

Well, I have to be honest and give credit to latest ChatGPT 4o, I was testing it to see if it is able to provide a viable solution based on your (very detailed) description. Even the measures and steps are AI generated.

Answers are pretty solid though.

Thank you

 
Posted : 25/08/2024 2:22 am
Share: