I have a function that does my plotting. Something like:
def myplot(data):
fig, ax = plt.subplots(10,10, figsize=(18,12))
for i in range(10):
ax[i/10, i%10].imshow(data[i/10, i%10],cmap=plt.cm.gist_yarg,
interpolation='nearest', aspect='equal')
plt.show()
#print the fist plot
myplot(data1)
#print another
myplot(data2)
When I run the script using ipython myscript.py it will pause after myplot(data1) and won't resume until I close the plot window. How can I keep multiple windows open?
Sure, just remove your plt.show() from the loop and put it at the end of your script. Every time you create a new figure (as in the plt.subplots(...) function), a new window is created.
Related
Coming from a R background I am now moving on to Python and would like to learn Spyder 4 as a next tool alongside RStudio for data analysis. I am running into a problem however trying to learn matplotlib.
Having this code:
import matplotlib.pyplot as plt
x = [1,2,3,4,5,6,7,8,5,4,3,3,2,4,5,6]
y = [5,5,6,7,8,3,4,5,6,7,8,6,5,4,3,2]
plt.xlabel('x-as')
plt.ylabel('y-as')
plt.title('My title')
plt.legend()
plt.scatter(x, y, label = 'test')
plt.show()
This will not wait for the call to plt.show(), but instead plot a graph for each of the calls to a matplotlib functions, in the plot viewer section of the IDE.
How would I make Spyder 4 wait untill I actually want it to draw the graph?
You want to put fig = plt.figure() before the rest of the plotting lines. Also, you want to put plt.legend() after the scatter function so that the label shows.
Background
With the help of the following, I have created a dynamically updating plot
Dynamically updating plot in matplotlib
Updating a plot in python's matplotlib
How to update a plot in matplotlib?
Plot code
plt.ion()
fig_analysis = plt.figure()
for i in range(5):
ax = fig_analysis.add_subplot(211)
l1, = ax.plot(np.linspace(0, 200, simulation_time), variable_1)
ax.set_ylabel(r'$Variable\ 1$')
ax = fig_analysis.add_subplot(212)
l2, = ax.plot(np.linspace(0, 200, simulation_time), variable_2)
ax.set_ylabel(r'$Variable\ 2$')
ax.set_xlabel(r'$years$')
fig_analysis.canvas.draw()
plt.pause(0.5)
Behaviour
This code creates a plot and updates it. However, it closes the final plot after completion of the loop
Question
How should I modify the code to ensure that at the end of the loop, the program doesn't close the plot window, and I can save the image as I want.
Manual solution
One of the ways of achieving this is to manually pause the program. However, as runtime of my program is not fixed, it is difficult to implement this strategy.
Add
plt.ioff() # turn interactive mode off
plt.show()
at the end of the code.
import time
import matplotlib.pyplot as plt
xvalues = [1,2,3,4,5,6,7,8,9]
yvalues = [1,3,5,9,8,7,8,5,6]
plt.xlabel('time in hours')
plt.ylabel('ph')
plt.plot([xvalues],[yvalues], 'ro')
plt.axis ([0,10,0,15])
plt.show()
time.sleep(1)
clf()
I want to make a figure with a plot, and then delete the figure after a specific time. But when I try it I get the error: undefined name on the last line where I want to delete the figure.
Concerning the error: clf() is not defined, you would want to use plt.clf() instead.
However, plt.clf() will not delete the figure. It only clears the figure. You may want to read
When to use cla(), clf() or close() for clearing a plot in matplotlib?
Unfortunately it is not entirely clear from the question what the expected behaviour of the code is. If running it as a script, the figure window will stay open until you manually close it; only then any code after plt.show() will be executed. The use of time.sleep() would then not make any sense and deleting the figure is unnecessary, since the script stops afterwards anyways, clearing the memory.
If instead you want to run this in interactive mode (plt.ion()) you can use plt.pause(1) to make a 1 second pause and then close the figure.
import matplotlib.pyplot as plt
plt.ion()
xvalues = [1,2,3,4,5,6,7,8,9]
yvalues = [1,3,5,9,8,7,8,5,6]
plt.xlabel('time in hours')
plt.ylabel('ph')
plt.plot([xvalues],[yvalues], 'ro')
plt.axis ([0,10,0,15])
plt.show()
plt.pause(1)
plt.close()
I am experiencing some problems with matplotlib.... I can't open 2 windows at once to display a image with show(), it seems that the script stops at the line i use show and doesn't continue unless I close the display manually. Is there a way to close the figure window within the scrip?
the following code doesn't run as I want:
import matplotlib.pyplot as plt
from time import sleep
from scipy import eye
plt.imshow(eye(3))
plt.show()
sleep(1)
plt.close()
plt.imshow(eye(2))
plt.show()
I expected the first window to close after 1 second and then opening the second one, but the window doesn't close until I close it myself. Am I doing something wrong, or is it the way it is supposed to be?
plt.show() is a blocking function.
Essentially, if you want two windows to open at once, you need to create two figures, and then use plt.show() at the end to display them. In fact, a general rule of thumb is that you set up your plots, and plt.show() is the very last thing you do.
So in your case:
fig1 = plt.figure(figsize=plt.figaspect(0.75))
ax1 = fig1.add_subplot(1, 1, 1)
im1, = plt.imshow(eye(3))
fig2 = plt.figure(figsize=plt.figaspect(0.75))
ax2 = fig2.add_subplot(1, 1, 1)
im2, = plt.imshow(eye(2))
plt.show()
You can switch between the plots using axes(ax2).
I put together a comprehensive example demonstrating why the plot function is blocking and how it can be used in an answer to another question: https://stackoverflow.com/a/11141305/1427975.
I use PyScripter and Python 2.7 and also had the problem of plt.show() blocking all executions until you manually close the figures.
I found that changing the Python engine to 'remote (Wx)' lets the script run after plt.show() - so could close figures with plt.close().
Say that I have two figures in matplotlib, with one plot per figure:
import matplotlib.pyplot as plt
f1 = plt.figure()
plt.plot(range(0,10))
f2 = plt.figure()
plt.plot(range(10,20))
Then I show both in one shot
plt.show()
Is there a way to show them separately, i.e. to show just f1?
Or better: how can I manage the figures separately like in the following 'wishful' code (that doesn't work):
f1 = plt.figure()
f1.plot(range(0,10))
f1.show()
Sure. Add an Axes using add_subplot. (Edited import.) (Edited show.)
import matplotlib.pyplot as plt
f1 = plt.figure()
f2 = plt.figure()
ax1 = f1.add_subplot(111)
ax1.plot(range(0,10))
ax2 = f2.add_subplot(111)
ax2.plot(range(10,20))
plt.show()
Alternatively, use add_axes.
ax1 = f1.add_axes([0.1,0.1,0.8,0.8])
ax1.plot(range(0,10))
ax2 = f2.add_axes([0.1,0.1,0.8,0.8])
ax2.plot(range(10,20))
With Matplotlib prior to version 1.0.1, show() should only be called once per program, even if it seems to work within certain environments (some backends, on some platforms, etc.).
The relevant drawing function is actually draw():
import matplotlib.pyplot as plt
plt.plot(range(10)) # Creates the plot. No need to save the current figure.
plt.draw() # Draws, but does not block
raw_input() # This shows the first figure "separately" (by waiting for "enter").
plt.figure() # New window, if needed. No need to save it, as pyplot uses the concept of current figure
plt.plot(range(10, 20))
plt.draw()
# raw_input() # If you need to wait here too...
# (...)
# Only at the end of your program:
plt.show() # blocks
It is important to recognize that show() is an infinite loop, designed to handle events in the various figures (resize, etc.). Note that in principle, the calls to draw() are optional if you call matplotlib.ion() at the beginning of your script (I have seen this fail on some platforms and backends, though).
I don't think that Matplotlib offers a mechanism for creating a figure and optionally displaying it; this means that all figures created with figure() will be displayed. If you only need to sequentially display separate figures (either in the same window or not), you can do like in the above code.
Now, the above solution might be sufficient in simple cases, and for some Matplotlib backends. Some backends are nice enough to let you interact with the first figure even though you have not called show(). But, as far as I understand, they do not have to be nice. The most robust approach would be to launch each figure drawing in a separate thread, with a final show() in each thread. I believe that this is essentially what IPython does.
The above code should be sufficient most of the time.
PS: now, with Matplotlib version 1.0.1+, show() can be called multiple times (with most backends).
I think I am a bit late to the party but...
In my opinion, what you need is the object oriented API of matplotlib. In matplotlib 1.4.2 and using IPython 2.4.1 with Qt4Agg backend, I can do the following:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1) # Creates figure fig and add an axes, ax.
fig2, ax2 = plt.subplots(1) # Another figure
ax.plot(range(20)) #Add a straight line to the axes of the first figure.
ax2.plot(range(100)) #Add a straight line to the axes of the first figure.
fig.show() #Only shows figure 1 and removes it from the "current" stack.
fig2.show() #Only shows figure 2 and removes it from the "current" stack.
plt.show() #Does not show anything, because there is nothing in the "current" stack.
fig.show() # Shows figure 1 again. You can show it as many times as you want.
In this case plt.show() shows anything in the "current" stack. You can specify figure.show() ONLY if you are using a GUI backend (e.g. Qt4Agg). Otherwise, I think you will need to really dig down into the guts of matplotlib to monkeypatch a solution.
Remember that most (all?) plt.* functions are just shortcuts and aliases for figure and axes methods. They are very useful for sequential programing, but you will find blocking walls very soon if you plan to use them in a more complex way.
Perhaps you need to read about interactive usage of Matplotlib. However, if you are going to build an app, you should be using the API and embedding the figures in the windows of your chosen GUI toolkit (see examples/embedding_in_tk.py, etc).
None of the above solutions seems to work in my case, with matplotlib 3.1.0 and Python 3.7.3. Either both the figures show up on calling show() or none show up in different answers posted above.
Building upon #Ivan's answer, and taking hint from here, the following seemed to work well for me:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1) # Creates figure fig and add an axes, ax.
fig2, ax2 = plt.subplots(1) # Another figure
ax.plot(range(20)) #Add a straight line to the axes of the first figure.
ax2.plot(range(100)) #Add a straight line to the axes of the first figure.
# plt.close(fig) # For not showing fig
plt.close(fig2) # For not showing fig2
plt.show()
As #arpanmangal, the solutions above do not work for me (matplotlib 3.0.3, python 3.5.2).
It seems that using .show() in a figure, e.g., figure.show(), is not recommended, because this method does not manage a GUI event loop and therefore the figure is just shown briefly. (See figure.show() documentation). However, I do not find any another way to show only a figure.
In my solution I get to prevent the figure for instantly closing by using click events. We do not have to close the figure — closing the figure deletes it.
I present two options:
- waitforbuttonpress(timeout=-1) will close the figure window when clicking on the figure, so we cannot use some window functions like zooming.
- ginput(n=-1,show_clicks=False) will wait until we close the window, but it releases an error :-.
Example:
import matplotlib.pyplot as plt
fig1, ax1 = plt.subplots(1) # Creates figure fig1 and add an axes, ax1
fig2, ax2 = plt.subplots(1) # Another figure fig2 and add an axes, ax2
ax1.plot(range(20),c='red') #Add a red straight line to the axes of fig1.
ax2.plot(range(100),c='blue') #Add a blue straight line to the axes of fig2.
#Option1: This command will hold the window of fig2 open until you click on the figure
fig2.waitforbuttonpress(timeout=-1) #Alternatively, use fig1
#Option2: This command will hold the window open until you close the window, but
#it releases an error.
#fig2.ginput(n=-1,show_clicks=False) #Alternatively, use fig1
#We show only fig2
fig2.show() #Alternatively, use fig1
As of November 2020, in order to show one figure at a time, the following works:
import matplotlib.pyplot as plt
f1, ax1 = plt.subplots()
ax1.plot(range(0,10))
f1.show()
input("Close the figure and press a key to continue")
f2, ax2 = plt.subplots()
ax2.plot(range(10,20))
f2.show()
input("Close the figure and press a key to continue")
The call to input() prevents the figure from opening and closing immediately.