Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

in matplotlib, is there a way to pop up a figure asynchronously?

Tags:

matplotlib

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?

like image 854
ev-br Avatar asked Feb 19 '11 13:02

ev-br


People also ask

Is matplotlib asynchronous?

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.

Can you make matplotlib interactive?

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.

What is interactive mode in 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.

Is PLT show () necessary?

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.


1 Answers

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.

  • Expensive calculations will have to go into worker threads (or alternatively into subprocesses) to avoid freezing the GUI.
  • Queue should be used to pass input data and get results out of the worker functions in a thread-safe way.
  • In my experience, it is not safe to call draw() in the worker thread so you also need to set up a way to schedule a repaint.
  • Different backends may start to do strange things and 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().

like image 183
wim Avatar answered Sep 20 '22 14:09

wim