Skip to content

Experiment Scripts

Users can define experimental scripts and then launch these from within Motif. Scripts are placed in a platform specific directory, /etc/motif/experiments on Linux or C:\ProgramData\Motif\Experiments on Windows.

These scripts can interact with the Motif using the Motif API in several ways:

  • Scripts can operation in a one-time fashion, for example by setting up an experimental protocol consisting of scheduled outputs and recordings. For more experimental scripts which use the scheduler, see here
  • Scripts can also run continuously, manipulating the motif API in realtime.
  • Advanced scripts can even perform realtime image processing to implement closed loop behavioural paradigms depending on the animal behaviour

Scripts placed in the appropriate directory are then shown in the user interface, where they can be launched.

Controlling Experiment Scripts From the WebUI

Once you have added your script to the appropriate directory it should appear in the "I/O & Scheduled" tab


The screenshot above shows the result of the example script here.

Clicking "Start" A will execute the script. If the script runs for a long time, it will indicate 'Running' at B. If the script crashes you can consult the adminstration page, clicking on the appropriate 'experiment:' section, and see any error messages.


While the Motif user interface provides an easy way to launch scripts, they may also be launched manually from either on the system, or another computer. This may provide more debugging information, however take care to provide the IP_ADDRESS and API_KEY of the Motif system if required

Writing Scripts

The following examples demonstrate how to use experiment scripts to control Motif itself and IO (flash LEDs). For examples more focused on scheduling actions, see the examples here.

By default, scripts are written in Python and use the python-motifapi library.

  • this library wraps the REST+JSON API and handles sending and parsing the responses
  • this library is compatible with all motif versions, although real-time image streaming and some IO operations are only supported in motif 5 and above

When an experiment script using this library is launched by Motif, then the constructed MotifApi() object is pre-configured for the executing motif system and you do not need to explicitly specify IP_ADDRESS and API_KEY. If not explicitly included in the example snippets below, a Motif experiment script must begin with

from motifapi import MotifApi
# already configured with correct IP address and API Key
api = MotifApi()

Example: Recording Control

Start Recording on All Cameras'recording/start',
         metadata={'genotype': 'wildtype', 'user': 'sarah'})

Stop Recording on All Cameras'recording/stop')

Start Recording on One Camera

# start recording on camera with serial number 12345'camera/12345/recording/start', codec='h264-hq')

Example: Copy and Export

# if true, delete files after successful copy'recordings/copy_all', delete_after=True))

Example: Flash One LED

The following two scripts perform the same task 'flash a LED while recording', but use two different methods.


These examples assume your Motif system has an appropriately configured and connected IO Device with one LED. It may not work on your system without modification.

from motifapi import MotifApi

# already configured with correct IP address and API Key
api = MotifApi()

# schedule a stimulus and start recording'schedule/io/led/set',
         cron_expression='%2 * * ? * * *',

while True:'io/led/set', value=random.random())

Example: Flash Two LEDs

The following example is slightly more complicated than the above and alternately flashes a red and blue LED when a specific camera with serial number 22075785 is connected.


These examples assume your Motif system has an appropriately configured and connected IO Device with two LEDs and a camera with the configured serial number. It may not work on your system without modification.

from motifapi import MotifApi

api = MotifApi()

camera_serial = '22075785''io/led_red/set', value=0)'io/led_green/set', value=1)'schedule/camera/%s/io/led_red/set' % camera_serial,
         cron_expression='%2 * * ? * * *',
         value=float('+inf'))'schedule/camera/%s/io/led_green/set' % camera_serial,
         cron_expression='%2 * * ? * * *',

Multiple Camera Support

When experiment scripts are executed, they are passed the associated camera serial number, if executed from a 'camera specific context'. A camera specific context is one of the following situations

  • executing a script in a single camera setup
  • executing a script from the camera-specific user interface of a connected camera, in a multi-camera setup

Scripts can then adapt their behaviour accordingly. For example, the following script calls different Motif API depending on whether is is launched in a multi- or single-camera context

api = MotifApi()
    sn = os.environ['MOTIF_CAMERA_SERIAL']'camera/%s/configure' % sn, AcquisitionFrameRate=10.0)
except KeyError:'cameras/configure', AcquisitionFrameRate=10.0)

Realtime Streaming

Motif can, with very low latency (<1ms), stream realtime images from the camera, without interfering with the recording, compression, or any other motif functions. This allows developing out of process realtime image processing algorithms for closed loop experiments. Such experiments could for example then provide stimulus to the animal using either Motif connected and configured outputs, or other user provided methods.

Per default streaming is limited to localhost (so such scripts must run on the same PC as Motif), however Motif can be configured to stream also to other network locations if you are aware of the latency implications and have sufficient network infrastructure.

Streaming Images

A realtime image stream can be established as follows (after constructing the api object with the correct IP address and API_KEY as indicated above

# small example using opencv to show the image in realtime, outside of motif

stream = api.get_stream(stream_type=MotifApi.STREAM_TYPE_IMAGE)
if stream is not None:
    while True:
        I, md = stream.get_next_image()
        cv2.imshow('live', I)


Motif sends ('pushes' - the image stream is push-pull) a new image every time one is received from the camera, which means that if the application processing the images can not operate at faster than the framerate, images will be buffered by ZMQ and the latency will increase. If this is the case your application should decide how it wants to discard unprocessed frames. Often what you want is to just process the 'most recent frame' - discarding ones that arrived while busy. An example of how to use a separate thread to do this is provided here here.

Streaming State

If you have other more custom data acquisition needs not supported by Motif IO / DAQ support, and want to subsequently integrate or synchronize this custom data with the motif imagestore frame_numbers and frame_times then you can use the realtime state streaming. Motif publishes to this stream, at low latency (<<1ms), the current frame_number, frame_time, and other information. A realtime state stream is established as follows

stream = api.get_stream(stream_type=MotifApi.STREAM_TYPE_STATE)
if stream is not None:
    while True:
        print stream.get_next_state()