Forum Discussion
DAX to create a Trend line?
- 8 years ago
Hi MarkSL
Just tested it out and the issue is with ALLSELECTED ( 'DateTable'[Date] ). It doesn't work as intended when you filter on a column other that Date, such as Month.
One possible fix is the change in red below.
I have restated your entire code for completeness.
That should work (tested a mock-up model at my end) but let me know if it doesn't
Oh, by the way, there is a "Combine Series" setting for trendlines that determines whether each series gets its own trend line.
Regards,
Owen
Estimated Sales = VAR Known = FILTER ( SELECTCOLUMNS ( CALCULATETABLE ( VALUES ( 'DateTable'[Date] ), ALLSELECTED ('DateTable') ), "Known[X]", 'DateTable'[Date], "Known[Y]", [SalesDaily2] ), AND ( NOT ( ISBLANK ( Known[X] ) ), NOT ( ISBLANK ( Known[Y] ) ) ) ) VAR Count_Items = COUNTROWS ( Known ) VAR Sum_X = SUMX ( Known, Known[X] ) VAR Sum_X2 = SUMX ( Known, Known[X] ^ 2 ) VAR Sum_Y = SUMX ( Known, Known[Y] ) VAR Sum_XY = SUMX ( Known, Known[X] * Known[Y] ) VAR Average_X = AVERAGEX ( Known, Known[X] ) VAR Average_Y = AVERAGEX ( Known, Known[Y] ) VAR Slope = DIVIDE ( Count_Items * Sum_XY - Sum_X * Sum_Y, Count_Items * Sum_X2 - Sum_X ^ 2 ) VAR Intercept = Average_Y - Slope * Average_X RETURN SUMX ( DISTINCT ( 'DateTable'[Date] ), Intercept + Slope * 'DateTable'[Date] )
Ah, I may have spoken to soon of success...
It appears that when I filter on month, to reduce the dataset, my calculated trend does not match the automatic trend. However, if I filter on another field, such as customer, the two lines do still match?? I am very new to DAX and so am not sure why this is happening?
Here is the code for the calculated trend:
Estimated Sales =
VAR Known =
FILTER (
SELECTCOLUMNS (
ALLSELECTED ( 'DateTable'[Date] ),
"Known[X]", 'DateTable'[Date],
"Known[Y]", [SalesDaily2]
),
AND (
NOT ( ISBLANK ( Known[X] ) ),
NOT ( ISBLANK ( Known[Y] ) )
)
)
VAR Count_Items =
COUNTROWS ( Known )
VAR Sum_X =
SUMX ( Known, Known[X] )
VAR Sum_X2 =
SUMX ( Known, Known[X] ^ 2 )
VAR Sum_Y =
SUMX ( Known, Known[Y] )
VAR Sum_XY =
SUMX ( Known, Known[X] * Known[Y] )
VAR Average_X =
AVERAGEX ( Known, Known[X] )
VAR Average_Y =
AVERAGEX ( Known, Known[Y] )
VAR Slope =
DIVIDE (
Count_Items * Sum_XY - Sum_X * Sum_Y,
Count_Items * Sum_X2 - Sum_X ^ 2
)
VAR Intercept =
Average_Y - Slope * Average_X
RETURN
SUMX (
DISTINCT ( 'DateTable'[Date] ),
Intercept + Slope * 'DateTable'[Date]
)
Thanks again.
Hi MarkSL
Just tested it out and the issue is with ALLSELECTED ( 'DateTable'[Date] ). It doesn't work as intended when you filter on a column other that Date, such as Month.
One possible fix is the change in red below.
I have restated your entire code for completeness.
That should work (tested a mock-up model at my end) but let me know if it doesn't
Oh, by the way, there is a "Combine Series" setting for trendlines that determines whether each series gets its own trend line.
Regards,
Owen
Estimated Sales =
VAR Known =
FILTER (
SELECTCOLUMNS (
CALCULATETABLE ( VALUES ( 'DateTable'[Date] ), ALLSELECTED ('DateTable') ),
"Known[X]", 'DateTable'[Date],
"Known[Y]", [SalesDaily2]
),
AND ( NOT ( ISBLANK ( Known[X] ) ), NOT ( ISBLANK ( Known[Y] ) ) )
)
VAR Count_Items =
COUNTROWS ( Known )
VAR Sum_X =
SUMX ( Known, Known[X] )
VAR Sum_X2 =
SUMX ( Known, Known[X] ^ 2 )
VAR Sum_Y =
SUMX ( Known, Known[Y] )
VAR Sum_XY =
SUMX ( Known, Known[X] * Known[Y] )
VAR Average_X =
AVERAGEX ( Known, Known[X] )
VAR Average_Y =
AVERAGEX ( Known, Known[Y] )
VAR Slope =
DIVIDE (
Count_Items * Sum_XY - Sum_X * Sum_Y,
Count_Items * Sum_X2 - Sum_X ^ 2
)
VAR Intercept = Average_Y
- Slope * Average_X
RETURN
SUMX ( DISTINCT ( 'DateTable'[Date] ),
Intercept + Slope * 'DateTable'[Date]
)- Anonymous7 years agoNot applicable
Hi Owen,
Thanks for the fantastic code!
I used your code to create a trend line, it's working great, but only calculates a trend for the entire dataset. I have a list of facilities, and I want the trend line to dynamically update when I select different facilities using a page level filter. I'm trying to change this so it can adapt to visual filters, but not much luck, and hope you might be able to help. Thanks a lot in advane!
Cheers,
Michael
- ECE4 years ago
Advocate II
Hi Owen,
I know this is an old thread, but I found this solution very interesting.However, I am haveing issues changing above code, to account for the X-axis being in text format, for example YearMonth (YYYY-MM).
Any chance you have an idea how to accomplish this?Any help would be highly appreciated,
Espen
- OwenAuger3 years ago
Super User
I'm sorry, this is a very late reply to your reply 😓
If you are dealing with YearMonth as a text column, I would sugget adding a YearMonth index to your Date table and using that instead.
To illustrate in DAX, the formula would be something like:
YearMonth Index = YEAR ( 'Date'[Date] ) * 12 + MONTH ( 'Date'[Date] ) - 1The reason for subtracting one is that the Year or Month can be recovered from the Index using integer division or the modulo operator.
This index increases by one for each month, so can be used in the regression calculation.
Regards,
Owen
- MarkSL8 years ago
Helper V
Hi OwenAuger
Brilliant, thank you very much for looking at this and finding the fix. My calculated trend line now matches that of the automatic trend line when using all filters; Customer & Month.
Thanks also for alerting me to the Combine Series option.
Regards
Mark
- ThomasDay7 years ago
Impactful Individual
Hello OwenAuger, I wonder if I could get a little help here on what surely seems to be an easy situation but confounding me nonetheless.
I'm looking to create a column in one table with the slope of trended metrics from another.
- One table (on the right) is current values of providers and associated metrics which I use for all sorts of things. I'd like to add a column with the slope of the trend for each provider/metric combination. There are ~600 metrics for each of ~4000 hospitals to compute a slope for.
- The other table (on the left) is a table of trend values...of these provider/metric combinations. So it contains the same ~600 metrics over as many as 8 years for the same ~4000 hospitals.
- Each table has a Variable_Name and Provdrno. I want to use the Provdrno AND Variable name from the row in the Right Table to give me the selection of trend values in the LEFT Table. Seems eacy enough
- So I've read what seem to be the relevant posts....and tried a variety of attacks. Here's the one that does seem promising.
TempSlope = VAR RowMetric = SelectedValue(HospMeasures[Variable_Name]) VAR RowProviderID = SelectedValue(HospMeasures[PROVDRNO]) VAR Known = SELECTCOLUMNS ( CALCULATETABLE ( ALL(TR_MeasureTrends), TR_MeasureTrends[PROVDRNO] = RowProviderID , Tr_MeasureTrends[Variable_Name] = RowMetric ), "Known[X]", Tr_MeasureTrends[FY_Trend] , "Known[Y]", Tr_MeasureTrends[Variable_Value] ) VAR Count_Items = COUNTROWS ( Known ) VAR Sum_X = SUMX ( Known, VALUE(Known[X]) ) VAR Sum_X2 = SUMX ( Known, VALUE(Known[X]) ^ 2 ) VAR Sum_Y = SUMX ( Known, Known[Y] ) VAR Sum_XY = SUMX ( Known, VALUE(Known[X]) * Known[Y] ) VAR Average_X = AVERAGEX ( Known, VALUE(Known[X]) ) VAR Average_Y = AVERAGEX ( Known, Known[Y] ) VAR Slope = DIVIDE ( Count_Items * Sum_XY - Sum_X * Sum_Y, Count_Items * Sum_X2 - Sum_X ^ 2 ) RETURN SlopeUnfortunately every row has the same value! ugggg.....It's very mysterious.
I believe the codes does the following
- creates VAR's for the relevant row info (ProvdrNo and Variable_Name)
- Select columns from the trend table where I
- clear all filters at the row level,
- filter for the proper provdrno and variable_name
- select the two columns I need for the slope calculation
- convert the FY_date column to a number as required.
- Do the calcs.
Yet every value is identical. As I thrashed around, the table name only did not yield any values, ALLSELECTED in any form did not yield any values (Yes, that was crazy)....so I'm stumped.
Suggestions? Thank you in advance,
Tom
- OwenAuger7 years ago
Super User
At a glance, I can see two fixes to make:
- There is no need to use SELECTEDVALUE when defining RowMetric and RowProviderID, as you can access the required values by direct column references. This is by virtue of the row context you have when defining a calculated column. If you use SELECTEDVALUE, you will get blank result as there is an "unfiltered" filter context when defining a calculated column.
- The expression CALCULATETABLE ( ALL(TR_MeasureTrends), ... ) will always return all rows of TR_MeasureTrends, effectively ignoring the filter arguments provided to CALCULATETABLE. Get rid of the ALL and this should work as intended.
I am assuming there are not relationships between the two tables by the way (appeared to be the case from the screenshot).
The first few rows of the corrected DAX should look like this:
TempSlope = VAR RowMetric = HospMeasures[Variable_Name] VAR RowProviderID = HospMeasures[PROVDRNO] VAR Known = SELECTCOLUMNS ( CALCULATETABLE ( TR_MeasureTrends, TR_MeasureTrends[PROVDRNO] = RowProviderID , Tr_MeasureTrends[Variable_Name] = RowMetric ), "Known[X]", Tr_MeasureTrends[FY_Trend] , "Known[Y]", Tr_MeasureTrends[Variable_Value] )
...Does that fix the problem?
Regards,
Owen
- matthewtay3 years agoRegular Visitor
Hi,
I've tried your exact code but I can't seem to get it to work. What am I doing wrongly? Please help!
I am plotting a Line and Clustered Column chart with "Sum of 'data'[Workers tested]" as the Column value and a created column "Percentage" = DIVIDE ( 'data'[Abnormal Results], 'data'[Workers tested]) for the Line value.
For the shared axis, I've used 'data'[Date of test].
Trendline =VAR Known =FILTER (SELECTCOLUMNS (CALCULATETABLE ( VALUES ( 'data'[Date of test] ), ALLSELECTED ('data') ),"Known[X]", 'data'[Date of test],"Known[Y]", 'data'[Percentage] >>>for some strange reason I can't use "Percentage" for "Known[Y]"),AND ( NOT ( ISBLANK ( Known[X] ) ), NOT ( ISBLANK ( Known[Y] ) ) ))VAR Count_Items =COUNTROWS ( Known )VAR Sum_X =SUMX ( Known, Known[X] )VAR Sum_X2 =SUMX ( Known, Known[X] ^ 2 )VAR Sum_Y =SUMX ( Known, Known[Y] )VAR Sum_XY =SUMX ( Known, Known[X] * Known[Y] )VAR Average_X =AVERAGEX ( Known, Known[X] )VAR Average_Y =AVERAGEX ( Known, Known[Y] )VAR Slope =DIVIDE (Count_Items * Sum_XY - Sum_X * Sum_Y,Count_Items * Sum_X2 - Sum_X ^ 2)VAR Intercept = Average_Y- Slope * Average_XRETURNSUMX ( DISTINCT ('data'[Date of test] ),Intercept + Slope * 'data'[Date of test])Below is a sample of the data used.
Date of test Workers tested Abnormal Results % Abnormal 1 Jan 2023 100 0 0 1 Jan 2023 50 25 0.5 1 Mar 2023 70 7 0.1 1 Apr 2023 40 20 0.5 - OwenAuger3 years ago
Super User
Hi matthewtay
Thanks for your patience as I have been a bit busy this month!
I have attached a PBIX containing a suggested approach.
- With the LINEST/LINESTX functions now available, I suggest using these rather than the calculation in the post above. For your example, I would use LINESTX.
- To get this to work, you will need Percentage to be a measure. That's why it wasn't appearing in the intellisense options.
Here are the measure definitions in the attached PBIX:
Percentage = DIVIDE ( SUM ( data[Abnormal Results] ), SUM ( data[Workers tested] ) )Trendline = VAR Known = FILTER ( SELECTCOLUMNS ( CALCULATETABLE ( VALUES ( 'data'[Date of test] ), ALLSELECTED ( 'data' ) ), "Known[X]", 'data'[Date of test], "Known[Y]", [Percentage] ), AND ( NOT ( ISBLANK ( Known[X] ) ), NOT ( ISBLANK ( Known[Y] ) ) ) ) -- Regression using LINESTX function rather than explicit calculation VAR Regression = LINESTX ( Known, Known[Y], Known[X] ) VAR Intercept = SELECTCOLUMNS ( Regression, "@Intercept", [Intercept] ) VAR Slope = SELECTCOLUMNS ( Regression, "@Slope", [Slope1] ) RETURN AVERAGEX ( -- Since the Y-values are percentages, it makes more sense to average than to sum DISTINCT ( 'data'[Date of test] ), Intercept + Slope * 'data'[Date of test] )Putting this into a visual similar to what you've described:
Hope this helps! Please post back if needed.
Kind regards
- matthewtay3 years agoRegular Visitor
No worries! Just glad that you're helping!
Unfortunately my company's IT department has yet to push down the latest Power BI app so I don't have the LINESTX function yet 😞
I've noticed that the main difference is that you've not changed the SUMX function to an AVERAGEX for the last line after the "RETURN" function. I've tried to incorporate this to the previous solution you've provided but to no avail, i still don't get a straight trend line.
Percentage of Abnormal Results = DIVIDE( SUM('data'[AbnormalResults]), SUM('data'[WorkersTested]) )Trend line = VAR Known = FILTER ( SELECTCOLUMNS ( CALCULATETABLE ( VALUES ( 'data'[SubmissionDate] ), ALLSELECTED ('data') ), "Known[X]", 'data'[SubmissionDate], "Known[Y]", [Percentage of Abnormal Results] ), AND ( NOT ( ISBLANK ( Known[X] ) ), NOT ( ISBLANK ( Known[Y] ) ) ) ) VAR Count_Items = COUNTROWS ( Known ) VAR Sum_X = SUMX ( Known, Known[X] ) VAR Sum_X2 = SUMX ( Known, Known[X] ^ 2 ) VAR Sum_Y = SUMX ( Known, Known[Y] ) VAR Sum_XY = SUMX ( Known, Known[X] * Known[Y] ) VAR Average_X = AVERAGEX ( Known, Known[X] ) VAR Average_Y = AVERAGEX ( Known, Known[Y] ) VAR Slope = DIVIDE ( Count_Items * Sum_XY - Sum_X * Sum_Y, Count_Items * Sum_X2 - Sum_X ^ 2 ) VAR Intercept = Average_Y - Slope * Average_X RETURN AVERAGEX ( DISTINCT ( 'data'[SubmissionDate] ), Intercept + Slope * 'data'[SubmissionDate] )Unfortunately I'm unable to upload my data as it's my companie's data.
Will be uploading the photo of the graph in a second.