Function plugins
Defines a plugin architecture so that new functions can be defined at runtime
and made available to the FunctionFactoryBase
used in the GUI to list available functions, and for analysis
.
ceed.function.register_all_functions()
is called by the GUI and it
registers any plugin functions with the
ceed.function.FunctionFactoryBase
used by the GUI for managing
functions. ceed.function.register_all_functions()
internally calls
get_plugin_functions()
to get all the functions exported by all the
Python plugin module files in the ceed/function/plugin
directory and
registers them with the ceed.function.FunctionFactoryBase
.
Additionally, if the user provides a package name in the
external_function_plugin_package
configuration
variable, the GUI will similarly import and register the plugins in
that package with ceed.function.register_external_functions()
.
The package must however be a proper python package that can be imported.
E.g. if external_function_plugin_package
is my_ceed_plugin.func
, Ceed will try something roughly like
from my_ceed_plugin.func import get_ceed_functions
.
Files in ceed/function/plugin
that want to define new function or function
distribution classes should define a function in the file called
get_ceed_functions
or get_ceed_distributions
, respectively, that
returns a list of functions or function distributions that will be
automatically registered with the function factory
FunctionFactoryBase
or
param_noise_factory
, respectively,
using register()
or
register_class()
.
To write a plugin, familiarize yourself with
FuncBase
, it’s properties, and relevant methods that
need to be overridden. CeedFunc
is the actual class
to inherit from. Some relevant methods are
get_gui_props()
,
get_state()
,
get_noise_supported_parameters()
,
get_prop_pretty_name()
,
init_func_tree()
,
init_func()
,
init_loop_iteration()
,
get_relative_time()
, and
resample_parameters()
.
__call__()
is how the function is called. It
takes the time in global time so it should convert it to function local time
with get_relative_time()
and then return the
function value.
See the ceed/function/plugin/__init__.py
file and
get_ceed_functions()
and get_ceed_distributions()
for an example
plugin.
- ceed.function.plugin.get_plugin_functions(function_factory: ceed.function.FunctionFactoryBase, base_package: str, root: Union[str, pathlib.Path]) Tuple[List[Type[ceed.function.FuncType]], List[Type[ceed.function.param_noise.NoiseType]], List[Tuple[Tuple[str], bytes]]]
Imports all the
.py
files in the given directory and sub-directories for the named package that don’t start with a underscore (except for__init__.py
of course, which is imported). For each imported module, it calls itsget_ceed_functions
andget_ceed_distributions
function (if they are defined in the module) which should return a list (that can be empty) of all the function and function distribution classes, respectively, exported by the module.It then returns all these exported functions, distributions, and all the file contents in the folder.
Ceed will automatically import all the plugins under
ceed/function/plugin
.- Parameters
function_factory – The
FunctionFactoryBase
instance with which the returned plugin functions will be registered.base_package – The package name from which the plugins will be imported. E.g. to import the plugins in
ceed/function/plugin
,base_package
isceed.function.plugin
because that’s the package containing name for theplugin
directory. Then, they are imported asceed.function.plugin
andceed.function.plugin.xyz
, if the plugin directory also contains axyz.py
plugin file.root – The full directory path that contains the plugins. E.g. for
ceed.function.plugin
it isceed/function/plugin
.
- Returns
A tuple with three values containing: a list of function classes exported by all the modules, a list of distribution classes exported by all the modules, and a list containing all the python files contents encountered in the directory.
The python files contents are returned so that Ceed can store it in the data files in case the plugins are changed between experimental runs.
See
get_ceed_functions()
,get_ceed_distributions()
, andregister_all_functions()
for an example how it’s used.
- class ceed.function.plugin.ConstFunc(name='Const', description='y(t) = a', **kwargs)
Bases:
ceed.function.CeedFunc
Defines a function which returns a constant value.
The function is defined as
y(t) = a
.- a
The amplitude value of the function.
- get_gui_props()
Called internally by the GUI to get the properties of the function that should be displayed to the user to be customized.
- Returns
A dict that contains all properties that should be displayed. The values of the property is as follows:
If it’s the string int, float, str or it’s the python type int, float, or str then the GUI will show a editable property for this type.
If it’s None, we look at the value of the property in the instance and display accordingly (e.g. if it’s a str type property, a string property is displayed to the user).
Note
The default value determines the type. So if the default value is
0
, the type will be int and a user won’t be able to enter a float. Use e.g.0.0
in the latter case.
E.g.:
>>> Cos = function_factory.get('CosFunc') >>> cos = Cos() >>> cos.get_gui_props() {'A': None, 'duration': None, 'f': None, 'loop': None, 'name': None, 't_offset': None, 'th0': None}
- get_state(*largs, **kwargs)
Returns a dict representation of the function so that it can be reconstructed later with
apply_state()
.- Params
- recurse: bool
When the function has children functions, e.g. a
FuncGroup
, if True all the children functions’ states will also be returned, otherwise, only this function’s state is returned. See the example.- expand_ref: bool
If True, if any sub-functions (or this function itself) are
CeedFuncRef
instances, they will be expanded to contain the state of the actual underlying function. Otherwise, it is returned as being a function reference.
- Returns
A dict with all the configuration data.
E.g.:
>>> Cos = function_factory.get('CosFunc') >>> cos = Cos() >>> cos.get_state() {'A': 1.0, 'cls': 'CosFunc', 'duration': 0, 'f': 1.0, 'loop': 1, 'name': 'Cos', 't_offset': 0, 'th0': 0.0} >>> Group = function_factory.get('FuncGroup') >>> g = Group() >>> g <ceed.function.FuncGroup at 0x4f85800> >>> g.add_func(cos) >>> g.get_state(recurse=True) {'cls': 'FuncGroup', 'funcs': [{'A': 1.0, 'cls': 'CosFunc', 'duration': 0, 'f': 1.0, 'loop': 1, 'name': 'Cos', 't_offset': 0, 'th0': 0.0}], 'loop': 1, 'name': 'Group'} >>> g.get_state(recurse=False) {'cls': 'FuncGroup', 'loop': 1, 'name': 'Group'}
- get_noise_supported_parameters()
Returns the set of property names of this function that supports randomness and may have an
ceed.function.param_noise.NoiseBase
instance associated with it.
- class ceed.function.plugin.LinearFunc(**kwargs)
Bases:
ceed.function.CeedFunc
Defines a linearly increasing function.
The function is defined as
y(t_in) = mt + b
, wheret = (t_in - t_start + t_offset)
.- m
The line’s slope.
- b
The line’s zero intercept.
- get_gui_props()
Called internally by the GUI to get the properties of the function that should be displayed to the user to be customized.
- Returns
A dict that contains all properties that should be displayed. The values of the property is as follows:
If it’s the string int, float, str or it’s the python type int, float, or str then the GUI will show a editable property for this type.
If it’s None, we look at the value of the property in the instance and display accordingly (e.g. if it’s a str type property, a string property is displayed to the user).
Note
The default value determines the type. So if the default value is
0
, the type will be int and a user won’t be able to enter a float. Use e.g.0.0
in the latter case.
E.g.:
>>> Cos = function_factory.get('CosFunc') >>> cos = Cos() >>> cos.get_gui_props() {'A': None, 'duration': None, 'f': None, 'loop': None, 'name': None, 't_offset': None, 'th0': None}
- get_state(*largs, **kwargs)
Returns a dict representation of the function so that it can be reconstructed later with
apply_state()
.- Params
- recurse: bool
When the function has children functions, e.g. a
FuncGroup
, if True all the children functions’ states will also be returned, otherwise, only this function’s state is returned. See the example.- expand_ref: bool
If True, if any sub-functions (or this function itself) are
CeedFuncRef
instances, they will be expanded to contain the state of the actual underlying function. Otherwise, it is returned as being a function reference.
- Returns
A dict with all the configuration data.
E.g.:
>>> Cos = function_factory.get('CosFunc') >>> cos = Cos() >>> cos.get_state() {'A': 1.0, 'cls': 'CosFunc', 'duration': 0, 'f': 1.0, 'loop': 1, 'name': 'Cos', 't_offset': 0, 'th0': 0.0} >>> Group = function_factory.get('FuncGroup') >>> g = Group() >>> g <ceed.function.FuncGroup at 0x4f85800> >>> g.add_func(cos) >>> g.get_state(recurse=True) {'cls': 'FuncGroup', 'funcs': [{'A': 1.0, 'cls': 'CosFunc', 'duration': 0, 'f': 1.0, 'loop': 1, 'name': 'Cos', 't_offset': 0, 'th0': 0.0}], 'loop': 1, 'name': 'Group'} >>> g.get_state(recurse=False) {'cls': 'FuncGroup', 'loop': 1, 'name': 'Group'}
- get_noise_supported_parameters()
Returns the set of property names of this function that supports randomness and may have an
ceed.function.param_noise.NoiseBase
instance associated with it.
- class ceed.function.plugin.ExponentialFunc(**kwargs)
Bases:
ceed.function.CeedFunc
Defines a double exponential function.
The function is defined as
y(t_in) = Ae^-t/tau1 + Be^-t/tau2
, wheret = (t_in - t_start + t_offset)
.- A
The amplitude of the first exponential.
- B
The amplitude of the second exponential.
- tau1
The time constant of the first exponential.
- tau2
The time constant of the second exponential.
- get_gui_props()
Called internally by the GUI to get the properties of the function that should be displayed to the user to be customized.
- Returns
A dict that contains all properties that should be displayed. The values of the property is as follows:
If it’s the string int, float, str or it’s the python type int, float, or str then the GUI will show a editable property for this type.
If it’s None, we look at the value of the property in the instance and display accordingly (e.g. if it’s a str type property, a string property is displayed to the user).
Note
The default value determines the type. So if the default value is
0
, the type will be int and a user won’t be able to enter a float. Use e.g.0.0
in the latter case.
E.g.:
>>> Cos = function_factory.get('CosFunc') >>> cos = Cos() >>> cos.get_gui_props() {'A': None, 'duration': None, 'f': None, 'loop': None, 'name': None, 't_offset': None, 'th0': None}
- get_state(*largs, **kwargs)
Returns a dict representation of the function so that it can be reconstructed later with
apply_state()
.- Params
- recurse: bool
When the function has children functions, e.g. a
FuncGroup
, if True all the children functions’ states will also be returned, otherwise, only this function’s state is returned. See the example.- expand_ref: bool
If True, if any sub-functions (or this function itself) are
CeedFuncRef
instances, they will be expanded to contain the state of the actual underlying function. Otherwise, it is returned as being a function reference.
- Returns
A dict with all the configuration data.
E.g.:
>>> Cos = function_factory.get('CosFunc') >>> cos = Cos() >>> cos.get_state() {'A': 1.0, 'cls': 'CosFunc', 'duration': 0, 'f': 1.0, 'loop': 1, 'name': 'Cos', 't_offset': 0, 'th0': 0.0} >>> Group = function_factory.get('FuncGroup') >>> g = Group() >>> g <ceed.function.FuncGroup at 0x4f85800> >>> g.add_func(cos) >>> g.get_state(recurse=True) {'cls': 'FuncGroup', 'funcs': [{'A': 1.0, 'cls': 'CosFunc', 'duration': 0, 'f': 1.0, 'loop': 1, 'name': 'Cos', 't_offset': 0, 'th0': 0.0}], 'loop': 1, 'name': 'Group'} >>> g.get_state(recurse=False) {'cls': 'FuncGroup', 'loop': 1, 'name': 'Group'}
- get_noise_supported_parameters()
Returns the set of property names of this function that supports randomness and may have an
ceed.function.param_noise.NoiseBase
instance associated with it.
- class ceed.function.plugin.CosFunc(**kwargs)
Bases:
ceed.function.CeedFunc
Defines a cosine function.
The function is defined as
y(t_in) = Acos(2pi*f*t + th0*pi/180) + b
, wheret = (t_in - t_start + t_offset)
.- f
The function’s frequency in Hz.
- A
The function’s amplitude.
- th0
The function’s angle offset in degrees.
- b
The function’s y offset.
- get_gui_props()
Called internally by the GUI to get the properties of the function that should be displayed to the user to be customized.
- Returns
A dict that contains all properties that should be displayed. The values of the property is as follows:
If it’s the string int, float, str or it’s the python type int, float, or str then the GUI will show a editable property for this type.
If it’s None, we look at the value of the property in the instance and display accordingly (e.g. if it’s a str type property, a string property is displayed to the user).
Note
The default value determines the type. So if the default value is
0
, the type will be int and a user won’t be able to enter a float. Use e.g.0.0
in the latter case.
E.g.:
>>> Cos = function_factory.get('CosFunc') >>> cos = Cos() >>> cos.get_gui_props() {'A': None, 'duration': None, 'f': None, 'loop': None, 'name': None, 't_offset': None, 'th0': None}
- get_state(*largs, **kwargs)
Returns a dict representation of the function so that it can be reconstructed later with
apply_state()
.- Params
- recurse: bool
When the function has children functions, e.g. a
FuncGroup
, if True all the children functions’ states will also be returned, otherwise, only this function’s state is returned. See the example.- expand_ref: bool
If True, if any sub-functions (or this function itself) are
CeedFuncRef
instances, they will be expanded to contain the state of the actual underlying function. Otherwise, it is returned as being a function reference.
- Returns
A dict with all the configuration data.
E.g.:
>>> Cos = function_factory.get('CosFunc') >>> cos = Cos() >>> cos.get_state() {'A': 1.0, 'cls': 'CosFunc', 'duration': 0, 'f': 1.0, 'loop': 1, 'name': 'Cos', 't_offset': 0, 'th0': 0.0} >>> Group = function_factory.get('FuncGroup') >>> g = Group() >>> g <ceed.function.FuncGroup at 0x4f85800> >>> g.add_func(cos) >>> g.get_state(recurse=True) {'cls': 'FuncGroup', 'funcs': [{'A': 1.0, 'cls': 'CosFunc', 'duration': 0, 'f': 1.0, 'loop': 1, 'name': 'Cos', 't_offset': 0, 'th0': 0.0}], 'loop': 1, 'name': 'Group'} >>> g.get_state(recurse=False) {'cls': 'FuncGroup', 'loop': 1, 'name': 'Group'}
- get_noise_supported_parameters()
Returns the set of property names of this function that supports randomness and may have an
ceed.function.param_noise.NoiseBase
instance associated with it.
- class ceed.function.plugin.CSVFunc(**kwargs)
Bases:
ceed.function.CeedFunc
Defines a function whose frames are read from a csv file.
There’s only one column of data with no header row. Each row in the column is the value of the function for one frame. The total duration of the function is the number of frames divided by the frame rate. I.e. each row corresponds to a frame, but the depending on the fps in Ceed it can be at different times.
Values are forced to the
[0, 1]
range.The function is defined as
y(t) = row(t * fps)
.- csv_path: str
The full path to the CSV file.
- get_gui_elements()
Returns widget instances that should be displayed to the user along with this function’s editable properties of
get_gui_props()
.These widgets are displayed along with other config parameters for the function and can be used for custom config options. This is called by the Ceed GUI when the settings are first displayed to the user.
- Returns
It should return a dict of the name of each setting mapped to the widget controlling the setting. It will be displayed in two columns: the name followed by the widget on the same row.
E.g.:
>>> Cos = function_factory.get('CosFunc') >>> cos = Cos() >>> cos.get_gui_elements() {}
- get_state(*largs, **kwargs)
Returns a dict representation of the function so that it can be reconstructed later with
apply_state()
.- Params
- recurse: bool
When the function has children functions, e.g. a
FuncGroup
, if True all the children functions’ states will also be returned, otherwise, only this function’s state is returned. See the example.- expand_ref: bool
If True, if any sub-functions (or this function itself) are
CeedFuncRef
instances, they will be expanded to contain the state of the actual underlying function. Otherwise, it is returned as being a function reference.
- Returns
A dict with all the configuration data.
E.g.:
>>> Cos = function_factory.get('CosFunc') >>> cos = Cos() >>> cos.get_state() {'A': 1.0, 'cls': 'CosFunc', 'duration': 0, 'f': 1.0, 'loop': 1, 'name': 'Cos', 't_offset': 0, 'th0': 0.0} >>> Group = function_factory.get('FuncGroup') >>> g = Group() >>> g <ceed.function.FuncGroup at 0x4f85800> >>> g.add_func(cos) >>> g.get_state(recurse=True) {'cls': 'FuncGroup', 'funcs': [{'A': 1.0, 'cls': 'CosFunc', 'duration': 0, 'f': 1.0, 'loop': 1, 'name': 'Cos', 't_offset': 0, 'th0': 0.0}], 'loop': 1, 'name': 'Group'} >>> g.get_state(recurse=False) {'cls': 'FuncGroup', 'loop': 1, 'name': 'Group'}
- init_func_tree(*args, **kwargs) None
Initializes the function as part of the function tree so it is ready to be called to get the function values as part of the tree. It is called once for each function of the entire function tree.
- Parameters
root – The root of the function tree. If None, it’s self.
For example, for the following function structure:
GroupFunc: name: 'root' loop: 5 GroupFunc: name: 'child_a' loop: 3 ConstFunc: name: 'child' loop: 4
when the experiment is ready, after
resample_parameters()
and the stage is ready to run, ceed will callinit_func_tree()
once forroot
,child_a
, andchild
in that order. Theroot
parameter passed will be theroot
function.Then, it will call
init_func()
forroot
,child_a
, andchild
1, 5, and 15 times, respectively. Once for each time the function is started.Finally, it will call
init_loop_iteration()
forroot
,child_a
, andchild
4, 10, and 45 times, respectively. Once for each loop iteration of the function, except the first.
- init_func(*args, **kwargs) None
Initializes the function so it is ready to be called to get the function values. See also
init_func_tree()
andinit_loop_iteration()
. If overriding,super
must be called.- Parameters
t_start – The time in seconds in global time.
t_start
will be set to this value. All subsequent calls to the function with a time value will be relative to this given time.
- init_loop_iteration(*args, **kwargs) None
Initializes the function at the beginning of each loop.
It’s called internally at the start of every
loop
iteration, except the first. See alsoinit_func_tree()
andinit_func()
. If overriding,super
must be called.- Parameters
t_start – The time in seconds in global time.
t_start
will be set to this value. All subsequent calls to the function with a time value will be relative to this given time.
- class ceed.function.plugin.GaussianNoise(**kwargs)
Bases:
ceed.function.param_noise.NoiseBase
Represents a Gaussian distribution.
- min_val
The minimum value to clip the sampled value before returning it.
- max_val
The maximum value to clip the sampled value before returning it.
- mean_val
The mean of the distribution,
- stdev
The standard deviation of the distribution,
- sample() float
Samples the distribution and returns a new value.
- get_config() dict
Returns a dict representation of the instance that can be then be used to reconstruct it with
ParameterNoiseFactory.make_instance()
.This is also used to display the instance parameters to the user. We infer the type of each parameter from the property value.
- get_prop_pretty_name() Dict[str, str]
Returns a dict mapping names of the parameters used by the class to a nicer representation shown to the user.
- class ceed.function.plugin.UniformNoise(**kwargs)
Bases:
ceed.function.param_noise.NoiseBase
Represents a uniform distribution.
- min_val
The minimum value of the range (inclusive).
- max_val
The maximum value of the range (inclusive depending on the system).
- sample() float
Samples the distribution and returns a new value.
- get_config() dict
Returns a dict representation of the instance that can be then be used to reconstruct it with
ParameterNoiseFactory.make_instance()
.This is also used to display the instance parameters to the user. We infer the type of each parameter from the property value.
- get_prop_pretty_name() Dict[str, str]
Returns a dict mapping names of the parameters used by the class to a nicer representation shown to the user.
- class ceed.function.plugin.DiscreteNoise(**kwargs)
Bases:
ceed.function.param_noise.NoiseBase
Represents a uniform distribution from equally spaced discrete values.
- start_value
The first value in the list of values (inclusive).
- step
The distance between values (e.g. if it’s 1 and
start_value
is 0 andnum_values
is 5, we have0, 1, 2, 3, 4
).
- num_values
The total number of values (e.g. if it’s 5 and
start_value
is 0 andstep
is 1, we have0, 1, 2, 3, 4
).
- with_replacement
Whether, when sampling the distribution, to sample with replacement.
If False, then
num_values
must be at least as large asn
ofsample_seq()
, if the distribution is used to sample more than once, e.g. if each loop iteration is sampled.
- sample() float
Samples the distribution and returns a new value.
- sample_seq(n) List[float]
Samples the distribution
n
times and returns a list of values.By default it just calls
sample()
n
times to get the samples.
- get_config() dict
Returns a dict representation of the instance that can be then be used to reconstruct it with
ParameterNoiseFactory.make_instance()
.This is also used to display the instance parameters to the user. We infer the type of each parameter from the property value.
- get_prop_pretty_name() Dict[str, str]
Returns a dict mapping names of the parameters used by the class to a nicer representation shown to the user.
- class ceed.function.plugin.DiscreteListNoise(**kwargs)
Bases:
ceed.function.param_noise.NoiseBase
Represents a uniform distribution from a list of discrete values.
- csv_list: str
A comma-separated list of float or integers representing the items from from which to sample. It may have optional spaces between the items, in addition to the required commas.
- num_dup: int
When
with_replacement
isTrue
,csv_list
is duplicatednum_dup
times before we sample from it. This can ensure there are enough samples in the distribution.If
with_replacement
isFalse
and this is not1
an error is raised. Same ifnum_dup
is less than1
.
- with_replacement: bool
Whether, when sampling the distribution, to sample with replacement.
If False, then the number of items in
csv_list
must be at least as large asn
ofsample_seq()
, if the distribution is used to sample more than once, e.g. if each loop iteration is sampled.
- sample() float
Samples the distribution and returns a new value.
- sample_seq(n) List[float]
Samples the distribution
n
times and returns a list of values.By default it just calls
sample()
n
times to get the samples.
- get_config() dict
Returns a dict representation of the instance that can be then be used to reconstruct it with
ParameterNoiseFactory.make_instance()
.This is also used to display the instance parameters to the user. We infer the type of each parameter from the property value.
- get_prop_pretty_name() Dict[str, str]
Returns a dict mapping names of the parameters used by the class to a nicer representation shown to the user.
- ceed.function.plugin.get_ceed_functions(function_factory: ceed.function.FunctionFactoryBase) Iterable[Type[ceed.function.FuncType]]
Returns all the function classes defined and exported in this file (
ConstFunc
,LinearFunc
, etc.).- Parameters
function_factory – The
FunctionFactoryBase
instance currently active in Ceed.
- ceed.function.plugin.get_ceed_distributions(function_factory: ceed.function.FunctionFactoryBase) Iterable[Type[ceed.function.param_noise.NoiseType]]
Returns all the distribution classes defined and exported in this file (
GaussianNoise
,UniformNoise
, etc.).- Parameters
function_factory – The
FunctionFactoryBase
instance currently active in Ceed.