diff --git a/doc/api.rst b/doc/api.rst index 055ec733641..b97f74d2ba7 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -481,6 +481,14 @@ Testing testing.assert_identical testing.assert_allclose +Exceptions +========== + +.. autosummary:: + :toctree: generated/ + + MergeError + Advanced API ============ diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 25c70806e92..6aadbec1701 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -38,6 +38,10 @@ Enhancements to ``py.test`` (:issue:`1393`). By `Matthew 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 `_. + Bug fixes ~~~~~~~~~ diff --git a/xarray/__init__.py b/xarray/__init__.py index c88a0176616..858bc3ec047 100644 --- a/xarray/__init__.py +++ b/xarray/__init__.py @@ -1,3 +1,4 @@ +# flake8: noqa from __future__ import absolute_import from __future__ import division from __future__ import print_function diff --git a/xarray/core/alignment.py b/xarray/core/alignment.py index 6350bcdff07..5770ec2cd50 100644 --- a/xarray/core/alignment.py +++ b/xarray/core/alignment.py @@ -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) @@ -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 @@ -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: diff --git a/xarray/core/computation.py b/xarray/core/computation.py index 685ac3f86bf..e866de2752a 100644 --- a/xarray/core/computation.py +++ b/xarray/core/computation.py @@ -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. diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py index ae5499a46a7..28524134474 100644 --- a/xarray/core/dataset.py +++ b/xarray/core/dataset.py @@ -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 ------- diff --git a/xarray/core/merge.py b/xarray/core/merge.py index 82596b3a6e5..d156d0d78ef 100644 --- a/xarray/core/merge.py +++ b/xarray/core/merge.py @@ -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 diff --git a/xarray/core/ops.py b/xarray/core/ops.py index 5c93c54cf90..45cc6ae80a6 100644 --- a/xarray/core/ops.py +++ b/xarray/core/ops.py @@ -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. diff --git a/xarray/tests/test_dataset.py b/xarray/tests/test_dataset.py index 0d5e3624a0f..92f86f4fcf3 100644 --- a/xarray/tests/test_dataset.py +++ b/xarray/tests/test_dataset.py @@ -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]})}) diff --git a/xarray/tests/test_merge.py b/xarray/tests/test_merge.py index c612e61fe35..c7b6868da26 100644 --- a/xarray/tests/test_merge.py +++ b/xarray/tests/test_merge.py @@ -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]})