Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Operation fixes #1093

Merged
merged 7 commits into from Feb 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 1 addition & 2 deletions holoviews/core/element.py
Expand Up @@ -39,8 +39,7 @@ def hist(self, dimension=None, num_bins=20, bin_range=None,
hists = []
for d in dimension[::-1]:
hist = histogram(self, num_bins=num_bins, bin_range=bin_range,
adjoin=False, individually=individually,
dimension=d, **kwargs)
individually=individually, dimension=d, **kwargs)
hists.append(hist)
if adjoin:
layout = self
Expand Down
3 changes: 2 additions & 1 deletion holoviews/core/util.py
Expand Up @@ -849,7 +849,8 @@ def is_dataframe(data):
def get_param_values(data):
params = dict(kdims=data.kdims, vdims=data.vdims,
label=data.label)
if data.group != data.params()['group'].default:
if (data.group != data.params()['group'].default and not
isinstance(type(data).group, property)):
params['group'] = data.group
return params

Expand Down
6 changes: 4 additions & 2 deletions holoviews/operation/datashader.py
@@ -1,6 +1,7 @@
from __future__ import absolute_import

from collections import Callable, Iterable
import warnings

import param
import numpy as np
Expand Down Expand Up @@ -309,8 +310,9 @@ def _process(self, element, key=None):
else:
shade_opts['cmap'] = self.p.cmap


img = tf.shade(array, **shade_opts)
with warnings.catch_warnings():
warnings.filterwarnings('ignore', r'invalid value encountered in true_divide')
img = tf.shade(array, **shade_opts)
params = dict(get_param_values(element), kdims=kdims,
bounds=bounds, vdims=RGB.vdims[:])
return RGB(self.uint32_to_uint8(img.data), **params)
Expand Down
23 changes: 7 additions & 16 deletions holoviews/operation/element.py
Expand Up @@ -462,22 +462,16 @@ class histogram(ElementOperation):
Returns a Histogram of the input element data, binned into
num_bins over the bin_range (if specified) along the specified
dimension.

If adjoin is True, the histogram will be returned adjoined to the
Element as a side-plot.
"""

adjoin = param.Boolean(default=True, doc="""
Whether to adjoin the histogram to the ViewableElement.""")

bin_range = param.NumericTuple(default=(0, 0), doc="""
bin_range = param.NumericTuple(default=None, length=2, doc="""
Specifies the range within which to compute the bins.""")

dimension = param.String(default=None, doc="""
Along which dimension of the ViewableElement to compute the histogram.""")
Along which dimension of the Element to compute the histogram.""")

individually = param.Boolean(default=True, doc="""
Specifies whether the histogram will be rescaled for each Raster in a UniformNdMapping.""")
Specifies whether the histogram will be rescaled for each Element in a UniformNdMapping.""")

log = param.Boolean(default=False, doc="""
Whether to use base 10 logarithmic samples for the bin edges.""")
Expand Down Expand Up @@ -547,10 +541,8 @@ def _process(self, view, key=None):
if view.group != view.__class__.__name__:
params['group'] = view.group

hist_view = Histogram(hist, edges, kdims=[view.get_dimension(selected_dim)],
label=view.label, **params)

return (view << hist_view) if self.p.adjoin else hist_view
return Histogram(hist, edges, kdims=[view.get_dimension(selected_dim)],
label=view.label, **params)



Expand Down Expand Up @@ -700,9 +692,8 @@ def _process(self, p, element, ranges={}):
if d1 == d2:
if p.diagonal_type is Histogram:
bin_range = ranges.get(d1.name, element.range(d1))
el = element.hist(dimension=d1.name,
bin_range=bin_range,
adjoin=False)(norm=dict(axiswise=True, framewise=True))
el = histogram(element, dimension=d1.name, bin_range=bin_range)
el = el(norm=dict(axiswise=True, framewise=True))
else:
values = element.dimension_values(d1)
el = p.diagonal_type(values, vdims=[d1])
Expand Down
85 changes: 85 additions & 0 deletions tests/testoperation.py
@@ -0,0 +1,85 @@
import numpy as np

from holoviews import (HoloMap, NdOverlay, Image, Contours, Polygons, Points,
Histogram)
from holoviews.element.comparison import ComparisonTestCase
from holoviews.operation.element import (operation, transform, threshold,
gradient, contours, histogram)

class ElementOperationTests(ComparisonTestCase):
"""
Tests allowable data formats when constructing
the basic Element types.
"""

def test_operation_element(self):
img = Image(np.random.rand(10, 10))
op_img = operation(img, op=lambda x, k: x.clone(x.data*2))
self.assertEqual(op_img, img.clone(img.data*2, group='Operation'))

def test_operation_holomap(self):
hmap = HoloMap({1: Image(np.random.rand(10, 10))})
op_hmap = operation(hmap, op=lambda x, k: x.clone(x.data*2))
self.assertEqual(op_hmap.last, hmap.last.clone(hmap.last.data*2, group='Operation'))

def test_image_transform(self):
img = Image(np.random.rand(10, 10))
op_img = transform(img, operator=lambda x: x*2)
self.assertEqual(op_img, img.clone(img.data*2, group='Transform'))

def test_image_threshold(self):
img = Image(np.array([[0, 1, 0], [3, 4, 5.]]))
op_img = threshold(img)
self.assertEqual(op_img, img.clone(np.array([[0, 1, 0], [1, 1, 1]]), group='Threshold'))

def test_image_gradient(self):
img = Image(np.array([[0, 1, 0], [3, 4, 5.], [6, 7, 8]]))
op_img = gradient(img)
self.assertEqual(op_img, img.clone(np.array([[3.162278, 3.162278], [3.162278, 3.162278]]), group='Gradient'))

def test_image_contours(self):
img = Image(np.array([[0, 1, 0], [3, 4, 5.], [6, 7, 8]]))
op_contours = contours(img)
ndoverlay = NdOverlay(None, kdims=['Levels'])
ndoverlay[0.5] = Contours([[(-0.5, 0.416667), (-0.25, 0.5)], [(0.25, 0.5), (0.5, 0.45)]],
group='Level', level=0.5, vdims=img.vdims)
self.assertEqual(op_contours, img*ndoverlay)

def test_image_contours_filled(self):
img = Image(np.array([[0, 1, 0], [3, 4, 5.], [6, 7, 8]]))
op_contours = contours(img, filled=True, levels=[2, 2.5])
ndoverlay = NdOverlay(None, kdims=['Levels'])
data = [[(0., 0.333333), (0.5, 0.3), (0.5, 0.25), (0., 0.25),
(-0.5, 0.08333333), (-0.5, 0.16666667), (0., 0.33333333)]]
ndoverlay[0.5] = Polygons(data, group='Level', level=2, vdims=img.vdims)
self.assertEqual(op_contours, img*ndoverlay)

def test_points_histogram(self):
points = Points([float(i) for i in range(10)])
op_hist = histogram(points, num_bins=3)
hist = Histogram(([0.1, 0.1, 0.133333], [0, 3, 6, 9]))
self.assertEqual(op_hist, hist)

def test_points_histogram_bin_range(self):
points = Points([float(i) for i in range(10)])
op_hist = histogram(points, num_bins=3, bin_range=(0, 3))
hist = Histogram(([0.25, 0.25, 0.5], [0., 1., 2., 3.]))
self.assertEqual(op_hist, hist)

def test_points_histogram_not_normed(self):
points = Points([float(i) for i in range(10)])
op_hist = histogram(points, num_bins=3, normed=False)
hist = Histogram(([3, 3, 4], [0, 3, 6, 9]))
self.assertEqual(op_hist, hist)

def test_points_histogram_weighted(self):
points = Points([float(i) for i in range(10)])
op_hist = histogram(points, num_bins=3, weight_dimension='y')
hist = Histogram(([0.022222, 0.088889, 0.222222], [0, 3, 6, 9]), vdims=['y'])
self.assertEqual(op_hist, hist)

def test_points_histogram_mean_weighted(self):
points = Points([float(i) for i in range(10)])
op_hist = histogram(points, num_bins=3, weight_dimension='y', mean_weighted=True)
hist = Histogram(([1., 4., 7.5], [0, 3, 6, 9]), vdims=['y'])
self.assertEqual(op_hist, hist)