Matplotlib animation either freezes after a few frames or just doesn't work
Asked Answered
A

8

6

I've been trying for hours to get this simple script working, but nothing I do seems to help. It's a slight modification of the most basic animated plot sample code from the Matplotlib website, that should just show a few frames of noise (I have the same issue with the unmodified code from their website BTW).

On my computer with the TkAgg backend I get about 20 frames (out of 60) before the plot window freezes. With Qt4Agg I just get a frozen, black window and no frames at all are plotted. I've tried multiple combinations of different NumPy, PyQt, Python and Matplotlib versions, but always get the same result.

Please let me know if this works for you or if anything looks wrong. I'm pretty sure this did work in the past, so I'm thinking it may be a Windows issue or something related to ion().

FYI I'm using Windows 7 (32 bit) and I've tested with Python 2.6/2.7, MPL 1.0.0/0.9.9.8, PyQt 4.6/4.7, Numpy 1.4/1.5b.

import matplotlib
matplotlib.use('TkAgg') # Qt4Agg gives an empty, black window
from pylab import *
import time

ion()
hold(False)

# create initial plot
z = zeros(10)
line, = plot(z)
ylim(-3, 3)

for i in range(60):
    print 'frame:', i

    d = randn(10)
    line.set_ydata(d)

    draw()
    time.sleep(10e-3)

This simpler version also freezes after the first couple frames:

from pylab import *

ion()
hold(False)

for i in range(40):
    plot(randn(10))
    draw()

show()

Thanks!

EDIT: These people seem to be having the same or a similar problem as me:

  • mail-archive.com/[email protected]/msg10844.html
  • https://mcmap.net/q/729429/-matplotlib-pyplot-pylab-not-updating-figure-while-isinteractive-using-ipython-pylab-duplicate
  • mail-archive.com/[email protected]/msg01283.html

Doesn't look like any of them were able to fix it either :(

Apple answered 9/8, 2010 at 16:1 Comment(3)
I tried the codes above in Windows (64-bit) with Python 2.6.5, Numpy 1.5.0b1, and Matplotlib 1.0.0 without any problem using the cmd line. I also tried them in IDLE and the first code hangs and crashes at the end, but the second one worked fine which surprised me. I don't know if that helps at all, but there you have it. I don't have any QT stuff installed so this was all with Tk.Koppel
Thanks a lot Justin. Are you sure all the frames were displayed? I get a couple before things freeze up myself.Apple
Think the QTAgg problems are related to this github issue, using pause() with pylab instead of draw() works, also show() shouldn't be needed.Perl
P
5

Typically, GUI frameworks need to 'own' the main loop of the program. Sitting in a tight loop with sleeps to delay iterations will usually 'break' GUI applications (your problem description is consistent with typical breakage along these lines). It's possible that the matplotlib devs have implemented some behind the scenes logic to pevent these lockups from happening for certain toolkits but restructuring your program slightly should eliminate any chance of mainloop ownership being the problem (which is very likely I think). The matplotlib animation wiki also suggests using native event loops for anything nontrivial (probably for this reason)

Rather than sitting in a loop with sleeps, I suggest that, instead, you use the GUI toolkit to schedule a function call after a certain delay.

def update_function():
    # do frame calculation here

refresh_timer = QtCore.QTimer()
QtCore.QObject.connect( refresh_timer, QtCore.SIGNAL('timeout()'), update_function )
refresh_timer.start( 1.0 / 30 ) # have update_function called at 30Hz

Looking at the matplotlib documentation suggests that it may be possible to use their API natively but I couldn't find any good examples using just a quick search.

Pitchford answered 9/8, 2010 at 17:41 Comment(3)
I may indeed need to do that when my script gets more involved, but I wouldn't expect my simple (trivial almost) example to need anything more complicated, particularly since I recall this working in the past.Apple
That it worked in the past may have been more of an accident than anything else. All common GUI toolkits are inherently asynchronous and attempting to use them synchronously is a definite design flaw. Using them asynchronously can still be kept really simple but it just doesn't look like the matplotlib developers have put much effort into it... probably due to animation being a much smaller use case than static image generation. Anyway, good luck with your app :)Pitchford
root.after(100, somefunc), and gobject.timeout_add(100, somefunc) aren't terribly complicated. Qt is a little more involved...Lollapalooza
G
2

After many hours fighting with this same issue I think I've found the answer: To do these simple animations with matplotlib you can only use the GTKAgg backend. This is stated as a passing remark in the scipy cookbook, but I think it should be stressed more clearly. When I use it, I can run your animations until the end without freezes or any other problem.

Beware that to use this backend you need to install PyGTK. I don't know what else you need on Windows (because I'm on Linux) but that seems the minimum. Besides, if you want to use it by default you have to add this line to your matplotlibrc (on Linux placed on ~/.matplotlib/matplotlibrc):

backend      : GTKAgg

To use the other backends you need to follow the official matplotlib examples, but that means you have to build a mini-gui application just to run a simple animation, and I find that quite awful!

Gilmore answered 8/9, 2010 at 15:22 Comment(1)
Switching to TK backend worked for meRepugnant
L
1

When you say freezes after the first couple of frames do you mean 2 or 3, or say, 40 or 60, as those are the upper limits of your loop?

If you want the animation to continue indefinitely you need something like

while True:
    d = randn(10)
    line.set_ydata(d)
    draw()
    time.sleep(10e-3)

But you'll have to force quit your program.

Lollapalooza answered 9/8, 2010 at 16:9 Comment(5)
Typically it freezes after about 20 frames and the plot window says "not responding", though the script keeps running and printing the frame numbers.Apple
Does this example work? matplotlib.sourceforge.net/examples/animation/…Lollapalooza
I don't have PyGTK, but matplotlib.sourceforge.net/examples/animation/… gives the same problem - it works for a while, then freezes.Apple
Does it freeze or finish? On the same indentation as print 'FPS:'... and before add ax.plot(range(10));fig.canvas.draw() - if you get a nice straight line from <0,0> to <9,9>, it's not freezing.Lollapalooza
The animations works for a while, freezes about half way through for about 10s (this is what I see: i.imgur.com/p4I7C.png), then it unfreezes and I see the final frame, along with the straight line.Apple
P
1

Generally you can't use show() and draw() like this. As the Posts are suggesting, you need a small GUI loop, just look at the Animations examples on the Matplotlib page.

Pooh answered 17/8, 2010 at 10:38 Comment(0)
W
1

I was struggling with this same problem for quite a while. I would recommend taking a look at this example: http://matplotlib.sourceforge.net/examples/animation/strip_chart_demo.html

I thought I was following this example exactly, but it wasn't working. It would only run the "update" function one time. Turns out the only difference in my code was that the animation.FuncAnimation() was not assigned to a variable. As soon as I assigned the return value of animation.FuncAnimation() to a value, everything worked.

Wickliffe answered 29/6, 2012 at 15:58 Comment(0)
R
1

I was having (I think) the same trouble, where the window would freeze if I took the focus off it or tried to drag it around, using Python 2.7 on Windows 7 with Matplotlib 1.3, and TKAgg backend. I had a call to time.sleep(1) in my main while loop, and when I replaced that with plt.pause(1), that fixed the problem. So, try and use matplotlib's pause function rather than time module sleep function, it worked for me.

Rode answered 13/8, 2013 at 19:11 Comment(0)
K
1

calling time.sleep() or plt.pause() causes flicker on the graph window when using blitting, but I got good results by simply calling the event loop explicitely :

fig.canvas.blit() # or draw()
fig.canvas.start_event_loop(0.001) #1 ms seems enough
Kuwait answered 2/10, 2014 at 12:57 Comment(0)
B
0

greetings from the future.

Here's how you'd do it in python 3:

import matplotlib
matplotlib.use('TkAgg') # Qt4Agg gives an empty, black window
import matplotlib.pylab as plt
import time

# create initial plot
z = zeros(10)
line, = plot(z)
ylim(-3, 3)

for i in range(60):
    print('frame:', i)

    d = randn(10)
    line.set_ydata(d)
    draw()
    #replace time.sleep() with plt.pause()
    plt.pause(0.5)

I got rid of the call to ion() and hold(False). I also replaced time.sleep with plt.pause

Beatty answered 11/3, 2020 at 17:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.