-
-
Notifications
You must be signed in to change notification settings - Fork 402
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
Grid based interface fixes #794
Changes from all commits
5428392
a280914
4426274
4124f29
0079735
f8e4ede
33b316a
5fd7ef4
b80437c
a984d64
46bb8fa
98725de
5d08919
75031a5
9004db4
b29cd21
30196f1
cb461b1
4ecb993
2c8aeed
3b5b042
b557f84
3dbdbd4
6e8e46f
309bedc
1ee04d7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -56,7 +56,10 @@ 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): | ||
# 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)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would just add a comment to say this is needed as dictionary can incorrectly accept xarray (duck typing fails here!). The comment might also mention that a cleaner approach would be welcome... |
||
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)) | ||
|
@@ -84,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 | ||
|
@@ -132,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]) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,6 +37,8 @@ class GridInterface(DictInterface): | |
|
||
datatype = 'grid' | ||
|
||
gridded = True | ||
|
||
@classmethod | ||
def init(cls, eltype, data, kdims, vdims): | ||
if kdims is None: | ||
|
@@ -53,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 | ||
|
@@ -71,7 +73,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}, {} | ||
|
||
|
||
|
@@ -101,19 +103,76 @@ def length(cls, dataset): | |
return np.product([len(dataset.data[d.name]) for d in dataset.kdims]) | ||
|
||
|
||
@classmethod | ||
def coords(cls, dataset, dim, ordered=False, expanded=False): | ||
""" | ||
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 canonicalize(cls, dataset, data, coord_dims=None): | ||
""" | ||
Canonicalize takes an array of values as input and | ||
reorients and transposes it to match the canonical | ||
format expected by plotting functions. In addition | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is probably too much of a pain to stick in the docstring but it would be good to describe our canonical format properly somewhere in our docs. Not something that should hold up this PR though! |
||
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. | ||
""" | ||
if coord_dims is None: | ||
coord_dims = dataset.dimensions('key', True) | ||
|
||
# Reorient data | ||
invert = False | ||
slices = [] | ||
for d in coord_dims: | ||
coords = cls.coords(dataset, d) | ||
if np.all(coords[1:] < coords[:-1]): | ||
slices.append(slice(None, None, -1)) | ||
invert = True | ||
else: | ||
slices.append(slice(None)) | ||
data = data.__getitem__(slices[::-1]) if invert else data | ||
|
||
# Transpose data | ||
dims = [name for name in coord_dims[::-1] | ||
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 | ||
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 | ||
|
||
|
||
@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]) | ||
idx = dataset.get_dimension_index(dim) | ||
values = prod[idx] | ||
return values.flatten() if flat else values | ||
else: | ||
if dim in dataset.vdims: | ||
dim = dataset.get_dimension(dim) | ||
values = dataset.data.get(dim.name) | ||
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.coords(dataset, dim, expanded=True) | ||
return data.flatten() if flat else data | ||
else: | ||
return cls.coords(dataset, dim, ordered=True) | ||
|
||
|
||
@classmethod | ||
|
@@ -282,17 +341,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 | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this looks right, but if I am not confused this is a separate fix from the rest of the PR? Looks like the kwargs weren't being passed into the group container when dynamic....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That caused weird bugs on the interfaces before I fixed the grid interfaces. So it's related at least.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm happy to have the fix! I just wanted to make sure I understood it...