Aissaoui A
Aissaoui A

Reputation: 109

Animating a Seaborn bubble chart using FuncAnimation

I have a data-set that contains the income and life expectancy per country across time. In the year 1800, it looks like this: 1

I would like to make an animated chart that shows how life expectancy and income evolve over time (from 1800 until 2019). Here's my code so far for a static plot:

import matplotlib
fig, ax = plt.subplots(figsize=(12, 7))

chart = sns.scatterplot(x="Income",
                        y="Life Expectancy",
                        size="Population",
                        data=gapminder_df[gapminder_df["Year"]==1800],
                        hue="Region", 
                        ax=ax,
                        alpha=.7,
                        sizes=(50, 3000)
                       )

ax.set_xscale('log')
ax.set_ylim(25, 90)
ax.set_xlim(100, 100000)

scatters = [c for c in ax.collections if isinstance(c, matplotlib.collections.PathCollection)]

handles, labels = ax.get_legend_handles_labels()
ax.legend(handles[:5], labels[:5])

def animate(i):
    data = gapminder_df[gapminder_df["Year"]==i+1800]
    for c in scatters:
        # do whatever do get the new data to plot
        x = data["Income"]
        y = data["Life Expectancy"]
        xy = np.hstack([x,y])
        # update PathCollection offsets
        c.set_offsets(xy)
        c.set_sizes(data["Population"])
        c.set_array(data["Region"])
    return scatters

ani = matplotlib.animation.FuncAnimation(fig, animate, frames=10, blit=True)
ani.save("test.mp4")

Here's the link to the data: https://github.com/abdennouraissaoui/Animated-bubble-chart

Thank you!

Upvotes: 3

Views: 2697

Answers (1)

Zephyr
Zephyr

Reputation: 12496

You can loop over years of your data through the i counter, which increases by 1 at each loop (at each frame). You can define a year variable, that depends on i, then filter your data by this year and plot the filtered dataframe. At each loop you have to erase the previous scatterplot with ax.cla(). Finally, I choose 220 frames in order to have a frame for each year, from 1800 to 2019.
Check this code as a reference:

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib.animation import FuncAnimation

gapminder_df = pd.read_csv('data.csv')

fig, ax = plt.subplots(figsize = (12, 7))

def animate(i):
    ax.cla()
    year = 1800 + i
    sns.scatterplot(x = 'Income',
                    y = 'Life Expectancy',
                    size = 'Population',
                    data = gapminder_df[gapminder_df['Year'] == year],
                    hue = 'Region',
                    ax = ax,
                    alpha = 0.7,
                    sizes = (50, 3000))
    ax.set_title(f'Year {year}')
    ax.set_xscale('log')
    ax.set_ylim(25, 90)
    ax.set_xlim(100, 100000)
    handles, labels = ax.get_legend_handles_labels()
    ax.legend(handles[:5], labels[:5], loc = 'upper left')

ani = FuncAnimation(fig = fig, func = animate, frames = 220, interval = 100)
plt.show()

which reproduce this animation:

enter image description here

(I cut the above animation in order to have a lighter file, less than 2 MB, in fact the data increases at a step of 5 years. However the code above reproduces the complete animation, with a step of 1 year)

Upvotes: 4

Related Questions