python without - Is there a way to detach matplotlib plots so that the computation can continue?
display how (16)
After these instructions in the Python interpreter one gets a window with a plot:
from matplotlib.pyplot import * plot([1,2,3]) show() # other code
Unfortunately, I don't know how to continue to interactively explore the figure created by
show() while the program does further calculations.
Is it possible at all? Sometimes calculations are long and it would help if they would proceed during examination of intermediate results.
In my opinion, the answers in this thread provide methods which don't work for every systems and in more complex situations like animations. I suggest to have a look at the answer of MikeTex in the following thread, where a robust method has been found: How to wait until matplotlib animation ends?
Use the keyword 'block' to override the blocking behavior, e.g.
from matplotlib.pyplot import show, plot plot(1) show(block=False) # your code
to continue your code.
I also wanted my plots to display run the rest of the code (and then keep on displaying) even if there is an error (I sometimes use plots for debugging). I coded up this little hack so that any plots inside this
with statement behave as such.
This is probably a bit too non-standard and not advisable for production code. There is probably a lot of hidden "gotchas" in this code.
from contextlib import contextmanager @contextmanager def keep_plots_open(keep_show_open_on_exit=True, even_when_error=True): ''' To continue excecuting code when plt.show() is called and keep the plot on displaying before this contex manager exits (even if an error caused the exit). ''' import matplotlib.pyplot show_original = matplotlib.pyplot.show def show_replacement(*args, **kwargs): kwargs['block'] = False show_original(*args, **kwargs) matplotlib.pyplot.show = show_replacement pylab_exists = True try: import pylab except ImportError: pylab_exists = False if pylab_exists: pylab.show = show_replacement try: yield except Exception, err: if keep_show_open_on_exit and even_when_error: print "*********************************************" print "Error early edition while waiting for show():" print "*********************************************" import traceback print traceback.format_exc() show_original() print "*********************************************" raise finally: matplotlib.pyplot.show = show_original if pylab_exists: pylab.show = show_original if keep_show_open_on_exit: show_original() # *********************** # Running example # *********************** import pylab as pl import time if __name__ == '__main__': with keep_plots_open(): pl.figure('a') pl.plot([1,2,3], [4,5,6]) pl.plot([3,2,1], [4,5,6]) pl.show() pl.figure('b') pl.plot([1,2,3], [4,5,6]) pl.show() time.sleep(1) print '...' time.sleep(1) print '...' time.sleep(1) print '...' this_will_surely_cause_an_error
If/when I implement a proper "keep the plots open (even if an error occurs) and allow new plots to be shown", I would want the script to properly exit if no user interference tells it otherwise (for batch execution purposes).
I may use something like a time-out-question "End of script! \nPress p if you want the plotting output to be paused (you have 5 seconds): " from https://.com/questions/26704840/corner-cases-for-my-wait-for-user-input-interruption-implementation.
On my system show() does not block, although I wanted the script to wait for the user to interact with the graph (and collect data using 'pick_event' callbacks) before continuing.
In order to block execution until the plot window is closed, I used the following:
fig = plt.figure() ax = fig.add_subplot(1,1,1) ax.plot(x,y) # set processing to continue when window closed def onclose(event): fig.canvas.stop_event_loop() fig.canvas.mpl_connect('close_event', onclose) fig.show() # this call does not block on my system fig.canvas.start_event_loop_default() # block here until window closed # continue with further processing, perhaps using result from callbacks
Note, however, that canvas.start_event_loop_default() produced the following warning:
C:\Python26\lib\site-packages\matplotlib\backend_bases.py:2051: DeprecationWarning: Using default event loop until function specific to this GUI is implemented warnings.warn(str,DeprecationWarning)
although the script still ran.
It is better to always check with the library you are using if it supports usage in a non-blocking way.
But if you want a more generic solution, or if there is no other way, you can run anything that blocks in a separated process by using the
multprocessing module included in python. Computation will continue:
from multiprocessing import Process from matplotlib.pyplot import plot, show def plot_graph(*args): for data in args: plot(data) show() p = Process(target=plot_graph, args=([1, 2, 3],)) p.start() print 'yay' print 'computation continues...' print 'that rocks.' print 'Now lets wait for the graph be closed to continue...:' p.join()
That has the overhead of launching a new process, and is sometimes harder to debug on complex scenarios, so I'd prefer the other solution (using
matplotlib's nonblocking API calls)
If you want to open multiple figures, while keeping them all opened, this code worked for me:
In many cases it is more convenient til save the image as a .png file on the hard drive. Here is why:
- You can open it, have a look at it and close it down any time in the process. This is particularly convenient when your application is running for a long time.
- Nothing pops up and you are not forced to have the windows open. This is particularly convenient when you are dealing with many figures.
- Your image is accessible for later reference and is not lost when closing the figure window.
- The only thing I can think of is that you will have to go and finder the folder and open the image yourself.
If you are working in console, i.e.
IPython you could use
plt.show(block=False) as pointed out in the other answers. But if you're lazy you could just type:
Which will be the same.
IMPORTANT: Just to make something clear. I assume that the commands are inside a
.py script and the script is called using e.g.
python script.py from the console.
A simple way that works for me is:
- Use the block = False inside show : plt.show(block = False)
- Use another show() at the end of the .py script.
plt.imshow(*something*) plt.colorbar() plt.xlabel("true ") plt.ylabel("predicted ") plt.title(" the matrix") # Add block = False plt.show(block = False) # OTHER CALCULATIONS AND CODE # the next is the last line of my script plt.show()
from matplotlib.pyplot import * plot([1,2,3]) show(block=False) # other code # [...] # Put show() # at the very end of your script # to make sure Python doesn't bail out # before you finished examining.
show() documentation says:
In non-interactive mode, display all figures and block until the figures have been closed; in interactive mode it has no effect unless figures were created prior to a change from non-interactive to interactive mode (not recommended). In that case it displays the figures but does not block.
A single experimental keyword argument,
block, may be set to
Falseto override the blocking behavior described above.
Here is an update (python 3.6.5 on Windows 10).
I tried all sorts of combinations - the simplest I've found is just to use
pause(0.01) after each plot - no need for a
show() for the intermediate plots - then a single
show() at the end ensures you can look at the final plot before termination.
As an example, here is a bit of code I use to check speed for various array sizes - higher plotted values are higher speeds... there are 10 overlaid plots...
from pylab import * import matplotlib.pyplot as plt from time import * ttot=clock(); mmax=6;npts=20;nplts=10; x=[int(a+0.5) for a in 10**linspace(0,mmax,npts)] for nrun in range(nplts): j=0;aa=1;bb=1;b=1; tim=zeros(npts) for n in x: aa=rand(n);bb=aa;b=aa; if n<100:m=10000 elif n<5000:m=1000 elif n<20000:m=100 else:m=100 tt=clock() for ii in range(1,m+1): b=aa*bb+aa tt1=clock()-tt tim[j]=tt1/n/m j=j+1 print(n,2/(tt1/n/m)/1e6); plt.semilogx(x,2/tim/1e6) pause(0.01) print(clock()-ttot) show()
plt.figure(1) plt.imshow(your_first_image) plt.figure(2) plt.imshow(your_second_image) plt.show(block=False) # That's important raw_input("Press ENTER to exist") # Useful when you run your Python script from the terminal and you want to hold the running to see your figures until you press Enter
In my case, I wanted to have several windows pop up as they are being computed. For reference, this is the way:
from matplotlib.pyplot import draw, figure, show f1, f2 = figure(), figure() af1 = f1.add_subplot(111) af2 = f2.add_subplot(111) af1.plot([1,2,3]) af2.plot([6,5,4]) draw() print 'continuing computation' show()
PS. A quite useful guide to matplotlib's OO interface.
If I understand the question properly, using Ipython (or Ipython QT or Ipython notebook) would allow you to work interactively with the chart while calculations go one in the background. http://ipython.org/
I had to also add
plt.pause(0.001) to my code to really make it working inside a for loop (otherwise it would only show the first and last plot):
import matplotlib.pyplot as plt plt.scatter(, ) plt.draw() plt.show(block=False) for i in range(10): plt.scatter([i], [i+1]) plt.draw() plt.pause(0.001)
tick_params method is very useful for stuff like this. This code turns off major and minor ticks and removes the labels from the x-axis.
from matplotlib import pyplot as plt plt.plot(range(10)) plt.tick_params( axis='x', # changes apply to the x-axis which='both', # both major and minor ticks are affected bottom=False, # ticks along the bottom edge are off top=False, # ticks along the top edge are off labelbottom=False) # labels along the bottom edge are off plt.show() plt.savefig('plot') plt.clf()