pythonmatplotlibanimation

Patches animation in matplotlib


I'm trying to create a simple particle animation using matplotlib, like this:

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

fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(7, 6.5)

ax = plt.axes(xlim=(0, 10), ylim=(0, 10))
patch = plt.Circle((5, -5), 0.75, fc='y')

def init():
    patch.center = (5, 5)
    ax.add_patch(patch)
    return patch,

def animate(i):
    x, y = patch.center
    x = 5 + 3 * np.sin(np.radians(i))
    y = 5 + 3 * np.cos(np.radians(i))
    patch.center = (x, y)
    return patch,

anim = animation.FuncAnimation(fig, animate, 
                               init_func=init, 
                               frames=36, 
                               interval=20,
                               blit=True)

HTML(anim.to_jshtml())

Now, I want to wrap the plt.Circle object in a "Particle" class, so that I can add other functionality (like giving it a velocity and so on). This is what I tried:

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

fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(7, 6.5)

ax = plt.axes(xlim=(0, 10), ylim=(0, 10))

class Particle:
    def __init__(self,x,y):
        self.x = x
        self.y = y
    def show(self):
        return plt.Circle((self.x, self.y), 0.75, fc='y')

p = Particle(5, -5)

def init():
    ax.add_patch(p.show())
    return p.show(),

def animate(i):
    p.x = 5 + 3 * np.sin(np.radians(i))
    p.y = 5 + 3 * np.cos(np.radians(i))
    return p.show(),

anim = animation.FuncAnimation(fig, animate, 
                               init_func=init, 
                               frames=36, 
                               interval=20,
                               blit=True)

HTML(anim.to_jshtml())

why doesn't this work?

I expected this to behave the same way as the first code, since p.show() returns a plt.Circle object.


Solution

  • You should update the position of an existing Circle object.

    import numpy as np
    from matplotlib import pyplot as plt
    from matplotlib import animation
    from IPython.display import HTML
    
    fig = plt.figure()
    fig.set_dpi(100)
    fig.set_size_inches(7, 6.5)
    
    ax = plt.axes(xlim=(0, 10), ylim=(0, 10))
    
    class Particle:
        def __init__(self, x, y):
            self.x = x
            self.y = y
            self.circle = plt.Circle((self.x, self.y), 0.75, fc='y')
    
        def show(self):
            self.circle.set_center((self.x, self.y))
            return self.circle
    
    p = Particle(5, 5)
    ax.add_patch(p.show())
    
    def init():
        p.show()
        return p.show(),
    
    def animate(i):
        p.x = 5 + 3 * np.sin(np.radians(i * 10))
        p.y = 5 + 3 * np.cos(np.radians(i * 10))
        p.show()
        return p.show(),
    
    anim = animation.FuncAnimation(fig, animate, 
                                   init_func=init, 
                                   frames=36, 
                                   interval=100,
                                   blit=True)
    
    HTML(anim.to_jshtml())