Skip to content

Commit

Permalink
review: enable coord specification
Browse files Browse the repository at this point in the history
  • Loading branch information
rcomer committed Oct 3, 2018
1 parent 57d38e0 commit 363ee2f
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 10 deletions.
54 changes: 50 additions & 4 deletions lib/iris/tests/unit/util/test_reverse.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def test_simple_array(self):
self.assertRaises(ValueError, reverse, a, 10)
self.assertRaises(ValueError, reverse, a, [-1])
self.assertRaises(ValueError, reverse, a, [0, -1])
self.assertRaises(TypeError, reverse, a, 'latitude')

def test_single_array(self):
a = np.arange(36).reshape(3, 4, 3)
Expand All @@ -53,6 +54,7 @@ def test_single_array(self):
self.assertRaises(ValueError, reverse, a, 10)
self.assertRaises(ValueError, reverse, a, [-1])
self.assertRaises(ValueError, reverse, a, [0, -1])
self.assertRaises(TypeError, reverse, a, 'latitude')


class Test_cube(tests.IrisTest):
Expand All @@ -61,17 +63,21 @@ def setUp(self):
# matching long names but the points array on one cube is reversed
# with respect to that on the other.
data = np.arange(12).reshape(3, 4)
a1 = iris.coords.DimCoord([1, 2, 3], long_name='a')
b1 = iris.coords.DimCoord([1, 2, 3, 4], long_name='b')
self.a1 = iris.coords.DimCoord([1, 2, 3], long_name='a')
self.b1 = iris.coords.DimCoord([1, 2, 3, 4], long_name='b')
a2 = iris.coords.DimCoord([3, 2, 1], long_name='a')
b2 = iris.coords.DimCoord([4, 3, 2, 1], long_name='b')
self.span = iris.coords.AuxCoord(np.arange(12).reshape(3, 4),
long_name='spanning')

self.cube1 = iris.cube.Cube(
data, dim_coords_and_dims=[(a1, 0), (b1, 1)])
data, dim_coords_and_dims=[(self.a1, 0), (self.b1, 1)],
aux_coords_and_dims=[(self.span, (0, 1))])

self.cube2 = iris.cube.Cube(
data, dim_coords_and_dims=[(a2, 0), (b2, 1)])

def test_cube(self):
def test_cube_dim(self):
cube1_reverse0 = reverse(self.cube1, 0)
cube1_reverse1 = reverse(self.cube1, 1)
cube1_reverse_both = reverse(self.cube1, (0, 1))
Expand All @@ -95,6 +101,46 @@ def test_cube(self):
self.assertArrayEqual(self.cube2.coord('b').points,
cube1_reverse_both.coord('b').points)

def test_cube_coord(self):
cube1_reverse0 = reverse(self.cube1, self.a1)
cube1_reverse1 = reverse(self.cube1, 'b')
cube1_reverse_both = reverse(self.cube1, (self.a1, self.b1))
cube1_reverse_spanning = reverse(self.cube1, 'spanning')

self.assertArrayEqual(self.cube1.data[::-1], cube1_reverse0.data)
self.assertArrayEqual(self.cube2.coord('a').points,
cube1_reverse0.coord('a').points)
self.assertArrayEqual(self.cube1.coord('b').points,
cube1_reverse0.coord('b').points)

self.assertArrayEqual(self.cube1.data[:, ::-1], cube1_reverse1.data)
self.assertArrayEqual(self.cube1.coord('a').points,
cube1_reverse1.coord('a').points)
self.assertArrayEqual(self.cube2.coord('b').points,
cube1_reverse1.coord('b').points)

self.assertArrayEqual(self.cube1.data[::-1, ::-1],
cube1_reverse_both.data)
self.assertArrayEqual(self.cube2.coord('a').points,
cube1_reverse_both.coord('a').points)
self.assertArrayEqual(self.cube2.coord('b').points,
cube1_reverse_both.coord('b').points)

self.assertArrayEqual(self.cube1.data[::-1, ::-1],
cube1_reverse_spanning.data)
self.assertArrayEqual(self.cube2.coord('a').points,
cube1_reverse_spanning.coord('a').points)
self.assertArrayEqual(self.cube2.coord('b').points,
cube1_reverse_spanning.coord('b').points)
self.assertArrayEqual(
self.span.points[::-1, ::-1],
cube1_reverse_spanning.coord('spanning').points)

self.assertRaises(iris.exceptions.CoordinateNotFoundError, reverse,
self.cube1, 'latitude')
self.assertRaises(ValueError, reverse, self.cube1, [])
self.assertRaises(TypeError, reverse, self.cube1, self.cube1)


if __name__ == '__main__':
unittest.main()
34 changes: 28 additions & 6 deletions lib/iris/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@

import iris
import iris.exceptions
import iris.cube


def broadcast_to_shape(array, shape, dim_map):
Expand Down Expand Up @@ -406,16 +407,19 @@ def between(lh, rh, lh_inclusive=True, rh_inclusive=True):
return lambda c: lh < c < rh


def reverse(cube_or_array, axes):
def reverse(cube_or_array, coords_or_dims):
"""
Reverse the cube or array along the given axes.
Reverse the cube or array along the given dimensions.
Args:
* cube_or_array: :class:`iris.cube.Cube` or :class:`numpy.ndarray`
The cube or array to reverse
* axes: int or sequence of ints
One or more axes to reverse.
The cube or array to reverse.
* coords_or_dims: int, str, :class:`iris.coords.Coord` or sequence of these.
Identify one or more dimensions to reverse. If cube_or_array is a
numpy array, use int or a sequence of ints, as in the examples below.
If cube_or_array is a Cube, a Coord or coordinate name (or sequence of
these) may be specified instead.
::
Expand Down Expand Up @@ -448,7 +452,25 @@ def reverse(cube_or_array, axes):
"""
index = [slice(None, None)] * cube_or_array.ndim
axes = np.array(axes, ndmin=1)

if iris.cube._is_single_item(coords_or_dims):
coords_or_dims = [coords_or_dims]

axes = set()
for coord_or_dim in coords_or_dims:
if isinstance(coord_or_dim, int):
axes.add(coord_or_dim)
elif isinstance(cube_or_array, np.ndarray):
raise TypeError(
'To reverse an array, provide an int or sequence of ints.')
else:
try:
axes.update(cube_or_array.coord_dims(coord_or_dim))
except AttributeError:
raise TypeError('coords_or_dims must be int, str, coordinate '
'or sequence of these.')

axes = np.array(list(axes), ndmin=1)
if axes.ndim != 1:
raise ValueError('Reverse was expecting a single axis or a 1d array '
'of axes, got %r' % axes)
Expand Down

0 comments on commit 363ee2f

Please sign in to comment.