OperationPlugin Documentation

This documentation provides information on the foundational aspects of the OperationPlugin class, as well as a more detailed API reference.

If you are new to developing Xi-CAM plugins, it is recommended that you follow the quick-start documentation first.

For more general development resources, see the Resources page.

What Is an OperationPlugin?

An OperationPlugin can be thought of as a function with some extra annotations attached to it. When we want to define an OperationPlugin, we simply need to define a Python function, then add some additional syntax to the function to define things like inputs, outputs, descriptions of inputs/outputs, units, etc.

To achieve this, The OperationClass makes extensive use of Python decorators.

Where Is OperationPlugin?

xicam.plugins.operationplugin

What Does an OperationPlugin Look Like?

Let’s start off with a simple function that computes the square of its input:

def my_square(n):
    return n**2

Now, let’s make this an OperationPlugin:

from xicam.plugins.operationplugin import operation, output_names

@operation
@output_names("square")
def my_square(n):
    return n**2

That’s it!

Notice the two decorators here: @operation and @output_names.

The @operation says that this function is now a Xi-CAM OperationPlugin. Any input arguments for the function will be the input names for the operation. In this case, our input is n. (This can actually be overwritten by using a different decorator, @input_names, which is described later.)

The @output_names allows us to name our outputs, in this case, square. This will be useful when connecting multiple operations together in a Workflow.

Default Input Values

If you want to provide your operation with default input values, you can use argument defaults in your function:

from xicam.plugins.operationplugin import operation, output_names

@operation
@output_names("square")
def my_square(n = 0):
    return n**2

This provides this operation’s n input with a default value of 0.

Required and Highly-Used Decorators

In order to make a function an operation, the following decorators must be used:

  • @operation – allows creation of operations from the function

  • @output_names – defines the name of the output(s)

Additionally, although not required to for an operation, the following decorators are highly-recommended for use:

  • @display_name – the name of the operation

  • @describe_input – attach a description to the specified input (can be used multiple times)

  • @describe_output – attach a description to the specified output (can be used multiple times)

Type Hinting (Optional)

With Python3 (3.5+), you can add type hinting to your code. In the context of Xi-CAM OperationPlugins, this can be used to make your operation code a little easier to read.

Let’s use the my_square function we defined earlier in this operation:

from xicam.plugins.operationplugin import operation, output_names

@operation
@output_names("square")
def my_square(n: int) -> int:
    return n**2

Note the n: int and the -> int: here. These suggest (but do not mandate) that the input be an integer, and the output expected is an integer.

Again, these are not required, but they can help with readability and debugging your code.

For more information, see Python’s typing module.

Example

A simple division operation that returns both the quotient and remainder.

This illustrates the use of multiple input/output descriptions and multiple outputs.

from typing import Tuple
from xicam.plugins.operationplugin import describe_input, describe_output, display_name, operation, output_names

@operation
@output_names("quotient", "remainder")
@display_name("Division with Remainder")
@describe_input("dividend", "The number being divided.")
@describe_input("divisor", "The number to divide by.")
@describe_output("quotient", "The result of the division.")
@describe_output("remainder", "The remaining value.")
def my_divide(dividend: int, divisor: int = 1) -> Tuple[int, int]:
    quotient = int(dividend // divisor)
    remainder = dividend % divisor
    return quotient, remainder

How Do I Use an OperationPlugin?

Now that we’ve defined an operation, how do we actually use it?

When we define an operation using the @operation decorator around a function, we are defining a new operation class.

We can then create an operation object by using the syntax func(), where func is the name of the function in the operation.

Let’s take our my_square operation (defined above) and create one:

from xicam.plugins.operationplugin import operation, output_names

@operation
@output_names("square")
def my_square(n):
    return n**2

op = my_square()

Now that we have an operation object (instance), op, we can use it within a Workflow.

Let’s create a Workflow, add our operation to it, then execute it.

from xicam.core.execution import Workflow
from xicam.plugins.operationplugin import operation, output_names

@operation
@output_names("square")
def my_square(n):
    return n**2

op = my_square()
workflow = Workflow()
workflow.add_operation(op)
result = workflow.execute(n=11).result()
print(result)

We create a my_square operation, create a Workflow, and add the operation to the Workflow. Then, we execute the Workflow, sending in the input n=11, wait for the result, and print it.

(For purposes of this document, we won’t cover Workflow in depth. More information about Workflow can be found in the Workflow Documentation.)

API Documentation

@xicam.plugins.operationplugin.operation(func: Callable, filled_values: Optional[dict] = None, fixable: Optional[dict] = None, fixed: Optional[dict] = None, input_names: Optional[Tuple[str, ...]] = None, output_names: Optional[Tuple[str, ...]] = None, limits: Optional[dict] = None, opts: Optional[dict] = None, output_shape: Optional[dict] = None, units: Optional[dict] = None, visible: Optional[dict] = None, name: Optional[str] = None, input_descriptions: Optional[dict] = None, output_descriptions: Optional[dict] = None, categories: Optional[Sequence[Union[tuple, str]]] = None) Type[OperationPlugin]

Create a new operation.

When you define a new operation, you must use this decorator (`@operation`) and the `@output_names` decorator.

This function can be used as a decorator to define a new operation type. The operation can then be instantiated by using the () operator on the operation function’s name.

Parameters
  • func (Callable) – Function that this operation will call.

  • filled_values (dict, optional) – Values to fill for the parameters.

  • fixable (dict, optional) – Indicates which parameters are able to be fixed.

  • fixed (dict, optional) – Indicates whether or not a parameter is fixed.

  • limits (dict, optional) – Defines limits for parameters.

  • opts (dict, optional) – Additional options (kwargs) for the parameter (useful with pyqtgraph’s Parameter/ParameterTree).

  • output_names (tuple, optional) – Names for the outputs, or returned values, of the operation.

  • output_shape (dict, optional) – Defines expected shapes for the outputs.

  • units (dict, optional) – Defines units for the parameters in the operation.

  • name (str, optional) – The display name to be shown to the user. Defaults to self.__name__

  • visible (dict, optional) – Indicates if a parameter is visible or not (see pyqtgraph.Parameter).

  • input_descriptions (dict, optional) – A mapping dict containing descriptions for each named input

  • output_descriptions (dict, optional) – A mapping dict containing descriptions for each named output

  • categories (List[Union[tuple, str], optional) – A sequence of categories to associate with this operation.

Example

Create a new operation type and create a new operation instance from it.

>>> from xicam.core.execution import Workflow
>>> from xicam.plugins.operationplugin import operation, output_names
>>> @operation
>>> @output_names("my_output")
>>> def my_func(x: float = 0.0) -> float:
>>>     return x * -1
>>> op = my_func()
>>> workflow = Workflow()
>>> result = workflow.execute(x=2.5).result()
>>> print(result)
@xicam.plugins.operationplugin.output_names

Decorator to define the names of the outputs for an operation.

Defines N-number of output names. These names will be used (in-order) to define any outputs that the operation has.

Parameters

names (List[str]) – Names for the outputs in the operation.

Example

Define an operation that has the outputs x and y.

>>> @OperationPlugin
>>> @output_names("x", "y")
>>> def some_operation(a: int, b: int) -> Tuple[int, int]:
>>>     return a, b
@xicam.plugins.operationplugin.categories(*categories: Union[tuple, str])

Decorator to assign categories to a operation.

These categories will be used to populate the structure of Xi-cam’s menus of OperationPlugins.

Parameters

categories (Tuple[Union[tuple, str]]) – A sequence of categories. Each item is a tuple or str. If an item is a tuple, each item in the tuple is considered as an additional depth in the menu structure.

Example

Define an operation that is in the following categories:

Generic Functions
    Simple Math
        (square operation)
Math Functions
        (square operation)
>>> @OperationPlugin
>>> @categories(('Generic Functions', 'Simple Math'), 'Math Functions')
>>> def square(x: int = 100) -> int:
>>>     return x**2
@xicam.plugins.operationplugin.describe_input(arg_name: str, description: str)

Decorator to set the description for input arg_name.

This is useful for annotating the parameter with additional information for users.

These annotations are displayed in GUI representations of the operation.

Parameters
  • arg_name (str) – Name of the input to add options for.

  • description (str) – A human-readable description of the input arg_name

Example

Define an operation and attach a description to its x input argument.

>>> @OperationPlugin
>>> @describe_input('x', 'The value to square.')
>>> def square(x: int = 100) -> int:
>>>     return x**2
@xicam.plugins.operationplugin.describe_output(arg_name: str, description: str)

Decorator to set the description for output arg_name.

This is useful for annotating the parameter with additional information for users.

These annotations are displayed in GUI representations of the operation.

Parameters
  • arg_name (str) – Name of the input to add options for.

  • description (str) – A human-readable description of the output arg_name.

Example

Define an operation and attach a description to its square output.

>>> @OperationPlugin
>>> @output_names('square')
>>> @describe_output('square', 'The squared value of x.')
>>> def square(x: int = 100) -> int:
>>>     return x**2
@xicam.plugins.operationplugin.display_name

Set the display name for the operation.

Display name is how this operation’s name will be displayed in Xi-cam.

Parameters

name (str) – Name for the operation.

Example

Create an operation whose display name is “Cube Operation.”

>>> @OperationPlugin
>>> @display_name('Cube Operation')
>>> def cube(n: int = 2) -> int:
>>>     return n**3
@xicam.plugins.operationplugin.fixed(arg_name, fix=True)

Decorator to set whether or not an input’s value is fixed.

Fixed means that the input’s value is fixed in the context of model fitting.

By default, sets the arg_name input to fixed, meaning its value cannot be changed.

Parameters
  • arg_name (str) – Name of the input to change fix-state for.

  • fix (bool, optional) – Whether or not to fix arg_name (default is True).

  • example (TODO) –

@xicam.plugins.operationplugin.input_names

Decorator to define input names for the operation.

The number of names provided must match the number of arguments for the operation/function.

If not provided, input names will be determined by examining the names of the arguments to the operation function.

Example

Create an addition operation and use the names “first” and “second” for the input names instead of the function arg names (x and y).

>>> @OperationPlugin
>>> @input_names("first", "second")
>>> def my_add(x: int, y: int) -> int:
>>>     return x + y
@xicam.plugins.operationplugin.limits(arg_name, limit)

Decorator to define limits for an input.

Limits restrict the allowable values for the input (inclusive lower-bound, inclusive upper-bound).

Parameters
  • arg_name (str) – Name of the input to define limits for.

  • limit (tuple[float]) – A 2-element sequence representing the lower and upper limit.

Example

Make an operation that has a limit on the x parameter from [0, 100].

>>> @OperationPlugin
>>> @limits('x', [0, 100])
>>> def op(x):
>>>     ...

Make an operation that has a limit on the x parameter from [0.0, 1.0].

>>> @OperationPlugin
>>> @limits('x', [0.0, 1.0])
>>> @opts('x', step=0.1)
>>> def op(x):
>>>     ...
@xicam.plugins.operationplugin.output_shape(arg_name: str, shape: Union[int, Collection[int]])

Decorator to set the shape of an output in an operation.”

Parameters
  • arg_name (str) – Name of the output to define a shape for.

  • shape (int or tuple of ints) – N-element tuple representing the shape (dimensions) of the output.

Example

TODO

@xicam.plugins.operationplugin.opts(arg_name: str, **options)

Decorator to set the opts (pyqtgraph Parameter opts) for arg_name.

This is useful for attaching any extra attributes onto an operation input argument.

These options correspond to the optional opts expected by pyqtgraph.Parameter. The options are typically used to add extra configuration to a Parameter.

Parameters
  • arg_name (str) – Name of the input to add options for.

  • options (keyword args) – Keyword arguments that can be used for the rendering backend (pyqtgraph).

Example

Define an operation where the x input is readonly.

>>> @OperationPlugin
>>> @opts('x', 'readonly'=True)
>>> def op(x: str = 100) -> str:
>>>     return x
@xicam.plugins.operationplugin.units(arg_name, unit)

Decorator to define units for an input.

Associates a unit of measurement with an input.

Parameters
  • arg_name (str) – Name of the input to attach a unit to.

  • unit (str) – Unit of measurement descriptor to use (e.g. “mm”).

Example

Create an operation where its x parameter has its units defined in microns.

>>> @OperationPlugin
>>> @units('x', 'μ'+'m')
>>> def op(x: float = -1) -> float:
>>>     return x *= -1.0
@xicam.plugins.operationplugin.visible(arg_name: str, is_visible=True)

Decorator to set whether an input is visible (shown in GUI) or not.

Parameters
  • arg_name (str) – Name of the input to change visibility for.

  • is_visible (bool, optional) – Whether or not to make the input visible or not (default is True).

Example

Define an operation that makes the data_image invisible to the GUI (when using as_parameter() and pyqtgraph).

>>> @OperationPlugin
>>> @visible('data_image')
>>> def threshold(data_image: np.ndarray, threshold: float = 0.5) -> np.ndarray:
>>>     return ...
class xicam.plugins.operationplugin.OperationPlugin(**filled_values)

A plugin that can be used to define an operation, which can be used in a Workflow.

Note: use the @operation decorator to create an operation type.

At its simplest level, an operation can be though of as a function. Any arguments (parameters) defined in the python function are treated as inputs for the operation. An operation’s outputs are defined by the returned values of the python function.

There are various methods available to help with modifying the operation’s parameters.

For more information on the attributes, see the documentation for their respective method (e.g. for more information on limits, see the limits method documentation).

For an easy way to expose parameters in the GUI, use OperationPlugin.as_parameter in conjunction with pyqtgraph.Parameter.create. Note that only input parameters that have type hinting annotations will be included in the return value of OperationPlugin.as_parameter.

filled_values

Keys are the parameter names, values are the current values for the parameter.

Type

dict

fixable

Keys are the parameter names, values are bools indicating whether or not the parameter is able to be fixed.

Type

dict

fixed

Keys are the parameter names, values are bools indicating whether or not the parameter is fixed.

Type

dict

input_names

Names (in order) of the input argument(s) for the operation. Note that if not provided, input names default to the argument names in the function signature.

Type

Tuple[str, …]

limits

Keys are the parameter names, values are the limits (which are a collection of floats).

Type

dict

opts

Any additional options (kwargs) to be passed to the parameter (useful with pyqtgraph).

Type

dict

output_names

Names (in order) of the output(s) for the operation.

Type

Tuple[str, …]

output_shape

Keys are the output parameter names, values are the expected shape of the output (which are of type list).

Type

dict

units

Keys are the parameter names, values are units (of type str).

Type

dict

visible

Keys are the pareameter names, values are bools indicating whehter or not the parameter is visible (when exposed using pyqtgraph).

Type

dict

disabled

Whether or not the operation is disabled (default is False).

Type

bool

display_name

The name of the operation as it should be displayed to a user.

Type

str

hints
Type

list

input_descriptions

A mapping dict containing descriptions of each named input parameter

Type

dict

output_descriptions

A mapping dict containing descriptions of each named output parameter

Type

dict

Notes

This class formally deprecates usage of the ProcessingPlugin API.

Example

Here, we define a function, then wrap it with the OperationPlugin decorator to make it an operation.

>>> @OperationPlugin
>>> def my_operation(x: int = 1, y: int = 2): -> int
>>>     return x + y
class xicam.plugins.operationplugin.ValidationError(operation, message)

Bases: OperationError

Exception raised for invalid OperationPlugin configurations.

operation

Reference to the operation that failed its validation check.

Type

OperationPlugin

message

Explanation of the error.

Type

str