The scan module: basic scanning capabilities

The scan module is part of the microscopy package. It provides a framework for multidimensional scanning routines while acquiring data.

Warning

Problem solved (hopefully) Occasionally, when pausing/resuming a scan, the active scan will save a wrong number of data points. As a result the pos and spec arrays are not properly dimensioned, causing an exception when saving to HDF5.

Usage

Assuming cam and ax are hal.Sensor and hal.Actuator objects, representing for example a camera as sensor and a translation stage as actuator. Create and start a 1D scan with

>>> from microscopy.scan import Scan1D, ScanND
>>> scan = Scan1D((10, -0.6, -0.01), cam, ax)
>>> scan.run()
    X: -0.5999 V  # scan progress is printed in console

For multidimensional scans, simply create as many Scan1D objects as required and combined them with ScanND():

>>> scan3d = ScanND((scan1, scan2, scan3, ...))
>>> scan3d.run(thread=True)

Here the scan was started in a background thread to avoid blocking the Python console. The first scan in the list will be the slowest.

Scans can be paused and resumed at will by pressing Ctrl+C (if running in the main thread) or scan.pause() (if running in a background thread). To resume, simply recall scan.run() or scan.run(thread=True). To see the scan progress:

>>> scan.ax.print_position()
    X: -0.5999 V

Interfacing with other Python objects

Several hooks are provided:

  1. Attributes Scan1D.at_every_point, Scan1D.at_start, Scan1D.at_end are list of functions that will be called after every sensor acquisition, at the beginning of a scan, and at the end of a scan, respectively. The functions must have no arguments. They can be passed to the constructor as keyword arguments, or appended to/removed from the attributes at any time with immediate effect.
  2. A threading.Event object may be passed to the constructor’s Scan1D.iteration_event keyword. The Event will be set at after every sensor acquisition to notify any object that may be waiting on the Event.
  3. A function returning a bool may be passed to the optional check argument The function will be called after every point, and the scan will be terminated if True is returned.

Method 1 is more suitable to trigger actions that will take place in the same thread as the scan, while Method 2 allows interaction with objects in a different thread.

Saving data

Inside a Scan1D object, the acquired data is saved as a multi-dimensional numpy.ndarray in the Scan1D.spectra. Similarly the position is recorded in Scan1D.pos, the position of all axes is recorded at every point. The Scan1D.save() method will write these arrays in a HDF5 h5py.File:

>>> scan.save('filename', 'dataset_name', comment='some comments')

class microscopy.scan.Scan1D(scan_range, cam, ax, at_start=(), at_every_point=(), at_end=(), iteration_event=None, check=<function <lambda>>, reverse_next=False, repeat=1, history=[], primary=True)[source]

Flexible 1D scan.

Required arguments:

Parameters:
  • scan_range – (start, length, step)
  • cam – A Sensor object that implements the snap() method
  • ax – an Actuator object that implements the move_to() and position() methods

Optional arguments:

Parameters:
  • at_start – tuple of functions that will be called before the scan start, after each snap, or at the end, respectively. Useful to run some optimisation routines or checks.
  • at_every_point – Similar to at_start, but the functions are called at every point in the scan
  • at_end – Similar to at_start
  • iteration_event – a threading.Event object that is set() at the end of every iteration.
  • check – function , called after every acquired data point. The scan will terminates it True is returned.
  • reverse_next (bool) – Whether to run the next scan in reverse
  • repeat (int) – Repeat the scan n times, appending the data. E.g. set reverse_next=True and repeat=2 to close the scan trajectory.
  • history – append a copy of scan object to this list when scan finishes.
  • primary – True if this is a true 1D scan, false if multi-dimensional.
pause()[source]

Tell the scan to pause when running in a background thread.

extend(distance)[source]

Extend the scan by an extra distance.

The scan state is set to ‘paused’. Call run() to acquire the extended segment.

reset()[source]

Call reset() if the scan as been interrupted but you want to restart at the beginning, not where is was stopped.

Note that the data will not be erased until run() is called.

loop(repeat=None, keep_old_data=False)[source]

Do one scan, and return True upon completion, False if interrupted.

Not to be called directly by the user (use run() instead).

Ctrl+C to gracefully stop it before scheduled end while keeping the acquired data.

Parameters:repeat (int) – How many times to repeat the scan, default=1 (no repeat). Can be used with reverse_next.
Returns:True if the scan is terminated successfully, False if interrupted before completion.
Return type:bool
run(thread=False, keep_old_data=False)[source]

Start the scan.

Parameters:
  • thread (bool) – whether to run the scan in a background thread.
  • keep_old_data (bool) – if True, new data will be appended to the existing one. If False, any existing data will be overwritten.
do(func_list, *args, **kwargs)[source]

Call all functions in func_list (with self as first argument)

save(filename, dataset_name, comment='')[source]

Save data and metadata in a new HDF5 group.

Parameters:
  • filename (string) – name of the H5 file (must already exist).
  • dataset_name (string) – name of the dataset (must not already exist).
  • comment (string) – to be saved as attribute ‘comment’ under ‘dataset_name’.
print_position()[source]

Print a pretty status string to the terminal.

position_string()[source]

Return a formatted status string.

microscopy.scan.Scan2D(slow, fast)[source]

Return a 2D scan made from two Scan1D objects.

The first scan is the slow one.

microscopy.scan.ScanND(scan_list)[source]

Return a mulidimensional scan from a list od 1D scans.

The slowest scan goes first.

Internally, individual scans are repackaged as hal.Actuator and hal.Sensor objects, and the multi-dimensional scan is a regular Scan1D object.

Parameters:scan_list – a list of Scan1D objects
Return type:Scan1D
Example:
>>> xscan = Scan1D((-1, 2, 0.008), h.cam, h.x)
>>> yscan = Scan1D((-1, 2, 0.008), h.cam, h.y)
>>> xyscan = ScanND((xscan, yscan))
>>> xyscan.run()
class microscopy.scan.Stepper(step, n)[source]

Transform a regular (square) scan into a stair-like scan by increase the start point of the scan by step every n scans:

|.........         ...          # in this example: 
|.........         ......       #   - step = 1
|.........   -->   .........    #   - n= 3
|.........         .........
|                     ......
|                        ... 
Usage:

Pass a Stepper object to the at_end keyword argument of the Scan1D constructor, and use the latter as the slow axis of a multidimensional scan as as usual:

>>> xscan = Scan1D((start, length, stop), cam, ax, at_end=[Stepper(step, n)])
>>> yscan = Scan1D(...)
>>> xyscan = ScanND((yscan, xscan))

Note

The scans will have to be recreated before running it again.

Parameters:
  • step – the offset introduced by every step
  • n (int) – number of scans between offset increase