Skip to content

Commit

Permalink
Merge pull request #2703 from astrofrog/fix-masked-fill-view
Browse files Browse the repository at this point in the history
Don't reset the fill_value of a MaskedArray when calling view() with no dtype
  • Loading branch information
rgommers committed Nov 27, 2012
2 parents b209e19 + dadf5b9 commit 09d82ea
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 6 deletions.
10 changes: 6 additions & 4 deletions numpy/add_newdocs.py
Expand Up @@ -4437,10 +4437,12 @@ def luf(lamdaexpr, *args, **kwargs):
Parameters
----------
dtype : data-type, optional
Data-type descriptor of the returned view, e.g., float32 or int16.
The default, None, results in the view having the same data-type
as `a`.
dtype : data-type or ndarray sub-class, optional
Data-type descriptor of the returned view, e.g., float32 or int16. The
default, None, results in the view having the same data-type as `a`.
This argument can also be specified as an ndarray sub-class, which
then specifies the type of the returned object (this is equivalent to
setting the ``type`` parameter).
type : Python type, optional
Type of the returned view, e.g., ndarray or matrix. Again, the
default None results in type preservation.
Expand Down
48 changes: 46 additions & 2 deletions numpy/ma/core.py
Expand Up @@ -2852,7 +2852,45 @@ def __array_wrap__(self, obj, context=None):
return result


def view(self, dtype=None, type=None):
def view(self, dtype=None, type=None, fill_value=None):
"""
Return a view of the MaskedArray data
Parameters
----------
dtype : data-type or ndarray sub-class, optional
Data-type descriptor of the returned view, e.g., float32 or int16.
The default, None, results in the view having the same data-type
as `a`. As with ``ndarray.view``, dtype can also be specified as
an ndarray sub-class, which then specifies the type of the
returned object (this is equivalent to setting the ``type``
parameter).
type : Python type, optional
Type of the returned view, e.g., ndarray or matrix. Again, the
default None results in type preservation.
Notes
-----
``a.view()`` is used two different ways:
``a.view(some_dtype)`` or ``a.view(dtype=some_dtype)`` constructs a view
of the array's memory with a different data-type. This can cause a
reinterpretation of the bytes of memory.
``a.view(ndarray_subclass)`` or ``a.view(type=ndarray_subclass)`` just
returns an instance of `ndarray_subclass` that looks at the same array
(same shape, dtype, etc.) This does not cause a reinterpretation of the
memory.
If `fill_value` is not specified, but `dtype` is specified (and is not
an ndarray sub-class), the `fill_value` of the MaskedArray will be
reset. If neither `fill_value` nor `dtype` are specified (or if
`dtype` is an ndarray sub-class), then the fill value is preserved.
Finally, if `fill_value` is specified, but `dtype` is not, the fill
value is set to the specified value.
"""

if dtype is None:
if type is None:
output = ndarray.view(self)
Expand Down Expand Up @@ -2882,7 +2920,13 @@ def view(self, dtype=None, type=None):
pass
# Make sure to reset the _fill_value if needed
if getattr(output, '_fill_value', None) is not None:
output._fill_value = None
if fill_value is None:
if dtype is None:
pass # leave _fill_value as is
else:
output._fill_value = None
else:
output.fill_value = fill_value
return output
view.__doc__ = ndarray.view.__doc__

Expand Down
42 changes: 42 additions & 0 deletions numpy/ma/tests/test_core.py
Expand Up @@ -1554,6 +1554,48 @@ def test_fillvalue_as_arguments(self):
a = identity(3, fill_value=0., dtype=complex)
assert_equal(a.fill_value, 0.)

def test_fillvalue_in_view(self):
"Test the behavior of fill_value in view"

# Create initial masked array
x = array([1,2,3], fill_value=1, dtype=np.int64)

# Check that fill_value is preserved by default
y = x.view()
assert_(y.fill_value==1)

# Check that fill_value is preserved if dtype is specified and the
# dtype is an ndarray sub-class and has a _fill_value attribute
y = x.view(MaskedArray)
assert_(y.fill_value==1)

# Check that fill_value is preserved if type is specified and the
# dtype is an ndarray sub-class and has a _fill_value attribute (by
# default, the first argument is dtype, not type)
y = x.view(type=MaskedArray)
assert_(y.fill_value==1)

# Check that code does not crash if passed an ndarray sub-class that
# does not have a _fill_value attribute
y = x.view(np.ndarray)
y = x.view(type=np.ndarray)

# Check that fill_value can be overriden with view
y = x.view(MaskedArray, fill_value=2)
assert_(y.fill_value==2)

# Check that fill_value can be overriden with view (using type=)
y = x.view(type=MaskedArray, fill_value=2)
assert_(y.fill_value==2)

# Check that fill_value gets reset if passed a dtype but not a
# fill_value. This is because even though in some cases one can safely
# cast the fill_value, e.g. if taking an int64 view of an int32 array,
# in other cases, this cannot be done (e.g. int32 view of an int64
# array with a large fill_value).
y = x.view(dtype=np.int32)
assert_(y.fill_value == 999999)

#------------------------------------------------------------------------------

class TestUfuncs(TestCase):
Expand Down

0 comments on commit 09d82ea

Please sign in to comment.