This week’s #WoW2020 challenge was set by Meera Umasankar who once again was tackling the concept of ‘run rate’, but this time with an added twist – only consider the working days (ie the typical Mon-Fri weekdays), rather than every day in the month, the assumption being, this ‘business’ does not trade on weekends. Following on from last week’s challenge, Meera also chose to include a bit of blending to combine actual orders against the plan/target. For this Meera provided a custom dataset which just included a sheet of Actuals by Region for each day in April 2020 up to 23rd April, and Plan by Region for the whole month of April.
As per usual I started by putting together a table of data with the core numbers I was going to need per region : MTD value, Run Rate value, Plan value.
Building the key data fields
Whilst Meera had provided data just for April up to April 23rd, I decided to build this in a way as if the data could change.
This stores the maximum date from the Actuals data source – ie 23 April 2020.
Current Month Only
[Date]>=DATETRUNC(‘month’, [Today]) AND [Date] <= [Today]
When true, this will just consider the records in the Actuals data source that are dated between 1st April & 23 April. As it happens, due to the data provided, this will be everything, but in a typical business situation, you’re actuals would probably contain previous months data too.
IF [Current Month Only] THEN [Sales] END
Only stores the sales for the month we want to report on.
To get the plan we need to blend to the Plan data source. As the data in the Actual data source is per day, and the Plan is per month, we need to blend the data at the month level. Whilst this can be set in other ways, I like to be explicit when using blending, so in my Actuals data source I created
BLEND – Date
This stores the 1st day of the month (1st April 2020) against every row of data.
In the Plan data I created a similar field, which is just essentially a duplicate field of the existing Date field, but by having the same name, it allows the blend joins to be automatically picked up.
Blend – Date
Ok, let’s get these 2 measures on a table, to sense check we have the right figures so far :
- Add Region to Rows (from the Actuals data)
- Add MTD to Text
- Add Plan to Text (from the Plan data)
- Ensure the blend join links on both Region and BLEND – Date are clicked (due to the minimal data we have, the blend on Region only will work, but it’s good practice to include the date blend too if the Plan data contained different months).
- Apply formatting as required to the MTD & Plan numbers
Calculating the Run Rate
Meera defines the Run Rate as being the value of Sales expected to be received in the whole month (the end of month position/forecast), based on the rate of sales so far in the month. So we’re looking to work out average sales made per day, then extrapolate that across the number of days in the month.
However, the twist in this challenge, is to only give consideration to the number of weekdays (ie working days).
As with many things, I chose to use my best friend ‘Google’ to see if it would throw up anything that may help this requirement, and it did, very quickly. There is an existing Tableau KB article that describes exactly how to work out the number of weekdays between 2 dates. You can find it here.
To work out the Run Rate I need
- to work out the average Sales per weekday so far
- multiply that by number of weekdays in the month
So I need to work out the number of working days between 1st April and 23rd April, and also the number of working days between 1st April & 30th April. I need a fair few calculated fields for all this, which I’ll build up rather than combine altogether.
Start of Current Month
simply truncates to 1st of month.
End of Current Month
DATEADD(‘day’, -1, DATEADD(‘month’, 1, [Start of Current Month]))
Adds 1 month onto start of month, then takes off 1 day to get the last day in the month
Following the steps in the article, I need to adjust these dates if they happen to fall on a weekend.
Start of Current Month (shift to weekday)
IF DATEPART(‘weekday’, [Start of Current Month]) = 1
THEN DATEADD(‘day’, 1, [Start of Current Month])
ELSEIF DATEPART(‘weekday’, [Start of Current Month]) = 7
THEN DATEADD(‘day’, 2, [Start of Current Month])
ELSE [Start of Current Month]
If the Start of Current Month lands on a Saturday or a Sunday, the start is shifted forward to the following Monday.
End of Current Month (shift to weekday)
IF DATEPART(‘weekday’, [End of Current Month]) = 1
THEN DATEADD(‘day’, -2, [End of Current Month])
ELSEIF DATEPART(‘weekday’, [End of Current Month]) = 7
THEN DATEADD(‘day’, -1, [End of Current Month])
ELSE [End of Current Month]
If the End of Current Month lands on a Saturday or Sunday, the end is shifted back to the previous Friday.
#Weekdays in Month
(DATEDIFF(‘day’, [Start of Current Month (shift to weekday)], [End of Current Month (shift to weekday)]) + 1) – (2 * DATEDIFF(‘week’, [Start of Current Month (shift to weekday)], [End of Current Month (shift to weekday)])))
This is working out the number of days between the adjusted start & end dates, then adding 1 to this number. It then works out the number of weeks between the adjusted start & end dates, multiples by 2 (since in every week there are 2 weekend days), and then this number is subtracted from the first.
We then need to repeat this to work out the working days from start to today.
Today (shift to weekday)
IF DATEPART(‘weekday’, [Today]) = 1
THEN DATEADD(‘day’, -2, [Today])
ELSEIF DATEPART(‘weekday’, [Today]) = 7
THEN DATEADD(‘day’, -1, [Today])
This is our end date, so the date is once again shifted back to the previous Friday if it happens to be a Saturday or Sunday.
# Weekdays from start to Today
(DATEDIFF(‘day’, [Start of Current Month (shift to weekday)], [Today (shift to weekday)])+ 1) – (2 * DATEDIFF(‘week’, [Start of Current Month (shift to weekday)], [Today (shift to weekday)])))
Now we have these values, we can work out
(SUM([MTD])/[# Weekdays from Start to Today]) * [# Weekdays in Month]
Format this and add to check table
Building the chart
The left hand side of the chart is all text, but to present it as required, we need a fake axis.
- From the Actuals data source, add Region to Rows
- In the Columns shelf type in MIN(0) to create the fake axis.
- Change the Mark Type to Text
- Add Region, MTD, Run Rate from the Actuals data source to Text shelf
- Add Plan from the Plan data source to the Text shelf (don’t forget to check the blend links)
- Make each row bigger if everything all seems a bit squashed.
We’ll come back to formatting these fields later. Let’s now get the bar displayed & target displayed. This is a dual axis combining a bar and a gantt chart. Add to the chart as follows
- Add Run Rate to Columns
- Change the Mark Type of this measure to Bar
- Remove all fields apart from Run Rate from the Label shelf of this card
- Change Alignment of the Label to be left aligned
- Add Plan to Columns (check the blend links)
- Change Mark Type to be Gantt and remove fields from Label shelf of this card
- Set to Dual Axis and Synchronise Axis.
- Remove Measure Names from Colour shelf of the Bar and Gantt marks cards
- Change Colour of the Gantt Bar (Plan) to black and add a black border to make it a bit thicker
- Turn off Tooltips on All marks cards.
Indicating if Plan isn’t going to be met
The bar chart should be red if the Run Rate is less than Plan. The Run Rate on the Text side should also be displayed in red too if it doesn’t meet and black otherwise. We’re going to need some additional fields for this.
Run Rate < Plan
[Run Rate] < SUM([Plan (2020_04_22_WW17_Sales Projection)].[Plan])
Add this to the Colour shelf on the Bar marks card, and adjust the True/False colours accordingly
We can’t conditionally format an individual field in a Text display, so we need to create 2 further instances of the Run Rate field, where only one will ever display.
Run Rate < Plan (red)
If [Run Rate < Plan] THEN [Run Rate] END
Run Rate > Plan (black)
If NOT([Run Rate < Plan]) THEN [Run Rate] END
Format these accordingly, then add to the Text shelf of the Text marks card. Remove the original Run Rate field. You should still only have 1 run rate value displayed per row.
Now we can tidy up the display of this text. Ensure the Run Rate < Plan (red) and Run Rate > Plan (black) fields are on the same line of text with no spaces between, then colour the fonts to match the requirements
Finally, remove axis/row headers, tidy up gridlines etc, and adjust the width of the bars to suit.
As the title needs to include the date, and to ensure it would be dynamic, I created a simple text sheet to display the title, and set the worksheet background to a light grey.
I then added both sheets to a dashboard, with both set to ‘Fit Entire View’, and titles hidden.
To get the Phone Layout display, I then selected the Phone option, clicked the padlock to Edit layout, and set to Fit all, and made adjustments to suit. The issue you might have though is that while things all look a bit squashed on your laptop display, it actually will render ok when published. This can unfortunately be a bit of trial & error.
My published viz is here.
Happy vizzin’ and stay safe!