class Callable
Callable is a wrapper class for callback functions used with DynamicMaps, providing memoization, stream management, and input/output tracking capabilities.
/tf/active/vicechatdev/patches/spaces.py
434 - 602
complex
Purpose
This class wraps callable functions to enable advanced features for dynamic visualizations in HoloViews. It manages memoization of function results based on arguments and stream states, tracks input dependencies for chaining operations, handles stream mappings for interactive visualizations, and provides introspection capabilities for the wrapped function. It's primarily used to create dynamic, interactive visualizations that can respond to user interactions and efficiently cache results.
Source Code
class Callable(param.Parameterized):
"""
Callable allows wrapping callbacks on one or more DynamicMaps
allowing their inputs (and in future outputs) to be defined.
This makes it possible to wrap DynamicMaps with streams and
makes it possible to traverse the graph of operations applied
to a DynamicMap.
Additionally, if the memoize attribute is True, a Callable will
memoize the last returned value based on the arguments to the
function and the state of all streams on its inputs, to avoid
calling the function unnecessarily. Note that because memoization
includes the streams found on the inputs it may be disabled if the
stream requires it and is triggering.
A Callable may also specify a stream_mapping which specifies the
objects that are associated with interactive (i.e. linked) streams
when composite objects such as Layouts are returned from the
callback. This is required for building interactive, linked
visualizations (for the backends that support them) when returning
Layouts, NdLayouts or GridSpace objects. When chaining multiple
DynamicMaps into a pipeline, the link_inputs parameter declares
whether the visualization generated using this Callable will
inherit the linked streams. This parameter is used as a hint by
the applicable backend.
The mapping should map from an appropriate key to a list of
streams associated with the selected object. The appropriate key
may be a type[.group][.label] specification for Layouts, an
integer index or a suitable NdLayout/GridSpace key. For more
information see the DynamicMap tutorial at holoviews.org.
"""
callable = param.Callable(default=None, constant=True, doc="""
The callable function being wrapped.""")
inputs = param.List(default=[], constant=True, doc="""
The list of inputs the callable function is wrapping. Used
to allow deep access to streams in chained Callables.""")
operation_kwargs = param.Dict(default={}, constant=True, doc="""
Potential dynamic keyword arguments associated with the
operation.""")
link_inputs = param.Boolean(default=True, doc="""
If the Callable wraps around other DynamicMaps in its inputs,
determines whether linked streams attached to the inputs are
transferred to the objects returned by the Callable.
For example the Callable wraps a DynamicMap with an RangeXY
stream, this switch determines whether the corresponding
visualization should update this stream with range changes
originating from the newly generated axes.""")
memoize = param.Boolean(default=True, doc="""
Whether the return value of the callable should be memoized
based on the call arguments and any streams attached to the
inputs.""")
operation = param.Callable(default=None, doc="""
The function being applied by the Callable. May be used
to record the transform(s) being applied inside the
callback function.""")
stream_mapping = param.Dict(default={}, constant=True, doc="""
Defines how streams should be mapped to objects returned by
the Callable, e.g. when it returns a Layout.""")
def __init__(self, callable, **params):
super().__init__(callable=callable,
**dict(params, name=util.callable_name(callable)))
self._memoized = {}
self._is_overlay = False
self.args = None
self.kwargs = None
self._stream_memoization = self.memoize
@property
def argspec(self):
return util.argspec(self.callable)
@property
def noargs(self):
"Returns True if the callable takes no arguments"
noargs = FullArgSpec(args=[], varargs=None, varkw=None, defaults=None, kwonlyargs=None, kwonlydefaults=None, annotations=None)
return self.argspec == noargs
def clone(self, callable=None, **overrides):
"""Clones the Callable optionally with new settings
Args:
callable: New callable function to wrap
**overrides: Parameter overrides to apply
Returns:
Cloned Callable object
"""
old = {k: v for k, v in self.param.get_param_values()
if k not in ['callable', 'name']}
params = dict(old, **overrides)
callable = self.callable if callable is None else callable
return self.__class__(callable, **params)
def __call__(self, *args, **kwargs):
"""Calls the callable function with supplied args and kwargs.
If enabled uses memoization to avoid calling function
unneccessarily.
Args:
*args: Arguments passed to the callable function
**kwargs: Keyword arguments passed to the callable function
Returns:
Return value of the wrapped callable function
"""
# Nothing to do for callbacks that accept no arguments
kwarg_hash = kwargs.pop('_memoization_hash_', ())
(self.args, self.kwargs) = (args, kwargs)
if not args and not kwargs and not any(kwarg_hash): return self.callable()
inputs = [i for i in self.inputs if isinstance(i, DynamicMap)]
streams = []
for stream in [s for i in inputs for s in get_nested_streams(i)]:
if stream not in streams: streams.append(stream)
memoize = self._stream_memoization and not any(s.transient and s._triggering for s in streams)
values = tuple(tuple(sorted(s.hashkey.items())) for s in streams)
key = args + kwarg_hash + values
hashed_key = util.deephash(key) if self.memoize else None
if hashed_key is not None and memoize and hashed_key in self._memoized:
return self._memoized[hashed_key]
if self.argspec.varargs is not None:
# Missing information on positional argument names, cannot promote to keywords
pass
elif len(args) != 0: # Turn positional arguments into keyword arguments
pos_kwargs = {k:v for k,v in zip(self.argspec.args, args)}
ignored = range(len(self.argspec.args),len(args))
if len(ignored):
self.param.warning('Ignoring extra positional argument %s'
% ', '.join('%s' % i for i in ignored))
clashes = set(pos_kwargs.keys()) & set(kwargs.keys())
if clashes:
self.param.warning(
'Positional arguments %r overriden by keywords'
% list(clashes))
args, kwargs = (), dict(pos_kwargs, **kwargs)
try:
ret = self.callable(*args, **kwargs)
except KeyError:
# KeyError is caught separately because it is used to signal
# invalid keys on DynamicMap and should not warn
raise
except Exception as e:
posstr = ', '.join(['%r' % el for el in self.args]) if self.args else ''
kwstr = ', '.join('%s=%r' % (k,v) for k,v in self.kwargs.items())
argstr = ', '.join([el for el in [posstr, kwstr] if el])
message = ("Callable raised \"{e}\".\n"
"Invoked as {name}({argstr})")
self.param.warning(message.format(name=self.name, argstr=argstr, e=repr(e)))
raise
if hashed_key is not None:
self._memoized = {hashed_key : ret}
return ret
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
bases |
param.Parameterized | - |
Parameter Details
callable: The callable function to be wrapped. This is the core function that will be executed when the Callable instance is invoked. Must be a valid Python callable (function, lambda, method, etc.).
inputs: List of input objects (typically DynamicMaps) that this callable depends on. Used to traverse the graph of operations and access nested streams. Default is empty list.
operation_kwargs: Dictionary of dynamic keyword arguments associated with the operation. These are potential parameters that may be passed to the callable. Default is empty dict.
link_inputs: Boolean flag determining whether linked streams from input DynamicMaps should be transferred to objects returned by this Callable. When True, interactive streams (like RangeXY) are propagated. Default is True.
memoize: Boolean flag controlling whether the callable's return value should be cached based on call arguments and stream states. When True, avoids redundant function calls. Default is True.
operation: Optional callable representing the actual operation/transform being applied. Used for recording the transformation pipeline. Default is None.
stream_mapping: Dictionary defining how streams should be mapped to objects returned by the Callable (e.g., when returning Layouts). Keys can be type specifications, indices, or Layout keys. Default is empty dict.
**params: Additional parameters passed to the parent param.Parameterized class, including 'name' which is auto-generated from the callable if not provided.
Return Value
Instantiation returns a Callable object that wraps the provided function. When the instance is called (via __call__), it returns the result of executing the wrapped callable function with the provided arguments. The clone() method returns a new Callable instance with optionally modified settings. The argspec property returns a FullArgSpec object describing the callable's signature. The noargs property returns a boolean indicating if the callable takes no arguments.
Class Interface
Methods
__init__(self, callable, **params)
Purpose: Initialize the Callable wrapper with a function and configuration parameters
Parameters:
callable: The function to wrap**params: Additional parameters including inputs, memoize, link_inputs, operation, stream_mapping, operation_kwargs
Returns: None - initializes the Callable instance
@property argspec(self)
property
Purpose: Returns the argument specification of the wrapped callable function
Returns: FullArgSpec object containing args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, and annotations
@property noargs(self)
property
Purpose: Checks if the wrapped callable takes no arguments
Returns: Boolean - True if the callable accepts no arguments, False otherwise
clone(self, callable=None, **overrides)
Purpose: Creates a copy of the Callable with optionally modified settings
Parameters:
callable: Optional new callable function to wrap in the clone. If None, uses the current callable**overrides: Parameter overrides to apply to the cloned instance (e.g., memoize=False, link_inputs=False)
Returns: New Callable instance with the same or modified configuration
__call__(self, *args, **kwargs)
Purpose: Executes the wrapped callable function with memoization support
Parameters:
*args: Positional arguments to pass to the wrapped function**kwargs: Keyword arguments to pass to the wrapped function. Special kwarg '_memoization_hash_' is used internally for cache key generation
Returns: The return value of the wrapped callable function, potentially retrieved from cache if memoization is enabled
Attributes
| Name | Type | Description | Scope |
|---|---|---|---|
callable |
param.Callable | The wrapped callable function. This is a constant parameter that cannot be changed after initialization. | instance |
inputs |
param.List | List of input objects (typically DynamicMaps) that this callable depends on. Used for stream traversal and dependency tracking. Constant after initialization. | instance |
operation_kwargs |
param.Dict | Dictionary of dynamic keyword arguments associated with the operation. Constant after initialization. | instance |
link_inputs |
param.Boolean | Flag controlling whether linked streams from inputs are transferred to returned objects. Can be modified after initialization. | instance |
memoize |
param.Boolean | Flag controlling whether return values should be cached based on arguments and stream states. Can be modified after initialization. | instance |
operation |
param.Callable | Optional callable representing the operation being applied. Used for recording transformations in the pipeline. | instance |
stream_mapping |
param.Dict | Dictionary mapping keys to lists of streams for composite return objects. Constant after initialization. | instance |
_memoized |
dict | Internal cache storing the last memoized result. Key is a hash of arguments and stream states, value is the cached return value. | instance |
_is_overlay |
bool | Internal flag indicating if the callable returns an overlay object. Initialized to False. | instance |
args |
tuple or None | Stores the positional arguments from the last call to __call__. Used for debugging and error reporting. | instance |
kwargs |
dict or None | Stores the keyword arguments from the last call to __call__. Used for debugging and error reporting. | instance |
_stream_memoization |
bool | Internal copy of the memoize setting used for stream-aware memoization logic. Initialized from the memoize parameter. | instance |
Dependencies
paramnumpyholoviews.core.utilholoviews.core.traversalholoviews.core.dimensionholoviews.core.layoutholoviews.core.ndmappingholoviews.core.overlayholoviews.core.optionsholoviews.streams
Required Imports
import param
import numpy as np
from inspect import FullArgSpec
from holoviews.core import util
from holoviews.core.spaces import DynamicMap
from holoviews.streams import get_nested_streams
Conditional/Optional Imports
These imports are only needed under specific conditions:
from inspect import ArgSpec as FullArgSpec
Condition: Fallback for older Python versions that don't have FullArgSpec
OptionalUsage Example
import param
from holoviews.core.spaces import Callable, DynamicMap
import numpy as np
# Define a simple callback function
def my_callback(x, y):
return x + y
# Create a Callable wrapper
callable_obj = Callable(my_callback, memoize=True, link_inputs=True)
# Call the wrapped function
result = callable_obj(5, 10)
print(result) # Output: 15
# Clone with different settings
cloned = callable_obj.clone(memoize=False)
# Check if callable takes no arguments
print(callable_obj.noargs) # Output: False
# Access the argument specification
print(callable_obj.argspec)
# Example with DynamicMap inputs
def process_data(data):
return data * 2
dmap = DynamicMap(lambda: np.random.rand(10))
callable_with_inputs = Callable(process_data, inputs=[dmap])
result = callable_with_inputs(np.array([1, 2, 3]))
Best Practices
- Enable memoization (memoize=True) for expensive computations to avoid redundant calls
- Set link_inputs=False if you don't want interactive streams to propagate from inputs to outputs
- Use stream_mapping when returning composite objects (Layouts, NdLayouts) to properly associate streams with sub-objects
- The callable should handle exceptions gracefully as the wrapper will catch and log them with context
- Memoization is automatically disabled for transient streams that are triggering to ensure fresh data
- When chaining Callables, be aware that streams from inputs are collected and their states affect memoization
- The _memoized cache only stores the last result, so it's not a full LRU cache
- Positional arguments are automatically converted to keyword arguments when possible for better introspection
- The args and kwargs attributes store the last call's arguments for debugging purposes
- Use clone() to create variations of a Callable with different settings without modifying the original
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
class DynamicMap 63.4% similar
-
function dynamicmap_memoization 62.3% similar
-
class HoloMap 51.6% similar
-
function validate_dynamic_argspec 48.4% similar
-
class periodic_v1 47.7% similar