2

I'm a little hesitant about asking this, since there seem to be many "Exception in Tkinter callback" questions, but I cannot find one that fits the problem I have here.

I am trying to save an MP4 animation (of a percolation simulation) using matplotlib with ffmpeg. The code works fine on my home laptop, but not on my work PC. It also works fine if I replace the anim.save line with plt.show(), but I do want to save the animation. I'm using Python 3.5.2 on Ubuntu 17.04 (and I have ffmpeg installed).

Here is the error:

>>> Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python3.5/tkinter/__init__.py", line 1558, in __call__
    return self.func(*args)
  File "/usr/lib/python3.5/tkinter/__init__.py", line 604, in callit
    func(*args)
  File "/usr/lib/python3/dist-packages/matplotlib/backends/backend_tkagg.py", line 373, in idle_draw
    self.draw()
  File "/usr/lib/python3/dist-packages/matplotlib/backends/backend_tkagg.py", line 354, in draw
    FigureCanvasAgg.draw(self)
  File "/usr/lib/python3/dist-packages/matplotlib/backends/backend_agg.py", line 474, in draw
    self.figure.draw(self.renderer)
  File "/usr/lib/python3/dist-packages/matplotlib/artist.py", line 62, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "/usr/lib/python3/dist-packages/matplotlib/figure.py", line 1165, in draw
    self.canvas.draw_event(renderer)
  File "/usr/lib/python3/dist-packages/matplotlib/backend_bases.py", line 1809, in draw_event
    self.callbacks.process(s, event)
  File "/usr/lib/python3/dist-packages/matplotlib/cbook.py", line 563, in process
    proxy(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/matplotlib/cbook.py", line 430, in __call__
    return mtd(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/matplotlib/animation.py", line 661, in _start
    self._init_draw()
  File "/usr/lib/python3/dist-packages/matplotlib/animation.py", line 1221, in _init_draw
    self._draw_frame(next(self.new_frame_seq()))
StopIteration

The code producing the error is:

def percolate():

    # initialize an instance of the Percolator class
    perc = Percolator(1, 100, 0.1)

    # initialize the image
    fig, ax = plt.subplots()
    im = plt.imshow(perc.states)

    anim = animation.FuncAnimation(fig, perc.update, perc.update_iter, repeat=False, fargs=(im, ), save_count=perc.n**2)
    anim.save("perc.mp4")

I can reproduce the code for the Percolator class if necessary, but that part is working fine. It has two functions: update_iter, a generator function that yields True as long as the animation should continue, and update, which takes (the result of the iterator and) im as inputs, and its last two lines are

im.set_array(self.states)
return im,

UPDATE:

Here's an MWE.

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


class Percolator:

    def __init__(self):
        self.i = 0
        self.states = np.zeros((10, 10))
        self.end = False

    def update(self, garbage=None, im=None):
        self.i += 1
        if self.i == 10:
            self.end = True
        im.set_array(self.states)
        return im,

    def update_iter(self):
        while self.end == False:
            yield True

def percolate():

    perc = Percolator()
    fig, ax = plt.subplots()
    im = plt.imshow(perc.states)

    anim = animation.FuncAnimation(fig, perc.update, perc.update_iter, repeat=False, \
                                   fargs=(im, ), save_count=100)

    anim.save("perc.gif", writer="imagemagick")

In this example, the Percolator class doesn't do anything interesting - it sets up a 10x10 grid of 0s, and each call to its update function sets the image to the same 10x10 grid.

If the frames attribute of FuncAnimation is set to 50 (say), rather than to perc.update_iter, then there is no error and the image is saved correctly. So the problem seems to be with my generator function. I want to use the generator function because I want to keep creating new frames until some condition on perc.states is met - here, boringly, I've just asked it to keep going for 10 iterations.

System details: Python 3.5.3, matplotlib 2.0.0, Ubuntu 17.04.

UPDATE 2:

Same problem after upgrading to matplotlib 2.0.2. Also, printing some output along the way reveals that the error occurs at the end of the iterations. In fact, if update_iter is changed to:

def update_iter(self):
    print(self.end)
    while self.end == False:
        yield True

... then the output is:

False
False
False
False
False
False
False
False
False
False
False
True
>>> True
Exception in Tkinter callback
Traceback (most recent call last):
etc.
paul
  • 75
  • 7
  • If the exact same code runs on one computer and does not run on another computer, the idea is of course to check thoroughly for the differences between the two in terms of system, versions, call procedure etc. – ImportanceOfBeingErnest Aug 22 '17 at 15:41
  • I'm sure there are all sorts of differences between the two machines, and unfortunately I have no idea what I'm looking for. If someone can tell me what the error means, for example, that might help to narrow it down. – paul Aug 22 '17 at 15:47
  • How many frames do you actually want to save? Where do you specify that? Did you have a look at [this question](https://stackoverflow.com/questions/43501800/trouble-saving-matplotlib-animation-with-ffmpeg?rq=1)? Did you try saving as animated gif instead of mp4? – ImportanceOfBeingErnest Aug 22 '17 at 15:57
  • I have seen that question (and others like it), but unlike those, the error here does not report that a file can't be found. The number of frames depends on the randomness of the initialization of the percolation model, which is why, instead of a fixed number of frames, I've used the generator function `perc.update_iter`. This continues to yield true as long as another frame should be produced. – paul Aug 22 '17 at 16:03
  • Hmm, I do get exactly the same error trying to save as an animated GIF. (But still no error not saving and using `plt.show()`.) – paul Aug 24 '17 at 09:08
  • That's somehow good news, because it tells us that it's not some strange ffmpeg error, but something with the animation itself, this should be easier to come by. What we would need (as usual) is a [mcve] of the issue (some code that can be copied pasted and run; hence you may quickly write a simplified version of `Percolator`) and the version numbers of your system, python and matplotlib. – ImportanceOfBeingErnest Aug 24 '17 at 09:33
  • I've added a MWE. – paul Aug 24 '17 at 11:44
  • Ok, so the mcve runs fine for me without error on win8, python2.7, matplotlib 2.0.2. I wouldn't think that the os or python makes a difference here, but I'm not sure about the difference between matplotlib 2.0.0 and matplotlib 2.0.2. There has been [some work on the animations in between the two versions](https://github.com/matplotlib/matplotlib/commits/master/lib/matplotlib/animation.py). – ImportanceOfBeingErnest Aug 24 '17 at 12:15
  • I've just upgraded to matplotlib 2.0.2 - I didn't realize upgrades needed to be done manually (as in, `sudo apt-get update` and `sudo apt-get install matplotlib` didn't do anything, I had to use pip). Unfortunately though the same error persists. – paul Aug 24 '17 at 13:18
  • That is unfortunate. Now we have a situation where the exact same code on the exact same version produces two different results. I fear at this point I have to give up, since I cannot test anything or reproduce the error. – ImportanceOfBeingErnest Aug 24 '17 at 13:31
  • I've added a second update to the original post. – paul Aug 24 '17 at 13:31
  • That is indeed unfortunate! – paul Aug 24 '17 at 13:32

0 Answers0