From 54283926a8408ef7786c037266e8e3258097d91a Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Mon, 18 Jul 2016 12:14:12 -0500
Subject: [PATCH 01/26] Ensure DictInterface does not consume unexpected types
---
holoviews/core/data/dictionary.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/holoviews/core/data/dictionary.py b/holoviews/core/data/dictionary.py
index 06574d0b20..51ac46a520 100644
--- a/holoviews/core/data/dictionary.py
+++ b/holoviews/core/data/dictionary.py
@@ -56,7 +56,7 @@ def init(cls, eltype, data, kdims, vdims):
data = {k: data[:,i] for i,k in enumerate(dimensions)}
elif isinstance(data, list) and np.isscalar(data[0]):
data = {dimensions[0]: np.arange(len(data)), dimensions[1]: data}
- elif not isinstance(data, dict):
+ elif not any(isinstance(data, interface) for interface in cls.interfaces):
data = {k: v for k, v in zip(dimensions, zip(*data))}
elif isinstance(data, dict) and not all(d in data for d in dimensions):
dict_data = zip(*((util.wrap_tuple(k)+util.wrap_tuple(v))
From a280914687cb1ce171d93615fdeaa68d93988e0b Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Mon, 18 Jul 2016 12:14:50 -0500
Subject: [PATCH 02/26] Reverted fix to flipped iris interface
---
holoviews/core/data/iris.py | 2 --
1 file changed, 2 deletions(-)
diff --git a/holoviews/core/data/iris.py b/holoviews/core/data/iris.py
index d4c13c1abf..14acda9a40 100644
--- a/holoviews/core/data/iris.py
+++ b/holoviews/core/data/iris.py
@@ -133,8 +133,6 @@ def values(cls, dataset, dim, expanded=True, flat=True):
dim_inds += [i for i in range(len(dataset.data.dim_coords))
if i not in dim_inds]
data = data.transpose(dim_inds)
- else:
- data = np.flipud(data)
elif expanded:
idx = dataset.get_dimension_index(dim)
data = util.cartesian_product([dataset.data.coords(d.name)[0].points
From 44262748790ad64a20981866d8b28e1356244edf Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Mon, 18 Jul 2016 12:15:25 -0500
Subject: [PATCH 03/26] Generalized and fixed xarray constructor
---
holoviews/core/data/xarray.py | 39 +++++++++++++++++++----------------
1 file changed, 21 insertions(+), 18 deletions(-)
diff --git a/holoviews/core/data/xarray.py b/holoviews/core/data/xarray.py
index abbd2bcb12..175f4faade 100644
--- a/holoviews/core/data/xarray.py
+++ b/holoviews/core/data/xarray.py
@@ -40,37 +40,40 @@ def init(cls, eltype, data, kdims, vdims):
vdim_param = element_params['vdims']
if kdims:
- kdim_names = [kd.name if isinstance(kd, Dimension) else kd for kd in kdims]
+ kdim_names = [kd.name if isinstance(kd, Dimension)
+ else kd for kd in kdims]
else:
kdim_names = [kd.name for kd in eltype.kdims]
if not isinstance(data, xr.Dataset):
- ndims = len(kdim_names)
kdims = [kd if isinstance(kd, Dimension) else Dimension(kd)
for kd in kdims]
- vdim = vdims[0].name if isinstance(vdims[0], Dimension) else vdims[0]
+ vdims = [d if isinstance(vd, Dimension) else Dimension(vd)
+ for vd in vdims]
if isinstance(data, tuple):
- value_array = np.array(data[-1])
- data = {d: vals for d, vals in zip(kdim_names + [vdim], data)}
- elif isinstance(data, dict):
- value_array = np.array(data[vdim])
- if value_array.ndim > 1:
- value_array = value_array.T
- dims, coords = zip(*[(kd.name, data[kd.name])
- for kd in kdims])
+ data = {d.name: vals for d, vals in zip(kdims + vdims, data)}
+ if not isinstance(data, dict):
+ raise TypeError('XArrayInterface could not interpret data type')
+ coords = [(kd.name, data[kd.name]) for kd in kdims][::-1]
+ arrays = {}
+ for vdim in vdims:
+ arr = data[vdim.name]
+ if not isinstance(arr, xr.DataArray):
+ arr = xr.DataArray(arr, coords=coords)
+ arrays[vdim.name] = arr
try:
- arr = xr.DataArray(value_array, coords=coords, dims=dims)
- data = xr.Dataset({vdim: arr})
+ data = xr.Dataset(arrays)
except:
pass
- if not isinstance(data, xr.Dataset):
- raise TypeError('Data must be be an xarray Dataset type.')
-
- if isinstance(data, xr.Dataset):
+ else:
if vdims is None:
vdims = list(data.data_vars.keys())
if kdims is None:
- kdims = list(data.dims.keys())
+ kdims = [name for name in data.dims
+ if isinstance(data[name].data, np.ndarray)]
+
+ if not isinstance(data, xr.Dataset):
+ raise TypeError('Data must be be an xarray Dataset type.')
return data, {'kdims': kdims, 'vdims': vdims}, {}
From 4124f299929ef430a037614294caf6574b0fab60 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Mon, 18 Jul 2016 12:15:47 -0500
Subject: [PATCH 04/26] Fix for XArrayInterface values method
---
holoviews/core/data/xarray.py | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/holoviews/core/data/xarray.py b/holoviews/core/data/xarray.py
index 175f4faade..53087f3146 100644
--- a/holoviews/core/data/xarray.py
+++ b/holoviews/core/data/xarray.py
@@ -125,8 +125,12 @@ def values(cls, dataset, dim, expanded=True, flat=True):
if dim in dataset.vdims:
if data.ndim == 1:
return np.array(data)
- else:
- return data.T.flatten() if flat else data
+ dims = [name for name in dataset.data.coords
+ if isinstance(dataset.data[name].data, np.ndarray) and
+ name in dataset.data.dims]
+ inds = [dims.index(kd.name) for kd in dataset.kdims]
+ transposed = data.transpose(inds[::-1])
+ return transposed.flatten() if flat else transposed
elif not expanded:
return data
else:
From 0079735605e46b85a0c0523a0e982f99cc389c9c Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Mon, 18 Jul 2016 12:17:33 -0500
Subject: [PATCH 05/26] Pass parameters through in dynamic groupby
---
holoviews/core/data/__init__.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/holoviews/core/data/__init__.py b/holoviews/core/data/__init__.py
index 9e00a837c1..8e58956825 100644
--- a/holoviews/core/data/__init__.py
+++ b/holoviews/core/data/__init__.py
@@ -393,13 +393,15 @@ def groupby(self, dimensions=[], container_type=HoloMap, group_type=None,
if dynamic:
group_dims = [d.name for d in self.kdims if d not in dimensions]
+ group_kwargs = dict(util.get_param_values(self))
+ group_kwargs.update(kwargs)
def load_subset(*args):
constraint = dict(zip(dim_names, args))
group = self.select(**constraint)
if np.isscalar(group):
return group_type(([group],), group=self.group,
label=self.label, vdims=self.vdims)
- return group_type(group.reindex(group_dims))
+ return group_type(group.reindex(group_dims), **group_kwargs)
dynamic_dims = [d(values=list(self.interface.values(self, d.name, False)))
for d in dimensions]
return DynamicMap(load_subset, kdims=dynamic_dims)
From f8e4ede1c1f43176ad38059222d968529cdb7f02 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Mon, 18 Jul 2016 12:17:59 -0500
Subject: [PATCH 06/26] Fixed GridImage dimension declarations
---
holoviews/element/raster.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/holoviews/element/raster.py b/holoviews/element/raster.py
index b2bf91e21a..6edb6aef65 100644
--- a/holoviews/element/raster.py
+++ b/holoviews/element/raster.py
@@ -648,9 +648,10 @@ class GridImage(Dataset, Element2D):
group = param.String(default='GridImage', constant=True)
- kdims = param.List(default=['x', 'y'], bounds=(2, 2))
+ kdims = param.List(default=[Dimension('x'), Dimension('y')],
+ bounds=(2, 2))
- vdims = param.List(default=['z'], bounds=(1, 1))
+ vdims = param.List(default=[Dimension('z')], bounds=(1, 1))
def __init__(self, data, **params):
super(GridImage, self).__init__(data, **params)
From 33b316ac3693a9dd448a8c05a430d40ede20a1fb Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Mon, 18 Jul 2016 16:14:35 -0400
Subject: [PATCH 07/26] Fix for DictInterface constructor
---
holoviews/core/data/dictionary.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/holoviews/core/data/dictionary.py b/holoviews/core/data/dictionary.py
index 51ac46a520..06cf26011d 100644
--- a/holoviews/core/data/dictionary.py
+++ b/holoviews/core/data/dictionary.py
@@ -56,7 +56,8 @@ def init(cls, eltype, data, kdims, vdims):
data = {k: data[:,i] for i,k in enumerate(dimensions)}
elif isinstance(data, list) and np.isscalar(data[0]):
data = {dimensions[0]: np.arange(len(data)), dimensions[1]: data}
- elif not any(isinstance(data, interface) for interface in cls.interfaces):
+ elif not any(isinstance(data, tuple(t for t in interface.types if t is not None))
+ for interface in cls.interfaces.values()):
data = {k: v for k, v in zip(dimensions, zip(*data))}
elif isinstance(data, dict) and not all(d in data for d in dimensions):
dict_data = zip(*((util.wrap_tuple(k)+util.wrap_tuple(v))
From 5fd7ef44fa39c5fe5ab1b3d6d341d789a88f428c Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Mon, 18 Jul 2016 16:14:55 -0400
Subject: [PATCH 08/26] Fixed CubeInterface test
---
tests/testirisinterface.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/tests/testirisinterface.py b/tests/testirisinterface.py
index 9c44859955..7386c8cf85 100644
--- a/tests/testirisinterface.py
+++ b/tests/testirisinterface.py
@@ -51,10 +51,10 @@ def test_dimension_values_kdim(self):
def test_dimension_values_vdim(self):
cube = Dataset(self.cube, kdims=['longitude', 'latitude'])
self.assertEqual(cube.dimension_values('unknown', flat=False),
- np.flipud(np.array([[ 0, 4, 8],
- [ 1, 5, 9],
- [ 2, 6, 10],
- [ 3, 7, 11]], dtype=np.int32).T))
+ np.array([[ 0, 4, 8],
+ [ 1, 5, 9],
+ [ 2, 6, 10],
+ [ 3, 7, 11]], dtype=np.int32).T)
def test_range_kdim(self):
cube = Dataset(self.cube, kdims=['longitude', 'latitude'])
From b80437c8e3ca4e1d7d85be69774e0131b8136c9f Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Mon, 18 Jul 2016 16:16:32 -0400
Subject: [PATCH 09/26] Fixed dynamic groupby parameter passing
---
holoviews/core/data/__init__.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/holoviews/core/data/__init__.py b/holoviews/core/data/__init__.py
index 8e58956825..a159f297a1 100644
--- a/holoviews/core/data/__init__.py
+++ b/holoviews/core/data/__init__.py
@@ -393,8 +393,8 @@ def groupby(self, dimensions=[], container_type=HoloMap, group_type=None,
if dynamic:
group_dims = [d.name for d in self.kdims if d not in dimensions]
- group_kwargs = dict(util.get_param_values(self))
- group_kwargs.update(kwargs)
+ group_kwargs = dict(util.get_param_values(self), **kwargs)
+ group_kwargs['kdims'] = [self.get_dimension(d) for d in group_dims]
def load_subset(*args):
constraint = dict(zip(dim_names, args))
group = self.select(**constraint)
From a984d64262f080384b68d7abfcd69f8c2ce9dc0e Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Mon, 25 Jul 2016 02:51:39 +0100
Subject: [PATCH 10/26] Added inverted coordinate systems in grid interfaces
---
holoviews/core/data/grid.py | 26 ++++++++++++++++++++++++--
holoviews/core/data/iris.py | 26 ++++++++++++++++++++++++--
holoviews/core/data/xarray.py | 24 ++++++++++++++++++++++--
3 files changed, 70 insertions(+), 6 deletions(-)
diff --git a/holoviews/core/data/grid.py b/holoviews/core/data/grid.py
index 683007c86c..8e78282362 100644
--- a/holoviews/core/data/grid.py
+++ b/holoviews/core/data/grid.py
@@ -101,18 +101,40 @@ def length(cls, dataset):
return np.product([len(dataset.data[d.name]) for d in dataset.kdims])
+ @classmethod
+ def invert(cls, dataset):
+ invert = False
+ slices = []
+ for d in dataset.kdims:
+ data = dataset.data[d.name]
+ if np.all(data[1:] < data[:-1]):
+ slices.append(slice(None, None, -1))
+ invert = True
+ else:
+ slices.append(slice(None))
+ return slices if invert else []
+
+
@classmethod
def values(cls, dataset, dim, expanded=True, flat=True):
if dim in dataset.kdims:
if not expanded:
- return dataset.data[dim]
- prod = util.cartesian_product([dataset.data[d.name] for d in dataset.kdims])
+ data = dataset.data[dim]
+ return data[::-1] if np.all(data[1:] < data[:-1]) else data
+ prod = util.cartesian_product([dataset.data[d.name]
+ for d in dataset.kdims])
idx = dataset.get_dimension_index(dim)
values = prod[idx]
+ invert = cls.invert(dataset)
+ if invert:
+ values = values.__getitem__(invert)
return values.flatten() if flat else values
else:
dim = dataset.get_dimension(dim)
values = dataset.data.get(dim.name)
+ invert = cls.invert(dataset)
+ if invert:
+ values = values.__getitem__(invert[::-1])
return values.T.flatten() if flat else values
diff --git a/holoviews/core/data/iris.py b/holoviews/core/data/iris.py
index 14acda9a40..6d79871939 100644
--- a/holoviews/core/data/iris.py
+++ b/holoviews/core/data/iris.py
@@ -118,6 +118,20 @@ def validate(cls, dataset):
pass
+ @classmethod
+ def invert(cls, dataset):
+ invert = False
+ slices = []
+ for d in dataset.kdims:
+ data = dataset.data.coords(d.name)[0].points
+ if np.all(data[1:] < data[:-1]):
+ slices.append(slice(None, None, -1))
+ invert = True
+ else:
+ slices.append(slice(None))
+ return slices if invert else []
+
+
@classmethod
def values(cls, dataset, dim, expanded=True, flat=True):
"""
@@ -128,18 +142,26 @@ def values(cls, dataset, dim, expanded=True, flat=True):
data = dataset.data.copy().data
coord_names = [c.name() for c in dataset.data.dim_coords
if c.name() in dataset.kdims]
+ inversions = cls.invert(dataset)
+ if inversions:
+ data = data.__getitem__(inversions[::-1])
if flat:
dim_inds = [coord_names.index(d.name) for d in dataset.kdims]
dim_inds += [i for i in range(len(dataset.data.dim_coords))
if i not in dim_inds]
- data = data.transpose(dim_inds)
+ data = data.transpose(dim_inds).flatten()
+ return data
elif expanded:
idx = dataset.get_dimension_index(dim)
data = util.cartesian_product([dataset.data.coords(d.name)[0].points
for d in dataset.kdims])[idx]
+ inversions = cls.invert(dataset)
+ if inversions:
+ data = data.__getitem__(inversions)
+ return data.flatten() if flat else data
else:
data = dataset.data.coords(dim.name)[0].points
- return data.flatten() if flat else data
+ return data if np.all(data[1:] >= data[:-1]) else data[::-1]
@classmethod
diff --git a/holoviews/core/data/xarray.py b/holoviews/core/data/xarray.py
index 53087f3146..a445a8b332 100644
--- a/holoviews/core/data/xarray.py
+++ b/holoviews/core/data/xarray.py
@@ -119,6 +119,20 @@ def groupby(cls, dataset, dimensions, container_type, group_type, **kwargs):
return container_type(data)
+ @classmethod
+ def invert(cls, dataset):
+ invert = False
+ slices = []
+ for d in dataset.data.dims:
+ data = dataset.data[d].data
+ if np.all(data[1:] < data[:-1]):
+ slices.append(slice(None, None, -1))
+ invert = True
+ else:
+ slices.append(slice(None))
+ return slices if invert else []
+
+
@classmethod
def values(cls, dataset, dim, expanded=True, flat=True):
data = dataset.data[dim].data
@@ -130,12 +144,18 @@ def values(cls, dataset, dim, expanded=True, flat=True):
name in dataset.data.dims]
inds = [dims.index(kd.name) for kd in dataset.kdims]
transposed = data.transpose(inds[::-1])
- return transposed.flatten() if flat else transposed
+ inversions = cls.invert(dataset)
+ if inversions:
+ transposed = transposed.__getitem__(inversions[::-1])
+ return transposed.T.flatten() if flat else transposed
elif not expanded:
- return data
+ return data if np.all(data[1:] >= data[:-1]) else data[::-1]
else:
arrays = [dataset.data[d.name].data for d in dataset.kdims]
product = util.cartesian_product(arrays)[dataset.get_dimension_index(dim)]
+ inversions = cls.invert(dataset)
+ if inversions:
+ product = product.__getitem__(inversions)
return product.flatten() if flat else product
From 46bb8fa91e80e37206efebdad8b08783f1cab5aa Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Mon, 25 Jul 2016 02:53:16 +0100
Subject: [PATCH 11/26] Fixed GridImage density
---
holoviews/element/raster.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/holoviews/element/raster.py b/holoviews/element/raster.py
index 6edb6aef65..4a8f98c79c 100644
--- a/holoviews/element/raster.py
+++ b/holoviews/element/raster.py
@@ -657,8 +657,8 @@ def __init__(self, data, **params):
super(GridImage, self).__init__(data, **params)
(l, r), (b, t) = self.interface.range(self, 0), self.interface.range(self, 1)
(ys, xs) = self.dimension_values(2, flat=False).shape
- xsampling = (float(r-l)/xs)/2.
- ysampling = (float(t-b)/ys)/2.
+ xsampling = (float(r-l)/(xs-1))/2.
+ ysampling = (float(t-b)/(ys-1))/2.
l, r = l-xsampling, r+xsampling
b, t = b-ysampling, t+ysampling
self.bounds = BoundingBox(points=((l, b), (r, t)))
From 98725de7acc714df377825b085d20f7686101811 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Mon, 25 Jul 2016 02:53:51 +0100
Subject: [PATCH 12/26] Added unit tests for Dataset
---
tests/testdataset.py | 89 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 89 insertions(+)
diff --git a/tests/testdataset.py b/tests/testdataset.py
index 058a015eca..23902e065e 100644
--- a/tests/testdataset.py
+++ b/tests/testdataset.py
@@ -437,6 +437,95 @@ def init_data(self):
self.y_ints = [i*2 for i in range(11)]
self.dataset_hm = Dataset((self.xs, self.y_ints),
kdims=['x'], vdims=['y'])
+ self.grid_xs = [0, 1]
+ self.grid_ys = [0.1, 0.2, 0.3]
+ self.grid_zs = [[0, 1], [2, 3], [4, 5]]
+ self.dataset_grid = Dataset((self.grid_xs, self.grid_ys,
+ self.grid_zs), kdims=['x', 'y'],
+ vdims=['z'])
+ self.dataset_grid_inv = Dataset((self.grid_xs[::-1], self.grid_ys[::-1],
+ self.grid_zs), kdims=['x', 'y'],
+ vdims=['z'])
+
+ def test_dataset_dim_vals_grid_kdims_xs(self):
+ self.assertEqual(self.dataset_grid.dimension_values(0, expanded=False),
+ np.array([0, 1]))
+
+ def test_dataset_dim_vals_grid_kdims_xs_inv(self):
+ self.assertEqual(self.dataset_grid_inv.dimension_values(0, expanded=False),
+ np.array([0, 1]))
+
+ def test_dataset_dim_vals_grid_kdims_expanded_xs_flat(self):
+ expanded_xs = np.array([0, 0, 0, 1, 1, 1])
+ self.assertEqual(self.dataset_grid.dimension_values(0),
+ expanded_xs)
+
+ def test_dataset_dim_vals_grid_kdims_expanded_xs_flat_inv(self):
+ expanded_xs = np.array([0, 0, 0, 1, 1, 1])
+ self.assertEqual(self.dataset_grid_inv.dimension_values(0),
+ expanded_xs)
+
+ def test_dataset_dim_vals_grid_kdims_expanded_xs(self):
+ expanded_xs = np.array([[0, 0, 0], [1, 1, 1]])
+ self.assertEqual(self.dataset_grid.dimension_values(0, flat=False),
+ expanded_xs)
+
+ def test_dataset_dim_vals_grid_kdims_expanded_xs_inv(self):
+ expanded_xs = np.array([[0, 0, 0], [1, 1, 1]])
+ self.assertEqual(self.dataset_grid_inv.dimension_values(0, flat=False),
+ expanded_xs)
+
+ def test_dataset_dim_vals_grid_kdims_ys(self):
+ self.assertEqual(self.dataset_grid.dimension_values(1, expanded=False),
+ np.array([0.1, 0.2, 0.3]))
+
+ def test_dataset_dim_vals_grid_kdims_ys_inv(self):
+ self.assertEqual(self.dataset_grid_inv.dimension_values(1, expanded=False),
+ np.array([0.1, 0.2, 0.3]))
+
+ def test_dataset_dim_vals_grid_kdims_expanded_ys_flat(self):
+ expanded_ys = np.array([0.1, 0.2, 0.3,
+ 0.1, 0.2, 0.3])
+ self.assertEqual(self.dataset_grid.dimension_values(1),
+ expanded_ys)
+
+ def test_dataset_dim_vals_grid_kdims_expanded_ys_flat_inv(self):
+ expanded_ys = np.array([0.1, 0.2, 0.3,
+ 0.1, 0.2, 0.3])
+ self.assertEqual(self.dataset_grid_inv.dimension_values(1),
+ expanded_ys)
+
+ def test_dataset_dim_vals_grid_kdims_expanded_ys(self):
+ expanded_ys = np.array([[0.1, 0.2, 0.3],
+ [0.1, 0.2, 0.3]])
+ self.assertEqual(self.dataset_grid.dimension_values(1, flat=False),
+ expanded_ys)
+
+ def test_dataset_dim_vals_grid_kdims_expanded_ys_inv(self):
+ expanded_ys = np.array([[0.1, 0.2, 0.3],
+ [0.1, 0.2, 0.3]])
+ self.assertEqual(self.dataset_grid_inv.dimension_values(1, flat=False),
+ expanded_ys)
+
+ def test_dataset_dim_vals_grid_vdims_zs_flat(self):
+ expanded_zs = np.array([0, 2, 4, 1, 3, 5])
+ self.assertEqual(self.dataset_grid.dimension_values(2),
+ expanded_zs)
+
+ def test_dataset_dim_vals_grid_vdims_zs_flat_inv(self):
+ expanded_zs = np.array([5, 3, 1, 4, 2, 0])
+ self.assertEqual(self.dataset_grid_inv.dimension_values(2),
+ expanded_zs)
+
+ def test_dataset_dim_vals_grid_vdims_zs(self):
+ expanded_zs = np.array([[0, 1], [2, 3], [4, 5]])
+ self.assertEqual(self.dataset_grid.dimension_values(2, flat=False),
+ expanded_zs)
+
+ def test_dataset_dim_vals_grid_vdims_zs_inv(self):
+ expanded_zs = np.array([[5, 4], [3, 2], [1, 0]])
+ self.assertEqual(self.dataset_grid_inv.dimension_values(2, flat=False),
+ expanded_zs)
def test_dataset_array_init_hm(self):
"Tests support for arrays (homogeneous)"
From 5d08919d0a0b4b16d6f3a3d1e4eafd5c3f83bf5d Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Mon, 25 Jul 2016 12:35:19 +0100
Subject: [PATCH 13/26] Avoid duplication of invert method on grid interfaces
---
holoviews/core/data/grid.py | 15 ++++++++++++++-
holoviews/core/data/iris.py | 17 ++++-------------
holoviews/core/data/xarray.py | 13 ++-----------
3 files changed, 20 insertions(+), 25 deletions(-)
diff --git a/holoviews/core/data/grid.py b/holoviews/core/data/grid.py
index 8e78282362..fe675eebde 100644
--- a/holoviews/core/data/grid.py
+++ b/holoviews/core/data/grid.py
@@ -101,12 +101,25 @@ def length(cls, dataset):
return np.product([len(dataset.data[d.name]) for d in dataset.kdims])
+ @classmethod
+ def get_coords(cls, dataset, dim):
+ """
+ Returns the coordinates along a dimension.
+ """
+ return dataset.data[dim]
+
+
@classmethod
def invert(cls, dataset):
+ """
+ Detects if coordinates along a dimension are inverted
+ and returns slices to flip the array to the expected
+ orientation.
+ """
invert = False
slices = []
for d in dataset.kdims:
- data = dataset.data[d.name]
+ data = cls.get_coords(dataset, d.name)
if np.all(data[1:] < data[:-1]):
slices.append(slice(None, None, -1))
invert = True
diff --git a/holoviews/core/data/iris.py b/holoviews/core/data/iris.py
index 6d79871939..58a01ef9dd 100644
--- a/holoviews/core/data/iris.py
+++ b/holoviews/core/data/iris.py
@@ -119,17 +119,8 @@ def validate(cls, dataset):
@classmethod
- def invert(cls, dataset):
- invert = False
- slices = []
- for d in dataset.kdims:
- data = dataset.data.coords(d.name)[0].points
- if np.all(data[1:] < data[:-1]):
- slices.append(slice(None, None, -1))
- invert = True
- else:
- slices.append(slice(None))
- return slices if invert else []
+ def get_coords(cls, dataset, dim):
+ return dataset.data.coords(dim)[0].points
@classmethod
@@ -153,14 +144,14 @@ def values(cls, dataset, dim, expanded=True, flat=True):
return data
elif expanded:
idx = dataset.get_dimension_index(dim)
- data = util.cartesian_product([dataset.data.coords(d.name)[0].points
+ data = util.cartesian_product([cls.get_coords(dataset, d.name)
for d in dataset.kdims])[idx]
inversions = cls.invert(dataset)
if inversions:
data = data.__getitem__(inversions)
return data.flatten() if flat else data
else:
- data = dataset.data.coords(dim.name)[0].points
+ data = cls.get_coords(dataset, dim.name)
return data if np.all(data[1:] >= data[:-1]) else data[::-1]
diff --git a/holoviews/core/data/xarray.py b/holoviews/core/data/xarray.py
index a445a8b332..c4af15cab5 100644
--- a/holoviews/core/data/xarray.py
+++ b/holoviews/core/data/xarray.py
@@ -120,17 +120,8 @@ def groupby(cls, dataset, dimensions, container_type, group_type, **kwargs):
@classmethod
- def invert(cls, dataset):
- invert = False
- slices = []
- for d in dataset.data.dims:
- data = dataset.data[d].data
- if np.all(data[1:] < data[:-1]):
- slices.append(slice(None, None, -1))
- invert = True
- else:
- slices.append(slice(None))
- return slices if invert else []
+ def get_coords(cls, dataset, dim):
+ return dataset.data[dim].data
@classmethod
From 75031a588c5fab15a5f0d5818a5420e5873f43f1 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Mon, 25 Jul 2016 14:27:52 +0100
Subject: [PATCH 14/26] Further fixes for grid interface orientations
---
holoviews/core/data/grid.py | 2 +-
holoviews/core/data/xarray.py | 10 ++++------
holoviews/plotting/bokeh/raster.py | 2 +-
holoviews/plotting/mpl/raster.py | 2 +-
4 files changed, 7 insertions(+), 9 deletions(-)
diff --git a/holoviews/core/data/grid.py b/holoviews/core/data/grid.py
index fe675eebde..6f754c1f9a 100644
--- a/holoviews/core/data/grid.py
+++ b/holoviews/core/data/grid.py
@@ -140,7 +140,7 @@ def values(cls, dataset, dim, expanded=True, flat=True):
values = prod[idx]
invert = cls.invert(dataset)
if invert:
- values = values.__getitem__(invert)
+ values = values.__getitem__(invert[::-1])
return values.flatten() if flat else values
else:
dim = dataset.get_dimension(dim)
diff --git a/holoviews/core/data/xarray.py b/holoviews/core/data/xarray.py
index c4af15cab5..4ed0e7902d 100644
--- a/holoviews/core/data/xarray.py
+++ b/holoviews/core/data/xarray.py
@@ -128,16 +128,14 @@ def get_coords(cls, dataset, dim):
def values(cls, dataset, dim, expanded=True, flat=True):
data = dataset.data[dim].data
if dim in dataset.vdims:
- if data.ndim == 1:
- return np.array(data)
- dims = [name for name in dataset.data.coords
+ inversions = cls.invert(dataset)
+ if inversions:
+ data = data.__getitem__(inversions[::-1])
+ dims = [name for name in dataset.data[dim].dims
if isinstance(dataset.data[name].data, np.ndarray) and
name in dataset.data.dims]
inds = [dims.index(kd.name) for kd in dataset.kdims]
transposed = data.transpose(inds[::-1])
- inversions = cls.invert(dataset)
- if inversions:
- transposed = transposed.__getitem__(inversions[::-1])
return transposed.T.flatten() if flat else transposed
elif not expanded:
return data if np.all(data[1:] >= data[:-1]) else data[::-1]
diff --git a/holoviews/plotting/bokeh/raster.py b/holoviews/plotting/bokeh/raster.py
index 6763832114..a6183c927c 100644
--- a/holoviews/plotting/bokeh/raster.py
+++ b/holoviews/plotting/bokeh/raster.py
@@ -82,7 +82,7 @@ def _update_glyph(self, glyph, properties, mapping):
class ImagePlot(RasterPlot):
def get_data(self, element, ranges=None, empty=False):
- img = np.flipud(element.dimension_values(2, flat=False))
+ img = element.dimension_values(2, flat=False)
l, b, r, t = element.bounds.lbrt()
dh, dw = t-b, r-l
mapping = dict(image='image', x='x', y='y', dw='dw', dh='dh')
diff --git a/holoviews/plotting/mpl/raster.py b/holoviews/plotting/mpl/raster.py
index c6d137f801..a734fecf39 100644
--- a/holoviews/plotting/mpl/raster.py
+++ b/holoviews/plotting/mpl/raster.py
@@ -183,7 +183,7 @@ def update_handles(self, key, axis, element, ranges, style):
class ImagePlot(RasterPlot):
def get_data(self, element, ranges, style):
- data = element.dimension_values(2, flat=False)
+ data = np.flipud(element.dimension_values(2, flat=False))
data = np.ma.array(data, mask=np.logical_not(np.isfinite(data)))
vdim = element.vdims[0]
self._norm_kwargs(element, ranges, style, vdim)
From 9004db449947861da8b0a0785360f5159259ce26 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Mon, 25 Jul 2016 15:06:21 +0100
Subject: [PATCH 15/26] Small fix for reorienting 1D arrays
---
holoviews/core/data/xarray.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/holoviews/core/data/xarray.py b/holoviews/core/data/xarray.py
index 4ed0e7902d..7b39a1531d 100644
--- a/holoviews/core/data/xarray.py
+++ b/holoviews/core/data/xarray.py
@@ -129,7 +129,7 @@ def values(cls, dataset, dim, expanded=True, flat=True):
data = dataset.data[dim].data
if dim in dataset.vdims:
inversions = cls.invert(dataset)
- if inversions:
+ if inversions and not (flat and data.ndim > 1):
data = data.__getitem__(inversions[::-1])
dims = [name for name in dataset.data[dim].dims
if isinstance(dataset.data[name].data, np.ndarray) and
From b29cd210dfba94a7e2a0b3890c73e8183c021582 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Mon, 25 Jul 2016 15:07:03 +0100
Subject: [PATCH 16/26] HeatMap avoids reaggregating grid based data
---
holoviews/element/raster.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/holoviews/element/raster.py b/holoviews/element/raster.py
index 4a8f98c79c..c82a913b7c 100644
--- a/holoviews/element/raster.py
+++ b/holoviews/element/raster.py
@@ -6,7 +6,8 @@
import param
from ..core import util
-from ..core.data import (ArrayInterface, NdElementInterface, DictInterface)
+from ..core.data import (ArrayInterface, NdElementInterface,
+ DictInterface, GridInterface)
from ..core import (Dimension, NdMapping, Element2D,
Overlay, Element, Dataset, NdElement)
from ..core.boundingregion import BoundingRegion, BoundingBox
@@ -396,6 +397,8 @@ def __init__(self, data, extents=None, **params):
def _compute_raster(self):
+ if issubclass(self.interface, GridInterface):
+ return self, self.dimension_values(2, flat=False)
d1keys = self.dimension_values(0, False)
d2keys = self.dimension_values(1, False)
coords = [(d1, d2, np.NaN) for d1 in d1keys for d2 in d2keys]
From 30196f15c488a799f8eb8d11ce1b194923660969 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Mon, 25 Jul 2016 15:32:39 +0100
Subject: [PATCH 17/26] Revert bad fix for xarray 1D dimension_values
---
holoviews/core/data/xarray.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/holoviews/core/data/xarray.py b/holoviews/core/data/xarray.py
index 7b39a1531d..c4062aeb2f 100644
--- a/holoviews/core/data/xarray.py
+++ b/holoviews/core/data/xarray.py
@@ -129,14 +129,15 @@ def values(cls, dataset, dim, expanded=True, flat=True):
data = dataset.data[dim].data
if dim in dataset.vdims:
inversions = cls.invert(dataset)
- if inversions and not (flat and data.ndim > 1):
+ if inversions:
data = data.__getitem__(inversions[::-1])
dims = [name for name in dataset.data[dim].dims
if isinstance(dataset.data[name].data, np.ndarray) and
name in dataset.data.dims]
inds = [dims.index(kd.name) for kd in dataset.kdims]
- transposed = data.transpose(inds[::-1])
- return transposed.T.flatten() if flat else transposed
+ if inds:
+ data = data.transpose(inds[::-1])
+ return data.T.flatten() if flat else data
elif not expanded:
return data if np.all(data[1:] >= data[:-1]) else data[::-1]
else:
From cb461b1b35f40ef8ade0a7ae60e074f74cad8a06 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Mon, 25 Jul 2016 16:26:56 +0100
Subject: [PATCH 18/26] Further orientation fixes for grid interfaces
---
holoviews/core/data/grid.py | 7 ++++---
holoviews/core/data/xarray.py | 4 ++--
holoviews/element/raster.py | 2 +-
3 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/holoviews/core/data/grid.py b/holoviews/core/data/grid.py
index 6f754c1f9a..31c76235c2 100644
--- a/holoviews/core/data/grid.py
+++ b/holoviews/core/data/grid.py
@@ -110,16 +110,17 @@ def get_coords(cls, dataset, dim):
@classmethod
- def invert(cls, dataset):
+ def invert(cls, dataset, dims=None):
"""
Detects if coordinates along a dimension are inverted
and returns slices to flip the array to the expected
orientation.
"""
+ dims = dataset.dimensions('key', True) if dims is None else dims
invert = False
slices = []
- for d in dataset.kdims:
- data = cls.get_coords(dataset, d.name)
+ for d in dims:
+ data = cls.get_coords(dataset, d)
if np.all(data[1:] < data[:-1]):
slices.append(slice(None, None, -1))
invert = True
diff --git a/holoviews/core/data/xarray.py b/holoviews/core/data/xarray.py
index c4062aeb2f..0cc01635bc 100644
--- a/holoviews/core/data/xarray.py
+++ b/holoviews/core/data/xarray.py
@@ -48,7 +48,7 @@ def init(cls, eltype, data, kdims, vdims):
if not isinstance(data, xr.Dataset):
kdims = [kd if isinstance(kd, Dimension) else Dimension(kd)
for kd in kdims]
- vdims = [d if isinstance(vd, Dimension) else Dimension(vd)
+ vdims = [vd if isinstance(vd, Dimension) else Dimension(vd)
for vd in vdims]
if isinstance(data, tuple):
data = {d.name: vals for d, vals in zip(kdims + vdims, data)}
@@ -128,7 +128,7 @@ def get_coords(cls, dataset, dim):
def values(cls, dataset, dim, expanded=True, flat=True):
data = dataset.data[dim].data
if dim in dataset.vdims:
- inversions = cls.invert(dataset)
+ inversions = cls.invert(dataset, dataset.data[dim].dims[::-1])
if inversions:
data = data.__getitem__(inversions[::-1])
dims = [name for name in dataset.data[dim].dims
diff --git a/holoviews/element/raster.py b/holoviews/element/raster.py
index c82a913b7c..2bdfe1140e 100644
--- a/holoviews/element/raster.py
+++ b/holoviews/element/raster.py
@@ -398,7 +398,7 @@ def __init__(self, data, extents=None, **params):
def _compute_raster(self):
if issubclass(self.interface, GridInterface):
- return self, self.dimension_values(2, flat=False)
+ return self, np.flipud(self.dimension_values(2, flat=False))
d1keys = self.dimension_values(0, False)
d2keys = self.dimension_values(1, False)
coords = [(d1, d2, np.NaN) for d1 in d1keys for d2 in d2keys]
From 4ecb99363643437753ff1160321da836ca74b60e Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Mon, 25 Jul 2016 16:27:20 +0100
Subject: [PATCH 19/26] GridInterface reindex fixes
---
holoviews/core/data/grid.py | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/holoviews/core/data/grid.py b/holoviews/core/data/grid.py
index 31c76235c2..1b4da4bc69 100644
--- a/holoviews/core/data/grid.py
+++ b/holoviews/core/data/grid.py
@@ -71,7 +71,7 @@ def init(cls, eltype, data, kdims, vdims):
if shape != expected[::-1] and not (not expected and shape == (1,)):
raise ValueError('Key dimension values and value array %s '
'shape do not match. Expected shape %s, '
- 'actual shape: %s' % (vdim, expected, shape))
+ 'actual shape: %s' % (vdim, expected[::-1], shape))
return data, {'kdims':kdims, 'vdims':vdims}, {}
@@ -318,17 +318,17 @@ def reindex(cls, dataset, kdims, vdims):
if k not in dropped_kdims+dropped_vdims}
if kdims != dataset.kdims:
- dropped_axes = tuple(dataset.ndims-dataset.kdims.index(d)-1
+ joined_dims = kdims+dropped_kdims
+ axes = tuple(dataset.ndims-dataset.kdims.index(d)-1
+ for d in joined_dims)
+ dropped_axes = tuple(dataset.ndims-joined_dims.index(d)-1
for d in dropped_kdims)
- old_kdims = [d for d in dataset.kdims if not d in dropped_kdims]
- axes = tuple(dataset.ndims-old_kdims.index(d)-1
- for d in kdims)
for vdim in vdims:
vdata = data[vdim.name]
+ if len(axes) > 1:
+ vdata = vdata.transpose(axes[::-1])
if dropped_axes:
vdata = vdata.squeeze(axis=dropped_axes)
- if len(axes) > 1:
- vdata = np.transpose(vdata, axes)
data[vdim.name] = vdata
return data
From 2c8aeed49fe1a0eb4fa942928f9354aa17cd97b6 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Tue, 26 Jul 2016 14:13:53 +0100
Subject: [PATCH 20/26] Refactored grid interface canonicalization code into
one method
---
holoviews/core/data/grid.py | 75 +++++++++++++++++++++--------------
holoviews/core/data/iris.py | 30 +++++---------
holoviews/core/data/xarray.py | 30 +++++---------
3 files changed, 67 insertions(+), 68 deletions(-)
diff --git a/holoviews/core/data/grid.py b/holoviews/core/data/grid.py
index 1b4da4bc69..3c106c4dcf 100644
--- a/holoviews/core/data/grid.py
+++ b/holoviews/core/data/grid.py
@@ -102,54 +102,71 @@ def length(cls, dataset):
@classmethod
- def get_coords(cls, dataset, dim):
+ def get_coords(cls, dataset, dim, ordered=False):
"""
Returns the coordinates along a dimension.
"""
- return dataset.data[dim]
+ data = dataset.data[dim]
+ if ordered and np.all(data[1:] < data[:-1]):
+ data = data[::-1]
+ return data
@classmethod
- def invert(cls, dataset, dims=None):
+ def expanded_coords(cls, dataset, dim):
+ arrays = [cls.get_coords(dataset, d.name, True)
+ for d in dataset.kdims]
+ idx = dataset.get_dimension_index(dim)
+ return util.cartesian_product(arrays)[idx]
+
+
+ @classmethod
+ def canonicalize(cls, dataset, data, coord_dims=None):
"""
- Detects if coordinates along a dimension are inverted
- and returns slices to flip the array to the expected
- orientation.
+ Canonicalize takes an array of values as input and
+ reorients and transposes it to match the canonical
+ format expected by plotting functions. In addition
+ to the dataset and the particular array to apply
+ transforms to a list of coord_dims may be supplied
+ in case the array indexing does not match the key
+ dimensions of the dataset.
"""
- dims = dataset.dimensions('key', True) if dims is None else dims
+ if coord_dims is None:
+ coord_dims = dataset.dimensions('key', True)
+
+ # Reorient data
invert = False
slices = []
- for d in dims:
- data = cls.get_coords(dataset, d)
- if np.all(data[1:] < data[:-1]):
+ for d in coord_dims:
+ coords = cls.get_coords(dataset, d)
+ if np.all(coords[1:] < coords[:-1]):
slices.append(slice(None, None, -1))
invert = True
else:
slices.append(slice(None))
- return slices if invert else []
+ data = data.__getitem__(slices[::-1]) if invert else data
+
+ # Transpose data
+ dims = [name for name in coord_dims[::-1]
+ if isinstance(cls.get_coords(dataset, name), np.ndarray)]
+ inds = [dims.index(kd.name) for kd in dataset.kdims]
+ if inds:
+ data = data.transpose(inds[::-1])
+ return data
@classmethod
def values(cls, dataset, dim, expanded=True, flat=True):
- if dim in dataset.kdims:
- if not expanded:
- data = dataset.data[dim]
- return data[::-1] if np.all(data[1:] < data[:-1]) else data
- prod = util.cartesian_product([dataset.data[d.name]
- for d in dataset.kdims])
- idx = dataset.get_dimension_index(dim)
- values = prod[idx]
- invert = cls.invert(dataset)
- if invert:
- values = values.__getitem__(invert[::-1])
- return values.flatten() if flat else values
- else:
+ if dim in dataset.vdims:
dim = dataset.get_dimension(dim)
- values = dataset.data.get(dim.name)
- invert = cls.invert(dataset)
- if invert:
- values = values.__getitem__(invert[::-1])
- return values.T.flatten() if flat else values
+ data = dataset.data.get(dim.name)
+ data = cls.canonicalize(dataset, data)
+ return data.T.flatten() if flat else data
+ elif expanded:
+ data = cls.expanded_coords(dataset, dim)
+ return data.flatten() if flat else data
+ else:
+ return cls.get_coords(dataset, dim, True)
@classmethod
diff --git a/holoviews/core/data/iris.py b/holoviews/core/data/iris.py
index 58a01ef9dd..461973a6e4 100644
--- a/holoviews/core/data/iris.py
+++ b/holoviews/core/data/iris.py
@@ -119,8 +119,11 @@ def validate(cls, dataset):
@classmethod
- def get_coords(cls, dataset, dim):
- return dataset.data.coords(dim)[0].points
+ def get_coords(cls, dataset, dim, ordered=False):
+ data = dataset.data.coords(dim)[0].points
+ if ordered and np.all(data[1:] < data[:-1]):
+ data = data[::-1]
+ return data
@classmethod
@@ -130,29 +133,16 @@ def values(cls, dataset, dim, expanded=True, flat=True):
"""
dim = dataset.get_dimension(dim)
if dim in dataset.vdims:
- data = dataset.data.copy().data
coord_names = [c.name() for c in dataset.data.dim_coords
if c.name() in dataset.kdims]
- inversions = cls.invert(dataset)
- if inversions:
- data = data.__getitem__(inversions[::-1])
- if flat:
- dim_inds = [coord_names.index(d.name) for d in dataset.kdims]
- dim_inds += [i for i in range(len(dataset.data.dim_coords))
- if i not in dim_inds]
- data = data.transpose(dim_inds).flatten()
- return data
+ data = dataset.data.copy().data.T
+ data = cls.canonicalize(dataset, data, coord_names)
+ return data.T.flatten() if flat else data
elif expanded:
- idx = dataset.get_dimension_index(dim)
- data = util.cartesian_product([cls.get_coords(dataset, d.name)
- for d in dataset.kdims])[idx]
- inversions = cls.invert(dataset)
- if inversions:
- data = data.__getitem__(inversions)
+ data = cls.expanded_coords(dataset, dim)
return data.flatten() if flat else data
else:
- data = cls.get_coords(dataset, dim.name)
- return data if np.all(data[1:] >= data[:-1]) else data[::-1]
+ return cls.get_coords(dataset, dim.name, True)
@classmethod
diff --git a/holoviews/core/data/xarray.py b/holoviews/core/data/xarray.py
index 0cc01635bc..fc28acb4b9 100644
--- a/holoviews/core/data/xarray.py
+++ b/holoviews/core/data/xarray.py
@@ -120,33 +120,25 @@ def groupby(cls, dataset, dimensions, container_type, group_type, **kwargs):
@classmethod
- def get_coords(cls, dataset, dim):
- return dataset.data[dim].data
+ def get_coords(cls, dataset, dim, ordered=False):
+ data = dataset.data[dim].data
+ if ordered and np.all(data[1:] < data[:-1]):
+ data = data[::-1]
+ return data
@classmethod
def values(cls, dataset, dim, expanded=True, flat=True):
data = dataset.data[dim].data
if dim in dataset.vdims:
- inversions = cls.invert(dataset, dataset.data[dim].dims[::-1])
- if inversions:
- data = data.__getitem__(inversions[::-1])
- dims = [name for name in dataset.data[dim].dims
- if isinstance(dataset.data[name].data, np.ndarray) and
- name in dataset.data.dims]
- inds = [dims.index(kd.name) for kd in dataset.kdims]
- if inds:
- data = data.transpose(inds[::-1])
+ coord_dims = dataset.data[dim].dims[::-1]
+ data = cls.canonicalize(dataset, data, coord_dims=coord_dims)
return data.T.flatten() if flat else data
- elif not expanded:
- return data if np.all(data[1:] >= data[:-1]) else data[::-1]
+ elif expanded:
+ data = cls.expanded_coords(dataset, dim)
+ return data.flatten() if flat else data
else:
- arrays = [dataset.data[d.name].data for d in dataset.kdims]
- product = util.cartesian_product(arrays)[dataset.get_dimension_index(dim)]
- inversions = cls.invert(dataset)
- if inversions:
- product = product.__getitem__(inversions)
- return product.flatten() if flat else product
+ return cls.get_coords(dataset, dim, True)
@classmethod
From 3b5b042694af389ee7e479338497ad08a0077d68 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Tue, 26 Jul 2016 19:19:34 +0100
Subject: [PATCH 21/26] Handle views into higher dimensional gridded datasets
---
holoviews/core/data/grid.py | 8 ++++++++
holoviews/core/data/iris.py | 3 +--
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/holoviews/core/data/grid.py b/holoviews/core/data/grid.py
index 3c106c4dcf..1add444d7f 100644
--- a/holoviews/core/data/grid.py
+++ b/holoviews/core/data/grid.py
@@ -149,9 +149,17 @@ def canonicalize(cls, dataset, data, coord_dims=None):
# Transpose data
dims = [name for name in coord_dims[::-1]
if isinstance(cls.get_coords(dataset, name), np.ndarray)]
+ dropped = [dims.index(d) for d in dims if d not in dataset.kdims]
inds = [dims.index(kd.name) for kd in dataset.kdims]
+ inds += dropped
if inds:
data = data.transpose(inds[::-1])
+
+ # Allow lower dimensional views into data
+ if len(dataset.kdims) < 2:
+ data = data.flatten()
+ elif dropped:
+ data = data.squeeze(axis=tuple(range(len(dropped))))
return data
diff --git a/holoviews/core/data/iris.py b/holoviews/core/data/iris.py
index 461973a6e4..8ac21b5650 100644
--- a/holoviews/core/data/iris.py
+++ b/holoviews/core/data/iris.py
@@ -133,8 +133,7 @@ def values(cls, dataset, dim, expanded=True, flat=True):
"""
dim = dataset.get_dimension(dim)
if dim in dataset.vdims:
- coord_names = [c.name() for c in dataset.data.dim_coords
- if c.name() in dataset.kdims]
+ coord_names = [c.name() for c in dataset.data.dim_coords]
data = dataset.data.copy().data.T
data = cls.canonicalize(dataset, data, coord_names)
return data.T.flatten() if flat else data
From b557f8464ad0f3bf26ff768b20119614debfc93e Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Wed, 27 Jul 2016 12:41:47 +0100
Subject: [PATCH 22/26] Added attribute to interface to check for gridded data
---
holoviews/core/data/grid.py | 2 ++
holoviews/core/data/interface.py | 2 ++
holoviews/element/raster.py | 2 +-
3 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/holoviews/core/data/grid.py b/holoviews/core/data/grid.py
index 1add444d7f..4dea3ee6ee 100644
--- a/holoviews/core/data/grid.py
+++ b/holoviews/core/data/grid.py
@@ -37,6 +37,8 @@ class GridInterface(DictInterface):
datatype = 'grid'
+ gridded = True
+
@classmethod
def init(cls, eltype, data, kdims, vdims):
if kdims is None:
diff --git a/holoviews/core/data/interface.py b/holoviews/core/data/interface.py
index c9fceb348f..ab5a0b5278 100644
--- a/holoviews/core/data/interface.py
+++ b/holoviews/core/data/interface.py
@@ -11,6 +11,8 @@ class Interface(param.Parameterized):
datatype = None
+ gridded = False
+
@classmethod
def register(cls, interface):
cls.interfaces[interface.datatype] = interface
diff --git a/holoviews/element/raster.py b/holoviews/element/raster.py
index 2bdfe1140e..2d780d728e 100644
--- a/holoviews/element/raster.py
+++ b/holoviews/element/raster.py
@@ -397,7 +397,7 @@ def __init__(self, data, extents=None, **params):
def _compute_raster(self):
- if issubclass(self.interface, GridInterface):
+ if self.interface.gridded:
return self, np.flipud(self.dimension_values(2, flat=False))
d1keys = self.dimension_values(0, False)
d2keys = self.dimension_values(1, False)
From 3dbdbd4811178c60ec3284943bfcf480dff43125 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Wed, 27 Jul 2016 12:45:32 +0100
Subject: [PATCH 23/26] Added comment to clarify dict interface type handling
---
holoviews/core/data/dictionary.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/holoviews/core/data/dictionary.py b/holoviews/core/data/dictionary.py
index 06cf26011d..2992abe328 100644
--- a/holoviews/core/data/dictionary.py
+++ b/holoviews/core/data/dictionary.py
@@ -56,6 +56,8 @@ def init(cls, eltype, data, kdims, vdims):
data = {k: data[:,i] for i,k in enumerate(dimensions)}
elif isinstance(data, list) and np.isscalar(data[0]):
data = {dimensions[0]: np.arange(len(data)), dimensions[1]: data}
+ # Ensure that interface does not consume data of other types
+ # with an iterator interface
elif not any(isinstance(data, tuple(t for t in interface.types if t is not None))
for interface in cls.interfaces.values()):
data = {k: v for k, v in zip(dimensions, zip(*data))}
From 6e8e46f5c3ce5da4b66e25a93d707400c22a1543 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Wed, 27 Jul 2016 12:51:05 +0100
Subject: [PATCH 24/26] Fixed various error messages in interfaces
---
holoviews/core/data/array.py | 2 +-
holoviews/core/data/dictionary.py | 6 +++---
holoviews/core/data/grid.py | 4 ++--
holoviews/core/data/iris.py | 2 +-
4 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/holoviews/core/data/array.py b/holoviews/core/data/array.py
index 435319a77c..4c15432327 100644
--- a/holoviews/core/data/array.py
+++ b/holoviews/core/data/array.py
@@ -72,7 +72,7 @@ def validate(cls, dataset):
ncols = dataset.data.shape[1] if dataset.data.ndim > 1 else 1
if ncols < ndims:
raise ValueError("Supplied data does not match specified "
- "dimensions, expected at least %s dataset." % ndims)
+ "dimensions, expected at least %s columns." % ndims)
@classmethod
def array(cls, dataset, dimensions):
diff --git a/holoviews/core/data/dictionary.py b/holoviews/core/data/dictionary.py
index 2992abe328..7a31b04054 100644
--- a/holoviews/core/data/dictionary.py
+++ b/holoviews/core/data/dictionary.py
@@ -87,7 +87,7 @@ def validate(cls, dataset):
raise ValueError('Following dimensions not found in data: %s' % not_found)
lengths = [len(dataset.data[dim]) for dim in dimensions]
if len({l for l in lengths if l > 1}) > 1:
- raise ValueError('Length of dataset do not match')
+ raise ValueError('Length of columns do not match')
@classmethod
@@ -135,8 +135,8 @@ def concat(cls, dataset_objs):
cast_objs = cls.cast(dataset_objs)
cols = set(tuple(c.data.keys()) for c in cast_objs)
if len(cols) != 1:
- raise Exception("In order to concatenate, all Column objects "
- "should have matching set of dataset.")
+ raise Exception("In order to concatenate, all Dataset objects "
+ "should have matching set of columns.")
concatenated = OrderedDict()
for column in cols.pop():
concatenated[column] = np.concatenate([obj[column] for obj in cast_objs])
diff --git a/holoviews/core/data/grid.py b/holoviews/core/data/grid.py
index 4dea3ee6ee..2ba2cd2b53 100644
--- a/holoviews/core/data/grid.py
+++ b/holoviews/core/data/grid.py
@@ -55,8 +55,8 @@ def init(cls, eltype, data, kdims, vdims):
if isinstance(data, tuple):
data = {d: v for d, v in zip(dimensions, data)}
elif not isinstance(data, dict):
- raise ValueError('GridInterface must be instantiated as a '
- 'dictionary or tuple')
+ raise TypeError('GridInterface must be instantiated as a '
+ 'dictionary or tuple')
for dim in kdims+vdims:
name = dim.name if isinstance(dim, Dimension) else dim
diff --git a/holoviews/core/data/iris.py b/holoviews/core/data/iris.py
index 8ac21b5650..5deb9b04a6 100644
--- a/holoviews/core/data/iris.py
+++ b/holoviews/core/data/iris.py
@@ -93,7 +93,7 @@ def init(cls, eltype, data, kdims, vdims):
except:
pass
if not isinstance(data, iris.cube.Cube):
- raise TypeError('Data must be be an iris dataset type.')
+ raise TypeError('Data must be be an iris Cube type.')
if kdims:
coords = []
From 309bedc7f097fa5e6ece41a5b0bc836faca058c8 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Wed, 27 Jul 2016 12:53:15 +0100
Subject: [PATCH 25/26] Renamed GridInterface get_coords to coords
---
holoviews/core/data/grid.py | 10 +++++-----
holoviews/core/data/iris.py | 4 ++--
holoviews/core/data/xarray.py | 4 ++--
3 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/holoviews/core/data/grid.py b/holoviews/core/data/grid.py
index 2ba2cd2b53..22951963fb 100644
--- a/holoviews/core/data/grid.py
+++ b/holoviews/core/data/grid.py
@@ -104,7 +104,7 @@ def length(cls, dataset):
@classmethod
- def get_coords(cls, dataset, dim, ordered=False):
+ def coords(cls, dataset, dim, ordered=False):
"""
Returns the coordinates along a dimension.
"""
@@ -116,7 +116,7 @@ def get_coords(cls, dataset, dim, ordered=False):
@classmethod
def expanded_coords(cls, dataset, dim):
- arrays = [cls.get_coords(dataset, d.name, True)
+ arrays = [cls.coords(dataset, d.name, True)
for d in dataset.kdims]
idx = dataset.get_dimension_index(dim)
return util.cartesian_product(arrays)[idx]
@@ -140,7 +140,7 @@ def canonicalize(cls, dataset, data, coord_dims=None):
invert = False
slices = []
for d in coord_dims:
- coords = cls.get_coords(dataset, d)
+ coords = cls.coords(dataset, d)
if np.all(coords[1:] < coords[:-1]):
slices.append(slice(None, None, -1))
invert = True
@@ -150,7 +150,7 @@ def canonicalize(cls, dataset, data, coord_dims=None):
# Transpose data
dims = [name for name in coord_dims[::-1]
- if isinstance(cls.get_coords(dataset, name), np.ndarray)]
+ if isinstance(cls.coords(dataset, name), np.ndarray)]
dropped = [dims.index(d) for d in dims if d not in dataset.kdims]
inds = [dims.index(kd.name) for kd in dataset.kdims]
inds += dropped
@@ -176,7 +176,7 @@ def values(cls, dataset, dim, expanded=True, flat=True):
data = cls.expanded_coords(dataset, dim)
return data.flatten() if flat else data
else:
- return cls.get_coords(dataset, dim, True)
+ return cls.coords(dataset, dim, True)
@classmethod
diff --git a/holoviews/core/data/iris.py b/holoviews/core/data/iris.py
index 5deb9b04a6..063ea87f1a 100644
--- a/holoviews/core/data/iris.py
+++ b/holoviews/core/data/iris.py
@@ -119,7 +119,7 @@ def validate(cls, dataset):
@classmethod
- def get_coords(cls, dataset, dim, ordered=False):
+ def coords(cls, dataset, dim, ordered=False):
data = dataset.data.coords(dim)[0].points
if ordered and np.all(data[1:] < data[:-1]):
data = data[::-1]
@@ -141,7 +141,7 @@ def values(cls, dataset, dim, expanded=True, flat=True):
data = cls.expanded_coords(dataset, dim)
return data.flatten() if flat else data
else:
- return cls.get_coords(dataset, dim.name, True)
+ return cls.coords(dataset, dim.name, True)
@classmethod
diff --git a/holoviews/core/data/xarray.py b/holoviews/core/data/xarray.py
index fc28acb4b9..67d1bf67a9 100644
--- a/holoviews/core/data/xarray.py
+++ b/holoviews/core/data/xarray.py
@@ -120,7 +120,7 @@ def groupby(cls, dataset, dimensions, container_type, group_type, **kwargs):
@classmethod
- def get_coords(cls, dataset, dim, ordered=False):
+ def coords(cls, dataset, dim, ordered=False):
data = dataset.data[dim].data
if ordered and np.all(data[1:] < data[:-1]):
data = data[::-1]
@@ -138,7 +138,7 @@ def values(cls, dataset, dim, expanded=True, flat=True):
data = cls.expanded_coords(dataset, dim)
return data.flatten() if flat else data
else:
- return cls.get_coords(dataset, dim, True)
+ return cls.coords(dataset, dim, True)
@classmethod
From 1ee04d7a05dfbfc129e960c1466608ad4a49e662 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Wed, 27 Jul 2016 13:31:25 +0100
Subject: [PATCH 26/26] Factored grid coordinate expansion out into utility
---
holoviews/core/data/grid.py | 20 ++++++++------------
holoviews/core/data/iris.py | 8 +++++---
holoviews/core/data/xarray.py | 10 ++++++----
holoviews/core/util.py | 13 +++++++++++++
4 files changed, 32 insertions(+), 19 deletions(-)
diff --git a/holoviews/core/data/grid.py b/holoviews/core/data/grid.py
index 22951963fb..36c533b1b7 100644
--- a/holoviews/core/data/grid.py
+++ b/holoviews/core/data/grid.py
@@ -104,24 +104,20 @@ def length(cls, dataset):
@classmethod
- def coords(cls, dataset, dim, ordered=False):
+ def coords(cls, dataset, dim, ordered=False, expanded=False):
"""
- Returns the coordinates along a dimension.
+ Returns the coordinates along a dimension. Ordered ensures
+ coordinates are in ascending order and expanded creates
+ ND-array matching the dimensionality of the dataset.
"""
+ if expanded:
+ return util.expand_grid_coords(dataset, dim)
data = dataset.data[dim]
if ordered and np.all(data[1:] < data[:-1]):
data = data[::-1]
return data
- @classmethod
- def expanded_coords(cls, dataset, dim):
- arrays = [cls.coords(dataset, d.name, True)
- for d in dataset.kdims]
- idx = dataset.get_dimension_index(dim)
- return util.cartesian_product(arrays)[idx]
-
-
@classmethod
def canonicalize(cls, dataset, data, coord_dims=None):
"""
@@ -173,10 +169,10 @@ def values(cls, dataset, dim, expanded=True, flat=True):
data = cls.canonicalize(dataset, data)
return data.T.flatten() if flat else data
elif expanded:
- data = cls.expanded_coords(dataset, dim)
+ data = cls.coords(dataset, dim, expanded=True)
return data.flatten() if flat else data
else:
- return cls.coords(dataset, dim, True)
+ return cls.coords(dataset, dim, ordered=True)
@classmethod
diff --git a/holoviews/core/data/iris.py b/holoviews/core/data/iris.py
index 063ea87f1a..732e3f44dc 100644
--- a/holoviews/core/data/iris.py
+++ b/holoviews/core/data/iris.py
@@ -119,7 +119,9 @@ def validate(cls, dataset):
@classmethod
- def coords(cls, dataset, dim, ordered=False):
+ def coords(cls, dataset, dim, ordered=False, expanded=False):
+ if expanded:
+ return util.expand_grid_coords(dataset, dim)
data = dataset.data.coords(dim)[0].points
if ordered and np.all(data[1:] < data[:-1]):
data = data[::-1]
@@ -138,10 +140,10 @@ def values(cls, dataset, dim, expanded=True, flat=True):
data = cls.canonicalize(dataset, data, coord_names)
return data.T.flatten() if flat else data
elif expanded:
- data = cls.expanded_coords(dataset, dim)
+ data = cls.coords(dataset, dim, expanded=True)
return data.flatten() if flat else data
else:
- return cls.coords(dataset, dim.name, True)
+ return cls.coords(dataset, dim.name, ordered=True)
@classmethod
diff --git a/holoviews/core/data/xarray.py b/holoviews/core/data/xarray.py
index 67d1bf67a9..6cca1a83b9 100644
--- a/holoviews/core/data/xarray.py
+++ b/holoviews/core/data/xarray.py
@@ -120,8 +120,10 @@ def groupby(cls, dataset, dimensions, container_type, group_type, **kwargs):
@classmethod
- def coords(cls, dataset, dim, ordered=False):
- data = dataset.data[dim].data
+ def coords(cls, dataset, dim, ordered=False, expanded=False):
+ if expanded:
+ return util.expand_grid_coords(dataset, dim)
+ data = dataset.data[dim].data
if ordered and np.all(data[1:] < data[:-1]):
data = data[::-1]
return data
@@ -135,10 +137,10 @@ def values(cls, dataset, dim, expanded=True, flat=True):
data = cls.canonicalize(dataset, data, coord_dims=coord_dims)
return data.T.flatten() if flat else data
elif expanded:
- data = cls.expanded_coords(dataset, dim)
+ data = cls.coords(dataset, dim, expanded=True)
return data.flatten() if flat else data
else:
- return cls.coords(dataset, dim, True)
+ return cls.coords(dataset, dim, ordered=True)
@classmethod
diff --git a/holoviews/core/util.py b/holoviews/core/util.py
index 2f2afe91ea..7e558c268f 100644
--- a/holoviews/core/util.py
+++ b/holoviews/core/util.py
@@ -904,3 +904,16 @@ def get_dynamic_item(map_obj, dimensions, key):
else:
el = None
return key, el
+
+
+def expand_grid_coords(dataset, dim):
+ """
+ Expand the coordinates along a dimension of the gridded
+ dataset into an ND-array matching the dimensionality of
+ the dataset.
+ """
+ arrays = [dataset.interface.coords(dataset, d.name, True)
+ for d in dataset.kdims]
+ idx = dataset.get_dimension_index(dim)
+ return cartesian_product(arrays)[idx]
+