Skip to main content
Help the Python Software Foundation raise $60,000 USD by December 31st!  Building the PSF Q4 Fundraiser

A Python package to control the Matisse 2 TS.

Project description


A Python package to control the Matisse 2 TS laser for the University of Washington's Optical Spintronics and Sensing Lab.

Requirements: Python 3.7+, NI VISA, PyVISA, pySerial, SciPy, matplotlib, PyQt5

Tested on Windows 7 and 10 (x64).



$ pip install matisse-controller

If you plan on using PLE features with Andor instruments, copy the required DLL files from the Andor SDK into [package install dir]/shamrock_ple/lib (see the README in that directory for more details)


To launch the GUI, connect the Matisse and a supported wavemeter, and then run:

$ matisse-controller

The GUI uses a Python API to control the Matisse. If you're writing a Python program, just import the subpackages that contain the APIs you want. The matisse subpackage contains Matisse-related components, the config subpackage contains configuration functionality, etc.

To configure the behavior of the program using a GUI, click the 'Configuration' menu option from the main GUI, or run:

$ matisse-config

Hovering over most fields in this configuration dialog will reveal tooltips with more information about what the options do.

API Documentation

API documentation for this project can be found at


The changelog for this project can be found at


There are a few important bits of terminology that may be confusing:

  • The target wavelength is the wavelength that is explicitly set (via Set > Wavelength), but if no target wavelength is given, the current measured wavelength is considered to be the target wavelength instead.
  • Auto-stabilization or stabilization in this case refers to constantly checking and scanning the device up and down to keep the wavelength at a particular value.
  • The stabilization piezos are the reference cell, the piezo etalon, and the slow piezo.
  • Scanning may refer to the act of moving a motor back and forth to locate an optimal position, or the act of adjusting the reference cell and stabilization piezos to adjust the wavelength.

Pickled Data

PLE data from this application is stored in text files as a list of counts separated by newlines, as well as a .pickle file, which is an efficient form of binary storage that Python uses to serialize objects.

To load the data from a .pickle file:

import pickle
with open('file_name_here.pickle', 'rb') as data_file:
    data = pickle.load(data_file)

GUI Options


  • Clear Log: clear the log window
  • Close All Plots: close any birefringent filter or thin etalon scan plot windows that may be open
  • Configuration: open a dialog that allows you to customize all configurable options
  • Reset: reset everything, or individual components (like Matisse motors, Matisse piezos, or PLE tasks)
  • Restart: close and re-open the GUI, reinitialize everything. Good for when things go wrong.


  • Wavelength: set the laser wavlength to a given value
  • BiFi Approx. Wavelength: move the birefringent filter to an approximate wavelength
  • BiFi Motor Position: set the position of the birefringent filter
  • Thin Etalon Motor Position: set the position of the thin etalon
  • Piezo Etalon Position: set the position of the piezo etalon
  • Slow Piezo Position: set the position of the slow piezo
  • RefCell Position: set the position of the reference cell


  • Birefringent Filter: perform a scan of the birefringent filter, choosing the location with maximum diode power
  • Thin Etalon: perform a scan of the thin etalon, choosing the mode closest to the target wavelength
  • Scan Device Up: slowly increase the wavelength by scanning the stabilization piezos and the thin etalon together
  • Scan Device Down: slowly decrease the wavelength by scanning the stabilization piezos and the thin etalon together
  • Stop Scanning Device: stop scanning the stabilization piezos and the thin etalon


  • Toggle Control Loop: toggle individual control loops of Matisse components
  • Toggle Lock Laser: toggle execution of a thread that attempts to lock the laser to the target wavelength
  • Set Recommended Fast Pz Setpoint: measure the reference cell transmission spectrum, and set the fast piezo setpoint
  • Toggle Auto Stabilization: toggle execution of a thread that scans the device up or down to keep the wavelength at the target value


  • Start PLE Scan: open a dialog to set parameters of a PLE scan, and perform the scan, saving acquired data in text files separated by wavelength, and also a .pickle file containing all the data
  • Start PLE Analysis: open a dialog to load a .pickle file of a PLE scan, and integrate the counts for each laser wavelength used in the scan. Opens a plot of integrated counts vs. laser wavelength afterwards. You can also load background data that you'd like to be subtracted from the acquisition data.
  • View PLE Analysis: plot the data in a .pickle file representing the analysis of a particular PLE scan
  • View Single Acquisition: plot a file containing data from the CCD, or acquire a single image from the CCD. This feature does not wait for the CCD to reach a particular temperature.


After checking out the repo, run pipenv install --dev to install dependencies. Using a virtual environment is recommended.

To install this package onto your local machine, run pip install -e ..

Useful documentation: PyVISA, pySerial, SciPy, matplotlib, Qt 5

Adding features to the Matisse class

The standard way of interacting with the Matisse outside of the existing API is to use the Matisse.query method. The Matisse implements several commands that run asynchronously, like motor movements, so if you want to run these synchronously, you must do it on your own (like checking the motor status until it's idle again).

Long-running tasks should be executed in a thread that can be started and gracefully stopped from the Matisse class. Currently, fetching a measurement from the wavemeter is a relatively expensive process, so avoid doing this too much if possible.

Adding another wavemeter

Currently I've only implemented an interface for the WaveMaster, but any class will do, as long as it implements the get_raw_value and get_wavelength methods. The get_raw_value method should return a value representing exactly what is seen on the wavemeter display (this might not be a measurement), and the get_wavelength method should always return a floating-point number representing the latest measurement from the wavemeter. The WaveMaster implementation blocks the thread until a value is returned from the instrument. Additionally, please ensure any code you write that communicates with instruments is thread-safe.

Adding features to the GUI

Logging and UI updates should have top priority, so take care not to block the UI thread. Here's the process I use:

  • Add a menu action under setup_menus and connect it to a Qt slot under setup_slots, to be executed on the main thread later.
  • Do UI updates in this slot, if you need a long-running task that also updates the UI, use a subclass of QThread with a slot (see LoggingThread, StatusUpdateThread for examples).
  • For long-running tasks that do not need access to the UI, submit a runnable object to the ControlApplication's instance of ThreadPoolExecutor. Hold a reference to the Future it gives you and call add_done_callback on it, passing in matisse_controller.gui.utils.raise_error_from_future if you want to log errors from that thread. For an example of a method that runs tasks one-by-one on the Matisse, see ControlApplication.run_matisse_task.

Adding another PLE procedure

Currently I've only implemented a PLE scan for the Andor Shamrock 750. If you'd like to implement your own PLE procedure, create a separate Python package with a class that has the methods start_ple_scan, stop_ple_scan, and analyze_ple_data. It's up to you to implement the scanning logic for your particular spectrometer and CCD setup. Modify the Matisse class __init__ method to use your chosen wavemeter and an instance of your PLE scanning class.


Bug reports and pull requests are welcome on GitHub at


The package is available as open source under the terms of the MIT License.

Project details

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Files for matisse-controller, version 0.4.0
Filename, size File type Python version Upload date Hashes
Filename, size matisse_controller-0.4.0-py3-none-any.whl (69.0 kB) File type Wheel Python version py3 Upload date Hashes View
Filename, size matisse-controller-0.4.0.tar.gz (54.7 kB) File type Source Python version None Upload date Hashes View

Supported by

Pingdom Pingdom Monitoring Google Google Object Storage and Download Analytics Sentry Sentry Error logging AWS AWS Cloud computing DataDog DataDog Monitoring Fastly Fastly CDN DigiCert DigiCert EV certificate StatusPage StatusPage Status page