All,
Here's a patch to the current version of svn/numpy/branches/maskedarray, that
corrects several bugs.
I tried to commit it to the server itself, but I unfortunately lost my
password (or maybe I never had a password for numpy branches in the first
place). Could anybody in charge of the SVN contact me offlist ? Thanks an
awful lot in advance.
The revision info is below.
Sorry for the noise, and thanks again.
P.
fix_invalid : change the default to copy=True
_MaskedUnaryOperation : make sure the result gets updated from the input
(for subclasses)
_MaskedBinaryOperation : make sure the result gets updated from the inputs
(for subclasses)
_DomainedBinaryOperation : make sure the result gets updated from the inputs
(for subclasses)
MaskedArray.__new__ : added the ndmin keyword
MaskedArray.__getitem__ : works with fields, using the global mask
MaskedArray.__setitem__ : works with fields. The global mask is NOT updated
MaskedArray.ids : fixed when nomask
MaskedArray.min/.max : force masked to be returned when the whole array is
masked
array : added the ndmin keyword
Index: /home/backtopop/workspace/svn_maskedarray/numpy/ma/core.py
===================================================================
--- /home/backtopop/workspace/svn_maskedarray/numpy/ma/core.py (revision 4673)
+++ /home/backtopop/workspace/svn_maskedarray/numpy/ma/core.py (working copy)
@@ -14,12 +14,12 @@
:author: Pierre Gerard-Marchant
:contact: pierregm_at_uga_dot_edu
-:version: $Id: core.py 3639 2007-12-13 03:39:17Z pierregm $
+:version: $Id: core.py 341 2007-12-25 16:23:05Z backtopop $
"""
-__author__ = "Pierre GF Gerard-Marchant ($Author: pierregm $)"
+__author__ = "Pierre GF Gerard-Marchant ($Author: backtopop $)"
__version__ = '1.0'
-__revision__ = "$Revision: 3639 $"
-__date__ = '$Date: 2007-12-13 05:39:17 +0200 (Thu, 13 Dec 2007) $'
+__revision__ = "$Revision: 341 $"
+__date__ = '$Date: 2007-12-25 11:23:05 -0500 (Tue, 25 Dec 2007) $'
__docformat__ = "restructuredtext en"
@@ -76,27 +76,16 @@
from numpy import array as narray
import warnings
-class NoMask(ndarray):
- def __new__(subtype):
- narray(False)
- return narray(False).view(subtype)
- def no_op(self,*args,**kwargs):
- return self
-
- def __array_finalize__(self,obj):
- obj.flags['WRITEABLE'] = False
-
- def copy(self):
- return self
-
MaskType = bool_
-nomask = NoMask()
+nomask = MaskType(0)
+#nomask = narray(False)
divide_tolerance = 1.e-35
numpy.seterr(all='ignore')
+
#####--------------------------------------------------------------------------
#---- --- Exceptions ---
#####--------------------------------------------------------------------------
@@ -417,8 +406,10 @@
#
def __call__ (self, a, *args, **kwargs):
"Execute the call behavior."
+ #
m = getmask(a)
d1 = get_data(a)
+ #
if self.domain is not None:
dm = narray(self.domain(d1), copy=False)
m = numpy.logical_or(m, dm)
@@ -429,14 +420,17 @@
# Take care of the masked singletong first ...
if not m.ndim and m:
return masked
- # Get the result..............................
+ # Get the result class .......................
if isinstance(a, MaskedArray):
- result = self.f(d1, *args, **kwargs).view(type(a))
+ subtype = type(a)
else:
- result = self.f(d1, *args, **kwargs).view(MaskedArray)
+ subtype = MaskedArray
+ # Get the result as a view of the subtype ...
+ result = self.f(d1, *args, **kwargs).view(subtype)
# Fix the mask if we don't have a scalar
if result.ndim > 0:
result._mask = m
+ result._update_from(a)
return result
#
def __str__ (self):
@@ -475,6 +469,10 @@
if m is not nomask:
result._mask = make_mask_none(result.shape)
result._mask.flat = m
+ if isinstance(a,MaskedArray):
+ result._update_from(a)
+ if isinstance(b,MaskedArray):
+ result._update_from(b)
elif m:
return masked
return result
@@ -586,6 +584,10 @@
result = self.f(d1, d2).view(get_masked_subclass(a,b))
if result.ndim > 0:
result._mask = m
+ if isinstance(a,MaskedArray):
+ result._update_from(a)
+ if isinstance(b,MaskedArray):
+ result._update_from(b)
return result
def __str__ (self):
@@ -1020,7 +1022,6 @@
cls = type(self.obj)
result = getattr(data, methodname)(*args, **params).view(cls)
result._update_from(self.obj)
- #result._shrinkmask = self.obj._shrinkmask
if result.ndim:
if not self._onmask:
result.__setmask__(mask)
@@ -1064,7 +1065,7 @@
Construction:
x = MaskedArray(data, mask=nomask, dtype=None, copy=True,
- fill_value=None, mask = nomask, fill_value=None, shrink=True)
+ fill_value=None, keep_mask = True, hard_mask=False, shrink=True)
*Parameters*:
data : {var}
@@ -1080,6 +1081,11 @@
copy : {boolean}
Whether to copy the input data (True), or to use a
reference instead. Note: data are NOT copied by default.
+ subok : {True, boolean}
+ Whether to return a subclass of MaskedArray (if possible)
+ or a plain MaskedArray.
+ ndmin : {0, int}
+ Minimum number of dimensions
fill_value : {var}
Value used to fill in the masked values when necessary. If
None, a default based on the datatype is used.
@@ -1089,9 +1095,9 @@
hard_mask : {False, boolean}
Whether to use a hard mask or not. With a hard mask,
masked values cannot be unmasked.
- subok : {True, boolean}
- Whether or not to return a subclass of MaskedArray (if
- possible) or a plain MaskedArray.
+ shrink : {True, boolean}
+ Whether to force compression of an empty mask.
+
"""
@@ -1101,8 +1107,9 @@
_baseclass = numeric.ndarray
def __new__(cls, data=None, mask=nomask, dtype=None, copy=False,
- fill_value=None, keep_mask=True, hard_mask=False, flag=None,
- subok=True, **options):
+ subok=True, ndmin=0, fill_value=None,
+ keep_mask=True, hard_mask=False, flag=None,shrink=True,
+ **options):
"""Create a new masked array from scratch.
Note: you can also create an array with the .view(MaskedArray)
@@ -1114,7 +1121,7 @@
DeprecationWarning)
shrink = flag
# Process data............
- _data = narray(data, dtype=dtype, copy=copy, subok=True)
+ _data = narray(data, dtype=dtype, copy=copy, subok=True, ndmin=ndmin)
_baseclass = getattr(data, '_baseclass', type(_data))
_basedict = getattr(data, '_basedict', getattr(data, '__dict__', None))
if not isinstance(data, MaskedArray) or not subok:
@@ -1128,7 +1135,10 @@
# Process mask ...........
if mask is nomask:
if not keep_mask:
- _data._mask = nomask
+ if shrink:
+ _data._mask = nomask
+ else:
+ _data._mask = make_mask_none(_data)
if copy:
_data._mask = _data._mask.copy()
_data._sharedmask = False
@@ -1183,7 +1193,7 @@
return
#........................
def __array_finalize__(self,obj):
- """Finalize the masked array.
+ """Finalizes the masked array.
"""
# Get main attributes .........
self._mask = getattr(obj, '_mask', nomask)
@@ -1195,7 +1205,6 @@
# Finalize the mask ...........
if self._mask is not nomask:
self._mask.shape = self.shape
-# self._data = self.view(self._baseclass)
return
#..................................
def __array_wrap__(self, obj, context=None):
@@ -1266,7 +1275,10 @@
dout._update_from(self)
# Update the mask if needed
if m is not nomask:
- dout._mask = ndarray.__getitem__(m, indx).reshape(dout.shape)
+ if isinstance(indx, basestring):
+ dout._mask = m.reshape(dout.shape)
+ else:
+ dout._mask = ndarray.__getitem__(m, indx).reshape(dout.shape)
# Note: Don't try to check for m.any(), that'll take too long...
# mask = ndarray.__getitem__(m, indx).reshape(dout.shape)
# if self._shrinkmask and not m.any():
@@ -1287,6 +1299,10 @@
# if getmask(indx) is not nomask:
# msg = "Masked arrays must be filled before they can be used as indices!"
# raise IndexError, msg
+ if isinstance(indx, basestring):
+ ndarray.__setitem__(self._data,indx, getdata(value))
+ warnings.warn("The mask is NOT affected!")
+ return
#....
if value is masked:
m = self._mask
@@ -1794,6 +1810,8 @@
#............................................
def ids (self):
"""Return the addresses of the data and mask areas."""
+ if self._mask is nomask:
+ return (self.ctypes.data, id(nomask))
return (self.ctypes.data, self._mask.ctypes.data)
#............................................
def all(self, axis=None, out=None):
@@ -2282,7 +2300,10 @@
mask = umath.logical_and.reduce(mask.flat)
else:
mask = umath.logical_and.reduce(mask, axis=axis)
- # Get the fil value ...........
+ # Skip if all masked ..........
+ if not mask.ndim and mask:
+ return masked
+ # Get the fill value ...........
if fill_value is None:
fill_value = minimum_fill_value(self)
# Get the data ................
@@ -2290,6 +2311,13 @@
if result.ndim > 0:
result._mask = mask
return result
+
+ def mini(self, axis=None):
+ if axis is None:
+ return minimum(self)
+ else:
+ return minimum.reduce(self, axis)
+
#........................
def max(self, axis=None, fill_value=None):
"""Return the maximum/a along the given axis.
@@ -2315,6 +2343,9 @@
mask = umath.logical_and.reduce(mask.flat)
else:
mask = umath.logical_and.reduce(mask, axis=axis)
+ # Skip if all masked ..........
+ if not mask.ndim and mask:
+ return masked
# Get the fill value ..........
if fill_value is None:
fill_value = maximum_fill_value(self)
@@ -2469,10 +2500,13 @@
masked_array = MaskedArray
-def array(data, dtype=None, copy=False, order=False, mask=nomask, subok=True,
- keep_mask=True, hard_mask=False, fill_value=None, shrink=True):
- """array(data, dtype=None, copy=True, order=False, mask=nomask,
- keep_mask=True, shrink=True, fill_value=None)
+def array(data, dtype=None, copy=False, order=False,
+ mask=nomask, fill_value=None,
+ keep_mask=True, hard_mask=False, shrink=True, subok=True, ndmin=0,
+ ):
+ """array(data, dtype=None, copy=False, order=False, mask=nomask,
+ fill_value=None, keep_mask=True, hard_mask=False, shrink=True,
+ subok=True, ndmin=0)
Acts as shortcut to MaskedArray, with options in a different order
for convenience. And backwards compatibility...
@@ -2481,7 +2515,7 @@
#TODO: we should try to put 'order' somwehere
return MaskedArray(data, mask=mask, dtype=dtype, copy=copy, subok=subok,
keep_mask=keep_mask, hard_mask=hard_mask,
- fill_value=fill_value)
+ fill_value=fill_value, ndmin=ndmin, shrink=shrink)
array.__doc__ = masked_array.__doc__
def is_masked(x):
@@ -2745,8 +2779,9 @@
return data
# OK, so we have to concatenate the masks
dm = numpy.concatenate([getmaskarray(a) for a in arrays], axis)
- shrink = numpy.logical_or.reduce([getattr(a,'_shrinkmask',True) for a in arrays])
- if shrink and not dm.any():
+# shrink = numpy.logical_or.reduce([getattr(a,'_shrinkmask',True) for a in arrays])
+# if shrink and not dm.any():
+ if not dm.any():
data._mask = nomask
else:
data._mask = dm.reshape(d.shape)
@@ -3188,33 +3223,32 @@
from maskedarray.testutils import assert_equal, assert_almost_equal
if 1:
- x = array([1,2,3,4,5,6])
- mx = array(x, mask=[0,0,0,1,1,1])
- mask = [0,0,1,0,0,1]
+ x = array(numpy.arange(12))
+ x[[1,-2]] = masked
+ xlist = x.tolist()
+ assert(xlist[1] is None)
+ assert(xlist[-2] is None)
+ #
+ x.shape = (3,4)
+ xlist = x.tolist()
+ #
if 1:
- # w/o mask, w/o masked values
- xx = x.copy()
- putmask(xx, mask, 99)
- assert_equal(xx, [1,2,99,4,5,99])
- # w/ mask, w/o masked values
- mxx = mx.copy()
- putmask(mxx, mask, 99)
- assert_equal(mxx._data, [1,2,99,4,5,99])
- assert_equal(mxx._mask, [0,0,0,1,1,0])
- # w/o mask, w/ masked values
- values = array([10,20,30,40,50,60],mask=[1,1,1,0,0,0])
- xx = x.copy()
- putmask(xx, mask, values)
- assert_equal(xx._data, [1,2,30,4,5,60])
- assert_equal(xx._mask, [0,0,1,0,0,0])
- # w/ mask, w/ masked values
- mxx = mx.copy()
- putmask(mxx, mask, values)
- assert_equal(mxx._data, [1,2,30,4,5,60])
- assert_equal(mxx._mask, [0,0,1,1,1,0])
- # w/ mask, w/ masked values + hardmask
- mxx = mx.copy()
- mxx.harden_mask()
- putmask(mxx, mask, values)
- assert_equal(mxx, [1,2,30,4,5,60])
+ "Tests ndmin"
+ x = array([1,2,3],mask=[1,0,0], ndmin=2)
+ assert_equal(x.shape,(1,3))
+ assert_equal(x._data,[[1,2,3]])
+ assert_equal(x._mask,[[1,0,0]])
+ if 1:
+ x = masked_array([1,2,3], mask=True)
+
+ z = x.min()
+
+ assert(x.sum() is masked)
+ assert(x.prod() is masked)
+ if 1:
+ mtype = [('f',float_),('s','|S3')]
+ x = array([(1,'a'),(2,'b'),(numpy.pi,'pi')], dtype=mtype)
+ x[1] = masked
+ x['f'] = 17
+
\ No newline at end of file
_______________________________________________
Numpy-discussion mailing list
[email protected]
http://projects.scipy.org/mailman/listinfo/numpy-discussion