Closing pyplot windows
Asked Answered
R

4

44

Final Edit:

What I found on the subject of closing pyplot windows is that it really probably shouldn't be done using pyplot. SRK gives a great example on how to handle plots that will be updated in his answer below. Also I have stumbled across how to put pyplot plots into a Tkinter window, and Tkinter is much more adept at opening and closing windows than pyplot. Here is how to put a pyplot plot into a Tk window also this is a good example.

/Final Edit

I would like to be able to display several plots and then be able to close (remove from screen) them individually from some code input, but I don't know the code input to do this.

Below is what I have tried so far. I have played around with the position of the show and close commands, but the only real result I have gotten from this is to have one or the other plot not come up, but I have not been able to remove a plot from the screen. I have been inserting a raw_input() to create pauses.

Edit: These plots are being called from a Tkinter gui and if there is a better way to do this from that direction I would be glad to hear it.

Any input would be appreciated, thanks.

import matplotlib.pyplot as plt

a = range(0,10)
b = range(0,20,2)
c = range(0,30,3)
d = range(0,40,4)

plot1 = plt.figure()
plt.plot(a,b, 'r-o')

plt.show()

plt.close()

plot2 = plt.figure()
plt.plot(c,d, 'b-o')

plt.show()
plt.close() 

Edit Code: This didn't work either.

plot1 = plt.figure(1)
plt.plot(a,b, 'r-o')

plot2 = plt.figure(2)
plt.plot(c,d, 'b-o')
#plt.close(1)
#this will prevent plot1 from being displayed
plt.show()
plt.close(1)  # or ('all') or (plot1)
Regular answered 21/6, 2012 at 14:51 Comment(0)
E
84

plt.close() will close current instance.

plt.close(2) will close figure 2

plt.close(plot1) will close figure with instance plot1

plt.close('all') will close all fiures

Found here.

Remember that plt.show() is a blocking function, so in the example code you used above, plt.close() isn't being executed until the window is closed, which makes it redundant.

You can use plt.ion() at the beginning of your code to make it non-blocking, although this has other implications.

EXAMPLE

After our discussion in the comments, I've put together a bit of an example just to demonstrate how the plot functionality can be used.

Below I create a plot:

fig = plt.figure(figsize=plt.figaspect(0.75))
ax = fig.add_subplot(1, 1, 1)
....
par_plot, = plot(x_data,y_data, lw=2, color='red')

In this case, ax above is a handle to a pair of axes. Whenever I want to do something to these axes, I can change my current set of axes to this particular set by calling axes(ax).

par_plot is a handle to the line2D instance. This is called an artist. If I want to change a property of the line, like change the ydata, I can do so by referring to this handle.

I can also create a slider widget by doing the following:

axsliderA = axes([0.12, 0.85, 0.16, 0.075])
sA = Slider(axsliderA, 'A', -1, 1.0, valinit=0.5)
sA.on_changed(update)

The first line creates a new axes for the slider (called axsliderA), the second line creates a slider instance sA which is placed in the axes, and the third line specifies a function to call when the slider value changes (update).

My update function could look something like this:

def update(val):
    A = sA.val
    B = sB.val
    C = sC.val
    y_data = A*x_data*x_data + B*x_data + C
    par_plot.set_ydata(y_data)
    draw()

The par_plot.set_ydata(y_data) changes the ydata property of the Line2D object with the handle par_plot.

The draw() function updates the current set of axes.

Putting it all together:

from pylab import *
import matplotlib.pyplot as plt
import numpy

def update(val):
    A = sA.val
    B = sB.val
    C = sC.val
    y_data = A*x_data*x_data + B*x_data + C
    par_plot.set_ydata(y_data)
    draw()


x_data = numpy.arange(-100,100,0.1);

fig = plt.figure(figsize=plt.figaspect(0.75))
ax = fig.add_subplot(1, 1, 1)
subplots_adjust(top=0.8)

ax.set_xlim(-100, 100);
ax.set_ylim(-100, 100);
ax.set_xlabel('X')
ax.set_ylabel('Y')

axsliderA = axes([0.12, 0.85, 0.16, 0.075])
sA = Slider(axsliderA, 'A', -1, 1.0, valinit=0.5)
sA.on_changed(update)

axsliderB = axes([0.43, 0.85, 0.16, 0.075])
sB = Slider(axsliderB, 'B', -30, 30.0, valinit=2)
sB.on_changed(update)

axsliderC = axes([0.74, 0.85, 0.16, 0.075])
sC = Slider(axsliderC, 'C', -30, 30.0, valinit=1)
sC.on_changed(update)

axes(ax)
A = 1;
B = 2;
C = 1;
y_data = A*x_data*x_data + B*x_data + C;

par_plot, = plot(x_data,y_data, lw=2, color='red')

show()

A note about the above: When I run the application, the code runs sequentially right through (it stores the update function in memory, I think), until it hits show(), which is blocking. When you make a change to one of the sliders, it runs the update function from memory (I think?).

This is the reason why show() is implemented in the way it is, so that you can change values in the background by using functions to process the data.

Engineering answered 21/6, 2012 at 15:16 Comment(7)
I tried that stuff and it didn't work (see edit). It does clear the memory of that instance, but it does not remove the plot from the screen. Any other ideas?Regular
I've added the reason why. plt.show() is a blocking function.Engineering
Thanks. So, what does this mean for my closing the shown plot? I guess the real question I have then it how do I deal with the windows created by the plt.show() function. Do you have any other ideas to handle that?Regular
Can you give me more of an idea of what you're trying to do? Usually I allow the user to close the windows, or detect when the main window is closed, and then close them all. It's not very common to close windows from within the code in the way you suggest.Engineering
I have a Tk gui that when asked will produce the plots, and if the user needs to tweak the plots then some variables are tweaked and the plots regenerated w/ tweaks. I just wanted to cut down on user input and have the program destroy the old plots before it makes the new ones, but I guess it would not be the end of the world if the user had to manually do this. Are you saying manual is the way to go in this case? Thanks!Regular
I tried using the plt.ion() like you mentioned, but with that I cannot keep a plot on the screen with or with out the plt.close(). Also if I use a raw_input() it causes the data not to be plotted and the program to hang until I enter data. Are these the "other implications" you mentioned?Regular
Ja, python isn't really supposed to be used with plt.ion(). The show() function is blocking for a reason. I'll elaborate more in an answer edit.Engineering
A
10

Please use

plt.show(block=False)
plt.close('all')
Asdic answered 21/2, 2020 at 5:24 Comment(0)
E
0

For those that come here because not wanting to close the matplotlib.pyplot, but actually want it to not be shown at all, change the backend. In my case, I use Jupytext to make both ipynb and .py files. That way, I want the .py file to not opening any windows (useful for pytest for example).

import sys

if 'ipykernel' not in sys.modules:
    import matplotlib
    matplotlib.use('Agg')  # don't show plot

Inspired by this asnwer.

Execute answered 3/11, 2022 at 4:12 Comment(0)
W
0

Hint to use plt.pause to not block is useful!

You can define a little function like this:

def autoclose_plot(t_show_plot=10):
    print(f'automatically closing plot in {t_show_plot}s...')
    plt.pause(t_show_plot)
    plt.close()
Wellspoken answered 6/11, 2023 at 10:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.