Dynamic hierarchies in Power BI

Dynamic hierarchies in Power BI

Currently, Power BI does not have a built-in feature that enables you to switch between hierarchy levels with a slicer. While some field wells let you use a hierarchy, others, such as Legend, do not. In this article, I am showing a way to choose a hierarchy level dynamically.

Creating the hierarchy table

For education purposes, I am going to use a simplistic data model:

Sales and Product tables

These tables have been imported from the AdventureWorksDW2014 database.

We are not going to create Power BI hierarchies — instead, we are going to imitate them, so that we can choose the desired hierarchy level with a slicer.

First, we need to create a new calculated table — ‘Product Hierarchy’:

Product Hierarchy = 
UNION (
    SELECTCOLUMNS (
        'Product',
        "ProductKey", 'Product'[ProductKey],
        "Name", 'Product'[Product],
        "Level", "Product",
        "LevelNumber", 1
    ),
    SELECTCOLUMNS (
        'Product',
        "ProductKey", 'Product'[ProductKey],
        "Name", 'Product'[Subcategory],
        "Level", "Subcategory",
        "LevelNumber", 2
    ),
    SELECTCOLUMNS (
        'Product',
        "ProductKey", 'Product'[ProductKey],
        "Name", 'Product'[Category],
        "Level", "Category",
        "LevelNumber", 3
    )
)

In this calculated table, we are duplicating portions of the ‘Product’ table and creating two new columns: Level and LevelNumber. The former is used to navigate within the product hierarchy; the latter is a sorting column for the former.

Next, we need to relate this table to the ‘Product’ table and set Cross Filter Direction to Both:

Cross Filter Direction should be set to Both

At this stage, we can already choose the hierarchy level dynamically.

Usage examples

We can use the Name column as a categorical field in a visual and the Level column as a slicer: Hierarchy level selected dynamically

This may not be particularly exciting, because you can achieve the same effect by creating a standard hierarchy.

However, you can also use the Name column in a legend, and Power BI does not support the usage of hierarchies as legend by default.Area level selected dynamically

In addition to this, you can use the Name column in a table or matrix visual.

Showing only one level at a time

Unless we make a selection in the Level slicer, we are going to see all hierarchy levels at once. This can be confusing to a user. We can create a measure that checks whether a level has been selected, and if not, then it chooses the default level. In this example, we show Category by default:

Safe Sales = 
IF (
    CALCULATE (
        HASONEVALUE ( 'Product Hierarchy'[Level] ),
        ALL ( 'Product Hierarchy'[Name] )
    ),
    [Sales Amount],
    CALCULATE (
        [Sales Amount],
        'Product Hierarchy'[Level] = "Category"
    )
)

Note that we have to remove any filters on the Name column when we check whether only one Level has been selected. This is because if we use Name as category, then it becomes part of filter context, and one Name has only one Level (the reverse is not true of course).

Performance considerations

It is important to understand that bidirectional filtering can be costly with large dimensions, especially since in this solution, we are effectively duplicating our ‘Product’ table.

One possible optimization is to reduce the number of rows to only those that we absolutely need. In the Adventure Works database, the ‘Product’ table has 606 rows, which results in ‘Product Hierarchy’ having 1,818 rows. We can filter the table so it only contains those product keys that appear in the Sales table:

Product Hierarchy =
VAR ProductHierarchy =
    UNION (
        SELECTCOLUMNS (
            'Product',
            "ProductKey", 'Product'[ProductKey],
            "Name", 'Product'[Product],
            "Level", "Product",
            "LevelNumber", 1
        ),
        SELECTCOLUMNS (
            'Product',
            "ProductKey", 'Product'[ProductKey],
            "Name", 'Product'[Subcategory],
            "Level", "Subcategory",
            "LevelNumber", 2
        ),
        SELECTCOLUMNS (
            'Product',
            "ProductKey", 'Product'[ProductKey],
            "Name", 'Product'[Category],
            "Level", "Category",
            "LevelNumber", 3
        )
    )
RETURN
    FILTER (
        ProductHierarchy,
        [ProductKey] IN VALUES ( Sales[ProductKey] )
    )

In case of Adventure Works, this results in a table with 474 rows, which is even smaller than the Product table. As always, the optimization technique that you need to choose depends on your particular data model.

Download sample file: Dynamic Hierarchy.pbix

  • Hi Daniil,

    that’s a very smart idea. Thanks for sharing 🙂

    Cheers,
    Lars

  • Igor George Abdo

    Congratulations about this. It’s perfect.
    I’ve a question.
    If I want use Measures, can be?
    For exemple.
    1 – Sales Amount
    2 – Sales Qty

    Is it possible?

    • Igor, do you want to show different measures based on slicer selection?

      If yes, then this can be done with a parameter table.

      Unfortunately, they will all have the same formatting, unless you format the results explicitly (but then they will be just text strings).

      • Igor George Abdo

        Yes.
        For example.
        The user can be show some some measures:
        Imagine a map.
        and when he clicked in measure “Total Sales $”, show the $.
        later, he can clicked in “Qty Sales” and show the Qty.
        I’ll read this that you recommend.

  • 3D Printing Science

    Exactly what I was looking for! thank you very much 🙂

  • Brian

    Hi Daniil, what about products having blank subcategories? Visual bars do not seem to have a blank group?

    • Brian, in this particular example it just so happens that products with blank subcategories have no sales. In another dataset, where this is not the case, blank subcategories will be grouped into a single (Blank) subcategory.

      • Brian

        Thanks for your reply, Daniil. That makes sense.
        I just realised that the dynamic hierarchy function can be achieved without DAX from Product Hierarchy 2-way table setup to Product table. To achieve the same results, we can use drag “Subcategory” and drop it on “Category”, and there you have a Category Hierarchy created by Power BI desktop, then drag “Product” and drop it on the created hierarchy. This 3-level hierarchy can then be used to dropped in Axis field of a bar chart. https://uploads.disquscdn.com/images/0c9e2d2f621dbeff53368feb7b4a62fbd8159cb5bb5a81c847a21260f89e0951.jpg
        Unlike switching Product, Subcategory and Category, dynamic hierarchy is achieved by clicking drill down from top left corner of the bar chart. https://uploads.disquscdn.com/images/ac9e08c248b34e60f94c7a5de0e0963e9d2c671aff312d8beaf23582aeb45512.jpg

        • Brian, thanks for your comment. You are right, and this is exactly what I meant when I wrote the following in the article:

          This may not be particularly exciting, because you can achieve the same effect by creating a standard hierarchy.

          The real value of this technique is realized when you cannot use standard hierarchies — in the Legend field well, for example (also covered in the article).

          • Brian

            True. Your legend field dynamic hierarchy slicer idea is very intuitive and well designed. Thanks for your brilliant idea!

          • Tarek Salha

            this comment might be late, but it becomes very valuable in the case, if you want multiple visuals in the page to change level synchronously. This is still not possible with out-of-the-box means in Power BI.

      • Nadeem

        Hi Daniil, Is there a way to drill down /up any visual based on slicer selection. Hierarchy will be from year to month to week to days. Any suggestions will help

  • beatriz sierra

    https://uploads.disquscdn.com/images/85251440b917c8a20252251ef420a37faf460edb1c3f4d01f6fa6a85f712f6c4.png

    How can I do that one? it would be amazing to know a bit more detailed. thank you!

    • Hi, Beatriz, have you downloaded the sample file? Which part specifically are you struggling with?

      While the graph from your screenshot is not in the file, the principle is the same: you use the Level field in a slicer, and you use the Name field in the visual legend.

      • beatriz sierra

        Hi Danii, I have already a table of data at Region, Area, and Account (several by Area) levels, with sales values.
        I would like to see the legend at the 3 different levels (total Region => Split by area => split by Account)

        So I am not sure how to use the Column Name slicer that you name here to see the legends at 3 different levels (like in your graph)

        Thank you!!

  • Nadeem

    Hi Daniil, Is there a way to drill down /up any visual based on slicer selection. Hierarchy will be from year to month to week to days. Any suggestions will help.