From 47ccfe1abeeb86e10da967f361e531fa84827a78 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Mon, 12 Sep 2016 19:42:45 +0100
Subject: [PATCH 1/5] Added utilities to handle streamed dimensions
---
holoviews/core/util.py | 24 +++++++++++++++++++++---
1 file changed, 21 insertions(+), 3 deletions(-)
diff --git a/holoviews/core/util.py b/holoviews/core/util.py
index b2ecb27981..6d90dc3e79 100644
--- a/holoviews/core/util.py
+++ b/holoviews/core/util.py
@@ -803,15 +803,23 @@ def dimensionless_contents(streams, kdims):
with any of the key dimensions.
"""
names = stream_parameters(streams)
- kdim_names = [kdim.name for kdim in kdims]
- return [name for name in names if name not in kdim_names]
+ return [name for name in names if name not in kdims]
+
+
+def streamless_dimensions(streams, kdims):
+ """
+ Return a list of dimensions that have not been associated with
+ any streams.
+ """
+ params = stream_parameters(streams)
+ return [d for d in kdims if d not in params]
def wrap_tuple_streams(unwrapped, kdims, streams):
"""
Fills in tuple keys with dimensioned stream values as appropriate.
"""
- param_groups = [(s.params().keys(), s) for s in streams]
+ param_groups = [(s.contents.keys(), s) for s in streams]
pairs = [(name,s) for (group, s) in param_groups for name in group]
substituted = []
for pos,el in enumerate(wrap_tuple(unwrapped)):
@@ -824,6 +832,16 @@ def wrap_tuple_streams(unwrapped, kdims, streams):
return tuple(substituted)
+def drop_streams(streams, keys, kdims):
+ """
+ Drop any dimensionsed streams from the keys and kdims.
+ """
+ stream_params = stream_parameters(streams)
+ inds, dims = zip(*[(ind, kdim) for ind, kdim in enumerate(kdims)
+ if kdim not in stream_params])
+ return dims, [tuple(key[ind] for ind in inds) for key in keys]
+
+
def itervalues(obj):
"Get value iterator from dictionary for Python 2 and 3"
return iter(obj.values()) if sys.version_info.major == 3 else obj.itervalues()
From 11fda8bcd2ffa30d3e8858d63b547c9103f1a268 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Mon, 12 Sep 2016 19:46:27 +0100
Subject: [PATCH 2/5] Widgets now ignore streamed dimensions
---
holoviews/plotting/bokeh/widgets.py | 4 ----
holoviews/plotting/mpl/widgets.py | 9 ---------
holoviews/plotting/plot.py | 12 ++++++++----
holoviews/plotting/renderer.py | 7 ++++---
holoviews/plotting/widgets/__init__.py | 20 ++++++++++++++------
5 files changed, 26 insertions(+), 26 deletions(-)
diff --git a/holoviews/plotting/bokeh/widgets.py b/holoviews/plotting/bokeh/widgets.py
index 0433ec4018..345710be1e 100644
--- a/holoviews/plotting/bokeh/widgets.py
+++ b/holoviews/plotting/bokeh/widgets.py
@@ -43,10 +43,6 @@ def _plot_figure(self, idx, fig_format='json'):
msg = dict(patch=json_patch, root=self.plot.state._id)
msg = serialize_json(msg)
return msg
- else:
- self.plot.push()
- return "Complete"
-
class BokehSelectionWidget(BokehWidget, SelectionWidget):
pass
diff --git a/holoviews/plotting/mpl/widgets.py b/holoviews/plotting/mpl/widgets.py
index 6f26a4cb1c..07a48a6869 100644
--- a/holoviews/plotting/mpl/widgets.py
+++ b/holoviews/plotting/mpl/widgets.py
@@ -32,15 +32,6 @@ def _plot_figure(self, idx):
return self.renderer.html(self.plot, figure_format, comm=False)
- def update(self, key):
- if self.plot.dynamic == 'bounded' and not isinstance(key, int):
- key = tuple(dim.values[k] if dim.values else k
- for dim, k in zip(self.mock_obj.kdims, tuple(key)))
- self.plot[key]
- self.plot.push()
- return '' if self.renderer.mode == 'nbagg' else 'Complete'
-
-
def get_frames(self):
if self.renderer.mode == 'nbagg':
manager = self.plot.comm.get_figure_manager()
diff --git a/holoviews/plotting/plot.py b/holoviews/plotting/plot.py
index 2e4fd3c73e..22678f6e01 100644
--- a/holoviews/plotting/plot.py
+++ b/holoviews/plotting/plot.py
@@ -484,10 +484,9 @@ def refresh(self, **kwargs):
the updated data if the plot has an associated Comm.
"""
traverse_setter(self, '_force', True)
- if self.current_key:
- self.update(self.current_key)
- else:
- self.update(0)
+ key = self.current_key if self.current_key else self.keys[0]
+ stream_key = util.wrap_tuple_streams(key, self.dimensions, self.streams)
+ self.update(stream_key)
if self.comm is not None:
self.push()
@@ -573,6 +572,8 @@ def __init__(self, element, keys=None, ranges=None, dimensions=None,
**dict(params, **plot_opts))
if top_level:
self.comm = self.init_comm(element)
+ if isinstance(self.hmap, DynamicMap):
+ self.streams = self.hmap.streams
# Update plot and style options for batched plots
if self.batched:
@@ -920,6 +921,9 @@ def __init__(self, layout, keys=None, dimensions=None, **params):
**params)
if top_level:
self.comm = self.init_comm(layout)
+ self.streams = [s for streams in layout.traverse(lambda x: x.streams,
+ [DynamicMap])
+ for s in streams]
def _get_frame(self, key):
diff --git a/holoviews/plotting/renderer.py b/holoviews/plotting/renderer.py
index b2e9884e44..1e4c4856ec 100644
--- a/holoviews/plotting/renderer.py
+++ b/holoviews/plotting/renderer.py
@@ -11,7 +11,7 @@
import param
from ..core.io import Exporter
from ..core.options import Store, StoreOptions, SkipRendering
-from ..core.util import find_file, unicode
+from ..core.util import find_file, unicode, streamless_dimensions
from .. import Layout, HoloMap, AdjointLayout
from .widgets import NdWidget, ScrubberWidget, SelectionWidget
@@ -201,9 +201,10 @@ def _validate(self, obj, fmt):
holomap_formats = self.mode_formats['holomap'][self.mode]
if fmt in ['auto', None]:
- if ((len(plot) == 1 and not plot.dynamic)
+ if (((len(plot) == 1 and not plot.dynamic)
or (len(plot) > 1 and self.holomap is None) or
- (plot.dynamic and len(plot.keys[0]) == 0)):
+ (plot.dynamic and len(plot.keys[0]) == 0)) or
+ not streamless_dimensions(plot.streams, plot.dimensions)):
fmt = fig_formats[0] if self.fig=='auto' else self.fig
else:
fmt = holomap_formats[0] if self.holomap=='auto' else self.holomap
diff --git a/holoviews/plotting/widgets/__init__.py b/holoviews/plotting/widgets/__init__.py
index c04755dffd..d1093cde46 100644
--- a/holoviews/plotting/widgets/__init__.py
+++ b/holoviews/plotting/widgets/__init__.py
@@ -8,7 +8,8 @@
from ...core import OrderedDict, NdMapping
from ...core.options import Store
from ...core.util import (dimension_sanitizer, safe_unicode,
- unique_array, unicode, isnumeric)
+ unique_array, unicode, isnumeric,
+ wrap_tuple_streams, drop_streams)
from ...core.traversal import hierarchical
def escape_vals(vals, escape_numerics=True):
@@ -106,9 +107,8 @@ def __init__(self, plot, renderer=None, **params):
super(NdWidget, self).__init__(**params)
self.id = plot.comm.target if plot.comm else uuid.uuid4().hex
self.plot = plot
- self.dimensions = plot.dimensions
- self.keys = plot.keys
-
+ dims, keys = drop_streams(drop_streams, plot.keys, plot.dimensions)
+ self.dimensions, self.keys = dims, keys
self.json_data = {}
if self.plot.dynamic: self.embed = False
if renderer is None:
@@ -194,7 +194,9 @@ def _plot_figure(self, idx):
def update(self, key):
- return self._plot_figure(key)
+ self.plot.update(key)
+ self.plot.push()
+ return 'Complete'
@@ -370,4 +372,10 @@ def update(self, key):
if self.plot.dynamic:
key = tuple(dim.values[k] if dim.values else k
for dim, k in zip(self.mock_obj.kdims, tuple(key)))
- return self._plot_figure(key)
+ key = [key[self.dimensions.index(kdim)] if kdim in self.dimensions else None
+ for kdim in self.plot.dimensions]
+ key = wrap_tuple_streams(tuple(key), self.plot.dimensions,
+ self.plot.streams)
+ self.plot.update(key)
+ self.plot.push()
+ return 'Complete'
From 75e63ccced713ce422a01a87ccbaa50ac1115324 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Mon, 12 Sep 2016 19:54:19 +0100
Subject: [PATCH 3/5] Small fix when defining Plot.streams
---
holoviews/plotting/plot.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/holoviews/plotting/plot.py b/holoviews/plotting/plot.py
index 22678f6e01..57e80bbdcb 100644
--- a/holoviews/plotting/plot.py
+++ b/holoviews/plotting/plot.py
@@ -572,8 +572,7 @@ def __init__(self, element, keys=None, ranges=None, dimensions=None,
**dict(params, **plot_opts))
if top_level:
self.comm = self.init_comm(element)
- if isinstance(self.hmap, DynamicMap):
- self.streams = self.hmap.streams
+ self.streams = self.hmap.streams if isinstance(self.hmap, DynamicMap) else []
# Update plot and style options for batched plots
if self.batched:
From 14e609b9e5ff0e5f2cbd1e54cdd1d4c65d4afdd6 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Mon, 12 Sep 2016 20:08:25 +0100
Subject: [PATCH 4/5] Fixed bug in widgets
---
holoviews/plotting/widgets/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/holoviews/plotting/widgets/__init__.py b/holoviews/plotting/widgets/__init__.py
index d1093cde46..b79226543a 100644
--- a/holoviews/plotting/widgets/__init__.py
+++ b/holoviews/plotting/widgets/__init__.py
@@ -107,7 +107,7 @@ def __init__(self, plot, renderer=None, **params):
super(NdWidget, self).__init__(**params)
self.id = plot.comm.target if plot.comm else uuid.uuid4().hex
self.plot = plot
- dims, keys = drop_streams(drop_streams, plot.keys, plot.dimensions)
+ dims, keys = drop_streams(plot.streams, plot.keys, plot.dimensions)
self.dimensions, self.keys = dims, keys
self.json_data = {}
if self.plot.dynamic: self.embed = False
From 51bb81d7868dde4cc99749ec05a697e67dc80a8d Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Mon, 12 Sep 2016 21:07:51 +0100
Subject: [PATCH 5/5] Minor cleanup
---
holoviews/core/util.py | 4 ++--
holoviews/plotting/renderer.py | 4 ++--
holoviews/plotting/widgets/__init__.py | 6 ++++--
3 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/holoviews/core/util.py b/holoviews/core/util.py
index 6d90dc3e79..040f3bc625 100644
--- a/holoviews/core/util.py
+++ b/holoviews/core/util.py
@@ -806,7 +806,7 @@ def dimensionless_contents(streams, kdims):
return [name for name in names if name not in kdims]
-def streamless_dimensions(streams, kdims):
+def unbound_dimensions(streams, kdims):
"""
Return a list of dimensions that have not been associated with
any streams.
@@ -832,7 +832,7 @@ def wrap_tuple_streams(unwrapped, kdims, streams):
return tuple(substituted)
-def drop_streams(streams, keys, kdims):
+def drop_streams(streams, kdims, keys):
"""
Drop any dimensionsed streams from the keys and kdims.
"""
diff --git a/holoviews/plotting/renderer.py b/holoviews/plotting/renderer.py
index 1e4c4856ec..860e98d306 100644
--- a/holoviews/plotting/renderer.py
+++ b/holoviews/plotting/renderer.py
@@ -11,7 +11,7 @@
import param
from ..core.io import Exporter
from ..core.options import Store, StoreOptions, SkipRendering
-from ..core.util import find_file, unicode, streamless_dimensions
+from ..core.util import find_file, unicode, unbound_dimensions
from .. import Layout, HoloMap, AdjointLayout
from .widgets import NdWidget, ScrubberWidget, SelectionWidget
@@ -204,7 +204,7 @@ def _validate(self, obj, fmt):
if (((len(plot) == 1 and not plot.dynamic)
or (len(plot) > 1 and self.holomap is None) or
(plot.dynamic and len(plot.keys[0]) == 0)) or
- not streamless_dimensions(plot.streams, plot.dimensions)):
+ not unbound_dimensions(plot.streams, plot.dimensions)):
fmt = fig_formats[0] if self.fig=='auto' else self.fig
else:
fmt = holomap_formats[0] if self.holomap=='auto' else self.holomap
diff --git a/holoviews/plotting/widgets/__init__.py b/holoviews/plotting/widgets/__init__.py
index b79226543a..4a903de91c 100644
--- a/holoviews/plotting/widgets/__init__.py
+++ b/holoviews/plotting/widgets/__init__.py
@@ -107,8 +107,10 @@ def __init__(self, plot, renderer=None, **params):
super(NdWidget, self).__init__(**params)
self.id = plot.comm.target if plot.comm else uuid.uuid4().hex
self.plot = plot
- dims, keys = drop_streams(plot.streams, plot.keys, plot.dimensions)
- self.dimensions, self.keys = dims, keys
+ self.dimensions, self.keys = drop_streams(plot.streams,
+ plot.dimensions,
+ plot.keys)
+
self.json_data = {}
if self.plot.dynamic: self.embed = False
if renderer is None: