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

Power BI is turning 10! Let’s celebrate together with dataviz contests, interactive sessions, and giveaways. Register now.

Reply
GiFin
Regular Visitor

Cumulative % or to group by percentile?

Hi, I'm going around in circles with this one. I want to group the customers with the lowest ticket volumes into one group, together making 40% of the overall total of ticket submissions. This is one step in what I want to come to, but I am stuck with how to add the lowest %s together until they come to 40% ot total. 
I
Does anyone have any suggestions please? this groupthis group

1 ACCEPTED SOLUTION
MarkLaf
Memorable Member
Memorable Member

I think I got this working, at least with the test data I used. Any time you want a dynamic axis, you must create a new table that adds your dynamic axis values to the ootb values. I set up a helper table, a numeric range parameter for setting the % cutoff (called 'Lowest X'), and a measure to dynamically group customers under the cutoff.

 

Given the below:

 

CustomerTickets:

CustomerTickets SubmittedGroup
C189A
C22B
C332C
C4123B
C532A
C64C
C734A
C824B
C934A
C102B
C112C
C125B
C1354A
C1445B
C1554C

 

I created this helper table with my grouping label ('Lowest X'):

 

 

CustomersDynRollup = 
UNION(
	SUMMARIZE(
		CustomerTickets,
		CustomerTickets[Customer],
		CustomerTickets[Tickets Submitted]
	),
	{
		("Lowest X", -1)
	}
)

 

 

CustomersDynRollup:

CustomerTickets Submitted
C189
C22
C332
C4123
C532
C64
C734
C824
C934
C102
C112
C125
C1354
C1445
C1554
Lowest X-1

 

* Be sure to set [Customer]'s Sort By to [Tickets Submitted]. Otherwise, the grouping will jump around on the pie chart.

 

And before we put the measure together, let's define the numeric range parameter that we'll use to change the target percentile with a slicer (MS doc: https://learn.microsoft.com/en-us/power-bi/transform-model/desktop-what-if😞

i) In Report view, go to Modeling ribbon

ii) Click the New parameter dropdown and then Numeric range

MarkLaf_3-1740619971347.png

Note: field parameters (the options other than numeric) is a preview feature, so your UI may look a little different from the above

iii) Create your numeric range with the following setup (Name: Lowest X, Data type: Decimal number, Minimum: 0, Maximum: 1, Increment: .01, Default: 0.4)

MarkLaf_4-1740619971349.png

iv) Power BI will then automatically create a single column table with the specified values, which you can use in a slicer. Additionally, PBI automatically creates a measure for referencing the selected value if it exists but otherwise using your specified default. If you created the parameter with the above inputs, this measure will be the [Lowest X] that we use in the below measure.

 

And here is the measure.

 

 

Low by Val = 
VAR _running =
GENERATE(
	ALLSELECTED(CustomerTickets),
	ROW(
		"RunningSum", DIVIDE(
			CALCULATE(
				SUM(CustomerTickets[Tickets Submitted]),
				WINDOW( 1, ABS, 0, REL,
					ALLSELECTED(
						CustomerTickets[Customer],
						CustomerTickets[Tickets Submitted]
					),
					ORDERBY(
						CustomerTickets[Tickets Submitted],
						ASC
					)
				),
				REMOVEFILTERS(CustomerTickets)
			),
			CALCULATE(
				SUM(CustomerTickets[Tickets Submitted]),
				ALLSELECTED(CustomerTickets)
			)
		)
	)
)
VAR _rowsAboveThreshold = FILTER(
	_running,
	[RunningSum] > [Lowest X Value]
)
VAR _rowsBelowThreshold = FILTER(
	_running,
	[RunningSum] <= [Lowest X Value]
)
RETURN
CALCULATE(
	SUM(CustomerTickets[Tickets Submitted]),
	_rowsAboveThreshold,
	TREATAS(
		VALUES(CustomersDynRollup[Customer]),
		CustomerTickets[Customer]
	)
)
+ IF(
	"Lowest X" IN VALUES(CustomersDynRollup[Customer]),
	CALCULATE(
		SUM(CustomerTickets[Tickets Submitted]),
		_rowsBelowThreshold
	)
)

 

 

Now for a pie chart, we can put CustomersDynRollup[Customer] in the Legend, and the measure [Low by Val] in the Values. CustomerTickets slicers should work on CustomersDynRollup because of the virtual relationship in the measure. Example next to a CustomerTickets table with some calcs to double-check the measure in the pie chart is working.

 

MarkLaf_0-1739902910155.gif

 

*Edit: included instructions for adding numeric range paramater

View solution in original post

12 REPLIES 12
MarkLaf
Memorable Member
Memorable Member

I think I got this working, at least with the test data I used. Any time you want a dynamic axis, you must create a new table that adds your dynamic axis values to the ootb values. I set up a helper table, a numeric range parameter for setting the % cutoff (called 'Lowest X'), and a measure to dynamically group customers under the cutoff.

 

Given the below:

 

CustomerTickets:

CustomerTickets SubmittedGroup
C189A
C22B
C332C
C4123B
C532A
C64C
C734A
C824B
C934A
C102B
C112C
C125B
C1354A
C1445B
C1554C

 

I created this helper table with my grouping label ('Lowest X'):

 

 

CustomersDynRollup = 
UNION(
	SUMMARIZE(
		CustomerTickets,
		CustomerTickets[Customer],
		CustomerTickets[Tickets Submitted]
	),
	{
		("Lowest X", -1)
	}
)

 

 

CustomersDynRollup:

CustomerTickets Submitted
C189
C22
C332
C4123
C532
C64
C734
C824
C934
C102
C112
C125
C1354
C1445
C1554
Lowest X-1

 

* Be sure to set [Customer]'s Sort By to [Tickets Submitted]. Otherwise, the grouping will jump around on the pie chart.

 

And before we put the measure together, let's define the numeric range parameter that we'll use to change the target percentile with a slicer (MS doc: https://learn.microsoft.com/en-us/power-bi/transform-model/desktop-what-if😞

i) In Report view, go to Modeling ribbon

ii) Click the New parameter dropdown and then Numeric range

MarkLaf_3-1740619971347.png

Note: field parameters (the options other than numeric) is a preview feature, so your UI may look a little different from the above

iii) Create your numeric range with the following setup (Name: Lowest X, Data type: Decimal number, Minimum: 0, Maximum: 1, Increment: .01, Default: 0.4)

MarkLaf_4-1740619971349.png

iv) Power BI will then automatically create a single column table with the specified values, which you can use in a slicer. Additionally, PBI automatically creates a measure for referencing the selected value if it exists but otherwise using your specified default. If you created the parameter with the above inputs, this measure will be the [Lowest X] that we use in the below measure.

 

And here is the measure.

 

 

Low by Val = 
VAR _running =
GENERATE(
	ALLSELECTED(CustomerTickets),
	ROW(
		"RunningSum", DIVIDE(
			CALCULATE(
				SUM(CustomerTickets[Tickets Submitted]),
				WINDOW( 1, ABS, 0, REL,
					ALLSELECTED(
						CustomerTickets[Customer],
						CustomerTickets[Tickets Submitted]
					),
					ORDERBY(
						CustomerTickets[Tickets Submitted],
						ASC
					)
				),
				REMOVEFILTERS(CustomerTickets)
			),
			CALCULATE(
				SUM(CustomerTickets[Tickets Submitted]),
				ALLSELECTED(CustomerTickets)
			)
		)
	)
)
VAR _rowsAboveThreshold = FILTER(
	_running,
	[RunningSum] > [Lowest X Value]
)
VAR _rowsBelowThreshold = FILTER(
	_running,
	[RunningSum] <= [Lowest X Value]
)
RETURN
CALCULATE(
	SUM(CustomerTickets[Tickets Submitted]),
	_rowsAboveThreshold,
	TREATAS(
		VALUES(CustomersDynRollup[Customer]),
		CustomerTickets[Customer]
	)
)
+ IF(
	"Lowest X" IN VALUES(CustomersDynRollup[Customer]),
	CALCULATE(
		SUM(CustomerTickets[Tickets Submitted]),
		_rowsBelowThreshold
	)
)

 

 

Now for a pie chart, we can put CustomersDynRollup[Customer] in the Legend, and the measure [Low by Val] in the Values. CustomerTickets slicers should work on CustomersDynRollup because of the virtual relationship in the measure. Example next to a CustomerTickets table with some calcs to double-check the measure in the pie chart is working.

 

MarkLaf_0-1739902910155.gif

 

*Edit: included instructions for adding numeric range paramater

Hi @MarkLaf  thank you so much! Sorry for the delay in responding, I had access issues. 
This looks amazing and I will try it out - but stupid question first - where do I set 

[Lowest X Value]

I don't get that part

MarkLaf
Memorable Member
Memorable Member

Yes, realizing I sort of skipped over, "I set up a helper table, a numeric range parameter for setting the % cutoff (called 'Lowest X'), and a measure to dynamically group customers under the cutoff." (emphasis added). Numeric range parameters are described here: https://learn.microsoft.com/en-us/power-bi/transform-model/desktop-what-if

 

By way of a quick walkthrough, to add the numeric range parameter:

i) In Report view, go to Modeling ribbon

ii) Click the New parameter dropdown and then Numeric range

MarkLaf_0-1740618154277.png

Note: field parameters (the options other than numeric) is a preview feature, so your UI may look a little different from the above

iii) Create your numeric range with the following setup (Name: Lowest X, Data type: Decimal number, Minimum: 0, Maximum: 1, Increment: .01, Default: 0.4)

MarkLaf_1-1740618459195.png

iv) Power BI will then automatically create a single column table with the specified values, which you can use in a slicer. Additionally, PBI automatically creates a measure for referencing the selected value if it exists but otherwise using your specified default. This measure is the [Lowest X] you were asking about.

MarkLaf_2-1740618953954.png

 

I'll add the above info to my original response so it's more complete.

 

Will take a look at your other response in a bit.

Wow! Thank you @MarkLaf ! Now got this working now on a pie with customer name & amt of tkts with slider 😍. Seems these are separate to the rest of the data though in this new table. My real data set is a lot larger, and want to select this lowest X % in order to analyze it - who are these customers, profiles etc. so I need to keep a relationship with the other data. I made a relationship in the model with cust name but then the slider functionality is lost 😞 Am I being too pushy with this extra bit? Thank you again for what you have shown though - incredibly helpful!

MarkLaf
Memorable Member
Memorable Member

Share what your other tables are related, what those relationships are (eg Customers -1---M-> Some other table), and what behavior you are trying to get vis a vis numeric slider and other visuals. Some dummy data is always helpful, too. We can see what we can do, then.

 

Also, I just noticed in your snip from your other post that you have a relationship set up between CustomersDynRollup and TicketData. The measure I provided is actually written to work without a relationship set up, so you should get rid of that. Perhaps that is causing the issue with the other relationships?

 

MarkLaf_0-1740697709039.png

 

Hi @MarkLaf, thanks again. 
I removed that relationship indeed. I'm sharing another image below. Essentially I would like to click on the lowest X group and see who those customers are. For now in the dummy data tht just means showing the Customer name, no. of tickets, the service they have, type and duration of tickets. 
At the moment when I click on Lowest X is acts like a separate group which I can't look into further. If I put more visuals around it, starting with a table just to see what's selected, it's doesn't seem to keep the customer name assocated with the Lowest X group as per the pie chart. I hope the image shows better what I mean. 
I don't see a way to share the file or the data here, is that possible? dyngrp2.png

MarkLaf
Memorable Member
Memorable Member

As mentioned previously, we are leveraging virtual relationships to control how the visuals behave, so if we want visual filtering to go in the other direction, we have to put together a different measure to enforce it.

 

 

Lowest X Filter = 
CALCULATE( 
    IF( NOT ISEMPTY( CustomersDynRollup ), 0 ), 
    TREATAS( VALUES( CustomerTickets[Customer] ), CustomersDynRollup[Customer] ), 
    VALUES( CustomersDynRollup[Customer] ) 
)
+ 
IF( 
    "Lowest X" IN VALUES( CustomersDynRollup[Customer] ), 
    VAR custSet =  CALCULATETABLE( 
        ALLSELECTED( CustomerTickets ), 
        ALL( CustomerTickets[Customer], CustomerTickets[Tickets Submitted] ) 
    )
    VAR running = CALCULATE( 
        SUM( CustomerTickets[Tickets Submitted] ), 
        WINDOW( 1, ABS, 0, REL, custSet, ORDERBY( CustomerTickets[Tickets Submitted], ASC ) ), 
        REMOVEFILTERS( CustomerTickets ) 
    ) 
    VAR perct = DIVIDE( 
        [Running Total], 
        CALCULATE( SUM( CustomerTickets[Tickets Submitted] ), custSet ) 
    )
    RETURN
    IF( NOT ISBLANK( perct ) && perct <= [Lowest X Value], 0 )
)

 

 

Put this in the filter pane of your table visual (no need to add in the Columns well) and then set the filter to 'is not blank'

MarkLaf_0-1740854575338.png

 

Output:

MarkLaf_1-1740854789262.gif

 

 

 

 

Also, perhaps too belatedly, I do want to point to a much simpler but more static approach to all of this. If you only need to group by 40% and don't expect to need to slice customers in any way (eg. where "Lowest 40%" has a different meaning when it's out of all customers vs out of all customers within some group you are slicing on), then you simply hard-code this logic into your original table. You'll need two columns: 1) either provide customer name or put under some "lowest label", 2) provide the sort values to ensure that the "lowest label" always stays at end of a visual when sorted by the "lowest label" column

 

The DAX for these two calculated columns would be:

 

 

Lowest 40% Group = 
VAR run = CALCULATE( 
    SUM( CustomerTickets[Tickets Submitted] ), 
    WINDOW( 1, ABS, 0, REL, ORDERBY( CustomerTickets[Tickets Submitted], ASC ) ), 
    REMOVEFILTERS( CustomerTickets ) 
)
VAR perc = DIVIDE( 
    run, 
    CALCULATE( SUM( CustomerTickets[Tickets Submitted] ), ALL( CustomerTickets ) ) 
)
RETURN
IF( perc <= .4, "Lowest 40%", CustomerTickets[Customer] )


Lowest 40% Group Sort = 
VAR run = CALCULATE( 
    SUM( CustomerTickets[Tickets Submitted] ), 
    WINDOW( 1, ABS, 0, REL, ORDERBY( CustomerTickets[Tickets Submitted], ASC ) ), 
    REMOVEFILTERS( CustomerTickets ) 
)
VAR perc = DIVIDE( 
    run, 
    CALCULATE( SUM( CustomerTickets[Tickets Submitted] ), ALL( CustomerTickets ) ) 
)
RETURN
IF( perc <= .4, -1, CustomerTickets[Tickets Submitted] )

 

 

Then, all you need to do is set the Sort By of [Lowest 40% Group] to [Lowest 40% Group Sort]. You can then drop the calculated column into your pie chart with your ticket aggregation (sort by calculated column, not agg), and drop your vanilla customer column and ticket agg into a table:

 

MarkLaf_2-1740855861573.gif

 

By way of a quick breakdown on these two approaches:

 

Calculated ColumnsHelper Table + Virtual Relationship

+ Very simple

 

+ "Just works" with other data in your customer table

 

- Static cumulative threshold

 

- Static "lowest label" assignment - does not recalculate based on slicers

+ Allows for dynamic cumulative % grouping

 

+ Handles dynamic calculation of cumulative % so slicers on other Customer columns work

 

- Complex compared to other approach

 

- Requires defining new virtual relationships to handle any visual interactions

 

Hi @MarkLaf  you've gone far above and beyond what I was expecting by way of help here. Hopefully this also helps others, no doubt it will. 
THANK YOU!!!

GiFin
Regular Visitor

Here is a view on what I'm working with:diff partsdiff parts

dyngrp.png

GiFin
Regular Visitor

Thank you @Rupak_bi for this! I am getting somewhere now but not there yet. I need to add the %TicketCount field of the lowest volume customers until that comes to 40% of the grand total of the ticket volume submitted by the customers in the selection - so this would be dynamic because it may change depending on which customers are selected. So I'm not sure if a calculated column would be the way to go? But I now have rank thanks to you, so I am a bit further. I will try to adjust to add the % vol (%TicketCount) instead of Count of Ticket Number. Will come back. 

Rupak_bi
Impactful Individual
Impactful Individual

Hi @GiFin 

Then you need to do the same thing in a measure. But that will be a bit tricky as your axis will be dynamic. Please share good amount of sample data with desired output so that it can be worked out



Regards
Rupak
FOLLOW ME : https://www.linkedin.com/in/rupaksar/
Rupak_bi
Impactful Individual
Impactful Individual

Hi @GiFin ,

Follow below steps,

1. Create a calculated column (index) to rank the nos. of tickets smallest to largest. RANKX(table,ticket,Asc,Dens)

2. Create another column (running total)to get running total of the tickets based on the index. calculate(sum(tickets),all(table),index<=earlier (index))

3. create another column to make new axis based on 40%
new axis = 

var other_category = calculate(sum(tickets),all(table))*40%
return

if(running total<other_category,"Other category),customer)

4 . now use this new axis in the chart.

 

please accept this as solution if this works, else, share sample data in plain text to workout.



Regards
Rupak
FOLLOW ME : https://www.linkedin.com/in/rupaksar/

Helpful resources

Announcements
June 2025 Power BI Update Carousel

Power BI Monthly Update - June 2025

Check out the June 2025 Power BI update to learn about new features.

June 2025 community update carousel

Fabric Community Update - June 2025

Find out what's new and trending in the Fabric community.