DP22 - Using Beast Mode to Build Data Storytelling - Formatting Text
This post is part of a series of beast modes I presented on during my “Using Beast Mode to Build Data Storytelling” Domopalooza 2022 session. If you find this post helpful please make sure to give it a like or an awesome below.
Use Case:
We wanted a way to allow our users to quickly visualize good or bad data results. To do this we would conditionally set the different values in an HTML table to different colors depending on the different conditions we defined.
Beast Modes:
Custom Color Definition
CONCAT('<span style="color: ', CASE WHEN MOD(FLOOR(SUM(`Daily Sales`)), 2) = 0 THEN 'green' ELSE 'red' END, '">', FLOOR(SUM(`Daily Sales`)), '</span>’)
Formatting Numbers with Commas
CONCAT('<span style="color: ', CASE WHEN MOD(FLOOR(SUM(`Daily Sales`)), 2) = 0 THEN 'green' ELSE 'red' END, '">$', CASE WHEN SUM(`Daily Sales`) < 0 THEN '-' ELSE '' END, CASE WHEN ABS(SUM(`Daily Sales`)) > 100000000000 THEN CONCAT( SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 1, 3), ',', SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 4, 3), ',', SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 7, 3), ',', SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 10, 3) ) WHEN ABS(SUM(`Daily Sales`)) >= 10000000000 THEN CONCAT( SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 1, 2), ',', SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 3, 3), ',', SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 6, 3), ',', SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 9, 3) ) WHEN ABS(SUM(`Daily Sales`)) >= 1000000000 THEN CONCAT( SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 1, 1), ',', SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 2, 3), ',', SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 5, 3), ',', SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 7, 3) ) WHEN ABS(SUM(`Daily Sales`)) >= 100000000 THEN CONCAT( SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 1, 3), ',', SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 4, 3), ',', SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 7, 3) ) WHEN ABS(SUM(`Daily Sales`)) >= 10000000 THEN CONCAT( SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 1, 2), ',', SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 3, 3), ',', SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 6, 3) ) WHEN ABS(SUM(`Daily Sales`)) >= 1000000 THEN CONCAT( SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 1, 1), ',', SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 2, 3), ',', SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 5, 3) ) WHEN ABS(SUM(`Daily Sales`)) >= 100000 THEN CONCAT( SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 1, 3), ',', SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 4, 3) ) WHEN ABS(SUM(`Daily Sales`)) >= 10000 THEN CONCAT( SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 1, 2), ',', SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 3, 3) ) WHEN ABS(SUM(`Daily Sales`)) >= 1000 THEN CONCAT( SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 1, 1), ',', SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 2, 3) ) WHEN ABS(SUM(`Daily Sales`)) < 1000 THEN ROUND(SUM(`Daily Sales`), 0) ELSE 'Unsupported number length' END, '</span>')
Formatting Abbreviated Number
CONCAT('<div style="color: ', CASE WHEN MOD(FLOOR(SUM(`Daily Sales`)), 2) = 0 THEN 'green' ELSE 'red' END, '">$', CASE WHEN ABS(`Daily Sales`) >= 1000000000 THEN CONCAT(ROUND(SUM(`Daily Sales`) / 1000000000, 2), 'B') -- 7 digits means Millions WHEN ABS(`Daily Sales`) >= 1000000 THEN CONCAT(ROUND(SUM(`Daily Sales`) / 1000000, 2), 'M') -- 4-6 digits = thousands WHEN ABS(`Daily Sales`) >= 1000 THEN CONCAT(ROUND(SUM(`Daily Sales`) / 1000, 2), 'K') WHEN ABS(`Daily Sales`) < 1000 THEN ROUND(SUM(`Daily Sales`), 0) END, '</div>')
Beast Mode Breakdown:
Custom Color Definition
<span style="color: ' … >Text To Color</span>
Here we utilize some HTML code to define a container to put the text we want to color into. The HTML code specifies a style to define which color we wish to utilize
CASE WHEN MOD(FLOOR(SUM(`Daily Sales`)), 2) = 0 THEN 'green' ELSE 'red' END
This is where we defined the conditions used to color the different text. In this case it’s checking to see if the daily sales is even, if it is make the color green otherwise make the color red however you can put whatever logic you wish here. Hexadecimal codes are also allowed as color values.
FLOOR(SUM(`Daily Sales`))
The value wrapped in between the <span></span> tags is what will be colored.
Formatting Numbers with Commas
CONCAT('<span style="color: ', CASE WHEN MOD(FLOOR(SUM(`Daily Sales`)), 2) = 0 THEN 'green' ELSE 'red' END, '">$', CASE WHEN SUM(`Daily Sales`) < 0 THEN '-' ELSE '' END, CASE WHEN ABS(SUM(`Daily Sales`)) > 100000000000 THEN CONCAT( SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 1, 3), ',', SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 4, 3), ',', SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 7, 3), ',', SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 10, 3) ) ... WHEN ABS(SUM(`Daily Sales`)) < 1000 THEN ROUND(SUM(`Daily Sales`), 0) ELSE 'Unsupported number length' END, '</span>')
Here we utilize a CASE statement to determine the value / length of the number we wish to format. Depending on the length it varies the different positions to extract out of the number utilizing the SUBSTRING command and concatenate each section of the string with commas. This example supports numbers up to 999 Billion however it can be expanded for larger numbers.
CASE WHEN SUM(`Daily Sales`) < 0 THEN '-' ELSE '' END
This is handling the negative numbers in order to simplify the beast mode logic so we only need to do one length condition instead of having to deal with positive and negative numbers.
CASE WHEN ABS(SUM(`Daily Sales`)) > 100000000000 THEN CONCAT( SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 1, 3), ',', SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 4, 3), ',', SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 7, 3), ',', SUBSTRING(ROUND(SUM(`Daily Sales`), 0), 10, 3) )
ABS
is used to get the absolute value, again for simplifying the logic of the beast mode.
SUBSTRING
is used to get a substring or piece of the number. In this case we’re getting the first 3 digits since we’re in the hundreds of billions, followed by the 3 digits for the millions, then thousands and hundreds.
The case statements are checking lengths in descending order. This is to simplify the beast mode further because the case statement will evaluate the first true clause and ignore anything after. For example if the number is 10,000 it’s checking for >= 10,000 but also implies < 100,000 because it's evaluated after the >= 100,000 condition.
Formatting Abbreviated Number
CONCAT('<div style="color: ', CASE WHEN MOD(FLOOR(SUM(`Daily Sales`)), 2) = 0 THEN 'green' ELSE 'red' END, '">$', CASE WHEN ABS(`Daily Sales`) >= 1000000000 THEN CONCAT(ROUND(SUM(`Daily Sales`) / 1000000000, 2), 'B') -- 7 digits means Millions WHEN ABS(`Daily Sales`) >= 1000000 THEN CONCAT(ROUND(SUM(`Daily Sales`) / 1000000, 2), 'M') -- 4-6 digits = thousands WHEN ABS(`Daily Sales`) >= 1000 THEN CONCAT(ROUND(SUM(`Daily Sales`) / 1000, 2), 'K') WHEN ABS(`Daily Sales`) < 1000 THEN ROUND(SUM(`Daily Sales`), 0) END, '</div>')
Similar logic here however we are just dividing by the largest possible unit (Billions, Millions, Thousands) in descending order.
ROUND(.. ,2)
rounds our number to two decimal places. This can be changed to 0, 1 or any number of decimal places you need for your use case.
CONCAT
will append our unit of measurement (B, M, K) to the end of the rounded number
Final Result:
**Did this solve your problem? Accept it as a solution!**
Comments
-
In an effort to more simplify the comma delimited version of the beast mode I'm posting an alternative version instead of having to check every single different potential lengths it will automatically calculate the different sections automatically making the beast mode more readable. This version also handles numbers up to the quadrillions (21 digits). It also reduces the original version of the beast mode from roughly 60 lines to about 9 and increases the digits of precision (billions -> quadrillions).
REPLACE(TRIM(CONCAT( SUBSTRING(`Number`, 1, CASE WHEN MOD(LENGTH(`Number`), 3) = 0 then 3 ELSE MOD(LENGTH(`Number`), 3) END), ' ', SUBSTRING(`Number`, 1 + (3*0) + CASE WHEN MOD(LENGTH(`Number`), 3) = 0 then 3 ELSE MOD(LENGTH(`Number`), 3) END, 3), ' ', SUBSTRING(`Number`, 1 + (3*1) + CASE WHEN MOD(LENGTH(`Number`), 3) = 0 then 3 ELSE MOD(LENGTH(`Number`), 3) END, 3), ' ', SUBSTRING(`Number`, 1 + (3*2) + CASE WHEN MOD(LENGTH(`Number`), 3) = 0 then 3 ELSE MOD(LENGTH(`Number`), 3) END, 3), ' '), SUBSTRING(`Number`, 1 + (3*3) + CASE WHEN MOD(LENGTH(`Number`), 3) = 0 then 3 ELSE MOD(LENGTH(`Number`), 3) END, 3), ' '), SUBSTRING(`Number`, 1 + (3*4) + CASE WHEN MOD(LENGTH(`Number`), 3) = 0 then 3 ELSE MOD(LENGTH(`Number`), 3) END, 3), ' '), SUBSTRING(`Number`, 1 + (3*5) + CASE WHEN MOD(LENGTH(`Number`), 3) = 0 then 3 ELSE MOD(LENGTH(`Number`), 3) END, 3), ' ') ), ' ', ',')
This is a simplified version which only handles positive whole numbers but could be expanded to handle negative numbers and decimals.
**Was this post helpful? Click Agree or Like below**
**Did this solve your problem? Accept it as a solution!**1
Categories
- All Categories
- 1.8K Product Ideas
- 1.8K Ideas Exchange
- 1.5K Connect
- 1.2K Connectors
- 300 Workbench
- 6 Cloud Amplifier
- 9 Federated
- 2.9K Transform
- 100 SQL DataFlows
- 620 Datasets
- 2.2K Magic ETL
- 3.9K Visualize
- 2.5K Charting
- 742 Beast Mode
- 58 App Studio
- 41 Variables
- 686 Automate
- 176 Apps
- 453 APIs & Domo Developer
- 47 Workflows
- 10 DomoAI
- 36 Predict
- 15 Jupyter Workspaces
- 21 R & Python Tiles
- 395 Distribute
- 113 Domo Everywhere
- 276 Scheduled Reports
- 6 Software Integrations
- 124 Manage
- 121 Governance & Security
- 8 Domo Community Gallery
- 38 Product Releases
- 10 Domo University
- 5.4K Community Forums
- 40 Getting Started
- 30 Community Member Introductions
- 108 Community Announcements
- 4.8K Archive