Skip to content

Commit

Permalink
Merge pull request #1103 from ioam/merge_dimension_values
Browse files Browse the repository at this point in the history
Merge dynamic dimension values
  • Loading branch information
jlstevens committed Feb 6, 2017
2 parents 9d23b9e + f66ec43 commit b38c518
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 4 deletions.
3 changes: 2 additions & 1 deletion holoviews/core/spaces.py
Expand Up @@ -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()
Expand Down
4 changes: 2 additions & 2 deletions holoviews/core/traversal.py
Expand Up @@ -8,6 +8,7 @@
from operator import itemgetter

from .dimension import Dimension, OrderedDict
from .util import merge_dimensions

try:
import itertools.izip as zip
Expand Down Expand Up @@ -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]
Expand Down
26 changes: 26 additions & 0 deletions holoviews/core/util.py
Expand Up @@ -608,6 +608,32 @@ 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
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 = []
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
Expand Down
18 changes: 17 additions & 1 deletion tests/testutils.py
Expand Up @@ -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
Expand Down Expand Up @@ -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])

0 comments on commit b38c518

Please sign in to comment.