Skip to content

Overview#

useq-schema is an implementation agnostic schema for describing a sequence of events during a multi-dimensional imaging acquisition.

The goal of this repo is to provide a specification (and some python utilities) for generating event objects that can be consumed by microscope acquisition engines. A hope is that this will encourage inter-operability between various efforts to drive automated image acquisition.

The schema tries to remain agnostic to the specific acquisition engine (though it was designed based on the capabilities Micro-Manager). We welcome feedback from interested parties regarding limitations and/or potential extensions to the schema! Similarly, while the "ideal" schema will support arbitrary dimensions (i.e. more than the conventional position, time, channel, z, ...), it also hard to avoid hard-coding some assumptions about dimensionality in certain places. Any and all feedback (even minor stuff, such as parameter naming, etc...) is welcome! Please open an issue.

Core Schema#

MDAEvent#

The primary "event" object is useq.MDAEvent. This describes a single event that a microscope should perform, including preparation of the hardware, and execution of the event (such as an image acquisition).

  • For micro-manager, this object is most similar (though not identical) to the events generated by generate-acq-sequence in the clojure acquisition engine that drives Micro-Managers multi-dimensional acquisitions.
  • For Pycro-manager, this object is similar to an individual acquisition event dict generated by multi_d_acquisition_events, (and, useq.pycromanager provides a to_pycromanager method that returns a dict following the pycro-manager event spec)
  • your object here?...

MDASequence#

useq.MDASequence represents a sequence of events – as might be generated by the multidimensional acquisition GUI in most microscope software. The Python MDASequence object is itself iterable, and yields useq.MDAEvent objects.

Executing an MDASequence#

This library is just a schema, and does not provide any built-in functionality for executing an MDASequence. However, pymmcore-plus implements an acquisition engine that can execute an MDASequence object with micro-manager (via the pymmcore python wrapper around the C++ MMCore). See the pymmcore-plus documentation for details. napari-micromanager also creates a useq.MDASequence object from user input and passes it to pymmcore-plus for execution.

hi! 👋

Have you implemented an acquisition engine that can execute a useq.MDASequence? Let us know so we can add it here!

Serialization and Deserialization#

MDASequence and MDAEvent objects are designed to be serialized and deserialized, allowing you to define an entire multi-dimensional acquisition in human-readable YAML (or JSON) file, and then load that file into your acquisition engine.

For example, the following file defines an experiment with:

  • 3 channels (DAPI, FITC, and Cy5), specifying exposure times in ms for each channel
  • a two-phase time-lapse: 3 frames in the first phase, followed by a frame every 10 seconds for 40 minutes
  • a Z-stack at each timepoint, with a range of 4 microns and a step size of 0.5 micron
  • two stage positions, specifying a unique Z-stack for the second position

Example

my_experiment.yaml
axis_order: tpcz
channels:
  - config: Cy5
    exposure: 50.0
  - config: FITC
    exposure: 100.0
  - config: DAPI
    acquire_every: 3
    do_stack: false
time_plan:
  phases:
    - interval: 0:00:03
      loops: 3
    - duration: 0:40:00
      interval: 0:00:10
z_plan:
  range: 4.0
  step: 0.5
stage_positions:
  - x: 10.0
    y: 20.0
  - name: Cell 1
    x: 10.0
    y: 20.0
    z: 50.0
    z_plan:
      above: 10.0
      below: 0.0
      step: 1.0
metadata:
  some info: about my experiment
my_experiment.json
{
  "axis_order": "tpcz",
  "channels": [
    {
      "config": "Cy5",
      "exposure": 50.0
    },
    {
      "config": "FITC",
      "exposure": 100.0
    },
    {
      "config": "DAPI",
      "acquire_every": 3,
      "do_stack": false
    }
  ],
  "time_plan": {
    "phases": [
      {
        "interval": "0:00:03",
        "loops": 3
      },
      {
        "duration": "0:40:00",
        "interval": "0:00:10"
      }
    ]
  },
  "z_plan": {
    "range": 4.0,
    "step": 0.5
  },
  "stage_positions": [
    {
      "x": 10.0,
      "y": 20.0
    },
    {
      "name": "Cell 1",
      "x": 10.0,
      "y": 20.0,
      "z": 50.0,
      "z_plan": {
        "above": 10.0,
        "below": 0.0,
        "step": 1.0
      }
    }
  ],
  "metadata": {
    "some info": "about my experiment"
  }
}