3. Improved interactive plotting with wanglib.pylab_extensions
¶
This module contains some useful extensions to the pylab interface.
3.1. Plotting while acquiring data¶
To plot while acquiring data, you will need to implement your data
gathering using Python generators. A generator is like a Python
function that, rather than returning data all at once (with the
return
statement), returns it point by point (with the yield
statement).
Suppose we have a spex
spectrometer object, and a
lockin
object that we are using to detect the signal at
the output slit of the spectrometer. Here is an example of a
generator we might use to scan a spectrum, while yielding
values along the way:
def scan_wls(wls):
for wl in wls:
spex.set_wl(wl)
sleep(0.1)
val = lockin.get_x()
yield wl, val
Note
This pattern is so common that a shorthand is provided for it in wanglib.util.scanner()
.
Then, if we wanted to scan from 800nm to 810nm, we would do
scan = scan_wls(numpy.arange(800, 810, 0.1))
for x,y in scan:
print x,y
This will print the data to STDOUT, but we could also:
- save it to a python list using list comprehensions
- save it as a numpy object using
numpy.fromiter()
- plot it progressively using
wanglib.pylab_extensions.live_plot.plotgen()
The plotgen
function reads from your generator, plotting data as
it goes along. In the case of our scan_wls
example above, we can
view the spectrum as it gets collected:
wls = arange(800, 810, 0.1))
plotgen(scan_wls(wls))
# ... measures data, plotting as it goes along ...
After your generator yields its last value, it will return the complete array of measured X and Y values. Sometimes we want to do extra things with that:
_,ref = plotgen(scan_wls(wls)) # measure reference spectrum and plot it
_,trn = plotgen(scan_wls(wls)) # measure transmission spectrum and plot it
plot(wls, log(ref/trn), 'k--') # plot absorption spectrum
Additionally, plotgen
can generate multiple lines. Say we wanted
to plot both the X and the Y quadrature from our lockin. We’d write
our generator like:
def scan_wls(wls):
for wl in wls:
spex.set_wl(wl)
sleep(0.1)
x = lockin.get_x()
y = lockin.get_y()
yield wl, x, wl, y
This is the same as before, but we’re yielding two X,Y pairs: one with
the X quadrature (wl, x)
and one with the Y quadrature (wl, y)
.
plotgen
recognizes this and plots two lines:
_,x,_,y = plotgen(scan_wls(wls))
By default, plotgen
plots these on the same axes, but sometimes
that doesn’t make sense. For example, if we’re measuring the signal
magnitude (in Volts) and phase (in degrees), then those two units have
nothing to do with each other, and we should plot them on separate
axes.
def scan_wls(wls):
for wl in wls:
spex.set_wl(wl)
sleep(0.1)
r = lockin.get_r()
p = lockin.get_phase()
yield wl, r, wl, p
# create two axes and pass them to plotgen explicitly
ax1 = pylab.subplot(211)
ax2 = pylab.subplot(212)
plotgen(scan_wls(wls), ax=(ax1,ax2))
Finally, you can limit the length of the plotted lines using the
maxlen
parameter. This is useful for generators which yield
infinitely - such as monitoring the last five minutes of a signal.
def monitor_signal():
start = time()
while True:
yield time() - start, lockin.get_phase()
sleep(0.1)
Note
This pattern is so common that a shorthand is provided for it in wanglib.util.monitor()
.
This will yield about 10 points per second forever. To cut it short after about 5 minutes of data, try this:
plotgen(monitor_signal(), maxlen=10*60*5)
Full documentation for plotgen
:
-
wanglib.pylab_extensions.live_plot.
plotgen
(gen, ax=None, maxlen=None, **kwargs)¶ Take X,Y data from a generator, and plot it at the same time.
Parameters: - gen – a generator object yielding X,Y pairs.
- ax – an axes object (optional).
- maxlen – maximum number of points to retain (optional).
Returns: an array of the measured X and Y values.
Any extra keyword arguments are passed to the plot function.
gen
can yield any even number of values, and these are interpreted as a set of X,Y pairs. That is, if the provided generator yields 4 values each time, plotgen will plot two lines - with the first line updated from the [0:2] slice and the second line updated from the [2:4] slice.ax
is the axes object into which the line(s) are plotted. By default, the current axes.ax
can also be a tuple of axes objects, as long as the tuple is the same length as the number of lines being plotted. Each line is then plotted into the corresponding axes.maxlen
, when provided, limits the buffer size. When the plotted lines each grow to this number of points, the oldest data points will start being trimmed off the line’s trailing end.
3.2. Saving/clearing traces¶
-
wanglib.pylab_extensions.misc.
apply_mask
(line, mask)¶ mask x and y (to remove bad points, etc).
-
wanglib.pylab_extensions.misc.
apply_offset
(line, offset)¶ move the line up or down
-
wanglib.pylab_extensions.misc.
apply_reference
(line, ref)¶ apply reference data (for absorption spectra)
-
wanglib.pylab_extensions.misc.
bll
(index=-1, lag=0.3)¶ blink the last line, identifying it
-
wanglib.pylab_extensions.misc.
cll
(index=-1)¶ clear last line. removes the last line from the figure.
To remove a different line, specify the index.
-
wanglib.pylab_extensions.misc.
dualtick
(func)¶ Decorator for dual-tick functions.
A dual-tick function is a function that, when called on an axis, adds a second set of tick to it in different units. This decorator creates such functions when applied to the unit conversion function.
For example:
>>> @dualtick >>> def eV(wl): >>> return 1240. / wl
Now, when working with plots of spectral data in units of nm, calling
>>> eV()
will add a second axis along the top in units of eV. To explicitly apply to some other axis
ax
, useeV(ax)
. Returns a reference to the twiny axis that was made.Another example, for a delay stage:
>>> @dualtick >>> def ns(pos): >>> c = 300. # mm / ns >>> zd = 521. # mm >>> return 2 * (zd - pos) / c
When plotting delay stage data enumerated in mm, this function will add an axis in ps delay from the zero-delay point at 521mm.
-
wanglib.pylab_extensions.misc.
gll
(index=-1, blink=True)¶ Get last line.
Retrieves x,y data of the last line and returns them as a tuple of two numpy arrays.
To get a different line, specify the index.
-
wanglib.pylab_extensions.misc.
relim
(line)¶ redraw the line’s figure to include the line.
-
wanglib.pylab_extensions.misc.
sll
(fname, index=-1, blink=True)¶ Save last line.
Saves x,y data of the last line, in .npy format. Specify the file name.
To save a different line, specify the index.
3.3. Density plots¶
-
wanglib.pylab_extensions.density.
density_plot
(two_dimensional, horiz, vert, ax=None, **kwargs)¶ Display a 2D density plot - like imshow, but with axes labels corresponding to the two axes provided.
This will only be accurate for regularly-spaced x and y axes (e.g., as generated by arange or linspace).
Parameters: - two_dimensional – data to plot. shape: (M, N)
- horiz – x-axis. should have length N.
- vert – y-axis. should have length M.
- ax – axis upon which to plot.
Keyword arguments are passed to imshow.