7

I have a loop like this

#!/usr/bin/env python
import matplotlib.pyplot as p

for i in xrange(N):
    # Create my_image here

    # Display this image
    p.figure()
    p.imshow(my_image)
    p.show()
    p.close()

This works fine when i=0. For the program to continue, I need to close the new figure created by pyplot. For all other loop iterations (i>0), another new figure is not created, a plot is not presented and the program just moves on. Why does closing a figure making pyplot unable to open new one (like MATLAB)?

The behavior which I expect is:

  1. Execution stops at p.show()
  2. When I close the figure, execution continues
  3. When p.show() is encountered again, the new image is displayed.
  4. Repeat step 2 until no more plot to show
Zephyr
  • 11,891
  • 53
  • 45
  • 80
Dat Chu
  • 10,822
  • 13
  • 58
  • 82
  • I am able to create sequential plots for N>=2. What IDE are you using (if you are using one)? I have to manually close the plot before I get the next, so in this example `p.close()` is pointless. – Paul Mar 01 '11 at 18:38
  • I use PyCharm to write the script and run it. I notice that this problem seems to occur only when running as a script instead of in ipython -pylab – Dat Chu Mar 01 '11 at 19:29

5 Answers5

5

There might be a better way to animate imshow's, but this should work in a pinch. It's a lightly modified version of an animation example from the docs.

# For detailed comments on animation and the techniqes used here, see
# the wiki entry http://www.scipy.org/Cookbook/Matplotlib/Animations

import matplotlib
matplotlib.use('TkAgg')

import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
import matplotlib.cm as cm

import sys
import numpy as np
import time

ax = plt.subplot(111)
canvas = ax.figure.canvas

delta=0.025
x=y= np.arange(-3.0, 3.0, delta)
x,y=np.meshgrid(x, y)
z1=mlab.bivariate_normal(x, y, 1.0, 1.0, 0.0, 0.0)
z2=mlab.bivariate_normal(x, y, 1.5, 0.5, 1, 1)
z=z2-z1  # difference of Gaussians

def run(z):
    fig=plt.gcf()
    for i in range(10):
        plt.imshow(z, interpolation='bilinear', cmap=cm.gray,
                  origin='lower', extent=[-3,3,-3,3])
        canvas.draw()
        plt.clf()
        z**=2

manager = plt.get_current_fig_manager()
manager.window.after(100, run, z)
plt.show()
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • 1
    Your solution is great for animation. But what I want is not animation, I just want a simple MATLAB-like behavior where I can view a certain image/matrix as my algorithm runs. – Dat Chu Mar 01 '11 at 19:34
  • @Dat Chu: I don't know MATLAB's behavior. – unutbu Mar 01 '11 at 19:38
  • @Dat Chu: Do you require that the code execution pause while the plot is being displayed? – Paul Mar 01 '11 at 19:45
  • @Dat Chu: You might be able to get your script to run (like inside `ipython -pylab`) by adding `p.ion()`. This puts matplotlib in interactive mode. Every matplotlib command is displayed immediately. This might be okay for debugging purposes, but I think it is frowned upon for "serious" scripts. For such situations I think you are encouraged to use a figure manager, like shown above. – unutbu Mar 01 '11 at 19:46
3

It might be from a bug in previous versions of matplotlib. I was having a similar problem when I issued sequential show() commands -- only the first would show (and stay); but, when I updated matplotlib to 1.0.1 the problem went away.

Andy Barbour
  • 8,783
  • 1
  • 24
  • 35
  • I updated to Matplotlib SVN and the problem goes away. I guess it is a bug. – Dat Chu Mar 01 '11 at 23:18
  • 2
    this was 'what's new' for version 1.0.1: A long standing request is to support multiple calls to show(). This has been difficult because it is hard to get consistent behavior across operating systems, user interface toolkits and versions. Eric Firing has done a lot of work on rationalizing show across backends, with the desired behavior to make show raise all newly created figures and block execution until they are closed. Repeated calls to show should raise newly created figures since the last call... – wim Jun 02 '11 at 05:22
0

Only set

import matplotlib.pyplot as plt

If you set for example as well :

import matplotlib
matplotlib.use('Agg')

This is interacting on the whole application. And cause in my case this Issue

niek tuytel
  • 899
  • 7
  • 18
0

After tinkering around with unutbu's example, I found a behavior that I could normally and debug with PyDev where I could progressively see the plots.

import time, threading
import numpy
from matplotlib.pyplot import *

x = numpy.linspace(0, 10)
y = x**2

def main():
    plot(x, x)
    draw()
    time.sleep(2)
    plot(x, y)
    draw()

thread = threading.Thread()
thread.run = main

manager = get_current_fig_manager()
manager.window.after(100, thread.start)
figure(1)
show()
eacousineau
  • 3,457
  • 3
  • 34
  • 37
  • Note that if you have multiple figures, I'd suggest you 'preallocate' them in before you show() the figure windows. Otherwise, any new figure windows seem to be confined to the calling thread. – eacousineau Jul 28 '11 at 19:43
0

I have long been looking into this problem and I may have a solution although I haven't thoroughly tested it yet.

The key is in writing code more like MatLab, name your figures and then call them to show().

eg.

 from matplotlib import pyplot as plt

 fig1 = plt.figure()
 fig2 = plt.figure()

 fig1.show()
 fig2.show()

This might work for animations and plotting at different stages

Zephyr
  • 11,891
  • 53
  • 45
  • 80
Kevin
  • 761
  • 1
  • 6
  • 11