summaryrefslogtreecommitdiff
path: root/numpy/ma
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/ma')
-rw-r--r--numpy/ma/core.py39
-rw-r--r--numpy/ma/extras.py43
-rw-r--r--numpy/ma/tests/test_core.py54
-rw-r--r--numpy/ma/tests/test_extras.py3
-rw-r--r--numpy/ma/tests/test_subclassing.py43
5 files changed, 156 insertions, 26 deletions
diff --git a/numpy/ma/core.py b/numpy/ma/core.py
index faf9896a5..fe3c03789 100644
--- a/numpy/ma/core.py
+++ b/numpy/ma/core.py
@@ -2470,7 +2470,6 @@ class _arraymethod(object):
return result
-
class MaskedIterator(object):
"""
Flat iterator object to iterate over masked arrays.
@@ -2534,8 +2533,14 @@ class MaskedIterator(object):
result = self.dataiter.__getitem__(indx).view(type(self.ma))
if self.maskiter is not None:
_mask = self.maskiter.__getitem__(indx)
- _mask.shape = result.shape
- result._mask = _mask
+ if isinstance(_mask, ndarray):
+ # set shape to match that of data; this is needed for matrices
+ _mask.shape = result.shape
+ result._mask = _mask
+ elif isinstance(_mask, np.void):
+ return mvoid(result, mask=_mask, hardmask=self.ma._hardmask)
+ elif _mask: # Just a scalar, masked
+ return masked
return result
### This won't work is ravel makes a copy
@@ -2567,8 +2572,12 @@ class MaskedIterator(object):
"""
d = next(self.dataiter)
- if self.maskiter is not None and next(self.maskiter):
- d = masked
+ if self.maskiter is not None:
+ m = next(self.maskiter)
+ if isinstance(m, np.void):
+ return mvoid(d, mask=m, hardmask=self.ma._hardmask)
+ elif m: # Just a scalar, masked
+ return masked
return d
next = __next__
@@ -3585,9 +3594,8 @@ class MaskedArray(ndarray):
if m.dtype.names:
m = m.view((bool, len(m.dtype)))
if m.any():
- r = np.array(self._data.tolist(), dtype=object)
- np.copyto(r, f, where=m)
- return str(tuple(r))
+ return str(tuple((f if _m else _d) for _d, _m in
+ zip(self._data.tolist(), m)))
else:
return str(self._data)
elif m:
@@ -3598,7 +3606,7 @@ class MaskedArray(ndarray):
names = self.dtype.names
if names is None:
res = self._data.astype("O")
- res[m] = f
+ res.view(ndarray)[m] = f
else:
rdtype = _recursive_make_descr(self.dtype, "O")
res = self._data.astype(rdtype)
@@ -3612,19 +3620,22 @@ class MaskedArray(ndarray):
"""
n = len(self.shape)
- name = repr(self._data).split('(')[0]
+ if self._baseclass is np.ndarray:
+ name = 'array'
+ else:
+ name = self._baseclass.__name__
+
parameters = dict(name=name, nlen=" " * len(name),
- data=str(self), mask=str(self._mask),
- fill=str(self.fill_value), dtype=str(self.dtype))
+ data=str(self), mask=str(self._mask),
+ fill=str(self.fill_value), dtype=str(self.dtype))
if self.dtype.names:
if n <= 1:
return _print_templates['short_flx'] % parameters
- return _print_templates['long_flx'] % parameters
+ return _print_templates['long_flx'] % parameters
elif n <= 1:
return _print_templates['short_std'] % parameters
return _print_templates['long_std'] % parameters
-
def __eq__(self, other):
"Check whether other equals self elementwise"
if self is masked:
diff --git a/numpy/ma/extras.py b/numpy/ma/extras.py
index 7182bf4ae..f53d9c7e5 100644
--- a/numpy/ma/extras.py
+++ b/numpy/ma/extras.py
@@ -416,26 +416,53 @@ def apply_over_axes(func, a, axes):
"""
(This docstring will be overwritten)
"""
- val = np.asarray(a)
- msk = getmaskarray(a)
+ val = asarray(a)
N = a.ndim
if array(axes).ndim == 0:
axes = (axes,)
for axis in axes:
if axis < 0: axis = N + axis
args = (val, axis)
- res = ma.array(func(*(val, axis)), mask=func(*(msk, axis)))
+ res = func(*args)
if res.ndim == val.ndim:
- (val, msk) = (res._data, res._mask)
+ val = res
else:
res = ma.expand_dims(res, axis)
if res.ndim == val.ndim:
- (val, msk) = (res._data, res._mask)
+ val = res
else:
- raise ValueError("Function is not returning"\
- " an array of correct shape")
+ raise ValueError("function is not returning "
+ "an array of the correct shape")
return val
-apply_over_axes.__doc__ = np.apply_over_axes.__doc__
+apply_over_axes.__doc__ = np.apply_over_axes.__doc__[
+ :np.apply_over_axes.__doc__.find('Notes')].rstrip() + \
+ """
+
+ Examples
+ --------
+ >>> a = ma.arange(24).reshape(2,3,4)
+ >>> a[:,0,1] = ma.masked
+ >>> a[:,1,:] = ma.masked
+ >>> print a
+ [[[0 -- 2 3]
+ [-- -- -- --]
+ [8 9 10 11]]
+
+ [[12 -- 14 15]
+ [-- -- -- --]
+ [20 21 22 23]]]
+ >>> print ma.apply_over_axes(ma.sum, a, [0,2])
+ [[[46]
+ [--]
+ [124]]]
+
+ Tuple axis arguments to ufuncs are equivalent:
+
+ >>> print ma.sum(a, axis=(0,2)).reshape((1,-1,1))
+ [[[46]
+ [--]
+ [124]]]
+"""
def average(a, axis=None, weights=None, returned=False):
diff --git a/numpy/ma/tests/test_core.py b/numpy/ma/tests/test_core.py
index 6bb8d5b2e..4a39103b2 100644
--- a/numpy/ma/tests/test_core.py
+++ b/numpy/ma/tests/test_core.py
@@ -369,6 +369,13 @@ class TestMaskedArray(TestCase):
assert_equal(copied.mask, [0, 0, 0])
assert_equal(a.mask, [0, 1, 0])
+ def test_str_repr(self):
+ a = array([0, 1, 2], mask=[False, True, False])
+ assert_equal(str(a), '[0 -- 2]')
+ assert_equal(repr(a), 'masked_array(data = [0 -- 2],\n'
+ ' mask = [False True False],\n'
+ ' fill_value = 999999)\n')
+
def test_pickling(self):
# Tests pickling
a = arange(10)
@@ -1298,16 +1305,57 @@ class TestMaskedArrayAttributes(TestCase):
assert_equal(a.mask, nomask)
def test_flat(self):
+ # Test that flat can return all types of items [#4585, #4615]
+ # test simple access
+ test = masked_array(np.matrix([[1, 2, 3]]), mask=[0, 0, 1])
+ assert_equal(test.flat[1], 2)
+ assert_equal(test.flat[2], masked)
+ self.assertTrue(np.all(test.flat[0:2] == test[0, 0:2]))
# Test flat on masked_matrices
test = masked_array(np.matrix([[1, 2, 3]]), mask=[0, 0, 1])
test.flat = masked_array([3, 2, 1], mask=[1, 0, 0])
control = masked_array(np.matrix([[3, 2, 1]]), mask=[1, 0, 0])
assert_equal(test, control)
- #
+ # Test setting
test = masked_array(np.matrix([[1, 2, 3]]), mask=[0, 0, 1])
testflat = test.flat
testflat[:] = testflat[[2, 1, 0]]
assert_equal(test, control)
+ testflat[0] = 9
+ assert_equal(test[0, 0], 9)
+ # test 2-D record array
+ # ... on structured array w/ masked records
+ x = array([[(1, 1.1, 'one'), (2, 2.2, 'two'), (3, 3.3, 'thr')],
+ [(4, 4.4, 'fou'), (5, 5.5, 'fiv'), (6, 6.6, 'six')]],
+ dtype=[('a', int), ('b', float), ('c', '|S8')])
+ x['a'][0, 1] = masked
+ x['b'][1, 0] = masked
+ x['c'][0, 2] = masked
+ x[-1, -1] = masked
+ xflat = x.flat
+ assert_equal(xflat[0], x[0, 0])
+ assert_equal(xflat[1], x[0, 1])
+ assert_equal(xflat[2], x[0, 2])
+ assert_equal(xflat[:3], x[0])
+ assert_equal(xflat[3], x[1, 0])
+ assert_equal(xflat[4], x[1, 1])
+ assert_equal(xflat[5], x[1, 2])
+ assert_equal(xflat[3:], x[1])
+ assert_equal(xflat[-1], x[-1, -1])
+ i = 0
+ j = 0
+ for xf in xflat:
+ assert_equal(xf, x[j, i])
+ i += 1
+ if i >= x.shape[-1]:
+ i = 0
+ j += 1
+ # test that matrices keep the correct shape (#4615)
+ a = masked_array(np.matrix(np.eye(2)), mask=0)
+ b = a.flat
+ b01 = b[:2]
+ assert_equal(b01.data, array([[1., 0.]]))
+ assert_equal(b01.mask, array([[False, False]]))
#------------------------------------------------------------------------------
@@ -3624,7 +3672,7 @@ def test_append_masked_array():
def test_append_masked_array_along_axis():
a = np.ma.masked_equal([1,2,3], value=2)
b = np.ma.masked_values([[4, 5, 6], [7, 8, 9]], 7)
-
+
# When `axis` is specified, `values` must have the correct shape.
assert_raises(ValueError, np.ma.append, a, b, axis=0)
@@ -3634,7 +3682,7 @@ def test_append_masked_array_along_axis():
expected = expected.reshape((3,3))
assert_array_equal(result.data, expected.data)
assert_array_equal(result.mask, expected.mask)
-
+
###############################################################################
if __name__ == "__main__":
diff --git a/numpy/ma/tests/test_extras.py b/numpy/ma/tests/test_extras.py
index dc0f87b92..fa7503392 100644
--- a/numpy/ma/tests/test_extras.py
+++ b/numpy/ma/tests/test_extras.py
@@ -489,7 +489,8 @@ class TestApplyOverAxes(TestCase):
assert_equal(test, ctrl)
a[(a % 2).astype(np.bool)] = masked
test = apply_over_axes(np.sum, a, [0, 2])
- ctrl = np.array([[[30], [44], [60]]])
+ ctrl = np.array([[[28], [44], [60]]])
+ assert_equal(test, ctrl)
class TestMedian(TestCase):
diff --git a/numpy/ma/tests/test_subclassing.py b/numpy/ma/tests/test_subclassing.py
index c2c9b8ec9..ade5c59da 100644
--- a/numpy/ma/tests/test_subclassing.py
+++ b/numpy/ma/tests/test_subclassing.py
@@ -82,6 +82,24 @@ class MMatrix(MaskedArray, np.matrix,):
mmatrix = MMatrix
+# also a subclass that overrides __str__, __repr__ and __setitem__, disallowing
+# setting to non-class values (and thus np.ma.core.masked_print_option)
+class ComplicatedSubArray(SubArray):
+ def __str__(self):
+ return 'myprefix {0} mypostfix'.format(
+ super(ComplicatedSubArray, self).__str__())
+
+ def __repr__(self):
+ # Return a repr that does not start with 'name('
+ return '<{0} {1}>'.format(self.__class__.__name__, self)
+
+ def __setitem__(self, item, value):
+ # this ensures direct assignment to masked_print_option will fail
+ if not isinstance(value, ComplicatedSubArray):
+ raise ValueError("Can only set to MySubArray values")
+ super(ComplicatedSubArray, self).__setitem__(item, value)
+
+
class TestSubclassing(TestCase):
# Test suite for masked subclasses of ndarray.
@@ -187,6 +205,31 @@ class TestSubclassing(TestCase):
assert_equal(mxsub.info, xsub.info)
assert_equal(mxsub._mask, m)
+ def test_subclass_repr(self):
+ """test that repr uses the name of the subclass
+ and 'array' for np.ndarray"""
+ x = np.arange(5)
+ mx = masked_array(x, mask=[True, False, True, False, False])
+ self.assertTrue(repr(mx).startswith('masked_array'))
+ xsub = SubArray(x)
+ mxsub = masked_array(xsub, mask=[True, False, True, False, False])
+ self.assertTrue(repr(mxsub).startswith(
+ 'masked_{0}(data = [-- 1 -- 3 4]'.format(SubArray.__name__)))
+
+ def test_subclass_str(self):
+ """test str with subclass that has overridden str, setitem"""
+ # first without override
+ x = np.arange(5)
+ xsub = SubArray(x)
+ mxsub = masked_array(xsub, mask=[True, False, True, False, False])
+ self.assertTrue(str(mxsub) == '[-- 1 -- 3 4]')
+
+ xcsub = ComplicatedSubArray(x)
+ assert_raises(ValueError, xcsub.__setitem__, 0,
+ np.ma.core.masked_print_option)
+ mxcsub = masked_array(xcsub, mask=[True, False, True, False, False])
+ self.assertTrue(str(mxcsub) == 'myprefix [-- 1 -- 3 4] mypostfix')
+
###############################################################################
if __name__ == '__main__':