Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

Register now to learn Fabric in free live sessions led by the best Microsoft experts. From Apr 16 to May 9, in English and Spanish.

PaulDBrown

Creating a “custom” or “hybrid” matrix in PowerBI

Backround

It seems that the request for help in creating a “custom” or “hybrid” matrix is fairly frequent in the PowerBI forums (I have come across three different threads asking for assistance regarding this topic over the last week alone).

While the default table and matrix visuals do not cater for these types of custom layouts of information, developing a solution is not actually that complicated, though it does require some work.
As is normally the case with PowerBI, there are probably a number of ways to achieve this, but I thought I would showcase a method I find relatively “painless”.

The challenge: How can we create a “custom” layout for the information in a matrix?

In the following example we wish to include a combination of columns of aggregated values as well as values filtered by a dimension itself.

Let me try to explain what I mean by the question above. Let’s say we have a simple model for sales by Channel and Item and we would like to see the performance of the sales against a target over selected periods. The default matrix visual will allow us to visualise this, albeit the layout of the information is restricted to the default structure inherent to the visual. For example we can show the information:

1) Having the dimensions and period itself as rows, and the [Sum of Actuals], Sum of Target]  and [% over target] as values:

Default rows.JPG

 

2) Having the Dimensions as rows, the periods as columns, and the [Sum of Actuals], [Sum of Target] and [% over target] as values:

default columns.JPG

 

However there is no option currently to “turn off” certain elements in the headers (or rearrange the actual structure to a specific custom layout). If we want to see the periods as columns, each value (in this case three different measures) is shown for each period.

What if we wanted to “customise” the structure of the visual to show something like this? We can actually create a custom column layout  to show the information we need. We just need to define it.

Hybrid.JPG

 

One way to create a “Custom” or “Hybrid” matrix:

First the model for the example: Two fact tables (Actuals1 & Target2) and three dimension tables (Calendar Table, Dim Item and Dim Channel)

the model.JPG

 

Step 1: Creating the custom layout for the columns of the matrix

The key to this solution is to create a “custom” column layout to use in the column bucket in the matrix. In this example, the column layout we are seeking is this:

Hybrid Columns.JPG

 

and the way to replicate this structure is by creating a corresponding table where each column header is a row of a table. This should not be hard to do in Power Query/Dax. For the purpose of this exercise

  • Create a table with three rows for the aggregate values (and an index for sorting/filtering purposes):

Values header table.JPG

  • Create a period table using the Calendar Table [Period] column referenced to the Calendar table already present in the model (in this case, the index starts at “4” to cater for the previous table rows in the previous table created):

period table.JPG

 

  • …and by appending these two tables, we have created the structure we need for the custom layout (let’s call this table “Hybrid Table”):

Hybrid table.JPG

 

Since the periods in this table are referenced to the calendar table, the rows will “grow” accordingly.

Something worth mentioning at this point is that the index column is important for two reasons:

  1. It allows for the correct sorting of the actual columns, even if the periods are filtered
  2. The index column is actually very useful in the FILTER expressions of the measures needed.

This table is unrelated to/disconnected from any other table in the model.

Full model.JPG

 

 

 

Just beware that if we are tempted to check the matrix out with the new column headers we have created the visual will “refuse to render” and complain about the lack of relationships between tables… just ignore this for now.

visual error.JPG

 

Step 2: Creating the measures for the custom matrix

Let the DAX fun begin…!

Filter Context.JPG

 

Since we are using as columns for our matrix an unrelated table, there are two main issues to be aware of regarding the filter context (with regards to the columns in the matrix) of the measures we are going to use. For this example:

  1. Which measures can rely on the actual relationships established in the model (the “aggregated values)

We can use the simple aggregation measures for these values (simple SUM and DIVIDE functions). We will specify the filter context for these in the final measure.

SumActuals.JPG

  

SumTarget.JPG

 

%DiffTarget.JPG

 

           2. In which measures we need to be specific as to the filter context and write the appropriate DAX to relate the filter to the corresponding context in the model.  (the “Period Values”)

For these measures we need to be specific about the filter context we want in the calculation. Since we are using columns from the “Hybrid Table” (which has no relationships in the model), we need to use a function to establish a virtual “one-to-one/many” relationship (TREATAS function) to enforce the filter context and filter the values accordingly using the expression as the filter in the measure.

TREATAS expression.JPG

 

Basically what we are doing is saying: “when the matrix column = Jan – 2020, filter the rows to show those which are filtered by the Calendar Table [Period] = Jan – 2020”.

 

In this example, we want to show the % difference between the actuals vs the target for each period in the matrix:

TREATAS.JPG

 

Having established the measures we need, all we need now is the final measure we will use in the matrix to take into account the filter context for each of the “HybridColumns” we are using in the matrix columns. This measure will establish which of the previous measures must be used based on the filter context established by the columns included in the matrix from our Hybrid Table. Since the actual results vary from whole/decimal numbers, we also need to specify the FORMAT required for each result:
The filter context is established by the columns:
Hybrid Columns.JPG

 Which come from our “Hybrid Table” (we are using the index reference for the Hybrid table for simplicity purposes):

Hybrid table.JPG

 

And this is the final measure which we will use for the values in the matrix:

Final Measure.JPG

 We can now create the matrix using:
         a) The Channel and Item dimensions as rows.

         b) The HybridColumns from our Hybrid Table for the Column Bucket

         c) The final measure [Values for Matrix] in the values bucket to get this:

         d) (some conditional formatting for the values displayed)

Final Custom Matrix.jpg

 

Step 3: Enabling the filtering of the columns in the custom matrix


Since we want to be able to filter the matrix by our periods of choice in a slicer, we need one more measure. The slicer on the page is from the ‘Calendar Table’ [Period] column, so we need to be able to select the periods to be shown in the matrix based on the selection made on this slicer from the calendar table. The measure must compare the values selected in the slicer with those established in the visual from the Hybrid Table:

FILTER Matrix1.JPG

 

We can then use this filter in the filter pane for the matrix visual to filter the columns based on the selection in the Calendar Table [Period] Slicer. We set the TopN for the HybridColumns field in the filter Pane  as “1” to make the visual respond to the selection made in the ‘Calendar Table’ [Period] Slicer.

TopN filter.JPG

 

We thereby can now use the Calendar Slicer (Calendar Table [Period]) to filter the periods we want to see in the visual.

 

Conclusion: The flexibility offered by PowerBI and DAX allows us to create “custom” matrices to reflect the layout of information we need to depict in our reports.

 

PS: If this tutorial is unclear, please feel free to contact me on this thread or via pm!

Comments

How do I join the forum?  

 

 

@bkanderso 

You're already registered. Here is the link to the list of forums

https://community.powerbi.com/t5/Forums/ct-p/PBI_Comm_Forums 

@PaulDBrown

Paul I appreciate the response.

 

Maybe you can help me.  I have tried the formula below hoping it would correct my problem. I keep getting "The measure formula must start with an equal sign".  The formula does start with a equal sign.  Can you look a the formula and give a suggestion as to how to correct this?

 

Values for Matrix =

VAR calc =
SWITCH(SELECTEDVALUE ('fHybridTable'[Index]),
1,[DeployQCount],
2,[HDQCount],
3,[SailorQCOunt],

IF(ISFILTERED('dPmonths'[P-Month]), //missing arguments in last if-statement
))

RETURN

IF (
AND ( ISBLANK ([DeployQCount]), ISBLANK ( [HDQCount])), ISBLANK([UnitQCount]),
BLANK (),
calc
)

Me puedes ayudar ?

 

Me gustaria filtrar por año y obtener el saldo por mes, mi matriz es un poco diferente..

Hi @PaulDBrown 
I have tagged you in my own forum post: https://community.powerbi.com/t5/Desktop/Creating-a-matrix-with-rounded-numbers-but-exact-total-a-qu... 

I was wondering if it would be possible to achieve, what I want with your method, but can't seem to get my head around whether it is possible or not. Would you mind giving it a look?

Thanks, it's a great blog and the sums are apearing correctly in my version, however I don't understand how the months Feb-2020 etc.. get loaded as the dax only goes up to index 3?

 

Hybrid Matrix Table

HybridColumnsIndex

2021

1
20222
20233
Jan - Feb 214
Mar - Apl 215
May - Jun 216
Jul - Aug 217
Sep - Oct 218
Nov - Dec 219
...

...

 

 

Date Table

Custom_Period_1
Jan - Feb 21
Mar - Apl 21
Jul - Aug 21
Sep - Oct 21
Nov - Dec 21
Jan - Feb 22
Mar - Apl 22
Jul - Aug 22
Sep - Oct 22
...

 

DAX

2021 = calcuate(sum(fact_table[value_dollar]), Dim_Date_Table([CalendarYear] = "2021"))

2022 = calcuate(sum(fact_table[value_dollar]), Dim_Date_Table([CalendarYear] = "2022"))

2023 = calcuate(sum(fact_table[value_dollar]), Dim_Date_Table([CalendarYear] = "2023"))

SUM_JAN_FEB_21 = CALCULATE(A_Measures[2021],TREATAS(VALUES(Hybrid_Matrix[HybridColumns], Dim_Date_Table[Custom_Period_1], Dim_Date_Table[Custom_Period_1] = "Jan - Feb 21"

SUM_MAR_APL_21 = CALCULATE(A_Measures[2021],TREATAS(VALUES(Hybrid_Matrix[HybridColumns], Dim_Date_Table[Custom_Period_1], Dim_Date_Table[Custom_Period_1] = "MAR - APL 21"

etc...

 

Values for Matrix =

VAR CALC = IF(SELECTEDVALUE(Hybrid_Value[Index] = 1, A_Measures[2021],

                       IF(SELECTEDVALUE(Hybrid_Value[Index] = 2, A_Measures[2022],

                          IF(SELECTEDVALUE(Hybrid_Value[Index] = 3, A_Measures[2023],BLANK()

                       )))

Return

IF(AND(AND(ISBLANK[2021]),ISBLANK([2022]), ISBLANK([2023])),BLANK(),calc)

 

Filter Matrix =

VAR dim =VALUES(Dim_Date_Table(Custom_Period_1)

VAR clod = CALCULATETABLE(VALUES(Hybrid_Matrix[HybridColumns]),Hybrid_Matrix[HybridColumns] IN {"2021","2022","2023"})

VAR ref = UNION(dim,clod)

VAR matrix = VALUES(Hybrid_Matrix[HybridColumns])

Return

COUNTROWS(INTERSECT(ref,matrix)

 

Current Result,

Years display correctly but none of the Periods\Months. They do if I add them seperately from the relevant measure or add a line to 'Values for Matrix'  IF(SELECTEDVALUE(Hybrid_Value[Index] = 4, A_Measures[Jan - Feb 21] etc...

 

Rows 2021 2022
product code 22322 76566
product code 55454 8776
product code 22322 44333

 

So I'm not sure what is missing for the months to be included.

 

Thanks

@ringovski 

 

Ok, you seem to be on the right track, but the [values for matrix] measure needs a measure(s) for index >3.

Having said that, you can probably achieve the [values for matrix] measure in a much simpler expression. Instead of writing a measure for each year, and since your date table contains a year column, you could use the following for the year calculations:

 

year measure =
CALCULATE (
    SUM ( 'fact_table'[value_dollar] ),
    TREATAS (
        VALUES ( 'Hybrid_Matrix'[HybridColumns] ),
        'Dim_Date_Table'[CalendarYear]
    )
)

 

Similarly for the period measures...

Let's assume that the measure you wish to display is the sum of a particular value which is to be filtered by the period: [Sum Value]

 

You can the use the following for the period measure:

 

Period Measure =
CALCULATE (
    [Sum Value],
    TREATAS (
        VALUES ( Hybrid_Matrix[HybridColumns] ),
        Dim_Date_Table[Custom_Period_1]
    )
)

 

 

The measure for the matrix then becomes:

 

Values for matrix =
IF (
    SELECTEDVALUE ( Hybrid_Value[Index] ) < 4,
    [year measure],
    [Period Measure]
)

 

 

Or you can put it all in a single measure using variables of course:

 

Values for Matrix =
VAR year_measure =
    CALCULATE (
        SUM ( 'fact_table'[value_dollar] ),
        TREATAS (
            VALUES ( 'Hybrid_Matrix'[HybridColumns] ),
            'Dim_Date_Table'[CalendarYear]
        )
    )
VAR Period_Measure =
    CALCULATE (
        [Sum Value],
        TREATAS (
            VALUES ( Hybrid_Matrix[HybridColumns] ),
            Dim_Date_Table[Custom_Period_1]
        )
    )
RETURN
    IF (
        SELECTEDVALUE ( Hybrid_Value[Index] ) < 4,
        [year_measure],
        [Period_Measure]
    )

 

When you use TREATAS, you are in effect establishing a virtual relationship between two disconnected tables, so the filter context passed onto de date table will filter the rows relevant to the conext (so 2021 filters 2021 data etc...)

 

You will of course need to use the relevants measures  to your calculations. I used a simple SUM as an example. 

I hope that helps.

 

 

Hi @PaulDBrown , Thankyou for the blog. I am just wondering is there a way to have a drill down at columns level for Year,Quarter,Month,Week ? or it can only be done at 1 level which is period

Thank you for the ste-by-step clear instructions. I have learnt a lot from this project.