How to Create Animate Graphs in Python | Towards Data Science

As data is forever expanding at unprecedented rates, data scientists are called upon to analyse it and make sense of it. Once that happens, there comes the need for effectively communicating the results.
Communicating the results of data analysis, however, can often be tricky. To effectively communicate, a popular and very potent technique is that of storytelling.
Having all the information in the world at our fingertips doesn’t make it easier to communicate: it makes it harder.― Cole Nussbaumer Knaflic
To assist with storytelling and communication, data visualisation is critical. Animated data visualisation takes things up a notch and adds a wow factor.
In this blog, we are going to examine how you can animate your charts. We will learn how to add a new dimension to line plots, bar charts and pie charts. This blog will get you started, but the possibilities are endless.
In typical fashion, as you’ve come to expect from Python, there exists a very easy-to-use package that enables us to add an extra dimension to our data visualisation.
The package in question is the FuncAnimation extension method and is part of the Animation class in Python’s matplotlib library. We will look at multiple examples on how to use it, but for now, you can think of this function as a while loop which keeps redrawing our figure on the canvas.
What helped me to understand how to animate graphs was to start from the end. The animation magic will happen from the following two lines:
import matplotlib.animation as anianimator = ani.FuncAnimation(fig, chartfunc, interval = 100)
Let us look at the above inputs of FuncAnimation:
fig is the figure object we will use to “draw our graph” onchartfunc is a function which takes a numeric input, which signifies the time on the time-series (as the number increases, we move along the timeline)interval is the delay between frames in milliseconds. Defaults to 200.
fig is the figure object we will use to “draw our graph” on
chartfunc is a function which takes a numeric input, which signifies the time on the time-series (as the number increases, we move along the timeline)
interval is the delay between frames in milliseconds. Defaults to 200.
For further optional inputs, check out the docs.
Delving into the above a bit further, all one needs to do, is parameterise their graphs into a function which takes as an input the point in the time-series, and it’s game on!
To ensure we have all basis covered, we are going to build upon our previous examples of data visualisation, which we’ve covered in:
towardsdatascience.com
In other words, we are going to use data from the pandemic (deaths per day), and we will use the final dataset given from the below code. Should you wish to learn more about the below data transformations and how to get started with simple data visualisation, simply read the above post first.
import matplotlib.animation as aniimport matplotlib.pyplot as pltimport numpy as npimport pandas as pdurl = 'https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_deaths_global.csv'df = pd.read_csv(url, delimiter=',', header='infer')df_interest = df.loc[    df['Country/Region'].isin(['United Kingdom', 'US', 'Italy', 'Germany'])    & df['Province/State'].isna()]df_interest.rename(    index=lambda x: df_interest.at[x, 'Country/Region'], inplace=True)df1 = df_interest.transpose()df1 = df1.drop(['Province/State', 'Country/Region', 'Lat', 'Long'])df1 = df1.loc[(df1 != 0).any(1)]df1.index = pd.to_datetime(df1.index)
The first thing we need to do is define the items of our graph, which will remain constant. That is, create the figure object, the x and y labels, set the line colours and the figure margins.
import numpy as npimport matplotlib.pyplot as pltcolor = ['red', 'green', 'blue', 'orange']fig = plt.figure()plt.xticks(rotation=45, ha="right", rotation_mode="anchor") #rotate the x-axis valuesplt.subplots_adjust(bottom = 0.2, top = 0.9) #ensuring the dates (on the x-axis) fit in the screenplt.ylabel('No of Deaths')plt.xlabel('Dates')
We then have to set up our curve function, and then animate it:
def buildmebarchart(i=int):    plt.legend(df1.columns)    p = plt.plot(df1[:i].index, df1[:i].values) #note it only returns the dataset, up to the point i    for i in range(0,4):        p[i].set_color(color[i]) #set the colour of each curveimport matplotlib.animation as anianimator = ani.FuncAnimation(fig, buildmebarchart, interval = 100)plt.show()
The code structure looks identical to that of a line graph. There are, however, some differences which we will go through.
import numpy as npimport matplotlib.pyplot as pltfig,ax = plt.subplots()explode=[0.01,0.01,0.01,0.01] #pop out each slice from the piedef getmepie(i):    def absolute_value(val): #turn % back to a number        a  = np.round(val/100.*df1.head(i).max().sum(), 0)        return int(a)    ax.clear()    plot = df1.head(i).max().plot.pie(y=df1.columns,autopct=absolute_value, label='',explode = explode, shadow = True)    plot.set_title('Total Number of Deaths\n' + str(df1.index[min( i, len(df1.index)-1 )].strftime('%y-%m-%d')), fontsize=12)import matplotlib.animation as anianimator = ani.FuncAnimation(fig, getmepie, interval = 200)plt.show()
One of the main differences is that in the above code, we return a single set of values each time. In the line plot, we were returning the whole time-series up to the point we were at. We achieve that through the use of
df1.head(i).max()
df1.head(i) returns a time-series, but the .max() ensures that we only get the latest records (because the total number of deaths would either remain the same or go up).
Building a bar chart is just as easy as the examples we’ve seen so far. For this example, I have included both a horizontal and a vertical bar chart. Depending on which one you want to see, you simply need to define the variable bar.
fig = plt.figure()bar = ''def buildmebarchart(i=int):    iv = min(i, len(df1.index)-1) #the loop iterates an extra one time, which causes the dataframes to go out of bounds. This was the easiest (most lazy) way to solve this :)    objects = df1.max().index    y_pos = np.arange(len(objects))    performance = df1.iloc[[iv]].values.tolist()[0]    if bar == 'vertical':        plt.bar(y_pos, performance, align='center', color=['red', 'green', 'blue', 'orange'])        plt.xticks(y_pos, objects)        plt.ylabel('Deaths')        plt.xlabel('Countries')        plt.title('Deaths per Country \n' + str(df1.index[iv].strftime('%y-%m-%d')))    else:        plt.barh(y_pos, performance, align='center', color=['red', 'green', 'blue', 'orange'])        plt.yticks(y_pos, objects)        plt.xlabel('Deaths')        plt.ylabel('Countries')animator = ani.FuncAnimation(fig, buildmebarchart, interval=100)plt.show()
So you have created your first animated graphs, and you want to share them. How do you save them?
Luckily, all it takes is a single line of code:
animator.save(r'C:\temp\myfirstAnimation.gif')
For more info, check out the docs.
If you’ve liked this blog post, you may also like: