Skip to content

Commit

Permalink
Implemented reverse selection expression transforms
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr committed Mar 2, 2020
1 parent 4bfffce commit 9df4a55
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 6 deletions.
46 changes: 44 additions & 2 deletions holoviews/core/accessors.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,46 @@ def _filter_cache(self, dmap, kdims):
filtered.append((key, value))
return filtered

def _transform_dimension(self, kdims, vdims, dimension):
if dimension in kdims:
idx = kdims.index(dimension)
dimension = self._obj.kdims[idx]
elif dimension in vdims:
idx = vdims.index(dimension)
dimension = self._obj.vdims[idx]
return dimension

def _create_expression_transform(self, kdims, vdims, exclude=[]):
from .dimension import dimension_name, Dimension
from ..util.transform import dim

def _transform_expression(expression):
if dimension_name(expression.dimension) in exclude:
dimension = expression.dimension
else:
dimension = self._transform_dimension(
kdims, vdims, expression.dimension
)
expression = expression.clone(dimension)
ops = []
for op in expression.ops:
new_op = dict(op)
new_args = []
for arg in op['args']:
if isinstance(arg, dim):
arg = _transform_expression(arg)
new_args.append(arg)
new_op['args'] = tuple(new_args)
new_kwargs = {}
for kw, kwarg in op['kwargs'].items():
if isinstance(kwarg, dim):
kwarg = _transform_expression(kwarg)
new_kwargs[kw] = kwarg
new_op['kwargs'] = new_kwargs
ops.append(new_op)
expression.ops = ops
return expression
return _transform_expression

def __call__(self, specs=None, **dimensions):
"""
Expand All @@ -331,13 +371,15 @@ def __call__(self, specs=None, **dimensions):
kdims = self.replace_dimensions(obj.kdims, dimensions)
vdims = self.replace_dimensions(obj.vdims, dimensions)
zipped_dims = zip(obj.kdims+obj.vdims, kdims+vdims)
renames = {pk.name: nk for pk, nk in zipped_dims if pk != nk}
renames = {pk.name: nk for pk, nk in zipped_dims if pk.name != nk.name}

if self.mode == 'dataset':
data = obj.data
if renames:
data = obj.interface.redim(obj, renames)
clone = obj.clone(data, kdims=kdims, vdims=vdims)
transform = self._create_expression_transform(kdims, vdims, list(renames.values()))
transforms = obj._transforms + [transform]
clone = obj.clone(data, kdims=kdims, vdims=vdims, transforms=transforms)
if self._obj.dimensions(label='name') == clone.dimensions(label='name'):
# Ensure that plot_id is inherited as long as dimension
# name does not change
Expand Down
14 changes: 11 additions & 3 deletions holoviews/core/data/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,14 +283,21 @@ def __init__(self, data, kdims=None, vdims=None, **kwargs):
input_data = data
dataset_provided = 'dataset' in kwargs
input_dataset = kwargs.pop('dataset', None)
input_pipeline = kwargs.pop(
'pipeline', None
)
input_pipeline = kwargs.pop('pipeline', None)
input_transforms = kwargs.pop('transforms', None)

if isinstance(data, Element):
pvals = util.get_param_values(data)
kwargs.update([(l, pvals[l]) for l in ['group', 'label']
if l in pvals and l not in kwargs])
if isinstance(data, Dataset):
if not dataset_provided and data._dataset is not None:
input_dataset = data._dataset
if input_pipeline is None:
input_pipeline = data.pipeline
if input_transforms is None:
input_transforms = data._transforms

kwargs.update(process_dimensions(kdims, vdims))
kdims, vdims = kwargs.get('kdims'), kwargs.get('vdims')

Expand All @@ -316,6 +323,7 @@ def __init__(self, data, kdims=None, vdims=None, **kwargs):
operations=input_pipeline.operations + [init_op],
output_type=type(self),
)
self._transforms = input_transforms or []

# Handle initializing the dataset property.
self._dataset = None
Expand Down
2 changes: 1 addition & 1 deletion holoviews/core/dimension.py
Original file line number Diff line number Diff line change
Expand Up @@ -965,7 +965,7 @@ def get_dimension(self, dimension, default=None, strict=False):
if isinstance(dimension, Dimension):
dims = [d for d in all_dims if dimension == d]
if strict and not dims:
raise KeyError("Dimension %r not found." % dimension)
raise KeyError("%r not found." % dimension)
elif dims:
return dims[0]
else:
Expand Down
3 changes: 3 additions & 0 deletions holoviews/streams.py
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,9 @@ def _set_expr(**params):
params = dict(params, index_cols=self._index_cols)
selection_expr, bbox, region_element = \
element._get_selection_expr_for_stream_value(**params)
for expr_transform in element._transforms[::-1]:
if selection_expr is not None:
selection_expr = expr_transform(selection_expr)

self.event(
selection_expr=selection_expr,
Expand Down
14 changes: 14 additions & 0 deletions holoviews/util/transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,20 @@ def __init__(self, obj, *args, **kwargs):
'reverse': kwargs.pop('reverse', False)}]
self.ops = ops


def clone(self, dimension=None, ops=None):
"""
Creates a clone of the dim expression optionally overriding
the dim and ops.
"""
if dimension is None:
dimension = self.dimension
new_dim = dim(dimension)
if ops is None:
ops = list(self.ops)
new_dim.ops = ops
return new_dim

@classmethod
def register(cls, key, function):
"""
Expand Down

0 comments on commit 9df4a55

Please sign in to comment.