Search code examples
pythonliveipythonmatplotlib

live plotting in matplotlib while performing a measurement that takes time


I would like to perform a measurement and plot a graph while the measurement is running. This measurements takes quite some time in python (it has to retrieve data over a slow connection). The problem is that the graph freezes when measuring. The measurement consists of setting a center wavelength, and then measuring some signal.

My program looks something like this:

# this is just some arbitrary library that has the functions set_wavelength and
# perform_measurement
from measurement_module import set_wavelength, perform_measurement
from pylab import *

xdata = np.linspace(600,1000,30) # this will be the x axis
ydata = np.zeros(len(xdata)) # this will be the y data. It will
for i in range(len(xdata)):
  # this call takes approx 1 s
  set_wavelength(xdata[i])
  # this takes approx 10 s
  ydata[i] = perform_measurement(xdata)
  # now I would like to plot the measured data
  plot(xdata,ydata)
  draw()

This will work when it is run in IPython with the -pylab module switched on, but while the measurement is running the figure will freeze. How can modify the behaviour to have an interactive plot while measuring?

You cannot simply use pylab.ion(), because python is busy while performing the measurements.

regards,

Dirk


Solution

  • Slow input and output is the perfect time to use threads and queues in Python. Threads have there limitations, but this is the case where they work easily and effectively.

    Outline of how to do this:
    Generally the GUI (e.g., the matplotlib window) needs to be in the main thread, so do the data collection in a second thread. In the data thread, check for new data coming in (and if you do this in some type of infinite polling loop, put in a short time.sleep to release the thread occasionally). Then, whenever needed, let the main thread know that there's some new data to be processed/displayed. Exactly how to do this depends on details of your program and your GUI, etc. You could just use a flag in the data thread that you check for from the main thread, or a theading.Event, or, e.g., if you have a wx backend for matplotlib wx.CallAfter is easy. I recommend looking through one of the many Python threading tutorials to get a sense of it, and also threading with a GUI usually has a few issues too so just do a quick google on threading with your particular backend. This sounds cumbersome as I explain it so briefly, but it's really pretty easy and powerful, and will be smoother than, e.g., reading and writing to the same file from different processes.