summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/release/1.15.0-notes.rst9
-rw-r--r--numpy/ma/extras.py50
-rw-r--r--numpy/ma/tests/test_extras.py42
3 files changed, 73 insertions, 28 deletions
diff --git a/doc/release/1.15.0-notes.rst b/doc/release/1.15.0-notes.rst
index fadce7684..6e4ef7eed 100644
--- a/doc/release/1.15.0-notes.rst
+++ b/doc/release/1.15.0-notes.rst
@@ -46,6 +46,15 @@ Future Changes
Compatibility notes
===================
+``np.ma.notmasked_contiguous`` and ``np.ma.flatnotmasked_contiguous`` always return lists
+-----------------------------------------------------------------------------------------
+This was always the documented behavior, but in reality the result used to be
+any of slice, None, or list.
+
+All downstream users seem to use detect the `None` result from
+``flatnotmasked_contiguous`` and replace it with ``[]``.
+These callers will continue to work as before.
+
C API changes
=============
diff --git a/numpy/ma/extras.py b/numpy/ma/extras.py
index e247fe170..8272dced9 100644
--- a/numpy/ma/extras.py
+++ b/numpy/ma/extras.py
@@ -1620,7 +1620,10 @@ def flatnotmasked_contiguous(a):
Returns
-------
slice_list : list
- A sorted sequence of slices (start index, end index).
+ A sorted sequence of `slice` objects (start index, end index).
+
+ ..versionchanged:: 1.15.0
+ Now returns an empty list instead of None for a fully masked array
See Also
--------
@@ -1635,7 +1638,7 @@ def flatnotmasked_contiguous(a):
--------
>>> a = np.ma.arange(10)
>>> np.ma.flatnotmasked_contiguous(a)
- slice(0, 10, None)
+ [slice(0, 10, None)]
>>> mask = (a < 3) | (a > 8) | (a == 5)
>>> a[mask] = np.ma.masked
@@ -1645,13 +1648,13 @@ def flatnotmasked_contiguous(a):
>>> np.ma.flatnotmasked_contiguous(a)
[slice(3, 5, None), slice(6, 9, None)]
>>> a[:] = np.ma.masked
- >>> print(np.ma.flatnotmasked_edges(a))
- None
+ >>> np.ma.flatnotmasked_contiguous(a)
+ []
"""
m = getmask(a)
if m is nomask:
- return slice(0, a.size, None)
+ return [slice(0, a.size)]
i = 0
result = []
for (k, g) in itertools.groupby(m.ravel()):
@@ -1659,7 +1662,7 @@ def flatnotmasked_contiguous(a):
if not k:
result.append(slice(i, i + n))
i += n
- return result or None
+ return result
def notmasked_contiguous(a, axis=None):
"""
@@ -1671,7 +1674,8 @@ def notmasked_contiguous(a, axis=None):
The input array.
axis : int, optional
Axis along which to perform the operation.
- If None (default), applies to a flattened version of the array.
+ If None (default), applies to a flattened version of the array, and this
+ is the same as `flatnotmasked_contiguous`.
Returns
-------
@@ -1679,6 +1683,8 @@ def notmasked_contiguous(a, axis=None):
A list of slices (start and end indexes) of unmasked indexes
in the array.
+ If the input is 2d and axis is specified, the result is a list of lists.
+
See Also
--------
flatnotmasked_edges, flatnotmasked_contiguous, notmasked_edges,
@@ -1690,17 +1696,35 @@ def notmasked_contiguous(a, axis=None):
Examples
--------
- >>> a = np.arange(9).reshape((3, 3))
+ >>> a = np.arange(12).reshape((3, 4))
>>> mask = np.zeros_like(a)
- >>> mask[1:, 1:] = 1
-
+ >>> mask[1:, :-1] = 1; mask[0, 1] = 1; mask[-1, 0] = 0
>>> ma = np.ma.array(a, mask=mask)
+ >>> ma
+ masked_array(
+ data=[[0, --, 2, 3],
+ [--, --, --, 7],
+ [8, --, --, 11]],
+ mask=[[False, True, False, False],
+ [ True, True, True, False],
+ [False, True, True, False]],
+ fill_value=999999)
>>> np.array(ma[~ma.mask])
- array([0, 1, 2, 3, 6])
+ array([ 0, 2, 3, 7, 8, 11])
>>> np.ma.notmasked_contiguous(ma)
- [slice(0, 4, None), slice(6, 7, None)]
+ [slice(0, 1, None), slice(2, 4, None), slice(7, 9, None), slice(11, 12, None)]
+
+ >>> np.ma.notmasked_contiguous(ma, axis=0)
+ [[slice(0, 1, None), slice(2, 3, None)], # column broken into two segments
+ [], # fully masked column
+ [slice(0, 1, None)],
+ [slice(0, 3, None)]]
+ >>> np.ma.notmasked_contiguous(ma, axis=1)
+ [[slice(0, 1, None), slice(2, 4, None)], # row broken into two segments
+ [slice(3, 4, None)],
+ [slice(0, 1, None), slice(3, 4, None)]]
"""
a = asarray(a)
nd = a.ndim
@@ -1717,7 +1741,7 @@ def notmasked_contiguous(a, axis=None):
#
for i in range(a.shape[other]):
idx[other] = i
- result.append(flatnotmasked_contiguous(a[tuple(idx)]) or None)
+ result.append(flatnotmasked_contiguous(a[tuple(idx)]))
return result
diff --git a/numpy/ma/tests/test_extras.py b/numpy/ma/tests/test_extras.py
index d1c1aa63e..95319eb65 100644
--- a/numpy/ma/tests/test_extras.py
+++ b/numpy/ma/tests/test_extras.py
@@ -128,7 +128,10 @@ class TestGeneric(object):
a = arange(10)
# No mask
test = flatnotmasked_contiguous(a)
- assert_equal(test, slice(0, a.size))
+ assert_equal(test, [slice(0, a.size)])
+ # mask of all false
+ a.mask = np.zeros(10, dtype=bool)
+ assert_equal(test, [slice(0, a.size)])
# Some mask
a[(a < 3) | (a > 8) | (a == 5)] = masked
test = flatnotmasked_contiguous(a)
@@ -136,7 +139,7 @@ class TestGeneric(object):
#
a[:] = masked
test = flatnotmasked_contiguous(a)
- assert_equal(test, None)
+ assert_equal(test, [])
class TestAverage(object):
@@ -368,23 +371,32 @@ class TestNotMasked(object):
a = masked_array(np.arange(24).reshape(3, 8),
mask=[[0, 0, 0, 0, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1],
- [0, 0, 0, 0, 0, 0, 1, 0], ])
+ [0, 0, 0, 0, 0, 0, 1, 0]])
tmp = notmasked_contiguous(a, None)
- assert_equal(tmp[-1], slice(23, 24, None))
- assert_equal(tmp[-2], slice(16, 22, None))
- assert_equal(tmp[-3], slice(0, 4, None))
- #
+ assert_equal(tmp, [
+ slice(0, 4, None),
+ slice(16, 22, None),
+ slice(23, 24, None)
+ ])
+
tmp = notmasked_contiguous(a, 0)
- assert_(len(tmp[-1]) == 1)
- assert_(tmp[-2] is None)
- assert_equal(tmp[-3], tmp[-1])
- assert_(len(tmp[0]) == 2)
+ assert_equal(tmp, [
+ [slice(0, 1, None), slice(2, 3, None)],
+ [slice(0, 1, None), slice(2, 3, None)],
+ [slice(0, 1, None), slice(2, 3, None)],
+ [slice(0, 1, None), slice(2, 3, None)],
+ [slice(2, 3, None)],
+ [slice(2, 3, None)],
+ [],
+ [slice(2, 3, None)]
+ ])
#
tmp = notmasked_contiguous(a, 1)
- assert_equal(tmp[0][-1], slice(0, 4, None))
- assert_(tmp[1] is None)
- assert_equal(tmp[2][-1], slice(7, 8, None))
- assert_equal(tmp[2][-2], slice(0, 6, None))
+ assert_equal(tmp, [
+ [slice(0, 4, None)],
+ [],
+ [slice(0, 6, None), slice(7, 8, None)]
+ ])
class TestCompressFunctions(object):