summaryrefslogtreecommitdiff
path: root/numpy/ma
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/ma')
-rw-r--r--numpy/ma/core.py173
-rw-r--r--numpy/ma/extras.py96
-rw-r--r--numpy/ma/mrecords.py4
-rw-r--r--numpy/ma/tests/test_core.py145
-rw-r--r--numpy/ma/tests/test_extras.py26
-rw-r--r--numpy/ma/tests/test_old_ma.py14
-rw-r--r--numpy/ma/tests/test_subclassing.py43
7 files changed, 380 insertions, 121 deletions
diff --git a/numpy/ma/core.py b/numpy/ma/core.py
index 8dc2ca86e..6c0a8f345 100644
--- a/numpy/ma/core.py
+++ b/numpy/ma/core.py
@@ -46,7 +46,7 @@ __docformat__ = "restructuredtext en"
__all__ = ['MAError', 'MaskError', 'MaskType', 'MaskedArray',
'bool_',
'abs', 'absolute', 'add', 'all', 'allclose', 'allequal', 'alltrue',
- 'amax', 'amin', 'angle', 'anom', 'anomalies', 'any', 'arange',
+ 'amax', 'amin', 'angle', 'anom', 'anomalies', 'any', 'append', 'arange',
'arccos', 'arccosh', 'arcsin', 'arcsinh', 'arctan', 'arctan2',
'arctanh', 'argmax', 'argmin', 'argsort', 'around',
'array', 'asarray', 'asanyarray',
@@ -416,14 +416,19 @@ def _check_fill_value(fill_value, ndtype):
fill_value = np.array(_recursive_set_fill_value(fill_value, descr),
dtype=ndtype)
else:
- if isinstance(fill_value, basestring) and (ndtype.char not in 'SVU'):
- fill_value = default_fill_value(ndtype)
+ if isinstance(fill_value, basestring) and (ndtype.char not in 'OSVU'):
+ err_msg = "Cannot set fill value of string with array of dtype %s"
+ raise TypeError(err_msg % ndtype)
else:
- # In case we want to convert 1e+20 to int...
+ # In case we want to convert 1e20 to int...
try:
- fill_value = np.array(fill_value, copy=False, dtype=ndtype)#.item()
+ fill_value = np.array(fill_value, copy=False, dtype=ndtype)
except OverflowError:
- fill_value = default_fill_value(ndtype)
+ # Raise TypeError instead of OverflowError. OverflowError
+ # is seldom used, and the real problem here is that the
+ # passed fill_value is not compatible with the ndtype.
+ err_msg = "Fill value %s overflows dtype %s"
+ raise TypeError(err_msg % (fill_value, ndtype))
return np.array(fill_value)
@@ -838,8 +843,7 @@ class _MaskedUnaryOperation:
d = getdata(a)
# Case 1.1. : Domained function
if self.domain is not None:
- with np.errstate():
- np.seterr(divide='ignore', invalid='ignore')
+ with np.errstate(divide='ignore', invalid='ignore'):
result = self.f(d, *args, **kwargs)
# Make a mask
m = ~umath.isfinite(result)
@@ -927,8 +931,7 @@ class _MaskedBinaryOperation:
else:
m = umath.logical_or(ma, mb)
# Get the result
- with np.errstate():
- np.seterr(divide='ignore', invalid='ignore')
+ with np.errstate(divide='ignore', invalid='ignore'):
result = self.f(da, db, *args, **kwargs)
# check it worked
if result is NotImplemented:
@@ -940,11 +943,8 @@ class _MaskedBinaryOperation:
return result
# Case 2. : array
# Revert result to da where masked
- if m.any():
- np.copyto(result, 0, casting='unsafe', where=m)
- # This only makes sense if the operation preserved the dtype
- if result.dtype == da.dtype:
- result += m * da
+ if m is not nomask:
+ np.copyto(result, da, casting='unsafe', where=m)
# Transforms to a (subclass of) MaskedArray
result = result.view(get_masked_subclass(a, b))
result._mask = m
@@ -1068,8 +1068,7 @@ class _DomainedBinaryOperation:
(da, db) = (getdata(a, subok=False), getdata(b, subok=False))
(ma, mb) = (getmask(a), getmask(b))
# Get the result
- with np.errstate():
- np.seterr(divide='ignore', invalid='ignore')
+ with np.errstate(divide='ignore', invalid='ignore'):
result = self.f(da, db, *args, **kwargs)
# check it worked
if result is NotImplemented:
@@ -1089,8 +1088,7 @@ class _DomainedBinaryOperation:
else:
return result
# When the mask is True, put back da
- np.copyto(result, 0, casting='unsafe', where=m)
- result += m * da
+ np.copyto(result, da, casting='unsafe', where=m)
result = result.view(get_masked_subclass(a, b))
result._mask = m
if isinstance(b, MaskedArray):
@@ -2465,7 +2463,6 @@ class _arraymethod(object):
return result
-
class MaskedIterator(object):
"""
Flat iterator object to iterate over masked arrays.
@@ -2529,8 +2526,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
@@ -2562,8 +2565,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__
@@ -3580,9 +3587,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:
@@ -3593,7 +3599,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)
@@ -3607,19 +3613,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:
@@ -3824,8 +3833,7 @@ class MaskedArray(ndarray):
"Raise self to the power other, in place."
other_data = getdata(other)
other_mask = getmask(other)
- with np.errstate():
- np.seterr(divide='ignore', invalid='ignore')
+ with np.errstate(divide='ignore', invalid='ignore'):
ndarray.__ipow__(self._data, np.where(self._mask, 1, other_data))
invalid = np.logical_not(np.isfinite(self._data))
if invalid.any():
@@ -3976,21 +3984,16 @@ class MaskedArray(ndarray):
"""
m = self._mask
s = self.shape
- ls = len(s)
if m is nomask:
- if ls == 0:
- return 1
- if ls == 1:
- return s[0]
if axis is None:
return self.size
else:
n = s[axis]
t = list(s)
del t[axis]
- return np.ones(t) * n
+ return np.full(t, n, dtype=np.intp)
n1 = np.size(m, axis)
- n2 = m.astype(int).sum(axis)
+ n2 = np.sum(m, axis=axis, dtype=np.intp)
if axis is None:
return (n1 - n2)
else:
@@ -5071,12 +5074,12 @@ class MaskedArray(ndarray):
filler = maximum_fill_value(self)
else:
filler = fill_value
- idx = np.indices(self.shape)
+ idx = np.meshgrid(*[np.arange(x) for x in self.shape], sparse=True,
+ indexing='ij')
idx[axis] = self.filled(filler).argsort(axis=axis, kind=kind,
order=order)
- idx_l = idx.tolist()
- tmp_mask = self._mask[idx_l].flat
- tmp_data = self._data[idx_l].flat
+ tmp_mask = self._mask[idx].flat
+ tmp_data = self._data[idx].flat
self._data.flat = tmp_data
self._mask.flat = tmp_mask
return
@@ -5387,10 +5390,20 @@ class MaskedArray(ndarray):
#........................
def tostring(self, fill_value=None, order='C'):
"""
+ This function is a compatibility alias for tobytes. Despite its name it
+ returns bytes not strings.
+ """
+
+ return self.tobytes(fill_value, order='C')
+ #........................
+ def tobytes(self, fill_value=None, order='C'):
+ """
Return the array data as a string containing the raw bytes in the array.
The array is filled with a fill value before the string conversion.
+ .. versionadded:: 1.9.0
+
Parameters
----------
fill_value : scalar, optional
@@ -5406,22 +5419,22 @@ class MaskedArray(ndarray):
See Also
--------
- ndarray.tostring
+ ndarray.tobytes
tolist, tofile
Notes
-----
- As for `ndarray.tostring`, information about the shape, dtype, etc.,
+ As for `ndarray.tobytes`, information about the shape, dtype, etc.,
but also about `fill_value`, will be lost.
Examples
--------
>>> x = np.ma.array(np.array([[1, 2], [3, 4]]), mask=[[0, 1], [1, 0]])
- >>> x.tostring()
+ >>> x.tobytes()
'\\x01\\x00\\x00\\x00?B\\x0f\\x00?B\\x0f\\x00\\x04\\x00\\x00\\x00'
"""
- return self.filled(fill_value).tostring(order=order)
+ return self.filled(fill_value).tobytes(order=order)
#........................
def tofile(self, fid, sep="", format="%s"):
"""
@@ -5503,9 +5516,9 @@ class MaskedArray(ndarray):
self.shape,
self.dtype,
self.flags.fnc,
- self._data.tostring(cf),
+ self._data.tobytes(cf),
#self._data.tolist(),
- getmaskarray(self).tostring(cf),
+ getmaskarray(self).tobytes(cf),
#getmaskarray(self).tolist(),
self._fill_value,
)
@@ -6089,8 +6102,7 @@ def power(a, b, third=None):
else:
basetype = MaskedArray
# Get the result and view it as a (subclass of) MaskedArray
- with np.errstate():
- np.seterr(divide='ignore', invalid='ignore')
+ with np.errstate(divide='ignore', invalid='ignore'):
result = np.where(m, fa, umath.power(fa, fb)).view(basetype)
result._update_from(a)
# Find where we're in trouble w/ NaNs and Infs
@@ -6151,7 +6163,7 @@ def argmax(a, axis=None, fill_value=None):
pass
d = filled(a, fill_value)
return d.argmax(axis=axis)
-argmin.__doc__ = MaskedArray.argmax.__doc__
+argmax.__doc__ = MaskedArray.argmax.__doc__
def sort(a, axis= -1, kind='quicksort', order=None, endwith=True, fill_value=None):
"Function version of the eponymous method."
@@ -6167,7 +6179,8 @@ def sort(a, axis= -1, kind='quicksort', order=None, endwith=True, fill_value=Non
else:
filler = fill_value
# return
- indx = np.indices(a.shape).tolist()
+ indx = np.meshgrid(*[np.arange(x) for x in a.shape], sparse=True,
+ indexing='ij')
indx[axis] = filled(a, filler).argsort(axis=axis, kind=kind, order=order)
return a[indx]
sort.__doc__ = MaskedArray.sort.__doc__
@@ -6921,6 +6934,13 @@ def allclose (a, b, masked_equal=True, rtol=1e-5, atol=1e-8):
"""
x = masked_array(a, copy=False)
y = masked_array(b, copy=False)
+
+ # make sure y is an inexact type to avoid abs(MIN_INT); will cause
+ # casting of x later.
+ dtype = np.result_type(y, 1.)
+ if y.dtype != dtype:
+ y = masked_array(y, dtype=dtype, copy=False)
+
m = mask_or(getmask(x), getmask(y))
xinf = np.isinf(masked_array(x, copy=False, mask=m)).filled(False)
# If we have some infs, they should fall at the same place.
@@ -6932,13 +6952,16 @@ def allclose (a, b, masked_equal=True, rtol=1e-5, atol=1e-8):
atol + rtol * umath.absolute(y)),
masked_equal)
return np.all(d)
+
if not np.all(filled(x[xinf] == y[xinf], masked_equal)):
return False
x = x[~xinf]
y = y[~xinf]
+
d = filled(umath.less_equal(umath.absolute(x - y),
atol + rtol * umath.absolute(y)),
masked_equal)
+
return np.all(d)
#..............................................................................
@@ -7243,3 +7266,41 @@ zeros = _convert2ma('zeros', params=dict(fill_value=None, hardmask=False))
zeros_like = np.zeros_like
###############################################################################
+def append(a, b, axis=None):
+ """Append values to the end of an array.
+
+ .. versionadded:: 1.9.0
+
+ Parameters
+ ----------
+ arr : array_like
+ Values are appended to a copy of this array.
+ values : array_like
+ These values are appended to a copy of `arr`. It must be of the
+ correct shape (the same shape as `arr`, excluding `axis`). If `axis`
+ is not specified, `values` can be any shape and will be flattened
+ before use.
+ axis : int, optional
+ The axis along which `values` are appended. If `axis` is not given,
+ both `arr` and `values` are flattened before use.
+
+ Returns
+ -------
+ append : MaskedArray
+ A copy of `arr` with `values` appended to `axis`. Note that `append`
+ does not occur in-place: a new array is allocated and filled. If
+ `axis` is None, the result is a flattened array.
+
+ See Also
+ --------
+ numpy.append : Equivalent function in the top-level NumPy module.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> a = ma.masked_values([1, 2, 3], 2)
+ >>> b = ma.masked_values([[4, 5, 6], [7, 8, 9]], 7)
+ >>> print(ma.append(a, b))
+ [1 -- 3 4 5 6 -- 8 9]
+ """
+ return concatenate([a, b], axis)
diff --git a/numpy/ma/extras.py b/numpy/ma/extras.py
index d14812093..82a61a67c 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):
@@ -448,8 +475,8 @@ def average(a, axis=None, weights=None, returned=False):
Data to be averaged.
Masked entries are not taken into account in the computation.
axis : int, optional
- Axis along which the variance is computed. The default is to compute
- the variance of the flattened array.
+ Axis along which the average is computed. The default is to compute
+ the average of the flattened array.
weights : array_like, optional
The importance that each element has in the computation of the average.
The weights array can either be 1-D (in which case its length must be
@@ -540,7 +567,7 @@ def average(a, axis=None, weights=None, returned=False):
else:
if weights is None:
n = add.reduce(a, axis)
- d = umath.add.reduce((-mask), axis=axis, dtype=float)
+ d = umath.add.reduce((~mask), axis=axis, dtype=float)
else:
w = filled(weights, 0.0)
wsh = w.shape
@@ -641,15 +668,9 @@ def median(a, axis=None, out=None, overwrite_input=False):
fill_value = 1e+20)
"""
- def _median1D(data):
- counts = filled(count(data), 0)
- (idx, rmd) = divmod(counts, 2)
- if rmd:
- choice = slice(idx, idx + 1)
- else:
- choice = slice(idx - 1, idx + 1)
- return data[choice].mean(0)
- #
+ if not hasattr(a, 'mask') or np.count_nonzero(a.mask) == 0:
+ return masked_array(np.median(a, axis=axis, out=out,
+ overwrite_input=overwrite_input), copy=False)
if overwrite_input:
if axis is None:
asorted = a.ravel()
@@ -660,14 +681,29 @@ def median(a, axis=None, out=None, overwrite_input=False):
else:
asorted = sort(a, axis=axis)
if axis is None:
- result = _median1D(asorted)
+ axis = 0
+ elif axis < 0:
+ axis += a.ndim
+
+ counts = asorted.shape[axis] - (asorted.mask).sum(axis=axis)
+ h = counts // 2
+ # create indexing mesh grid for all but reduced axis
+ axes_grid = [np.arange(x) for i, x in enumerate(asorted.shape)
+ if i != axis]
+ ind = np.meshgrid(*axes_grid, sparse=True, indexing='ij')
+ # insert indices of low and high median
+ ind.insert(axis, h - 1)
+ low = asorted[ind]
+ ind[axis] = h
+ high = asorted[ind]
+ # duplicate high if odd number of elements so mean does nothing
+ odd = counts % 2 == 1
+ if asorted.ndim == 1:
+ if odd:
+ low = high
else:
- result = apply_along_axis(_median1D, axis, asorted)
- if out is not None:
- out = result
- return result
-
-
+ low[odd] = high[odd]
+ return np.ma.mean([low, high], axis=0, out=out)
#..............................................................................
@@ -842,9 +878,9 @@ def mask_rowcols(a, axis=None):
fill_value=999999)
"""
- a = asarray(a)
+ a = array(a, subok=False)
if a.ndim != 2:
- raise NotImplementedError("compress2d works for 2D arrays only.")
+ raise NotImplementedError("mask_rowcols works for 2D arrays only.")
m = getmask(a)
# Nothing is masked: return a
if m is nomask or not m.any():
@@ -1735,7 +1771,7 @@ def _ezclump(mask):
#def clump_masked(a):
if mask.ndim > 1:
mask = mask.ravel()
- idx = (mask[1:] - mask[:-1]).nonzero()
+ idx = (mask[1:] ^ mask[:-1]).nonzero()
idx = idx[0] + 1
slices = [slice(left, right)
for (left, right) in zip(itertools.chain([0], idx),
diff --git a/numpy/ma/mrecords.py b/numpy/ma/mrecords.py
index a2380d813..e66596509 100644
--- a/numpy/ma/mrecords.py
+++ b/numpy/ma/mrecords.py
@@ -426,8 +426,8 @@ The fieldname base is either `_data` or `_mask`."""
self.shape,
self.dtype,
self.flags.fnc,
- self._data.tostring(),
- self._mask.tostring(),
+ self._data.tobytes(),
+ self._mask.tobytes(),
self._fill_value,
)
return state
diff --git a/numpy/ma/tests/test_core.py b/numpy/ma/tests/test_core.py
index 764915236..8172335a8 100644
--- a/numpy/ma/tests/test_core.py
+++ b/numpy/ma/tests/test_core.py
@@ -13,6 +13,8 @@ import sys
import pickle
from functools import reduce
+from nose.tools import assert_raises
+
import numpy as np
import numpy.ma.core
import numpy.core.fromnumeric as fromnumeric
@@ -192,8 +194,7 @@ class TestMaskedArray(TestCase):
def test_fix_invalid(self):
# Checks fix_invalid.
- with np.errstate():
- np.seterr(invalid='ignore')
+ with np.errstate(invalid='ignore'):
data = masked_array([np.nan, 0., 1.], mask=[0, 0, 1])
data_fixed = fix_invalid(data)
assert_equal(data_fixed._data, [data.fill_value, 0., 1.])
@@ -354,6 +355,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)
@@ -474,6 +482,10 @@ class TestMaskedArray(TestCase):
atest[idx] = btest[idx]
assert_equal(atest, [20])
+ def test_filled_w_object_dtype(self):
+ a = np.ma.masked_all(1, dtype='O')
+ assert_equal(a.filled('x')[0], 'x')
+
def test_filled_w_flexible_dtype(self):
# Test filled w/ flexible dtype
flexi = array([(1, 1, 1)],
@@ -795,23 +807,29 @@ class TestMaskedArrayArithmetic(TestCase):
def test_count_func(self):
# Tests count
- ott = array([0., 1., 2., 3.], mask=[1, 0, 0, 0])
- if sys.version_info[0] >= 3:
- self.assertTrue(isinstance(count(ott), np.integer))
- else:
- self.assertTrue(isinstance(count(ott), int))
- assert_equal(3, count(ott))
assert_equal(1, count(1))
assert_equal(0, array(1, mask=[1]))
+
+ ott = array([0., 1., 2., 3.], mask=[1, 0, 0, 0])
+ res = count(ott)
+ self.assertTrue(res.dtype.type is np.intp)
+ assert_equal(3, res)
+
ott = ott.reshape((2, 2))
- assert_(isinstance(count(ott, 0), ndarray))
- if sys.version_info[0] >= 3:
- assert_(isinstance(count(ott), np.integer))
- else:
- assert_(isinstance(count(ott), int))
- assert_equal(3, count(ott))
- assert_(getmask(count(ott, 0)) is nomask)
- assert_equal([1, 2], count(ott, 0))
+ res = count(ott)
+ assert_(res.dtype.type is np.intp)
+ assert_equal(3, res)
+ res = count(ott, 0)
+ assert_(isinstance(res, ndarray))
+ assert_equal([1, 2], res)
+ assert_(getmask(res) is nomask)
+
+ ott= array([0., 1., 2., 3.])
+ res = count(ott, 0)
+ assert_(isinstance(res, ndarray))
+ assert_(res.dtype.type is np.intp)
+
+ assert_raises(IndexError, ott.count, 1)
def test_minmax_func(self):
# Tests minimum and maximum.
@@ -1275,23 +1293,64 @@ 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]]))
#------------------------------------------------------------------------------
class TestFillingValues(TestCase):
- #
+
def test_check_on_scalar(self):
- # Test _check_fill_value
+ # Test _check_fill_value set to valid and invalid values
_check_fill_value = np.ma.core._check_fill_value
#
fval = _check_fill_value(0, int)
@@ -1303,9 +1362,8 @@ class TestFillingValues(TestCase):
assert_equal(fval, asbytes("0"))
fval = _check_fill_value(None, "|S3")
assert_equal(fval, default_fill_value("|S3"))
- #
- fval = _check_fill_value(1e+20, int)
- assert_equal(fval, default_fill_value(0))
+ self.assertRaises(TypeError, _check_fill_value, 1e+20, int)
+ self.assertRaises(TypeError, _check_fill_value, 'stuff', int)
def test_check_on_fields(self):
# Tests _check_fill_value with records
@@ -1991,6 +2049,10 @@ class TestMaskedArrayMethods(TestCase):
a[0] = 0
self.assertTrue(allclose(a, 0, masked_equal=True))
+ # Test that the function works for MIN_INT integer typed arrays
+ a = masked_array([np.iinfo(np.int_).min], dtype=np.int_)
+ self.assertTrue(allclose(a, a))
+
def test_allany(self):
# Checks the any/all methods/functions.
x = np.array([[0.13, 0.26, 0.90],
@@ -3571,6 +3633,45 @@ def test_masked_array():
a = np.ma.array([0, 1, 2, 3], mask=[0, 0, 1, 0])
assert_equal(np.argwhere(a), [[1], [3]])
+def test_append_masked_array():
+ a = np.ma.masked_equal([1,2,3], value=2)
+ b = np.ma.masked_equal([4,3,2], value=2)
+
+ result = np.ma.append(a, b)
+ expected_data = [1, 2, 3, 4, 3, 2]
+ expected_mask = [False, True, False, False, False, True]
+ assert_array_equal(result.data, expected_data)
+ assert_array_equal(result.mask, expected_mask)
+
+ a = np.ma.masked_all((2,2))
+ b = np.ma.ones((3,1))
+
+ result = np.ma.append(a, b)
+ expected_data = [1] * 3
+ expected_mask = [True] * 4 + [False] * 3
+ assert_array_equal(result.data[-3], expected_data)
+ assert_array_equal(result.mask, expected_mask)
+
+ result = np.ma.append(a, b, axis=None)
+ assert_array_equal(result.data[-3], expected_data)
+ assert_array_equal(result.mask, expected_mask)
+
+
+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)
+
+ result = np.ma.append(a[np.newaxis,:], b, axis=0)
+ expected = np.ma.arange(1, 10)
+ expected[[1, 6]] = np.ma.masked
+ expected = expected.reshape((3,3))
+ assert_array_equal(result.data, expected.data)
+ assert_array_equal(result.mask, expected.mask)
+
+
###############################################################################
if __name__ == "__main__":
run_module_suite()
diff --git a/numpy/ma/tests/test_extras.py b/numpy/ma/tests/test_extras.py
index dc0f87b92..6ce1dc346 100644
--- a/numpy/ma/tests/test_extras.py
+++ b/numpy/ma/tests/test_extras.py
@@ -479,6 +479,16 @@ class TestApplyAlongAxis(TestCase):
xa = apply_along_axis(myfunc, 2, a)
assert_equal(xa, [[1, 4], [7, 10]])
+ # Tests kwargs functions
+ def test_3d_kwargs(self):
+ a = arange(12).reshape(2, 2, 3)
+
+ def myfunc(b, offset=0):
+ return b[1+offset]
+
+ xa = apply_along_axis(myfunc, 2, a, offset=1)
+ assert_equal(xa, [[2, 5], [8, 11]])
+
class TestApplyOverAxes(TestCase):
# Tests apply_over_axes
@@ -489,7 +499,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):
@@ -530,6 +541,19 @@ class TestMedian(TestCase):
x[x % 5 == 0] = masked
assert_equal(median(x, 0), [[12, 10], [8, 9], [16, 17]])
+ def test_neg_axis(self):
+ x = masked_array(np.arange(30).reshape(10, 3))
+ x[:3] = x[-3:] = masked
+ assert_equal(median(x, axis=-1), median(x, axis=1))
+
+ def test_out(self):
+ x = masked_array(np.arange(30).reshape(10, 3))
+ x[:3] = x[-3:] = masked
+ out = masked_array(np.ones(10))
+ r = median(x, axis=1, out=out)
+ assert_equal(r, out)
+ assert_(type(r) == MaskedArray)
+
class TestCov(TestCase):
diff --git a/numpy/ma/tests/test_old_ma.py b/numpy/ma/tests/test_old_ma.py
index 27d699385..047f91c77 100644
--- a/numpy/ma/tests/test_old_ma.py
+++ b/numpy/ma/tests/test_old_ma.py
@@ -153,19 +153,14 @@ class TestMa(TestCase):
def test_xtestCount(self):
# Test count
ott = array([0., 1., 2., 3.], mask=[1, 0, 0, 0])
- if sys.version_info[0] >= 3:
- self.assertTrue(isinstance(count(ott), np.integer))
- else:
- self.assertTrue(isinstance(count(ott), int))
+ self.assertTrue(count(ott).dtype.type is np.intp)
self.assertEqual(3, count(ott))
self.assertEqual(1, count(1))
self.assertTrue(eq(0, array(1, mask=[1])))
ott = ott.reshape((2, 2))
+ self.assertTrue(count(ott).dtype.type is np.intp)
assert_(isinstance(count(ott, 0), np.ndarray))
- if sys.version_info[0] >= 3:
- assert_(isinstance(count(ott), np.integer))
- else:
- assert_(isinstance(count(ott), int))
+ self.assertTrue(count(ott).dtype.type is np.intp)
self.assertTrue(eq(3, count(ott)))
assert_(getmask(count(ott, 0)) is nomask)
self.assertTrue(eq([1, 2], count(ott, 0)))
@@ -612,8 +607,7 @@ class TestMa(TestCase):
def test_testScalarArithmetic(self):
xm = array(0, mask=1)
#TODO FIXME: Find out what the following raises a warning in r8247
- with np.errstate():
- np.seterr(divide='ignore')
+ with np.errstate(divide='ignore'):
self.assertTrue((1 / array(0)).mask)
self.assertTrue((1 + xm).mask)
self.assertTrue((-xm).mask)
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__':