Making a Bar Chart Race Plot using Plotly — made easy | by Luis Chaves | Towards Data Science

Have you ever seen these racing bar plots for ranking things or people over time? They are getting popular, they are fun to look at and they enable seeing who or what has topped a certain ranking over time. You might have seen the ranking of countries by COVID19 cases in 2020, or the ranking of the richest people from Rockefeller to Jeff Bezos. Whatever sort of ranking you are into, today you will learn how to make a racing plot of your own using Python and Plotly! — package provided too :)
Acknowledgments
Amanda Iglesias Moreno wrote a Medium post in 2017 on making a Bar chart race plot with the top baby names in Barcelona. I learned quite a bit from that post, my intention in this article is to use what I have learned from her post and other resources to make code that can be used for any specific use case.
This Plotly tutorial offers all the code to make an animated Gapminder scatterplot. While the example is very rich, little to no code is explained. I am writing this post to help others understand what all the Plotly arguments mean. When I use “weird” Plotly arguments I will explain what they do in simple terms in the code comments.
If you are not interested in seeing the inside of how to make this kind of plot, I’ve written a package for you to plot your own data hassle-free. Simply install the following package using pip
pip install raceplotly
And then run the following in a python script:
And you will obtain the timeline of the top 10 most-produced crops between 1961 and 2018 (see below). I obtained the data from the Food and Agriculture Organisation (FAO).
Please submit issues to the raceplotly repository if you find any or PRs if you want to offer improvements!
To those of you that are left here, thank you. I will try to be as succinct as possible in making you understand how to build one of these plots and go beyond.
Many new Plotly users first come across the plotly.express library. In this library, the Plotly developers have removed the complexity of Plotly figures to make it more user-friendly. Though whenever one wants to go beyond the plotly.express capacities it becomes necessary to see what is happening under the hood.
The first thing to know is that all Plotly figures contain 3 main elements: data, layout, and frames.
The data element is a python list containing information about the kind of plot you want to make: scatter plot, bar plot, funnel plot, heatmap, choropleth... and the relevant arguments for such plot: x, y, z, color, size...
The layout element is a python dictionary containing information about how the plot looks like, i.e. properties of the figure(title, size, legend, background-color...), properties of the axis (title, color, ticks...), and about the interactive properties of the figure (buttons, sliders, what and where to display when the user clicks or hovers over the figure). Additionally, many arguments are present to tweak every single kind of graph (specific to bar plots, specific to funnel plots...).
The frames element allow the user to make animated plots. frames is a python list containing each frame to be rendered in sequential order.
If you want more detail please refer to the official Plotly fundamentals guide about their Figure Data Structure and/or the documentation for the core Plotly Figure.
As with many other plotting libraries, Plotly offers a vast range of arguments to modify a plot. While this is useful when you wish to perfect a plot, it can also be overwhelming, especially when getting started or prototyping. Let’s now explore how to write a Plotly figure in python to generate a race bar plot like the one above.
As mentioned in Plotly Fundamentals, in python a Plotly figure can be a dictionary or a plotly.graph_objects.Figure instance. I personally do not prefer one over the other, I like creating an instance first but then access. We will be creating the Plotly figure element by element, first data then layout, and then frames, though of course, you could do this all in one block.
We will first load our data (the one I downloaded from FAO):
Note: If you are using a custom dataset, make sure it has 3 columns: one corresponding to the items you are ranking (Item in this tutorial), one corresponding to the value by which you are ranking (Value in this tutorial), and another corresponding to the year or date of each corresponding item-value pair (Year in this tutorial)
Now let’s instantiate our figure:
import plotly.graph_objects as gofig = {    "data": [],    "layout": {},    "frames": []}
Next, let’s define the data element. As we said before this must be a python list that contains the kind of plot we wish to make (in this case a bar plot) and the corresponding columns of our data frame corresponding to each axis. In our case we are building an animation and the data we select for the default figure will correspond to the data slice shown before the animation starts. Here I have chosen to make the default frame the one with the earliest available data (from 1961).
We also need one color per item we are ranking. Amanda Iglesias Moreno in her 2017 post, writes a function to assign an RGB triplet to each category. Using list comprehensions we can do this in one line (see code below).
Note: To see what’s possible with texttemplate refer to Plotly docs
Now let’s move on to populate the layout. My default choice here was to use a white background with no axis info in the y-axis (corresponding to the item names), given we are already displaying that information with text annotations. Additionally, I decided to show the x-axis ticks and their corresponding values and to set the x-axis to a fixed value (equal to the maximum ever value in the table).
Because we are creating an animated plot we must include two extra entries in our layout: update buttons (Play and Pause) and a slider. We will leave the slider empty for now as we will populate a slider dictionary when we create the frames. Plotly offers a layout property called updatemenus which allows us to create buttons, drop-down menus, update the layout, and control animations.
Note: The transition duration corresponds to how long the frame transition takes. Low values will make the transitions very snappy, like switching pictures whereas longer values will make it more like a video. The frame duration controls how long each frame is displayed.
Finally, we will create the frames corresponding to the top 10 for each year. In this step, we also populate the sliders property of the layout. This is done in this way so that each frame is linked to a position in the slider. First, we initialize a dictionary with the sliders meta-information and an empty stepslist:
Next, we make the frames and generate the steps:
Finally, and after all this hard work you can simply run go.Figure(fig) to display your hard-earned figure.
We need a whole lot of code to generate a Bar Chart Race plot. Moving that code around is painful, I encourage you to use raceplotly if you plan to use this often!
One thing I should point out is that our bars do not slide past each other when overtaking one another. I have not been able to implement this with Plotly, Ted Petrou managed to do so using matplotlib so check him out!
If you have made it this far, I hope you’ve found this useful. If you have any specific issue with your own plot feel free to get in touch.
PS: I must point you at the Flourish app for code-free happiness