In matplotlib, is there a simple way of plotting a figure without interrupting the control flow of the script?
Using pseudocode for clarity, here's what I'm trying to achieve:
fig1 = figure()
fig1.plot_a_figure(datasets)
for dataset in datasets:
results = analyze(dataset) # this takes several minutes
update(fig1)
pop_up_another_figure(results) # would like to have a look at this one
# while the next dataset is being processed
Of course, I can just savefig() these intermediate figures, but I only need a quick glance at a them and it would be the best to have them just pop up on the screen in real time.
EDIT: A runnable example:
#!/usr/bin/python
import pylab as plb
import matplotlib.pyplot as plt
fig1=plt.figure(1)
ax = fig1.add_subplot(1,1,1)
ax.plot([1,2,3],[4,5,6],'ro-')
#fig1.show() # this does not show a figure if uncommented
plt.show() # until the plot window is closed, the next line is not executed
print "doing something else now"
Am I missing something very very basic?
Matplotlib supports rich interactive figures by embedding figures into a GUI window. The basic interactions of panning and zooming in an Axes to inspect your data is 'baked in' to Matplotlib.
But did you know that it is also possible to create interactive plots with matplotlib directly, provided you are using an interactive backend? This article will look at two such backends and how they render interactivity within the notebooks, using only matplotlib.
Matplotlib can be used in an interactive or non-interactive modes. In the interactive mode, the graph display gets updated after each statement. In the non-interactive mode, the graph does not get displayed until explicitly asked to do so.
Show() would help whenever there is no interactive plot. fig. Show() would help to display all the figures if it is interactive. Let's take an example to observe the difference between plt.
First things first, don't forget a simple alternative is to just make new figure windows with plt.figure(2)
, plt.figure(3)
etc. If you really want to update the existing figure window, you had better keep a handle on your lines object with
h = ax.plot([1,2,3],[4,5,6],'ro-')
And then later you would be doing something like:
h[0].set_data(some_new_results)
ax.figure.canvas.draw()
As for the real meat of the question, if you're still battling with this read on..
You need to enable interactive mode if you want plt.show()
to be non-blocking. To modify your runnable example so that "doing something else now" would print immediately, as opposed to waiting for the figure window to be closed, the following would do:
#!/usr/bin/python
import pylab as plb
import matplotlib.pyplot as plt
fig1=plt.figure(1)
ax = fig1.add_subplot(1,1,1)
ax.plot([1,2,3],[4,5,6],'ro-')
#fig1.show() # this does not show a figure if uncommented
plt.ion() # turns on interactive mode
plt.show() # now this should be non-blocking
print "doing something else now"
raw_input('Press Enter to continue...')
However, this is just scratching the surface of things - there are many complications once you start wanting to do background work while interacting with the plots. This is a natural consequence of painting with what's essentially a state machine, it doesn't rub well with threading and programming in an object-oriented environment.
Queue
should be used to pass input data and get results out of the worker functions in a thread-safe way.draw()
in the worker thread so you also need to set up a way to schedule a repaint. TkAgg
seems to be the only one which works 100% (see here). The easiest and best solution is not to use the vanilla python interpreter, but to use ipython -pylab
(as ianalis has rightly suggested), because they have already figured out most of the tricks needed to get interactive stuff working smoothly. It can be done without ipython
/pylab
but it's a significant amount of extra work.
Note: I still often like to farm off worker threads whilst using ipython and pyplot GUI windows, and to get threading working smoothly I also need to use another commandline argument ipython -pylab -wthread
. I'm on python 2.7.1+
with matplotlib v1.1.0
, your mileage may vary. Hope this helps!
Note for Ubuntu users: The repositories are still back on v0.99 for quite some time now, it is worth upgrading your matplotlib
because there were many improvements coming up to the v1.0 release including a Bugfix marathon, and major changes to the behaviour of show()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With