Skip to content

Commit

Permalink
Cleaned up .sample/.reduce API and fixed sanitization
Browse files Browse the repository at this point in the history
Fixes issue #182
  • Loading branch information
philippjfr committed Jun 26, 2015
1 parent 94020d5 commit 6685633
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 38 deletions.
4 changes: 3 additions & 1 deletion holoviews/core/dimension.py
Expand Up @@ -584,7 +584,9 @@ def get_dimension_index(self, dim):
else:
return IndexError('Dimension index out of bounds')
try:
return [d.name for d in self.dimensions()].index(dim)
sanitized = {sanitize_identifier(kd): kd
for kd in self._cached_index_names}
return [d.name for d in self.dimensions()].index(sanitized.get(dim, dim))
except ValueError:
raise Exception("Dimension %s not found in %s." %
(dim, self.__class__.__name__))
Expand Down
40 changes: 26 additions & 14 deletions holoviews/core/element.py
Expand Up @@ -10,7 +10,7 @@
from .ndmapping import OrderedDict, UniformNdMapping, NdMapping, item_check
from .overlay import Overlayable, NdOverlay, Overlay, CompositeOverlay
from .tree import AttrTree

from .util import sanitize_identifier

class Element(ViewableElement, Composable, Overlayable):
"""
Expand Down Expand Up @@ -103,26 +103,41 @@ def closest(self, coords):
return coords


def sample(self, **samples):
def sample(self, samples=[], **sample_values):
"""
Base class signature to demonstrate API for sampling Views.
To sample a ViewableElement kwargs, where the keyword matches a Dimension
in the ViewableElement and the value matches a corresponding entry in the
data.
Base class signature to demonstrate API for sampling Elements.
To sample an Element supply either a list of sampels or keyword
arguments, where the key should match an existing key dimension
on the Element.
"""
raise NotImplementedError


def reduce(self, **reduce_map):
def reduce(self, dimensions=[], function=None, **reduce_map):
"""
Base class signature to demonstrate API for reducing Elements,
using some reduce function, e.g. np.mean, which is applied
along a particular Dimension. The dimensions and reduce functions
should be passed as keyword arguments.
should be passed as keyword arguments or as a list of dimensions
and a single function.
"""
raise NotImplementedError


def _reduce_map(self, dimensions, function, reduce_map):
dimensions = self._valid_dimensions(dimensions)
if dimensions and reduce_map:
raise Exception("Pass reduced dimensions either as an argument"
"or as part of the kwargs not both.")
elif dimensions:
reduce_map = {dimensions[0]: function}
elif not reduce_map:
reduce_map = {d: function for d in self._cached_index_names}
sanitized = {sanitize_identifier(kd): kd
for kd in self._cached_index_names}
return {sanitized.get(d, d): fn for d, fn in reduce_map.items()}


def table(self, **kwargs):
"""
This method transforms any ViewableElement type into a Table
Expand Down Expand Up @@ -333,12 +348,8 @@ def reduce(self, dimensions=None, function=None, **reduce_map):
the dimension name and reduce_fn as kwargs. Reduces
dimensionality of Table until only an ItemTable is left.
"""
dimensions = self._valid_dimensions(dimensions)
if dimensions and reduce_map:
raise Exception("Pass reduced dimensions either as an argument"
"or as part of the kwargs not both.")
elif dimensions:
reduce_map = {d: function for d in dimensions}
reduce_map = self._reduce_map(dimensions, function, reduce_map)

dim_labels = self._cached_index_names
reduced_table = self
for reduce_fn, group in groupby(reduce_map.items(), lambda x: x[1]):
Expand Down Expand Up @@ -667,6 +678,7 @@ def reduce(self, dimensions=None, function=None, **reduce_map):
for k, v in self.items()]
return self.clone(reduced_items).table()


def relabel(self, label=None, group=None, depth=1):
# Identical to standard relabel method except for default depth of 1
return super(HoloMap, self).relabel(label=label, group=group, depth=depth)
Expand Down
13 changes: 3 additions & 10 deletions holoviews/element/chart.py
Expand Up @@ -139,7 +139,7 @@ def collapse_data(cls, data, function, **kwargs):

def sample(self, samples=[]):
"""
Allows sampling of Element2D objects using the default
Allows sampling of Chart Elements using the default
syntax of providing a map of dimensions and sample pairs.
"""
sample_data = OrderedDict()
Expand All @@ -158,14 +158,7 @@ def reduce(self, dimensions=[], function=None, **reduce_map):
Allows collapsing of Chart objects using the supplied map of
dimensions and reduce functions.
"""
dimensions = self._valid_dimensions(dimensions)
if dimensions and reduce_map:
raise Exception("Pass reduced dimensions either as an argument"
"or as part of the kwargs not both.")
elif dimensions:
reduce_map = {dimensions[0]: function}
elif not reduce_map:
reduce_map = {d: function for d in self._cached_index_names}
reduce_map = self._reduce_map(dimensions, function, reduce_map)

if len(reduce_map) > 1:
raise ValueError("Chart Elements may only be reduced to a point.")
Expand Down Expand Up @@ -425,7 +418,7 @@ def dimension_values(self, dim):
return super(Histogram, self).dimension_values(dim)


def sample(self, **samples):
def sample(self, samples=[], **sample_values):
raise NotImplementedError('Cannot sample a Histogram.')


Expand Down
16 changes: 5 additions & 11 deletions holoviews/element/raster.py
Expand Up @@ -99,10 +99,12 @@ def sample(self, samples=[], **sample_values):
raise ValueError(
'Raster sampling requires coordinates not slices,'
'use regular slicing syntax.')
other_dimension = [d for d in self.kdims if
d.name != dimension]
# Indices inverted for indexing
sample_ind = self.get_dimension_index(dimension)
if sample_ind is None:
raise Exception("Dimension %s not found during sampling" % dimension)
other_dimension = [d for i, d in enumerate(self.kdims) if
i != sample_ind]

# Generate sample slice
sample = [slice(None) for i in range(self.ndims)]
Expand All @@ -123,15 +125,7 @@ def reduce(self, dimensions=None, function=None, **reduce_map):
Optionally a label_prefix can be provided to prepend to
the result Element label.
"""
dimensions = self._valid_dimensions(dimensions)
if dimensions and reduce_map:
raise Exception("Pass reduced dimensions either as an argument"
"or as part of the kwargs not both.")
elif dimensions:
reduce_map = {d: function for d in dimensions}
elif not reduce_map:
reduce_map = {d: function for d in self._cached_index_names}

reduce_map = self._reduce_map(dimensions, function, reduce_map)
if len(reduce_map) == self.ndims:
reduced_view = self
for dim, reduce_fn in reduce_map.items():
Expand Down
4 changes: 2 additions & 2 deletions holoviews/interface/seaborn.py
Expand Up @@ -59,11 +59,11 @@ def dimension_values(self, dimension):
return super(TimeSeries, self).dimension_values(dimension)


def sample(self, **samples):
def sample(self, samples=[], **sample_values):
raise NotImplementedError('Cannot sample a TimeSeries.')


def reduce(self, **dimreduce_map):
def reduce(self, dimensions=[], function=None, **reduce_map):
raise NotImplementedError('Reduction of TimeSeries not '
'implemented.')

Expand Down

0 comments on commit 6685633

Please sign in to comment.