Bugs in close('all') with the TkAgg backend

planck[pylab]> cat tkbug.py from matplotlib import pylab

    > pylab.plot(range(10)) pylab.show()

    > # Now I try to run this with plain python, no ipython in
    > sight:

This is the result of adding

    if rcParams['tk.pythoninspect']:
        os.environ['PYTHONINSPECT'] = '1'

to tkagg. Comment out the pythoninspect line (or set the rc param
accordingly) and see if makes a difference. The pythoninspect thing
appears to be required to make idle work in interactive mode, though
it was introduced for other reasons I won't go into now.

The rc param is only in CVS -- you may just want to comment out the
whole bit and see if it helps.

Let me know...

JDH

John Hunter wrote:

"Fernando" == Fernando Perez <Fernando.Perez@...76...> writes:

    > planck[pylab]> cat tkbug.py from matplotlib import pylab

    > pylab.plot(range(10)) pylab.show()

    > # Now I try to run this with plain python, no ipython in
    > sight:

This is the result of adding

    if rcParams['tk.pythoninspect']:
        os.environ['PYTHONINSPECT'] = '1'

to tkagg. Comment out the pythoninspect line (or set the rc param
accordingly) and see if makes a difference. The pythoninspect thing
appears to be required to make idle work in interactive mode, though
it was introduced for other reasons I won't go into now.

OK, my report from this afternoon was written in the office, where I have mpl 0.71. I'm now home, and my laptop runs 0.70. Here, I don't see the problem at all. I can't test here the big code where I saw the massive mayavi breakdown, because that was written by my officemate. But at least I can confirm that 0.70, whose show() looks like:

def show():
     """
     Show all the figures and enter the gtk mainloop

     This should be the last line of your script
     """
     for manager in Gcf.get_all_fig_managers():
         manager.show()
     import matplotlib
     matplotlib.interactive(True)
     #os.environ['PYTHONINSPECT'] = '1'
     if show._needmain:
         Tk.mainloop()
         show._needmain = False

does not show the spurious prompt thingie (note the PYTHONINSPECT thingie is commented out). I'll try to make this change to 0.71 and test the larger code with the mayavi problems, but it may be a few days before I can do that.

HTH,

f

John Hunter wrote:

"Fernando" == Fernando Perez <Fernando.Perez@...76...> writes:

    > planck[pylab]> cat tkbug.py from matplotlib import pylab

    > pylab.plot(range(10)) pylab.show()

    > # Now I try to run this with plain python, no ipython in
    > sight:

This is the result of adding

    if rcParams['tk.pythoninspect']:
        os.environ['PYTHONINSPECT'] = '1'

to tkagg. Comment out the pythoninspect line (or set the rc param
accordingly) and see if makes a difference. The pythoninspect thing
appears to be required to make idle work in interactive mode, though
it was introduced for other reasons I won't go into now.

OK, to summarize things with respect to this bug. Indeed, commenting out the pythoninspect line solves the spurious prompt problem. But it does nothing to the close('all') bug. I managed to find a small test case to replicate the bug:

planck[pylab]> pylab

In [1]: cat tkbug.py
# This script crashes vtk, when run in an ipython -pylab session, with TkAgg
# as the default backend.

# The key is that the pylab.plot() call is made BEFORE the imv.surf call. If
# I call imv.surf() first, it works fine. Something in matplotlib is
# destroying windows it shouldn't.

from matplotlib import pylab
from mayavi.tools import imv

x = y = pylab.arange(256)
z = pylab.rand(256,256)

pylab.plot(range(10))
pylab.show()

imv.surf(x,y,z)

print "*** I'm about to close figure 1, this will crash VTK!!! *** \n"
pylab.close(1)
########################## EOF

In [2]: run tkbug
*** I'm about to close figure 1, this will crash VTK!!! ***

Generic Warning: In /usr/local/installers/src/vtk/VTK/Rendering/vtkTkRenderWidget.cxx, line 633
A TkRenderWidget is being destroyed before it associated vtkRenderWindow is destroyed. This is very bad and usually due to the order in which objects are being destroyed. Always destroy the vtkRenderWindow before destroying the user interface components.

Somehow, it seems that the Tk figure manager is messing with windows it shouldn't touch.

On a related note, I've been playing with some things in matplotlib which require looping through figure lists, making new figures with guaranteed new numbers, etc. I'd like to propose a change.

I'd like figure() to allow calling wit None as the num argument. If num is None, it would produce a guaranteed new figure window, with a number equal to the currently highest + 1. This would make it easy, amongst other things, to write code which displays arrays with a proper aspect ratio by wrapping imshow() or figimage(). I can currently make such a guaranteed new number by using the following as a patch to pylab.py:

     if num==0:
         error_msg('Figure number can not be 0.\n' + \
                   'Hey, give me a break, this is matlab(TM) compatability')

     # NEW CODE
     if num is None:
         allnums = [f.num for f in _pylab_helpers.Gcf.get_all_fig_managers()]
         if allnums:
             num = max(allnums) + 1
         else:
             num = 1
     # /NEW CODE

I also think the default value for num should be None instead of 1. This would allow you to make the following simple, clean use for building new plots:

planck[~]> pylab

In [1]: plot(range(10))
Out[1]: [<matplotlib.lines.Line2D instance at 0x412ccd8c>]

In [2]: figure()
Out[2]: <matplotlib.figure.Figure instance at 0x412ccd2c>

In [3]: plot(range(20))
Out[3]: [<matplotlib.lines.Line2D instance at 0x410d320c>]

In [4]: figure()
Out[4]: <matplotlib.figure.Figure instance at 0x410d32ac>

In [5]: plot(range(30))
Out[5]: [<matplotlib.lines.Line2D instance at 0x4115b02c>]

without never having to worry about manually managing figure number lists (unless you explicitly want to, which you still can).

Finally, is this really a close bug?

In [20]: fig=plot(range(10))

In [21]: close(fig)
ERROR: Unrecognized argument type to close

It sounds to me from reading the docstring like this should work, but maybe I just misunderstood things...

Regards,

f