savefig problem in interactive mode

Hi all, I have a question: in interactive (ipython

    > -pylab) mode, a call to savefig('foo.eps') (either via
    > %run or straight at the prompt) still pops up a GUI plot
    > window. If I run the same script from a system command
    > line, the eps is made, but no GUI opens (what I consider
    > the correct behavior).

    > Is this something that should be fixed in ipython or in
    > matplotlib?

For the sake of clarity, let's consider the canonical script

    import matplotlib
    matplotlib.use('PS')
    from pylab import *
    plot([1,2,3])
    savefig('test.ps')
    show()

When run from the shell, it does what you want -- makes a PS with no
popup. It fails in ipython (pops up a window) because you have
already selected a backend and all pylab commands are directed to that
backend.

How to fix it?

* ipython invokes an external python process to run each script. Of
   course you pay a performance hit here, and this would likely change
   the meaning of the way run is meant to work (eg, are local ipython
   shell vars available in a "run" script.

* provide better support for backend switching in matplotlib. Eg,
   allowing you at any time to call matplotlib.use. Currently, this
   only works before the import of pylab. It may be possible to write
   a pylab.use that simply rebinds the 4 backend functions:
   new_figure_manager, error_msg, draw_if_interactive, show. At the
   end of a "run", you could simply do a
   matplotlib.pylab.use(defaultBackend) to rebind. run could be
   enhanced to support backend switching

     run somescript.py -dPS

   much like one can do from the shell.

  You know more about python module reloading than I do. How does one
  force a module to reload, eg if I wanted to set the rc 'backend'
  param and then do, eg

    rcParams['backend'] = 'PS'
    from backends import new_figure_manager, error_msg, draw_if_interactive, show

  to get new symbols?

There may be another way, but those two come to mind. I'll mull it
over.

    > ps. Yes, John, I've finally started to use matplotlib
    > for my own work. Brace yourself, I'm compiling a pretty
    > hefty list of things to do. I hope you don't plan on
    > sleeping much in the coming months :wink:

Well, I knew it was coming.... Stress tests are usually a good
thing. Plus, I'm sure you can't do anything to interrupt my sleep
that my 3 kids haven't already mastered!

JDH

John Hunter wrote:

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

    > Hi all, I have a question: in interactive (ipython
    > -pylab) mode, a call to savefig('foo.eps') (either via
    > %run or straight at the prompt) still pops up a GUI plot
    > window. If I run the same script from a system command
    > line, the eps is made, but no GUI opens (what I consider
    > the correct behavior).

    > Is this something that should be fixed in ipython or in
    > matplotlib?

For the sake of clarity, let's consider the canonical script

    import matplotlib
    matplotlib.use('PS')
    from pylab import *
    plot([1,2,3])
    savefig('test.ps')
    show()

When run from the shell, it does what you want -- makes a PS with no
popup. It fails in ipython (pops up a window) because you have
already selected a backend and all pylab commands are directed to that
backend.

How to fix it?

* ipython invokes an external python process to run each script. Of
   course you pay a performance hit here, and this would likely change
   the meaning of the way run is meant to work (eg, are local ipython
   shell vars available in a "run" script.

Not good. If users want this, they can always just call !python foo.py and be done. The whole point of %run is to benefit from enhanced tracebacks, debug hooks, variable access, etc. Doing that across processes is basically impossible.

* provide better support for backend switching in matplotlib. Eg,
   allowing you at any time to call matplotlib.use. Currently, this
   only works before the import of pylab. It may be possible to write
   a pylab.use that simply rebinds the 4 backend functions:
   new_figure_manager, error_msg, draw_if_interactive, show. At the
   end of a "run", you could simply do a
   matplotlib.pylab.use(defaultBackend) to rebind. run could be
   enhanced to support backend switching

     run somescript.py -dPS

   much like one can do from the shell.

  You know more about python module reloading than I do. How does one
  force a module to reload, eg if I wanted to set the rc 'backend'
  param and then do, eg

     rcParams['backend'] = 'PS'
    from backends import new_figure_manager, error_msg, draw_if_interactive, show

  to get new symbols?

You have to carefully wire reload() calls into the proper backends. It's doable, but doing it generically and with all the complex mpl backend machinery would likely take a bit of effort.

There may be another way, but those two come to mind. I'll mull it
over.

It's not a big deal anyway, just something to think about. My concern is that if I run from ipython (for testing/debugging) some big script which is wired to dump hundreds of EPS figures to a plots directory (yes, I do stuff like that with Gnuplot), my screen is going to be instantly flooded with hundreds of windows.

But for now, I'd rather see the tk close bug fixed and the figure() improvements I referred to in my other mail :wink:

Cheers,

f