diff options
Diffstat (limited to 'numpy/ma')
-rw-r--r-- | numpy/ma/core.py | 39 | ||||
-rw-r--r-- | numpy/ma/extras.py | 43 | ||||
-rw-r--r-- | numpy/ma/tests/test_core.py | 54 | ||||
-rw-r--r-- | numpy/ma/tests/test_extras.py | 3 | ||||
-rw-r--r-- | numpy/ma/tests/test_subclassing.py | 43 |
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__': |