Property#
- class deeptrack.properties.Property(sampling_rule: Callable[..., Any] | list[Any] | dict[Any, Any] | tuple[Any, ...] | np.ndarray | torch.Tensor | slice | DeepTrackNode | Any, node_name: str | None = None, **dependencies: Property)#
Bases:
DeepTrackNodeProperty of a feature in the DeepTrack2 framework.
A Property defines a rule for sampling values used to evaluate features. It supports various data types and structures, such as constants, functions, lists, iterators, dictionaries, tuples, NumPy arrays, PyTorch tensors, slices, and DeepTrackNode objects.
The behavior of a Property depends on the type of the sampling rule:
- Constant values (including tuples, NumPy arrays, and PyTorch
tensors) always return the same value.
- Functions are evaluated dynamically, potentially using other
properties as arguments.
- **Lists, dictionaries, or tuples ** evaluate and sample each member
individually.
- Iterators return the next value in the sequence, repeating the final
value indefinitely.
Slices sample the start, stop, and step values individually.
- DeepTrackNode’s (e.g., other properties or features) use the value
computed by the node.
Dependencies between properties are tracked automatically, enabling efficient recomputation when dependencies change.
Parameters#
- sampling_rule: Any
The rule for sampling values. Can be a constant, function, list, dictionary, iterator, tuple, NumPy array, PyTorch tensor, slice, or DeepTrackNode.
- node_name: str | None
The name of this node. Defaults to None.
- **dependencies: Property
Additional dependencies passed as named arguments. These dependencies can be used as inputs to functions or other dynamic components of the sampling rule.
Methods#
- create_action(sampling_rule, **dependencies) -> Callable[…, Any]
Creates an action that defines how the property is evaluated. The behavior of the action depends on the type of sampling_rule.
Examples#
>>> import deeptrack as dt
Constant properties are returned forever:
>>> const_prop = dt.Property(42) # Number >>> const_prop() 42
>>> const_prop = dt.Property([1, 2, 3]) # List >>> const_prop() [1, 2, 3]
>>> const_prop = dt.Property((1, 2, 3)) # Tuple >>> const_prop() (1, 2, 3)
>>> import numpy as np >>> >>> const_prop = dt.Property(np.array([1, 2, 3])) # NumPy array >>> const_prop() array([1, 2, 3])
>>> import torch >>> >>> const_prop = dt.Property(torch.Tensor([1, 2, 3])) # PyTorch tensor >>> const_prop() tensor([1., 2., 3.])
Dynamic property typically use functions and can also depend on other properties:
>>> dynamic_prop = dt.Property(lambda: np.random.rand()) >>> dynamic_prop() # Returns random value 0.37700241766131415 >>> dynamic_prop() # Returns same random value 0.37700241766131415 >>> dynamic_prop.update() # Updates the value >>> dynamic_prop() # Returns different random value 0.5862725216547282 >>> dynamic_prop.new() # Returns different random value 0.36122033451938484
>>> const_prop = dt.Property(5) >>> dynamic_prop = dt.Property(lambda x: 2 * x, x=const_prop) >>> dynamic_prop() 10
>>> def func(x): ... return 2 * x >>> >>> const_prop = dt.Property(5) >>> dynamic_prop = dt.Property(func, x=const_prop) >>> dynamic_prop() 10
Slices can be constructed from dynamic or static components:
>>> slice_prop = dt.Property(slice(1, lambda: 10, dt.Property(2))) >>> s = slice_prop() >>> s.start, s.stop, s.step (1, 10, 2)
Iterators return their next value each time, repeating the last indefinitely:
>>> iter_prop = dt.Property(iter([1, 2, 3])) >>> iter_prop() 1 >>> iter_prop.new() # equivalent to iter_prop.update()() 2 >>> iter_prop.new() 3 >>> iter_prop.new() # Last value repeats 3
Lists, dictionaries, and tuples can contain properties, functions, or constants:
>>> list_prop = dt.Property([ ... 1, ... lambda: 2, ... dt.Property(3), ... ]) >>> list_prop() [1, 2, 3]
>>> dict_prop = dt.Property({ ... "a": 1, ... "b": lambda: 2, ... "c": dt.Property(3), ... }) >>> dict_prop() {'a': 1, 'b': 2, 'c': 3}
>>> tuple_prop = dt.Property(( ... 1, ... lambda: 2, ... dt.Property(3), ... )) >>> tuple_prop() (1, 2, 3)
Property can wrap a DeepTrackNode, such as another feature node:
>>> node = dt.DeepTrackNode(100) >>> node_prop = dt.Property(node) >>> node_prop() 100
>>> node = dt.DeepTrackNode(lambda _ID=(): np.random.rand()) >>> node_prop = dt.Property(node) >>> node_prop() 0.5065650298607408
The ID mechanism allows parameterizing evaluation:
>>> id_prop0 = dt.Property(lambda _ID: _ID) >>> id_prop0() () >>> id_prop0((1,)) () >>> id_prop0((1, 2, 3)) ()
>>> id_prop1 = dt.Property(lambda _ID: _ID) >>> id_prop1((1,)) (1,) >>> id_prop1((1, 2, 3)) (1,)
>>> id_prop2 = dt.Property(lambda _ID: _ID) >>> id_prop2((1, 2, 3)) (1, 2, 3)
Properties can be combined in complex nested structures:
>>> P = dt.Property( ... { ... "constant": 42, ... "list": [1, lambda: 2, dt.Property(3)], ... "dict": {"a": dt.Property(1), "b": lambda: 2}, ... "function": lambda x, y: x * y, ... "slice": slice(1, lambda: 10, dt.Property(2)), ... }, ... x=dt.Property(5), ... y=dt.Property(3), ... ) >>> result = P() >>> result["constant"] 42 >>> result["list"] [1, 2, 3] >>> result["dict"] {'a': 1, 'b': 2} >>> result["function"] 15 >>> result["slice"].start 1 >>> result["slice"].stop 10 >>> result["slice"].step 2
Methods Summary
create_action(sampling_rule, **dependencies)Create an action defining how the property is evaluated.
Methods Documentation
- create_action(sampling_rule: Callable[..., Any] | list[Any] | dict[Any, Any] | tuple[Any, ...] | np.ndarray | torch.Tensor | slice | DeepTrackNode | Any, **dependencies: Property) Callable[..., Any]#
Create an action defining how the property is evaluated.
Parameters#
- sampling_rule: Any
The rule to sample values for the property. It can be essentially anything, most often: Callable[…, Any] or list[Any] or dict[Any, Any] or tuple or NumPy array or PyTorch tensor or slice or DeepTrackNode or Any
- **dependencies: Property
Dependencies to be used in the sampling rule.
Returns#
- Callable[…, Any]
A callable that defines the evaluation behavior of the property.