Package: camacq
camacqPython project to control microscope through client-server program.InstallInstall the camacq package. Python version 3.6+ is supported.# Check python version.python--version# Install package.pipinstallcamacq# Test that program is callable and show help.camacq-hRuncamacqConfigurecamacq uses a yaml configuration file, config.yml, for configuring
almost all settings in the app. The configuration file is found in the
configuration directory. The default configuration directory is located
in the home directory and called.camacq.The location of the configuration directory can be overridden when
starting camacq.camacq--config/my_custom_config_dirWhen camacq is started it checks the configuration directory for the
configuration file, and if none is found creates a default configuration
file. See below for an example of how to configure the leica api and a
simple automation, in the configuration yaml file.leica:host:localhostport:8895imaging_dir:'/imaging_dir'automations:-name:starttrigger:-type:eventid:camacq_start_eventaction:-type:commandid:start_imagingAPITo interact with a microscope camacq needs to connect to an API from a
microscope vendor, which in turn will control the microscope. Currently
camacq can connect to the Computer Aided Microscopy (CAM) interface of
Leica Microsystems' microscopes that have that feature activated. The
design of camacq is built to be able to easily extend to APIs of other
microscope vendors in the future. We welcome pull requests for this and
other improvements. The API interface should be contained within a
separate Python library, that instantiates a client object which camacq
can use.leica:host:localhostport:8895imaging_dir:'/imaging_dir'AutomationsTo tell the microscope what to do, camacq uses automations. Automations
are blocks of yaml consisting of triggers, optional conditions and
actions. A trigger is the notification of an event in camacq, eg a new
image is saved. An action is what camacq should do when the trigger
triggers, eg go to the next well. A condition is a criteria that has to
be true to allow the action to execute, when a trigger has triggered.As events happen, camacq checks the configured automations to see if any
automation trigger matches the event. If there is a match, it also
checks for possible conditions and if they are true. If both trigger and
conditions matches and resolves to true, the corresponding action(s)
will be executed.For each automation block, it is possible to have multiple triggers,
multiple conditions and multiple actions. Eg we can configure an
automation with two triggers and two actions. If any of the triggers
matches an event, both actions will be executed, in sequence.automations:name:image_next_welltrigger:-type:eventid:camacq_start_event-type:eventid:well_eventdata:well_img_ok:trueaction:-type:sampleid:set_sampledata:plate_name:plate_1well_x:1well_y:>{{ trigger.event.well_y + 1 }}-type:commandid:start_imagingTriggerLet us look more closely at the trigger section of the above automation.trigger:-type:eventid:camacq_start_event-type:eventid:well_eventdata:well_img_ok:trueThis section now holds a sequence of two trigger items, where each has a
type and an id. The second item also has adatakey. Thetypekey tells camacq what type of trigger it should
configure. Currently only triggers of typeeventare
available. See thedocumentationfor
all available event ids. Theidkey sets the trigger id
which will be the first part of the matching criteria for the trigger.
The second part is optional and is the value of thedatakey. This key can hold key-value pairs with event data that should match
the attributes of the event for the trigger to trigger. So for the
second item we want the event to have idwell_eventand
to have an attribute calledwell_img_okwhich should
returnTrue, for the event to trigger our trigger.ActionLooking at the action section of our example automation, we see that it
also has two items. And exactly as for the triggers, each action has atypeand anid, and can optionally specify
adatakey. Actions can have different types, egsampleorcommand. You will find all of
the action types in thedocumentation.
For an action, thedatakey sets the keyword arguments
that should be provided to the action handler function that executes the
action.action:-type:sampleid:set_sampledata:plate_name:plate_1well_x:1well_y:>{{ trigger.event.well_y + 1 }}-type:commandid:start_imagingIn our example we want to do two things, first set a well, and then
start the imaging. To not have to define this automation for each well
we want to image, automations allow for dynamic rendering of the value
of a data key, via use of theJinja2template language. You can recognize this part by the curly brackets.
See the template section below for further details.TemplateUsing templates in automations allows us to build powerful and flexible
pieces of automation configuration code to control the microscope.
Besides having all the standard Jinja2 features, we also have the
trigger event and the full sample state data available as variables when
the template is rendered. Eg if a well event triggered the automation we
can usetrigger.event.containerinside the template and have
access to all the attributes of the well container that triggered the event.
Useful sample attributes are also directly available on thetrigger.eventegtrigger.event.well_x.well_y:>{% if trigger.event.container is defined %}{{ trigger.event.well_y + 1 }}{% else %}1{% endif %}If we need access to some sample state that isn't part of the trigger,
we can usesamplesdirectly in the template. Via this
variable the whole sample state data is accessible from inside a
template. See below for the sample attribute structure. Note that only
condition and action values in key-value pairs support rendering a
template. Templates are not supported in the keys of key-value pairs and
not in trigger sections.ConditionA condition can be used to check the current sample state and only
execute the action if some criteria is met. Say eg we want to make sure
that channel 3 of well 1:1 of plate 1 is green and that gain is set to
800.condition:type:ANDconditions:-condition:>{% if samples.leica.data['{"name": "channel", "plate_name": "plate_1", "well_x": 1, "well_y": 1, "channel_id": 3}'].values['channel_name'] == 'green' %}true{% endif %}-condition:>{% if samples.leica.data['{"name": "channel", "plate_name": "plate_1", "well_x": 1, "well_y": 1, "channel_id": 3}'].values['gain'] == 800 %}true{% endif %}The trigger event data is also available in the condition template as a
variable. Below example will evaluate to true if the well that triggered
the event has either 1 or 2 as x coordinate.condition:type:ORconditions:-condition:>{% if trigger.event.well_x == 1 %}true{% endif %}-condition:>{% if trigger.event.well_x == 2 %}true{% endif %}Currently each condition must be a template that renders to the stringtrueif the condition criteria is met.SampleThe sample state should represent the sample with a representation that
is specific to each implemented microscope api using theImageContainerapi of camacq. An image container has aname, a dictionary ofimagesand
a dictionary ofvaluesas attributes. The container also fires a specific
event on container change.There are two special cases of the image container. The first is the main
sample container of each microscope api, eg the leica container. The main
container has an extra attributedatawhich is a dictionary with all the
containers of the sample. The second special case is the image in the
dictionary of images of an image container. The image is also a container
and has only itself in the images dictionary and apathattribute with
the path of the image.Eg for the leica sample there are plate, well, field, z_slice, channel and
image containers under the main leica sample container.All implemented sample states are available as a variablesamplesin
templates in automations. The leica sample is available assamples.leica.See below for the leica sample state attribute structure in camacq.
The words in all capital letters are example values. Each image container
has a name, which is either of plate, well, field, z_slice, channel or image.
The different leica containers have different leica specific attributes
that aren't all shown below.samples:leica:name:leicaimages:PATH:name:imagepath:PATHplate_name:PLATE_NAMEwell_x:WELL_Xwell_y:WELL_Yfield_x:FIELD_Xfield_y:FIELD_Yz_slice_id:Z_SLICE_IDchannel_id:CHANNEL_IDimages:PATH:selfvalues:VALUE_KEY:VALUEvalues:VALUE_KEY:VALUEdata:CONTAINER_ID:name:plate/well/field/z_slice/channel/imageimages:PATH:name:imagepath:PATHplate_name:PLATE_NAMEwell_x:WELL_Xwell_y:WELL_Yfield_x:FIELD_Xfield_y:FIELD_Yz_slice_id:Z_SLICE_IDchannel_id:CHANNEL_IDimages:PATH:selfvalues:VALUE_KEY:VALUEvalues:VALUE_KEY:VALUEPluginsTo extend the functionality of camacq and to make it possible to do
automated feedback microscopy, camacq supports plugins. A plugin is a
module or a package in camacq that provides code for a specific task. It
can eg be an image analysis script. See thedocumentationfor all default available
plugins.To install a custom plugin, create a Python package with asetup.pymodule that
implements the entry_points interface with key"camacq.plugins".setup(...entry_points={"camacq.plugins":"plugin_a = package_a.plugin_a"},...)See the packagingdocsfor details.camacqwill
automatically load installed modules or packages that implement this entry_point.Add asetup_modulecoroutine function in the module or package. This function
will be awaited withcenterandconfigas arguments.asyncdefsetup_module(center,config):"""Set up the plugin package."""Each plugin must have its own configuration section at the root of the config.example_plugin:...DevelopmentInstall the packages needed for development.pipinstall-rrequirements_dev.txtUse the Makefile to run common development tasks.makeReleaseSee therelease instructions.CreditsA lot of the inspiration for the architecture of camacq comes from
another open-source Python automation app:Home
Assistant. This is
also the source for the automations interface in camacq.