From 84f25c460f698dc37254c168b3e9c733a4a8e866 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Sun, 5 Feb 2017 22:37:22 +0000 Subject: [PATCH 1/2] Merge dynamic dimension values --- holoviews/core/spaces.py | 3 ++- holoviews/core/traversal.py | 4 ++-- holoviews/core/util.py | 17 +++++++++++++++++ tests/testutils.py | 18 +++++++++++++++++- 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/holoviews/core/spaces.py b/holoviews/core/spaces.py index 5480a33f7b..58b50a6d5b 100644 --- a/holoviews/core/spaces.py +++ b/holoviews/core/spaces.py @@ -171,7 +171,8 @@ def __mul__(self, other): # dimension labels for the new view self_in_other = self_set.issubset(other_set) other_in_self = other_set.issubset(self_set) - dimensions = self.kdims + dims = [other.kdims, self.kdims] if self_in_other else [self.kdims, other.kdims] + dimensions = util.merge_dimensions(dims) if self_in_other and other_in_self: # superset of each other keys = self._dimension_keys() + other._dimension_keys() diff --git a/holoviews/core/traversal.py b/holoviews/core/traversal.py index 896e69f708..c377e178ae 100644 --- a/holoviews/core/traversal.py +++ b/holoviews/core/traversal.py @@ -8,6 +8,7 @@ from operator import itemgetter from .dimension import Dimension, OrderedDict +from .util import merge_dimensions try: import itertools.izip as zip @@ -56,8 +57,7 @@ def unique_dimkeys(obj, default_dim='Frame'): subset = all(g1 <= g2 or g1 >= g2 for g1 in dgroups for g2 in dgroups) # Find unique keys if subset: - dims = OrderedDict([(dim.name, dim) for dim_group in dim_groups - for dim in dim_group]).values() + dims = merge_dimensions(dim_groups) all_dims = sorted(dims, key=lambda x: dim_groups[0].index(x)) else: all_dims = [default_dim] diff --git a/holoviews/core/util.py b/holoviews/core/util.py index 9223f01077..e5a071cc7b 100644 --- a/holoviews/core/util.py +++ b/holoviews/core/util.py @@ -608,6 +608,23 @@ def python2sort(x,key=None): return itertools.chain.from_iterable(sorted(group, key=key) for group in groups) +def merge_dimensions(dimensions_list): + """ + Merges lists of fully or partially overlapping dimensions by + combining their values. + """ + dvalues = defaultdict(list) + dimensions = [] + for dims in dimensions_list: + for d in dims: + dvalues[d.name].append(d.values) + if d not in dimensions: + dimensions.append(d) + dvalues = {k: list(unique_iterator(itertools.chain(*vals))) + for k, vals in dvalues.items()} + return [d(values=dvalues.get(d.name, [])) for d in dimensions] + + def dimension_sort(odict, kdims, vdims, categorical, key_index, cached_values): """ Sorts data by key using usual Python tuple sorting semantics diff --git a/tests/testutils.py b/tests/testutils.py index 7fc7b4b656..5aabb9954c 100644 --- a/tests/testutils.py +++ b/tests/testutils.py @@ -14,7 +14,10 @@ except: pd = None -from holoviews.core.util import sanitize_identifier_fn, find_range, max_range, wrap_tuple_streams, deephash +from holoviews.core.util import ( + sanitize_identifier_fn, find_range, max_range, wrap_tuple_streams, + deephash, merge_dimensions +) from holoviews import Dimension from holoviews.streams import PositionXY from holoviews.element.comparison import ComparisonTestCase @@ -447,3 +450,16 @@ def test_no_streams_two_stream_substitution(self): [Dimension('x'), Dimension('y')], [PositionXY(x=0,y=5)]) self.assertEqual(result, (0,5)) + + +class TestMergeDimensions(unittest.TestCase): + + def test_merge_dimensions(self): + dimensions = merge_dimensions([[Dimension('A')], [Dimension('A'), Dimension('B')]]) + self.assertEqual(dimensions, [Dimension('A'), Dimension('B')]) + + def test_merge_dimensions_with_values(self): + dimensions = merge_dimensions([[Dimension('A', values=[0, 1])], + [Dimension('A', values=[1, 2]), Dimension('B')]]) + self.assertEqual(dimensions, [Dimension('A'), Dimension('B')]) + self.assertEqual(dimensions[0].values, [0, 1, 2]) From f66ec437186335cca7b62ad69bb22c187e886656 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Mon, 6 Feb 2017 17:30:23 +0000 Subject: [PATCH 2/2] Added doctest to merge_dimensions utility --- holoviews/core/util.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/holoviews/core/util.py b/holoviews/core/util.py index e5a071cc7b..1800d45811 100644 --- a/holoviews/core/util.py +++ b/holoviews/core/util.py @@ -611,7 +611,16 @@ def python2sort(x,key=None): def merge_dimensions(dimensions_list): """ Merges lists of fully or partially overlapping dimensions by - combining their values. + merging their values. + + >>> from holoviews import Dimension + >>> dim_list = [[Dimension('A', values=[1, 2, 3]), Dimension('B')], + ... [Dimension('A', values=[2, 3, 4])]] + >>> dimensions = merge_dimensions(dim_list) + >>> dimensions + [Dimension('A'), Dimension('B')] + >>> dimensions[0].values + [1, 2, 3, 4] """ dvalues = defaultdict(list) dimensions = []