Skip to content

If join='exact', raise an error for non-aligned objects #1330

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

Merged
merged 4 commits into from
May 31, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions doc/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,14 @@ Testing
testing.assert_identical
testing.assert_allclose

Exceptions
==========

.. autosummary::
:toctree: generated/

MergeError

Advanced API
============

Expand Down
4 changes: 4 additions & 0 deletions doc/whats-new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ Enhancements
to ``py.test`` (:issue:`1393`).
By `Matthew Gidden <https://github.com/gidden>`_.

- :py:func:`~xarray.align` now supports ``join='exact'``, which raises
an error instead of aligning when indexes to be aligned are not equal.
By `Stephan Hoyer <https://github.com/shoyer>`_.

Bug fixes
~~~~~~~~~

Expand Down
1 change: 1 addition & 0 deletions xarray/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# flake8: noqa
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
Expand Down
12 changes: 11 additions & 1 deletion xarray/core/alignment.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ def _get_joiner(join):
return operator.itemgetter(0)
elif join == 'right':
return operator.itemgetter(-1)
elif join == 'exact':
# We cannot return a function to "align" in this case, because it needs
# access to the dimension name to give a good error message.
return None
else:
raise ValueError('invalid value for join: %s' % join)

Expand All @@ -47,13 +51,15 @@ def align(*objects, **kwargs):
----------
*objects : Dataset or DataArray
Objects to align.
join : {'outer', 'inner', 'left', 'right'}, optional
join : {'outer', 'inner', 'left', 'right', 'exact'}, optional
Method for joining the indexes of the passed objects along each
dimension:
- 'outer': use the union of object indexes
- 'inner': use the intersection of object indexes
- 'left': use indexes from the first object with each dimension
- 'right': use indexes from the last object with each dimension
- 'exact': instead of aligning, raise `ValueError` when indexes to be
aligned are not equal
copy : bool, optional
If ``copy=True``, data in the return values is always copied. If
``copy=False`` and reindexing is unnecessary, or can be performed with
Expand Down Expand Up @@ -120,6 +126,10 @@ def align(*objects, **kwargs):
if (any(not matching_indexes[0].equals(other)
for other in matching_indexes[1:]) or
dim in unlabeled_dim_sizes):
if join == 'exact':
raise ValueError(
'indexes along dimension {!r} are not equal'
.format(dim))
index = joiner(matching_indexes)
joined_indexes[dim] = index
else:
Expand Down
2 changes: 2 additions & 0 deletions xarray/core/computation.py
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,8 @@ def apply_ufunc(func, *args, **kwargs):
- 'inner': use the intersection of object indexes
- 'left': use indexes from the first object with each dimension
- 'right': use indexes from the last object with each dimension
- 'exact': raise `ValueError` instead of aligning when indexes to be
aligned are not equal
dataset_join : {'outer', 'inner', 'left', 'right'}, optional
Method for joining variables of Dataset objects with mismatched
data variables.
Expand Down
3 changes: 2 additions & 1 deletion xarray/core/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -1944,13 +1944,14 @@ def merge(self, other, inplace=False, overwrite_vars=frozenset(),
- 'no_conflicts': only values which are not null in both datasets
must be equal. The returned dataset then contains the combination
of all non-null values.
join : {'outer', 'inner', 'left', 'right'}, optional
join : {'outer', 'inner', 'left', 'right', 'exact'}, optional
Method for joining ``self`` and ``other`` along shared dimensions:

- 'outer': use the union of the indexes
- 'inner': use the intersection of the indexes
- 'left': use indexes from ``self``
- 'right': use indexes from ``other``
- 'exact': error instead of aligning non-equal indexes

Returns
-------
Expand Down
2 changes: 1 addition & 1 deletion xarray/core/merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ def merge(objects, compat='no_conflicts', join='outer'):
- 'no_conflicts': only values which are not null in both datasets
must be equal. The returned dataset then contains the combination
of all non-null values.
join : {'outer', 'inner', 'left', 'right'}, optional
join : {'outer', 'inner', 'left', 'right', 'exact'}, optional
How to combine objects with different indexes.

Returns
Expand Down
2 changes: 2 additions & 0 deletions xarray/core/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ def fillna(data, other, join="left", dataset_join="left"):
- 'inner': use the intersection of object indexes
- 'left': use indexes from the first object with each dimension
- 'right': use indexes from the last object with each dimension
- 'exact': raise `ValueError` instead of aligning when indexes to be
aligned are not equal
dataset_join : {'outer', 'inner', 'left', 'right'}, optional
Method for joining variables of Dataset objects with mismatched
data variables.
Expand Down
11 changes: 11 additions & 0 deletions xarray/tests/test_dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -1245,6 +1245,17 @@ def test_align(self):
with self.assertRaises(TypeError):
align(left, right, foo='bar')

def test_align_exact(self):
left = xr.Dataset(coords={'x': [0, 1]})
right = xr.Dataset(coords={'x': [1, 2]})

left1, left2 = xr.align(left, left, join='exact')
self.assertDatasetIdentical(left1, left)
self.assertDatasetIdentical(left2, left)

with self.assertRaisesRegexp(ValueError, 'indexes .* not equal'):
xr.align(left, right, join='exact')

def test_align_exclude(self):
x = Dataset({'foo': DataArray([[1, 2], [3, 4]], dims=['x', 'y'],
coords={'x': [1, 2], 'y': [3, 4]})})
Expand Down
6 changes: 6 additions & 0 deletions xarray/tests/test_merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ def test_merge_error(self):
with self.assertRaises(xr.MergeError):
xr.merge([ds, ds + 1])

def test_merge_alignment_error(self):
ds = xr.Dataset(coords={'x': [1, 2]})
other = xr.Dataset(coords={'x': [2, 3]})
with self.assertRaisesRegexp(ValueError, 'indexes .* not equal'):
xr.merge([ds, other], join='exact')

def test_merge_no_conflicts_single_var(self):
ds1 = xr.Dataset({'a': ('x', [1, 2]), 'x': [0, 1]})
ds2 = xr.Dataset({'a': ('x', [2, 3]), 'x': [1, 2]})
Expand Down