summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpierregm <pierregm@localhost>2009-12-17 21:15:05 +0000
committerpierregm <pierregm@localhost>2009-12-17 21:15:05 +0000
commitf6f1c821fb5bbe83da52e917ccfd66adfd13dc92 (patch)
treed74f9e7b66ead7e93707dd2db718400f3255f673
parent6938cc09cfa9fa94448132cd48ae4257ccaddc17 (diff)
downloadnumpy-f6f1c821fb5bbe83da52e917ccfd66adfd13dc92.tar.gz
* added log2
* removed the global np.seterr * prevented warnings to be emitted with ma.ufuncs * introduced mvoid to help the iteration/item access of masked structured arrays
-rw-r--r--numpy/ma/core.py245
-rw-r--r--numpy/ma/tests/test_core.py40
2 files changed, 207 insertions, 78 deletions
diff --git a/numpy/ma/core.py b/numpy/ma/core.py
index 506749ba3..7c59593fb 100644
--- a/numpy/ma/core.py
+++ b/numpy/ma/core.py
@@ -65,8 +65,8 @@ __all__ = ['MAError', 'MaskError', 'MaskType', 'MaskedArray',
'harden_mask', 'hypot',
'identity', 'ids', 'indices', 'inner', 'innerproduct',
'isMA', 'isMaskedArray', 'is_mask', 'is_masked', 'isarray',
- 'left_shift', 'less', 'less_equal', 'load', 'loads', 'log', 'log10',
- 'logical_and', 'logical_not', 'logical_or', 'logical_xor',
+ 'left_shift', 'less', 'less_equal', 'load', 'loads', 'log', 'log2',
+ 'log10', 'logical_and', 'logical_not', 'logical_or', 'logical_xor',
'make_mask', 'make_mask_descr', 'make_mask_none', 'mask_or',
'masked', 'masked_array', 'masked_equal', 'masked_greater',
'masked_greater_equal', 'masked_inside', 'masked_invalid',
@@ -74,7 +74,7 @@ __all__ = ['MAError', 'MaskError', 'MaskType', 'MaskedArray',
'masked_object', 'masked_outside', 'masked_print_option',
'masked_singleton', 'masked_values', 'masked_where', 'max', 'maximum',
'maximum_fill_value', 'mean', 'min', 'minimum', 'minimum_fill_value',
- 'mod', 'multiply',
+ 'mod', 'multiply', 'mvoid',
'negative', 'nomask', 'nonzero', 'not_equal',
'ones', 'outer', 'outerproduct',
'power', 'prod', 'product', 'ptp', 'put', 'putmask',
@@ -843,11 +843,11 @@ class _MaskedUnaryOperation:
if self.domain is not None:
# Save the error status
err_status_ini = np.geterr()
- np.seterr(divide='ignore', invalid='ignore')
- # Get the result
- result = self.f(d, *args, **kwargs)
- # Reset the error status
- np.seterr(**err_status_ini)
+ try:
+ np.seterr(divide='ignore', invalid='ignore')
+ result = self.f(d, *args, **kwargs)
+ finally:
+ np.seterr(**err_status_ini)
# Make a mask
m = ~umath.isfinite(result)
m |= self.domain(d)
@@ -934,7 +934,12 @@ class _MaskedBinaryOperation:
else:
m = umath.logical_or(ma, mb)
# Get the result
- result = self.f(da, db, *args, **kwargs)
+ err_status_ini = np.geterr()
+ try:
+ np.seterr(divide='ignore', invalid='ignore')
+ result = self.f(da, db, *args, **kwargs)
+ finally:
+ np.seterr(**err_status_ini)
# Case 1. : scalar
if not result.ndim:
if m:
@@ -1068,7 +1073,12 @@ class _DomainedBinaryOperation:
err_status_ini = np.geterr()
np.seterr(divide='ignore', invalid='ignore')
# Get the result
- result = self.f(da, db, *args, **kwargs)
+ err_status_ini = np.geterr()
+ try:
+ np.seterr(divide='ignore', invalid='ignore')
+ result = self.f(da, db, *args, **kwargs)
+ finally:
+ np.seterr(**err_status_ini)
# Reset the error status
np.seterr(**err_status_ini)
# Get the mask as a combination of ma, mb and invalid
@@ -1122,6 +1132,8 @@ sqrt = _MaskedUnaryOperation(umath.sqrt, 0.0,
_DomainGreaterEqual(0.0))
log = _MaskedUnaryOperation(umath.log, 1.0,
_DomainGreater(0.0))
+log2 = _MaskedUnaryOperation(umath.log2, 1.0,
+ _DomainGreater(0.0))
log10 = _MaskedUnaryOperation(umath.log10, 1.0,
_DomainGreater(0.0))
tan = _MaskedUnaryOperation(umath.tan, 0.0,
@@ -2331,7 +2343,62 @@ def _recursive_filled(a, mask, fill_value):
else:
np.putmask(current, mask[name], fill_value[name])
-#...............................................................................
+
+
+def flatten_structured_array(a):
+ """
+ Flatten a structured array.
+
+ The data type of the output is chosen such that it can represent all of the
+ (nested) fields.
+
+ Parameters
+ ----------
+ a : structured array
+
+ Returns
+ -------
+ output : masked array or ndarray
+ A flattened masked array if the input is a masked array, otherwise a
+ standard ndarray.
+
+ Examples
+ --------
+ >>> ndtype = [('a', int), ('b', float)]
+ >>> a = np.array([(1, 1), (2, 2)], dtype=ndtype)
+ >>> flatten_structured_array(a)
+ array([[1., 1.],
+ [2., 2.]])
+
+ """
+ #
+ def flatten_sequence(iterable):
+ """Flattens a compound of nested iterables."""
+ for elm in iter(iterable):
+ if hasattr(elm, '__iter__'):
+ for f in flatten_sequence(elm):
+ yield f
+ else:
+ yield elm
+ #
+ a = np.asanyarray(a)
+ inishape = a.shape
+ a = a.ravel()
+ if isinstance(a, MaskedArray):
+ out = np.array([tuple(flatten_sequence(d.item())) for d in a._data])
+ out = out.view(MaskedArray)
+ out._mask = np.array([tuple(flatten_sequence(d.item()))
+ for d in getmaskarray(a)])
+ else:
+ out = np.array([tuple(flatten_sequence(d.item())) for d in a])
+ if len(inishape) > 1:
+ newshape = list(out.shape)
+ newshape[0] = inishape
+ out.shape = tuple(flatten_sequence(newshape))
+ return out
+
+
+
class _arraymethod(object):
"""
Define a wrapper for basic array methods.
@@ -2399,7 +2466,8 @@ class _arraymethod(object):
if mask.ndim and (not mask.dtype.names and mask.all()):
return masked
return result
-#..........................................................
+
+
class MaskedIterator(object):
"""
@@ -2503,59 +2571,6 @@ class MaskedIterator(object):
return d
-def flatten_structured_array(a):
- """
- Flatten a structured array.
-
- The data type of the output is chosen such that it can represent all of the
- (nested) fields.
-
- Parameters
- ----------
- a : structured array
-
- Returns
- -------
- output : masked array or ndarray
- A flattened masked array if the input is a masked array, otherwise a
- standard ndarray.
-
- Examples
- --------
- >>> ndtype = [('a', int), ('b', float)]
- >>> a = np.array([(1, 1), (2, 2)], dtype=ndtype)
- >>> flatten_structured_array(a)
- array([[1., 1.],
- [2., 2.]])
-
- """
- #
- def flatten_sequence(iterable):
- """Flattens a compound of nested iterables."""
- for elm in iter(iterable):
- if hasattr(elm, '__iter__'):
- for f in flatten_sequence(elm):
- yield f
- else:
- yield elm
- #
- a = np.asanyarray(a)
- inishape = a.shape
- a = a.ravel()
- if isinstance(a, MaskedArray):
- out = np.array([tuple(flatten_sequence(d.item())) for d in a._data])
- out = out.view(MaskedArray)
- out._mask = np.array([tuple(flatten_sequence(d.item()))
- for d in getmaskarray(a)])
- else:
- out = np.array([tuple(flatten_sequence(d.item())) for d in a])
- if len(inishape) > 1:
- newshape = list(out.shape)
- newshape[0] = inishape
- out.shape = tuple(flatten_sequence(newshape))
- return out
-
-
class MaskedArray(ndarray):
@@ -2762,7 +2777,8 @@ class MaskedArray(ndarray):
self.__dict__.update(_dict)
self.__dict__.update(_optinfo)
return
- #........................
+
+
def __array_finalize__(self, obj):
"""Finalizes the masked array.
"""
@@ -2783,8 +2799,16 @@ class MaskedArray(ndarray):
self._mask.shape = self.shape
except ValueError:
self._mask = nomask
+ except AttributeError:
+ # When _mask.shape is not writable (because it's a void)
+ pass
return
- #..................................
+
+
+# def __array_prepare__(self, obj, context=None):
+# print "DEBUG: __array_prepare__ on obj", obj, " with context:", context
+
+
def __array_wrap__(self, obj, context=None):
"""
Special hook for ufuncs.
@@ -2832,7 +2856,8 @@ class MaskedArray(ndarray):
result._sharedmask = False
#....
return result
- #.............................................
+
+
def view(self, dtype=None, type=None):
if dtype is None:
if type is None:
@@ -2855,15 +2880,19 @@ class MaskedArray(ndarray):
if dtype is None:
dtype = output.dtype
mdtype = make_mask_descr(dtype)
-
output._mask = self._mask.view(mdtype, ndarray)
- output._mask.shape = output.shape
+ # Try to reset the shape of the mask (if we don't have a void)
+ try:
+ output._mask.shape = output.shape
+ except AttributeError:
+ pass
# Make sure to reset the _fill_value if needed
if getattr(output, '_fill_value', None):
output._fill_value = None
return output
view.__doc__ = ndarray.view.__doc__
- #.............................................
+
+
def astype(self, newtype):
"""
Returns a copy of the MaskedArray cast to given newtype.
@@ -2902,7 +2931,8 @@ class MaskedArray(ndarray):
if self._fill_value is not None:
output._fill_value = _check_fill_value(self._fill_value, newtype)
return output
- #.............................................
+
+
def __getitem__(self, indx):
"""x.__getitem__(y) <==> x[y]
@@ -2913,7 +2943,8 @@ class MaskedArray(ndarray):
# if getmask(indx) is not nomask:
# msg = "Masked arrays must be filled before they can be used as indices!"
# raise IndexError, msg
- dout = ndarray.__getitem__(ndarray.view(self, ndarray), indx)
+ _data = ndarray.view(self, ndarray)
+ dout = ndarray.__getitem__(_data, indx)
# We could directly use ndarray.__getitem__ on self...
# But then we would have to modify __array_finalize__ to prevent the
# mask of being reshaped if it hasn't been set up properly yet...
@@ -2924,7 +2955,7 @@ class MaskedArray(ndarray):
if isinstance(dout, np.void):
mask = _mask[indx]
if flatten_mask(mask).any():
- dout = masked_array(dout, mask=mask)
+ dout = mvoid(dout, mask=mask)
else:
return dout
# Just a scalar............
@@ -2946,7 +2977,7 @@ class MaskedArray(ndarray):
dout._sharedmask = True
# Note: Don't try to check for m.any(), that'll take too long...
return dout
- #........................
+
def __setitem__(self, indx, value):
"""x.__setitem__(i, y) <==> x[i]=y
@@ -3033,7 +3064,6 @@ class MaskedArray(ndarray):
"""
return self.__getitem__(slice(i, j))
-
def __setslice__(self, i, j, value):
"""x.__setslice__(i, j, value) <==> x[i:j]=value
@@ -3728,7 +3758,8 @@ class MaskedArray(ndarray):
elif self._mask:
raise MaskError, 'Cannot convert masked element to a Python int.'
return int(self.item())
- #............................................
+
+
def get_imag(self):
"""
Return the imaginary part of the masked array.
@@ -5400,6 +5431,66 @@ def _mareconstruct(subtype, baseclass, baseshape, basetype,):
return subtype.__new__(subtype, _data, mask=_mask, dtype=basetype,)
+
+
+
+
+class mvoid(MaskedArray):
+ """
+ Fake a 'void' object to use for masked array with structured dtypes.
+ """
+ #
+ def __new__(self, data, mask=nomask):
+ _data = ndarray.__new__(self, (), dtype=data.dtype, buffer=data.data)
+# _data = _data.view(self)
+# self = MaskedArray.__new__(self, np.void(data), mask=nomask)
+ if mask is not nomask:
+ _data._mask = np.void(mask)
+ return _data
+ #
+ def _get_data(self):
+ # Make sure that the _data part is a np.void
+ return self.view(ndarray).reshape(1)[0]
+ _data = property(fget=_get_data)
+ #
+ def __getitem__(self, indx):
+ "Get the index..."
+ _mask = self._mask.astype(np.void)
+ if _mask is not nomask and _mask[indx]:
+ return masked
+ return self._data[indx]
+ #
+ def __str__(self):
+ m = self._mask
+ if (m is nomask):
+ return self._data.__str__()
+ m = tuple(m)
+ if (not any(m)):
+ return self._data.__repr__()
+ r = self._data.tolist()
+ p = masked_print_option
+ if not p.enabled():
+ p = 'N/A'
+ else:
+ p = str(p)
+ r = [(str(_), p)[_m] for (_, _m) in zip(self._data.tolist(), tuple(m))]
+ return "(%s)" % ", ".join(r)
+
+ __repr__ = __str__
+
+ def __iter__(self):
+ (_data, _mask) = (self._data, self._mask)
+ if _mask is nomask:
+ for d in _data:
+ yield d
+ else:
+ for (d, m) in zip(_data, _mask):
+ if m:
+ yield masked
+ else:
+ yield d
+
+
#####--------------------------------------------------------------------------
#---- --- Shortcuts ---
#####---------------------------------------------------------------------------
diff --git a/numpy/ma/tests/test_core.py b/numpy/ma/tests/test_core.py
index 541c34589..1549ef3c9 100644
--- a/numpy/ma/tests/test_core.py
+++ b/numpy/ma/tests/test_core.py
@@ -62,7 +62,6 @@ class TestMaskedArray(TestCase):
x = array(0, mask=1)
self.failUnless(x.filled().dtype is x._data.dtype)
-
def test_basic1d(self):
"Test of basic array creation and properties in 1 dimension."
(x, y, a10, m1, m2, xm, ym, z, zm, xf) = self.d
@@ -565,6 +564,45 @@ class TestMaskedArray(TestCase):
+ def test_void0d(self):
+ "Test creating a mvoid object"
+ ndtype = [('a', int), ('b', int)]
+ a = np.array([(1, 2,)], dtype=ndtype)[0]
+ f = mvoid(a)
+ assert(isinstance(f, mvoid))
+ #
+ a = masked_array([(1, 2)], mask=[(1, 0)], dtype=ndtype)[0]
+ assert(isinstance(a, mvoid))
+ #
+ a = masked_array([(1, 2), (1, 2)], mask=[(1, 0), (0, 0)], dtype=ndtype)
+ f = mvoid(a._data[0], a._mask[0])
+ assert(isinstance(f, mvoid))
+
+ def test_mvoid_getitem(self):
+ "Test mvoid.__getitem__"
+ ndtype = [('a', int), ('b', int)]
+ a = masked_array([(1, 2,), (3, 4)], mask=[(0, 0), (1, 0)], dtype=ndtype)
+ # w/o mask
+ f = a[0]
+ self.failUnless(isinstance(f, np.void))
+ assert_equal((f[0], f['a']), (1, 1))
+ assert_equal(f['b'], 2)
+ # w/ mask
+ f = a[1]
+ self.failUnless(isinstance(f, mvoid))
+ self.failUnless(f[0] is masked)
+ self.failUnless(f['a'] is masked)
+ assert_equal(f[1], 4)
+
+ def test_mvoid_iter(self):
+ "Test iteration on __getitem__"
+ ndtype = [('a', int), ('b', int)]
+ a = masked_array([(1, 2,), (3, 4)], mask=[(0, 0), (1, 0)], dtype=ndtype)
+ # w/o mask
+ assert_equal(list(a[0]), [1, 2])
+ # w/ mask
+ assert_equal(list(a[1]), [masked, 4])
+
#------------------------------------------------------------------------------