10

I'm trying to plot two rotating ellipses using the Matplotlib animation library, and I managed to get it working (more or less). The problem is that the first frame that is being rendered does not update, so while I got two rotating ellipses in my canvas, I also have the ellipses in their original position/orientation. Check out my simple piece of code:

import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
from matplotlib import animation

fig = plt.figure()
ax = fig.add_subplot(111, aspect='equal')
e1 = Ellipse(xy=(0.5, 0.5), width=0.5, height=0.2, angle=60)
e2 = Ellipse(xy=(0.8, 0.8), width=0.5, height=0.2, angle=100)

def init():
    ax.add_patch(e1)
    ax.add_patch(e2)
    return [e1,e2]

def animate(i):
    e1.angle = e1.angle + 0.5
    e2.angle = e2.angle + 0.5
    return [e1,e2]

anim = animation.FuncAnimation(fig, animate, init_func=init, interval=1, blit=True)
plt.show()

Any idea how to fix this? I could of course turn off blit, but that makes it horribly slow, so that's not really an option.

EDIT: Final (working) Code

import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
from matplotlib import animation

fig = plt.figure()
ax = fig.add_subplot(111, aspect='equal')
e1 = Ellipse(xy=(0.5, 0.5), width=0.5, height=0.2, angle=60)
e2 = Ellipse(xy=(0.8, 0.8), width=0.5, height=0.2, angle=100)
ax.add_patch(e1)
ax.add_patch(e2)

def init():
    e1.set_visible(False)
    e2.set_visible(False)
    return [e1,e2]

def animate(i):
    if i == 1:
        e1.set_visible(True)
        e2.set_visible(True)
    e1.angle = e1.angle + 0.5
    e2.angle = e2.angle + 0.5
    return [e1,e2]

anim = animation.FuncAnimation(fig, animate, init_func=init, interval=1, blit=True)
plt.show()
Seanny123
  • 8,776
  • 13
  • 68
  • 124
MPA
  • 1,878
  • 2
  • 26
  • 51

2 Answers2

4

The proposed answer seems like a hack. You're hiding the patch for one frame, then showing it the next, for no rhyme or reason. Also, I noticed the init function gets called whenever you resize the plot, which would then make the ellipse invisible after resizing with the proposed solution.

I think the correct way to do this is to set animated=True on the Ellipse objects. See the matplotlib animation documentation. Here's some code that works for me:

import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
from matplotlib import animation

fig = plt.figure()
ax = fig.add_subplot(111, aspect='equal')
e1 = Ellipse(xy=(0.5, 0.5), width=0.5, height=0.2, angle=60, animated=True)
e2 = Ellipse(xy=(0.8, 0.8), width=0.5, height=0.2, angle=100, animated=True)
ax.add_patch(e1)
ax.add_patch(e2)

def init():
    return [e1, e2]

def animate(i):
    e1.angle = e1.angle + 0.5
    e2.angle = e2.angle + 0.5
    return [e1, e2]

anim = animation.FuncAnimation(fig, animate, init_func=init, interval=1, blit=True)
plt.show()
Stanley Bak
  • 543
  • 3
  • 16
3

Try this:

import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
from matplotlib import animation

fig = plt.figure()
ax = fig.add_subplot(111, aspect='equal')
e1 = Ellipse(xy=(0.5, 0.5), width=0.5, height=0.2, angle=60)
e2 = Ellipse(xy=(0.8, 0.8), width=0.5, height=0.2, angle=100)


def init():
    return [ax]

def animate(i):
    if i==0:
        ax.add_patch(e1)
        ax.add_patch(e2)    
    e1.angle = e1.angle + 0.5
    e2.angle = e2.angle + 0.5
    return [e1,e2]

anim = animation.FuncAnimation(fig, animate, init_func=init, interval=1, blit=True)
plt.show()

Screen-shot showing the correct behavior

Try this other approach (not I've used only one ellipse just for testing, it also renders fine here):

import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
from matplotlib import animation

fig = plt.figure()
ax = fig.add_subplot(111, aspect='equal')
e1 = Ellipse(xy=(0.5, 0.5), width=0.5, height=0.2, angle=60)
ax.add_patch(e1)

def init():
    e1.set_visible(False)
    return e1,

def animate(i):
    if i==0:
        e1.set_visible(True)
    e1.angle = e1.angle + 0.5
    return e1,

anim = animation.FuncAnimation(fig, animate, init_func=init, interval=1, blit=True)
plt.show()
Alvaro Fuentes
  • 16,937
  • 4
  • 56
  • 68
  • Are you sure? I've copy-pasted the code I posted yesterday and it works smoothly here. (Matplotlib 1.2.1) – Alvaro Fuentes Jan 30 '14 at 13:46
  • Yes, I've copy-pasted your code, still the same as before. I'm on v1.2.1 as well. – MPA Jan 30 '14 at 14:19
  • Humm..., Well I'm using PyQt4 as back-end and I'm on Linux Min 15, maybe you have a different back-end? I'm thinking is an issue on matplotlib? I I try your code with `blit=False` it runs fine. – Alvaro Fuentes Jan 30 '14 at 14:41
  • I've tried using a different backend (for instance `matplotlib.use('Qt4Agg')`), but without success. I'm on Windows 7. And yes, with `blit=False` it runs, but terribly slow – MPA Jan 30 '14 at 15:32
  • Well, maybe is a problem with W7, I've updated the answer with another idea, try it if you like. – Alvaro Fuentes Jan 30 '14 at 15:38
  • Your last idea works! The only change I had to make was set `i == 0` to `i == 1`, otherwise nothing would show. But it works as intended now. Thanks! – MPA Jan 30 '14 at 16:06