Skip to content

Commit

Permalink
Moved stream_remapping specification onto Callable
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr committed Apr 5, 2017
1 parent 002ded4 commit a2cfa4c
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 18 deletions.
47 changes: 41 additions & 6 deletions holoviews/core/spaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,13 @@ class Callable(param.Parameterized):
returned value based on the arguments to the function and the
state of all streams on its inputs, to avoid calling the function
unnecessarily.
A Callable may also specify a stream_mapping which allows
specifying which objects to attached linked streams to on
callbacks which return composite objects like (Nd)Layout and
GridSpace objects. The mapping should map between an integer index
or a type[.group][.label] specification and lists of streams
matching the object.
"""

callable_function = param.Callable(default=lambda x: x, doc="""
Expand All @@ -410,11 +417,12 @@ class Callable(param.Parameterized):
inputs = param.List(default=[], doc="""
The list of inputs the callable function is wrapping.""")

def __init__(self, callable_function=None, **params):
def __init__(self, callable_function=None, stream_mapping={}, **params):
if callable_function is not None:
params['callable_function'] = callable_function
super(Callable, self).__init__(**params)
self._memoized = {}
self.stream_mapping = stream_mapping

def __call__(self, *args, **kwargs):
inputs = [i for i in self.inputs if isinstance(i, DynamicMap)]
Expand Down Expand Up @@ -796,7 +804,7 @@ def dynamic_redim(obj):
return Dynamic(redimmed, shared_data=True, operation=dynamic_redim)


def collate(self, streams=[]):
def collate(self):
"""
Collation allows collapsing DynamicMaps with invalid nesting
hierarchies. This is particularly useful when defining
Expand Down Expand Up @@ -842,21 +850,48 @@ def collation_cb(*args, **kwargs):
# Expand Layout/NdLayout
from ..util import Dynamic
new_item = self.last.clone(shared_data=False)

# Get stream mapping from callback
remapped_streams = []
streams = self.callback.stream_mapping
for i, (k, v) in enumerate(self.last.items()):
if isinstance(streams, dict):
vstreams = streams.get(i, [])
elif isinstance(streams, list):
vstreams = streams[i] if i < len(streams) else []
vstreams = streams.get(i, [])
if not vstreams:
if isinstance(self.last, Layout):
for l in range(len(k)):
path = '.'.join(k[:l])
if path in streams:
vstreams = streams[path]
break
else:
vstreams = streams.get(k, [])
remapped_streams += vstreams

# Define collation callback
def collation_cb(*args, **kwargs):
return self[args][kwargs['collation_key']]
callback = Callable(partial(collation_cb, collation_key=k),
inputs=[self])
vdmap = self.clone(callback=callback, shared_data=False,
streams=vstreams)

# Remap source of streams
for stream in vstreams:
if stream.source is self:
stream.source = vdmap
new_item[k] = vdmap

unmapped_streams = [repr(stream) for stream in self.streams
if (stream.source is self) and
(stream not in remapped_streams)
and stream.linked]
if unmapped_streams:
raise ValueError(
'The following streams are set to be automatically '
'linked to a plot, but no stream_mapping specifying '
'which item in the (Nd)Layout to link it to was found:\n%s'
% ', '.join(unmapped_streams)
)
return new_item
else:
self.warning('DynamicMap does not need to be collated.')
Expand Down
2 changes: 2 additions & 0 deletions holoviews/plotting/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ def collate(obj):
"structure shown in the Composing Data tutorial"
"(http://git.io/vtIQh)" % nested_type)
return obj.collate()
if isinstance(obj, DynamicMap):
return obj.collate()
if isinstance(obj, HoloMap):
display_warning.warning("Nesting {0}s within a {1} makes it difficult "
"to access your data or control how it appears; "
Expand Down
36 changes: 24 additions & 12 deletions holoviews/streams.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ class Stream(param.Parameterized):
the parameter dictionary when the trigger classmethod is called.
Depending on the plotting backend certain streams may interactively
subscribe to events and changes by the plotting backend. To disable
this behavior instantiate the Stream with linked=False.
subscribe to events and changes by the plotting backend. For this
purpose use the LinkedStream baseclass, which enables the linked
option by default.
"""

# Mapping from a source id to a list of streams
Expand Down Expand Up @@ -60,7 +61,7 @@ def trigger(cls, streams):
stream.deactivate()


def __init__(self, rename={}, source=None, subscribers=[], linked=True, **params):
def __init__(self, rename={}, source=None, subscribers=[], linked=False, **params):
"""
The rename argument allows multiple streams with similar event
state to be used by remapping parameter names.
Expand Down Expand Up @@ -222,7 +223,18 @@ def __str__(self):
return repr(self)


class PositionX(Stream):
class LinkedStream(Stream):
"""
A LinkedStream indicates is automatically linked to plot interactions
on a backend via a Renderer. Not all backends may support dynamically
supplying stream data.
"""

def __init__(self, linked=True, **params):
super(LinkedStream, self).__init__(linked=linked, **params)


class PositionX(LinkedStream):
"""
A position along the x-axis in data coordinates.
Expand All @@ -234,7 +246,7 @@ class PositionX(Stream):
Position along the x-axis in data coordinates""", constant=True)


class PositionY(Stream):
class PositionY(LinkedStream):
"""
A position along the y-axis in data coordinates.
Expand All @@ -246,7 +258,7 @@ class PositionY(Stream):
Position along the y-axis in data coordinates""", constant=True)


class PositionXY(Stream):
class PositionXY(LinkedStream):
"""
A position along the x- and y-axes in data coordinates.
Expand Down Expand Up @@ -287,7 +299,7 @@ class MouseLeave(PositionXY):
"""


class PlotSize(Stream):
class PlotSize(LinkedStream):
"""
Returns the dimensions of a plot once it has been displayed.
"""
Expand All @@ -304,7 +316,7 @@ def transform(self):
'height': int(self.height * self.scale)}


class RangeXY(Stream):
class RangeXY(LinkedStream):
"""
Axis ranges along x- and y-axis in data coordinates.
"""
Expand All @@ -316,7 +328,7 @@ class RangeXY(Stream):
Range of the y-axis of a plot in data coordinates""")


class RangeX(Stream):
class RangeX(LinkedStream):
"""
Axis range along x-axis in data coordinates.
"""
Expand All @@ -325,7 +337,7 @@ class RangeX(Stream):
Range of the x-axis of a plot in data coordinates""")


class RangeY(Stream):
class RangeY(LinkedStream):
"""
Axis range along y-axis in data coordinates.
"""
Expand All @@ -334,7 +346,7 @@ class RangeY(Stream):
Range of the y-axis of a plot in data coordinates""")


class Bounds(Stream):
class Bounds(LinkedStream):
"""
A stream representing the bounds of a box selection as an
tuple of the left, bottom, right and top coordinates.
Expand All @@ -345,7 +357,7 @@ class Bounds(Stream):
Bounds defined as (left, bottom, top, right) tuple.""")


class Selection1D(Stream):
class Selection1D(LinkedStream):
"""
A stream representing a 1D selection of objects by their index.
"""
Expand Down

0 comments on commit a2cfa4c

Please sign in to comment.