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