Search code examples
pythonmatplotlibseabornline-plotmatplotlib-animation

How to create a lineplot animation


I have a pandas DataFrame that looks:

d = {'time': [1, 3, 5,7, 9, 11, 13, 15, 17, 19],
     'method1':[0.864231038, 0.874805716, 0.890315836, 0.906831719, 0.91634293, 0.928120905, 0.938231839, 0.947280697,
              0.951635588, 0.951468784],
    'method2':[0.867868393, 0.878908199, 0.893329853, 0.911470465, 0.924099528, 0.934628044, 0.945209861, 0.951776017,
               0.954180089, 0.95553498]} 

df = pd.DataFrame(data=d)
df

output:

    time    method1 method2
0   1   0.864231    0.867868
1   3   0.874806    0.878908
2   5   0.890316    0.893330
3   7   0.906832    0.911470
4   9   0.916343    0.924100
5   11  0.928121    0.934628
6   13  0.938232    0.945210
7   15  0.947281    0.951776
8   17  0.951636    0.954180
9   19  0.951469    0.955535

I plotted this dataframe for method 1 and method 2 with respect value column as follows

x_labels = df['time']
fig, ax = plt.subplots()
ax.set_xlabel('Time', fontsize=14)
ax.set_ylabel('value', fontsize=14)

sns.lineplot(x=x_labels, y=df['method1'], ax=ax, label='method1')
sns.lineplot(x=x_labels, y=df['method2'], ax=ax, label='method2')
plt.xlim(xmin=0)
ax.set_xlim([1, 19])

Output:

enter image description here

However, I want to visualize the data by using GIFS, This is How my expected output look like:

enter image description here


Solution

  • You can use the matplotlib.animation API.

    import matplotlib.animation as animation
    

    Here's an example:

    import matplotlib.pyplot as plt
    fig, ax = plt.subplots()
    
    def animate(i):
        ax.clear()
        x_labels = df['time'][:i+1]
        ax.set_xlim([1, 19])
        ax.set_xlabel('Time', fontsize=14)
        ax.set_ylabel('value', fontsize=14)
        sns.lineplot(x=x_labels, y=df['method1'][:i+1], ax=ax, label='method1')
        sns.lineplot(x=x_labels, y=df['method2'][:i+1], ax=ax, label='method2')
    
    anim = animation.FuncAnimation(fig, animate, frames=len(df), interval=500)
    anim.save('test.gif')
    

    enter image description here


    The standard implementation is to pass the dataframe in a long form, instead of a wide form, which allows for the use of the hue parameter, and only one plot call. However, this results in the lines being drawn consecutively, instead of concurrently.

    # convert the dataframe to a long form
    df = df.melt(id_vars='time')
    
    fig, ax = plt.subplots()
    
    def animate(i):
        ax.clear()
        data = df.iloc[:i+1, :]  # select rows to i+1 with each frame
        sns.lineplot(data=data, x='time', y='value', ax=ax, hue='variable')
        ax.set_xlabel('Time', fontsize=14)
        ax.set_ylabel('value', fontsize=14)
        ax.set_xlim([1, 19])
    
    anim = animation.FuncAnimation(fig, animate, frames=len(df), interval=500)
    anim.save('test.gif')
    

    enter image description here