Awesome Plotly with code series (Part 5): The order in bar charts matters
And it is not always simply ordering by highest to lowest
Welcome to the fifth post in my “Plotly with code” series! If you missed the first one, you can check it out in the link below, or browse through my “one post to rule them all” to follow along with the entire series or other topics I have previously written about.
A short summary on why am I writing this series
My go-to tool for creating visualisations is Plotly. It’s incredibly intuitive, from layering traces to adding interactivity. However, whilst Plotly excels at functionality, it doesn’t come with a “data journalism” template that offers polished charts right out of the box.
That’s where this series comes in — I’ll be sharing how to transform Plotly’s charts into sleek, professional-grade charts that meet data journalism standards.
Intro - Rethinking bar chart order: when size isn’t the story
The general rule of thumb for visualising bar charts is: plot the bars in ascending (or descending) order in relation to the y-axis. This should probably be no surprise to you. Just to state this basic point, check the 2 bar charts below. The left one is ordered alphabetically with regards to the x-axis, whilst the right one is following a descending order based on the y-axis. Which one do you prefer?
My answer would be: it depends:
If your story wants to focus on highlighting the highest or lowest bars, then the one of the right would be a great ordering choice.
But, what if the x-axis had a certain meaning? What if you wanted to keep that ordering? How can we deal with differentiating (or not) these non-sorted y-axis categories?
What will we cover in this blog?
Scenario 1: Reordering a specific category (or bar) to prioritise it visually
Scenario 2: Using logical ordering for ordinal data
Scenario 3: Displaying a distribution
Scenario 4: Sorting by multiple categories for more layered insights
As always, code and links to my GitHub repository will be provided along the way. Let’s get started!
Scenario 1: The “Other” category - where should it belong?
Imagine you are a teacher and are scoring which animals are the most popular across the school year. You might gather information like the dataframe below. The dataframe is ordered from highest to lowest. You detect that the “other” category accounts for the 3rd highest percentage, so you wonder what is the best option to present this data?
1st attempt: single coloured bar chart with a descending order categorisation.
To begin things, let’s plot the basic output that plotly.express
would show us.
It is a solid starting point, but you are worried of not highlighting the fact that the “other” category is not a real animal category. It is a category that might represent up to 19 animals, so you would rather ensure the reader immediately understands things.
2nd attempt: using colour contrast whilst keeping the same ordering
In my previous Awesome Plotly with code series (Part 2): Colouring bar charts post, we saw how colour contrast can be used to ensure that the brain can easily interpret categories. In this case, even if we kept the ordering, we easily identify this “Other” category. You can see that we have done some other aesthetic changes, but the important bit is that the grey box representing “Other” contrasts with the blue boxes which represent real animals.
However, there is still something nagging at you. “Other” is something that in reality you want to separate as a category.
3rd and final attempt: separating the “other” category
My preferred way to deal with these scenarios is to move the “Other” category to the end of the plot. In other words, keep the animals as a sorting category separate from “Other”. Check the resulting chart below.
Why do I think this plot is better?
Clear separation of the animal vs other category.
Easy to understand which animal is higher than the other by sorting and showing the actual labels. In fact, the labels help to easily compare where the “other” category would have sat amongst the animals.
Reduced clutter by removing y-axis and grid lines.
Y-axis title rotation horizontally allows us to provide more context than a simple “percentage” text title.
Clear message conveyed by title, subtitle.
Tips on how to create this plot
How to force the separation of both animals vs others?
The idea is to create an auxiliary sorting column. For example, we can create a binary flag: if it is an animal then assign a 1, if not a 0. Then, sort first by this binary flag and second by percentage.
df['SortOrder'] = df['Animal'].apply(lambda x: 1 if x == 'Other' else 0)
df = df.sort_values(by=['SortOrder', 'Percentage'], ascending=[True, False]).reset_index(drop=True)
fig = go.Figure(
data=[
go.Bar(
x=df['Animal'],
y=df['Percentage'],
marker_color=[
'lightgrey' if animal == 'Other' else 'darkblue' for animal in df['Animal']
],
text=df['Percentage'].round(1),
textposition='outside'
)
]
)
Scenario 2: Do not override a logical ordinal ordering
Keep reading with a 7-day free trial
Subscribe to Senior Data Science Lead to keep reading this post and get 7 days of free access to the full post archives.