3

I am new to animating with Matplotlib, and having a little trouble. I would like to create an animation of particle positions, and I would like to display the frame number at each step. I have created sample data at the beginning of my code snippet so the code is self-contained (normally my data is read in from a csv).

The problem - the displayed plot is completely blank. However, if I comment out the return of time_text (i.e. change 'return patches, time_text' to 'return patches') everything works fine. I assume the problem is in how I am updating the time_text, but I am stuck as to how to fix it.


from matplotlib import pyplot as plt  
from matplotlib import animation  
import numpy as np  
import pandas as pd  

box_size = 50  
radius = 1

df =pd.DataFrame(np.array([np.arange(50),np.arange(50),np.arange(50)]).T,
                          columns = ['x','y','frame'])

#set up the figure
fig = plt.figure()
plt.axis([0,box_size,0,box_size])
ax = plt.gca()
ax.set_aspect(1)
time_text = ax.text(5, 5,'')

#initialization of animation, plot empty array of patches
def init():
    time_text.set_text('initial')
    return []

def animate(i):
    patches = []
    #data for this frame only
    data = df[df.frame == i]
    time_text.set_text('frame'+str(i))
    #plot circles at particle positions
    for idx,row in data.iterrows():
        patches.append(ax.add_patch(plt.Circle((row.x,row.y),radius,color= 'b',
                                               alpha = 0.5)))            
    return patches, time_text

anim = animation.FuncAnimation(fig, animate, init_func=init, repeat = False,
                               frames=int(df.frame.max()), interval=50, 
                                blit=True)
mdriscoll
  • 173
  • 2
  • 6

1 Answers1

0

You will need to let your initialization function return the pyplot.text object. You should also initiate the object that you want to modify at each call from the anim function.

Have a look at ArtistAnimation, it might be better suited for what you are doing.

To avoid that many circles gather on the canvas, I would rather update the position of the path object instead of appending new ones at each iteration.

from matplotlib import pyplot as plt  
import matplotlib.patches as patches
from matplotlib import animation  
import numpy as np  
import pandas as pd  

box_size = 50  
radius = 1

df = pd.DataFrame(np.array([np.arange(50),np.arange(50),np.arange(50)]).T,
                          columns = ['x','y','frame'])

#set up the figure
fig = plt.figure()
plt.axis([0,box_size,0,box_size])
ax = plt.gca()
time_text = ax.text(5, 5,'')

circle = plt.Circle((1.0,1.0), radius,color='b', alpha=0.5, facecolor='orange', lw=2)


#initialization of animation, plot empty array of patches
def init():
    time_text.set_text('initial')
    ax.add_patch( circle )
    return time_text, ax

def animate(i):
    #data for this frame only
    data = df[df.frame == i]
    time_text.set_text('frame' + str(i) )

    #plot circles at particle positions
    for idx,row in data.iterrows():
        circle.center = row.x,row.y

    return time_text, ax

anim = animation.FuncAnimation(fig, animate, init_func=init, repeat = False,
                               frames=int(df.frame.max()), interval=200, blit=True)

plt.show()
Sevle
  • 3,109
  • 2
  • 19
  • 31
snake_charmer
  • 2,845
  • 4
  • 26
  • 39
  • @mdriscoll Welcome to Stack Overflow. Observe that my solution introduces a problem, you will have to find a way to remove the old paths as new ones are being added. – snake_charmer Jan 15 '15 at 20:54
  • Having init() function return time_text unfortunately does not help - it still returns a blank plot with no animation. Is there a kwarg in FuncAnimation I am missing? – mdriscoll Jan 15 '15 at 23:47
  • It should return at least 2 objects since the method expects an iterable. This is why I returned the `matplotlib.axes.AxesSubplot`. The modified code I posted shows an animation with a changing text on both my computers, have you tried to run it? – snake_charmer Jan 16 '15 at 08:53
  • Thanks - the code you posted does update the text. However now the patches are just be appended to the same ax object, so I see the all of the circles, rather than a moving circle. Is there a way to clear the ax object? (this is why I had the line patches = [] in the animate function in the original code) – mdriscoll Jan 16 '15 at 16:22