Skip to content

Commit 6b18d77

Browse files
authored
If join='exact', raise an error for non-aligned objects (#1330)
* If join='exact', raise an error for non-aligned objects `align` now supports ``join='exact'``, which raises `xarray.AlignmentError` instead of aligning when indexes to be aligned are not equal. This is useful for asserting that objects are identical instead of aligning in xarray operations. For example: ds1 = xarray.Dataset({'x': [0, 1]}) ds2 = xarray.Dataset({'x': [1, 2]}) xarray.merge([ds1, ds2], join='exact') # AlignmentError: indexes along dimension 'x' are not equal * Switch AlignmentError -> ValueError * What's new fix
1 parent 8df660b commit 6b18d77

File tree

10 files changed

+48
-3
lines changed

10 files changed

+48
-3
lines changed

doc/api.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,14 @@ Testing
481481
testing.assert_identical
482482
testing.assert_allclose
483483

484+
Exceptions
485+
==========
486+
487+
.. autosummary::
488+
:toctree: generated/
489+
490+
MergeError
491+
484492
Advanced API
485493
============
486494

doc/whats-new.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ Enhancements
3838
to ``py.test`` (:issue:`1393`).
3939
By `Matthew Gidden <https://github.com/gidden>`_.
4040

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

xarray/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# flake8: noqa
12
from __future__ import absolute_import
23
from __future__ import division
34
from __future__ import print_function

xarray/core/alignment.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ def _get_joiner(join):
2424
return operator.itemgetter(0)
2525
elif join == 'right':
2626
return operator.itemgetter(-1)
27+
elif join == 'exact':
28+
# We cannot return a function to "align" in this case, because it needs
29+
# access to the dimension name to give a good error message.
30+
return None
2731
else:
2832
raise ValueError('invalid value for join: %s' % join)
2933

@@ -47,13 +51,15 @@ def align(*objects, **kwargs):
4751
----------
4852
*objects : Dataset or DataArray
4953
Objects to align.
50-
join : {'outer', 'inner', 'left', 'right'}, optional
54+
join : {'outer', 'inner', 'left', 'right', 'exact'}, optional
5155
Method for joining the indexes of the passed objects along each
5256
dimension:
5357
- 'outer': use the union of object indexes
5458
- 'inner': use the intersection of object indexes
5559
- 'left': use indexes from the first object with each dimension
5660
- 'right': use indexes from the last object with each dimension
61+
- 'exact': instead of aligning, raise `ValueError` when indexes to be
62+
aligned are not equal
5763
copy : bool, optional
5864
If ``copy=True``, data in the return values is always copied. If
5965
``copy=False`` and reindexing is unnecessary, or can be performed with
@@ -120,6 +126,10 @@ def align(*objects, **kwargs):
120126
if (any(not matching_indexes[0].equals(other)
121127
for other in matching_indexes[1:]) or
122128
dim in unlabeled_dim_sizes):
129+
if join == 'exact':
130+
raise ValueError(
131+
'indexes along dimension {!r} are not equal'
132+
.format(dim))
123133
index = joiner(matching_indexes)
124134
joined_indexes[dim] = index
125135
else:

xarray/core/computation.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,8 @@ def apply_ufunc(func, *args, **kwargs):
599599
- 'inner': use the intersection of object indexes
600600
- 'left': use indexes from the first object with each dimension
601601
- 'right': use indexes from the last object with each dimension
602+
- 'exact': raise `ValueError` instead of aligning when indexes to be
603+
aligned are not equal
602604
dataset_join : {'outer', 'inner', 'left', 'right'}, optional
603605
Method for joining variables of Dataset objects with mismatched
604606
data variables.

xarray/core/dataset.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1944,13 +1944,14 @@ def merge(self, other, inplace=False, overwrite_vars=frozenset(),
19441944
- 'no_conflicts': only values which are not null in both datasets
19451945
must be equal. The returned dataset then contains the combination
19461946
of all non-null values.
1947-
join : {'outer', 'inner', 'left', 'right'}, optional
1947+
join : {'outer', 'inner', 'left', 'right', 'exact'}, optional
19481948
Method for joining ``self`` and ``other`` along shared dimensions:
19491949
19501950
- 'outer': use the union of the indexes
19511951
- 'inner': use the intersection of the indexes
19521952
- 'left': use indexes from ``self``
19531953
- 'right': use indexes from ``other``
1954+
- 'exact': error instead of aligning non-equal indexes
19541955
19551956
Returns
19561957
-------

xarray/core/merge.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ def merge(objects, compat='no_conflicts', join='outer'):
457457
- 'no_conflicts': only values which are not null in both datasets
458458
must be equal. The returned dataset then contains the combination
459459
of all non-null values.
460-
join : {'outer', 'inner', 'left', 'right'}, optional
460+
join : {'outer', 'inner', 'left', 'right', 'exact'}, optional
461461
How to combine objects with different indexes.
462462
463463
Returns

xarray/core/ops.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ def fillna(data, other, join="left", dataset_join="left"):
133133
- 'inner': use the intersection of object indexes
134134
- 'left': use indexes from the first object with each dimension
135135
- 'right': use indexes from the last object with each dimension
136+
- 'exact': raise `ValueError` instead of aligning when indexes to be
137+
aligned are not equal
136138
dataset_join : {'outer', 'inner', 'left', 'right'}, optional
137139
Method for joining variables of Dataset objects with mismatched
138140
data variables.

xarray/tests/test_dataset.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,6 +1245,17 @@ def test_align(self):
12451245
with self.assertRaises(TypeError):
12461246
align(left, right, foo='bar')
12471247

1248+
def test_align_exact(self):
1249+
left = xr.Dataset(coords={'x': [0, 1]})
1250+
right = xr.Dataset(coords={'x': [1, 2]})
1251+
1252+
left1, left2 = xr.align(left, left, join='exact')
1253+
self.assertDatasetIdentical(left1, left)
1254+
self.assertDatasetIdentical(left2, left)
1255+
1256+
with self.assertRaisesRegexp(ValueError, 'indexes .* not equal'):
1257+
xr.align(left, right, join='exact')
1258+
12481259
def test_align_exclude(self):
12491260
x = Dataset({'foo': DataArray([[1, 2], [3, 4]], dims=['x', 'y'],
12501261
coords={'x': [1, 2], 'y': [3, 4]})})

xarray/tests/test_merge.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ def test_merge_error(self):
6363
with self.assertRaises(xr.MergeError):
6464
xr.merge([ds, ds + 1])
6565

66+
def test_merge_alignment_error(self):
67+
ds = xr.Dataset(coords={'x': [1, 2]})
68+
other = xr.Dataset(coords={'x': [2, 3]})
69+
with self.assertRaisesRegexp(ValueError, 'indexes .* not equal'):
70+
xr.merge([ds, other], join='exact')
71+
6672
def test_merge_no_conflicts_single_var(self):
6773
ds1 = xr.Dataset({'a': ('x', [1, 2]), 'x': [0, 1]})
6874
ds2 = xr.Dataset({'a': ('x', [2, 3]), 'x': [1, 2]})

0 commit comments

Comments
 (0)