summaryrefslogtreecommitdiffstats
path: root/venv/lib/python3.9/site-packages/numpy/ma
diff options
context:
space:
mode:
authornoptuno <repollo.marrero@gmail.com>2023-04-28 02:40:47 +0200
committernoptuno <repollo.marrero@gmail.com>2023-04-28 02:40:47 +0200
commit6f6a73987201c9c303047c61389b82ad98b15597 (patch)
treebf67eb590d49979d6740bc1e94b4018df48bce98 /venv/lib/python3.9/site-packages/numpy/ma
parentResolved merge conflicts and merged pr_218 into STREAMLIT_CHAT_IMPLEMENTATION (diff)
parentMerging PR_218 openai_rev package with new streamlit chat app (diff)
downloadgpt4free-6f6a73987201c9c303047c61389b82ad98b15597.tar
gpt4free-6f6a73987201c9c303047c61389b82ad98b15597.tar.gz
gpt4free-6f6a73987201c9c303047c61389b82ad98b15597.tar.bz2
gpt4free-6f6a73987201c9c303047c61389b82ad98b15597.tar.lz
gpt4free-6f6a73987201c9c303047c61389b82ad98b15597.tar.xz
gpt4free-6f6a73987201c9c303047c61389b82ad98b15597.tar.zst
gpt4free-6f6a73987201c9c303047c61389b82ad98b15597.zip
Diffstat (limited to 'venv/lib/python3.9/site-packages/numpy/ma')
-rw-r--r--venv/lib/python3.9/site-packages/numpy/ma/__init__.py54
-rw-r--r--venv/lib/python3.9/site-packages/numpy/ma/__init__.pyi235
-rw-r--r--venv/lib/python3.9/site-packages/numpy/ma/bench.py130
-rw-r--r--venv/lib/python3.9/site-packages/numpy/ma/core.py8404
-rw-r--r--venv/lib/python3.9/site-packages/numpy/ma/core.pyi472
-rw-r--r--venv/lib/python3.9/site-packages/numpy/ma/extras.py2045
-rw-r--r--venv/lib/python3.9/site-packages/numpy/ma/extras.pyi85
-rw-r--r--venv/lib/python3.9/site-packages/numpy/ma/mrecords.py783
-rw-r--r--venv/lib/python3.9/site-packages/numpy/ma/mrecords.pyi90
-rw-r--r--venv/lib/python3.9/site-packages/numpy/ma/setup.py12
-rw-r--r--venv/lib/python3.9/site-packages/numpy/ma/tests/__init__.py0
-rw-r--r--venv/lib/python3.9/site-packages/numpy/ma/tests/test_core.py5564
-rw-r--r--venv/lib/python3.9/site-packages/numpy/ma/tests/test_deprecations.py84
-rw-r--r--venv/lib/python3.9/site-packages/numpy/ma/tests/test_extras.py1829
-rw-r--r--venv/lib/python3.9/site-packages/numpy/ma/tests/test_mrecords.py493
-rw-r--r--venv/lib/python3.9/site-packages/numpy/ma/tests/test_old_ma.py874
-rw-r--r--venv/lib/python3.9/site-packages/numpy/ma/tests/test_regression.py91
-rw-r--r--venv/lib/python3.9/site-packages/numpy/ma/tests/test_subclassing.py450
-rw-r--r--venv/lib/python3.9/site-packages/numpy/ma/testutils.py288
-rw-r--r--venv/lib/python3.9/site-packages/numpy/ma/timer_comparison.py443
20 files changed, 22426 insertions, 0 deletions
diff --git a/venv/lib/python3.9/site-packages/numpy/ma/__init__.py b/venv/lib/python3.9/site-packages/numpy/ma/__init__.py
new file mode 100644
index 00000000..870cc4ef
--- /dev/null
+++ b/venv/lib/python3.9/site-packages/numpy/ma/__init__.py
@@ -0,0 +1,54 @@
+"""
+=============
+Masked Arrays
+=============
+
+Arrays sometimes contain invalid or missing data. When doing operations
+on such arrays, we wish to suppress invalid values, which is the purpose masked
+arrays fulfill (an example of typical use is given below).
+
+For example, examine the following array:
+
+>>> x = np.array([2, 1, 3, np.nan, 5, 2, 3, np.nan])
+
+When we try to calculate the mean of the data, the result is undetermined:
+
+>>> np.mean(x)
+nan
+
+The mean is calculated using roughly ``np.sum(x)/len(x)``, but since
+any number added to ``NaN`` [1]_ produces ``NaN``, this doesn't work. Enter
+masked arrays:
+
+>>> m = np.ma.masked_array(x, np.isnan(x))
+>>> m
+masked_array(data = [2.0 1.0 3.0 -- 5.0 2.0 3.0 --],
+ mask = [False False False True False False False True],
+ fill_value=1e+20)
+
+Here, we construct a masked array that suppress all ``NaN`` values. We
+may now proceed to calculate the mean of the other values:
+
+>>> np.mean(m)
+2.6666666666666665
+
+.. [1] Not-a-Number, a floating point value that is the result of an
+ invalid operation.
+
+.. moduleauthor:: Pierre Gerard-Marchant
+.. moduleauthor:: Jarrod Millman
+
+"""
+from . import core
+from .core import *
+
+from . import extras
+from .extras import *
+
+__all__ = ['core', 'extras']
+__all__ += core.__all__
+__all__ += extras.__all__
+
+from numpy._pytesttester import PytestTester
+test = PytestTester(__name__)
+del PytestTester
diff --git a/venv/lib/python3.9/site-packages/numpy/ma/__init__.pyi b/venv/lib/python3.9/site-packages/numpy/ma/__init__.pyi
new file mode 100644
index 00000000..7f5cb56a
--- /dev/null
+++ b/venv/lib/python3.9/site-packages/numpy/ma/__init__.pyi
@@ -0,0 +1,235 @@
+from numpy._pytesttester import PytestTester
+
+from numpy.ma import extras as extras
+
+from numpy.ma.core import (
+ MAError as MAError,
+ MaskError as MaskError,
+ MaskType as MaskType,
+ MaskedArray as MaskedArray,
+ abs as abs,
+ absolute as absolute,
+ add as add,
+ all as all,
+ allclose as allclose,
+ allequal as allequal,
+ alltrue as alltrue,
+ amax as amax,
+ amin as amin,
+ angle as angle,
+ anom as anom,
+ anomalies as anomalies,
+ any as any,
+ append as append,
+ arange as arange,
+ arccos as arccos,
+ arccosh as arccosh,
+ arcsin as arcsin,
+ arcsinh as arcsinh,
+ arctan as arctan,
+ arctan2 as arctan2,
+ arctanh as arctanh,
+ argmax as argmax,
+ argmin as argmin,
+ argsort as argsort,
+ around as around,
+ array as array,
+ asanyarray as asanyarray,
+ asarray as asarray,
+ bitwise_and as bitwise_and,
+ bitwise_or as bitwise_or,
+ bitwise_xor as bitwise_xor,
+ bool_ as bool_,
+ ceil as ceil,
+ choose as choose,
+ clip as clip,
+ common_fill_value as common_fill_value,
+ compress as compress,
+ compressed as compressed,
+ concatenate as concatenate,
+ conjugate as conjugate,
+ convolve as convolve,
+ copy as copy,
+ correlate as correlate,
+ cos as cos,
+ cosh as cosh,
+ count as count,
+ cumprod as cumprod,
+ cumsum as cumsum,
+ default_fill_value as default_fill_value,
+ diag as diag,
+ diagonal as diagonal,
+ diff as diff,
+ divide as divide,
+ empty as empty,
+ empty_like as empty_like,
+ equal as equal,
+ exp as exp,
+ expand_dims as expand_dims,
+ fabs as fabs,
+ filled as filled,
+ fix_invalid as fix_invalid,
+ flatten_mask as flatten_mask,
+ flatten_structured_array as flatten_structured_array,
+ floor as floor,
+ floor_divide as floor_divide,
+ fmod as fmod,
+ frombuffer as frombuffer,
+ fromflex as fromflex,
+ fromfunction as fromfunction,
+ getdata as getdata,
+ getmask as getmask,
+ getmaskarray as getmaskarray,
+ greater as greater,
+ greater_equal as greater_equal,
+ harden_mask as harden_mask,
+ hypot as hypot,
+ identity as identity,
+ ids as ids,
+ indices as indices,
+ inner as inner,
+ innerproduct as innerproduct,
+ isMA as isMA,
+ isMaskedArray as isMaskedArray,
+ is_mask as is_mask,
+ is_masked as is_masked,
+ isarray as isarray,
+ left_shift as left_shift,
+ less as less,
+ less_equal as less_equal,
+ log as log,
+ log10 as log10,
+ log2 as log2,
+ logical_and as logical_and,
+ logical_not as logical_not,
+ logical_or as logical_or,
+ logical_xor as logical_xor,
+ make_mask as make_mask,
+ make_mask_descr as make_mask_descr,
+ make_mask_none as make_mask_none,
+ mask_or as mask_or,
+ masked as masked,
+ masked_array as masked_array,
+ masked_equal as masked_equal,
+ masked_greater as masked_greater,
+ masked_greater_equal as masked_greater_equal,
+ masked_inside as masked_inside,
+ masked_invalid as masked_invalid,
+ masked_less as masked_less,
+ masked_less_equal as masked_less_equal,
+ masked_not_equal as masked_not_equal,
+ masked_object as masked_object,
+ masked_outside as masked_outside,
+ masked_print_option as masked_print_option,
+ masked_singleton as masked_singleton,
+ masked_values as masked_values,
+ masked_where as masked_where,
+ max as max,
+ maximum as maximum,
+ maximum_fill_value as maximum_fill_value,
+ mean as mean,
+ min as min,
+ minimum as minimum,
+ minimum_fill_value as minimum_fill_value,
+ mod as mod,
+ multiply as multiply,
+ mvoid as mvoid,
+ ndim as ndim,
+ negative as negative,
+ nomask as nomask,
+ nonzero as nonzero,
+ not_equal as not_equal,
+ ones as ones,
+ outer as outer,
+ outerproduct as outerproduct,
+ power as power,
+ prod as prod,
+ product as product,
+ ptp as ptp,
+ put as put,
+ putmask as putmask,
+ ravel as ravel,
+ remainder as remainder,
+ repeat as repeat,
+ reshape as reshape,
+ resize as resize,
+ right_shift as right_shift,
+ round as round,
+ round_ as round_,
+ set_fill_value as set_fill_value,
+ shape as shape,
+ sin as sin,
+ sinh as sinh,
+ size as size,
+ soften_mask as soften_mask,
+ sometrue as sometrue,
+ sort as sort,
+ sqrt as sqrt,
+ squeeze as squeeze,
+ std as std,
+ subtract as subtract,
+ sum as sum,
+ swapaxes as swapaxes,
+ take as take,
+ tan as tan,
+ tanh as tanh,
+ trace as trace,
+ transpose as transpose,
+ true_divide as true_divide,
+ var as var,
+ where as where,
+ zeros as zeros,
+)
+
+from numpy.ma.extras import (
+ apply_along_axis as apply_along_axis,
+ apply_over_axes as apply_over_axes,
+ atleast_1d as atleast_1d,
+ atleast_2d as atleast_2d,
+ atleast_3d as atleast_3d,
+ average as average,
+ clump_masked as clump_masked,
+ clump_unmasked as clump_unmasked,
+ column_stack as column_stack,
+ compress_cols as compress_cols,
+ compress_nd as compress_nd,
+ compress_rowcols as compress_rowcols,
+ compress_rows as compress_rows,
+ count_masked as count_masked,
+ corrcoef as corrcoef,
+ cov as cov,
+ diagflat as diagflat,
+ dot as dot,
+ dstack as dstack,
+ ediff1d as ediff1d,
+ flatnotmasked_contiguous as flatnotmasked_contiguous,
+ flatnotmasked_edges as flatnotmasked_edges,
+ hsplit as hsplit,
+ hstack as hstack,
+ isin as isin,
+ in1d as in1d,
+ intersect1d as intersect1d,
+ mask_cols as mask_cols,
+ mask_rowcols as mask_rowcols,
+ mask_rows as mask_rows,
+ masked_all as masked_all,
+ masked_all_like as masked_all_like,
+ median as median,
+ mr_ as mr_,
+ ndenumerate as ndenumerate,
+ notmasked_contiguous as notmasked_contiguous,
+ notmasked_edges as notmasked_edges,
+ polyfit as polyfit,
+ row_stack as row_stack,
+ setdiff1d as setdiff1d,
+ setxor1d as setxor1d,
+ stack as stack,
+ unique as unique,
+ union1d as union1d,
+ vander as vander,
+ vstack as vstack,
+)
+
+__all__: list[str]
+__path__: list[str]
+test: PytestTester
diff --git a/venv/lib/python3.9/site-packages/numpy/ma/bench.py b/venv/lib/python3.9/site-packages/numpy/ma/bench.py
new file mode 100644
index 00000000..56865683
--- /dev/null
+++ b/venv/lib/python3.9/site-packages/numpy/ma/bench.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python3
+
+import timeit
+import numpy
+
+
+###############################################################################
+# Global variables #
+###############################################################################
+
+
+# Small arrays
+xs = numpy.random.uniform(-1, 1, 6).reshape(2, 3)
+ys = numpy.random.uniform(-1, 1, 6).reshape(2, 3)
+zs = xs + 1j * ys
+m1 = [[True, False, False], [False, False, True]]
+m2 = [[True, False, True], [False, False, True]]
+nmxs = numpy.ma.array(xs, mask=m1)
+nmys = numpy.ma.array(ys, mask=m2)
+nmzs = numpy.ma.array(zs, mask=m1)
+
+# Big arrays
+xl = numpy.random.uniform(-1, 1, 100*100).reshape(100, 100)
+yl = numpy.random.uniform(-1, 1, 100*100).reshape(100, 100)
+zl = xl + 1j * yl
+maskx = xl > 0.8
+masky = yl < -0.8
+nmxl = numpy.ma.array(xl, mask=maskx)
+nmyl = numpy.ma.array(yl, mask=masky)
+nmzl = numpy.ma.array(zl, mask=maskx)
+
+
+###############################################################################
+# Functions #
+###############################################################################
+
+
+def timer(s, v='', nloop=500, nrep=3):
+ units = ["s", "ms", "µs", "ns"]
+ scaling = [1, 1e3, 1e6, 1e9]
+ print("%s : %-50s : " % (v, s), end=' ')
+ varnames = ["%ss,nm%ss,%sl,nm%sl" % tuple(x*4) for x in 'xyz']
+ setup = 'from __main__ import numpy, ma, %s' % ','.join(varnames)
+ Timer = timeit.Timer(stmt=s, setup=setup)
+ best = min(Timer.repeat(nrep, nloop)) / nloop
+ if best > 0.0:
+ order = min(-int(numpy.floor(numpy.log10(best)) // 3), 3)
+ else:
+ order = 3
+ print("%d loops, best of %d: %.*g %s per loop" % (nloop, nrep,
+ 3,
+ best * scaling[order],
+ units[order]))
+
+
+def compare_functions_1v(func, nloop=500,
+ xs=xs, nmxs=nmxs, xl=xl, nmxl=nmxl):
+ funcname = func.__name__
+ print("-"*50)
+ print(f'{funcname} on small arrays')
+ module, data = "numpy.ma", "nmxs"
+ timer("%(module)s.%(funcname)s(%(data)s)" % locals(), v="%11s" % module, nloop=nloop)
+
+ print("%s on large arrays" % funcname)
+ module, data = "numpy.ma", "nmxl"
+ timer("%(module)s.%(funcname)s(%(data)s)" % locals(), v="%11s" % module, nloop=nloop)
+ return
+
+def compare_methods(methodname, args, vars='x', nloop=500, test=True,
+ xs=xs, nmxs=nmxs, xl=xl, nmxl=nmxl):
+ print("-"*50)
+ print(f'{methodname} on small arrays')
+ data, ver = f'nm{vars}l', 'numpy.ma'
+ timer("%(data)s.%(methodname)s(%(args)s)" % locals(), v=ver, nloop=nloop)
+
+ print("%s on large arrays" % methodname)
+ data, ver = "nm%sl" % vars, 'numpy.ma'
+ timer("%(data)s.%(methodname)s(%(args)s)" % locals(), v=ver, nloop=nloop)
+ return
+
+def compare_functions_2v(func, nloop=500, test=True,
+ xs=xs, nmxs=nmxs,
+ ys=ys, nmys=nmys,
+ xl=xl, nmxl=nmxl,
+ yl=yl, nmyl=nmyl):
+ funcname = func.__name__
+ print("-"*50)
+ print(f'{funcname} on small arrays')
+ module, data = "numpy.ma", "nmxs,nmys"
+ timer("%(module)s.%(funcname)s(%(data)s)" % locals(), v="%11s" % module, nloop=nloop)
+
+ print(f'{funcname} on large arrays')
+ module, data = "numpy.ma", "nmxl,nmyl"
+ timer("%(module)s.%(funcname)s(%(data)s)" % locals(), v="%11s" % module, nloop=nloop)
+ return
+
+
+if __name__ == '__main__':
+ compare_functions_1v(numpy.sin)
+ compare_functions_1v(numpy.log)
+ compare_functions_1v(numpy.sqrt)
+
+ compare_functions_2v(numpy.multiply)
+ compare_functions_2v(numpy.divide)
+ compare_functions_2v(numpy.power)
+
+ compare_methods('ravel', '', nloop=1000)
+ compare_methods('conjugate', '', 'z', nloop=1000)
+ compare_methods('transpose', '', nloop=1000)
+ compare_methods('compressed', '', nloop=1000)
+ compare_methods('__getitem__', '0', nloop=1000)
+ compare_methods('__getitem__', '(0,0)', nloop=1000)
+ compare_methods('__getitem__', '[0,-1]', nloop=1000)
+ compare_methods('__setitem__', '0, 17', nloop=1000, test=False)
+ compare_methods('__setitem__', '(0,0), 17', nloop=1000, test=False)
+
+ print("-"*50)
+ print("__setitem__ on small arrays")
+ timer('nmxs.__setitem__((-1,0),numpy.ma.masked)', 'numpy.ma ', nloop=10000)
+
+ print("-"*50)
+ print("__setitem__ on large arrays")
+ timer('nmxl.__setitem__((-1,0),numpy.ma.masked)', 'numpy.ma ', nloop=10000)
+
+ print("-"*50)
+ print("where on small arrays")
+ timer('numpy.ma.where(nmxs>2,nmxs,nmys)', 'numpy.ma ', nloop=1000)
+ print("-"*50)
+ print("where on large arrays")
+ timer('numpy.ma.where(nmxl>2,nmxl,nmyl)', 'numpy.ma ', nloop=100)
diff --git a/venv/lib/python3.9/site-packages/numpy/ma/core.py b/venv/lib/python3.9/site-packages/numpy/ma/core.py
new file mode 100644
index 00000000..acf1a044
--- /dev/null
+++ b/venv/lib/python3.9/site-packages/numpy/ma/core.py
@@ -0,0 +1,8404 @@
+"""
+numpy.ma : a package to handle missing or invalid values.
+
+This package was initially written for numarray by Paul F. Dubois
+at Lawrence Livermore National Laboratory.
+In 2006, the package was completely rewritten by Pierre Gerard-Marchant
+(University of Georgia) to make the MaskedArray class a subclass of ndarray,
+and to improve support of structured arrays.
+
+
+Copyright 1999, 2000, 2001 Regents of the University of California.
+Released for unlimited redistribution.
+
+* Adapted for numpy_core 2005 by Travis Oliphant and (mainly) Paul Dubois.
+* Subclassing of the base `ndarray` 2006 by Pierre Gerard-Marchant
+ (pgmdevlist_AT_gmail_DOT_com)
+* Improvements suggested by Reggie Dugard (reggie_AT_merfinllc_DOT_com)
+
+.. moduleauthor:: Pierre Gerard-Marchant
+
+"""
+# pylint: disable-msg=E1002
+import builtins
+import inspect
+import operator
+import warnings
+import textwrap
+import re
+from functools import reduce
+
+import numpy as np
+import numpy.core.umath as umath
+import numpy.core.numerictypes as ntypes
+from numpy.core import multiarray as mu
+from numpy import ndarray, amax, amin, iscomplexobj, bool_, _NoValue
+from numpy import array as narray
+from numpy.lib.function_base import angle
+from numpy.compat import (
+ getargspec, formatargspec, long, unicode, bytes
+ )
+from numpy import expand_dims
+from numpy.core.numeric import normalize_axis_tuple
+
+
+__all__ = [
+ 'MAError', 'MaskError', 'MaskType', 'MaskedArray', 'abs', 'absolute',
+ 'add', 'all', 'allclose', 'allequal', 'alltrue', 'amax', 'amin',
+ 'angle', 'anom', 'anomalies', 'any', 'append', 'arange', 'arccos',
+ 'arccosh', 'arcsin', 'arcsinh', 'arctan', 'arctan2', 'arctanh',
+ 'argmax', 'argmin', 'argsort', 'around', 'array', 'asanyarray',
+ 'asarray', 'bitwise_and', 'bitwise_or', 'bitwise_xor', 'bool_', 'ceil',
+ 'choose', 'clip', 'common_fill_value', 'compress', 'compressed',
+ 'concatenate', 'conjugate', 'convolve', 'copy', 'correlate', 'cos', 'cosh',
+ 'count', 'cumprod', 'cumsum', 'default_fill_value', 'diag', 'diagonal',
+ 'diff', 'divide', 'empty', 'empty_like', 'equal', 'exp',
+ 'expand_dims', 'fabs', 'filled', 'fix_invalid', 'flatten_mask',
+ 'flatten_structured_array', 'floor', 'floor_divide', 'fmod',
+ 'frombuffer', 'fromflex', 'fromfunction', 'getdata', 'getmask',
+ 'getmaskarray', 'greater', 'greater_equal', 'harden_mask', 'hypot',
+ 'identity', 'ids', 'indices', 'inner', 'innerproduct', 'isMA',
+ 'isMaskedArray', 'is_mask', 'is_masked', 'isarray', 'left_shift',
+ 'less', 'less_equal', 'log', 'log10', 'log2',
+ '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',
+ 'masked_less', 'masked_less_equal', 'masked_not_equal',
+ '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', 'mvoid', 'ndim', 'negative', 'nomask', 'nonzero',
+ 'not_equal', 'ones', 'ones_like', 'outer', 'outerproduct', 'power', 'prod',
+ 'product', 'ptp', 'put', 'putmask', 'ravel', 'remainder',
+ 'repeat', 'reshape', 'resize', 'right_shift', 'round', 'round_',
+ 'set_fill_value', 'shape', 'sin', 'sinh', 'size', 'soften_mask',
+ 'sometrue', 'sort', 'sqrt', 'squeeze', 'std', 'subtract', 'sum',
+ 'swapaxes', 'take', 'tan', 'tanh', 'trace', 'transpose', 'true_divide',
+ 'var', 'where', 'zeros', 'zeros_like',
+ ]
+
+MaskType = np.bool_
+nomask = MaskType(0)
+
+class MaskedArrayFutureWarning(FutureWarning):
+ pass
+
+def _deprecate_argsort_axis(arr):
+ """
+ Adjust the axis passed to argsort, warning if necessary
+
+ Parameters
+ ----------
+ arr
+ The array which argsort was called on
+
+ np.ma.argsort has a long-term bug where the default of the axis argument
+ is wrong (gh-8701), which now must be kept for backwards compatibility.
+ Thankfully, this only makes a difference when arrays are 2- or more-
+ dimensional, so we only need a warning then.
+ """
+ if arr.ndim <= 1:
+ # no warning needed - but switch to -1 anyway, to avoid surprising
+ # subclasses, which are more likely to implement scalar axes.
+ return -1
+ else:
+ # 2017-04-11, Numpy 1.13.0, gh-8701: warn on axis default
+ warnings.warn(
+ "In the future the default for argsort will be axis=-1, not the "
+ "current None, to match its documentation and np.argsort. "
+ "Explicitly pass -1 or None to silence this warning.",
+ MaskedArrayFutureWarning, stacklevel=3)
+ return None
+
+
+def doc_note(initialdoc, note):
+ """
+ Adds a Notes section to an existing docstring.
+
+ """
+ if initialdoc is None:
+ return
+ if note is None:
+ return initialdoc
+
+ notesplit = re.split(r'\n\s*?Notes\n\s*?-----', inspect.cleandoc(initialdoc))
+ notedoc = "\n\nNotes\n-----\n%s\n" % inspect.cleandoc(note)
+
+ return ''.join(notesplit[:1] + [notedoc] + notesplit[1:])
+
+
+def get_object_signature(obj):
+ """
+ Get the signature from obj
+
+ """
+ try:
+ sig = formatargspec(*getargspec(obj))
+ except TypeError:
+ sig = ''
+ return sig
+
+
+###############################################################################
+# Exceptions #
+###############################################################################
+
+
+class MAError(Exception):
+ """
+ Class for masked array related errors.
+
+ """
+ pass
+
+
+class MaskError(MAError):
+ """
+ Class for mask related errors.
+
+ """
+ pass
+
+
+###############################################################################
+# Filling options #
+###############################################################################
+
+
+# b: boolean - c: complex - f: floats - i: integer - O: object - S: string
+default_filler = {'b': True,
+ 'c': 1.e20 + 0.0j,
+ 'f': 1.e20,
+ 'i': 999999,
+ 'O': '?',
+ 'S': b'N/A',
+ 'u': 999999,
+ 'V': b'???',
+ 'U': 'N/A'
+ }
+
+# Add datetime64 and timedelta64 types
+for v in ["Y", "M", "W", "D", "h", "m", "s", "ms", "us", "ns", "ps",
+ "fs", "as"]:
+ default_filler["M8[" + v + "]"] = np.datetime64("NaT", v)
+ default_filler["m8[" + v + "]"] = np.timedelta64("NaT", v)
+
+float_types_list = [np.half, np.single, np.double, np.longdouble,
+ np.csingle, np.cdouble, np.clongdouble]
+max_filler = ntypes._minvals
+max_filler.update([(k, -np.inf) for k in float_types_list[:4]])
+max_filler.update([(k, complex(-np.inf, -np.inf)) for k in float_types_list[-3:]])
+
+min_filler = ntypes._maxvals
+min_filler.update([(k, +np.inf) for k in float_types_list[:4]])
+min_filler.update([(k, complex(+np.inf, +np.inf)) for k in float_types_list[-3:]])
+
+del float_types_list
+
+def _recursive_fill_value(dtype, f):
+ """
+ Recursively produce a fill value for `dtype`, calling f on scalar dtypes
+ """
+ if dtype.names is not None:
+ # We wrap into `array` here, which ensures we use NumPy cast rules
+ # for integer casts, this allows the use of 99999 as a fill value
+ # for int8.
+ # TODO: This is probably a mess, but should best preserve behavior?
+ vals = tuple(
+ np.array(_recursive_fill_value(dtype[name], f))
+ for name in dtype.names)
+ return np.array(vals, dtype=dtype)[()] # decay to void scalar from 0d
+ elif dtype.subdtype:
+ subtype, shape = dtype.subdtype
+ subval = _recursive_fill_value(subtype, f)
+ return np.full(shape, subval)
+ else:
+ return f(dtype)
+
+
+def _get_dtype_of(obj):
+ """ Convert the argument for *_fill_value into a dtype """
+ if isinstance(obj, np.dtype):
+ return obj
+ elif hasattr(obj, 'dtype'):
+ return obj.dtype
+ else:
+ return np.asanyarray(obj).dtype
+
+
+def default_fill_value(obj):
+ """
+ Return the default fill value for the argument object.
+
+ The default filling value depends on the datatype of the input
+ array or the type of the input scalar:
+
+ ======== ========
+ datatype default
+ ======== ========
+ bool True
+ int 999999
+ float 1.e20
+ complex 1.e20+0j
+ object '?'
+ string 'N/A'
+ ======== ========
+
+ For structured types, a structured scalar is returned, with each field the
+ default fill value for its type.
+
+ For subarray types, the fill value is an array of the same size containing
+ the default scalar fill value.
+
+ Parameters
+ ----------
+ obj : ndarray, dtype or scalar
+ The array data-type or scalar for which the default fill value
+ is returned.
+
+ Returns
+ -------
+ fill_value : scalar
+ The default fill value.
+
+ Examples
+ --------
+ >>> np.ma.default_fill_value(1)
+ 999999
+ >>> np.ma.default_fill_value(np.array([1.1, 2., np.pi]))
+ 1e+20
+ >>> np.ma.default_fill_value(np.dtype(complex))
+ (1e+20+0j)
+
+ """
+ def _scalar_fill_value(dtype):
+ if dtype.kind in 'Mm':
+ return default_filler.get(dtype.str[1:], '?')
+ else:
+ return default_filler.get(dtype.kind, '?')
+
+ dtype = _get_dtype_of(obj)
+ return _recursive_fill_value(dtype, _scalar_fill_value)
+
+
+def _extremum_fill_value(obj, extremum, extremum_name):
+
+ def _scalar_fill_value(dtype):
+ try:
+ return extremum[dtype]
+ except KeyError as e:
+ raise TypeError(
+ f"Unsuitable type {dtype} for calculating {extremum_name}."
+ ) from None
+
+ dtype = _get_dtype_of(obj)
+ return _recursive_fill_value(dtype, _scalar_fill_value)
+
+
+def minimum_fill_value(obj):
+ """
+ Return the maximum value that can be represented by the dtype of an object.
+
+ This function is useful for calculating a fill value suitable for
+ taking the minimum of an array with a given dtype.
+
+ Parameters
+ ----------
+ obj : ndarray, dtype or scalar
+ An object that can be queried for it's numeric type.
+
+ Returns
+ -------
+ val : scalar
+ The maximum representable value.
+
+ Raises
+ ------
+ TypeError
+ If `obj` isn't a suitable numeric type.
+
+ See Also
+ --------
+ maximum_fill_value : The inverse function.
+ set_fill_value : Set the filling value of a masked array.
+ MaskedArray.fill_value : Return current fill value.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> a = np.int8()
+ >>> ma.minimum_fill_value(a)
+ 127
+ >>> a = np.int32()
+ >>> ma.minimum_fill_value(a)
+ 2147483647
+
+ An array of numeric data can also be passed.
+
+ >>> a = np.array([1, 2, 3], dtype=np.int8)
+ >>> ma.minimum_fill_value(a)
+ 127
+ >>> a = np.array([1, 2, 3], dtype=np.float32)
+ >>> ma.minimum_fill_value(a)
+ inf
+
+ """
+ return _extremum_fill_value(obj, min_filler, "minimum")
+
+
+def maximum_fill_value(obj):
+ """
+ Return the minimum value that can be represented by the dtype of an object.
+
+ This function is useful for calculating a fill value suitable for
+ taking the maximum of an array with a given dtype.
+
+ Parameters
+ ----------
+ obj : ndarray, dtype or scalar
+ An object that can be queried for it's numeric type.
+
+ Returns
+ -------
+ val : scalar
+ The minimum representable value.
+
+ Raises
+ ------
+ TypeError
+ If `obj` isn't a suitable numeric type.
+
+ See Also
+ --------
+ minimum_fill_value : The inverse function.
+ set_fill_value : Set the filling value of a masked array.
+ MaskedArray.fill_value : Return current fill value.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> a = np.int8()
+ >>> ma.maximum_fill_value(a)
+ -128
+ >>> a = np.int32()
+ >>> ma.maximum_fill_value(a)
+ -2147483648
+
+ An array of numeric data can also be passed.
+
+ >>> a = np.array([1, 2, 3], dtype=np.int8)
+ >>> ma.maximum_fill_value(a)
+ -128
+ >>> a = np.array([1, 2, 3], dtype=np.float32)
+ >>> ma.maximum_fill_value(a)
+ -inf
+
+ """
+ return _extremum_fill_value(obj, max_filler, "maximum")
+
+
+def _recursive_set_fill_value(fillvalue, dt):
+ """
+ Create a fill value for a structured dtype.
+
+ Parameters
+ ----------
+ fillvalue : scalar or array_like
+ Scalar or array representing the fill value. If it is of shorter
+ length than the number of fields in dt, it will be resized.
+ dt : dtype
+ The structured dtype for which to create the fill value.
+
+ Returns
+ -------
+ val : tuple
+ A tuple of values corresponding to the structured fill value.
+
+ """
+ fillvalue = np.resize(fillvalue, len(dt.names))
+ output_value = []
+ for (fval, name) in zip(fillvalue, dt.names):
+ cdtype = dt[name]
+ if cdtype.subdtype:
+ cdtype = cdtype.subdtype[0]
+
+ if cdtype.names is not None:
+ output_value.append(tuple(_recursive_set_fill_value(fval, cdtype)))
+ else:
+ output_value.append(np.array(fval, dtype=cdtype).item())
+ return tuple(output_value)
+
+
+def _check_fill_value(fill_value, ndtype):
+ """
+ Private function validating the given `fill_value` for the given dtype.
+
+ If fill_value is None, it is set to the default corresponding to the dtype.
+
+ If fill_value is not None, its value is forced to the given dtype.
+
+ The result is always a 0d array.
+
+ """
+ ndtype = np.dtype(ndtype)
+ if fill_value is None:
+ fill_value = default_fill_value(ndtype)
+ elif ndtype.names is not None:
+ if isinstance(fill_value, (ndarray, np.void)):
+ try:
+ fill_value = np.array(fill_value, copy=False, dtype=ndtype)
+ except ValueError as e:
+ err_msg = "Unable to transform %s to dtype %s"
+ raise ValueError(err_msg % (fill_value, ndtype)) from e
+ else:
+ fill_value = np.asarray(fill_value, dtype=object)
+ fill_value = np.array(_recursive_set_fill_value(fill_value, ndtype),
+ dtype=ndtype)
+ else:
+ if isinstance(fill_value, str) and (ndtype.char not in 'OSVU'):
+ # Note this check doesn't work if fill_value is not a scalar
+ 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 1e20 to int.
+ # Also in case of converting string arrays.
+ try:
+ fill_value = np.array(fill_value, copy=False, dtype=ndtype)
+ except (OverflowError, ValueError) as e:
+ # Raise TypeError instead of OverflowError or ValueError.
+ # OverflowError is seldom used, and the real problem here is
+ # that the passed fill_value is not compatible with the ndtype.
+ err_msg = "Cannot convert fill_value %s to dtype %s"
+ raise TypeError(err_msg % (fill_value, ndtype)) from e
+ return np.array(fill_value)
+
+
+def set_fill_value(a, fill_value):
+ """
+ Set the filling value of a, if a is a masked array.
+
+ This function changes the fill value of the masked array `a` in place.
+ If `a` is not a masked array, the function returns silently, without
+ doing anything.
+
+ Parameters
+ ----------
+ a : array_like
+ Input array.
+ fill_value : dtype
+ Filling value. A consistency test is performed to make sure
+ the value is compatible with the dtype of `a`.
+
+ Returns
+ -------
+ None
+ Nothing returned by this function.
+
+ See Also
+ --------
+ maximum_fill_value : Return the default fill value for a dtype.
+ MaskedArray.fill_value : Return current fill value.
+ MaskedArray.set_fill_value : Equivalent method.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> a = np.arange(5)
+ >>> a
+ array([0, 1, 2, 3, 4])
+ >>> a = ma.masked_where(a < 3, a)
+ >>> a
+ masked_array(data=[--, --, --, 3, 4],
+ mask=[ True, True, True, False, False],
+ fill_value=999999)
+ >>> ma.set_fill_value(a, -999)
+ >>> a
+ masked_array(data=[--, --, --, 3, 4],
+ mask=[ True, True, True, False, False],
+ fill_value=-999)
+
+ Nothing happens if `a` is not a masked array.
+
+ >>> a = list(range(5))
+ >>> a
+ [0, 1, 2, 3, 4]
+ >>> ma.set_fill_value(a, 100)
+ >>> a
+ [0, 1, 2, 3, 4]
+ >>> a = np.arange(5)
+ >>> a
+ array([0, 1, 2, 3, 4])
+ >>> ma.set_fill_value(a, 100)
+ >>> a
+ array([0, 1, 2, 3, 4])
+
+ """
+ if isinstance(a, MaskedArray):
+ a.set_fill_value(fill_value)
+ return
+
+
+def get_fill_value(a):
+ """
+ Return the filling value of a, if any. Otherwise, returns the
+ default filling value for that type.
+
+ """
+ if isinstance(a, MaskedArray):
+ result = a.fill_value
+ else:
+ result = default_fill_value(a)
+ return result
+
+
+def common_fill_value(a, b):
+ """
+ Return the common filling value of two masked arrays, if any.
+
+ If ``a.fill_value == b.fill_value``, return the fill value,
+ otherwise return None.
+
+ Parameters
+ ----------
+ a, b : MaskedArray
+ The masked arrays for which to compare fill values.
+
+ Returns
+ -------
+ fill_value : scalar or None
+ The common fill value, or None.
+
+ Examples
+ --------
+ >>> x = np.ma.array([0, 1.], fill_value=3)
+ >>> y = np.ma.array([0, 1.], fill_value=3)
+ >>> np.ma.common_fill_value(x, y)
+ 3.0
+
+ """
+ t1 = get_fill_value(a)
+ t2 = get_fill_value(b)
+ if t1 == t2:
+ return t1
+ return None
+
+
+def filled(a, fill_value=None):
+ """
+ Return input as an array with masked data replaced by a fill value.
+
+ If `a` is not a `MaskedArray`, `a` itself is returned.
+ If `a` is a `MaskedArray` and `fill_value` is None, `fill_value` is set to
+ ``a.fill_value``.
+
+ Parameters
+ ----------
+ a : MaskedArray or array_like
+ An input object.
+ fill_value : array_like, optional.
+ Can be scalar or non-scalar. If non-scalar, the
+ resulting filled array should be broadcastable
+ over input array. Default is None.
+
+ Returns
+ -------
+ a : ndarray
+ The filled array.
+
+ See Also
+ --------
+ compressed
+
+ Examples
+ --------
+ >>> x = np.ma.array(np.arange(9).reshape(3, 3), mask=[[1, 0, 0],
+ ... [1, 0, 0],
+ ... [0, 0, 0]])
+ >>> x.filled()
+ array([[999999, 1, 2],
+ [999999, 4, 5],
+ [ 6, 7, 8]])
+ >>> x.filled(fill_value=333)
+ array([[333, 1, 2],
+ [333, 4, 5],
+ [ 6, 7, 8]])
+ >>> x.filled(fill_value=np.arange(3))
+ array([[0, 1, 2],
+ [0, 4, 5],
+ [6, 7, 8]])
+
+ """
+ if hasattr(a, 'filled'):
+ return a.filled(fill_value)
+
+ elif isinstance(a, ndarray):
+ # Should we check for contiguity ? and a.flags['CONTIGUOUS']:
+ return a
+ elif isinstance(a, dict):
+ return np.array(a, 'O')
+ else:
+ return np.array(a)
+
+
+def get_masked_subclass(*arrays):
+ """
+ Return the youngest subclass of MaskedArray from a list of (masked) arrays.
+
+ In case of siblings, the first listed takes over.
+
+ """
+ if len(arrays) == 1:
+ arr = arrays[0]
+ if isinstance(arr, MaskedArray):
+ rcls = type(arr)
+ else:
+ rcls = MaskedArray
+ else:
+ arrcls = [type(a) for a in arrays]
+ rcls = arrcls[0]
+ if not issubclass(rcls, MaskedArray):
+ rcls = MaskedArray
+ for cls in arrcls[1:]:
+ if issubclass(cls, rcls):
+ rcls = cls
+ # Don't return MaskedConstant as result: revert to MaskedArray
+ if rcls.__name__ == 'MaskedConstant':
+ return MaskedArray
+ return rcls
+
+
+def getdata(a, subok=True):
+ """
+ Return the data of a masked array as an ndarray.
+
+ Return the data of `a` (if any) as an ndarray if `a` is a ``MaskedArray``,
+ else return `a` as a ndarray or subclass (depending on `subok`) if not.
+
+ Parameters
+ ----------
+ a : array_like
+ Input ``MaskedArray``, alternatively a ndarray or a subclass thereof.
+ subok : bool
+ Whether to force the output to be a `pure` ndarray (False) or to
+ return a subclass of ndarray if appropriate (True, default).
+
+ See Also
+ --------
+ getmask : Return the mask of a masked array, or nomask.
+ getmaskarray : Return the mask of a masked array, or full array of False.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> a = ma.masked_equal([[1,2],[3,4]], 2)
+ >>> a
+ masked_array(
+ data=[[1, --],
+ [3, 4]],
+ mask=[[False, True],
+ [False, False]],
+ fill_value=2)
+ >>> ma.getdata(a)
+ array([[1, 2],
+ [3, 4]])
+
+ Equivalently use the ``MaskedArray`` `data` attribute.
+
+ >>> a.data
+ array([[1, 2],
+ [3, 4]])
+
+ """
+ try:
+ data = a._data
+ except AttributeError:
+ data = np.array(a, copy=False, subok=subok)
+ if not subok:
+ return data.view(ndarray)
+ return data
+
+
+get_data = getdata
+
+
+def fix_invalid(a, mask=nomask, copy=True, fill_value=None):
+ """
+ Return input with invalid data masked and replaced by a fill value.
+
+ Invalid data means values of `nan`, `inf`, etc.
+
+ Parameters
+ ----------
+ a : array_like
+ Input array, a (subclass of) ndarray.
+ mask : sequence, optional
+ Mask. Must be convertible to an array of booleans with the same
+ shape as `data`. True indicates a masked (i.e. invalid) data.
+ copy : bool, optional
+ Whether to use a copy of `a` (True) or to fix `a` in place (False).
+ Default is True.
+ fill_value : scalar, optional
+ Value used for fixing invalid data. Default is None, in which case
+ the ``a.fill_value`` is used.
+
+ Returns
+ -------
+ b : MaskedArray
+ The input array with invalid entries fixed.
+
+ Notes
+ -----
+ A copy is performed by default.
+
+ Examples
+ --------
+ >>> x = np.ma.array([1., -1, np.nan, np.inf], mask=[1] + [0]*3)
+ >>> x
+ masked_array(data=[--, -1.0, nan, inf],
+ mask=[ True, False, False, False],
+ fill_value=1e+20)
+ >>> np.ma.fix_invalid(x)
+ masked_array(data=[--, -1.0, --, --],
+ mask=[ True, False, True, True],
+ fill_value=1e+20)
+
+ >>> fixed = np.ma.fix_invalid(x)
+ >>> fixed.data
+ array([ 1.e+00, -1.e+00, 1.e+20, 1.e+20])
+ >>> x.data
+ array([ 1., -1., nan, inf])
+
+ """
+ a = masked_array(a, copy=copy, mask=mask, subok=True)
+ invalid = np.logical_not(np.isfinite(a._data))
+ if not invalid.any():
+ return a
+ a._mask |= invalid
+ if fill_value is None:
+ fill_value = a.fill_value
+ a._data[invalid] = fill_value
+ return a
+
+def is_string_or_list_of_strings(val):
+ return (isinstance(val, str) or
+ (isinstance(val, list) and val and
+ builtins.all(isinstance(s, str) for s in val)))
+
+###############################################################################
+# Ufuncs #
+###############################################################################
+
+
+ufunc_domain = {}
+ufunc_fills = {}
+
+
+class _DomainCheckInterval:
+ """
+ Define a valid interval, so that :
+
+ ``domain_check_interval(a,b)(x) == True`` where
+ ``x < a`` or ``x > b``.
+
+ """
+
+ def __init__(self, a, b):
+ "domain_check_interval(a,b)(x) = true where x < a or y > b"
+ if a > b:
+ (a, b) = (b, a)
+ self.a = a
+ self.b = b
+
+ def __call__(self, x):
+ "Execute the call behavior."
+ # nans at masked positions cause RuntimeWarnings, even though
+ # they are masked. To avoid this we suppress warnings.
+ with np.errstate(invalid='ignore'):
+ return umath.logical_or(umath.greater(x, self.b),
+ umath.less(x, self.a))
+
+
+class _DomainTan:
+ """
+ Define a valid interval for the `tan` function, so that:
+
+ ``domain_tan(eps) = True`` where ``abs(cos(x)) < eps``
+
+ """
+
+ def __init__(self, eps):
+ "domain_tan(eps) = true where abs(cos(x)) < eps)"
+ self.eps = eps
+
+ def __call__(self, x):
+ "Executes the call behavior."
+ with np.errstate(invalid='ignore'):
+ return umath.less(umath.absolute(umath.cos(x)), self.eps)
+
+
+class _DomainSafeDivide:
+ """
+ Define a domain for safe division.
+
+ """
+
+ def __init__(self, tolerance=None):
+ self.tolerance = tolerance
+
+ def __call__(self, a, b):
+ # Delay the selection of the tolerance to here in order to reduce numpy
+ # import times. The calculation of these parameters is a substantial
+ # component of numpy's import time.
+ if self.tolerance is None:
+ self.tolerance = np.finfo(float).tiny
+ # don't call ma ufuncs from __array_wrap__ which would fail for scalars
+ a, b = np.asarray(a), np.asarray(b)
+ with np.errstate(invalid='ignore'):
+ return umath.absolute(a) * self.tolerance >= umath.absolute(b)
+
+
+class _DomainGreater:
+ """
+ DomainGreater(v)(x) is True where x <= v.
+
+ """
+
+ def __init__(self, critical_value):
+ "DomainGreater(v)(x) = true where x <= v"
+ self.critical_value = critical_value
+
+ def __call__(self, x):
+ "Executes the call behavior."
+ with np.errstate(invalid='ignore'):
+ return umath.less_equal(x, self.critical_value)
+
+
+class _DomainGreaterEqual:
+ """
+ DomainGreaterEqual(v)(x) is True where x < v.
+
+ """
+
+ def __init__(self, critical_value):
+ "DomainGreaterEqual(v)(x) = true where x < v"
+ self.critical_value = critical_value
+
+ def __call__(self, x):
+ "Executes the call behavior."
+ with np.errstate(invalid='ignore'):
+ return umath.less(x, self.critical_value)
+
+
+class _MaskedUFunc:
+ def __init__(self, ufunc):
+ self.f = ufunc
+ self.__doc__ = ufunc.__doc__
+ self.__name__ = ufunc.__name__
+
+ def __str__(self):
+ return f"Masked version of {self.f}"
+
+
+class _MaskedUnaryOperation(_MaskedUFunc):
+ """
+ Defines masked version of unary operations, where invalid values are
+ pre-masked.
+
+ Parameters
+ ----------
+ mufunc : callable
+ The function for which to define a masked version. Made available
+ as ``_MaskedUnaryOperation.f``.
+ fill : scalar, optional
+ Filling value, default is 0.
+ domain : class instance
+ Domain for the function. Should be one of the ``_Domain*``
+ classes. Default is None.
+
+ """
+
+ def __init__(self, mufunc, fill=0, domain=None):
+ super().__init__(mufunc)
+ self.fill = fill
+ self.domain = domain
+ ufunc_domain[mufunc] = domain
+ ufunc_fills[mufunc] = fill
+
+ def __call__(self, a, *args, **kwargs):
+ """
+ Execute the call behavior.
+
+ """
+ d = getdata(a)
+ # Deal with domain
+ if self.domain is not None:
+ # Case 1.1. : Domained function
+ # nans at masked positions cause RuntimeWarnings, even though
+ # they are masked. To avoid this we suppress warnings.
+ with np.errstate(divide='ignore', invalid='ignore'):
+ result = self.f(d, *args, **kwargs)
+ # Make a mask
+ m = ~umath.isfinite(result)
+ m |= self.domain(d)
+ m |= getmask(a)
+ else:
+ # Case 1.2. : Function without a domain
+ # Get the result and the mask
+ with np.errstate(divide='ignore', invalid='ignore'):
+ result = self.f(d, *args, **kwargs)
+ m = getmask(a)
+
+ if not result.ndim:
+ # Case 2.1. : The result is scalarscalar
+ if m:
+ return masked
+ return result
+
+ if m is not nomask:
+ # Case 2.2. The result is an array
+ # We need to fill the invalid data back w/ the input Now,
+ # that's plain silly: in C, we would just skip the element and
+ # keep the original, but we do have to do it that way in Python
+
+ # In case result has a lower dtype than the inputs (as in
+ # equal)
+ try:
+ np.copyto(result, d, where=m)
+ except TypeError:
+ pass
+ # Transform to
+ masked_result = result.view(get_masked_subclass(a))
+ masked_result._mask = m
+ masked_result._update_from(a)
+ return masked_result
+
+
+class _MaskedBinaryOperation(_MaskedUFunc):
+ """
+ Define masked version of binary operations, where invalid
+ values are pre-masked.
+
+ Parameters
+ ----------
+ mbfunc : function
+ The function for which to define a masked version. Made available
+ as ``_MaskedBinaryOperation.f``.
+ domain : class instance
+ Default domain for the function. Should be one of the ``_Domain*``
+ classes. Default is None.
+ fillx : scalar, optional
+ Filling value for the first argument, default is 0.
+ filly : scalar, optional
+ Filling value for the second argument, default is 0.
+
+ """
+
+ def __init__(self, mbfunc, fillx=0, filly=0):
+ """
+ abfunc(fillx, filly) must be defined.
+
+ abfunc(x, filly) = x for all x to enable reduce.
+
+ """
+ super().__init__(mbfunc)
+ self.fillx = fillx
+ self.filly = filly
+ ufunc_domain[mbfunc] = None
+ ufunc_fills[mbfunc] = (fillx, filly)
+
+ def __call__(self, a, b, *args, **kwargs):
+ """
+ Execute the call behavior.
+
+ """
+ # Get the data, as ndarray
+ (da, db) = (getdata(a), getdata(b))
+ # Get the result
+ with np.errstate():
+ np.seterr(divide='ignore', invalid='ignore')
+ result = self.f(da, db, *args, **kwargs)
+ # Get the mask for the result
+ (ma, mb) = (getmask(a), getmask(b))
+ if ma is nomask:
+ if mb is nomask:
+ m = nomask
+ else:
+ m = umath.logical_or(getmaskarray(a), mb)
+ elif mb is nomask:
+ m = umath.logical_or(ma, getmaskarray(b))
+ else:
+ m = umath.logical_or(ma, mb)
+
+ # Case 1. : scalar
+ if not result.ndim:
+ if m:
+ return masked
+ return result
+
+ # Case 2. : array
+ # Revert result to da where masked
+ if m is not nomask and m.any():
+ # any errors, just abort; impossible to guarantee masked values
+ try:
+ np.copyto(result, da, casting='unsafe', where=m)
+ except Exception:
+ pass
+
+ # Transforms to a (subclass of) MaskedArray
+ masked_result = result.view(get_masked_subclass(a, b))
+ masked_result._mask = m
+ if isinstance(a, MaskedArray):
+ masked_result._update_from(a)
+ elif isinstance(b, MaskedArray):
+ masked_result._update_from(b)
+ return masked_result
+
+ def reduce(self, target, axis=0, dtype=None):
+ """
+ Reduce `target` along the given `axis`.
+
+ """
+ tclass = get_masked_subclass(target)
+ m = getmask(target)
+ t = filled(target, self.filly)
+ if t.shape == ():
+ t = t.reshape(1)
+ if m is not nomask:
+ m = make_mask(m, copy=True)
+ m.shape = (1,)
+
+ if m is nomask:
+ tr = self.f.reduce(t, axis)
+ mr = nomask
+ else:
+ tr = self.f.reduce(t, axis, dtype=dtype)
+ mr = umath.logical_and.reduce(m, axis)
+
+ if not tr.shape:
+ if mr:
+ return masked
+ else:
+ return tr
+ masked_tr = tr.view(tclass)
+ masked_tr._mask = mr
+ return masked_tr
+
+ def outer(self, a, b):
+ """
+ Return the function applied to the outer product of a and b.
+
+ """
+ (da, db) = (getdata(a), getdata(b))
+ d = self.f.outer(da, db)
+ ma = getmask(a)
+ mb = getmask(b)
+ if ma is nomask and mb is nomask:
+ m = nomask
+ else:
+ ma = getmaskarray(a)
+ mb = getmaskarray(b)
+ m = umath.logical_or.outer(ma, mb)
+ if (not m.ndim) and m:
+ return masked
+ if m is not nomask:
+ np.copyto(d, da, where=m)
+ if not d.shape:
+ return d
+ masked_d = d.view(get_masked_subclass(a, b))
+ masked_d._mask = m
+ return masked_d
+
+ def accumulate(self, target, axis=0):
+ """Accumulate `target` along `axis` after filling with y fill
+ value.
+
+ """
+ tclass = get_masked_subclass(target)
+ t = filled(target, self.filly)
+ result = self.f.accumulate(t, axis)
+ masked_result = result.view(tclass)
+ return masked_result
+
+
+
+class _DomainedBinaryOperation(_MaskedUFunc):
+ """
+ Define binary operations that have a domain, like divide.
+
+ They have no reduce, outer or accumulate.
+
+ Parameters
+ ----------
+ mbfunc : function
+ The function for which to define a masked version. Made available
+ as ``_DomainedBinaryOperation.f``.
+ domain : class instance
+ Default domain for the function. Should be one of the ``_Domain*``
+ classes.
+ fillx : scalar, optional
+ Filling value for the first argument, default is 0.
+ filly : scalar, optional
+ Filling value for the second argument, default is 0.
+
+ """
+
+ def __init__(self, dbfunc, domain, fillx=0, filly=0):
+ """abfunc(fillx, filly) must be defined.
+ abfunc(x, filly) = x for all x to enable reduce.
+ """
+ super().__init__(dbfunc)
+ self.domain = domain
+ self.fillx = fillx
+ self.filly = filly
+ ufunc_domain[dbfunc] = domain
+ ufunc_fills[dbfunc] = (fillx, filly)
+
+ def __call__(self, a, b, *args, **kwargs):
+ "Execute the call behavior."
+ # Get the data
+ (da, db) = (getdata(a), getdata(b))
+ # Get the result
+ with np.errstate(divide='ignore', invalid='ignore'):
+ result = self.f(da, db, *args, **kwargs)
+ # Get the mask as a combination of the source masks and invalid
+ m = ~umath.isfinite(result)
+ m |= getmask(a)
+ m |= getmask(b)
+ # Apply the domain
+ domain = ufunc_domain.get(self.f, None)
+ if domain is not None:
+ m |= domain(da, db)
+ # Take care of the scalar case first
+ if not m.ndim:
+ if m:
+ return masked
+ else:
+ return result
+ # When the mask is True, put back da if possible
+ # any errors, just abort; impossible to guarantee masked values
+ try:
+ np.copyto(result, 0, casting='unsafe', where=m)
+ # avoid using "*" since this may be overlaid
+ masked_da = umath.multiply(m, da)
+ # only add back if it can be cast safely
+ if np.can_cast(masked_da.dtype, result.dtype, casting='safe'):
+ result += masked_da
+ except Exception:
+ pass
+
+ # Transforms to a (subclass of) MaskedArray
+ masked_result = result.view(get_masked_subclass(a, b))
+ masked_result._mask = m
+ if isinstance(a, MaskedArray):
+ masked_result._update_from(a)
+ elif isinstance(b, MaskedArray):
+ masked_result._update_from(b)
+ return masked_result
+
+
+# Unary ufuncs
+exp = _MaskedUnaryOperation(umath.exp)
+conjugate = _MaskedUnaryOperation(umath.conjugate)
+sin = _MaskedUnaryOperation(umath.sin)
+cos = _MaskedUnaryOperation(umath.cos)
+arctan = _MaskedUnaryOperation(umath.arctan)
+arcsinh = _MaskedUnaryOperation(umath.arcsinh)
+sinh = _MaskedUnaryOperation(umath.sinh)
+cosh = _MaskedUnaryOperation(umath.cosh)
+tanh = _MaskedUnaryOperation(umath.tanh)
+abs = absolute = _MaskedUnaryOperation(umath.absolute)
+angle = _MaskedUnaryOperation(angle) # from numpy.lib.function_base
+fabs = _MaskedUnaryOperation(umath.fabs)
+negative = _MaskedUnaryOperation(umath.negative)
+floor = _MaskedUnaryOperation(umath.floor)
+ceil = _MaskedUnaryOperation(umath.ceil)
+around = _MaskedUnaryOperation(np.round_)
+logical_not = _MaskedUnaryOperation(umath.logical_not)
+
+# Domained unary ufuncs
+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,
+ _DomainTan(1e-35))
+arcsin = _MaskedUnaryOperation(umath.arcsin, 0.0,
+ _DomainCheckInterval(-1.0, 1.0))
+arccos = _MaskedUnaryOperation(umath.arccos, 0.0,
+ _DomainCheckInterval(-1.0, 1.0))
+arccosh = _MaskedUnaryOperation(umath.arccosh, 1.0,
+ _DomainGreaterEqual(1.0))
+arctanh = _MaskedUnaryOperation(umath.arctanh, 0.0,
+ _DomainCheckInterval(-1.0 + 1e-15, 1.0 - 1e-15))
+
+# Binary ufuncs
+add = _MaskedBinaryOperation(umath.add)
+subtract = _MaskedBinaryOperation(umath.subtract)
+multiply = _MaskedBinaryOperation(umath.multiply, 1, 1)
+arctan2 = _MaskedBinaryOperation(umath.arctan2, 0.0, 1.0)
+equal = _MaskedBinaryOperation(umath.equal)
+equal.reduce = None
+not_equal = _MaskedBinaryOperation(umath.not_equal)
+not_equal.reduce = None
+less_equal = _MaskedBinaryOperation(umath.less_equal)
+less_equal.reduce = None
+greater_equal = _MaskedBinaryOperation(umath.greater_equal)
+greater_equal.reduce = None
+less = _MaskedBinaryOperation(umath.less)
+less.reduce = None
+greater = _MaskedBinaryOperation(umath.greater)
+greater.reduce = None
+logical_and = _MaskedBinaryOperation(umath.logical_and)
+alltrue = _MaskedBinaryOperation(umath.logical_and, 1, 1).reduce
+logical_or = _MaskedBinaryOperation(umath.logical_or)
+sometrue = logical_or.reduce
+logical_xor = _MaskedBinaryOperation(umath.logical_xor)
+bitwise_and = _MaskedBinaryOperation(umath.bitwise_and)
+bitwise_or = _MaskedBinaryOperation(umath.bitwise_or)
+bitwise_xor = _MaskedBinaryOperation(umath.bitwise_xor)
+hypot = _MaskedBinaryOperation(umath.hypot)
+
+# Domained binary ufuncs
+divide = _DomainedBinaryOperation(umath.divide, _DomainSafeDivide(), 0, 1)
+true_divide = _DomainedBinaryOperation(umath.true_divide,
+ _DomainSafeDivide(), 0, 1)
+floor_divide = _DomainedBinaryOperation(umath.floor_divide,
+ _DomainSafeDivide(), 0, 1)
+remainder = _DomainedBinaryOperation(umath.remainder,
+ _DomainSafeDivide(), 0, 1)
+fmod = _DomainedBinaryOperation(umath.fmod, _DomainSafeDivide(), 0, 1)
+mod = _DomainedBinaryOperation(umath.mod, _DomainSafeDivide(), 0, 1)
+
+
+###############################################################################
+# Mask creation functions #
+###############################################################################
+
+
+def _replace_dtype_fields_recursive(dtype, primitive_dtype):
+ "Private function allowing recursion in _replace_dtype_fields."
+ _recurse = _replace_dtype_fields_recursive
+
+ # Do we have some name fields ?
+ if dtype.names is not None:
+ descr = []
+ for name in dtype.names:
+ field = dtype.fields[name]
+ if len(field) == 3:
+ # Prepend the title to the name
+ name = (field[-1], name)
+ descr.append((name, _recurse(field[0], primitive_dtype)))
+ new_dtype = np.dtype(descr)
+
+ # Is this some kind of composite a la (float,2)
+ elif dtype.subdtype:
+ descr = list(dtype.subdtype)
+ descr[0] = _recurse(dtype.subdtype[0], primitive_dtype)
+ new_dtype = np.dtype(tuple(descr))
+
+ # this is a primitive type, so do a direct replacement
+ else:
+ new_dtype = primitive_dtype
+
+ # preserve identity of dtypes
+ if new_dtype == dtype:
+ new_dtype = dtype
+
+ return new_dtype
+
+
+def _replace_dtype_fields(dtype, primitive_dtype):
+ """
+ Construct a dtype description list from a given dtype.
+
+ Returns a new dtype object, with all fields and subtypes in the given type
+ recursively replaced with `primitive_dtype`.
+
+ Arguments are coerced to dtypes first.
+ """
+ dtype = np.dtype(dtype)
+ primitive_dtype = np.dtype(primitive_dtype)
+ return _replace_dtype_fields_recursive(dtype, primitive_dtype)
+
+
+def make_mask_descr(ndtype):
+ """
+ Construct a dtype description list from a given dtype.
+
+ Returns a new dtype object, with the type of all fields in `ndtype` to a
+ boolean type. Field names are not altered.
+
+ Parameters
+ ----------
+ ndtype : dtype
+ The dtype to convert.
+
+ Returns
+ -------
+ result : dtype
+ A dtype that looks like `ndtype`, the type of all fields is boolean.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> dtype = np.dtype({'names':['foo', 'bar'],
+ ... 'formats':[np.float32, np.int64]})
+ >>> dtype
+ dtype([('foo', '<f4'), ('bar', '<i8')])
+ >>> ma.make_mask_descr(dtype)
+ dtype([('foo', '|b1'), ('bar', '|b1')])
+ >>> ma.make_mask_descr(np.float32)
+ dtype('bool')
+
+ """
+ return _replace_dtype_fields(ndtype, MaskType)
+
+
+def getmask(a):
+ """
+ Return the mask of a masked array, or nomask.
+
+ Return the mask of `a` as an ndarray if `a` is a `MaskedArray` and the
+ mask is not `nomask`, else return `nomask`. To guarantee a full array
+ of booleans of the same shape as a, use `getmaskarray`.
+
+ Parameters
+ ----------
+ a : array_like
+ Input `MaskedArray` for which the mask is required.
+
+ See Also
+ --------
+ getdata : Return the data of a masked array as an ndarray.
+ getmaskarray : Return the mask of a masked array, or full array of False.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> a = ma.masked_equal([[1,2],[3,4]], 2)
+ >>> a
+ masked_array(
+ data=[[1, --],
+ [3, 4]],
+ mask=[[False, True],
+ [False, False]],
+ fill_value=2)
+ >>> ma.getmask(a)
+ array([[False, True],
+ [False, False]])
+
+ Equivalently use the `MaskedArray` `mask` attribute.
+
+ >>> a.mask
+ array([[False, True],
+ [False, False]])
+
+ Result when mask == `nomask`
+
+ >>> b = ma.masked_array([[1,2],[3,4]])
+ >>> b
+ masked_array(
+ data=[[1, 2],
+ [3, 4]],
+ mask=False,
+ fill_value=999999)
+ >>> ma.nomask
+ False
+ >>> ma.getmask(b) == ma.nomask
+ True
+ >>> b.mask == ma.nomask
+ True
+
+ """
+ return getattr(a, '_mask', nomask)
+
+
+get_mask = getmask
+
+
+def getmaskarray(arr):
+ """
+ Return the mask of a masked array, or full boolean array of False.
+
+ Return the mask of `arr` as an ndarray if `arr` is a `MaskedArray` and
+ the mask is not `nomask`, else return a full boolean array of False of
+ the same shape as `arr`.
+
+ Parameters
+ ----------
+ arr : array_like
+ Input `MaskedArray` for which the mask is required.
+
+ See Also
+ --------
+ getmask : Return the mask of a masked array, or nomask.
+ getdata : Return the data of a masked array as an ndarray.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> a = ma.masked_equal([[1,2],[3,4]], 2)
+ >>> a
+ masked_array(
+ data=[[1, --],
+ [3, 4]],
+ mask=[[False, True],
+ [False, False]],
+ fill_value=2)
+ >>> ma.getmaskarray(a)
+ array([[False, True],
+ [False, False]])
+
+ Result when mask == ``nomask``
+
+ >>> b = ma.masked_array([[1,2],[3,4]])
+ >>> b
+ masked_array(
+ data=[[1, 2],
+ [3, 4]],
+ mask=False,
+ fill_value=999999)
+ >>> ma.getmaskarray(b)
+ array([[False, False],
+ [False, False]])
+
+ """
+ mask = getmask(arr)
+ if mask is nomask:
+ mask = make_mask_none(np.shape(arr), getattr(arr, 'dtype', None))
+ return mask
+
+
+def is_mask(m):
+ """
+ Return True if m is a valid, standard mask.
+
+ This function does not check the contents of the input, only that the
+ type is MaskType. In particular, this function returns False if the
+ mask has a flexible dtype.
+
+ Parameters
+ ----------
+ m : array_like
+ Array to test.
+
+ Returns
+ -------
+ result : bool
+ True if `m.dtype.type` is MaskType, False otherwise.
+
+ See Also
+ --------
+ ma.isMaskedArray : Test whether input is an instance of MaskedArray.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> m = ma.masked_equal([0, 1, 0, 2, 3], 0)
+ >>> m
+ masked_array(data=[--, 1, --, 2, 3],
+ mask=[ True, False, True, False, False],
+ fill_value=0)
+ >>> ma.is_mask(m)
+ False
+ >>> ma.is_mask(m.mask)
+ True
+
+ Input must be an ndarray (or have similar attributes)
+ for it to be considered a valid mask.
+
+ >>> m = [False, True, False]
+ >>> ma.is_mask(m)
+ False
+ >>> m = np.array([False, True, False])
+ >>> m
+ array([False, True, False])
+ >>> ma.is_mask(m)
+ True
+
+ Arrays with complex dtypes don't return True.
+
+ >>> dtype = np.dtype({'names':['monty', 'pithon'],
+ ... 'formats':[bool, bool]})
+ >>> dtype
+ dtype([('monty', '|b1'), ('pithon', '|b1')])
+ >>> m = np.array([(True, False), (False, True), (True, False)],
+ ... dtype=dtype)
+ >>> m
+ array([( True, False), (False, True), ( True, False)],
+ dtype=[('monty', '?'), ('pithon', '?')])
+ >>> ma.is_mask(m)
+ False
+
+ """
+ try:
+ return m.dtype.type is MaskType
+ except AttributeError:
+ return False
+
+
+def _shrink_mask(m):
+ """
+ Shrink a mask to nomask if possible
+ """
+ if m.dtype.names is None and not m.any():
+ return nomask
+ else:
+ return m
+
+
+def make_mask(m, copy=False, shrink=True, dtype=MaskType):
+ """
+ Create a boolean mask from an array.
+
+ Return `m` as a boolean mask, creating a copy if necessary or requested.
+ The function can accept any sequence that is convertible to integers,
+ or ``nomask``. Does not require that contents must be 0s and 1s, values
+ of 0 are interpreted as False, everything else as True.
+
+ Parameters
+ ----------
+ m : array_like
+ Potential mask.
+ copy : bool, optional
+ Whether to return a copy of `m` (True) or `m` itself (False).
+ shrink : bool, optional
+ Whether to shrink `m` to ``nomask`` if all its values are False.
+ dtype : dtype, optional
+ Data-type of the output mask. By default, the output mask has a
+ dtype of MaskType (bool). If the dtype is flexible, each field has
+ a boolean dtype. This is ignored when `m` is ``nomask``, in which
+ case ``nomask`` is always returned.
+
+ Returns
+ -------
+ result : ndarray
+ A boolean mask derived from `m`.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> m = [True, False, True, True]
+ >>> ma.make_mask(m)
+ array([ True, False, True, True])
+ >>> m = [1, 0, 1, 1]
+ >>> ma.make_mask(m)
+ array([ True, False, True, True])
+ >>> m = [1, 0, 2, -3]
+ >>> ma.make_mask(m)
+ array([ True, False, True, True])
+
+ Effect of the `shrink` parameter.
+
+ >>> m = np.zeros(4)
+ >>> m
+ array([0., 0., 0., 0.])
+ >>> ma.make_mask(m)
+ False
+ >>> ma.make_mask(m, shrink=False)
+ array([False, False, False, False])
+
+ Using a flexible `dtype`.
+
+ >>> m = [1, 0, 1, 1]
+ >>> n = [0, 1, 0, 0]
+ >>> arr = []
+ >>> for man, mouse in zip(m, n):
+ ... arr.append((man, mouse))
+ >>> arr
+ [(1, 0), (0, 1), (1, 0), (1, 0)]
+ >>> dtype = np.dtype({'names':['man', 'mouse'],
+ ... 'formats':[np.int64, np.int64]})
+ >>> arr = np.array(arr, dtype=dtype)
+ >>> arr
+ array([(1, 0), (0, 1), (1, 0), (1, 0)],
+ dtype=[('man', '<i8'), ('mouse', '<i8')])
+ >>> ma.make_mask(arr, dtype=dtype)
+ array([(True, False), (False, True), (True, False), (True, False)],
+ dtype=[('man', '|b1'), ('mouse', '|b1')])
+
+ """
+ if m is nomask:
+ return nomask
+
+ # Make sure the input dtype is valid.
+ dtype = make_mask_descr(dtype)
+
+ # legacy boolean special case: "existence of fields implies true"
+ if isinstance(m, ndarray) and m.dtype.fields and dtype == np.bool_:
+ return np.ones(m.shape, dtype=dtype)
+
+ # Fill the mask in case there are missing data; turn it into an ndarray.
+ result = np.array(filled(m, True), copy=copy, dtype=dtype, subok=True)
+ # Bas les masques !
+ if shrink:
+ result = _shrink_mask(result)
+ return result
+
+
+def make_mask_none(newshape, dtype=None):
+ """
+ Return a boolean mask of the given shape, filled with False.
+
+ This function returns a boolean ndarray with all entries False, that can
+ be used in common mask manipulations. If a complex dtype is specified, the
+ type of each field is converted to a boolean type.
+
+ Parameters
+ ----------
+ newshape : tuple
+ A tuple indicating the shape of the mask.
+ dtype : {None, dtype}, optional
+ If None, use a MaskType instance. Otherwise, use a new datatype with
+ the same fields as `dtype`, converted to boolean types.
+
+ Returns
+ -------
+ result : ndarray
+ An ndarray of appropriate shape and dtype, filled with False.
+
+ See Also
+ --------
+ make_mask : Create a boolean mask from an array.
+ make_mask_descr : Construct a dtype description list from a given dtype.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> ma.make_mask_none((3,))
+ array([False, False, False])
+
+ Defining a more complex dtype.
+
+ >>> dtype = np.dtype({'names':['foo', 'bar'],
+ ... 'formats':[np.float32, np.int64]})
+ >>> dtype
+ dtype([('foo', '<f4'), ('bar', '<i8')])
+ >>> ma.make_mask_none((3,), dtype=dtype)
+ array([(False, False), (False, False), (False, False)],
+ dtype=[('foo', '|b1'), ('bar', '|b1')])
+
+ """
+ if dtype is None:
+ result = np.zeros(newshape, dtype=MaskType)
+ else:
+ result = np.zeros(newshape, dtype=make_mask_descr(dtype))
+ return result
+
+
+def _recursive_mask_or(m1, m2, newmask):
+ names = m1.dtype.names
+ for name in names:
+ current1 = m1[name]
+ if current1.dtype.names is not None:
+ _recursive_mask_or(current1, m2[name], newmask[name])
+ else:
+ umath.logical_or(current1, m2[name], newmask[name])
+
+
+def mask_or(m1, m2, copy=False, shrink=True):
+ """
+ Combine two masks with the ``logical_or`` operator.
+
+ The result may be a view on `m1` or `m2` if the other is `nomask`
+ (i.e. False).
+
+ Parameters
+ ----------
+ m1, m2 : array_like
+ Input masks.
+ copy : bool, optional
+ If copy is False and one of the inputs is `nomask`, return a view
+ of the other input mask. Defaults to False.
+ shrink : bool, optional
+ Whether to shrink the output to `nomask` if all its values are
+ False. Defaults to True.
+
+ Returns
+ -------
+ mask : output mask
+ The result masks values that are masked in either `m1` or `m2`.
+
+ Raises
+ ------
+ ValueError
+ If `m1` and `m2` have different flexible dtypes.
+
+ Examples
+ --------
+ >>> m1 = np.ma.make_mask([0, 1, 1, 0])
+ >>> m2 = np.ma.make_mask([1, 0, 0, 0])
+ >>> np.ma.mask_or(m1, m2)
+ array([ True, True, True, False])
+
+ """
+
+ if (m1 is nomask) or (m1 is False):
+ dtype = getattr(m2, 'dtype', MaskType)
+ return make_mask(m2, copy=copy, shrink=shrink, dtype=dtype)
+ if (m2 is nomask) or (m2 is False):
+ dtype = getattr(m1, 'dtype', MaskType)
+ return make_mask(m1, copy=copy, shrink=shrink, dtype=dtype)
+ if m1 is m2 and is_mask(m1):
+ return m1
+ (dtype1, dtype2) = (getattr(m1, 'dtype', None), getattr(m2, 'dtype', None))
+ if dtype1 != dtype2:
+ raise ValueError("Incompatible dtypes '%s'<>'%s'" % (dtype1, dtype2))
+ if dtype1.names is not None:
+ # Allocate an output mask array with the properly broadcast shape.
+ newmask = np.empty(np.broadcast(m1, m2).shape, dtype1)
+ _recursive_mask_or(m1, m2, newmask)
+ return newmask
+ return make_mask(umath.logical_or(m1, m2), copy=copy, shrink=shrink)
+
+
+def flatten_mask(mask):
+ """
+ Returns a completely flattened version of the mask, where nested fields
+ are collapsed.
+
+ Parameters
+ ----------
+ mask : array_like
+ Input array, which will be interpreted as booleans.
+
+ Returns
+ -------
+ flattened_mask : ndarray of bools
+ The flattened input.
+
+ Examples
+ --------
+ >>> mask = np.array([0, 0, 1])
+ >>> np.ma.flatten_mask(mask)
+ array([False, False, True])
+
+ >>> mask = np.array([(0, 0), (0, 1)], dtype=[('a', bool), ('b', bool)])
+ >>> np.ma.flatten_mask(mask)
+ array([False, False, False, True])
+
+ >>> mdtype = [('a', bool), ('b', [('ba', bool), ('bb', bool)])]
+ >>> mask = np.array([(0, (0, 0)), (0, (0, 1))], dtype=mdtype)
+ >>> np.ma.flatten_mask(mask)
+ array([False, False, False, False, False, True])
+
+ """
+
+ def _flatmask(mask):
+ "Flatten the mask and returns a (maybe nested) sequence of booleans."
+ mnames = mask.dtype.names
+ if mnames is not None:
+ return [flatten_mask(mask[name]) for name in mnames]
+ else:
+ return mask
+
+ def _flatsequence(sequence):
+ "Generates a flattened version of the sequence."
+ try:
+ for element in sequence:
+ if hasattr(element, '__iter__'):
+ yield from _flatsequence(element)
+ else:
+ yield element
+ except TypeError:
+ yield sequence
+
+ mask = np.asarray(mask)
+ flattened = _flatsequence(_flatmask(mask))
+ return np.array([_ for _ in flattened], dtype=bool)
+
+
+def _check_mask_axis(mask, axis, keepdims=np._NoValue):
+ "Check whether there are masked values along the given axis"
+ kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
+ if mask is not nomask:
+ return mask.all(axis=axis, **kwargs)
+ return nomask
+
+
+###############################################################################
+# Masking functions #
+###############################################################################
+
+def masked_where(condition, a, copy=True):
+ """
+ Mask an array where a condition is met.
+
+ Return `a` as an array masked where `condition` is True.
+ Any masked values of `a` or `condition` are also masked in the output.
+
+ Parameters
+ ----------
+ condition : array_like
+ Masking condition. When `condition` tests floating point values for
+ equality, consider using ``masked_values`` instead.
+ a : array_like
+ Array to mask.
+ copy : bool
+ If True (default) make a copy of `a` in the result. If False modify
+ `a` in place and return a view.
+
+ Returns
+ -------
+ result : MaskedArray
+ The result of masking `a` where `condition` is True.
+
+ See Also
+ --------
+ masked_values : Mask using floating point equality.
+ masked_equal : Mask where equal to a given value.
+ masked_not_equal : Mask where `not` equal to a given value.
+ masked_less_equal : Mask where less than or equal to a given value.
+ masked_greater_equal : Mask where greater than or equal to a given value.
+ masked_less : Mask where less than a given value.
+ masked_greater : Mask where greater than a given value.
+ masked_inside : Mask inside a given interval.
+ masked_outside : Mask outside a given interval.
+ masked_invalid : Mask invalid values (NaNs or infs).
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> a = np.arange(4)
+ >>> a
+ array([0, 1, 2, 3])
+ >>> ma.masked_where(a <= 2, a)
+ masked_array(data=[--, --, --, 3],
+ mask=[ True, True, True, False],
+ fill_value=999999)
+
+ Mask array `b` conditional on `a`.
+
+ >>> b = ['a', 'b', 'c', 'd']
+ >>> ma.masked_where(a == 2, b)
+ masked_array(data=['a', 'b', --, 'd'],
+ mask=[False, False, True, False],
+ fill_value='N/A',
+ dtype='<U1')
+
+ Effect of the `copy` argument.
+
+ >>> c = ma.masked_where(a <= 2, a)
+ >>> c
+ masked_array(data=[--, --, --, 3],
+ mask=[ True, True, True, False],
+ fill_value=999999)
+ >>> c[0] = 99
+ >>> c
+ masked_array(data=[99, --, --, 3],
+ mask=[False, True, True, False],
+ fill_value=999999)
+ >>> a
+ array([0, 1, 2, 3])
+ >>> c = ma.masked_where(a <= 2, a, copy=False)
+ >>> c[0] = 99
+ >>> c
+ masked_array(data=[99, --, --, 3],
+ mask=[False, True, True, False],
+ fill_value=999999)
+ >>> a
+ array([99, 1, 2, 3])
+
+ When `condition` or `a` contain masked values.
+
+ >>> a = np.arange(4)
+ >>> a = ma.masked_where(a == 2, a)
+ >>> a
+ masked_array(data=[0, 1, --, 3],
+ mask=[False, False, True, False],
+ fill_value=999999)
+ >>> b = np.arange(4)
+ >>> b = ma.masked_where(b == 0, b)
+ >>> b
+ masked_array(data=[--, 1, 2, 3],
+ mask=[ True, False, False, False],
+ fill_value=999999)
+ >>> ma.masked_where(a == 3, b)
+ masked_array(data=[--, 1, --, --],
+ mask=[ True, False, True, True],
+ fill_value=999999)
+
+ """
+ # Make sure that condition is a valid standard-type mask.
+ cond = make_mask(condition, shrink=False)
+ a = np.array(a, copy=copy, subok=True)
+
+ (cshape, ashape) = (cond.shape, a.shape)
+ if cshape and cshape != ashape:
+ raise IndexError("Inconsistent shape between the condition and the input"
+ " (got %s and %s)" % (cshape, ashape))
+ if hasattr(a, '_mask'):
+ cond = mask_or(cond, a._mask)
+ cls = type(a)
+ else:
+ cls = MaskedArray
+ result = a.view(cls)
+ # Assign to *.mask so that structured masks are handled correctly.
+ result.mask = _shrink_mask(cond)
+ # There is no view of a boolean so when 'a' is a MaskedArray with nomask
+ # the update to the result's mask has no effect.
+ if not copy and hasattr(a, '_mask') and getmask(a) is nomask:
+ a._mask = result._mask.view()
+ return result
+
+
+def masked_greater(x, value, copy=True):
+ """
+ Mask an array where greater than a given value.
+
+ This function is a shortcut to ``masked_where``, with
+ `condition` = (x > value).
+
+ See Also
+ --------
+ masked_where : Mask where a condition is met.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> a = np.arange(4)
+ >>> a
+ array([0, 1, 2, 3])
+ >>> ma.masked_greater(a, 2)
+ masked_array(data=[0, 1, 2, --],
+ mask=[False, False, False, True],
+ fill_value=999999)
+
+ """
+ return masked_where(greater(x, value), x, copy=copy)
+
+
+def masked_greater_equal(x, value, copy=True):
+ """
+ Mask an array where greater than or equal to a given value.
+
+ This function is a shortcut to ``masked_where``, with
+ `condition` = (x >= value).
+
+ See Also
+ --------
+ masked_where : Mask where a condition is met.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> a = np.arange(4)
+ >>> a
+ array([0, 1, 2, 3])
+ >>> ma.masked_greater_equal(a, 2)
+ masked_array(data=[0, 1, --, --],
+ mask=[False, False, True, True],
+ fill_value=999999)
+
+ """
+ return masked_where(greater_equal(x, value), x, copy=copy)
+
+
+def masked_less(x, value, copy=True):
+ """
+ Mask an array where less than a given value.
+
+ This function is a shortcut to ``masked_where``, with
+ `condition` = (x < value).
+
+ See Also
+ --------
+ masked_where : Mask where a condition is met.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> a = np.arange(4)
+ >>> a
+ array([0, 1, 2, 3])
+ >>> ma.masked_less(a, 2)
+ masked_array(data=[--, --, 2, 3],
+ mask=[ True, True, False, False],
+ fill_value=999999)
+
+ """
+ return masked_where(less(x, value), x, copy=copy)
+
+
+def masked_less_equal(x, value, copy=True):
+ """
+ Mask an array where less than or equal to a given value.
+
+ This function is a shortcut to ``masked_where``, with
+ `condition` = (x <= value).
+
+ See Also
+ --------
+ masked_where : Mask where a condition is met.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> a = np.arange(4)
+ >>> a
+ array([0, 1, 2, 3])
+ >>> ma.masked_less_equal(a, 2)
+ masked_array(data=[--, --, --, 3],
+ mask=[ True, True, True, False],
+ fill_value=999999)
+
+ """
+ return masked_where(less_equal(x, value), x, copy=copy)
+
+
+def masked_not_equal(x, value, copy=True):
+ """
+ Mask an array where `not` equal to a given value.
+
+ This function is a shortcut to ``masked_where``, with
+ `condition` = (x != value).
+
+ See Also
+ --------
+ masked_where : Mask where a condition is met.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> a = np.arange(4)
+ >>> a
+ array([0, 1, 2, 3])
+ >>> ma.masked_not_equal(a, 2)
+ masked_array(data=[--, --, 2, --],
+ mask=[ True, True, False, True],
+ fill_value=999999)
+
+ """
+ return masked_where(not_equal(x, value), x, copy=copy)
+
+
+def masked_equal(x, value, copy=True):
+ """
+ Mask an array where equal to a given value.
+
+ Return a MaskedArray, masked where the data in array `x` are
+ equal to `value`. The fill_value of the returned MaskedArray
+ is set to `value`.
+
+ For floating point arrays, consider using ``masked_values(x, value)``.
+
+ See Also
+ --------
+ masked_where : Mask where a condition is met.
+ masked_values : Mask using floating point equality.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> a = np.arange(4)
+ >>> a
+ array([0, 1, 2, 3])
+ >>> ma.masked_equal(a, 2)
+ masked_array(data=[0, 1, --, 3],
+ mask=[False, False, True, False],
+ fill_value=2)
+
+ """
+ output = masked_where(equal(x, value), x, copy=copy)
+ output.fill_value = value
+ return output
+
+
+def masked_inside(x, v1, v2, copy=True):
+ """
+ Mask an array inside a given interval.
+
+ Shortcut to ``masked_where``, where `condition` is True for `x` inside
+ the interval [v1,v2] (v1 <= x <= v2). The boundaries `v1` and `v2`
+ can be given in either order.
+
+ See Also
+ --------
+ masked_where : Mask where a condition is met.
+
+ Notes
+ -----
+ The array `x` is prefilled with its filling value.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> x = [0.31, 1.2, 0.01, 0.2, -0.4, -1.1]
+ >>> ma.masked_inside(x, -0.3, 0.3)
+ masked_array(data=[0.31, 1.2, --, --, -0.4, -1.1],
+ mask=[False, False, True, True, False, False],
+ fill_value=1e+20)
+
+ The order of `v1` and `v2` doesn't matter.
+
+ >>> ma.masked_inside(x, 0.3, -0.3)
+ masked_array(data=[0.31, 1.2, --, --, -0.4, -1.1],
+ mask=[False, False, True, True, False, False],
+ fill_value=1e+20)
+
+ """
+ if v2 < v1:
+ (v1, v2) = (v2, v1)
+ xf = filled(x)
+ condition = (xf >= v1) & (xf <= v2)
+ return masked_where(condition, x, copy=copy)
+
+
+def masked_outside(x, v1, v2, copy=True):
+ """
+ Mask an array outside a given interval.
+
+ Shortcut to ``masked_where``, where `condition` is True for `x` outside
+ the interval [v1,v2] (x < v1)|(x > v2).
+ The boundaries `v1` and `v2` can be given in either order.
+
+ See Also
+ --------
+ masked_where : Mask where a condition is met.
+
+ Notes
+ -----
+ The array `x` is prefilled with its filling value.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> x = [0.31, 1.2, 0.01, 0.2, -0.4, -1.1]
+ >>> ma.masked_outside(x, -0.3, 0.3)
+ masked_array(data=[--, --, 0.01, 0.2, --, --],
+ mask=[ True, True, False, False, True, True],
+ fill_value=1e+20)
+
+ The order of `v1` and `v2` doesn't matter.
+
+ >>> ma.masked_outside(x, 0.3, -0.3)
+ masked_array(data=[--, --, 0.01, 0.2, --, --],
+ mask=[ True, True, False, False, True, True],
+ fill_value=1e+20)
+
+ """
+ if v2 < v1:
+ (v1, v2) = (v2, v1)
+ xf = filled(x)
+ condition = (xf < v1) | (xf > v2)
+ return masked_where(condition, x, copy=copy)
+
+
+def masked_object(x, value, copy=True, shrink=True):
+ """
+ Mask the array `x` where the data are exactly equal to value.
+
+ This function is similar to `masked_values`, but only suitable
+ for object arrays: for floating point, use `masked_values` instead.
+
+ Parameters
+ ----------
+ x : array_like
+ Array to mask
+ value : object
+ Comparison value
+ copy : {True, False}, optional
+ Whether to return a copy of `x`.
+ shrink : {True, False}, optional
+ Whether to collapse a mask full of False to nomask
+
+ Returns
+ -------
+ result : MaskedArray
+ The result of masking `x` where equal to `value`.
+
+ See Also
+ --------
+ masked_where : Mask where a condition is met.
+ masked_equal : Mask where equal to a given value (integers).
+ masked_values : Mask using floating point equality.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> food = np.array(['green_eggs', 'ham'], dtype=object)
+ >>> # don't eat spoiled food
+ >>> eat = ma.masked_object(food, 'green_eggs')
+ >>> eat
+ masked_array(data=[--, 'ham'],
+ mask=[ True, False],
+ fill_value='green_eggs',
+ dtype=object)
+ >>> # plain ol` ham is boring
+ >>> fresh_food = np.array(['cheese', 'ham', 'pineapple'], dtype=object)
+ >>> eat = ma.masked_object(fresh_food, 'green_eggs')
+ >>> eat
+ masked_array(data=['cheese', 'ham', 'pineapple'],
+ mask=False,
+ fill_value='green_eggs',
+ dtype=object)
+
+ Note that `mask` is set to ``nomask`` if possible.
+
+ >>> eat
+ masked_array(data=['cheese', 'ham', 'pineapple'],
+ mask=False,
+ fill_value='green_eggs',
+ dtype=object)
+
+ """
+ if isMaskedArray(x):
+ condition = umath.equal(x._data, value)
+ mask = x._mask
+ else:
+ condition = umath.equal(np.asarray(x), value)
+ mask = nomask
+ mask = mask_or(mask, make_mask(condition, shrink=shrink))
+ return masked_array(x, mask=mask, copy=copy, fill_value=value)
+
+
+def masked_values(x, value, rtol=1e-5, atol=1e-8, copy=True, shrink=True):
+ """
+ Mask using floating point equality.
+
+ Return a MaskedArray, masked where the data in array `x` are approximately
+ equal to `value`, determined using `isclose`. The default tolerances for
+ `masked_values` are the same as those for `isclose`.
+
+ For integer types, exact equality is used, in the same way as
+ `masked_equal`.
+
+ The fill_value is set to `value` and the mask is set to ``nomask`` if
+ possible.
+
+ Parameters
+ ----------
+ x : array_like
+ Array to mask.
+ value : float
+ Masking value.
+ rtol, atol : float, optional
+ Tolerance parameters passed on to `isclose`
+ copy : bool, optional
+ Whether to return a copy of `x`.
+ shrink : bool, optional
+ Whether to collapse a mask full of False to ``nomask``.
+
+ Returns
+ -------
+ result : MaskedArray
+ The result of masking `x` where approximately equal to `value`.
+
+ See Also
+ --------
+ masked_where : Mask where a condition is met.
+ masked_equal : Mask where equal to a given value (integers).
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> x = np.array([1, 1.1, 2, 1.1, 3])
+ >>> ma.masked_values(x, 1.1)
+ masked_array(data=[1.0, --, 2.0, --, 3.0],
+ mask=[False, True, False, True, False],
+ fill_value=1.1)
+
+ Note that `mask` is set to ``nomask`` if possible.
+
+ >>> ma.masked_values(x, 2.1)
+ masked_array(data=[1. , 1.1, 2. , 1.1, 3. ],
+ mask=False,
+ fill_value=2.1)
+
+ Unlike `masked_equal`, `masked_values` can perform approximate equalities.
+
+ >>> ma.masked_values(x, 2.1, atol=1e-1)
+ masked_array(data=[1.0, 1.1, --, 1.1, 3.0],
+ mask=[False, False, True, False, False],
+ fill_value=2.1)
+
+ """
+ xnew = filled(x, value)
+ if np.issubdtype(xnew.dtype, np.floating):
+ mask = np.isclose(xnew, value, atol=atol, rtol=rtol)
+ else:
+ mask = umath.equal(xnew, value)
+ ret = masked_array(xnew, mask=mask, copy=copy, fill_value=value)
+ if shrink:
+ ret.shrink_mask()
+ return ret
+
+
+def masked_invalid(a, copy=True):
+ """
+ Mask an array where invalid values occur (NaNs or infs).
+
+ This function is a shortcut to ``masked_where``, with
+ `condition` = ~(np.isfinite(a)). Any pre-existing mask is conserved.
+ Only applies to arrays with a dtype where NaNs or infs make sense
+ (i.e. floating point types), but accepts any array_like object.
+
+ See Also
+ --------
+ masked_where : Mask where a condition is met.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> a = np.arange(5, dtype=float)
+ >>> a[2] = np.NaN
+ >>> a[3] = np.PINF
+ >>> a
+ array([ 0., 1., nan, inf, 4.])
+ >>> ma.masked_invalid(a)
+ masked_array(data=[0.0, 1.0, --, --, 4.0],
+ mask=[False, False, True, True, False],
+ fill_value=1e+20)
+
+ """
+ a = np.array(a, copy=False, subok=True)
+ res = masked_where(~(np.isfinite(a)), a, copy=copy)
+ # masked_invalid previously never returned nomask as a mask and doing so
+ # threw off matplotlib (gh-22842). So use shrink=False:
+ if res._mask is nomask:
+ res._mask = make_mask_none(res.shape, res.dtype)
+ return res
+
+###############################################################################
+# Printing options #
+###############################################################################
+
+
+class _MaskedPrintOption:
+ """
+ Handle the string used to represent missing data in a masked array.
+
+ """
+
+ def __init__(self, display):
+ """
+ Create the masked_print_option object.
+
+ """
+ self._display = display
+ self._enabled = True
+
+ def display(self):
+ """
+ Display the string to print for masked values.
+
+ """
+ return self._display
+
+ def set_display(self, s):
+ """
+ Set the string to print for masked values.
+
+ """
+ self._display = s
+
+ def enabled(self):
+ """
+ Is the use of the display value enabled?
+
+ """
+ return self._enabled
+
+ def enable(self, shrink=1):
+ """
+ Set the enabling shrink to `shrink`.
+
+ """
+ self._enabled = shrink
+
+ def __str__(self):
+ return str(self._display)
+
+ __repr__ = __str__
+
+# if you single index into a masked location you get this object.
+masked_print_option = _MaskedPrintOption('--')
+
+
+def _recursive_printoption(result, mask, printopt):
+ """
+ Puts printoptions in result where mask is True.
+
+ Private function allowing for recursion
+
+ """
+ names = result.dtype.names
+ if names is not None:
+ for name in names:
+ curdata = result[name]
+ curmask = mask[name]
+ _recursive_printoption(curdata, curmask, printopt)
+ else:
+ np.copyto(result, printopt, where=mask)
+ return
+
+# For better or worse, these end in a newline
+_legacy_print_templates = dict(
+ long_std=textwrap.dedent("""\
+ masked_%(name)s(data =
+ %(data)s,
+ %(nlen)s mask =
+ %(mask)s,
+ %(nlen)s fill_value = %(fill)s)
+ """),
+ long_flx=textwrap.dedent("""\
+ masked_%(name)s(data =
+ %(data)s,
+ %(nlen)s mask =
+ %(mask)s,
+ %(nlen)s fill_value = %(fill)s,
+ %(nlen)s dtype = %(dtype)s)
+ """),
+ short_std=textwrap.dedent("""\
+ masked_%(name)s(data = %(data)s,
+ %(nlen)s mask = %(mask)s,
+ %(nlen)s fill_value = %(fill)s)
+ """),
+ short_flx=textwrap.dedent("""\
+ masked_%(name)s(data = %(data)s,
+ %(nlen)s mask = %(mask)s,
+ %(nlen)s fill_value = %(fill)s,
+ %(nlen)s dtype = %(dtype)s)
+ """)
+)
+
+###############################################################################
+# MaskedArray class #
+###############################################################################
+
+
+def _recursive_filled(a, mask, fill_value):
+ """
+ Recursively fill `a` with `fill_value`.
+
+ """
+ names = a.dtype.names
+ for name in names:
+ current = a[name]
+ if current.dtype.names is not None:
+ _recursive_filled(current, mask[name], fill_value[name])
+ else:
+ np.copyto(current, fill_value[name], where=mask[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)
+ >>> np.ma.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__'):
+ yield from flatten_sequence(elm)
+ 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
+
+
+def _arraymethod(funcname, onmask=True):
+ """
+ Return a class method wrapper around a basic array method.
+
+ Creates a class method which returns a masked array, where the new
+ ``_data`` array is the output of the corresponding basic method called
+ on the original ``_data``.
+
+ If `onmask` is True, the new mask is the output of the method called
+ on the initial mask. Otherwise, the new mask is just a reference
+ to the initial mask.
+
+ Parameters
+ ----------
+ funcname : str
+ Name of the function to apply on data.
+ onmask : bool
+ Whether the mask must be processed also (True) or left
+ alone (False). Default is True. Make available as `_onmask`
+ attribute.
+
+ Returns
+ -------
+ method : instancemethod
+ Class method wrapper of the specified basic array method.
+
+ """
+ def wrapped_method(self, *args, **params):
+ result = getattr(self._data, funcname)(*args, **params)
+ result = result.view(type(self))
+ result._update_from(self)
+ mask = self._mask
+ if not onmask:
+ result.__setmask__(mask)
+ elif mask is not nomask:
+ # __setmask__ makes a copy, which we don't want
+ result._mask = getattr(mask, funcname)(*args, **params)
+ return result
+ methdoc = getattr(ndarray, funcname, None) or getattr(np, funcname, None)
+ if methdoc is not None:
+ wrapped_method.__doc__ = methdoc.__doc__
+ wrapped_method.__name__ = funcname
+ return wrapped_method
+
+
+class MaskedIterator:
+ """
+ Flat iterator object to iterate over masked arrays.
+
+ A `MaskedIterator` iterator is returned by ``x.flat`` for any masked array
+ `x`. It allows iterating over the array as if it were a 1-D array,
+ either in a for-loop or by calling its `next` method.
+
+ Iteration is done in C-contiguous style, with the last index varying the
+ fastest. The iterator can also be indexed using basic slicing or
+ advanced indexing.
+
+ See Also
+ --------
+ MaskedArray.flat : Return a flat iterator over an array.
+ MaskedArray.flatten : Returns a flattened copy of an array.
+
+ Notes
+ -----
+ `MaskedIterator` is not exported by the `ma` module. Instead of
+ instantiating a `MaskedIterator` directly, use `MaskedArray.flat`.
+
+ Examples
+ --------
+ >>> x = np.ma.array(arange(6).reshape(2, 3))
+ >>> fl = x.flat
+ >>> type(fl)
+ <class 'numpy.ma.core.MaskedIterator'>
+ >>> for item in fl:
+ ... print(item)
+ ...
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+
+ Extracting more than a single element b indexing the `MaskedIterator`
+ returns a masked array:
+
+ >>> fl[2:4]
+ masked_array(data = [2 3],
+ mask = False,
+ fill_value = 999999)
+
+ """
+
+ def __init__(self, ma):
+ self.ma = ma
+ self.dataiter = ma._data.flat
+
+ if ma._mask is nomask:
+ self.maskiter = None
+ else:
+ self.maskiter = ma._mask.flat
+
+ def __iter__(self):
+ return self
+
+ def __getitem__(self, indx):
+ result = self.dataiter.__getitem__(indx).view(type(self.ma))
+ if self.maskiter is not None:
+ _mask = self.maskiter.__getitem__(indx)
+ 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 if ravel makes a copy
+ def __setitem__(self, index, value):
+ self.dataiter[index] = getdata(value)
+ if self.maskiter is not None:
+ self.maskiter[index] = getmaskarray(value)
+
+ def __next__(self):
+ """
+ Return the next value, or raise StopIteration.
+
+ Examples
+ --------
+ >>> x = np.ma.array([3, 2], mask=[0, 1])
+ >>> fl = x.flat
+ >>> next(fl)
+ 3
+ >>> next(fl)
+ masked
+ >>> next(fl)
+ Traceback (most recent call last):
+ ...
+ StopIteration
+
+ """
+ d = next(self.dataiter)
+ 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
+
+
+class MaskedArray(ndarray):
+ """
+ An array class with possibly masked values.
+
+ Masked values of True exclude the corresponding element from any
+ computation.
+
+ Construction::
+
+ x = MaskedArray(data, mask=nomask, dtype=None, copy=False, subok=True,
+ ndmin=0, fill_value=None, keep_mask=True, hard_mask=None,
+ shrink=True, order=None)
+
+ Parameters
+ ----------
+ data : array_like
+ Input data.
+ mask : sequence, optional
+ Mask. Must be convertible to an array of booleans with the same
+ shape as `data`. True indicates a masked (i.e. invalid) data.
+ dtype : dtype, optional
+ Data type of the output.
+ If `dtype` is None, the type of the data argument (``data.dtype``)
+ is used. If `dtype` is not None and different from ``data.dtype``,
+ a copy is performed.
+ copy : bool, optional
+ Whether to copy the input data (True), or to use a reference instead.
+ Default is False.
+ subok : bool, optional
+ Whether to return a subclass of `MaskedArray` if possible (True) or a
+ plain `MaskedArray`. Default is True.
+ ndmin : int, optional
+ Minimum number of dimensions. Default is 0.
+ fill_value : scalar, optional
+ Value used to fill in the masked values when necessary.
+ If None, a default based on the data-type is used.
+ keep_mask : bool, optional
+ Whether to combine `mask` with the mask of the input data, if any
+ (True), or to use only `mask` for the output (False). Default is True.
+ hard_mask : bool, optional
+ Whether to use a hard mask or not. With a hard mask, masked values
+ cannot be unmasked. Default is False.
+ shrink : bool, optional
+ Whether to force compression of an empty mask. Default is True.
+ order : {'C', 'F', 'A'}, optional
+ Specify the order of the array. If order is 'C', then the array
+ will be in C-contiguous order (last-index varies the fastest).
+ If order is 'F', then the returned array will be in
+ Fortran-contiguous order (first-index varies the fastest).
+ If order is 'A' (default), then the returned array may be
+ in any order (either C-, Fortran-contiguous, or even discontiguous),
+ unless a copy is required, in which case it will be C-contiguous.
+
+ Examples
+ --------
+
+ The ``mask`` can be initialized with an array of boolean values
+ with the same shape as ``data``.
+
+ >>> data = np.arange(6).reshape((2, 3))
+ >>> np.ma.MaskedArray(data, mask=[[False, True, False],
+ ... [False, False, True]])
+ masked_array(
+ data=[[0, --, 2],
+ [3, 4, --]],
+ mask=[[False, True, False],
+ [False, False, True]],
+ fill_value=999999)
+
+ Alternatively, the ``mask`` can be initialized to homogeneous boolean
+ array with the same shape as ``data`` by passing in a scalar
+ boolean value:
+
+ >>> np.ma.MaskedArray(data, mask=False)
+ masked_array(
+ data=[[0, 1, 2],
+ [3, 4, 5]],
+ mask=[[False, False, False],
+ [False, False, False]],
+ fill_value=999999)
+
+ >>> np.ma.MaskedArray(data, mask=True)
+ masked_array(
+ data=[[--, --, --],
+ [--, --, --]],
+ mask=[[ True, True, True],
+ [ True, True, True]],
+ fill_value=999999,
+ dtype=int64)
+
+ .. note::
+ The recommended practice for initializing ``mask`` with a scalar
+ boolean value is to use ``True``/``False`` rather than
+ ``np.True_``/``np.False_``. The reason is :attr:`nomask`
+ is represented internally as ``np.False_``.
+
+ >>> np.False_ is np.ma.nomask
+ True
+
+ """
+
+ __array_priority__ = 15
+ _defaultmask = nomask
+ _defaulthardmask = False
+ _baseclass = ndarray
+
+ # Maximum number of elements per axis used when printing an array. The
+ # 1d case is handled separately because we need more values in this case.
+ _print_width = 100
+ _print_width_1d = 1500
+
+ def __new__(cls, data=None, mask=nomask, dtype=None, copy=False,
+ subok=True, ndmin=0, fill_value=None, keep_mask=True,
+ hard_mask=None, shrink=True, order=None):
+ """
+ Create a new masked array from scratch.
+
+ Notes
+ -----
+ A masked array can also be created by taking a .view(MaskedArray).
+
+ """
+ # Process data.
+ _data = np.array(data, dtype=dtype, copy=copy,
+ order=order, subok=True, ndmin=ndmin)
+ _baseclass = getattr(data, '_baseclass', type(_data))
+ # Check that we're not erasing the mask.
+ if isinstance(data, MaskedArray) and (data.shape != _data.shape):
+ copy = True
+
+ # Here, we copy the _view_, so that we can attach new properties to it
+ # we must never do .view(MaskedConstant), as that would create a new
+ # instance of np.ma.masked, which make identity comparison fail
+ if isinstance(data, cls) and subok and not isinstance(data, MaskedConstant):
+ _data = ndarray.view(_data, type(data))
+ else:
+ _data = ndarray.view(_data, cls)
+
+ # Handle the case where data is not a subclass of ndarray, but
+ # still has the _mask attribute like MaskedArrays
+ if hasattr(data, '_mask') and not isinstance(data, ndarray):
+ _data._mask = data._mask
+ # FIXME: should we set `_data._sharedmask = True`?
+ # Process mask.
+ # Type of the mask
+ mdtype = make_mask_descr(_data.dtype)
+
+ if mask is nomask:
+ # Case 1. : no mask in input.
+ # Erase the current mask ?
+ if not keep_mask:
+ # With a reduced version
+ if shrink:
+ _data._mask = nomask
+ # With full version
+ else:
+ _data._mask = np.zeros(_data.shape, dtype=mdtype)
+ # Check whether we missed something
+ elif isinstance(data, (tuple, list)):
+ try:
+ # If data is a sequence of masked array
+ mask = np.array(
+ [getmaskarray(np.asanyarray(m, dtype=_data.dtype))
+ for m in data], dtype=mdtype)
+ except ValueError:
+ # If data is nested
+ mask = nomask
+ # Force shrinking of the mask if needed (and possible)
+ if (mdtype == MaskType) and mask.any():
+ _data._mask = mask
+ _data._sharedmask = False
+ else:
+ _data._sharedmask = not copy
+ if copy:
+ _data._mask = _data._mask.copy()
+ # Reset the shape of the original mask
+ if getmask(data) is not nomask:
+ data._mask.shape = data.shape
+ else:
+ # Case 2. : With a mask in input.
+ # If mask is boolean, create an array of True or False
+ if mask is True and mdtype == MaskType:
+ mask = np.ones(_data.shape, dtype=mdtype)
+ elif mask is False and mdtype == MaskType:
+ mask = np.zeros(_data.shape, dtype=mdtype)
+ else:
+ # Read the mask with the current mdtype
+ try:
+ mask = np.array(mask, copy=copy, dtype=mdtype)
+ # Or assume it's a sequence of bool/int
+ except TypeError:
+ mask = np.array([tuple([m] * len(mdtype)) for m in mask],
+ dtype=mdtype)
+ # Make sure the mask and the data have the same shape
+ if mask.shape != _data.shape:
+ (nd, nm) = (_data.size, mask.size)
+ if nm == 1:
+ mask = np.resize(mask, _data.shape)
+ elif nm == nd:
+ mask = np.reshape(mask, _data.shape)
+ else:
+ msg = "Mask and data not compatible: data size is %i, " + \
+ "mask size is %i."
+ raise MaskError(msg % (nd, nm))
+ copy = True
+ # Set the mask to the new value
+ if _data._mask is nomask:
+ _data._mask = mask
+ _data._sharedmask = not copy
+ else:
+ if not keep_mask:
+ _data._mask = mask
+ _data._sharedmask = not copy
+ else:
+ if _data.dtype.names is not None:
+ def _recursive_or(a, b):
+ "do a|=b on each field of a, recursively"
+ for name in a.dtype.names:
+ (af, bf) = (a[name], b[name])
+ if af.dtype.names is not None:
+ _recursive_or(af, bf)
+ else:
+ af |= bf
+
+ _recursive_or(_data._mask, mask)
+ else:
+ _data._mask = np.logical_or(mask, _data._mask)
+ _data._sharedmask = False
+ # Update fill_value.
+ if fill_value is None:
+ fill_value = getattr(data, '_fill_value', None)
+ # But don't run the check unless we have something to check.
+ if fill_value is not None:
+ _data._fill_value = _check_fill_value(fill_value, _data.dtype)
+ # Process extra options ..
+ if hard_mask is None:
+ _data._hardmask = getattr(data, '_hardmask', False)
+ else:
+ _data._hardmask = hard_mask
+ _data._baseclass = _baseclass
+ return _data
+
+
+ def _update_from(self, obj):
+ """
+ Copies some attributes of obj to self.
+
+ """
+ if isinstance(obj, ndarray):
+ _baseclass = type(obj)
+ else:
+ _baseclass = ndarray
+ # We need to copy the _basedict to avoid backward propagation
+ _optinfo = {}
+ _optinfo.update(getattr(obj, '_optinfo', {}))
+ _optinfo.update(getattr(obj, '_basedict', {}))
+ if not isinstance(obj, MaskedArray):
+ _optinfo.update(getattr(obj, '__dict__', {}))
+ _dict = dict(_fill_value=getattr(obj, '_fill_value', None),
+ _hardmask=getattr(obj, '_hardmask', False),
+ _sharedmask=getattr(obj, '_sharedmask', False),
+ _isfield=getattr(obj, '_isfield', False),
+ _baseclass=getattr(obj, '_baseclass', _baseclass),
+ _optinfo=_optinfo,
+ _basedict=_optinfo)
+ self.__dict__.update(_dict)
+ self.__dict__.update(_optinfo)
+ return
+
+ def __array_finalize__(self, obj):
+ """
+ Finalizes the masked array.
+
+ """
+ # Get main attributes.
+ self._update_from(obj)
+
+ # We have to decide how to initialize self.mask, based on
+ # obj.mask. This is very difficult. There might be some
+ # correspondence between the elements in the array we are being
+ # created from (= obj) and us. Or there might not. This method can
+ # be called in all kinds of places for all kinds of reasons -- could
+ # be empty_like, could be slicing, could be a ufunc, could be a view.
+ # The numpy subclassing interface simply doesn't give us any way
+ # to know, which means that at best this method will be based on
+ # guesswork and heuristics. To make things worse, there isn't even any
+ # clear consensus about what the desired behavior is. For instance,
+ # most users think that np.empty_like(marr) -- which goes via this
+ # method -- should return a masked array with an empty mask (see
+ # gh-3404 and linked discussions), but others disagree, and they have
+ # existing code which depends on empty_like returning an array that
+ # matches the input mask.
+ #
+ # Historically our algorithm was: if the template object mask had the
+ # same *number of elements* as us, then we used *it's mask object
+ # itself* as our mask, so that writes to us would also write to the
+ # original array. This is horribly broken in multiple ways.
+ #
+ # Now what we do instead is, if the template object mask has the same
+ # number of elements as us, and we do not have the same base pointer
+ # as the template object (b/c views like arr[...] should keep the same
+ # mask), then we make a copy of the template object mask and use
+ # that. This is also horribly broken but somewhat less so. Maybe.
+ if isinstance(obj, ndarray):
+ # XX: This looks like a bug -- shouldn't it check self.dtype
+ # instead?
+ if obj.dtype.names is not None:
+ _mask = getmaskarray(obj)
+ else:
+ _mask = getmask(obj)
+
+ # If self and obj point to exactly the same data, then probably
+ # self is a simple view of obj (e.g., self = obj[...]), so they
+ # should share the same mask. (This isn't 100% reliable, e.g. self
+ # could be the first row of obj, or have strange strides, but as a
+ # heuristic it's not bad.) In all other cases, we make a copy of
+ # the mask, so that future modifications to 'self' do not end up
+ # side-effecting 'obj' as well.
+ if (_mask is not nomask and obj.__array_interface__["data"][0]
+ != self.__array_interface__["data"][0]):
+ # We should make a copy. But we could get here via astype,
+ # in which case the mask might need a new dtype as well
+ # (e.g., changing to or from a structured dtype), and the
+ # order could have changed. So, change the mask type if
+ # needed and use astype instead of copy.
+ if self.dtype == obj.dtype:
+ _mask_dtype = _mask.dtype
+ else:
+ _mask_dtype = make_mask_descr(self.dtype)
+
+ if self.flags.c_contiguous:
+ order = "C"
+ elif self.flags.f_contiguous:
+ order = "F"
+ else:
+ order = "K"
+
+ _mask = _mask.astype(_mask_dtype, order)
+ else:
+ # Take a view so shape changes, etc., do not propagate back.
+ _mask = _mask.view()
+ else:
+ _mask = nomask
+
+ self._mask = _mask
+ # Finalize the mask
+ if self._mask is not nomask:
+ try:
+ self._mask.shape = self.shape
+ except ValueError:
+ self._mask = nomask
+ except (TypeError, AttributeError):
+ # When _mask.shape is not writable (because it's a void)
+ pass
+
+ # Finalize the fill_value
+ if self._fill_value is not None:
+ self._fill_value = _check_fill_value(self._fill_value, self.dtype)
+ elif self.dtype.names is not None:
+ # Finalize the default fill_value for structured arrays
+ self._fill_value = _check_fill_value(None, self.dtype)
+
+ def __array_wrap__(self, obj, context=None):
+ """
+ Special hook for ufuncs.
+
+ Wraps the numpy array and sets the mask according to context.
+
+ """
+ if obj is self: # for in-place operations
+ result = obj
+ else:
+ result = obj.view(type(self))
+ result._update_from(self)
+
+ if context is not None:
+ result._mask = result._mask.copy()
+ func, args, out_i = context
+ # args sometimes contains outputs (gh-10459), which we don't want
+ input_args = args[:func.nin]
+ m = reduce(mask_or, [getmaskarray(arg) for arg in input_args])
+ # Get the domain mask
+ domain = ufunc_domain.get(func, None)
+ if domain is not None:
+ # Take the domain, and make sure it's a ndarray
+ with np.errstate(divide='ignore', invalid='ignore'):
+ d = filled(domain(*input_args), True)
+
+ if d.any():
+ # Fill the result where the domain is wrong
+ try:
+ # Binary domain: take the last value
+ fill_value = ufunc_fills[func][-1]
+ except TypeError:
+ # Unary domain: just use this one
+ fill_value = ufunc_fills[func]
+ except KeyError:
+ # Domain not recognized, use fill_value instead
+ fill_value = self.fill_value
+
+ np.copyto(result, fill_value, where=d)
+
+ # Update the mask
+ if m is nomask:
+ m = d
+ else:
+ # Don't modify inplace, we risk back-propagation
+ m = (m | d)
+
+ # Make sure the mask has the proper size
+ if result is not self and result.shape == () and m:
+ return masked
+ else:
+ result._mask = m
+ result._sharedmask = False
+
+ return result
+
+ 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, either ndarray or a subclass. The
+ default None results in type preservation.
+ fill_value : scalar, optional
+ The value to use for invalid entries (None by default).
+ If None, then this argument is inferred from the passed `dtype`, or
+ in its absence the original array, as discussed in the notes below.
+
+ See Also
+ --------
+ numpy.ndarray.view : Equivalent method on ndarray object.
+
+ 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.
+
+ For ``a.view(some_dtype)``, if ``some_dtype`` has a different number of
+ bytes per entry than the previous dtype (for example, converting a
+ regular array to a structured array), then the behavior of the view
+ cannot be predicted just from the superficial appearance of ``a`` (shown
+ by ``print(a)``). It also depends on exactly how ``a`` is stored in
+ memory. Therefore if ``a`` is C-ordered versus fortran-ordered, versus
+ defined as a slice or transpose, etc., the view may give different
+ results.
+ """
+
+ if dtype is None:
+ if type is None:
+ output = ndarray.view(self)
+ else:
+ output = ndarray.view(self, type)
+ elif type is None:
+ try:
+ if issubclass(dtype, ndarray):
+ output = ndarray.view(self, dtype)
+ dtype = None
+ else:
+ output = ndarray.view(self, dtype)
+ except TypeError:
+ output = ndarray.view(self, dtype)
+ else:
+ output = ndarray.view(self, dtype, type)
+
+ # also make the mask be a view (so attr changes to the view's
+ # mask do no affect original object's mask)
+ # (especially important to avoid affecting np.masked singleton)
+ if getmask(output) is not nomask:
+ output._mask = output._mask.view()
+
+ # Make sure to reset the _fill_value if needed
+ if getattr(output, '_fill_value', None) is not 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
+
+ def __getitem__(self, indx):
+ """
+ x.__getitem__(y) <==> x[y]
+
+ Return the item described by i, as a masked array.
+
+ """
+ # 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
+ # So it's easier to stick to the current version
+ dout = self.data[indx]
+ _mask = self._mask
+
+ def _is_scalar(m):
+ return not isinstance(m, np.ndarray)
+
+ def _scalar_heuristic(arr, elem):
+ """
+ Return whether `elem` is a scalar result of indexing `arr`, or None
+ if undecidable without promoting nomask to a full mask
+ """
+ # obviously a scalar
+ if not isinstance(elem, np.ndarray):
+ return True
+
+ # object array scalar indexing can return anything
+ elif arr.dtype.type is np.object_:
+ if arr.dtype is not elem.dtype:
+ # elem is an array, but dtypes do not match, so must be
+ # an element
+ return True
+
+ # well-behaved subclass that only returns 0d arrays when
+ # expected - this is not a scalar
+ elif type(arr).__getitem__ == ndarray.__getitem__:
+ return False
+
+ return None
+
+ if _mask is not nomask:
+ # _mask cannot be a subclass, so it tells us whether we should
+ # expect a scalar. It also cannot be of dtype object.
+ mout = _mask[indx]
+ scalar_expected = _is_scalar(mout)
+
+ else:
+ # attempt to apply the heuristic to avoid constructing a full mask
+ mout = nomask
+ scalar_expected = _scalar_heuristic(self.data, dout)
+ if scalar_expected is None:
+ # heuristics have failed
+ # construct a full array, so we can be certain. This is costly.
+ # we could also fall back on ndarray.__getitem__(self.data, indx)
+ scalar_expected = _is_scalar(getmaskarray(self)[indx])
+
+ # Did we extract a single item?
+ if scalar_expected:
+ # A record
+ if isinstance(dout, np.void):
+ # We should always re-cast to mvoid, otherwise users can
+ # change masks on rows that already have masked values, but not
+ # on rows that have no masked values, which is inconsistent.
+ return mvoid(dout, mask=mout, hardmask=self._hardmask)
+
+ # special case introduced in gh-5962
+ elif (self.dtype.type is np.object_ and
+ isinstance(dout, np.ndarray) and
+ dout is not masked):
+ # If masked, turn into a MaskedArray, with everything masked.
+ if mout:
+ return MaskedArray(dout, mask=True)
+ else:
+ return dout
+
+ # Just a scalar
+ else:
+ if mout:
+ return masked
+ else:
+ return dout
+ else:
+ # Force dout to MA
+ dout = dout.view(type(self))
+ # Inherit attributes from self
+ dout._update_from(self)
+ # Check the fill_value
+ if is_string_or_list_of_strings(indx):
+ if self._fill_value is not None:
+ dout._fill_value = self._fill_value[indx]
+
+ # Something like gh-15895 has happened if this check fails.
+ # _fill_value should always be an ndarray.
+ if not isinstance(dout._fill_value, np.ndarray):
+ raise RuntimeError('Internal NumPy error.')
+ # If we're indexing a multidimensional field in a
+ # structured array (such as dtype("(2,)i2,(2,)i1")),
+ # dimensionality goes up (M[field].ndim == M.ndim +
+ # M.dtype[field].ndim). That's fine for
+ # M[field] but problematic for M[field].fill_value
+ # which should have shape () to avoid breaking several
+ # methods. There is no great way out, so set to
+ # first element. See issue #6723.
+ if dout._fill_value.ndim > 0:
+ if not (dout._fill_value ==
+ dout._fill_value.flat[0]).all():
+ warnings.warn(
+ "Upon accessing multidimensional field "
+ f"{indx!s}, need to keep dimensionality "
+ "of fill_value at 0. Discarding "
+ "heterogeneous fill_value and setting "
+ f"all to {dout._fill_value[0]!s}.",
+ stacklevel=2)
+ # Need to use `.flat[0:1].squeeze(...)` instead of just
+ # `.flat[0]` to ensure the result is a 0d array and not
+ # a scalar.
+ dout._fill_value = dout._fill_value.flat[0:1].squeeze(axis=0)
+ dout._isfield = True
+ # Update the mask if needed
+ if mout is not nomask:
+ # set shape to match that of data; this is needed for matrices
+ dout._mask = reshape(mout, dout.shape)
+ dout._sharedmask = True
+ # Note: Don't try to check for m.any(), that'll take too long
+ return dout
+
+ # setitem may put NaNs into integer arrays or occasionally overflow a
+ # float. But this may happen in masked values, so avoid otherwise
+ # correct warnings (as is typical also in masked calculations).
+ @np.errstate(over='ignore', invalid='ignore')
+ def __setitem__(self, indx, value):
+ """
+ x.__setitem__(i, y) <==> x[i]=y
+
+ Set item described by index. If value is masked, masks those
+ locations.
+
+ """
+ if self is masked:
+ raise MaskError('Cannot alter the masked element.')
+ _data = self._data
+ _mask = self._mask
+ if isinstance(indx, str):
+ _data[indx] = value
+ if _mask is nomask:
+ self._mask = _mask = make_mask_none(self.shape, self.dtype)
+ _mask[indx] = getmask(value)
+ return
+
+ _dtype = _data.dtype
+
+ if value is masked:
+ # The mask wasn't set: create a full version.
+ if _mask is nomask:
+ _mask = self._mask = make_mask_none(self.shape, _dtype)
+ # Now, set the mask to its value.
+ if _dtype.names is not None:
+ _mask[indx] = tuple([True] * len(_dtype.names))
+ else:
+ _mask[indx] = True
+ return
+
+ # Get the _data part of the new value
+ dval = getattr(value, '_data', value)
+ # Get the _mask part of the new value
+ mval = getmask(value)
+ if _dtype.names is not None and mval is nomask:
+ mval = tuple([False] * len(_dtype.names))
+ if _mask is nomask:
+ # Set the data, then the mask
+ _data[indx] = dval
+ if mval is not nomask:
+ _mask = self._mask = make_mask_none(self.shape, _dtype)
+ _mask[indx] = mval
+ elif not self._hardmask:
+ # Set the data, then the mask
+ if (isinstance(indx, masked_array) and
+ not isinstance(value, masked_array)):
+ _data[indx.data] = dval
+ else:
+ _data[indx] = dval
+ _mask[indx] = mval
+ elif hasattr(indx, 'dtype') and (indx.dtype == MaskType):
+ indx = indx * umath.logical_not(_mask)
+ _data[indx] = dval
+ else:
+ if _dtype.names is not None:
+ err_msg = "Flexible 'hard' masks are not yet supported."
+ raise NotImplementedError(err_msg)
+ mindx = mask_or(_mask[indx], mval, copy=True)
+ dindx = self._data[indx]
+ if dindx.size > 1:
+ np.copyto(dindx, dval, where=~mindx)
+ elif mindx is nomask:
+ dindx = dval
+ _data[indx] = dindx
+ _mask[indx] = mindx
+ return
+
+ # Define so that we can overwrite the setter.
+ @property
+ def dtype(self):
+ return super().dtype
+
+ @dtype.setter
+ def dtype(self, dtype):
+ super(MaskedArray, type(self)).dtype.__set__(self, dtype)
+ if self._mask is not nomask:
+ self._mask = self._mask.view(make_mask_descr(dtype), ndarray)
+ # Try to reset the shape of the mask (if we don't have a void).
+ # This raises a ValueError if the dtype change won't work.
+ try:
+ self._mask.shape = self.shape
+ except (AttributeError, TypeError):
+ pass
+
+ @property
+ def shape(self):
+ return super().shape
+
+ @shape.setter
+ def shape(self, shape):
+ super(MaskedArray, type(self)).shape.__set__(self, shape)
+ # Cannot use self._mask, since it may not (yet) exist when a
+ # masked matrix sets the shape.
+ if getmask(self) is not nomask:
+ self._mask.shape = self.shape
+
+ def __setmask__(self, mask, copy=False):
+ """
+ Set the mask.
+
+ """
+ idtype = self.dtype
+ current_mask = self._mask
+ if mask is masked:
+ mask = True
+
+ if current_mask is nomask:
+ # Make sure the mask is set
+ # Just don't do anything if there's nothing to do.
+ if mask is nomask:
+ return
+ current_mask = self._mask = make_mask_none(self.shape, idtype)
+
+ if idtype.names is None:
+ # No named fields.
+ # Hardmask: don't unmask the data
+ if self._hardmask:
+ current_mask |= mask
+ # Softmask: set everything to False
+ # If it's obviously a compatible scalar, use a quick update
+ # method.
+ elif isinstance(mask, (int, float, np.bool_, np.number)):
+ current_mask[...] = mask
+ # Otherwise fall back to the slower, general purpose way.
+ else:
+ current_mask.flat = mask
+ else:
+ # Named fields w/
+ mdtype = current_mask.dtype
+ mask = np.array(mask, copy=False)
+ # Mask is a singleton
+ if not mask.ndim:
+ # It's a boolean : make a record
+ if mask.dtype.kind == 'b':
+ mask = np.array(tuple([mask.item()] * len(mdtype)),
+ dtype=mdtype)
+ # It's a record: make sure the dtype is correct
+ else:
+ mask = mask.astype(mdtype)
+ # Mask is a sequence
+ else:
+ # Make sure the new mask is a ndarray with the proper dtype
+ try:
+ mask = np.array(mask, copy=copy, dtype=mdtype)
+ # Or assume it's a sequence of bool/int
+ except TypeError:
+ mask = np.array([tuple([m] * len(mdtype)) for m in mask],
+ dtype=mdtype)
+ # Hardmask: don't unmask the data
+ if self._hardmask:
+ for n in idtype.names:
+ current_mask[n] |= mask[n]
+ # Softmask: set everything to False
+ # If it's obviously a compatible scalar, use a quick update
+ # method.
+ elif isinstance(mask, (int, float, np.bool_, np.number)):
+ current_mask[...] = mask
+ # Otherwise fall back to the slower, general purpose way.
+ else:
+ current_mask.flat = mask
+ # Reshape if needed
+ if current_mask.shape:
+ current_mask.shape = self.shape
+ return
+
+ _set_mask = __setmask__
+
+ @property
+ def mask(self):
+ """ Current mask. """
+
+ # We could try to force a reshape, but that wouldn't work in some
+ # cases.
+ # Return a view so that the dtype and shape cannot be changed in place
+ # This still preserves nomask by identity
+ return self._mask.view()
+
+ @mask.setter
+ def mask(self, value):
+ self.__setmask__(value)
+
+ @property
+ def recordmask(self):
+ """
+ Get or set the mask of the array if it has no named fields. For
+ structured arrays, returns a ndarray of booleans where entries are
+ ``True`` if **all** the fields are masked, ``False`` otherwise:
+
+ >>> x = np.ma.array([(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)],
+ ... mask=[(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)],
+ ... dtype=[('a', int), ('b', int)])
+ >>> x.recordmask
+ array([False, False, True, False, False])
+ """
+
+ _mask = self._mask.view(ndarray)
+ if _mask.dtype.names is None:
+ return _mask
+ return np.all(flatten_structured_array(_mask), axis=-1)
+
+ @recordmask.setter
+ def recordmask(self, mask):
+ raise NotImplementedError("Coming soon: setting the mask per records!")
+
+ def harden_mask(self):
+ """
+ Force the mask to hard, preventing unmasking by assignment.
+
+ Whether the mask of a masked array is hard or soft is determined by
+ its `~ma.MaskedArray.hardmask` property. `harden_mask` sets
+ `~ma.MaskedArray.hardmask` to ``True`` (and returns the modified
+ self).
+
+ See Also
+ --------
+ ma.MaskedArray.hardmask
+ ma.MaskedArray.soften_mask
+
+ """
+ self._hardmask = True
+ return self
+
+ def soften_mask(self):
+ """
+ Force the mask to soft (default), allowing unmasking by assignment.
+
+ Whether the mask of a masked array is hard or soft is determined by
+ its `~ma.MaskedArray.hardmask` property. `soften_mask` sets
+ `~ma.MaskedArray.hardmask` to ``False`` (and returns the modified
+ self).
+
+ See Also
+ --------
+ ma.MaskedArray.hardmask
+ ma.MaskedArray.harden_mask
+
+ """
+ self._hardmask = False
+ return self
+
+ @property
+ def hardmask(self):
+ """
+ Specifies whether values can be unmasked through assignments.
+
+ By default, assigning definite values to masked array entries will
+ unmask them. When `hardmask` is ``True``, the mask will not change
+ through assignments.
+
+ See Also
+ --------
+ ma.MaskedArray.harden_mask
+ ma.MaskedArray.soften_mask
+
+ Examples
+ --------
+ >>> x = np.arange(10)
+ >>> m = np.ma.masked_array(x, x>5)
+ >>> assert not m.hardmask
+
+ Since `m` has a soft mask, assigning an element value unmasks that
+ element:
+
+ >>> m[8] = 42
+ >>> m
+ masked_array(data=[0, 1, 2, 3, 4, 5, --, --, 42, --],
+ mask=[False, False, False, False, False, False,
+ True, True, False, True],
+ fill_value=999999)
+
+ After hardening, the mask is not affected by assignments:
+
+ >>> hardened = np.ma.harden_mask(m)
+ >>> assert m.hardmask and hardened is m
+ >>> m[:] = 23
+ >>> m
+ masked_array(data=[23, 23, 23, 23, 23, 23, --, --, 23, --],
+ mask=[False, False, False, False, False, False,
+ True, True, False, True],
+ fill_value=999999)
+
+ """
+ return self._hardmask
+
+ def unshare_mask(self):
+ """
+ Copy the mask and set the `sharedmask` flag to ``False``.
+
+ Whether the mask is shared between masked arrays can be seen from
+ the `sharedmask` property. `unshare_mask` ensures the mask is not
+ shared. A copy of the mask is only made if it was shared.
+
+ See Also
+ --------
+ sharedmask
+
+ """
+ if self._sharedmask:
+ self._mask = self._mask.copy()
+ self._sharedmask = False
+ return self
+
+ @property
+ def sharedmask(self):
+ """ Share status of the mask (read-only). """
+ return self._sharedmask
+
+ def shrink_mask(self):
+ """
+ Reduce a mask to nomask when possible.
+
+ Parameters
+ ----------
+ None
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ >>> x = np.ma.array([[1,2 ], [3, 4]], mask=[0]*4)
+ >>> x.mask
+ array([[False, False],
+ [False, False]])
+ >>> x.shrink_mask()
+ masked_array(
+ data=[[1, 2],
+ [3, 4]],
+ mask=False,
+ fill_value=999999)
+ >>> x.mask
+ False
+
+ """
+ self._mask = _shrink_mask(self._mask)
+ return self
+
+ @property
+ def baseclass(self):
+ """ Class of the underlying data (read-only). """
+ return self._baseclass
+
+ def _get_data(self):
+ """
+ Returns the underlying data, as a view of the masked array.
+
+ If the underlying data is a subclass of :class:`numpy.ndarray`, it is
+ returned as such.
+
+ >>> x = np.ma.array(np.matrix([[1, 2], [3, 4]]), mask=[[0, 1], [1, 0]])
+ >>> x.data
+ matrix([[1, 2],
+ [3, 4]])
+
+ The type of the data can be accessed through the :attr:`baseclass`
+ attribute.
+ """
+ return ndarray.view(self, self._baseclass)
+
+ _data = property(fget=_get_data)
+ data = property(fget=_get_data)
+
+ @property
+ def flat(self):
+ """ Return a flat iterator, or set a flattened version of self to value. """
+ return MaskedIterator(self)
+
+ @flat.setter
+ def flat(self, value):
+ y = self.ravel()
+ y[:] = value
+
+ @property
+ def fill_value(self):
+ """
+ The filling value of the masked array is a scalar. When setting, None
+ will set to a default based on the data type.
+
+ Examples
+ --------
+ >>> for dt in [np.int32, np.int64, np.float64, np.complex128]:
+ ... np.ma.array([0, 1], dtype=dt).get_fill_value()
+ ...
+ 999999
+ 999999
+ 1e+20
+ (1e+20+0j)
+
+ >>> x = np.ma.array([0, 1.], fill_value=-np.inf)
+ >>> x.fill_value
+ -inf
+ >>> x.fill_value = np.pi
+ >>> x.fill_value
+ 3.1415926535897931 # may vary
+
+ Reset to default:
+
+ >>> x.fill_value = None
+ >>> x.fill_value
+ 1e+20
+
+ """
+ if self._fill_value is None:
+ self._fill_value = _check_fill_value(None, self.dtype)
+
+ # Temporary workaround to account for the fact that str and bytes
+ # scalars cannot be indexed with (), whereas all other numpy
+ # scalars can. See issues #7259 and #7267.
+ # The if-block can be removed after #7267 has been fixed.
+ if isinstance(self._fill_value, ndarray):
+ return self._fill_value[()]
+ return self._fill_value
+
+ @fill_value.setter
+ def fill_value(self, value=None):
+ target = _check_fill_value(value, self.dtype)
+ if not target.ndim == 0:
+ # 2019-11-12, 1.18.0
+ warnings.warn(
+ "Non-scalar arrays for the fill value are deprecated. Use "
+ "arrays with scalar values instead. The filled function "
+ "still supports any array as `fill_value`.",
+ DeprecationWarning, stacklevel=2)
+
+ _fill_value = self._fill_value
+ if _fill_value is None:
+ # Create the attribute if it was undefined
+ self._fill_value = target
+ else:
+ # Don't overwrite the attribute, just fill it (for propagation)
+ _fill_value[()] = target
+
+ # kept for compatibility
+ get_fill_value = fill_value.fget
+ set_fill_value = fill_value.fset
+
+ def filled(self, fill_value=None):
+ """
+ Return a copy of self, with masked values filled with a given value.
+ **However**, if there are no masked values to fill, self will be
+ returned instead as an ndarray.
+
+ Parameters
+ ----------
+ fill_value : array_like, optional
+ The value to use for invalid entries. Can be scalar or non-scalar.
+ If non-scalar, the resulting ndarray must be broadcastable over
+ input array. Default is None, in which case, the `fill_value`
+ attribute of the array is used instead.
+
+ Returns
+ -------
+ filled_array : ndarray
+ A copy of ``self`` with invalid entries replaced by *fill_value*
+ (be it the function argument or the attribute of ``self``), or
+ ``self`` itself as an ndarray if there are no invalid entries to
+ be replaced.
+
+ Notes
+ -----
+ The result is **not** a MaskedArray!
+
+ Examples
+ --------
+ >>> x = np.ma.array([1,2,3,4,5], mask=[0,0,1,0,1], fill_value=-999)
+ >>> x.filled()
+ array([ 1, 2, -999, 4, -999])
+ >>> x.filled(fill_value=1000)
+ array([ 1, 2, 1000, 4, 1000])
+ >>> type(x.filled())
+ <class 'numpy.ndarray'>
+
+ Subclassing is preserved. This means that if, e.g., the data part of
+ the masked array is a recarray, `filled` returns a recarray:
+
+ >>> x = np.array([(-1, 2), (-3, 4)], dtype='i8,i8').view(np.recarray)
+ >>> m = np.ma.array(x, mask=[(True, False), (False, True)])
+ >>> m.filled()
+ rec.array([(999999, 2), ( -3, 999999)],
+ dtype=[('f0', '<i8'), ('f1', '<i8')])
+ """
+ m = self._mask
+ if m is nomask:
+ return self._data
+
+ if fill_value is None:
+ fill_value = self.fill_value
+ else:
+ fill_value = _check_fill_value(fill_value, self.dtype)
+
+ if self is masked_singleton:
+ return np.asanyarray(fill_value)
+
+ if m.dtype.names is not None:
+ result = self._data.copy('K')
+ _recursive_filled(result, self._mask, fill_value)
+ elif not m.any():
+ return self._data
+ else:
+ result = self._data.copy('K')
+ try:
+ np.copyto(result, fill_value, where=m)
+ except (TypeError, AttributeError):
+ fill_value = narray(fill_value, dtype=object)
+ d = result.astype(object)
+ result = np.choose(m, (d, fill_value))
+ except IndexError:
+ # ok, if scalar
+ if self._data.shape:
+ raise
+ elif m:
+ result = np.array(fill_value, dtype=self.dtype)
+ else:
+ result = self._data
+ return result
+
+ def compressed(self):
+ """
+ Return all the non-masked data as a 1-D array.
+
+ Returns
+ -------
+ data : ndarray
+ A new `ndarray` holding the non-masked data is returned.
+
+ Notes
+ -----
+ The result is **not** a MaskedArray!
+
+ Examples
+ --------
+ >>> x = np.ma.array(np.arange(5), mask=[0]*2 + [1]*3)
+ >>> x.compressed()
+ array([0, 1])
+ >>> type(x.compressed())
+ <class 'numpy.ndarray'>
+
+ """
+ data = ndarray.ravel(self._data)
+ if self._mask is not nomask:
+ data = data.compress(np.logical_not(ndarray.ravel(self._mask)))
+ return data
+
+ def compress(self, condition, axis=None, out=None):
+ """
+ Return `a` where condition is ``True``.
+
+ If condition is a `~ma.MaskedArray`, missing values are considered
+ as ``False``.
+
+ Parameters
+ ----------
+ condition : var
+ Boolean 1-d array selecting which entries to return. If len(condition)
+ is less than the size of a along the axis, then output is truncated
+ to length of condition array.
+ axis : {None, int}, optional
+ Axis along which the operation must be performed.
+ out : {None, ndarray}, optional
+ Alternative output array in which to place the result. It must have
+ the same shape as the expected output but the type will be cast if
+ necessary.
+
+ Returns
+ -------
+ result : MaskedArray
+ A :class:`~ma.MaskedArray` object.
+
+ Notes
+ -----
+ Please note the difference with :meth:`compressed` !
+ The output of :meth:`compress` has a mask, the output of
+ :meth:`compressed` does not.
+
+ Examples
+ --------
+ >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4)
+ >>> x
+ masked_array(
+ data=[[1, --, 3],
+ [--, 5, --],
+ [7, --, 9]],
+ mask=[[False, True, False],
+ [ True, False, True],
+ [False, True, False]],
+ fill_value=999999)
+ >>> x.compress([1, 0, 1])
+ masked_array(data=[1, 3],
+ mask=[False, False],
+ fill_value=999999)
+
+ >>> x.compress([1, 0, 1], axis=1)
+ masked_array(
+ data=[[1, 3],
+ [--, --],
+ [7, 9]],
+ mask=[[False, False],
+ [ True, True],
+ [False, False]],
+ fill_value=999999)
+
+ """
+ # Get the basic components
+ (_data, _mask) = (self._data, self._mask)
+
+ # Force the condition to a regular ndarray and forget the missing
+ # values.
+ condition = np.asarray(condition)
+
+ _new = _data.compress(condition, axis=axis, out=out).view(type(self))
+ _new._update_from(self)
+ if _mask is not nomask:
+ _new._mask = _mask.compress(condition, axis=axis)
+ return _new
+
+ def _insert_masked_print(self):
+ """
+ Replace masked values with masked_print_option, casting all innermost
+ dtypes to object.
+ """
+ if masked_print_option.enabled():
+ mask = self._mask
+ if mask is nomask:
+ res = self._data
+ else:
+ # convert to object array to make filled work
+ data = self._data
+ # For big arrays, to avoid a costly conversion to the
+ # object dtype, extract the corners before the conversion.
+ print_width = (self._print_width if self.ndim > 1
+ else self._print_width_1d)
+ for axis in range(self.ndim):
+ if data.shape[axis] > print_width:
+ ind = print_width // 2
+ arr = np.split(data, (ind, -ind), axis=axis)
+ data = np.concatenate((arr[0], arr[2]), axis=axis)
+ arr = np.split(mask, (ind, -ind), axis=axis)
+ mask = np.concatenate((arr[0], arr[2]), axis=axis)
+
+ rdtype = _replace_dtype_fields(self.dtype, "O")
+ res = data.astype(rdtype)
+ _recursive_printoption(res, mask, masked_print_option)
+ else:
+ res = self.filled(self.fill_value)
+ return res
+
+ def __str__(self):
+ return str(self._insert_masked_print())
+
+ def __repr__(self):
+ """
+ Literal string representation.
+
+ """
+ if self._baseclass is np.ndarray:
+ name = 'array'
+ else:
+ name = self._baseclass.__name__
+
+
+ # 2016-11-19: Demoted to legacy format
+ if np.core.arrayprint._get_legacy_print_mode() <= 113:
+ is_long = self.ndim > 1
+ parameters = dict(
+ name=name,
+ nlen=" " * len(name),
+ data=str(self),
+ mask=str(self._mask),
+ fill=str(self.fill_value),
+ dtype=str(self.dtype)
+ )
+ is_structured = bool(self.dtype.names)
+ key = '{}_{}'.format(
+ 'long' if is_long else 'short',
+ 'flx' if is_structured else 'std'
+ )
+ return _legacy_print_templates[key] % parameters
+
+ prefix = f"masked_{name}("
+
+ dtype_needed = (
+ not np.core.arrayprint.dtype_is_implied(self.dtype) or
+ np.all(self.mask) or
+ self.size == 0
+ )
+
+ # determine which keyword args need to be shown
+ keys = ['data', 'mask', 'fill_value']
+ if dtype_needed:
+ keys.append('dtype')
+
+ # array has only one row (non-column)
+ is_one_row = builtins.all(dim == 1 for dim in self.shape[:-1])
+
+ # choose what to indent each keyword with
+ min_indent = 2
+ if is_one_row:
+ # first key on the same line as the type, remaining keys
+ # aligned by equals
+ indents = {}
+ indents[keys[0]] = prefix
+ for k in keys[1:]:
+ n = builtins.max(min_indent, len(prefix + keys[0]) - len(k))
+ indents[k] = ' ' * n
+ prefix = '' # absorbed into the first indent
+ else:
+ # each key on its own line, indented by two spaces
+ indents = {k: ' ' * min_indent for k in keys}
+ prefix = prefix + '\n' # first key on the next line
+
+ # format the field values
+ reprs = {}
+ reprs['data'] = np.array2string(
+ self._insert_masked_print(),
+ separator=", ",
+ prefix=indents['data'] + 'data=',
+ suffix=',')
+ reprs['mask'] = np.array2string(
+ self._mask,
+ separator=", ",
+ prefix=indents['mask'] + 'mask=',
+ suffix=',')
+ reprs['fill_value'] = repr(self.fill_value)
+ if dtype_needed:
+ reprs['dtype'] = np.core.arrayprint.dtype_short_repr(self.dtype)
+
+ # join keys with values and indentations
+ result = ',\n'.join(
+ '{}{}={}'.format(indents[k], k, reprs[k])
+ for k in keys
+ )
+ return prefix + result + ')'
+
+ def _delegate_binop(self, other):
+ # This emulates the logic in
+ # private/binop_override.h:forward_binop_should_defer
+ if isinstance(other, type(self)):
+ return False
+ array_ufunc = getattr(other, "__array_ufunc__", False)
+ if array_ufunc is False:
+ other_priority = getattr(other, "__array_priority__", -1000000)
+ return self.__array_priority__ < other_priority
+ else:
+ # If array_ufunc is not None, it will be called inside the ufunc;
+ # None explicitly tells us to not call the ufunc, i.e., defer.
+ return array_ufunc is None
+
+ def _comparison(self, other, compare):
+ """Compare self with other using operator.eq or operator.ne.
+
+ When either of the elements is masked, the result is masked as well,
+ but the underlying boolean data are still set, with self and other
+ considered equal if both are masked, and unequal otherwise.
+
+ For structured arrays, all fields are combined, with masked values
+ ignored. The result is masked if all fields were masked, with self
+ and other considered equal only if both were fully masked.
+ """
+ omask = getmask(other)
+ smask = self.mask
+ mask = mask_or(smask, omask, copy=True)
+
+ odata = getdata(other)
+ if mask.dtype.names is not None:
+ # only == and != are reasonably defined for structured dtypes,
+ # so give up early for all other comparisons:
+ if compare not in (operator.eq, operator.ne):
+ return NotImplemented
+ # For possibly masked structured arrays we need to be careful,
+ # since the standard structured array comparison will use all
+ # fields, masked or not. To avoid masked fields influencing the
+ # outcome, we set all masked fields in self to other, so they'll
+ # count as equal. To prepare, we ensure we have the right shape.
+ broadcast_shape = np.broadcast(self, odata).shape
+ sbroadcast = np.broadcast_to(self, broadcast_shape, subok=True)
+ sbroadcast._mask = mask
+ sdata = sbroadcast.filled(odata)
+ # Now take care of the mask; the merged mask should have an item
+ # masked if all fields were masked (in one and/or other).
+ mask = (mask == np.ones((), mask.dtype))
+
+ else:
+ # For regular arrays, just use the data as they come.
+ sdata = self.data
+
+ check = compare(sdata, odata)
+
+ if isinstance(check, (np.bool_, bool)):
+ return masked if mask else check
+
+ if mask is not nomask and compare in (operator.eq, operator.ne):
+ # Adjust elements that were masked, which should be treated
+ # as equal if masked in both, unequal if masked in one.
+ # Note that this works automatically for structured arrays too.
+ # Ignore this for operations other than `==` and `!=`
+ check = np.where(mask, compare(smask, omask), check)
+ if mask.shape != check.shape:
+ # Guarantee consistency of the shape, making a copy since the
+ # the mask may need to get written to later.
+ mask = np.broadcast_to(mask, check.shape).copy()
+
+ check = check.view(type(self))
+ check._update_from(self)
+ check._mask = mask
+
+ # Cast fill value to bool_ if needed. If it cannot be cast, the
+ # default boolean fill value is used.
+ if check._fill_value is not None:
+ try:
+ fill = _check_fill_value(check._fill_value, np.bool_)
+ except (TypeError, ValueError):
+ fill = _check_fill_value(None, np.bool_)
+ check._fill_value = fill
+
+ return check
+
+ def __eq__(self, other):
+ """Check whether other equals self elementwise.
+
+ When either of the elements is masked, the result is masked as well,
+ but the underlying boolean data are still set, with self and other
+ considered equal if both are masked, and unequal otherwise.
+
+ For structured arrays, all fields are combined, with masked values
+ ignored. The result is masked if all fields were masked, with self
+ and other considered equal only if both were fully masked.
+ """
+ return self._comparison(other, operator.eq)
+
+ def __ne__(self, other):
+ """Check whether other does not equal self elementwise.
+
+ When either of the elements is masked, the result is masked as well,
+ but the underlying boolean data are still set, with self and other
+ considered equal if both are masked, and unequal otherwise.
+
+ For structured arrays, all fields are combined, with masked values
+ ignored. The result is masked if all fields were masked, with self
+ and other considered equal only if both were fully masked.
+ """
+ return self._comparison(other, operator.ne)
+
+ # All other comparisons:
+ def __le__(self, other):
+ return self._comparison(other, operator.le)
+
+ def __lt__(self, other):
+ return self._comparison(other, operator.lt)
+
+ def __ge__(self, other):
+ return self._comparison(other, operator.ge)
+
+ def __gt__(self, other):
+ return self._comparison(other, operator.gt)
+
+ def __add__(self, other):
+ """
+ Add self to other, and return a new masked array.
+
+ """
+ if self._delegate_binop(other):
+ return NotImplemented
+ return add(self, other)
+
+ def __radd__(self, other):
+ """
+ Add other to self, and return a new masked array.
+
+ """
+ # In analogy with __rsub__ and __rdiv__, use original order:
+ # we get here from `other + self`.
+ return add(other, self)
+
+ def __sub__(self, other):
+ """
+ Subtract other from self, and return a new masked array.
+
+ """
+ if self._delegate_binop(other):
+ return NotImplemented
+ return subtract(self, other)
+
+ def __rsub__(self, other):
+ """
+ Subtract self from other, and return a new masked array.
+
+ """
+ return subtract(other, self)
+
+ def __mul__(self, other):
+ "Multiply self by other, and return a new masked array."
+ if self._delegate_binop(other):
+ return NotImplemented
+ return multiply(self, other)
+
+ def __rmul__(self, other):
+ """
+ Multiply other by self, and return a new masked array.
+
+ """
+ # In analogy with __rsub__ and __rdiv__, use original order:
+ # we get here from `other * self`.
+ return multiply(other, self)
+
+ def __div__(self, other):
+ """
+ Divide other into self, and return a new masked array.
+
+ """
+ if self._delegate_binop(other):
+ return NotImplemented
+ return divide(self, other)
+
+ def __truediv__(self, other):
+ """
+ Divide other into self, and return a new masked array.
+
+ """
+ if self._delegate_binop(other):
+ return NotImplemented
+ return true_divide(self, other)
+
+ def __rtruediv__(self, other):
+ """
+ Divide self into other, and return a new masked array.
+
+ """
+ return true_divide(other, self)
+
+ def __floordiv__(self, other):
+ """
+ Divide other into self, and return a new masked array.
+
+ """
+ if self._delegate_binop(other):
+ return NotImplemented
+ return floor_divide(self, other)
+
+ def __rfloordiv__(self, other):
+ """
+ Divide self into other, and return a new masked array.
+
+ """
+ return floor_divide(other, self)
+
+ def __pow__(self, other):
+ """
+ Raise self to the power other, masking the potential NaNs/Infs
+
+ """
+ if self._delegate_binop(other):
+ return NotImplemented
+ return power(self, other)
+
+ def __rpow__(self, other):
+ """
+ Raise other to the power self, masking the potential NaNs/Infs
+
+ """
+ return power(other, self)
+
+ def __iadd__(self, other):
+ """
+ Add other to self in-place.
+
+ """
+ m = getmask(other)
+ if self._mask is nomask:
+ if m is not nomask and m.any():
+ self._mask = make_mask_none(self.shape, self.dtype)
+ self._mask += m
+ else:
+ if m is not nomask:
+ self._mask += m
+ other_data = getdata(other)
+ other_data = np.where(self._mask, other_data.dtype.type(0), other_data)
+ self._data.__iadd__(other_data)
+ return self
+
+ def __isub__(self, other):
+ """
+ Subtract other from self in-place.
+
+ """
+ m = getmask(other)
+ if self._mask is nomask:
+ if m is not nomask and m.any():
+ self._mask = make_mask_none(self.shape, self.dtype)
+ self._mask += m
+ elif m is not nomask:
+ self._mask += m
+ other_data = getdata(other)
+ other_data = np.where(self._mask, other_data.dtype.type(0), other_data)
+ self._data.__isub__(other_data)
+ return self
+
+ def __imul__(self, other):
+ """
+ Multiply self by other in-place.
+
+ """
+ m = getmask(other)
+ if self._mask is nomask:
+ if m is not nomask and m.any():
+ self._mask = make_mask_none(self.shape, self.dtype)
+ self._mask += m
+ elif m is not nomask:
+ self._mask += m
+ other_data = getdata(other)
+ other_data = np.where(self._mask, other_data.dtype.type(1), other_data)
+ self._data.__imul__(other_data)
+ return self
+
+ def __idiv__(self, other):
+ """
+ Divide self by other in-place.
+
+ """
+ other_data = getdata(other)
+ dom_mask = _DomainSafeDivide().__call__(self._data, other_data)
+ other_mask = getmask(other)
+ new_mask = mask_or(other_mask, dom_mask)
+ # The following 4 lines control the domain filling
+ if dom_mask.any():
+ (_, fval) = ufunc_fills[np.divide]
+ other_data = np.where(
+ dom_mask, other_data.dtype.type(fval), other_data)
+ self._mask |= new_mask
+ other_data = np.where(self._mask, other_data.dtype.type(1), other_data)
+ self._data.__idiv__(other_data)
+ return self
+
+ def __ifloordiv__(self, other):
+ """
+ Floor divide self by other in-place.
+
+ """
+ other_data = getdata(other)
+ dom_mask = _DomainSafeDivide().__call__(self._data, other_data)
+ other_mask = getmask(other)
+ new_mask = mask_or(other_mask, dom_mask)
+ # The following 3 lines control the domain filling
+ if dom_mask.any():
+ (_, fval) = ufunc_fills[np.floor_divide]
+ other_data = np.where(
+ dom_mask, other_data.dtype.type(fval), other_data)
+ self._mask |= new_mask
+ other_data = np.where(self._mask, other_data.dtype.type(1), other_data)
+ self._data.__ifloordiv__(other_data)
+ return self
+
+ def __itruediv__(self, other):
+ """
+ True divide self by other in-place.
+
+ """
+ other_data = getdata(other)
+ dom_mask = _DomainSafeDivide().__call__(self._data, other_data)
+ other_mask = getmask(other)
+ new_mask = mask_or(other_mask, dom_mask)
+ # The following 3 lines control the domain filling
+ if dom_mask.any():
+ (_, fval) = ufunc_fills[np.true_divide]
+ other_data = np.where(
+ dom_mask, other_data.dtype.type(fval), other_data)
+ self._mask |= new_mask
+ other_data = np.where(self._mask, other_data.dtype.type(1), other_data)
+ self._data.__itruediv__(other_data)
+ return self
+
+ def __ipow__(self, other):
+ """
+ Raise self to the power other, in place.
+
+ """
+ other_data = getdata(other)
+ other_data = np.where(self._mask, other_data.dtype.type(1), other_data)
+ other_mask = getmask(other)
+ with np.errstate(divide='ignore', invalid='ignore'):
+ self._data.__ipow__(other_data)
+ invalid = np.logical_not(np.isfinite(self._data))
+ if invalid.any():
+ if self._mask is not nomask:
+ self._mask |= invalid
+ else:
+ self._mask = invalid
+ np.copyto(self._data, self.fill_value, where=invalid)
+ new_mask = mask_or(other_mask, invalid)
+ self._mask = mask_or(self._mask, new_mask)
+ return self
+
+ def __float__(self):
+ """
+ Convert to float.
+
+ """
+ if self.size > 1:
+ raise TypeError("Only length-1 arrays can be converted "
+ "to Python scalars")
+ elif self._mask:
+ warnings.warn("Warning: converting a masked element to nan.", stacklevel=2)
+ return np.nan
+ return float(self.item())
+
+ def __int__(self):
+ """
+ Convert to int.
+
+ """
+ if self.size > 1:
+ raise TypeError("Only length-1 arrays can be converted "
+ "to Python scalars")
+ elif self._mask:
+ raise MaskError('Cannot convert masked element to a Python int.')
+ return int(self.item())
+
+ @property
+ def imag(self):
+ """
+ The imaginary part of the masked array.
+
+ This property is a view on the imaginary part of this `MaskedArray`.
+
+ See Also
+ --------
+ real
+
+ Examples
+ --------
+ >>> x = np.ma.array([1+1.j, -2j, 3.45+1.6j], mask=[False, True, False])
+ >>> x.imag
+ masked_array(data=[1.0, --, 1.6],
+ mask=[False, True, False],
+ fill_value=1e+20)
+
+ """
+ result = self._data.imag.view(type(self))
+ result.__setmask__(self._mask)
+ return result
+
+ # kept for compatibility
+ get_imag = imag.fget
+
+ @property
+ def real(self):
+ """
+ The real part of the masked array.
+
+ This property is a view on the real part of this `MaskedArray`.
+
+ See Also
+ --------
+ imag
+
+ Examples
+ --------
+ >>> x = np.ma.array([1+1.j, -2j, 3.45+1.6j], mask=[False, True, False])
+ >>> x.real
+ masked_array(data=[1.0, --, 3.45],
+ mask=[False, True, False],
+ fill_value=1e+20)
+
+ """
+ result = self._data.real.view(type(self))
+ result.__setmask__(self._mask)
+ return result
+
+ # kept for compatibility
+ get_real = real.fget
+
+ def count(self, axis=None, keepdims=np._NoValue):
+ """
+ Count the non-masked elements of the array along the given axis.
+
+ Parameters
+ ----------
+ axis : None or int or tuple of ints, optional
+ Axis or axes along which the count is performed.
+ The default, None, performs the count over all
+ the dimensions of the input array. `axis` may be negative, in
+ which case it counts from the last to the first axis.
+
+ .. versionadded:: 1.10.0
+
+ If this is a tuple of ints, the count is performed on multiple
+ axes, instead of a single axis or all the axes as before.
+ keepdims : bool, optional
+ If this is set to True, the axes which are reduced are left
+ in the result as dimensions with size one. With this option,
+ the result will broadcast correctly against the array.
+
+ Returns
+ -------
+ result : ndarray or scalar
+ An array with the same shape as the input array, with the specified
+ axis removed. If the array is a 0-d array, or if `axis` is None, a
+ scalar is returned.
+
+ See Also
+ --------
+ ma.count_masked : Count masked elements in array or along a given axis.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> a = ma.arange(6).reshape((2, 3))
+ >>> a[1, :] = ma.masked
+ >>> a
+ masked_array(
+ data=[[0, 1, 2],
+ [--, --, --]],
+ mask=[[False, False, False],
+ [ True, True, True]],
+ fill_value=999999)
+ >>> a.count()
+ 3
+
+ When the `axis` keyword is specified an array of appropriate size is
+ returned.
+
+ >>> a.count(axis=0)
+ array([1, 1, 1])
+ >>> a.count(axis=1)
+ array([3, 0])
+
+ """
+ kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
+
+ m = self._mask
+ # special case for matrices (we assume no other subclasses modify
+ # their dimensions)
+ if isinstance(self.data, np.matrix):
+ if m is nomask:
+ m = np.zeros(self.shape, dtype=np.bool_)
+ m = m.view(type(self.data))
+
+ if m is nomask:
+ # compare to _count_reduce_items in _methods.py
+
+ if self.shape == ():
+ if axis not in (None, 0):
+ raise np.AxisError(axis=axis, ndim=self.ndim)
+ return 1
+ elif axis is None:
+ if kwargs.get('keepdims', False):
+ return np.array(self.size, dtype=np.intp, ndmin=self.ndim)
+ return self.size
+
+ axes = normalize_axis_tuple(axis, self.ndim)
+ items = 1
+ for ax in axes:
+ items *= self.shape[ax]
+
+ if kwargs.get('keepdims', False):
+ out_dims = list(self.shape)
+ for a in axes:
+ out_dims[a] = 1
+ else:
+ out_dims = [d for n, d in enumerate(self.shape)
+ if n not in axes]
+ # make sure to return a 0-d array if axis is supplied
+ return np.full(out_dims, items, dtype=np.intp)
+
+ # take care of the masked singleton
+ if self is masked:
+ return 0
+
+ return (~m).sum(axis=axis, dtype=np.intp, **kwargs)
+
+ def ravel(self, order='C'):
+ """
+ Returns a 1D version of self, as a view.
+
+ Parameters
+ ----------
+ order : {'C', 'F', 'A', 'K'}, optional
+ The elements of `a` are read using this index order. 'C' means to
+ index the elements in C-like order, with the last axis index
+ changing fastest, back to the first axis index changing slowest.
+ 'F' means to index the elements in Fortran-like index order, with
+ the first index changing fastest, and the last index changing
+ slowest. Note that the 'C' and 'F' options take no account of the
+ memory layout of the underlying array, and only refer to the order
+ of axis indexing. 'A' means to read the elements in Fortran-like
+ index order if `m` is Fortran *contiguous* in memory, C-like order
+ otherwise. 'K' means to read the elements in the order they occur
+ in memory, except for reversing the data when strides are negative.
+ By default, 'C' index order is used.
+ (Masked arrays currently use 'A' on the data when 'K' is passed.)
+
+ Returns
+ -------
+ MaskedArray
+ Output view is of shape ``(self.size,)`` (or
+ ``(np.ma.product(self.shape),)``).
+
+ Examples
+ --------
+ >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4)
+ >>> x
+ masked_array(
+ data=[[1, --, 3],
+ [--, 5, --],
+ [7, --, 9]],
+ mask=[[False, True, False],
+ [ True, False, True],
+ [False, True, False]],
+ fill_value=999999)
+ >>> x.ravel()
+ masked_array(data=[1, --, 3, --, 5, --, 7, --, 9],
+ mask=[False, True, False, True, False, True, False, True,
+ False],
+ fill_value=999999)
+
+ """
+ # The order of _data and _mask could be different (it shouldn't be
+ # normally). Passing order `K` or `A` would be incorrect.
+ # So we ignore the mask memory order.
+ # TODO: We don't actually support K, so use A instead. We could
+ # try to guess this correct by sorting strides or deprecate.
+ if order in "kKaA":
+ order = "C" if self._data.flags.fnc else "F"
+ r = ndarray.ravel(self._data, order=order).view(type(self))
+ r._update_from(self)
+ if self._mask is not nomask:
+ r._mask = ndarray.ravel(self._mask, order=order).reshape(r.shape)
+ else:
+ r._mask = nomask
+ return r
+
+
+ def reshape(self, *s, **kwargs):
+ """
+ Give a new shape to the array without changing its data.
+
+ Returns a masked array containing the same data, but with a new shape.
+ The result is a view on the original array; if this is not possible, a
+ ValueError is raised.
+
+ Parameters
+ ----------
+ shape : int or tuple of ints
+ The new shape should be compatible with the original shape. If an
+ integer is supplied, then the result will be a 1-D array of that
+ length.
+ order : {'C', 'F'}, optional
+ Determines whether the array data should be viewed as in C
+ (row-major) or FORTRAN (column-major) order.
+
+ Returns
+ -------
+ reshaped_array : array
+ A new view on the array.
+
+ See Also
+ --------
+ reshape : Equivalent function in the masked array module.
+ numpy.ndarray.reshape : Equivalent method on ndarray object.
+ numpy.reshape : Equivalent function in the NumPy module.
+
+ Notes
+ -----
+ The reshaping operation cannot guarantee that a copy will not be made,
+ to modify the shape in place, use ``a.shape = s``
+
+ Examples
+ --------
+ >>> x = np.ma.array([[1,2],[3,4]], mask=[1,0,0,1])
+ >>> x
+ masked_array(
+ data=[[--, 2],
+ [3, --]],
+ mask=[[ True, False],
+ [False, True]],
+ fill_value=999999)
+ >>> x = x.reshape((4,1))
+ >>> x
+ masked_array(
+ data=[[--],
+ [2],
+ [3],
+ [--]],
+ mask=[[ True],
+ [False],
+ [False],
+ [ True]],
+ fill_value=999999)
+
+ """
+ kwargs.update(order=kwargs.get('order', 'C'))
+ result = self._data.reshape(*s, **kwargs).view(type(self))
+ result._update_from(self)
+ mask = self._mask
+ if mask is not nomask:
+ result._mask = mask.reshape(*s, **kwargs)
+ return result
+
+ def resize(self, newshape, refcheck=True, order=False):
+ """
+ .. warning::
+
+ This method does nothing, except raise a ValueError exception. A
+ masked array does not own its data and therefore cannot safely be
+ resized in place. Use the `numpy.ma.resize` function instead.
+
+ This method is difficult to implement safely and may be deprecated in
+ future releases of NumPy.
+
+ """
+ # Note : the 'order' keyword looks broken, let's just drop it
+ errmsg = "A masked array does not own its data "\
+ "and therefore cannot be resized.\n" \
+ "Use the numpy.ma.resize function instead."
+ raise ValueError(errmsg)
+
+ def put(self, indices, values, mode='raise'):
+ """
+ Set storage-indexed locations to corresponding values.
+
+ Sets self._data.flat[n] = values[n] for each n in indices.
+ If `values` is shorter than `indices` then it will repeat.
+ If `values` has some masked values, the initial mask is updated
+ in consequence, else the corresponding values are unmasked.
+
+ Parameters
+ ----------
+ indices : 1-D array_like
+ Target indices, interpreted as integers.
+ values : array_like
+ Values to place in self._data copy at target indices.
+ mode : {'raise', 'wrap', 'clip'}, optional
+ Specifies how out-of-bounds indices will behave.
+ 'raise' : raise an error.
+ 'wrap' : wrap around.
+ 'clip' : clip to the range.
+
+ Notes
+ -----
+ `values` can be a scalar or length 1 array.
+
+ Examples
+ --------
+ >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4)
+ >>> x
+ masked_array(
+ data=[[1, --, 3],
+ [--, 5, --],
+ [7, --, 9]],
+ mask=[[False, True, False],
+ [ True, False, True],
+ [False, True, False]],
+ fill_value=999999)
+ >>> x.put([0,4,8],[10,20,30])
+ >>> x
+ masked_array(
+ data=[[10, --, 3],
+ [--, 20, --],
+ [7, --, 30]],
+ mask=[[False, True, False],
+ [ True, False, True],
+ [False, True, False]],
+ fill_value=999999)
+
+ >>> x.put(4,999)
+ >>> x
+ masked_array(
+ data=[[10, --, 3],
+ [--, 999, --],
+ [7, --, 30]],
+ mask=[[False, True, False],
+ [ True, False, True],
+ [False, True, False]],
+ fill_value=999999)
+
+ """
+ # Hard mask: Get rid of the values/indices that fall on masked data
+ if self._hardmask and self._mask is not nomask:
+ mask = self._mask[indices]
+ indices = narray(indices, copy=False)
+ values = narray(values, copy=False, subok=True)
+ values.resize(indices.shape)
+ indices = indices[~mask]
+ values = values[~mask]
+
+ self._data.put(indices, values, mode=mode)
+
+ # short circuit if neither self nor values are masked
+ if self._mask is nomask and getmask(values) is nomask:
+ return
+
+ m = getmaskarray(self)
+
+ if getmask(values) is nomask:
+ m.put(indices, False, mode=mode)
+ else:
+ m.put(indices, values._mask, mode=mode)
+ m = make_mask(m, copy=False, shrink=True)
+ self._mask = m
+ return
+
+ def ids(self):
+ """
+ Return the addresses of the data and mask areas.
+
+ Parameters
+ ----------
+ None
+
+ Examples
+ --------
+ >>> x = np.ma.array([1, 2, 3], mask=[0, 1, 1])
+ >>> x.ids()
+ (166670640, 166659832) # may vary
+
+ If the array has no mask, the address of `nomask` is returned. This address
+ is typically not close to the data in memory:
+
+ >>> x = np.ma.array([1, 2, 3])
+ >>> x.ids()
+ (166691080, 3083169284) # may vary
+
+ """
+ if self._mask is nomask:
+ return (self.ctypes.data, id(nomask))
+ return (self.ctypes.data, self._mask.ctypes.data)
+
+ def iscontiguous(self):
+ """
+ Return a boolean indicating whether the data is contiguous.
+
+ Parameters
+ ----------
+ None
+
+ Examples
+ --------
+ >>> x = np.ma.array([1, 2, 3])
+ >>> x.iscontiguous()
+ True
+
+ `iscontiguous` returns one of the flags of the masked array:
+
+ >>> x.flags
+ C_CONTIGUOUS : True
+ F_CONTIGUOUS : True
+ OWNDATA : False
+ WRITEABLE : True
+ ALIGNED : True
+ WRITEBACKIFCOPY : False
+
+ """
+ return self.flags['CONTIGUOUS']
+
+ def all(self, axis=None, out=None, keepdims=np._NoValue):
+ """
+ Returns True if all elements evaluate to True.
+
+ The output array is masked where all the values along the given axis
+ are masked: if the output would have been a scalar and that all the
+ values are masked, then the output is `masked`.
+
+ Refer to `numpy.all` for full documentation.
+
+ See Also
+ --------
+ numpy.ndarray.all : corresponding function for ndarrays
+ numpy.all : equivalent function
+
+ Examples
+ --------
+ >>> np.ma.array([1,2,3]).all()
+ True
+ >>> a = np.ma.array([1,2,3], mask=True)
+ >>> (a.all() is np.ma.masked)
+ True
+
+ """
+ kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
+
+ mask = _check_mask_axis(self._mask, axis, **kwargs)
+ if out is None:
+ d = self.filled(True).all(axis=axis, **kwargs).view(type(self))
+ if d.ndim:
+ d.__setmask__(mask)
+ elif mask:
+ return masked
+ return d
+ self.filled(True).all(axis=axis, out=out, **kwargs)
+ if isinstance(out, MaskedArray):
+ if out.ndim or mask:
+ out.__setmask__(mask)
+ return out
+
+ def any(self, axis=None, out=None, keepdims=np._NoValue):
+ """
+ Returns True if any of the elements of `a` evaluate to True.
+
+ Masked values are considered as False during computation.
+
+ Refer to `numpy.any` for full documentation.
+
+ See Also
+ --------
+ numpy.ndarray.any : corresponding function for ndarrays
+ numpy.any : equivalent function
+
+ """
+ kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
+
+ mask = _check_mask_axis(self._mask, axis, **kwargs)
+ if out is None:
+ d = self.filled(False).any(axis=axis, **kwargs).view(type(self))
+ if d.ndim:
+ d.__setmask__(mask)
+ elif mask:
+ d = masked
+ return d
+ self.filled(False).any(axis=axis, out=out, **kwargs)
+ if isinstance(out, MaskedArray):
+ if out.ndim or mask:
+ out.__setmask__(mask)
+ return out
+
+ def nonzero(self):
+ """
+ Return the indices of unmasked elements that are not zero.
+
+ Returns a tuple of arrays, one for each dimension, containing the
+ indices of the non-zero elements in that dimension. The corresponding
+ non-zero values can be obtained with::
+
+ a[a.nonzero()]
+
+ To group the indices by element, rather than dimension, use
+ instead::
+
+ np.transpose(a.nonzero())
+
+ The result of this is always a 2d array, with a row for each non-zero
+ element.
+
+ Parameters
+ ----------
+ None
+
+ Returns
+ -------
+ tuple_of_arrays : tuple
+ Indices of elements that are non-zero.
+
+ See Also
+ --------
+ numpy.nonzero :
+ Function operating on ndarrays.
+ flatnonzero :
+ Return indices that are non-zero in the flattened version of the input
+ array.
+ numpy.ndarray.nonzero :
+ Equivalent ndarray method.
+ count_nonzero :
+ Counts the number of non-zero elements in the input array.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> x = ma.array(np.eye(3))
+ >>> x
+ masked_array(
+ data=[[1., 0., 0.],
+ [0., 1., 0.],
+ [0., 0., 1.]],
+ mask=False,
+ fill_value=1e+20)
+ >>> x.nonzero()
+ (array([0, 1, 2]), array([0, 1, 2]))
+
+ Masked elements are ignored.
+
+ >>> x[1, 1] = ma.masked
+ >>> x
+ masked_array(
+ data=[[1.0, 0.0, 0.0],
+ [0.0, --, 0.0],
+ [0.0, 0.0, 1.0]],
+ mask=[[False, False, False],
+ [False, True, False],
+ [False, False, False]],
+ fill_value=1e+20)
+ >>> x.nonzero()
+ (array([0, 2]), array([0, 2]))
+
+ Indices can also be grouped by element.
+
+ >>> np.transpose(x.nonzero())
+ array([[0, 0],
+ [2, 2]])
+
+ A common use for ``nonzero`` is to find the indices of an array, where
+ a condition is True. Given an array `a`, the condition `a` > 3 is a
+ boolean array and since False is interpreted as 0, ma.nonzero(a > 3)
+ yields the indices of the `a` where the condition is true.
+
+ >>> a = ma.array([[1,2,3],[4,5,6],[7,8,9]])
+ >>> a > 3
+ masked_array(
+ data=[[False, False, False],
+ [ True, True, True],
+ [ True, True, True]],
+ mask=False,
+ fill_value=True)
+ >>> ma.nonzero(a > 3)
+ (array([1, 1, 1, 2, 2, 2]), array([0, 1, 2, 0, 1, 2]))
+
+ The ``nonzero`` method of the condition array can also be called.
+
+ >>> (a > 3).nonzero()
+ (array([1, 1, 1, 2, 2, 2]), array([0, 1, 2, 0, 1, 2]))
+
+ """
+ return narray(self.filled(0), copy=False).nonzero()
+
+ def trace(self, offset=0, axis1=0, axis2=1, dtype=None, out=None):
+ """
+ (this docstring should be overwritten)
+ """
+ #!!!: implement out + test!
+ m = self._mask
+ if m is nomask:
+ result = super().trace(offset=offset, axis1=axis1, axis2=axis2,
+ out=out)
+ return result.astype(dtype)
+ else:
+ D = self.diagonal(offset=offset, axis1=axis1, axis2=axis2)
+ return D.astype(dtype).filled(0).sum(axis=-1, out=out)
+ trace.__doc__ = ndarray.trace.__doc__
+
+ def dot(self, b, out=None, strict=False):
+ """
+ a.dot(b, out=None)
+
+ Masked dot product of two arrays. Note that `out` and `strict` are
+ located in different positions than in `ma.dot`. In order to
+ maintain compatibility with the functional version, it is
+ recommended that the optional arguments be treated as keyword only.
+ At some point that may be mandatory.
+
+ .. versionadded:: 1.10.0
+
+ Parameters
+ ----------
+ b : masked_array_like
+ Inputs array.
+ out : masked_array, optional
+ Output argument. This must have the exact kind that would be
+ returned if it was not used. In particular, it must have the
+ right type, must be C-contiguous, and its dtype must be the
+ dtype that would be returned for `ma.dot(a,b)`. This is a
+ performance feature. Therefore, if these conditions are not
+ met, an exception is raised, instead of attempting to be
+ flexible.
+ strict : bool, optional
+ Whether masked data are propagated (True) or set to 0 (False)
+ for the computation. Default is False. Propagating the mask
+ means that if a masked value appears in a row or column, the
+ whole row or column is considered masked.
+
+ .. versionadded:: 1.10.2
+
+ See Also
+ --------
+ numpy.ma.dot : equivalent function
+
+ """
+ return dot(self, b, out=out, strict=strict)
+
+ def sum(self, axis=None, dtype=None, out=None, keepdims=np._NoValue):
+ """
+ Return the sum of the array elements over the given axis.
+
+ Masked elements are set to 0 internally.
+
+ Refer to `numpy.sum` for full documentation.
+
+ See Also
+ --------
+ numpy.ndarray.sum : corresponding function for ndarrays
+ numpy.sum : equivalent function
+
+ Examples
+ --------
+ >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4)
+ >>> x
+ masked_array(
+ data=[[1, --, 3],
+ [--, 5, --],
+ [7, --, 9]],
+ mask=[[False, True, False],
+ [ True, False, True],
+ [False, True, False]],
+ fill_value=999999)
+ >>> x.sum()
+ 25
+ >>> x.sum(axis=1)
+ masked_array(data=[4, 5, 16],
+ mask=[False, False, False],
+ fill_value=999999)
+ >>> x.sum(axis=0)
+ masked_array(data=[8, 5, 12],
+ mask=[False, False, False],
+ fill_value=999999)
+ >>> print(type(x.sum(axis=0, dtype=np.int64)[0]))
+ <class 'numpy.int64'>
+
+ """
+ kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
+
+ _mask = self._mask
+ newmask = _check_mask_axis(_mask, axis, **kwargs)
+ # No explicit output
+ if out is None:
+ result = self.filled(0).sum(axis, dtype=dtype, **kwargs)
+ rndim = getattr(result, 'ndim', 0)
+ if rndim:
+ result = result.view(type(self))
+ result.__setmask__(newmask)
+ elif newmask:
+ result = masked
+ return result
+ # Explicit output
+ result = self.filled(0).sum(axis, dtype=dtype, out=out, **kwargs)
+ if isinstance(out, MaskedArray):
+ outmask = getmask(out)
+ if outmask is nomask:
+ outmask = out._mask = make_mask_none(out.shape)
+ outmask.flat = newmask
+ return out
+
+ def cumsum(self, axis=None, dtype=None, out=None):
+ """
+ Return the cumulative sum of the array elements over the given axis.
+
+ Masked values are set to 0 internally during the computation.
+ However, their position is saved, and the result will be masked at
+ the same locations.
+
+ Refer to `numpy.cumsum` for full documentation.
+
+ Notes
+ -----
+ The mask is lost if `out` is not a valid :class:`ma.MaskedArray` !
+
+ Arithmetic is modular when using integer types, and no error is
+ raised on overflow.
+
+ See Also
+ --------
+ numpy.ndarray.cumsum : corresponding function for ndarrays
+ numpy.cumsum : equivalent function
+
+ Examples
+ --------
+ >>> marr = np.ma.array(np.arange(10), mask=[0,0,0,1,1,1,0,0,0,0])
+ >>> marr.cumsum()
+ masked_array(data=[0, 1, 3, --, --, --, 9, 16, 24, 33],
+ mask=[False, False, False, True, True, True, False, False,
+ False, False],
+ fill_value=999999)
+
+ """
+ result = self.filled(0).cumsum(axis=axis, dtype=dtype, out=out)
+ if out is not None:
+ if isinstance(out, MaskedArray):
+ out.__setmask__(self.mask)
+ return out
+ result = result.view(type(self))
+ result.__setmask__(self._mask)
+ return result
+
+ def prod(self, axis=None, dtype=None, out=None, keepdims=np._NoValue):
+ """
+ Return the product of the array elements over the given axis.
+
+ Masked elements are set to 1 internally for computation.
+
+ Refer to `numpy.prod` for full documentation.
+
+ Notes
+ -----
+ Arithmetic is modular when using integer types, and no error is raised
+ on overflow.
+
+ See Also
+ --------
+ numpy.ndarray.prod : corresponding function for ndarrays
+ numpy.prod : equivalent function
+ """
+ kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
+
+ _mask = self._mask
+ newmask = _check_mask_axis(_mask, axis, **kwargs)
+ # No explicit output
+ if out is None:
+ result = self.filled(1).prod(axis, dtype=dtype, **kwargs)
+ rndim = getattr(result, 'ndim', 0)
+ if rndim:
+ result = result.view(type(self))
+ result.__setmask__(newmask)
+ elif newmask:
+ result = masked
+ return result
+ # Explicit output
+ result = self.filled(1).prod(axis, dtype=dtype, out=out, **kwargs)
+ if isinstance(out, MaskedArray):
+ outmask = getmask(out)
+ if outmask is nomask:
+ outmask = out._mask = make_mask_none(out.shape)
+ outmask.flat = newmask
+ return out
+ product = prod
+
+ def cumprod(self, axis=None, dtype=None, out=None):
+ """
+ Return the cumulative product of the array elements over the given axis.
+
+ Masked values are set to 1 internally during the computation.
+ However, their position is saved, and the result will be masked at
+ the same locations.
+
+ Refer to `numpy.cumprod` for full documentation.
+
+ Notes
+ -----
+ The mask is lost if `out` is not a valid MaskedArray !
+
+ Arithmetic is modular when using integer types, and no error is
+ raised on overflow.
+
+ See Also
+ --------
+ numpy.ndarray.cumprod : corresponding function for ndarrays
+ numpy.cumprod : equivalent function
+ """
+ result = self.filled(1).cumprod(axis=axis, dtype=dtype, out=out)
+ if out is not None:
+ if isinstance(out, MaskedArray):
+ out.__setmask__(self._mask)
+ return out
+ result = result.view(type(self))
+ result.__setmask__(self._mask)
+ return result
+
+ def mean(self, axis=None, dtype=None, out=None, keepdims=np._NoValue):
+ """
+ Returns the average of the array elements along given axis.
+
+ Masked entries are ignored, and result elements which are not
+ finite will be masked.
+
+ Refer to `numpy.mean` for full documentation.
+
+ See Also
+ --------
+ numpy.ndarray.mean : corresponding function for ndarrays
+ numpy.mean : Equivalent function
+ numpy.ma.average : Weighted average.
+
+ Examples
+ --------
+ >>> a = np.ma.array([1,2,3], mask=[False, False, True])
+ >>> a
+ masked_array(data=[1, 2, --],
+ mask=[False, False, True],
+ fill_value=999999)
+ >>> a.mean()
+ 1.5
+
+ """
+ kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
+ if self._mask is nomask:
+ result = super().mean(axis=axis, dtype=dtype, **kwargs)[()]
+ else:
+ is_float16_result = False
+ if dtype is None:
+ if issubclass(self.dtype.type, (ntypes.integer, ntypes.bool_)):
+ dtype = mu.dtype('f8')
+ elif issubclass(self.dtype.type, ntypes.float16):
+ dtype = mu.dtype('f4')
+ is_float16_result = True
+ dsum = self.sum(axis=axis, dtype=dtype, **kwargs)
+ cnt = self.count(axis=axis, **kwargs)
+ if cnt.shape == () and (cnt == 0):
+ result = masked
+ elif is_float16_result:
+ result = self.dtype.type(dsum * 1. / cnt)
+ else:
+ result = dsum * 1. / cnt
+ if out is not None:
+ out.flat = result
+ if isinstance(out, MaskedArray):
+ outmask = getmask(out)
+ if outmask is nomask:
+ outmask = out._mask = make_mask_none(out.shape)
+ outmask.flat = getmask(result)
+ return out
+ return result
+
+ def anom(self, axis=None, dtype=None):
+ """
+ Compute the anomalies (deviations from the arithmetic mean)
+ along the given axis.
+
+ Returns an array of anomalies, with the same shape as the input and
+ where the arithmetic mean is computed along the given axis.
+
+ Parameters
+ ----------
+ axis : int, optional
+ Axis over which the anomalies are taken.
+ The default is to use the mean of the flattened array as reference.
+ dtype : dtype, optional
+ Type to use in computing the variance. For arrays of integer type
+ the default is float32; for arrays of float types it is the same as
+ the array type.
+
+ See Also
+ --------
+ mean : Compute the mean of the array.
+
+ Examples
+ --------
+ >>> a = np.ma.array([1,2,3])
+ >>> a.anom()
+ masked_array(data=[-1., 0., 1.],
+ mask=False,
+ fill_value=1e+20)
+
+ """
+ m = self.mean(axis, dtype)
+ if not axis:
+ return self - m
+ else:
+ return self - expand_dims(m, axis)
+
+ def var(self, axis=None, dtype=None, out=None, ddof=0,
+ keepdims=np._NoValue):
+ """
+ Returns the variance of the array elements along given axis.
+
+ Masked entries are ignored, and result elements which are not
+ finite will be masked.
+
+ Refer to `numpy.var` for full documentation.
+
+ See Also
+ --------
+ numpy.ndarray.var : corresponding function for ndarrays
+ numpy.var : Equivalent function
+ """
+ kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
+
+ # Easy case: nomask, business as usual
+ if self._mask is nomask:
+ ret = super().var(axis=axis, dtype=dtype, out=out, ddof=ddof,
+ **kwargs)[()]
+ if out is not None:
+ if isinstance(out, MaskedArray):
+ out.__setmask__(nomask)
+ return out
+ return ret
+
+ # Some data are masked, yay!
+ cnt = self.count(axis=axis, **kwargs) - ddof
+ danom = self - self.mean(axis, dtype, keepdims=True)
+ if iscomplexobj(self):
+ danom = umath.absolute(danom) ** 2
+ else:
+ danom *= danom
+ dvar = divide(danom.sum(axis, **kwargs), cnt).view(type(self))
+ # Apply the mask if it's not a scalar
+ if dvar.ndim:
+ dvar._mask = mask_or(self._mask.all(axis, **kwargs), (cnt <= 0))
+ dvar._update_from(self)
+ elif getmask(dvar):
+ # Make sure that masked is returned when the scalar is masked.
+ dvar = masked
+ if out is not None:
+ if isinstance(out, MaskedArray):
+ out.flat = 0
+ out.__setmask__(True)
+ elif out.dtype.kind in 'biu':
+ errmsg = "Masked data information would be lost in one or "\
+ "more location."
+ raise MaskError(errmsg)
+ else:
+ out.flat = np.nan
+ return out
+ # In case with have an explicit output
+ if out is not None:
+ # Set the data
+ out.flat = dvar
+ # Set the mask if needed
+ if isinstance(out, MaskedArray):
+ out.__setmask__(dvar.mask)
+ return out
+ return dvar
+ var.__doc__ = np.var.__doc__
+
+ def std(self, axis=None, dtype=None, out=None, ddof=0,
+ keepdims=np._NoValue):
+ """
+ Returns the standard deviation of the array elements along given axis.
+
+ Masked entries are ignored.
+
+ Refer to `numpy.std` for full documentation.
+
+ See Also
+ --------
+ numpy.ndarray.std : corresponding function for ndarrays
+ numpy.std : Equivalent function
+ """
+ kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
+
+ dvar = self.var(axis, dtype, out, ddof, **kwargs)
+ if dvar is not masked:
+ if out is not None:
+ np.power(out, 0.5, out=out, casting='unsafe')
+ return out
+ dvar = sqrt(dvar)
+ return dvar
+
+ def round(self, decimals=0, out=None):
+ """
+ Return each element rounded to the given number of decimals.
+
+ Refer to `numpy.around` for full documentation.
+
+ See Also
+ --------
+ numpy.ndarray.round : corresponding function for ndarrays
+ numpy.around : equivalent function
+ """
+ result = self._data.round(decimals=decimals, out=out).view(type(self))
+ if result.ndim > 0:
+ result._mask = self._mask
+ result._update_from(self)
+ elif self._mask:
+ # Return masked when the scalar is masked
+ result = masked
+ # No explicit output: we're done
+ if out is None:
+ return result
+ if isinstance(out, MaskedArray):
+ out.__setmask__(self._mask)
+ return out
+
+ def argsort(self, axis=np._NoValue, kind=None, order=None,
+ endwith=True, fill_value=None):
+ """
+ Return an ndarray of indices that sort the array along the
+ specified axis. Masked values are filled beforehand to
+ `fill_value`.
+
+ Parameters
+ ----------
+ axis : int, optional
+ Axis along which to sort. If None, the default, the flattened array
+ is used.
+
+ .. versionchanged:: 1.13.0
+ Previously, the default was documented to be -1, but that was
+ in error. At some future date, the default will change to -1, as
+ originally intended.
+ Until then, the axis should be given explicitly when
+ ``arr.ndim > 1``, to avoid a FutureWarning.
+ kind : {'quicksort', 'mergesort', 'heapsort', 'stable'}, optional
+ The sorting algorithm used.
+ order : list, optional
+ When `a` is an array with fields defined, this argument specifies
+ which fields to compare first, second, etc. Not all fields need be
+ specified.
+ endwith : {True, False}, optional
+ Whether missing values (if any) should be treated as the largest values
+ (True) or the smallest values (False)
+ When the array contains unmasked values at the same extremes of the
+ datatype, the ordering of these values and the masked values is
+ undefined.
+ fill_value : scalar or None, optional
+ Value used internally for the masked values.
+ If ``fill_value`` is not None, it supersedes ``endwith``.
+
+ Returns
+ -------
+ index_array : ndarray, int
+ Array of indices that sort `a` along the specified axis.
+ In other words, ``a[index_array]`` yields a sorted `a`.
+
+ See Also
+ --------
+ ma.MaskedArray.sort : Describes sorting algorithms used.
+ lexsort : Indirect stable sort with multiple keys.
+ numpy.ndarray.sort : Inplace sort.
+
+ Notes
+ -----
+ See `sort` for notes on the different sorting algorithms.
+
+ Examples
+ --------
+ >>> a = np.ma.array([3,2,1], mask=[False, False, True])
+ >>> a
+ masked_array(data=[3, 2, --],
+ mask=[False, False, True],
+ fill_value=999999)
+ >>> a.argsort()
+ array([1, 0, 2])
+
+ """
+
+ # 2017-04-11, Numpy 1.13.0, gh-8701: warn on axis default
+ if axis is np._NoValue:
+ axis = _deprecate_argsort_axis(self)
+
+ if fill_value is None:
+ if endwith:
+ # nan > inf
+ if np.issubdtype(self.dtype, np.floating):
+ fill_value = np.nan
+ else:
+ fill_value = minimum_fill_value(self)
+ else:
+ fill_value = maximum_fill_value(self)
+
+ filled = self.filled(fill_value)
+ return filled.argsort(axis=axis, kind=kind, order=order)
+
+ def argmin(self, axis=None, fill_value=None, out=None, *,
+ keepdims=np._NoValue):
+ """
+ Return array of indices to the minimum values along the given axis.
+
+ Parameters
+ ----------
+ axis : {None, integer}
+ If None, the index is into the flattened array, otherwise along
+ the specified axis
+ fill_value : scalar or None, optional
+ Value used to fill in the masked values. If None, the output of
+ minimum_fill_value(self._data) is used instead.
+ out : {None, array}, optional
+ Array into which the result can be placed. Its type is preserved
+ and it must be of the right shape to hold the output.
+
+ Returns
+ -------
+ ndarray or scalar
+ If multi-dimension input, returns a new ndarray of indices to the
+ minimum values along the given axis. Otherwise, returns a scalar
+ of index to the minimum values along the given axis.
+
+ Examples
+ --------
+ >>> x = np.ma.array(np.arange(4), mask=[1,1,0,0])
+ >>> x.shape = (2,2)
+ >>> x
+ masked_array(
+ data=[[--, --],
+ [2, 3]],
+ mask=[[ True, True],
+ [False, False]],
+ fill_value=999999)
+ >>> x.argmin(axis=0, fill_value=-1)
+ array([0, 0])
+ >>> x.argmin(axis=0, fill_value=9)
+ array([1, 1])
+
+ """
+ if fill_value is None:
+ fill_value = minimum_fill_value(self)
+ d = self.filled(fill_value).view(ndarray)
+ keepdims = False if keepdims is np._NoValue else bool(keepdims)
+ return d.argmin(axis, out=out, keepdims=keepdims)
+
+ def argmax(self, axis=None, fill_value=None, out=None, *,
+ keepdims=np._NoValue):
+ """
+ Returns array of indices of the maximum values along the given axis.
+ Masked values are treated as if they had the value fill_value.
+
+ Parameters
+ ----------
+ axis : {None, integer}
+ If None, the index is into the flattened array, otherwise along
+ the specified axis
+ fill_value : scalar or None, optional
+ Value used to fill in the masked values. If None, the output of
+ maximum_fill_value(self._data) is used instead.
+ out : {None, array}, optional
+ Array into which the result can be placed. Its type is preserved
+ and it must be of the right shape to hold the output.
+
+ Returns
+ -------
+ index_array : {integer_array}
+
+ Examples
+ --------
+ >>> a = np.arange(6).reshape(2,3)
+ >>> a.argmax()
+ 5
+ >>> a.argmax(0)
+ array([1, 1, 1])
+ >>> a.argmax(1)
+ array([2, 2])
+
+ """
+ if fill_value is None:
+ fill_value = maximum_fill_value(self._data)
+ d = self.filled(fill_value).view(ndarray)
+ keepdims = False if keepdims is np._NoValue else bool(keepdims)
+ return d.argmax(axis, out=out, keepdims=keepdims)
+
+ def sort(self, axis=-1, kind=None, order=None,
+ endwith=True, fill_value=None):
+ """
+ Sort the array, in-place
+
+ Parameters
+ ----------
+ a : array_like
+ Array to be sorted.
+ axis : int, optional
+ Axis along which to sort. If None, the array is flattened before
+ sorting. The default is -1, which sorts along the last axis.
+ kind : {'quicksort', 'mergesort', 'heapsort', 'stable'}, optional
+ The sorting algorithm used.
+ order : list, optional
+ When `a` is a structured array, this argument specifies which fields
+ to compare first, second, and so on. This list does not need to
+ include all of the fields.
+ endwith : {True, False}, optional
+ Whether missing values (if any) should be treated as the largest values
+ (True) or the smallest values (False)
+ When the array contains unmasked values sorting at the same extremes of the
+ datatype, the ordering of these values and the masked values is
+ undefined.
+ fill_value : scalar or None, optional
+ Value used internally for the masked values.
+ If ``fill_value`` is not None, it supersedes ``endwith``.
+
+ Returns
+ -------
+ sorted_array : ndarray
+ Array of the same type and shape as `a`.
+
+ See Also
+ --------
+ numpy.ndarray.sort : Method to sort an array in-place.
+ argsort : Indirect sort.
+ lexsort : Indirect stable sort on multiple keys.
+ searchsorted : Find elements in a sorted array.
+
+ Notes
+ -----
+ See ``sort`` for notes on the different sorting algorithms.
+
+ Examples
+ --------
+ >>> a = np.ma.array([1, 2, 5, 4, 3],mask=[0, 1, 0, 1, 0])
+ >>> # Default
+ >>> a.sort()
+ >>> a
+ masked_array(data=[1, 3, 5, --, --],
+ mask=[False, False, False, True, True],
+ fill_value=999999)
+
+ >>> a = np.ma.array([1, 2, 5, 4, 3],mask=[0, 1, 0, 1, 0])
+ >>> # Put missing values in the front
+ >>> a.sort(endwith=False)
+ >>> a
+ masked_array(data=[--, --, 1, 3, 5],
+ mask=[ True, True, False, False, False],
+ fill_value=999999)
+
+ >>> a = np.ma.array([1, 2, 5, 4, 3],mask=[0, 1, 0, 1, 0])
+ >>> # fill_value takes over endwith
+ >>> a.sort(endwith=False, fill_value=3)
+ >>> a
+ masked_array(data=[1, --, --, 3, 5],
+ mask=[False, True, True, False, False],
+ fill_value=999999)
+
+ """
+ if self._mask is nomask:
+ ndarray.sort(self, axis=axis, kind=kind, order=order)
+ return
+
+ if self is masked:
+ return
+
+ sidx = self.argsort(axis=axis, kind=kind, order=order,
+ fill_value=fill_value, endwith=endwith)
+
+ self[...] = np.take_along_axis(self, sidx, axis=axis)
+
+ def min(self, axis=None, out=None, fill_value=None, keepdims=np._NoValue):
+ """
+ Return the minimum along a given axis.
+
+ Parameters
+ ----------
+ axis : None or int or tuple of ints, optional
+ Axis along which to operate. By default, ``axis`` is None and the
+ flattened input is used.
+ .. versionadded:: 1.7.0
+ If this is a tuple of ints, the minimum is selected over multiple
+ axes, instead of a single axis or all the axes as before.
+ out : array_like, optional
+ Alternative output array in which to place the result. Must be of
+ the same shape and buffer length as the expected output.
+ fill_value : scalar or None, optional
+ Value used to fill in the masked values.
+ If None, use the output of `minimum_fill_value`.
+ keepdims : bool, optional
+ If this is set to True, the axes which are reduced are left
+ in the result as dimensions with size one. With this option,
+ the result will broadcast correctly against the array.
+
+ Returns
+ -------
+ amin : array_like
+ New array holding the result.
+ If ``out`` was specified, ``out`` is returned.
+
+ See Also
+ --------
+ ma.minimum_fill_value
+ Returns the minimum filling value for a given datatype.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> x = [[1., -2., 3.], [0.2, -0.7, 0.1]]
+ >>> mask = [[1, 1, 0], [0, 0, 1]]
+ >>> masked_x = ma.masked_array(x, mask)
+ >>> masked_x
+ masked_array(
+ data=[[--, --, 3.0],
+ [0.2, -0.7, --]],
+ mask=[[ True, True, False],
+ [False, False, True]],
+ fill_value=1e+20)
+ >>> ma.min(masked_x)
+ -0.7
+ >>> ma.min(masked_x, axis=-1)
+ masked_array(data=[3.0, -0.7],
+ mask=[False, False],
+ fill_value=1e+20)
+ >>> ma.min(masked_x, axis=0, keepdims=True)
+ masked_array(data=[[0.2, -0.7, 3.0]],
+ mask=[[False, False, False]],
+ fill_value=1e+20)
+ >>> mask = [[1, 1, 1,], [1, 1, 1]]
+ >>> masked_x = ma.masked_array(x, mask)
+ >>> ma.min(masked_x, axis=0)
+ masked_array(data=[--, --, --],
+ mask=[ True, True, True],
+ fill_value=1e+20,
+ dtype=float64)
+ """
+ kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
+
+ _mask = self._mask
+ newmask = _check_mask_axis(_mask, axis, **kwargs)
+ if fill_value is None:
+ fill_value = minimum_fill_value(self)
+ # No explicit output
+ if out is None:
+ result = self.filled(fill_value).min(
+ axis=axis, out=out, **kwargs).view(type(self))
+ if result.ndim:
+ # Set the mask
+ result.__setmask__(newmask)
+ # Get rid of Infs
+ if newmask.ndim:
+ np.copyto(result, result.fill_value, where=newmask)
+ elif newmask:
+ result = masked
+ return result
+ # Explicit output
+ result = self.filled(fill_value).min(axis=axis, out=out, **kwargs)
+ if isinstance(out, MaskedArray):
+ outmask = getmask(out)
+ if outmask is nomask:
+ outmask = out._mask = make_mask_none(out.shape)
+ outmask.flat = newmask
+ else:
+ if out.dtype.kind in 'biu':
+ errmsg = "Masked data information would be lost in one or more"\
+ " location."
+ raise MaskError(errmsg)
+ np.copyto(out, np.nan, where=newmask)
+ return out
+
+ def max(self, axis=None, out=None, fill_value=None, keepdims=np._NoValue):
+ """
+ Return the maximum along a given axis.
+
+ Parameters
+ ----------
+ axis : None or int or tuple of ints, optional
+ Axis along which to operate. By default, ``axis`` is None and the
+ flattened input is used.
+ .. versionadded:: 1.7.0
+ If this is a tuple of ints, the maximum is selected over multiple
+ axes, instead of a single axis or all the axes as before.
+ out : array_like, optional
+ Alternative output array in which to place the result. Must
+ be of the same shape and buffer length as the expected output.
+ fill_value : scalar or None, optional
+ Value used to fill in the masked values.
+ If None, use the output of maximum_fill_value().
+ keepdims : bool, optional
+ If this is set to True, the axes which are reduced are left
+ in the result as dimensions with size one. With this option,
+ the result will broadcast correctly against the array.
+
+ Returns
+ -------
+ amax : array_like
+ New array holding the result.
+ If ``out`` was specified, ``out`` is returned.
+
+ See Also
+ --------
+ ma.maximum_fill_value
+ Returns the maximum filling value for a given datatype.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> x = [[-1., 2.5], [4., -2.], [3., 0.]]
+ >>> mask = [[0, 0], [1, 0], [1, 0]]
+ >>> masked_x = ma.masked_array(x, mask)
+ >>> masked_x
+ masked_array(
+ data=[[-1.0, 2.5],
+ [--, -2.0],
+ [--, 0.0]],
+ mask=[[False, False],
+ [ True, False],
+ [ True, False]],
+ fill_value=1e+20)
+ >>> ma.max(masked_x)
+ 2.5
+ >>> ma.max(masked_x, axis=0)
+ masked_array(data=[-1.0, 2.5],
+ mask=[False, False],
+ fill_value=1e+20)
+ >>> ma.max(masked_x, axis=1, keepdims=True)
+ masked_array(
+ data=[[2.5],
+ [-2.0],
+ [0.0]],
+ mask=[[False],
+ [False],
+ [False]],
+ fill_value=1e+20)
+ >>> mask = [[1, 1], [1, 1], [1, 1]]
+ >>> masked_x = ma.masked_array(x, mask)
+ >>> ma.max(masked_x, axis=1)
+ masked_array(data=[--, --, --],
+ mask=[ True, True, True],
+ fill_value=1e+20,
+ dtype=float64)
+ """
+ kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
+
+ _mask = self._mask
+ newmask = _check_mask_axis(_mask, axis, **kwargs)
+ if fill_value is None:
+ fill_value = maximum_fill_value(self)
+ # No explicit output
+ if out is None:
+ result = self.filled(fill_value).max(
+ axis=axis, out=out, **kwargs).view(type(self))
+ if result.ndim:
+ # Set the mask
+ result.__setmask__(newmask)
+ # Get rid of Infs
+ if newmask.ndim:
+ np.copyto(result, result.fill_value, where=newmask)
+ elif newmask:
+ result = masked
+ return result
+ # Explicit output
+ result = self.filled(fill_value).max(axis=axis, out=out, **kwargs)
+ if isinstance(out, MaskedArray):
+ outmask = getmask(out)
+ if outmask is nomask:
+ outmask = out._mask = make_mask_none(out.shape)
+ outmask.flat = newmask
+ else:
+
+ if out.dtype.kind in 'biu':
+ errmsg = "Masked data information would be lost in one or more"\
+ " location."
+ raise MaskError(errmsg)
+ np.copyto(out, np.nan, where=newmask)
+ return out
+
+ def ptp(self, axis=None, out=None, fill_value=None, keepdims=False):
+ """
+ Return (maximum - minimum) along the given dimension
+ (i.e. peak-to-peak value).
+
+ .. warning::
+ `ptp` preserves the data type of the array. This means the
+ return value for an input of signed integers with n bits
+ (e.g. `np.int8`, `np.int16`, etc) is also a signed integer
+ with n bits. In that case, peak-to-peak values greater than
+ ``2**(n-1)-1`` will be returned as negative values. An example
+ with a work-around is shown below.
+
+ Parameters
+ ----------
+ axis : {None, int}, optional
+ Axis along which to find the peaks. If None (default) the
+ flattened array is used.
+ out : {None, array_like}, optional
+ Alternative output array in which to place the result. It must
+ have the same shape and buffer length as the expected output
+ but the type will be cast if necessary.
+ fill_value : scalar or None, optional
+ Value used to fill in the masked values.
+ keepdims : bool, optional
+ If this is set to True, the axes which are reduced are left
+ in the result as dimensions with size one. With this option,
+ the result will broadcast correctly against the array.
+
+ Returns
+ -------
+ ptp : ndarray.
+ A new array holding the result, unless ``out`` was
+ specified, in which case a reference to ``out`` is returned.
+
+ Examples
+ --------
+ >>> x = np.ma.MaskedArray([[4, 9, 2, 10],
+ ... [6, 9, 7, 12]])
+
+ >>> x.ptp(axis=1)
+ masked_array(data=[8, 6],
+ mask=False,
+ fill_value=999999)
+
+ >>> x.ptp(axis=0)
+ masked_array(data=[2, 0, 5, 2],
+ mask=False,
+ fill_value=999999)
+
+ >>> x.ptp()
+ 10
+
+ This example shows that a negative value can be returned when
+ the input is an array of signed integers.
+
+ >>> y = np.ma.MaskedArray([[1, 127],
+ ... [0, 127],
+ ... [-1, 127],
+ ... [-2, 127]], dtype=np.int8)
+ >>> y.ptp(axis=1)
+ masked_array(data=[ 126, 127, -128, -127],
+ mask=False,
+ fill_value=999999,
+ dtype=int8)
+
+ A work-around is to use the `view()` method to view the result as
+ unsigned integers with the same bit width:
+
+ >>> y.ptp(axis=1).view(np.uint8)
+ masked_array(data=[126, 127, 128, 129],
+ mask=False,
+ fill_value=999999,
+ dtype=uint8)
+ """
+ if out is None:
+ result = self.max(axis=axis, fill_value=fill_value,
+ keepdims=keepdims)
+ result -= self.min(axis=axis, fill_value=fill_value,
+ keepdims=keepdims)
+ return result
+ out.flat = self.max(axis=axis, out=out, fill_value=fill_value,
+ keepdims=keepdims)
+ min_value = self.min(axis=axis, fill_value=fill_value,
+ keepdims=keepdims)
+ np.subtract(out, min_value, out=out, casting='unsafe')
+ return out
+
+ def partition(self, *args, **kwargs):
+ warnings.warn("Warning: 'partition' will ignore the 'mask' "
+ f"of the {self.__class__.__name__}.",
+ stacklevel=2)
+ return super().partition(*args, **kwargs)
+
+ def argpartition(self, *args, **kwargs):
+ warnings.warn("Warning: 'argpartition' will ignore the 'mask' "
+ f"of the {self.__class__.__name__}.",
+ stacklevel=2)
+ return super().argpartition(*args, **kwargs)
+
+ def take(self, indices, axis=None, out=None, mode='raise'):
+ """
+ """
+ (_data, _mask) = (self._data, self._mask)
+ cls = type(self)
+ # Make sure the indices are not masked
+ maskindices = getmask(indices)
+ if maskindices is not nomask:
+ indices = indices.filled(0)
+ # Get the data, promoting scalars to 0d arrays with [...] so that
+ # .view works correctly
+ if out is None:
+ out = _data.take(indices, axis=axis, mode=mode)[...].view(cls)
+ else:
+ np.take(_data, indices, axis=axis, mode=mode, out=out)
+ # Get the mask
+ if isinstance(out, MaskedArray):
+ if _mask is nomask:
+ outmask = maskindices
+ else:
+ outmask = _mask.take(indices, axis=axis, mode=mode)
+ outmask |= maskindices
+ out.__setmask__(outmask)
+ # demote 0d arrays back to scalars, for consistency with ndarray.take
+ return out[()]
+
+ # Array methods
+ copy = _arraymethod('copy')
+ diagonal = _arraymethod('diagonal')
+ flatten = _arraymethod('flatten')
+ repeat = _arraymethod('repeat')
+ squeeze = _arraymethod('squeeze')
+ swapaxes = _arraymethod('swapaxes')
+ T = property(fget=lambda self: self.transpose())
+ transpose = _arraymethod('transpose')
+
+ def tolist(self, fill_value=None):
+ """
+ Return the data portion of the masked array as a hierarchical Python list.
+
+ Data items are converted to the nearest compatible Python type.
+ Masked values are converted to `fill_value`. If `fill_value` is None,
+ the corresponding entries in the output list will be ``None``.
+
+ Parameters
+ ----------
+ fill_value : scalar, optional
+ The value to use for invalid entries. Default is None.
+
+ Returns
+ -------
+ result : list
+ The Python list representation of the masked array.
+
+ Examples
+ --------
+ >>> x = np.ma.array([[1,2,3], [4,5,6], [7,8,9]], mask=[0] + [1,0]*4)
+ >>> x.tolist()
+ [[1, None, 3], [None, 5, None], [7, None, 9]]
+ >>> x.tolist(-999)
+ [[1, -999, 3], [-999, 5, -999], [7, -999, 9]]
+
+ """
+ _mask = self._mask
+ # No mask ? Just return .data.tolist ?
+ if _mask is nomask:
+ return self._data.tolist()
+ # Explicit fill_value: fill the array and get the list
+ if fill_value is not None:
+ return self.filled(fill_value).tolist()
+ # Structured array.
+ names = self.dtype.names
+ if names:
+ result = self._data.astype([(_, object) for _ in names])
+ for n in names:
+ result[n][_mask[n]] = None
+ return result.tolist()
+ # Standard arrays.
+ if _mask is nomask:
+ return [None]
+ # Set temps to save time when dealing w/ marrays.
+ inishape = self.shape
+ result = np.array(self._data.ravel(), dtype=object)
+ result[_mask.ravel()] = None
+ result.shape = inishape
+ return result.tolist()
+
+ def tostring(self, fill_value=None, order='C'):
+ r"""
+ A compatibility alias for `tobytes`, with exactly the same behavior.
+
+ Despite its name, it returns `bytes` not `str`\ s.
+
+ .. deprecated:: 1.19.0
+ """
+ # 2020-03-30, Numpy 1.19.0
+ warnings.warn(
+ "tostring() is deprecated. Use tobytes() instead.",
+ DeprecationWarning, stacklevel=2)
+
+ return self.tobytes(fill_value, order=order)
+
+ 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
+ Value used to fill in the masked values. Default is None, in which
+ case `MaskedArray.fill_value` is used.
+ order : {'C','F','A'}, optional
+ Order of the data item in the copy. Default is 'C'.
+
+ - 'C' -- C order (row major).
+ - 'F' -- Fortran order (column major).
+ - 'A' -- Any, current order of array.
+ - None -- Same as 'A'.
+
+ See Also
+ --------
+ numpy.ndarray.tobytes
+ tolist, tofile
+
+ Notes
+ -----
+ 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.tobytes()
+ b'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00?B\\x0f\\x00\\x00\\x00\\x00\\x00?B\\x0f\\x00\\x00\\x00\\x00\\x00\\x04\\x00\\x00\\x00\\x00\\x00\\x00\\x00'
+
+ """
+ return self.filled(fill_value).tobytes(order=order)
+
+ def tofile(self, fid, sep="", format="%s"):
+ """
+ Save a masked array to a file in binary format.
+
+ .. warning::
+ This function is not implemented yet.
+
+ Raises
+ ------
+ NotImplementedError
+ When `tofile` is called.
+
+ """
+ raise NotImplementedError("MaskedArray.tofile() not implemented yet.")
+
+ def toflex(self):
+ """
+ Transforms a masked array into a flexible-type array.
+
+ The flexible type array that is returned will have two fields:
+
+ * the ``_data`` field stores the ``_data`` part of the array.
+ * the ``_mask`` field stores the ``_mask`` part of the array.
+
+ Parameters
+ ----------
+ None
+
+ Returns
+ -------
+ record : ndarray
+ A new flexible-type `ndarray` with two fields: the first element
+ containing a value, the second element containing the corresponding
+ mask boolean. The returned record shape matches self.shape.
+
+ Notes
+ -----
+ A side-effect of transforming a masked array into a flexible `ndarray` is
+ that meta information (``fill_value``, ...) will be lost.
+
+ Examples
+ --------
+ >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4)
+ >>> x
+ masked_array(
+ data=[[1, --, 3],
+ [--, 5, --],
+ [7, --, 9]],
+ mask=[[False, True, False],
+ [ True, False, True],
+ [False, True, False]],
+ fill_value=999999)
+ >>> x.toflex()
+ array([[(1, False), (2, True), (3, False)],
+ [(4, True), (5, False), (6, True)],
+ [(7, False), (8, True), (9, False)]],
+ dtype=[('_data', '<i8'), ('_mask', '?')])
+
+ """
+ # Get the basic dtype.
+ ddtype = self.dtype
+ # Make sure we have a mask
+ _mask = self._mask
+ if _mask is None:
+ _mask = make_mask_none(self.shape, ddtype)
+ # And get its dtype
+ mdtype = self._mask.dtype
+
+ record = np.ndarray(shape=self.shape,
+ dtype=[('_data', ddtype), ('_mask', mdtype)])
+ record['_data'] = self._data
+ record['_mask'] = self._mask
+ return record
+ torecords = toflex
+
+ # Pickling
+ def __getstate__(self):
+ """Return the internal state of the masked array, for pickling
+ purposes.
+
+ """
+ cf = 'CF'[self.flags.fnc]
+ data_state = super().__reduce__()[2]
+ return data_state + (getmaskarray(self).tobytes(cf), self._fill_value)
+
+ def __setstate__(self, state):
+ """Restore the internal state of the masked array, for
+ pickling purposes. ``state`` is typically the output of the
+ ``__getstate__`` output, and is a 5-tuple:
+
+ - class name
+ - a tuple giving the shape of the data
+ - a typecode for the data
+ - a binary string for the data
+ - a binary string for the mask.
+
+ """
+ (_, shp, typ, isf, raw, msk, flv) = state
+ super().__setstate__((shp, typ, isf, raw))
+ self._mask.__setstate__((shp, make_mask_descr(typ), isf, msk))
+ self.fill_value = flv
+
+ def __reduce__(self):
+ """Return a 3-tuple for pickling a MaskedArray.
+
+ """
+ return (_mareconstruct,
+ (self.__class__, self._baseclass, (0,), 'b',),
+ self.__getstate__())
+
+ def __deepcopy__(self, memo=None):
+ from copy import deepcopy
+ copied = MaskedArray.__new__(type(self), self, copy=True)
+ if memo is None:
+ memo = {}
+ memo[id(self)] = copied
+ for (k, v) in self.__dict__.items():
+ copied.__dict__[k] = deepcopy(v, memo)
+ return copied
+
+
+def _mareconstruct(subtype, baseclass, baseshape, basetype,):
+ """Internal function that builds a new MaskedArray from the
+ information stored in a pickle.
+
+ """
+ _data = ndarray.__new__(baseclass, baseshape, basetype)
+ _mask = ndarray.__new__(ndarray, baseshape, make_mask_descr(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, dtype=None, fill_value=None,
+ hardmask=False, copy=False, subok=True):
+ _data = np.array(data, copy=copy, subok=subok, dtype=dtype)
+ _data = _data.view(self)
+ _data._hardmask = hardmask
+ if mask is not nomask:
+ if isinstance(mask, np.void):
+ _data._mask = mask
+ else:
+ try:
+ # Mask is already a 0D array
+ _data._mask = np.void(mask)
+ except TypeError:
+ # Transform the mask to a void
+ mdtype = make_mask_descr(dtype)
+ _data._mask = np.array(mask, dtype=mdtype)[()]
+ if fill_value is not None:
+ _data.fill_value = fill_value
+ return _data
+
+ @property
+ def _data(self):
+ # Make sure that the _data part is a np.void
+ return super()._data[()]
+
+ def __getitem__(self, indx):
+ """
+ Get the index.
+
+ """
+ m = self._mask
+ if isinstance(m[indx], ndarray):
+ # Can happen when indx is a multi-dimensional field:
+ # A = ma.masked_array(data=[([0,1],)], mask=[([True,
+ # False],)], dtype=[("A", ">i2", (2,))])
+ # x = A[0]; y = x["A"]; then y.mask["A"].size==2
+ # and we can not say masked/unmasked.
+ # The result is no longer mvoid!
+ # See also issue #6724.
+ return masked_array(
+ data=self._data[indx], mask=m[indx],
+ fill_value=self._fill_value[indx],
+ hard_mask=self._hardmask)
+ if m is not nomask and m[indx]:
+ return masked
+ return self._data[indx]
+
+ def __setitem__(self, indx, value):
+ self._data[indx] = value
+ if self._hardmask:
+ self._mask[indx] |= getattr(value, "_mask", False)
+ else:
+ self._mask[indx] = getattr(value, "_mask", False)
+
+ def __str__(self):
+ m = self._mask
+ if m is nomask:
+ return str(self._data)
+
+ rdtype = _replace_dtype_fields(self._data.dtype, "O")
+ data_arr = super()._data
+ res = data_arr.astype(rdtype)
+ _recursive_printoption(res, self._mask, masked_print_option)
+ return str(res)
+
+ __repr__ = __str__
+
+ def __iter__(self):
+ "Defines an iterator for mvoid"
+ (_data, _mask) = (self._data, self._mask)
+ if _mask is nomask:
+ yield from _data
+ else:
+ for (d, m) in zip(_data, _mask):
+ if m:
+ yield masked
+ else:
+ yield d
+
+ def __len__(self):
+ return self._data.__len__()
+
+ def filled(self, fill_value=None):
+ """
+ Return a copy with masked fields filled with a given value.
+
+ Parameters
+ ----------
+ fill_value : array_like, optional
+ The value to use for invalid entries. Can be scalar or
+ non-scalar. If latter is the case, the filled array should
+ be broadcastable over input array. Default is None, in
+ which case the `fill_value` attribute is used instead.
+
+ Returns
+ -------
+ filled_void
+ A `np.void` object
+
+ See Also
+ --------
+ MaskedArray.filled
+
+ """
+ return asarray(self).filled(fill_value)[()]
+
+ def tolist(self):
+ """
+ Transforms the mvoid object into a tuple.
+
+ Masked fields are replaced by None.
+
+ Returns
+ -------
+ returned_tuple
+ Tuple of fields
+ """
+ _mask = self._mask
+ if _mask is nomask:
+ return self._data.tolist()
+ result = []
+ for (d, m) in zip(self._data, self._mask):
+ if m:
+ result.append(None)
+ else:
+ # .item() makes sure we return a standard Python object
+ result.append(d.item())
+ return tuple(result)
+
+
+##############################################################################
+# Shortcuts #
+##############################################################################
+
+
+def isMaskedArray(x):
+ """
+ Test whether input is an instance of MaskedArray.
+
+ This function returns True if `x` is an instance of MaskedArray
+ and returns False otherwise. Any object is accepted as input.
+
+ Parameters
+ ----------
+ x : object
+ Object to test.
+
+ Returns
+ -------
+ result : bool
+ True if `x` is a MaskedArray.
+
+ See Also
+ --------
+ isMA : Alias to isMaskedArray.
+ isarray : Alias to isMaskedArray.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> a = np.eye(3, 3)
+ >>> a
+ array([[ 1., 0., 0.],
+ [ 0., 1., 0.],
+ [ 0., 0., 1.]])
+ >>> m = ma.masked_values(a, 0)
+ >>> m
+ masked_array(
+ data=[[1.0, --, --],
+ [--, 1.0, --],
+ [--, --, 1.0]],
+ mask=[[False, True, True],
+ [ True, False, True],
+ [ True, True, False]],
+ fill_value=0.0)
+ >>> ma.isMaskedArray(a)
+ False
+ >>> ma.isMaskedArray(m)
+ True
+ >>> ma.isMaskedArray([0, 1, 2])
+ False
+
+ """
+ return isinstance(x, MaskedArray)
+
+
+isarray = isMaskedArray
+isMA = isMaskedArray # backward compatibility
+
+
+class MaskedConstant(MaskedArray):
+ # the lone np.ma.masked instance
+ __singleton = None
+
+ @classmethod
+ def __has_singleton(cls):
+ # second case ensures `cls.__singleton` is not just a view on the
+ # superclass singleton
+ return cls.__singleton is not None and type(cls.__singleton) is cls
+
+ def __new__(cls):
+ if not cls.__has_singleton():
+ # We define the masked singleton as a float for higher precedence.
+ # Note that it can be tricky sometimes w/ type comparison
+ data = np.array(0.)
+ mask = np.array(True)
+
+ # prevent any modifications
+ data.flags.writeable = False
+ mask.flags.writeable = False
+
+ # don't fall back on MaskedArray.__new__(MaskedConstant), since
+ # that might confuse it - this way, the construction is entirely
+ # within our control
+ cls.__singleton = MaskedArray(data, mask=mask).view(cls)
+
+ return cls.__singleton
+
+ def __array_finalize__(self, obj):
+ if not self.__has_singleton():
+ # this handles the `.view` in __new__, which we want to copy across
+ # properties normally
+ return super().__array_finalize__(obj)
+ elif self is self.__singleton:
+ # not clear how this can happen, play it safe
+ pass
+ else:
+ # everywhere else, we want to downcast to MaskedArray, to prevent a
+ # duplicate maskedconstant.
+ self.__class__ = MaskedArray
+ MaskedArray.__array_finalize__(self, obj)
+
+ def __array_prepare__(self, obj, context=None):
+ return self.view(MaskedArray).__array_prepare__(obj, context)
+
+ def __array_wrap__(self, obj, context=None):
+ return self.view(MaskedArray).__array_wrap__(obj, context)
+
+ def __str__(self):
+ return str(masked_print_option._display)
+
+ def __repr__(self):
+ if self is MaskedConstant.__singleton:
+ return 'masked'
+ else:
+ # it's a subclass, or something is wrong, make it obvious
+ return object.__repr__(self)
+
+ def __format__(self, format_spec):
+ # Replace ndarray.__format__ with the default, which supports no format characters.
+ # Supporting format characters is unwise here, because we do not know what type
+ # the user was expecting - better to not guess.
+ try:
+ return object.__format__(self, format_spec)
+ except TypeError:
+ # 2020-03-23, NumPy 1.19.0
+ warnings.warn(
+ "Format strings passed to MaskedConstant are ignored, but in future may "
+ "error or produce different behavior",
+ FutureWarning, stacklevel=2
+ )
+ return object.__format__(self, "")
+
+ def __reduce__(self):
+ """Override of MaskedArray's __reduce__.
+ """
+ return (self.__class__, ())
+
+ # inplace operations have no effect. We have to override them to avoid
+ # trying to modify the readonly data and mask arrays
+ def __iop__(self, other):
+ return self
+ __iadd__ = \
+ __isub__ = \
+ __imul__ = \
+ __ifloordiv__ = \
+ __itruediv__ = \
+ __ipow__ = \
+ __iop__
+ del __iop__ # don't leave this around
+
+ def copy(self, *args, **kwargs):
+ """ Copy is a no-op on the maskedconstant, as it is a scalar """
+ # maskedconstant is a scalar, so copy doesn't need to copy. There's
+ # precedent for this with `np.bool_` scalars.
+ return self
+
+ def __copy__(self):
+ return self
+
+ def __deepcopy__(self, memo):
+ return self
+
+ def __setattr__(self, attr, value):
+ if not self.__has_singleton():
+ # allow the singleton to be initialized
+ return super().__setattr__(attr, value)
+ elif self is self.__singleton:
+ raise AttributeError(
+ f"attributes of {self!r} are not writeable")
+ else:
+ # duplicate instance - we can end up here from __array_finalize__,
+ # where we set the __class__ attribute
+ return super().__setattr__(attr, value)
+
+
+masked = masked_singleton = MaskedConstant()
+masked_array = MaskedArray
+
+
+def array(data, dtype=None, copy=False, order=None,
+ mask=nomask, fill_value=None, keep_mask=True,
+ hard_mask=False, shrink=True, subok=True, ndmin=0):
+ """
+ Shortcut to MaskedArray.
+
+ The options are in a different order for convenience and backwards
+ compatibility.
+
+ """
+ return MaskedArray(data, mask=mask, dtype=dtype, copy=copy,
+ subok=subok, keep_mask=keep_mask,
+ hard_mask=hard_mask, fill_value=fill_value,
+ ndmin=ndmin, shrink=shrink, order=order)
+array.__doc__ = masked_array.__doc__
+
+
+def is_masked(x):
+ """
+ Determine whether input has masked values.
+
+ Accepts any object as input, but always returns False unless the
+ input is a MaskedArray containing masked values.
+
+ Parameters
+ ----------
+ x : array_like
+ Array to check for masked values.
+
+ Returns
+ -------
+ result : bool
+ True if `x` is a MaskedArray with masked values, False otherwise.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> x = ma.masked_equal([0, 1, 0, 2, 3], 0)
+ >>> x
+ masked_array(data=[--, 1, --, 2, 3],
+ mask=[ True, False, True, False, False],
+ fill_value=0)
+ >>> ma.is_masked(x)
+ True
+ >>> x = ma.masked_equal([0, 1, 0, 2, 3], 42)
+ >>> x
+ masked_array(data=[0, 1, 0, 2, 3],
+ mask=False,
+ fill_value=42)
+ >>> ma.is_masked(x)
+ False
+
+ Always returns False if `x` isn't a MaskedArray.
+
+ >>> x = [False, True, False]
+ >>> ma.is_masked(x)
+ False
+ >>> x = 'a string'
+ >>> ma.is_masked(x)
+ False
+
+ """
+ m = getmask(x)
+ if m is nomask:
+ return False
+ elif m.any():
+ return True
+ return False
+
+
+##############################################################################
+# Extrema functions #
+##############################################################################
+
+
+class _extrema_operation(_MaskedUFunc):
+ """
+ Generic class for maximum/minimum functions.
+
+ .. note::
+ This is the base class for `_maximum_operation` and
+ `_minimum_operation`.
+
+ """
+ def __init__(self, ufunc, compare, fill_value):
+ super().__init__(ufunc)
+ self.compare = compare
+ self.fill_value_func = fill_value
+
+ def __call__(self, a, b):
+ "Executes the call behavior."
+
+ return where(self.compare(a, b), a, b)
+
+ def reduce(self, target, axis=np._NoValue):
+ "Reduce target along the given axis."
+ target = narray(target, copy=False, subok=True)
+ m = getmask(target)
+
+ if axis is np._NoValue and target.ndim > 1:
+ # 2017-05-06, Numpy 1.13.0: warn on axis default
+ warnings.warn(
+ f"In the future the default for ma.{self.__name__}.reduce will be axis=0, "
+ f"not the current None, to match np.{self.__name__}.reduce. "
+ "Explicitly pass 0 or None to silence this warning.",
+ MaskedArrayFutureWarning, stacklevel=2)
+ axis = None
+
+ if axis is not np._NoValue:
+ kwargs = dict(axis=axis)
+ else:
+ kwargs = dict()
+
+ if m is nomask:
+ t = self.f.reduce(target, **kwargs)
+ else:
+ target = target.filled(
+ self.fill_value_func(target)).view(type(target))
+ t = self.f.reduce(target, **kwargs)
+ m = umath.logical_and.reduce(m, **kwargs)
+ if hasattr(t, '_mask'):
+ t._mask = m
+ elif m:
+ t = masked
+ return t
+
+ def outer(self, a, b):
+ "Return the function applied to the outer product of a and b."
+ ma = getmask(a)
+ mb = getmask(b)
+ if ma is nomask and mb is nomask:
+ m = nomask
+ else:
+ ma = getmaskarray(a)
+ mb = getmaskarray(b)
+ m = logical_or.outer(ma, mb)
+ result = self.f.outer(filled(a), filled(b))
+ if not isinstance(result, MaskedArray):
+ result = result.view(MaskedArray)
+ result._mask = m
+ return result
+
+def min(obj, axis=None, out=None, fill_value=None, keepdims=np._NoValue):
+ kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
+
+ try:
+ return obj.min(axis=axis, fill_value=fill_value, out=out, **kwargs)
+ except (AttributeError, TypeError):
+ # If obj doesn't have a min method, or if the method doesn't accept a
+ # fill_value argument
+ return asanyarray(obj).min(axis=axis, fill_value=fill_value,
+ out=out, **kwargs)
+min.__doc__ = MaskedArray.min.__doc__
+
+def max(obj, axis=None, out=None, fill_value=None, keepdims=np._NoValue):
+ kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
+
+ try:
+ return obj.max(axis=axis, fill_value=fill_value, out=out, **kwargs)
+ except (AttributeError, TypeError):
+ # If obj doesn't have a max method, or if the method doesn't accept a
+ # fill_value argument
+ return asanyarray(obj).max(axis=axis, fill_value=fill_value,
+ out=out, **kwargs)
+max.__doc__ = MaskedArray.max.__doc__
+
+
+def ptp(obj, axis=None, out=None, fill_value=None, keepdims=np._NoValue):
+ kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
+ try:
+ return obj.ptp(axis, out=out, fill_value=fill_value, **kwargs)
+ except (AttributeError, TypeError):
+ # If obj doesn't have a ptp method or if the method doesn't accept
+ # a fill_value argument
+ return asanyarray(obj).ptp(axis=axis, fill_value=fill_value,
+ out=out, **kwargs)
+ptp.__doc__ = MaskedArray.ptp.__doc__
+
+
+##############################################################################
+# Definition of functions from the corresponding methods #
+##############################################################################
+
+
+class _frommethod:
+ """
+ Define functions from existing MaskedArray methods.
+
+ Parameters
+ ----------
+ methodname : str
+ Name of the method to transform.
+
+ """
+
+ def __init__(self, methodname, reversed=False):
+ self.__name__ = methodname
+ self.__doc__ = self.getdoc()
+ self.reversed = reversed
+
+ def getdoc(self):
+ "Return the doc of the function (from the doc of the method)."
+ meth = getattr(MaskedArray, self.__name__, None) or\
+ getattr(np, self.__name__, None)
+ signature = self.__name__ + get_object_signature(meth)
+ if meth is not None:
+ doc = """ %s\n%s""" % (
+ signature, getattr(meth, '__doc__', None))
+ return doc
+
+ def __call__(self, a, *args, **params):
+ if self.reversed:
+ args = list(args)
+ a, args[0] = args[0], a
+
+ marr = asanyarray(a)
+ method_name = self.__name__
+ method = getattr(type(marr), method_name, None)
+ if method is None:
+ # use the corresponding np function
+ method = getattr(np, method_name)
+
+ return method(marr, *args, **params)
+
+
+all = _frommethod('all')
+anomalies = anom = _frommethod('anom')
+any = _frommethod('any')
+compress = _frommethod('compress', reversed=True)
+cumprod = _frommethod('cumprod')
+cumsum = _frommethod('cumsum')
+copy = _frommethod('copy')
+diagonal = _frommethod('diagonal')
+harden_mask = _frommethod('harden_mask')
+ids = _frommethod('ids')
+maximum = _extrema_operation(umath.maximum, greater, maximum_fill_value)
+mean = _frommethod('mean')
+minimum = _extrema_operation(umath.minimum, less, minimum_fill_value)
+nonzero = _frommethod('nonzero')
+prod = _frommethod('prod')
+product = _frommethod('prod')
+ravel = _frommethod('ravel')
+repeat = _frommethod('repeat')
+shrink_mask = _frommethod('shrink_mask')
+soften_mask = _frommethod('soften_mask')
+std = _frommethod('std')
+sum = _frommethod('sum')
+swapaxes = _frommethod('swapaxes')
+#take = _frommethod('take')
+trace = _frommethod('trace')
+var = _frommethod('var')
+
+count = _frommethod('count')
+
+def take(a, indices, axis=None, out=None, mode='raise'):
+ """
+ """
+ a = masked_array(a)
+ return a.take(indices, axis=axis, out=out, mode=mode)
+
+
+def power(a, b, third=None):
+ """
+ Returns element-wise base array raised to power from second array.
+
+ This is the masked array version of `numpy.power`. For details see
+ `numpy.power`.
+
+ See Also
+ --------
+ numpy.power
+
+ Notes
+ -----
+ The *out* argument to `numpy.power` is not supported, `third` has to be
+ None.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> x = [11.2, -3.973, 0.801, -1.41]
+ >>> mask = [0, 0, 0, 1]
+ >>> masked_x = ma.masked_array(x, mask)
+ >>> masked_x
+ masked_array(data=[11.2, -3.973, 0.801, --],
+ mask=[False, False, False, True],
+ fill_value=1e+20)
+ >>> ma.power(masked_x, 2)
+ masked_array(data=[125.43999999999998, 15.784728999999999,
+ 0.6416010000000001, --],
+ mask=[False, False, False, True],
+ fill_value=1e+20)
+ >>> y = [-0.5, 2, 0, 17]
+ >>> masked_y = ma.masked_array(y, mask)
+ >>> masked_y
+ masked_array(data=[-0.5, 2.0, 0.0, --],
+ mask=[False, False, False, True],
+ fill_value=1e+20)
+ >>> ma.power(masked_x, masked_y)
+ masked_array(data=[0.29880715233359845, 15.784728999999999, 1.0, --],
+ mask=[False, False, False, True],
+ fill_value=1e+20)
+
+ """
+ if third is not None:
+ raise MaskError("3-argument power not supported.")
+ # Get the masks
+ ma = getmask(a)
+ mb = getmask(b)
+ m = mask_or(ma, mb)
+ # Get the rawdata
+ fa = getdata(a)
+ fb = getdata(b)
+ # Get the type of the result (so that we preserve subclasses)
+ if isinstance(a, MaskedArray):
+ basetype = type(a)
+ else:
+ basetype = MaskedArray
+ # Get the result and view it as a (subclass of) MaskedArray
+ 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
+ invalid = np.logical_not(np.isfinite(result.view(ndarray)))
+ # Add the initial mask
+ if m is not nomask:
+ if not result.ndim:
+ return masked
+ result._mask = np.logical_or(m, invalid)
+ # Fix the invalid parts
+ if invalid.any():
+ if not result.ndim:
+ return masked
+ elif result._mask is nomask:
+ result._mask = invalid
+ result._data[invalid] = result.fill_value
+ return result
+
+argmin = _frommethod('argmin')
+argmax = _frommethod('argmax')
+
+def argsort(a, axis=np._NoValue, kind=None, order=None, endwith=True, fill_value=None):
+ "Function version of the eponymous method."
+ a = np.asanyarray(a)
+
+ # 2017-04-11, Numpy 1.13.0, gh-8701: warn on axis default
+ if axis is np._NoValue:
+ axis = _deprecate_argsort_axis(a)
+
+ if isinstance(a, MaskedArray):
+ return a.argsort(axis=axis, kind=kind, order=order,
+ endwith=endwith, fill_value=fill_value)
+ else:
+ return a.argsort(axis=axis, kind=kind, order=order)
+argsort.__doc__ = MaskedArray.argsort.__doc__
+
+def sort(a, axis=-1, kind=None, order=None, endwith=True, fill_value=None):
+ """
+ Return a sorted copy of the masked array.
+
+ Equivalent to creating a copy of the array
+ and applying the MaskedArray ``sort()`` method.
+
+ Refer to ``MaskedArray.sort`` for the full documentation
+
+ See Also
+ --------
+ MaskedArray.sort : equivalent method
+ """
+ a = np.array(a, copy=True, subok=True)
+ if axis is None:
+ a = a.flatten()
+ axis = 0
+
+ if isinstance(a, MaskedArray):
+ a.sort(axis=axis, kind=kind, order=order,
+ endwith=endwith, fill_value=fill_value)
+ else:
+ a.sort(axis=axis, kind=kind, order=order)
+ return a
+
+
+def compressed(x):
+ """
+ Return all the non-masked data as a 1-D array.
+
+ This function is equivalent to calling the "compressed" method of a
+ `ma.MaskedArray`, see `ma.MaskedArray.compressed` for details.
+
+ See Also
+ --------
+ ma.MaskedArray.compressed : Equivalent method.
+
+ """
+ return asanyarray(x).compressed()
+
+
+def concatenate(arrays, axis=0):
+ """
+ Concatenate a sequence of arrays along the given axis.
+
+ Parameters
+ ----------
+ arrays : sequence of array_like
+ The arrays must have the same shape, except in the dimension
+ corresponding to `axis` (the first, by default).
+ axis : int, optional
+ The axis along which the arrays will be joined. Default is 0.
+
+ Returns
+ -------
+ result : MaskedArray
+ The concatenated array with any masked entries preserved.
+
+ See Also
+ --------
+ numpy.concatenate : Equivalent function in the top-level NumPy module.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> a = ma.arange(3)
+ >>> a[1] = ma.masked
+ >>> b = ma.arange(2, 5)
+ >>> a
+ masked_array(data=[0, --, 2],
+ mask=[False, True, False],
+ fill_value=999999)
+ >>> b
+ masked_array(data=[2, 3, 4],
+ mask=False,
+ fill_value=999999)
+ >>> ma.concatenate([a, b])
+ masked_array(data=[0, --, 2, 2, 3, 4],
+ mask=[False, True, False, False, False, False],
+ fill_value=999999)
+
+ """
+ d = np.concatenate([getdata(a) for a in arrays], axis)
+ rcls = get_masked_subclass(*arrays)
+ data = d.view(rcls)
+ # Check whether one of the arrays has a non-empty mask.
+ for x in arrays:
+ if getmask(x) is not nomask:
+ break
+ else:
+ return data
+ # OK, so we have to concatenate the masks
+ dm = np.concatenate([getmaskarray(a) for a in arrays], axis)
+ dm = dm.reshape(d.shape)
+
+ # If we decide to keep a '_shrinkmask' option, we want to check that
+ # all of them are True, and then check for dm.any()
+ data._mask = _shrink_mask(dm)
+ return data
+
+
+def diag(v, k=0):
+ """
+ Extract a diagonal or construct a diagonal array.
+
+ This function is the equivalent of `numpy.diag` that takes masked
+ values into account, see `numpy.diag` for details.
+
+ See Also
+ --------
+ numpy.diag : Equivalent function for ndarrays.
+
+ """
+ output = np.diag(v, k).view(MaskedArray)
+ if getmask(v) is not nomask:
+ output._mask = np.diag(v._mask, k)
+ return output
+
+
+def left_shift(a, n):
+ """
+ Shift the bits of an integer to the left.
+
+ This is the masked array version of `numpy.left_shift`, for details
+ see that function.
+
+ See Also
+ --------
+ numpy.left_shift
+
+ """
+ m = getmask(a)
+ if m is nomask:
+ d = umath.left_shift(filled(a), n)
+ return masked_array(d)
+ else:
+ d = umath.left_shift(filled(a, 0), n)
+ return masked_array(d, mask=m)
+
+
+def right_shift(a, n):
+ """
+ Shift the bits of an integer to the right.
+
+ This is the masked array version of `numpy.right_shift`, for details
+ see that function.
+
+ See Also
+ --------
+ numpy.right_shift
+
+ """
+ m = getmask(a)
+ if m is nomask:
+ d = umath.right_shift(filled(a), n)
+ return masked_array(d)
+ else:
+ d = umath.right_shift(filled(a, 0), n)
+ return masked_array(d, mask=m)
+
+
+def put(a, indices, values, mode='raise'):
+ """
+ Set storage-indexed locations to corresponding values.
+
+ This function is equivalent to `MaskedArray.put`, see that method
+ for details.
+
+ See Also
+ --------
+ MaskedArray.put
+
+ """
+ # We can't use 'frommethod', the order of arguments is different
+ try:
+ return a.put(indices, values, mode=mode)
+ except AttributeError:
+ return narray(a, copy=False).put(indices, values, mode=mode)
+
+
+def putmask(a, mask, values): # , mode='raise'):
+ """
+ Changes elements of an array based on conditional and input values.
+
+ This is the masked array version of `numpy.putmask`, for details see
+ `numpy.putmask`.
+
+ See Also
+ --------
+ numpy.putmask
+
+ Notes
+ -----
+ Using a masked array as `values` will **not** transform a `ndarray` into
+ a `MaskedArray`.
+
+ """
+ # We can't use 'frommethod', the order of arguments is different
+ if not isinstance(a, MaskedArray):
+ a = a.view(MaskedArray)
+ (valdata, valmask) = (getdata(values), getmask(values))
+ if getmask(a) is nomask:
+ if valmask is not nomask:
+ a._sharedmask = True
+ a._mask = make_mask_none(a.shape, a.dtype)
+ np.copyto(a._mask, valmask, where=mask)
+ elif a._hardmask:
+ if valmask is not nomask:
+ m = a._mask.copy()
+ np.copyto(m, valmask, where=mask)
+ a.mask |= m
+ else:
+ if valmask is nomask:
+ valmask = getmaskarray(values)
+ np.copyto(a._mask, valmask, where=mask)
+ np.copyto(a._data, valdata, where=mask)
+ return
+
+
+def transpose(a, axes=None):
+ """
+ Permute the dimensions of an array.
+
+ This function is exactly equivalent to `numpy.transpose`.
+
+ See Also
+ --------
+ numpy.transpose : Equivalent function in top-level NumPy module.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> x = ma.arange(4).reshape((2,2))
+ >>> x[1, 1] = ma.masked
+ >>> x
+ masked_array(
+ data=[[0, 1],
+ [2, --]],
+ mask=[[False, False],
+ [False, True]],
+ fill_value=999999)
+
+ >>> ma.transpose(x)
+ masked_array(
+ data=[[0, 2],
+ [1, --]],
+ mask=[[False, False],
+ [False, True]],
+ fill_value=999999)
+ """
+ # We can't use 'frommethod', as 'transpose' doesn't take keywords
+ try:
+ return a.transpose(axes)
+ except AttributeError:
+ return narray(a, copy=False).transpose(axes).view(MaskedArray)
+
+
+def reshape(a, new_shape, order='C'):
+ """
+ Returns an array containing the same data with a new shape.
+
+ Refer to `MaskedArray.reshape` for full documentation.
+
+ See Also
+ --------
+ MaskedArray.reshape : equivalent function
+
+ """
+ # We can't use 'frommethod', it whine about some parameters. Dmmit.
+ try:
+ return a.reshape(new_shape, order=order)
+ except AttributeError:
+ _tmp = narray(a, copy=False).reshape(new_shape, order=order)
+ return _tmp.view(MaskedArray)
+
+
+def resize(x, new_shape):
+ """
+ Return a new masked array with the specified size and shape.
+
+ This is the masked equivalent of the `numpy.resize` function. The new
+ array is filled with repeated copies of `x` (in the order that the
+ data are stored in memory). If `x` is masked, the new array will be
+ masked, and the new mask will be a repetition of the old one.
+
+ See Also
+ --------
+ numpy.resize : Equivalent function in the top level NumPy module.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> a = ma.array([[1, 2] ,[3, 4]])
+ >>> a[0, 1] = ma.masked
+ >>> a
+ masked_array(
+ data=[[1, --],
+ [3, 4]],
+ mask=[[False, True],
+ [False, False]],
+ fill_value=999999)
+ >>> np.resize(a, (3, 3))
+ masked_array(
+ data=[[1, 2, 3],
+ [4, 1, 2],
+ [3, 4, 1]],
+ mask=False,
+ fill_value=999999)
+ >>> ma.resize(a, (3, 3))
+ masked_array(
+ data=[[1, --, 3],
+ [4, 1, --],
+ [3, 4, 1]],
+ mask=[[False, True, False],
+ [False, False, True],
+ [False, False, False]],
+ fill_value=999999)
+
+ A MaskedArray is always returned, regardless of the input type.
+
+ >>> a = np.array([[1, 2] ,[3, 4]])
+ >>> ma.resize(a, (3, 3))
+ masked_array(
+ data=[[1, 2, 3],
+ [4, 1, 2],
+ [3, 4, 1]],
+ mask=False,
+ fill_value=999999)
+
+ """
+ # We can't use _frommethods here, as N.resize is notoriously whiny.
+ m = getmask(x)
+ if m is not nomask:
+ m = np.resize(m, new_shape)
+ result = np.resize(x, new_shape).view(get_masked_subclass(x))
+ if result.ndim:
+ result._mask = m
+ return result
+
+
+def ndim(obj):
+ """
+ maskedarray version of the numpy function.
+
+ """
+ return np.ndim(getdata(obj))
+
+ndim.__doc__ = np.ndim.__doc__
+
+
+def shape(obj):
+ "maskedarray version of the numpy function."
+ return np.shape(getdata(obj))
+shape.__doc__ = np.shape.__doc__
+
+
+def size(obj, axis=None):
+ "maskedarray version of the numpy function."
+ return np.size(getdata(obj), axis)
+size.__doc__ = np.size.__doc__
+
+
+##############################################################################
+# Extra functions #
+##############################################################################
+
+
+def where(condition, x=_NoValue, y=_NoValue):
+ """
+ Return a masked array with elements from `x` or `y`, depending on condition.
+
+ .. note::
+ When only `condition` is provided, this function is identical to
+ `nonzero`. The rest of this documentation covers only the case where
+ all three arguments are provided.
+
+ Parameters
+ ----------
+ condition : array_like, bool
+ Where True, yield `x`, otherwise yield `y`.
+ x, y : array_like, optional
+ Values from which to choose. `x`, `y` and `condition` need to be
+ broadcastable to some shape.
+
+ Returns
+ -------
+ out : MaskedArray
+ An masked array with `masked` elements where the condition is masked,
+ elements from `x` where `condition` is True, and elements from `y`
+ elsewhere.
+
+ See Also
+ --------
+ numpy.where : Equivalent function in the top-level NumPy module.
+ nonzero : The function that is called when x and y are omitted
+
+ Examples
+ --------
+ >>> x = np.ma.array(np.arange(9.).reshape(3, 3), mask=[[0, 1, 0],
+ ... [1, 0, 1],
+ ... [0, 1, 0]])
+ >>> x
+ masked_array(
+ data=[[0.0, --, 2.0],
+ [--, 4.0, --],
+ [6.0, --, 8.0]],
+ mask=[[False, True, False],
+ [ True, False, True],
+ [False, True, False]],
+ fill_value=1e+20)
+ >>> np.ma.where(x > 5, x, -3.1416)
+ masked_array(
+ data=[[-3.1416, --, -3.1416],
+ [--, -3.1416, --],
+ [6.0, --, 8.0]],
+ mask=[[False, True, False],
+ [ True, False, True],
+ [False, True, False]],
+ fill_value=1e+20)
+
+ """
+
+ # handle the single-argument case
+ missing = (x is _NoValue, y is _NoValue).count(True)
+ if missing == 1:
+ raise ValueError("Must provide both 'x' and 'y' or neither.")
+ if missing == 2:
+ return nonzero(condition)
+
+ # we only care if the condition is true - false or masked pick y
+ cf = filled(condition, False)
+ xd = getdata(x)
+ yd = getdata(y)
+
+ # we need the full arrays here for correct final dimensions
+ cm = getmaskarray(condition)
+ xm = getmaskarray(x)
+ ym = getmaskarray(y)
+
+ # deal with the fact that masked.dtype == float64, but we don't actually
+ # want to treat it as that.
+ if x is masked and y is not masked:
+ xd = np.zeros((), dtype=yd.dtype)
+ xm = np.ones((), dtype=ym.dtype)
+ elif y is masked and x is not masked:
+ yd = np.zeros((), dtype=xd.dtype)
+ ym = np.ones((), dtype=xm.dtype)
+
+ data = np.where(cf, xd, yd)
+ mask = np.where(cf, xm, ym)
+ mask = np.where(cm, np.ones((), dtype=mask.dtype), mask)
+
+ # collapse the mask, for backwards compatibility
+ mask = _shrink_mask(mask)
+
+ return masked_array(data, mask=mask)
+
+
+def choose(indices, choices, out=None, mode='raise'):
+ """
+ Use an index array to construct a new array from a list of choices.
+
+ Given an array of integers and a list of n choice arrays, this method
+ will create a new array that merges each of the choice arrays. Where a
+ value in `index` is i, the new array will have the value that choices[i]
+ contains in the same place.
+
+ Parameters
+ ----------
+ indices : ndarray of ints
+ This array must contain integers in ``[0, n-1]``, where n is the
+ number of choices.
+ choices : sequence of arrays
+ Choice arrays. The index array and all of the choices should be
+ broadcastable to the same shape.
+ out : array, optional
+ If provided, the result will be inserted into this array. It should
+ be of the appropriate shape and `dtype`.
+ mode : {'raise', 'wrap', 'clip'}, optional
+ Specifies how out-of-bounds indices will behave.
+
+ * 'raise' : raise an error
+ * 'wrap' : wrap around
+ * 'clip' : clip to the range
+
+ Returns
+ -------
+ merged_array : array
+
+ See Also
+ --------
+ choose : equivalent function
+
+ Examples
+ --------
+ >>> choice = np.array([[1,1,1], [2,2,2], [3,3,3]])
+ >>> a = np.array([2, 1, 0])
+ >>> np.ma.choose(a, choice)
+ masked_array(data=[3, 2, 1],
+ mask=False,
+ fill_value=999999)
+
+ """
+ def fmask(x):
+ "Returns the filled array, or True if masked."
+ if x is masked:
+ return True
+ return filled(x)
+
+ def nmask(x):
+ "Returns the mask, True if ``masked``, False if ``nomask``."
+ if x is masked:
+ return True
+ return getmask(x)
+ # Get the indices.
+ c = filled(indices, 0)
+ # Get the masks.
+ masks = [nmask(x) for x in choices]
+ data = [fmask(x) for x in choices]
+ # Construct the mask
+ outputmask = np.choose(c, masks, mode=mode)
+ outputmask = make_mask(mask_or(outputmask, getmask(indices)),
+ copy=False, shrink=True)
+ # Get the choices.
+ d = np.choose(c, data, mode=mode, out=out).view(MaskedArray)
+ if out is not None:
+ if isinstance(out, MaskedArray):
+ out.__setmask__(outputmask)
+ return out
+ d.__setmask__(outputmask)
+ return d
+
+
+def round_(a, decimals=0, out=None):
+ """
+ Return a copy of a, rounded to 'decimals' places.
+
+ When 'decimals' is negative, it specifies the number of positions
+ to the left of the decimal point. The real and imaginary parts of
+ complex numbers are rounded separately. Nothing is done if the
+ array is not of float type and 'decimals' is greater than or equal
+ to 0.
+
+ Parameters
+ ----------
+ decimals : int
+ Number of decimals to round to. May be negative.
+ out : array_like
+ Existing array to use for output.
+ If not given, returns a default copy of a.
+
+ Notes
+ -----
+ If out is given and does not have a mask attribute, the mask of a
+ is lost!
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> x = [11.2, -3.973, 0.801, -1.41]
+ >>> mask = [0, 0, 0, 1]
+ >>> masked_x = ma.masked_array(x, mask)
+ >>> masked_x
+ masked_array(data=[11.2, -3.973, 0.801, --],
+ mask=[False, False, False, True],
+ fill_value=1e+20)
+ >>> ma.round_(masked_x)
+ masked_array(data=[11.0, -4.0, 1.0, --],
+ mask=[False, False, False, True],
+ fill_value=1e+20)
+ >>> ma.round(masked_x, decimals=1)
+ masked_array(data=[11.2, -4.0, 0.8, --],
+ mask=[False, False, False, True],
+ fill_value=1e+20)
+ >>> ma.round_(masked_x, decimals=-1)
+ masked_array(data=[10.0, -0.0, 0.0, --],
+ mask=[False, False, False, True],
+ fill_value=1e+20)
+ """
+ if out is None:
+ return np.round_(a, decimals, out)
+ else:
+ np.round_(getdata(a), decimals, out)
+ if hasattr(out, '_mask'):
+ out._mask = getmask(a)
+ return out
+round = round_
+
+
+# Needed by dot, so move here from extras.py. It will still be exported
+# from extras.py for compatibility.
+def mask_rowcols(a, axis=None):
+ """
+ Mask rows and/or columns of a 2D array that contain masked values.
+
+ Mask whole rows and/or columns of a 2D array that contain
+ masked values. The masking behavior is selected using the
+ `axis` parameter.
+
+ - If `axis` is None, rows *and* columns are masked.
+ - If `axis` is 0, only rows are masked.
+ - If `axis` is 1 or -1, only columns are masked.
+
+ Parameters
+ ----------
+ a : array_like, MaskedArray
+ The array to mask. If not a MaskedArray instance (or if no array
+ elements are masked). The result is a MaskedArray with `mask` set
+ to `nomask` (False). Must be a 2D array.
+ axis : int, optional
+ Axis along which to perform the operation. If None, applies to a
+ flattened version of the array.
+
+ Returns
+ -------
+ a : MaskedArray
+ A modified version of the input array, masked depending on the value
+ of the `axis` parameter.
+
+ Raises
+ ------
+ NotImplementedError
+ If input array `a` is not 2D.
+
+ See Also
+ --------
+ mask_rows : Mask rows of a 2D array that contain masked values.
+ mask_cols : Mask cols of a 2D array that contain masked values.
+ masked_where : Mask where a condition is met.
+
+ Notes
+ -----
+ The input array's mask is modified by this function.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> a = np.zeros((3, 3), dtype=int)
+ >>> a[1, 1] = 1
+ >>> a
+ array([[0, 0, 0],
+ [0, 1, 0],
+ [0, 0, 0]])
+ >>> a = ma.masked_equal(a, 1)
+ >>> a
+ masked_array(
+ data=[[0, 0, 0],
+ [0, --, 0],
+ [0, 0, 0]],
+ mask=[[False, False, False],
+ [False, True, False],
+ [False, False, False]],
+ fill_value=1)
+ >>> ma.mask_rowcols(a)
+ masked_array(
+ data=[[0, --, 0],
+ [--, --, --],
+ [0, --, 0]],
+ mask=[[False, True, False],
+ [ True, True, True],
+ [False, True, False]],
+ fill_value=1)
+
+ """
+ a = array(a, subok=False)
+ if a.ndim != 2:
+ 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():
+ return a
+ maskedval = m.nonzero()
+ a._mask = a._mask.copy()
+ if not axis:
+ a[np.unique(maskedval[0])] = masked
+ if axis in [None, 1, -1]:
+ a[:, np.unique(maskedval[1])] = masked
+ return a
+
+
+# Include masked dot here to avoid import problems in getting it from
+# extras.py. Note that it is not included in __all__, but rather exported
+# from extras in order to avoid backward compatibility problems.
+def dot(a, b, strict=False, out=None):
+ """
+ Return the dot product of two arrays.
+
+ This function is the equivalent of `numpy.dot` that takes masked values
+ into account. Note that `strict` and `out` are in different position
+ than in the method version. In order to maintain compatibility with the
+ corresponding method, it is recommended that the optional arguments be
+ treated as keyword only. At some point that may be mandatory.
+
+ .. note::
+ Works only with 2-D arrays at the moment.
+
+
+ Parameters
+ ----------
+ a, b : masked_array_like
+ Inputs arrays.
+ strict : bool, optional
+ Whether masked data are propagated (True) or set to 0 (False) for
+ the computation. Default is False. Propagating the mask means that
+ if a masked value appears in a row or column, the whole row or
+ column is considered masked.
+ out : masked_array, optional
+ Output argument. This must have the exact kind that would be returned
+ if it was not used. In particular, it must have the right type, must be
+ C-contiguous, and its dtype must be the dtype that would be returned
+ for `dot(a,b)`. This is a performance feature. Therefore, if these
+ conditions are not met, an exception is raised, instead of attempting
+ to be flexible.
+
+ .. versionadded:: 1.10.2
+
+ See Also
+ --------
+ numpy.dot : Equivalent function for ndarrays.
+
+ Examples
+ --------
+ >>> a = np.ma.array([[1, 2, 3], [4, 5, 6]], mask=[[1, 0, 0], [0, 0, 0]])
+ >>> b = np.ma.array([[1, 2], [3, 4], [5, 6]], mask=[[1, 0], [0, 0], [0, 0]])
+ >>> np.ma.dot(a, b)
+ masked_array(
+ data=[[21, 26],
+ [45, 64]],
+ mask=[[False, False],
+ [False, False]],
+ fill_value=999999)
+ >>> np.ma.dot(a, b, strict=True)
+ masked_array(
+ data=[[--, --],
+ [--, 64]],
+ mask=[[ True, True],
+ [ True, False]],
+ fill_value=999999)
+
+ """
+ # !!!: Works only with 2D arrays. There should be a way to get it to run
+ # with higher dimension
+ if strict and (a.ndim == 2) and (b.ndim == 2):
+ a = mask_rowcols(a, 0)
+ b = mask_rowcols(b, 1)
+ am = ~getmaskarray(a)
+ bm = ~getmaskarray(b)
+
+ if out is None:
+ d = np.dot(filled(a, 0), filled(b, 0))
+ m = ~np.dot(am, bm)
+ if d.ndim == 0:
+ d = np.asarray(d)
+ r = d.view(get_masked_subclass(a, b))
+ r.__setmask__(m)
+ return r
+ else:
+ d = np.dot(filled(a, 0), filled(b, 0), out._data)
+ if out.mask.shape != d.shape:
+ out._mask = np.empty(d.shape, MaskType)
+ np.dot(am, bm, out._mask)
+ np.logical_not(out._mask, out._mask)
+ return out
+
+
+def inner(a, b):
+ """
+ Returns the inner product of a and b for arrays of floating point types.
+
+ Like the generic NumPy equivalent the product sum is over the last dimension
+ of a and b. The first argument is not conjugated.
+
+ """
+ fa = filled(a, 0)
+ fb = filled(b, 0)
+ if fa.ndim == 0:
+ fa.shape = (1,)
+ if fb.ndim == 0:
+ fb.shape = (1,)
+ return np.inner(fa, fb).view(MaskedArray)
+inner.__doc__ = doc_note(np.inner.__doc__,
+ "Masked values are replaced by 0.")
+innerproduct = inner
+
+
+def outer(a, b):
+ "maskedarray version of the numpy function."
+ fa = filled(a, 0).ravel()
+ fb = filled(b, 0).ravel()
+ d = np.outer(fa, fb)
+ ma = getmask(a)
+ mb = getmask(b)
+ if ma is nomask and mb is nomask:
+ return masked_array(d)
+ ma = getmaskarray(a)
+ mb = getmaskarray(b)
+ m = make_mask(1 - np.outer(1 - ma, 1 - mb), copy=False)
+ return masked_array(d, mask=m)
+outer.__doc__ = doc_note(np.outer.__doc__,
+ "Masked values are replaced by 0.")
+outerproduct = outer
+
+
+def _convolve_or_correlate(f, a, v, mode, propagate_mask):
+ """
+ Helper function for ma.correlate and ma.convolve
+ """
+ if propagate_mask:
+ # results which are contributed to by either item in any pair being invalid
+ mask = (
+ f(getmaskarray(a), np.ones(np.shape(v), dtype=bool), mode=mode)
+ | f(np.ones(np.shape(a), dtype=bool), getmaskarray(v), mode=mode)
+ )
+ data = f(getdata(a), getdata(v), mode=mode)
+ else:
+ # results which are not contributed to by any pair of valid elements
+ mask = ~f(~getmaskarray(a), ~getmaskarray(v))
+ data = f(filled(a, 0), filled(v, 0), mode=mode)
+
+ return masked_array(data, mask=mask)
+
+
+def correlate(a, v, mode='valid', propagate_mask=True):
+ """
+ Cross-correlation of two 1-dimensional sequences.
+
+ Parameters
+ ----------
+ a, v : array_like
+ Input sequences.
+ mode : {'valid', 'same', 'full'}, optional
+ Refer to the `np.convolve` docstring. Note that the default
+ is 'valid', unlike `convolve`, which uses 'full'.
+ propagate_mask : bool
+ If True, then a result element is masked if any masked element contributes towards it.
+ If False, then a result element is only masked if no non-masked element
+ contribute towards it
+
+ Returns
+ -------
+ out : MaskedArray
+ Discrete cross-correlation of `a` and `v`.
+
+ See Also
+ --------
+ numpy.correlate : Equivalent function in the top-level NumPy module.
+ """
+ return _convolve_or_correlate(np.correlate, a, v, mode, propagate_mask)
+
+
+def convolve(a, v, mode='full', propagate_mask=True):
+ """
+ Returns the discrete, linear convolution of two one-dimensional sequences.
+
+ Parameters
+ ----------
+ a, v : array_like
+ Input sequences.
+ mode : {'valid', 'same', 'full'}, optional
+ Refer to the `np.convolve` docstring.
+ propagate_mask : bool
+ If True, then if any masked element is included in the sum for a result
+ element, then the result is masked.
+ If False, then the result element is only masked if no non-masked cells
+ contribute towards it
+
+ Returns
+ -------
+ out : MaskedArray
+ Discrete, linear convolution of `a` and `v`.
+
+ See Also
+ --------
+ numpy.convolve : Equivalent function in the top-level NumPy module.
+ """
+ return _convolve_or_correlate(np.convolve, a, v, mode, propagate_mask)
+
+
+def allequal(a, b, fill_value=True):
+ """
+ Return True if all entries of a and b are equal, using
+ fill_value as a truth value where either or both are masked.
+
+ Parameters
+ ----------
+ a, b : array_like
+ Input arrays to compare.
+ fill_value : bool, optional
+ Whether masked values in a or b are considered equal (True) or not
+ (False).
+
+ Returns
+ -------
+ y : bool
+ Returns True if the two arrays are equal within the given
+ tolerance, False otherwise. If either array contains NaN,
+ then False is returned.
+
+ See Also
+ --------
+ all, any
+ numpy.ma.allclose
+
+ Examples
+ --------
+ >>> a = np.ma.array([1e10, 1e-7, 42.0], mask=[0, 0, 1])
+ >>> a
+ masked_array(data=[10000000000.0, 1e-07, --],
+ mask=[False, False, True],
+ fill_value=1e+20)
+
+ >>> b = np.array([1e10, 1e-7, -42.0])
+ >>> b
+ array([ 1.00000000e+10, 1.00000000e-07, -4.20000000e+01])
+ >>> np.ma.allequal(a, b, fill_value=False)
+ False
+ >>> np.ma.allequal(a, b)
+ True
+
+ """
+ m = mask_or(getmask(a), getmask(b))
+ if m is nomask:
+ x = getdata(a)
+ y = getdata(b)
+ d = umath.equal(x, y)
+ return d.all()
+ elif fill_value:
+ x = getdata(a)
+ y = getdata(b)
+ d = umath.equal(x, y)
+ dm = array(d, mask=m, copy=False)
+ return dm.filled(True).all(None)
+ else:
+ return False
+
+
+def allclose(a, b, masked_equal=True, rtol=1e-5, atol=1e-8):
+ """
+ Returns True if two arrays are element-wise equal within a tolerance.
+
+ This function is equivalent to `allclose` except that masked values
+ are treated as equal (default) or unequal, depending on the `masked_equal`
+ argument.
+
+ Parameters
+ ----------
+ a, b : array_like
+ Input arrays to compare.
+ masked_equal : bool, optional
+ Whether masked values in `a` and `b` are considered equal (True) or not
+ (False). They are considered equal by default.
+ rtol : float, optional
+ Relative tolerance. The relative difference is equal to ``rtol * b``.
+ Default is 1e-5.
+ atol : float, optional
+ Absolute tolerance. The absolute difference is equal to `atol`.
+ Default is 1e-8.
+
+ Returns
+ -------
+ y : bool
+ Returns True if the two arrays are equal within the given
+ tolerance, False otherwise. If either array contains NaN, then
+ False is returned.
+
+ See Also
+ --------
+ all, any
+ numpy.allclose : the non-masked `allclose`.
+
+ Notes
+ -----
+ If the following equation is element-wise True, then `allclose` returns
+ True::
+
+ absolute(`a` - `b`) <= (`atol` + `rtol` * absolute(`b`))
+
+ Return True if all elements of `a` and `b` are equal subject to
+ given tolerances.
+
+ Examples
+ --------
+ >>> a = np.ma.array([1e10, 1e-7, 42.0], mask=[0, 0, 1])
+ >>> a
+ masked_array(data=[10000000000.0, 1e-07, --],
+ mask=[False, False, True],
+ fill_value=1e+20)
+ >>> b = np.ma.array([1e10, 1e-8, -42.0], mask=[0, 0, 1])
+ >>> np.ma.allclose(a, b)
+ False
+
+ >>> a = np.ma.array([1e10, 1e-8, 42.0], mask=[0, 0, 1])
+ >>> b = np.ma.array([1.00001e10, 1e-9, -42.0], mask=[0, 0, 1])
+ >>> np.ma.allclose(a, b)
+ True
+ >>> np.ma.allclose(a, b, masked_equal=False)
+ False
+
+ Masked values are not compared directly.
+
+ >>> a = np.ma.array([1e10, 1e-8, 42.0], mask=[0, 0, 1])
+ >>> b = np.ma.array([1.00001e10, 1e-9, 42.0], mask=[0, 0, 1])
+ >>> np.ma.allclose(a, b)
+ True
+ >>> np.ma.allclose(a, b, masked_equal=False)
+ False
+
+ """
+ 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.
+ # NOTE: We explicitly allow timedelta, which used to work. This could
+ # possibly be deprecated. See also gh-18286.
+ # timedelta works if `atol` is an integer or also a timedelta.
+ # Although, the default tolerances are unlikely to be useful
+ if y.dtype.kind != "m":
+ 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.
+ if not np.all(xinf == filled(np.isinf(y), False)):
+ return False
+ # No infs at all
+ if not np.any(xinf):
+ d = filled(less_equal(absolute(x - y), atol + rtol * 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(less_equal(absolute(x - y), atol + rtol * absolute(y)),
+ masked_equal)
+
+ return np.all(d)
+
+
+def asarray(a, dtype=None, order=None):
+ """
+ Convert the input to a masked array of the given data-type.
+
+ No copy is performed if the input is already an `ndarray`. If `a` is
+ a subclass of `MaskedArray`, a base class `MaskedArray` is returned.
+
+ Parameters
+ ----------
+ a : array_like
+ Input data, in any form that can be converted to a masked array. This
+ includes lists, lists of tuples, tuples, tuples of tuples, tuples
+ of lists, ndarrays and masked arrays.
+ dtype : dtype, optional
+ By default, the data-type is inferred from the input data.
+ order : {'C', 'F'}, optional
+ Whether to use row-major ('C') or column-major ('FORTRAN') memory
+ representation. Default is 'C'.
+
+ Returns
+ -------
+ out : MaskedArray
+ Masked array interpretation of `a`.
+
+ See Also
+ --------
+ asanyarray : Similar to `asarray`, but conserves subclasses.
+
+ Examples
+ --------
+ >>> x = np.arange(10.).reshape(2, 5)
+ >>> x
+ array([[0., 1., 2., 3., 4.],
+ [5., 6., 7., 8., 9.]])
+ >>> np.ma.asarray(x)
+ masked_array(
+ data=[[0., 1., 2., 3., 4.],
+ [5., 6., 7., 8., 9.]],
+ mask=False,
+ fill_value=1e+20)
+ >>> type(np.ma.asarray(x))
+ <class 'numpy.ma.core.MaskedArray'>
+
+ """
+ order = order or 'C'
+ return masked_array(a, dtype=dtype, copy=False, keep_mask=True,
+ subok=False, order=order)
+
+
+def asanyarray(a, dtype=None):
+ """
+ Convert the input to a masked array, conserving subclasses.
+
+ If `a` is a subclass of `MaskedArray`, its class is conserved.
+ No copy is performed if the input is already an `ndarray`.
+
+ Parameters
+ ----------
+ a : array_like
+ Input data, in any form that can be converted to an array.
+ dtype : dtype, optional
+ By default, the data-type is inferred from the input data.
+ order : {'C', 'F'}, optional
+ Whether to use row-major ('C') or column-major ('FORTRAN') memory
+ representation. Default is 'C'.
+
+ Returns
+ -------
+ out : MaskedArray
+ MaskedArray interpretation of `a`.
+
+ See Also
+ --------
+ asarray : Similar to `asanyarray`, but does not conserve subclass.
+
+ Examples
+ --------
+ >>> x = np.arange(10.).reshape(2, 5)
+ >>> x
+ array([[0., 1., 2., 3., 4.],
+ [5., 6., 7., 8., 9.]])
+ >>> np.ma.asanyarray(x)
+ masked_array(
+ data=[[0., 1., 2., 3., 4.],
+ [5., 6., 7., 8., 9.]],
+ mask=False,
+ fill_value=1e+20)
+ >>> type(np.ma.asanyarray(x))
+ <class 'numpy.ma.core.MaskedArray'>
+
+ """
+ # workaround for #8666, to preserve identity. Ideally the bottom line
+ # would handle this for us.
+ if isinstance(a, MaskedArray) and (dtype is None or dtype == a.dtype):
+ return a
+ return masked_array(a, dtype=dtype, copy=False, keep_mask=True, subok=True)
+
+
+##############################################################################
+# Pickling #
+##############################################################################
+
+
+def fromfile(file, dtype=float, count=-1, sep=''):
+ raise NotImplementedError(
+ "fromfile() not yet implemented for a MaskedArray.")
+
+
+def fromflex(fxarray):
+ """
+ Build a masked array from a suitable flexible-type array.
+
+ The input array has to have a data-type with ``_data`` and ``_mask``
+ fields. This type of array is output by `MaskedArray.toflex`.
+
+ Parameters
+ ----------
+ fxarray : ndarray
+ The structured input array, containing ``_data`` and ``_mask``
+ fields. If present, other fields are discarded.
+
+ Returns
+ -------
+ result : MaskedArray
+ The constructed masked array.
+
+ See Also
+ --------
+ MaskedArray.toflex : Build a flexible-type array from a masked array.
+
+ Examples
+ --------
+ >>> x = np.ma.array(np.arange(9).reshape(3, 3), mask=[0] + [1, 0] * 4)
+ >>> rec = x.toflex()
+ >>> rec
+ array([[(0, False), (1, True), (2, False)],
+ [(3, True), (4, False), (5, True)],
+ [(6, False), (7, True), (8, False)]],
+ dtype=[('_data', '<i8'), ('_mask', '?')])
+ >>> x2 = np.ma.fromflex(rec)
+ >>> x2
+ masked_array(
+ data=[[0, --, 2],
+ [--, 4, --],
+ [6, --, 8]],
+ mask=[[False, True, False],
+ [ True, False, True],
+ [False, True, False]],
+ fill_value=999999)
+
+ Extra fields can be present in the structured array but are discarded:
+
+ >>> dt = [('_data', '<i4'), ('_mask', '|b1'), ('field3', '<f4')]
+ >>> rec2 = np.zeros((2, 2), dtype=dt)
+ >>> rec2
+ array([[(0, False, 0.), (0, False, 0.)],
+ [(0, False, 0.), (0, False, 0.)]],
+ dtype=[('_data', '<i4'), ('_mask', '?'), ('field3', '<f4')])
+ >>> y = np.ma.fromflex(rec2)
+ >>> y
+ masked_array(
+ data=[[0, 0],
+ [0, 0]],
+ mask=[[False, False],
+ [False, False]],
+ fill_value=999999,
+ dtype=int32)
+
+ """
+ return masked_array(fxarray['_data'], mask=fxarray['_mask'])
+
+
+class _convert2ma:
+
+ """
+ Convert functions from numpy to numpy.ma.
+
+ Parameters
+ ----------
+ _methodname : string
+ Name of the method to transform.
+
+ """
+ __doc__ = None
+
+ def __init__(self, funcname, np_ret, np_ma_ret, params=None):
+ self._func = getattr(np, funcname)
+ self.__doc__ = self.getdoc(np_ret, np_ma_ret)
+ self._extras = params or {}
+
+ def getdoc(self, np_ret, np_ma_ret):
+ "Return the doc of the function (from the doc of the method)."
+ doc = getattr(self._func, '__doc__', None)
+ sig = get_object_signature(self._func)
+ if doc:
+ doc = self._replace_return_type(doc, np_ret, np_ma_ret)
+ # Add the signature of the function at the beginning of the doc
+ if sig:
+ sig = "%s%s\n" % (self._func.__name__, sig)
+ doc = sig + doc
+ return doc
+
+ def _replace_return_type(self, doc, np_ret, np_ma_ret):
+ """
+ Replace documentation of ``np`` function's return type.
+
+ Replaces it with the proper type for the ``np.ma`` function.
+
+ Parameters
+ ----------
+ doc : str
+ The documentation of the ``np`` method.
+ np_ret : str
+ The return type string of the ``np`` method that we want to
+ replace. (e.g. "out : ndarray")
+ np_ma_ret : str
+ The return type string of the ``np.ma`` method.
+ (e.g. "out : MaskedArray")
+ """
+ if np_ret not in doc:
+ raise RuntimeError(
+ f"Failed to replace `{np_ret}` with `{np_ma_ret}`. "
+ f"The documentation string for return type, {np_ret}, is not "
+ f"found in the docstring for `np.{self._func.__name__}`. "
+ f"Fix the docstring for `np.{self._func.__name__}` or "
+ "update the expected string for return type."
+ )
+
+ return doc.replace(np_ret, np_ma_ret)
+
+ def __call__(self, *args, **params):
+ # Find the common parameters to the call and the definition
+ _extras = self._extras
+ common_params = set(params).intersection(_extras)
+ # Drop the common parameters from the call
+ for p in common_params:
+ _extras[p] = params.pop(p)
+ # Get the result
+ result = self._func.__call__(*args, **params).view(MaskedArray)
+ if "fill_value" in common_params:
+ result.fill_value = _extras.get("fill_value", None)
+ if "hardmask" in common_params:
+ result._hardmask = bool(_extras.get("hard_mask", False))
+ return result
+
+
+arange = _convert2ma(
+ 'arange',
+ params=dict(fill_value=None, hardmask=False),
+ np_ret='arange : ndarray',
+ np_ma_ret='arange : MaskedArray',
+)
+clip = _convert2ma(
+ 'clip',
+ params=dict(fill_value=None, hardmask=False),
+ np_ret='clipped_array : ndarray',
+ np_ma_ret='clipped_array : MaskedArray',
+)
+diff = _convert2ma(
+ 'diff',
+ params=dict(fill_value=None, hardmask=False),
+ np_ret='diff : ndarray',
+ np_ma_ret='diff : MaskedArray',
+)
+empty = _convert2ma(
+ 'empty',
+ params=dict(fill_value=None, hardmask=False),
+ np_ret='out : ndarray',
+ np_ma_ret='out : MaskedArray',
+)
+empty_like = _convert2ma(
+ 'empty_like',
+ np_ret='out : ndarray',
+ np_ma_ret='out : MaskedArray',
+)
+frombuffer = _convert2ma(
+ 'frombuffer',
+ np_ret='out : ndarray',
+ np_ma_ret='out: MaskedArray',
+)
+fromfunction = _convert2ma(
+ 'fromfunction',
+ np_ret='fromfunction : any',
+ np_ma_ret='fromfunction: MaskedArray',
+)
+identity = _convert2ma(
+ 'identity',
+ params=dict(fill_value=None, hardmask=False),
+ np_ret='out : ndarray',
+ np_ma_ret='out : MaskedArray',
+)
+indices = _convert2ma(
+ 'indices',
+ params=dict(fill_value=None, hardmask=False),
+ np_ret='grid : one ndarray or tuple of ndarrays',
+ np_ma_ret='grid : one MaskedArray or tuple of MaskedArrays',
+)
+ones = _convert2ma(
+ 'ones',
+ params=dict(fill_value=None, hardmask=False),
+ np_ret='out : ndarray',
+ np_ma_ret='out : MaskedArray',
+)
+ones_like = _convert2ma(
+ 'ones_like',
+ np_ret='out : ndarray',
+ np_ma_ret='out : MaskedArray',
+)
+squeeze = _convert2ma(
+ 'squeeze',
+ params=dict(fill_value=None, hardmask=False),
+ np_ret='squeezed : ndarray',
+ np_ma_ret='squeezed : MaskedArray',
+)
+zeros = _convert2ma(
+ 'zeros',
+ params=dict(fill_value=None, hardmask=False),
+ np_ret='out : ndarray',
+ np_ma_ret='out : MaskedArray',
+)
+zeros_like = _convert2ma(
+ 'zeros_like',
+ np_ret='out : ndarray',
+ np_ma_ret='out : MaskedArray',
+)
+
+
+def append(a, b, axis=None):
+ """Append values to the end of an array.
+
+ .. versionadded:: 1.9.0
+
+ Parameters
+ ----------
+ a : array_like
+ Values are appended to a copy of this array.
+ b : array_like
+ These values are appended to a copy of `a`. It must be of the
+ correct shape (the same shape as `a`, excluding `axis`). If `axis`
+ is not specified, `b` can be any shape and will be flattened
+ before use.
+ axis : int, optional
+ The axis along which `v` are appended. If `axis` is not given,
+ both `a` and `b` are flattened before use.
+
+ Returns
+ -------
+ append : MaskedArray
+ A copy of `a` with `b` 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)
+ >>> ma.append(a, b)
+ masked_array(data=[1, --, 3, 4, 5, 6, --, 8, 9],
+ mask=[False, True, False, False, False, False, True, False,
+ False],
+ fill_value=999999)
+ """
+ return concatenate([a, b], axis)
diff --git a/venv/lib/python3.9/site-packages/numpy/ma/core.pyi b/venv/lib/python3.9/site-packages/numpy/ma/core.pyi
new file mode 100644
index 00000000..d5d4f7f3
--- /dev/null
+++ b/venv/lib/python3.9/site-packages/numpy/ma/core.pyi
@@ -0,0 +1,472 @@
+from collections.abc import Callable
+from typing import Any, TypeVar
+from numpy import ndarray, dtype, float64
+
+from numpy import (
+ amax as amax,
+ amin as amin,
+ bool_ as bool_,
+ expand_dims as expand_dims,
+ diff as diff,
+ clip as clip,
+ indices as indices,
+ ones_like as ones_like,
+ squeeze as squeeze,
+ zeros_like as zeros_like,
+)
+
+from numpy.lib.function_base import (
+ angle as angle,
+)
+
+# TODO: Set the `bound` to something more suitable once we
+# have proper shape support
+_ShapeType = TypeVar("_ShapeType", bound=Any)
+_DType_co = TypeVar("_DType_co", bound=dtype[Any], covariant=True)
+
+__all__: list[str]
+
+MaskType = bool_
+nomask: bool_
+
+class MaskedArrayFutureWarning(FutureWarning): ...
+class MAError(Exception): ...
+class MaskError(MAError): ...
+
+def default_fill_value(obj): ...
+def minimum_fill_value(obj): ...
+def maximum_fill_value(obj): ...
+def set_fill_value(a, fill_value): ...
+def common_fill_value(a, b): ...
+def filled(a, fill_value=...): ...
+def getdata(a, subok=...): ...
+get_data = getdata
+
+def fix_invalid(a, mask=..., copy=..., fill_value=...): ...
+
+class _MaskedUFunc:
+ f: Any
+ __doc__: Any
+ __name__: Any
+ def __init__(self, ufunc): ...
+
+class _MaskedUnaryOperation(_MaskedUFunc):
+ fill: Any
+ domain: Any
+ def __init__(self, mufunc, fill=..., domain=...): ...
+ def __call__(self, a, *args, **kwargs): ...
+
+class _MaskedBinaryOperation(_MaskedUFunc):
+ fillx: Any
+ filly: Any
+ def __init__(self, mbfunc, fillx=..., filly=...): ...
+ def __call__(self, a, b, *args, **kwargs): ...
+ def reduce(self, target, axis=..., dtype=...): ...
+ def outer(self, a, b): ...
+ def accumulate(self, target, axis=...): ...
+
+class _DomainedBinaryOperation(_MaskedUFunc):
+ domain: Any
+ fillx: Any
+ filly: Any
+ def __init__(self, dbfunc, domain, fillx=..., filly=...): ...
+ def __call__(self, a, b, *args, **kwargs): ...
+
+exp: _MaskedUnaryOperation
+conjugate: _MaskedUnaryOperation
+sin: _MaskedUnaryOperation
+cos: _MaskedUnaryOperation
+arctan: _MaskedUnaryOperation
+arcsinh: _MaskedUnaryOperation
+sinh: _MaskedUnaryOperation
+cosh: _MaskedUnaryOperation
+tanh: _MaskedUnaryOperation
+abs: _MaskedUnaryOperation
+absolute: _MaskedUnaryOperation
+fabs: _MaskedUnaryOperation
+negative: _MaskedUnaryOperation
+floor: _MaskedUnaryOperation
+ceil: _MaskedUnaryOperation
+around: _MaskedUnaryOperation
+logical_not: _MaskedUnaryOperation
+sqrt: _MaskedUnaryOperation
+log: _MaskedUnaryOperation
+log2: _MaskedUnaryOperation
+log10: _MaskedUnaryOperation
+tan: _MaskedUnaryOperation
+arcsin: _MaskedUnaryOperation
+arccos: _MaskedUnaryOperation
+arccosh: _MaskedUnaryOperation
+arctanh: _MaskedUnaryOperation
+
+add: _MaskedBinaryOperation
+subtract: _MaskedBinaryOperation
+multiply: _MaskedBinaryOperation
+arctan2: _MaskedBinaryOperation
+equal: _MaskedBinaryOperation
+not_equal: _MaskedBinaryOperation
+less_equal: _MaskedBinaryOperation
+greater_equal: _MaskedBinaryOperation
+less: _MaskedBinaryOperation
+greater: _MaskedBinaryOperation
+logical_and: _MaskedBinaryOperation
+alltrue: _MaskedBinaryOperation
+logical_or: _MaskedBinaryOperation
+sometrue: Callable[..., Any]
+logical_xor: _MaskedBinaryOperation
+bitwise_and: _MaskedBinaryOperation
+bitwise_or: _MaskedBinaryOperation
+bitwise_xor: _MaskedBinaryOperation
+hypot: _MaskedBinaryOperation
+divide: _MaskedBinaryOperation
+true_divide: _MaskedBinaryOperation
+floor_divide: _MaskedBinaryOperation
+remainder: _MaskedBinaryOperation
+fmod: _MaskedBinaryOperation
+mod: _MaskedBinaryOperation
+
+def make_mask_descr(ndtype): ...
+def getmask(a): ...
+get_mask = getmask
+
+def getmaskarray(arr): ...
+def is_mask(m): ...
+def make_mask(m, copy=..., shrink=..., dtype=...): ...
+def make_mask_none(newshape, dtype=...): ...
+def mask_or(m1, m2, copy=..., shrink=...): ...
+def flatten_mask(mask): ...
+def masked_where(condition, a, copy=...): ...
+def masked_greater(x, value, copy=...): ...
+def masked_greater_equal(x, value, copy=...): ...
+def masked_less(x, value, copy=...): ...
+def masked_less_equal(x, value, copy=...): ...
+def masked_not_equal(x, value, copy=...): ...
+def masked_equal(x, value, copy=...): ...
+def masked_inside(x, v1, v2, copy=...): ...
+def masked_outside(x, v1, v2, copy=...): ...
+def masked_object(x, value, copy=..., shrink=...): ...
+def masked_values(x, value, rtol=..., atol=..., copy=..., shrink=...): ...
+def masked_invalid(a, copy=...): ...
+
+class _MaskedPrintOption:
+ def __init__(self, display): ...
+ def display(self): ...
+ def set_display(self, s): ...
+ def enabled(self): ...
+ def enable(self, shrink=...): ...
+
+masked_print_option: _MaskedPrintOption
+
+def flatten_structured_array(a): ...
+
+class MaskedIterator:
+ ma: Any
+ dataiter: Any
+ maskiter: Any
+ def __init__(self, ma): ...
+ def __iter__(self): ...
+ def __getitem__(self, indx): ...
+ def __setitem__(self, index, value): ...
+ def __next__(self): ...
+
+class MaskedArray(ndarray[_ShapeType, _DType_co]):
+ __array_priority__: Any
+ def __new__(cls, data=..., mask=..., dtype=..., copy=..., subok=..., ndmin=..., fill_value=..., keep_mask=..., hard_mask=..., shrink=..., order=...): ...
+ def __array_finalize__(self, obj): ...
+ def __array_wrap__(self, obj, context=...): ...
+ def view(self, dtype=..., type=..., fill_value=...): ...
+ def __getitem__(self, indx): ...
+ def __setitem__(self, indx, value): ...
+ @property
+ def dtype(self): ...
+ @dtype.setter
+ def dtype(self, dtype): ...
+ @property
+ def shape(self): ...
+ @shape.setter
+ def shape(self, shape): ...
+ def __setmask__(self, mask, copy=...): ...
+ @property
+ def mask(self): ...
+ @mask.setter
+ def mask(self, value): ...
+ @property
+ def recordmask(self): ...
+ @recordmask.setter
+ def recordmask(self, mask): ...
+ def harden_mask(self): ...
+ def soften_mask(self): ...
+ @property
+ def hardmask(self): ...
+ def unshare_mask(self): ...
+ @property
+ def sharedmask(self): ...
+ def shrink_mask(self): ...
+ @property
+ def baseclass(self): ...
+ data: Any
+ @property
+ def flat(self): ...
+ @flat.setter
+ def flat(self, value): ...
+ @property
+ def fill_value(self): ...
+ @fill_value.setter
+ def fill_value(self, value=...): ...
+ get_fill_value: Any
+ set_fill_value: Any
+ def filled(self, fill_value=...): ...
+ def compressed(self): ...
+ def compress(self, condition, axis=..., out=...): ...
+ def __eq__(self, other): ...
+ def __ne__(self, other): ...
+ def __ge__(self, other): ...
+ def __gt__(self, other): ...
+ def __le__(self, other): ...
+ def __lt__(self, other): ...
+ def __add__(self, other): ...
+ def __radd__(self, other): ...
+ def __sub__(self, other): ...
+ def __rsub__(self, other): ...
+ def __mul__(self, other): ...
+ def __rmul__(self, other): ...
+ def __div__(self, other): ...
+ def __truediv__(self, other): ...
+ def __rtruediv__(self, other): ...
+ def __floordiv__(self, other): ...
+ def __rfloordiv__(self, other): ...
+ def __pow__(self, other): ...
+ def __rpow__(self, other): ...
+ def __iadd__(self, other): ...
+ def __isub__(self, other): ...
+ def __imul__(self, other): ...
+ def __idiv__(self, other): ...
+ def __ifloordiv__(self, other): ...
+ def __itruediv__(self, other): ...
+ def __ipow__(self, other): ...
+ def __float__(self): ...
+ def __int__(self): ...
+ @property # type: ignore[misc]
+ def imag(self): ...
+ get_imag: Any
+ @property # type: ignore[misc]
+ def real(self): ...
+ get_real: Any
+ def count(self, axis=..., keepdims=...): ...
+ def ravel(self, order=...): ...
+ def reshape(self, *s, **kwargs): ...
+ def resize(self, newshape, refcheck=..., order=...): ...
+ def put(self, indices, values, mode=...): ...
+ def ids(self): ...
+ def iscontiguous(self): ...
+ def all(self, axis=..., out=..., keepdims=...): ...
+ def any(self, axis=..., out=..., keepdims=...): ...
+ def nonzero(self): ...
+ def trace(self, offset=..., axis1=..., axis2=..., dtype=..., out=...): ...
+ def dot(self, b, out=..., strict=...): ...
+ def sum(self, axis=..., dtype=..., out=..., keepdims=...): ...
+ def cumsum(self, axis=..., dtype=..., out=...): ...
+ def prod(self, axis=..., dtype=..., out=..., keepdims=...): ...
+ product: Any
+ def cumprod(self, axis=..., dtype=..., out=...): ...
+ def mean(self, axis=..., dtype=..., out=..., keepdims=...): ...
+ def anom(self, axis=..., dtype=...): ...
+ def var(self, axis=..., dtype=..., out=..., ddof=..., keepdims=...): ...
+ def std(self, axis=..., dtype=..., out=..., ddof=..., keepdims=...): ...
+ def round(self, decimals=..., out=...): ...
+ def argsort(self, axis=..., kind=..., order=..., endwith=..., fill_value=...): ...
+ def argmin(self, axis=..., fill_value=..., out=..., *, keepdims=...): ...
+ def argmax(self, axis=..., fill_value=..., out=..., *, keepdims=...): ...
+ def sort(self, axis=..., kind=..., order=..., endwith=..., fill_value=...): ...
+ def min(self, axis=..., out=..., fill_value=..., keepdims=...): ...
+ # NOTE: deprecated
+ # def tostring(self, fill_value=..., order=...): ...
+ def max(self, axis=..., out=..., fill_value=..., keepdims=...): ...
+ def ptp(self, axis=..., out=..., fill_value=..., keepdims=...): ...
+ def partition(self, *args, **kwargs): ...
+ def argpartition(self, *args, **kwargs): ...
+ def take(self, indices, axis=..., out=..., mode=...): ...
+ copy: Any
+ diagonal: Any
+ flatten: Any
+ repeat: Any
+ squeeze: Any
+ swapaxes: Any
+ T: Any
+ transpose: Any
+ def tolist(self, fill_value=...): ...
+ def tobytes(self, fill_value=..., order=...): ...
+ def tofile(self, fid, sep=..., format=...): ...
+ def toflex(self): ...
+ torecords: Any
+ def __reduce__(self): ...
+ def __deepcopy__(self, memo=...): ...
+
+class mvoid(MaskedArray[_ShapeType, _DType_co]):
+ def __new__(
+ self,
+ data,
+ mask=...,
+ dtype=...,
+ fill_value=...,
+ hardmask=...,
+ copy=...,
+ subok=...,
+ ): ...
+ def __getitem__(self, indx): ...
+ def __setitem__(self, indx, value): ...
+ def __iter__(self): ...
+ def __len__(self): ...
+ def filled(self, fill_value=...): ...
+ def tolist(self): ...
+
+def isMaskedArray(x): ...
+isarray = isMaskedArray
+isMA = isMaskedArray
+
+# 0D float64 array
+class MaskedConstant(MaskedArray[Any, dtype[float64]]):
+ def __new__(cls): ...
+ __class__: Any
+ def __array_finalize__(self, obj): ...
+ def __array_prepare__(self, obj, context=...): ...
+ def __array_wrap__(self, obj, context=...): ...
+ def __format__(self, format_spec): ...
+ def __reduce__(self): ...
+ def __iop__(self, other): ...
+ __iadd__: Any
+ __isub__: Any
+ __imul__: Any
+ __ifloordiv__: Any
+ __itruediv__: Any
+ __ipow__: Any
+ def copy(self, *args, **kwargs): ...
+ def __copy__(self): ...
+ def __deepcopy__(self, memo): ...
+ def __setattr__(self, attr, value): ...
+
+masked: MaskedConstant
+masked_singleton: MaskedConstant
+masked_array = MaskedArray
+
+def array(
+ data,
+ dtype=...,
+ copy=...,
+ order=...,
+ mask=...,
+ fill_value=...,
+ keep_mask=...,
+ hard_mask=...,
+ shrink=...,
+ subok=...,
+ ndmin=...,
+): ...
+def is_masked(x): ...
+
+class _extrema_operation(_MaskedUFunc):
+ compare: Any
+ fill_value_func: Any
+ def __init__(self, ufunc, compare, fill_value): ...
+ # NOTE: in practice `b` has a default value, but users should
+ # explicitly provide a value here as the default is deprecated
+ def __call__(self, a, b): ...
+ def reduce(self, target, axis=...): ...
+ def outer(self, a, b): ...
+
+def min(obj, axis=..., out=..., fill_value=..., keepdims=...): ...
+def max(obj, axis=..., out=..., fill_value=..., keepdims=...): ...
+def ptp(obj, axis=..., out=..., fill_value=..., keepdims=...): ...
+
+class _frommethod:
+ __name__: Any
+ __doc__: Any
+ reversed: Any
+ def __init__(self, methodname, reversed=...): ...
+ def getdoc(self): ...
+ def __call__(self, a, *args, **params): ...
+
+all: _frommethod
+anomalies: _frommethod
+anom: _frommethod
+any: _frommethod
+compress: _frommethod
+cumprod: _frommethod
+cumsum: _frommethod
+copy: _frommethod
+diagonal: _frommethod
+harden_mask: _frommethod
+ids: _frommethod
+mean: _frommethod
+nonzero: _frommethod
+prod: _frommethod
+product: _frommethod
+ravel: _frommethod
+repeat: _frommethod
+soften_mask: _frommethod
+std: _frommethod
+sum: _frommethod
+swapaxes: _frommethod
+trace: _frommethod
+var: _frommethod
+count: _frommethod
+argmin: _frommethod
+argmax: _frommethod
+
+minimum: _extrema_operation
+maximum: _extrema_operation
+
+def take(a, indices, axis=..., out=..., mode=...): ...
+def power(a, b, third=...): ...
+def argsort(a, axis=..., kind=..., order=..., endwith=..., fill_value=...): ...
+def sort(a, axis=..., kind=..., order=..., endwith=..., fill_value=...): ...
+def compressed(x): ...
+def concatenate(arrays, axis=...): ...
+def diag(v, k=...): ...
+def left_shift(a, n): ...
+def right_shift(a, n): ...
+def put(a, indices, values, mode=...): ...
+def putmask(a, mask, values): ...
+def transpose(a, axes=...): ...
+def reshape(a, new_shape, order=...): ...
+def resize(x, new_shape): ...
+def ndim(obj): ...
+def shape(obj): ...
+def size(obj, axis=...): ...
+def where(condition, x=..., y=...): ...
+def choose(indices, choices, out=..., mode=...): ...
+def round_(a, decimals=..., out=...): ...
+round = round_
+
+def inner(a, b): ...
+innerproduct = inner
+
+def outer(a, b): ...
+outerproduct = outer
+
+def correlate(a, v, mode=..., propagate_mask=...): ...
+def convolve(a, v, mode=..., propagate_mask=...): ...
+def allequal(a, b, fill_value=...): ...
+def allclose(a, b, masked_equal=..., rtol=..., atol=...): ...
+def asarray(a, dtype=..., order=...): ...
+def asanyarray(a, dtype=...): ...
+def fromflex(fxarray): ...
+
+class _convert2ma:
+ __doc__: Any
+ def __init__(self, funcname, params=...): ...
+ def getdoc(self): ...
+ def __call__(self, *args, **params): ...
+
+arange: _convert2ma
+empty: _convert2ma
+empty_like: _convert2ma
+frombuffer: _convert2ma
+fromfunction: _convert2ma
+identity: _convert2ma
+ones: _convert2ma
+zeros: _convert2ma
+
+def append(a, b, axis=...): ...
+def dot(a, b, strict=..., out=...): ...
+def mask_rowcols(a, axis=...): ...
diff --git a/venv/lib/python3.9/site-packages/numpy/ma/extras.py b/venv/lib/python3.9/site-packages/numpy/ma/extras.py
new file mode 100644
index 00000000..41bce0f2
--- /dev/null
+++ b/venv/lib/python3.9/site-packages/numpy/ma/extras.py
@@ -0,0 +1,2045 @@
+"""
+Masked arrays add-ons.
+
+A collection of utilities for `numpy.ma`.
+
+:author: Pierre Gerard-Marchant
+:contact: pierregm_at_uga_dot_edu
+:version: $Id: extras.py 3473 2007-10-29 15:18:13Z jarrod.millman $
+
+"""
+__all__ = [
+ 'apply_along_axis', 'apply_over_axes', 'atleast_1d', 'atleast_2d',
+ 'atleast_3d', 'average', 'clump_masked', 'clump_unmasked', 'column_stack',
+ 'compress_cols', 'compress_nd', 'compress_rowcols', 'compress_rows',
+ 'count_masked', 'corrcoef', 'cov', 'diagflat', 'dot', 'dstack', 'ediff1d',
+ 'flatnotmasked_contiguous', 'flatnotmasked_edges', 'hsplit', 'hstack',
+ 'isin', 'in1d', 'intersect1d', 'mask_cols', 'mask_rowcols', 'mask_rows',
+ 'masked_all', 'masked_all_like', 'median', 'mr_', 'ndenumerate',
+ 'notmasked_contiguous', 'notmasked_edges', 'polyfit', 'row_stack',
+ 'setdiff1d', 'setxor1d', 'stack', 'unique', 'union1d', 'vander', 'vstack',
+ ]
+
+import itertools
+import warnings
+
+from . import core as ma
+from .core import (
+ MaskedArray, MAError, add, array, asarray, concatenate, filled, count,
+ getmask, getmaskarray, make_mask_descr, masked, masked_array, mask_or,
+ nomask, ones, sort, zeros, getdata, get_masked_subclass, dot,
+ mask_rowcols
+ )
+
+import numpy as np
+from numpy import ndarray, array as nxarray
+from numpy.core.multiarray import normalize_axis_index
+from numpy.core.numeric import normalize_axis_tuple
+from numpy.lib.function_base import _ureduce
+from numpy.lib.index_tricks import AxisConcatenator
+
+
+def issequence(seq):
+ """
+ Is seq a sequence (ndarray, list or tuple)?
+
+ """
+ return isinstance(seq, (ndarray, tuple, list))
+
+
+def count_masked(arr, axis=None):
+ """
+ Count the number of masked elements along the given axis.
+
+ Parameters
+ ----------
+ arr : array_like
+ An array with (possibly) masked elements.
+ axis : int, optional
+ Axis along which to count. If None (default), a flattened
+ version of the array is used.
+
+ Returns
+ -------
+ count : int, ndarray
+ The total number of masked elements (axis=None) or the number
+ of masked elements along each slice of the given axis.
+
+ See Also
+ --------
+ MaskedArray.count : Count non-masked elements.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> a = np.arange(9).reshape((3,3))
+ >>> a = ma.array(a)
+ >>> a[1, 0] = ma.masked
+ >>> a[1, 2] = ma.masked
+ >>> a[2, 1] = ma.masked
+ >>> a
+ masked_array(
+ data=[[0, 1, 2],
+ [--, 4, --],
+ [6, --, 8]],
+ mask=[[False, False, False],
+ [ True, False, True],
+ [False, True, False]],
+ fill_value=999999)
+ >>> ma.count_masked(a)
+ 3
+
+ When the `axis` keyword is used an array is returned.
+
+ >>> ma.count_masked(a, axis=0)
+ array([1, 1, 1])
+ >>> ma.count_masked(a, axis=1)
+ array([0, 2, 1])
+
+ """
+ m = getmaskarray(arr)
+ return m.sum(axis)
+
+
+def masked_all(shape, dtype=float):
+ """
+ Empty masked array with all elements masked.
+
+ Return an empty masked array of the given shape and dtype, where all the
+ data are masked.
+
+ Parameters
+ ----------
+ shape : int or tuple of ints
+ Shape of the required MaskedArray, e.g., ``(2, 3)`` or ``2``.
+ dtype : dtype, optional
+ Data type of the output.
+
+ Returns
+ -------
+ a : MaskedArray
+ A masked array with all data masked.
+
+ See Also
+ --------
+ masked_all_like : Empty masked array modelled on an existing array.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> ma.masked_all((3, 3))
+ masked_array(
+ data=[[--, --, --],
+ [--, --, --],
+ [--, --, --]],
+ mask=[[ True, True, True],
+ [ True, True, True],
+ [ True, True, True]],
+ fill_value=1e+20,
+ dtype=float64)
+
+ The `dtype` parameter defines the underlying data type.
+
+ >>> a = ma.masked_all((3, 3))
+ >>> a.dtype
+ dtype('float64')
+ >>> a = ma.masked_all((3, 3), dtype=np.int32)
+ >>> a.dtype
+ dtype('int32')
+
+ """
+ a = masked_array(np.empty(shape, dtype),
+ mask=np.ones(shape, make_mask_descr(dtype)))
+ return a
+
+
+def masked_all_like(arr):
+ """
+ Empty masked array with the properties of an existing array.
+
+ Return an empty masked array of the same shape and dtype as
+ the array `arr`, where all the data are masked.
+
+ Parameters
+ ----------
+ arr : ndarray
+ An array describing the shape and dtype of the required MaskedArray.
+
+ Returns
+ -------
+ a : MaskedArray
+ A masked array with all data masked.
+
+ Raises
+ ------
+ AttributeError
+ If `arr` doesn't have a shape attribute (i.e. not an ndarray)
+
+ See Also
+ --------
+ masked_all : Empty masked array with all elements masked.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> arr = np.zeros((2, 3), dtype=np.float32)
+ >>> arr
+ array([[0., 0., 0.],
+ [0., 0., 0.]], dtype=float32)
+ >>> ma.masked_all_like(arr)
+ masked_array(
+ data=[[--, --, --],
+ [--, --, --]],
+ mask=[[ True, True, True],
+ [ True, True, True]],
+ fill_value=1e+20,
+ dtype=float32)
+
+ The dtype of the masked array matches the dtype of `arr`.
+
+ >>> arr.dtype
+ dtype('float32')
+ >>> ma.masked_all_like(arr).dtype
+ dtype('float32')
+
+ """
+ a = np.empty_like(arr).view(MaskedArray)
+ a._mask = np.ones(a.shape, dtype=make_mask_descr(a.dtype))
+ return a
+
+
+#####--------------------------------------------------------------------------
+#---- --- Standard functions ---
+#####--------------------------------------------------------------------------
+class _fromnxfunction:
+ """
+ Defines a wrapper to adapt NumPy functions to masked arrays.
+
+
+ An instance of `_fromnxfunction` can be called with the same parameters
+ as the wrapped NumPy function. The docstring of `newfunc` is adapted from
+ the wrapped function as well, see `getdoc`.
+
+ This class should not be used directly. Instead, one of its extensions that
+ provides support for a specific type of input should be used.
+
+ Parameters
+ ----------
+ funcname : str
+ The name of the function to be adapted. The function should be
+ in the NumPy namespace (i.e. ``np.funcname``).
+
+ """
+
+ def __init__(self, funcname):
+ self.__name__ = funcname
+ self.__doc__ = self.getdoc()
+
+ def getdoc(self):
+ """
+ Retrieve the docstring and signature from the function.
+
+ The ``__doc__`` attribute of the function is used as the docstring for
+ the new masked array version of the function. A note on application
+ of the function to the mask is appended.
+
+ Parameters
+ ----------
+ None
+
+ """
+ npfunc = getattr(np, self.__name__, None)
+ doc = getattr(npfunc, '__doc__', None)
+ if doc:
+ sig = self.__name__ + ma.get_object_signature(npfunc)
+ doc = ma.doc_note(doc, "The function is applied to both the _data "
+ "and the _mask, if any.")
+ return '\n\n'.join((sig, doc))
+ return
+
+ def __call__(self, *args, **params):
+ pass
+
+
+class _fromnxfunction_single(_fromnxfunction):
+ """
+ A version of `_fromnxfunction` that is called with a single array
+ argument followed by auxiliary args that are passed verbatim for
+ both the data and mask calls.
+ """
+ def __call__(self, x, *args, **params):
+ func = getattr(np, self.__name__)
+ if isinstance(x, ndarray):
+ _d = func(x.__array__(), *args, **params)
+ _m = func(getmaskarray(x), *args, **params)
+ return masked_array(_d, mask=_m)
+ else:
+ _d = func(np.asarray(x), *args, **params)
+ _m = func(getmaskarray(x), *args, **params)
+ return masked_array(_d, mask=_m)
+
+
+class _fromnxfunction_seq(_fromnxfunction):
+ """
+ A version of `_fromnxfunction` that is called with a single sequence
+ of arrays followed by auxiliary args that are passed verbatim for
+ both the data and mask calls.
+ """
+ def __call__(self, x, *args, **params):
+ func = getattr(np, self.__name__)
+ _d = func(tuple([np.asarray(a) for a in x]), *args, **params)
+ _m = func(tuple([getmaskarray(a) for a in x]), *args, **params)
+ return masked_array(_d, mask=_m)
+
+
+class _fromnxfunction_args(_fromnxfunction):
+ """
+ A version of `_fromnxfunction` that is called with multiple array
+ arguments. The first non-array-like input marks the beginning of the
+ arguments that are passed verbatim for both the data and mask calls.
+ Array arguments are processed independently and the results are
+ returned in a list. If only one array is found, the return value is
+ just the processed array instead of a list.
+ """
+ def __call__(self, *args, **params):
+ func = getattr(np, self.__name__)
+ arrays = []
+ args = list(args)
+ while len(args) > 0 and issequence(args[0]):
+ arrays.append(args.pop(0))
+ res = []
+ for x in arrays:
+ _d = func(np.asarray(x), *args, **params)
+ _m = func(getmaskarray(x), *args, **params)
+ res.append(masked_array(_d, mask=_m))
+ if len(arrays) == 1:
+ return res[0]
+ return res
+
+
+class _fromnxfunction_allargs(_fromnxfunction):
+ """
+ A version of `_fromnxfunction` that is called with multiple array
+ arguments. Similar to `_fromnxfunction_args` except that all args
+ are converted to arrays even if they are not so already. This makes
+ it possible to process scalars as 1-D arrays. Only keyword arguments
+ are passed through verbatim for the data and mask calls. Arrays
+ arguments are processed independently and the results are returned
+ in a list. If only one arg is present, the return value is just the
+ processed array instead of a list.
+ """
+ def __call__(self, *args, **params):
+ func = getattr(np, self.__name__)
+ res = []
+ for x in args:
+ _d = func(np.asarray(x), **params)
+ _m = func(getmaskarray(x), **params)
+ res.append(masked_array(_d, mask=_m))
+ if len(args) == 1:
+ return res[0]
+ return res
+
+
+atleast_1d = _fromnxfunction_allargs('atleast_1d')
+atleast_2d = _fromnxfunction_allargs('atleast_2d')
+atleast_3d = _fromnxfunction_allargs('atleast_3d')
+
+vstack = row_stack = _fromnxfunction_seq('vstack')
+hstack = _fromnxfunction_seq('hstack')
+column_stack = _fromnxfunction_seq('column_stack')
+dstack = _fromnxfunction_seq('dstack')
+stack = _fromnxfunction_seq('stack')
+
+hsplit = _fromnxfunction_single('hsplit')
+
+diagflat = _fromnxfunction_single('diagflat')
+
+
+#####--------------------------------------------------------------------------
+#----
+#####--------------------------------------------------------------------------
+def flatten_inplace(seq):
+ """Flatten a sequence in place."""
+ k = 0
+ while (k != len(seq)):
+ while hasattr(seq[k], '__iter__'):
+ seq[k:(k + 1)] = seq[k]
+ k += 1
+ return seq
+
+
+def apply_along_axis(func1d, axis, arr, *args, **kwargs):
+ """
+ (This docstring should be overwritten)
+ """
+ arr = array(arr, copy=False, subok=True)
+ nd = arr.ndim
+ axis = normalize_axis_index(axis, nd)
+ ind = [0] * (nd - 1)
+ i = np.zeros(nd, 'O')
+ indlist = list(range(nd))
+ indlist.remove(axis)
+ i[axis] = slice(None, None)
+ outshape = np.asarray(arr.shape).take(indlist)
+ i.put(indlist, ind)
+ res = func1d(arr[tuple(i.tolist())], *args, **kwargs)
+ # if res is a number, then we have a smaller output array
+ asscalar = np.isscalar(res)
+ if not asscalar:
+ try:
+ len(res)
+ except TypeError:
+ asscalar = True
+ # Note: we shouldn't set the dtype of the output from the first result
+ # so we force the type to object, and build a list of dtypes. We'll
+ # just take the largest, to avoid some downcasting
+ dtypes = []
+ if asscalar:
+ dtypes.append(np.asarray(res).dtype)
+ outarr = zeros(outshape, object)
+ outarr[tuple(ind)] = res
+ Ntot = np.product(outshape)
+ k = 1
+ while k < Ntot:
+ # increment the index
+ ind[-1] += 1
+ n = -1
+ while (ind[n] >= outshape[n]) and (n > (1 - nd)):
+ ind[n - 1] += 1
+ ind[n] = 0
+ n -= 1
+ i.put(indlist, ind)
+ res = func1d(arr[tuple(i.tolist())], *args, **kwargs)
+ outarr[tuple(ind)] = res
+ dtypes.append(asarray(res).dtype)
+ k += 1
+ else:
+ res = array(res, copy=False, subok=True)
+ j = i.copy()
+ j[axis] = ([slice(None, None)] * res.ndim)
+ j.put(indlist, ind)
+ Ntot = np.product(outshape)
+ holdshape = outshape
+ outshape = list(arr.shape)
+ outshape[axis] = res.shape
+ dtypes.append(asarray(res).dtype)
+ outshape = flatten_inplace(outshape)
+ outarr = zeros(outshape, object)
+ outarr[tuple(flatten_inplace(j.tolist()))] = res
+ k = 1
+ while k < Ntot:
+ # increment the index
+ ind[-1] += 1
+ n = -1
+ while (ind[n] >= holdshape[n]) and (n > (1 - nd)):
+ ind[n - 1] += 1
+ ind[n] = 0
+ n -= 1
+ i.put(indlist, ind)
+ j.put(indlist, ind)
+ res = func1d(arr[tuple(i.tolist())], *args, **kwargs)
+ outarr[tuple(flatten_inplace(j.tolist()))] = res
+ dtypes.append(asarray(res).dtype)
+ k += 1
+ max_dtypes = np.dtype(np.asarray(dtypes).max())
+ if not hasattr(arr, '_mask'):
+ result = np.asarray(outarr, dtype=max_dtypes)
+ else:
+ result = asarray(outarr, dtype=max_dtypes)
+ result.fill_value = ma.default_fill_value(result)
+ return result
+apply_along_axis.__doc__ = np.apply_along_axis.__doc__
+
+
+def apply_over_axes(func, a, axes):
+ """
+ (This docstring will be overwritten)
+ """
+ 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 = func(*args)
+ if res.ndim == val.ndim:
+ val = res
+ else:
+ res = ma.expand_dims(res, axis)
+ if res.ndim == val.ndim:
+ val = res
+ else:
+ raise ValueError("function is not returning "
+ "an array of the correct shape")
+ return val
+
+
+if apply_over_axes.__doc__ is not None:
+ apply_over_axes.__doc__ = np.apply_over_axes.__doc__[
+ :np.apply_over_axes.__doc__.find('Notes')].rstrip() + \
+ """
+
+ Examples
+ --------
+ >>> a = np.ma.arange(24).reshape(2,3,4)
+ >>> a[:,0,1] = np.ma.masked
+ >>> a[:,1,:] = np.ma.masked
+ >>> a
+ masked_array(
+ data=[[[0, --, 2, 3],
+ [--, --, --, --],
+ [8, 9, 10, 11]],
+ [[12, --, 14, 15],
+ [--, --, --, --],
+ [20, 21, 22, 23]]],
+ mask=[[[False, True, False, False],
+ [ True, True, True, True],
+ [False, False, False, False]],
+ [[False, True, False, False],
+ [ True, True, True, True],
+ [False, False, False, False]]],
+ fill_value=999999)
+ >>> np.ma.apply_over_axes(np.ma.sum, a, [0,2])
+ masked_array(
+ data=[[[46],
+ [--],
+ [124]]],
+ mask=[[[False],
+ [ True],
+ [False]]],
+ fill_value=999999)
+
+ Tuple axis arguments to ufuncs are equivalent:
+
+ >>> np.ma.sum(a, axis=(0,2)).reshape((1,-1,1))
+ masked_array(
+ data=[[[46],
+ [--],
+ [124]]],
+ mask=[[[False],
+ [ True],
+ [False]]],
+ fill_value=999999)
+ """
+
+
+def average(a, axis=None, weights=None, returned=False, *,
+ keepdims=np._NoValue):
+ """
+ Return the weighted average of array over the given axis.
+
+ Parameters
+ ----------
+ a : array_like
+ Data to be averaged.
+ Masked entries are not taken into account in the computation.
+ axis : int, optional
+ Axis along which to average `a`. If None, averaging is done over
+ 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
+ the size of `a` along the given axis) or of the same shape as `a`.
+ If ``weights=None``, then all data in `a` are assumed to have a
+ weight equal to one. The 1-D calculation is::
+
+ avg = sum(a * weights) / sum(weights)
+
+ The only constraint on `weights` is that `sum(weights)` must not be 0.
+ returned : bool, optional
+ Flag indicating whether a tuple ``(result, sum of weights)``
+ should be returned as output (True), or just the result (False).
+ Default is False.
+ keepdims : bool, optional
+ If this is set to True, the axes which are reduced are left
+ in the result as dimensions with size one. With this option,
+ the result will broadcast correctly against the original `a`.
+ *Note:* `keepdims` will not work with instances of `numpy.matrix`
+ or other classes whose methods do not support `keepdims`.
+
+ .. versionadded:: 1.23.0
+
+ Returns
+ -------
+ average, [sum_of_weights] : (tuple of) scalar or MaskedArray
+ The average along the specified axis. When returned is `True`,
+ return a tuple with the average as the first element and the sum
+ of the weights as the second element. The return type is `np.float64`
+ if `a` is of integer type and floats smaller than `float64`, or the
+ input data-type, otherwise. If returned, `sum_of_weights` is always
+ `float64`.
+
+ Examples
+ --------
+ >>> a = np.ma.array([1., 2., 3., 4.], mask=[False, False, True, True])
+ >>> np.ma.average(a, weights=[3, 1, 0, 0])
+ 1.25
+
+ >>> x = np.ma.arange(6.).reshape(3, 2)
+ >>> x
+ masked_array(
+ data=[[0., 1.],
+ [2., 3.],
+ [4., 5.]],
+ mask=False,
+ fill_value=1e+20)
+ >>> avg, sumweights = np.ma.average(x, axis=0, weights=[1, 2, 3],
+ ... returned=True)
+ >>> avg
+ masked_array(data=[2.6666666666666665, 3.6666666666666665],
+ mask=[False, False],
+ fill_value=1e+20)
+
+ With ``keepdims=True``, the following result has shape (3, 1).
+
+ >>> np.ma.average(x, axis=1, keepdims=True)
+ masked_array(
+ data=[[0.5],
+ [2.5],
+ [4.5]],
+ mask=False,
+ fill_value=1e+20)
+ """
+ a = asarray(a)
+ m = getmask(a)
+
+ # inspired by 'average' in numpy/lib/function_base.py
+
+ if keepdims is np._NoValue:
+ # Don't pass on the keepdims argument if one wasn't given.
+ keepdims_kw = {}
+ else:
+ keepdims_kw = {'keepdims': keepdims}
+
+ if weights is None:
+ avg = a.mean(axis, **keepdims_kw)
+ scl = avg.dtype.type(a.count(axis))
+ else:
+ wgt = asarray(weights)
+
+ if issubclass(a.dtype.type, (np.integer, np.bool_)):
+ result_dtype = np.result_type(a.dtype, wgt.dtype, 'f8')
+ else:
+ result_dtype = np.result_type(a.dtype, wgt.dtype)
+
+ # Sanity checks
+ if a.shape != wgt.shape:
+ if axis is None:
+ raise TypeError(
+ "Axis must be specified when shapes of a and weights "
+ "differ.")
+ if wgt.ndim != 1:
+ raise TypeError(
+ "1D weights expected when shapes of a and weights differ.")
+ if wgt.shape[0] != a.shape[axis]:
+ raise ValueError(
+ "Length of weights not compatible with specified axis.")
+
+ # setup wgt to broadcast along axis
+ wgt = np.broadcast_to(wgt, (a.ndim-1)*(1,) + wgt.shape, subok=True)
+ wgt = wgt.swapaxes(-1, axis)
+
+ if m is not nomask:
+ wgt = wgt*(~a.mask)
+ wgt.mask |= a.mask
+
+ scl = wgt.sum(axis=axis, dtype=result_dtype, **keepdims_kw)
+ avg = np.multiply(a, wgt,
+ dtype=result_dtype).sum(axis, **keepdims_kw) / scl
+
+ if returned:
+ if scl.shape != avg.shape:
+ scl = np.broadcast_to(scl, avg.shape).copy()
+ return avg, scl
+ else:
+ return avg
+
+
+def median(a, axis=None, out=None, overwrite_input=False, keepdims=False):
+ """
+ Compute the median along the specified axis.
+
+ Returns the median of the array elements.
+
+ Parameters
+ ----------
+ a : array_like
+ Input array or object that can be converted to an array.
+ axis : int, optional
+ Axis along which the medians are computed. The default (None) is
+ to compute the median along a flattened version of the array.
+ out : ndarray, optional
+ Alternative output array in which to place the result. It must
+ have the same shape and buffer length as the expected output
+ but the type will be cast if necessary.
+ overwrite_input : bool, optional
+ If True, then allow use of memory of input array (a) for
+ calculations. The input array will be modified by the call to
+ median. This will save memory when you do not need to preserve
+ the contents of the input array. Treat the input as undefined,
+ but it will probably be fully or partially sorted. Default is
+ False. Note that, if `overwrite_input` is True, and the input
+ is not already an `ndarray`, an error will be raised.
+ keepdims : bool, optional
+ If this is set to True, the axes which are reduced are left
+ in the result as dimensions with size one. With this option,
+ the result will broadcast correctly against the input array.
+
+ .. versionadded:: 1.10.0
+
+ Returns
+ -------
+ median : ndarray
+ A new array holding the result is returned unless out is
+ specified, in which case a reference to out is returned.
+ Return data-type is `float64` for integers and floats smaller than
+ `float64`, or the input data-type, otherwise.
+
+ See Also
+ --------
+ mean
+
+ Notes
+ -----
+ Given a vector ``V`` with ``N`` non masked values, the median of ``V``
+ is the middle value of a sorted copy of ``V`` (``Vs``) - i.e.
+ ``Vs[(N-1)/2]``, when ``N`` is odd, or ``{Vs[N/2 - 1] + Vs[N/2]}/2``
+ when ``N`` is even.
+
+ Examples
+ --------
+ >>> x = np.ma.array(np.arange(8), mask=[0]*4 + [1]*4)
+ >>> np.ma.median(x)
+ 1.5
+
+ >>> x = np.ma.array(np.arange(10).reshape(2, 5), mask=[0]*6 + [1]*4)
+ >>> np.ma.median(x)
+ 2.5
+ >>> np.ma.median(x, axis=-1, overwrite_input=True)
+ masked_array(data=[2.0, 5.0],
+ mask=[False, False],
+ fill_value=1e+20)
+
+ """
+ if not hasattr(a, 'mask'):
+ m = np.median(getdata(a, subok=True), axis=axis,
+ out=out, overwrite_input=overwrite_input,
+ keepdims=keepdims)
+ if isinstance(m, np.ndarray) and 1 <= m.ndim:
+ return masked_array(m, copy=False)
+ else:
+ return m
+
+ return _ureduce(a, func=_median, keepdims=keepdims, axis=axis, out=out,
+ overwrite_input=overwrite_input)
+
+
+def _median(a, axis=None, out=None, overwrite_input=False):
+ # when an unmasked NaN is present return it, so we need to sort the NaN
+ # values behind the mask
+ if np.issubdtype(a.dtype, np.inexact):
+ fill_value = np.inf
+ else:
+ fill_value = None
+ if overwrite_input:
+ if axis is None:
+ asorted = a.ravel()
+ asorted.sort(fill_value=fill_value)
+ else:
+ a.sort(axis=axis, fill_value=fill_value)
+ asorted = a
+ else:
+ asorted = sort(a, axis=axis, fill_value=fill_value)
+
+ if axis is None:
+ axis = 0
+ else:
+ axis = normalize_axis_index(axis, asorted.ndim)
+
+ if asorted.shape[axis] == 0:
+ # for empty axis integer indices fail so use slicing to get same result
+ # as median (which is mean of empty slice = nan)
+ indexer = [slice(None)] * asorted.ndim
+ indexer[axis] = slice(0, 0)
+ indexer = tuple(indexer)
+ return np.ma.mean(asorted[indexer], axis=axis, out=out)
+
+ if asorted.ndim == 1:
+ idx, odd = divmod(count(asorted), 2)
+ mid = asorted[idx + odd - 1:idx + 1]
+ if np.issubdtype(asorted.dtype, np.inexact) and asorted.size > 0:
+ # avoid inf / x = masked
+ s = mid.sum(out=out)
+ if not odd:
+ s = np.true_divide(s, 2., casting='safe', out=out)
+ s = np.lib.utils._median_nancheck(asorted, s, axis)
+ else:
+ s = mid.mean(out=out)
+
+ # if result is masked either the input contained enough
+ # minimum_fill_value so that it would be the median or all values
+ # masked
+ if np.ma.is_masked(s) and not np.all(asorted.mask):
+ return np.ma.minimum_fill_value(asorted)
+ return s
+
+ counts = count(asorted, axis=axis, keepdims=True)
+ h = counts // 2
+
+ # duplicate high if odd number of elements so mean does nothing
+ odd = counts % 2 == 1
+ l = np.where(odd, h, h-1)
+
+ lh = np.concatenate([l,h], axis=axis)
+
+ # get low and high median
+ low_high = np.take_along_axis(asorted, lh, axis=axis)
+
+ def replace_masked(s):
+ # Replace masked entries with minimum_full_value unless it all values
+ # are masked. This is required as the sort order of values equal or
+ # larger than the fill value is undefined and a valid value placed
+ # elsewhere, e.g. [4, --, inf].
+ if np.ma.is_masked(s):
+ rep = (~np.all(asorted.mask, axis=axis, keepdims=True)) & s.mask
+ s.data[rep] = np.ma.minimum_fill_value(asorted)
+ s.mask[rep] = False
+
+ replace_masked(low_high)
+
+ if np.issubdtype(asorted.dtype, np.inexact):
+ # avoid inf / x = masked
+ s = np.ma.sum(low_high, axis=axis, out=out)
+ np.true_divide(s.data, 2., casting='unsafe', out=s.data)
+
+ s = np.lib.utils._median_nancheck(asorted, s, axis)
+ else:
+ s = np.ma.mean(low_high, axis=axis, out=out)
+
+ return s
+
+
+def compress_nd(x, axis=None):
+ """Suppress slices from multiple dimensions which contain masked values.
+
+ Parameters
+ ----------
+ x : array_like, MaskedArray
+ The array to operate on. If not a MaskedArray instance (or if no array
+ elements are masked), `x` is interpreted as a MaskedArray with `mask`
+ set to `nomask`.
+ axis : tuple of ints or int, optional
+ Which dimensions to suppress slices from can be configured with this
+ parameter.
+ - If axis is a tuple of ints, those are the axes to suppress slices from.
+ - If axis is an int, then that is the only axis to suppress slices from.
+ - If axis is None, all axis are selected.
+
+ Returns
+ -------
+ compress_array : ndarray
+ The compressed array.
+ """
+ x = asarray(x)
+ m = getmask(x)
+ # Set axis to tuple of ints
+ if axis is None:
+ axis = tuple(range(x.ndim))
+ else:
+ axis = normalize_axis_tuple(axis, x.ndim)
+
+ # Nothing is masked: return x
+ if m is nomask or not m.any():
+ return x._data
+ # All is masked: return empty
+ if m.all():
+ return nxarray([])
+ # Filter elements through boolean indexing
+ data = x._data
+ for ax in axis:
+ axes = tuple(list(range(ax)) + list(range(ax + 1, x.ndim)))
+ data = data[(slice(None),)*ax + (~m.any(axis=axes),)]
+ return data
+
+
+def compress_rowcols(x, axis=None):
+ """
+ Suppress the rows and/or columns of a 2-D array that contain
+ masked values.
+
+ The suppression behavior is selected with the `axis` parameter.
+
+ - If axis is None, both rows and columns are suppressed.
+ - If axis is 0, only rows are suppressed.
+ - If axis is 1 or -1, only columns are suppressed.
+
+ Parameters
+ ----------
+ x : array_like, MaskedArray
+ The array to operate on. If not a MaskedArray instance (or if no array
+ elements are masked), `x` is interpreted as a MaskedArray with
+ `mask` set to `nomask`. Must be a 2D array.
+ axis : int, optional
+ Axis along which to perform the operation. Default is None.
+
+ Returns
+ -------
+ compressed_array : ndarray
+ The compressed array.
+
+ Examples
+ --------
+ >>> x = np.ma.array(np.arange(9).reshape(3, 3), mask=[[1, 0, 0],
+ ... [1, 0, 0],
+ ... [0, 0, 0]])
+ >>> x
+ masked_array(
+ data=[[--, 1, 2],
+ [--, 4, 5],
+ [6, 7, 8]],
+ mask=[[ True, False, False],
+ [ True, False, False],
+ [False, False, False]],
+ fill_value=999999)
+
+ >>> np.ma.compress_rowcols(x)
+ array([[7, 8]])
+ >>> np.ma.compress_rowcols(x, 0)
+ array([[6, 7, 8]])
+ >>> np.ma.compress_rowcols(x, 1)
+ array([[1, 2],
+ [4, 5],
+ [7, 8]])
+
+ """
+ if asarray(x).ndim != 2:
+ raise NotImplementedError("compress_rowcols works for 2D arrays only.")
+ return compress_nd(x, axis=axis)
+
+
+def compress_rows(a):
+ """
+ Suppress whole rows of a 2-D array that contain masked values.
+
+ This is equivalent to ``np.ma.compress_rowcols(a, 0)``, see
+ `compress_rowcols` for details.
+
+ See Also
+ --------
+ compress_rowcols
+
+ """
+ a = asarray(a)
+ if a.ndim != 2:
+ raise NotImplementedError("compress_rows works for 2D arrays only.")
+ return compress_rowcols(a, 0)
+
+
+def compress_cols(a):
+ """
+ Suppress whole columns of a 2-D array that contain masked values.
+
+ This is equivalent to ``np.ma.compress_rowcols(a, 1)``, see
+ `compress_rowcols` for details.
+
+ See Also
+ --------
+ compress_rowcols
+
+ """
+ a = asarray(a)
+ if a.ndim != 2:
+ raise NotImplementedError("compress_cols works for 2D arrays only.")
+ return compress_rowcols(a, 1)
+
+
+def mask_rows(a, axis=np._NoValue):
+ """
+ Mask rows of a 2D array that contain masked values.
+
+ This function is a shortcut to ``mask_rowcols`` with `axis` equal to 0.
+
+ See Also
+ --------
+ mask_rowcols : Mask rows and/or columns of a 2D array.
+ masked_where : Mask where a condition is met.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> a = np.zeros((3, 3), dtype=int)
+ >>> a[1, 1] = 1
+ >>> a
+ array([[0, 0, 0],
+ [0, 1, 0],
+ [0, 0, 0]])
+ >>> a = ma.masked_equal(a, 1)
+ >>> a
+ masked_array(
+ data=[[0, 0, 0],
+ [0, --, 0],
+ [0, 0, 0]],
+ mask=[[False, False, False],
+ [False, True, False],
+ [False, False, False]],
+ fill_value=1)
+
+ >>> ma.mask_rows(a)
+ masked_array(
+ data=[[0, 0, 0],
+ [--, --, --],
+ [0, 0, 0]],
+ mask=[[False, False, False],
+ [ True, True, True],
+ [False, False, False]],
+ fill_value=1)
+
+ """
+ if axis is not np._NoValue:
+ # remove the axis argument when this deprecation expires
+ # NumPy 1.18.0, 2019-11-28
+ warnings.warn(
+ "The axis argument has always been ignored, in future passing it "
+ "will raise TypeError", DeprecationWarning, stacklevel=2)
+ return mask_rowcols(a, 0)
+
+
+def mask_cols(a, axis=np._NoValue):
+ """
+ Mask columns of a 2D array that contain masked values.
+
+ This function is a shortcut to ``mask_rowcols`` with `axis` equal to 1.
+
+ See Also
+ --------
+ mask_rowcols : Mask rows and/or columns of a 2D array.
+ masked_where : Mask where a condition is met.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> a = np.zeros((3, 3), dtype=int)
+ >>> a[1, 1] = 1
+ >>> a
+ array([[0, 0, 0],
+ [0, 1, 0],
+ [0, 0, 0]])
+ >>> a = ma.masked_equal(a, 1)
+ >>> a
+ masked_array(
+ data=[[0, 0, 0],
+ [0, --, 0],
+ [0, 0, 0]],
+ mask=[[False, False, False],
+ [False, True, False],
+ [False, False, False]],
+ fill_value=1)
+ >>> ma.mask_cols(a)
+ masked_array(
+ data=[[0, --, 0],
+ [0, --, 0],
+ [0, --, 0]],
+ mask=[[False, True, False],
+ [False, True, False],
+ [False, True, False]],
+ fill_value=1)
+
+ """
+ if axis is not np._NoValue:
+ # remove the axis argument when this deprecation expires
+ # NumPy 1.18.0, 2019-11-28
+ warnings.warn(
+ "The axis argument has always been ignored, in future passing it "
+ "will raise TypeError", DeprecationWarning, stacklevel=2)
+ return mask_rowcols(a, 1)
+
+
+#####--------------------------------------------------------------------------
+#---- --- arraysetops ---
+#####--------------------------------------------------------------------------
+
+def ediff1d(arr, to_end=None, to_begin=None):
+ """
+ Compute the differences between consecutive elements of an array.
+
+ This function is the equivalent of `numpy.ediff1d` that takes masked
+ values into account, see `numpy.ediff1d` for details.
+
+ See Also
+ --------
+ numpy.ediff1d : Equivalent function for ndarrays.
+
+ """
+ arr = ma.asanyarray(arr).flat
+ ed = arr[1:] - arr[:-1]
+ arrays = [ed]
+ #
+ if to_begin is not None:
+ arrays.insert(0, to_begin)
+ if to_end is not None:
+ arrays.append(to_end)
+ #
+ if len(arrays) != 1:
+ # We'll save ourselves a copy of a potentially large array in the common
+ # case where neither to_begin or to_end was given.
+ ed = hstack(arrays)
+ #
+ return ed
+
+
+def unique(ar1, return_index=False, return_inverse=False):
+ """
+ Finds the unique elements of an array.
+
+ Masked values are considered the same element (masked). The output array
+ is always a masked array. See `numpy.unique` for more details.
+
+ See Also
+ --------
+ numpy.unique : Equivalent function for ndarrays.
+
+ Examples
+ --------
+ >>> import numpy.ma as ma
+ >>> a = [1, 2, 1000, 2, 3]
+ >>> mask = [0, 0, 1, 0, 0]
+ >>> masked_a = ma.masked_array(a, mask)
+ >>> masked_a
+ masked_array(data=[1, 2, --, 2, 3],
+ mask=[False, False, True, False, False],
+ fill_value=999999)
+ >>> ma.unique(masked_a)
+ masked_array(data=[1, 2, 3, --],
+ mask=[False, False, False, True],
+ fill_value=999999)
+ >>> ma.unique(masked_a, return_index=True)
+ (masked_array(data=[1, 2, 3, --],
+ mask=[False, False, False, True],
+ fill_value=999999), array([0, 1, 4, 2]))
+ >>> ma.unique(masked_a, return_inverse=True)
+ (masked_array(data=[1, 2, 3, --],
+ mask=[False, False, False, True],
+ fill_value=999999), array([0, 1, 3, 1, 2]))
+ >>> ma.unique(masked_a, return_index=True, return_inverse=True)
+ (masked_array(data=[1, 2, 3, --],
+ mask=[False, False, False, True],
+ fill_value=999999), array([0, 1, 4, 2]), array([0, 1, 3, 1, 2]))
+ """
+ output = np.unique(ar1,
+ return_index=return_index,
+ return_inverse=return_inverse)
+ if isinstance(output, tuple):
+ output = list(output)
+ output[0] = output[0].view(MaskedArray)
+ output = tuple(output)
+ else:
+ output = output.view(MaskedArray)
+ return output
+
+
+def intersect1d(ar1, ar2, assume_unique=False):
+ """
+ Returns the unique elements common to both arrays.
+
+ Masked values are considered equal one to the other.
+ The output is always a masked array.
+
+ See `numpy.intersect1d` for more details.
+
+ See Also
+ --------
+ numpy.intersect1d : Equivalent function for ndarrays.
+
+ Examples
+ --------
+ >>> x = np.ma.array([1, 3, 3, 3], mask=[0, 0, 0, 1])
+ >>> y = np.ma.array([3, 1, 1, 1], mask=[0, 0, 0, 1])
+ >>> np.ma.intersect1d(x, y)
+ masked_array(data=[1, 3, --],
+ mask=[False, False, True],
+ fill_value=999999)
+
+ """
+ if assume_unique:
+ aux = ma.concatenate((ar1, ar2))
+ else:
+ # Might be faster than unique( intersect1d( ar1, ar2 ) )?
+ aux = ma.concatenate((unique(ar1), unique(ar2)))
+ aux.sort()
+ return aux[:-1][aux[1:] == aux[:-1]]
+
+
+def setxor1d(ar1, ar2, assume_unique=False):
+ """
+ Set exclusive-or of 1-D arrays with unique elements.
+
+ The output is always a masked array. See `numpy.setxor1d` for more details.
+
+ See Also
+ --------
+ numpy.setxor1d : Equivalent function for ndarrays.
+
+ """
+ if not assume_unique:
+ ar1 = unique(ar1)
+ ar2 = unique(ar2)
+
+ aux = ma.concatenate((ar1, ar2))
+ if aux.size == 0:
+ return aux
+ aux.sort()
+ auxf = aux.filled()
+# flag = ediff1d( aux, to_end = 1, to_begin = 1 ) == 0
+ flag = ma.concatenate(([True], (auxf[1:] != auxf[:-1]), [True]))
+# flag2 = ediff1d( flag ) == 0
+ flag2 = (flag[1:] == flag[:-1])
+ return aux[flag2]
+
+
+def in1d(ar1, ar2, assume_unique=False, invert=False):
+ """
+ Test whether each element of an array is also present in a second
+ array.
+
+ The output is always a masked array. See `numpy.in1d` for more details.
+
+ We recommend using :func:`isin` instead of `in1d` for new code.
+
+ See Also
+ --------
+ isin : Version of this function that preserves the shape of ar1.
+ numpy.in1d : Equivalent function for ndarrays.
+
+ Notes
+ -----
+ .. versionadded:: 1.4.0
+
+ """
+ if not assume_unique:
+ ar1, rev_idx = unique(ar1, return_inverse=True)
+ ar2 = unique(ar2)
+
+ ar = ma.concatenate((ar1, ar2))
+ # We need this to be a stable sort, so always use 'mergesort'
+ # here. The values from the first array should always come before
+ # the values from the second array.
+ order = ar.argsort(kind='mergesort')
+ sar = ar[order]
+ if invert:
+ bool_ar = (sar[1:] != sar[:-1])
+ else:
+ bool_ar = (sar[1:] == sar[:-1])
+ flag = ma.concatenate((bool_ar, [invert]))
+ indx = order.argsort(kind='mergesort')[:len(ar1)]
+
+ if assume_unique:
+ return flag[indx]
+ else:
+ return flag[indx][rev_idx]
+
+
+def isin(element, test_elements, assume_unique=False, invert=False):
+ """
+ Calculates `element in test_elements`, broadcasting over
+ `element` only.
+
+ The output is always a masked array of the same shape as `element`.
+ See `numpy.isin` for more details.
+
+ See Also
+ --------
+ in1d : Flattened version of this function.
+ numpy.isin : Equivalent function for ndarrays.
+
+ Notes
+ -----
+ .. versionadded:: 1.13.0
+
+ """
+ element = ma.asarray(element)
+ return in1d(element, test_elements, assume_unique=assume_unique,
+ invert=invert).reshape(element.shape)
+
+
+def union1d(ar1, ar2):
+ """
+ Union of two arrays.
+
+ The output is always a masked array. See `numpy.union1d` for more details.
+
+ See Also
+ --------
+ numpy.union1d : Equivalent function for ndarrays.
+
+ """
+ return unique(ma.concatenate((ar1, ar2), axis=None))
+
+
+def setdiff1d(ar1, ar2, assume_unique=False):
+ """
+ Set difference of 1D arrays with unique elements.
+
+ The output is always a masked array. See `numpy.setdiff1d` for more
+ details.
+
+ See Also
+ --------
+ numpy.setdiff1d : Equivalent function for ndarrays.
+
+ Examples
+ --------
+ >>> x = np.ma.array([1, 2, 3, 4], mask=[0, 1, 0, 1])
+ >>> np.ma.setdiff1d(x, [1, 2])
+ masked_array(data=[3, --],
+ mask=[False, True],
+ fill_value=999999)
+
+ """
+ if assume_unique:
+ ar1 = ma.asarray(ar1).ravel()
+ else:
+ ar1 = unique(ar1)
+ ar2 = unique(ar2)
+ return ar1[in1d(ar1, ar2, assume_unique=True, invert=True)]
+
+
+###############################################################################
+# Covariance #
+###############################################################################
+
+
+def _covhelper(x, y=None, rowvar=True, allow_masked=True):
+ """
+ Private function for the computation of covariance and correlation
+ coefficients.
+
+ """
+ x = ma.array(x, ndmin=2, copy=True, dtype=float)
+ xmask = ma.getmaskarray(x)
+ # Quick exit if we can't process masked data
+ if not allow_masked and xmask.any():
+ raise ValueError("Cannot process masked data.")
+ #
+ if x.shape[0] == 1:
+ rowvar = True
+ # Make sure that rowvar is either 0 or 1
+ rowvar = int(bool(rowvar))
+ axis = 1 - rowvar
+ if rowvar:
+ tup = (slice(None), None)
+ else:
+ tup = (None, slice(None))
+ #
+ if y is None:
+ xnotmask = np.logical_not(xmask).astype(int)
+ else:
+ y = array(y, copy=False, ndmin=2, dtype=float)
+ ymask = ma.getmaskarray(y)
+ if not allow_masked and ymask.any():
+ raise ValueError("Cannot process masked data.")
+ if xmask.any() or ymask.any():
+ if y.shape == x.shape:
+ # Define some common mask
+ common_mask = np.logical_or(xmask, ymask)
+ if common_mask is not nomask:
+ xmask = x._mask = y._mask = ymask = common_mask
+ x._sharedmask = False
+ y._sharedmask = False
+ x = ma.concatenate((x, y), axis)
+ xnotmask = np.logical_not(np.concatenate((xmask, ymask), axis)).astype(int)
+ x -= x.mean(axis=rowvar)[tup]
+ return (x, xnotmask, rowvar)
+
+
+def cov(x, y=None, rowvar=True, bias=False, allow_masked=True, ddof=None):
+ """
+ Estimate the covariance matrix.
+
+ Except for the handling of missing data this function does the same as
+ `numpy.cov`. For more details and examples, see `numpy.cov`.
+
+ By default, masked values are recognized as such. If `x` and `y` have the
+ same shape, a common mask is allocated: if ``x[i,j]`` is masked, then
+ ``y[i,j]`` will also be masked.
+ Setting `allow_masked` to False will raise an exception if values are
+ missing in either of the input arrays.
+
+ Parameters
+ ----------
+ x : array_like
+ A 1-D or 2-D array containing multiple variables and observations.
+ Each row of `x` represents a variable, and each column a single
+ observation of all those variables. Also see `rowvar` below.
+ y : array_like, optional
+ An additional set of variables and observations. `y` has the same
+ shape as `x`.
+ rowvar : bool, optional
+ If `rowvar` is True (default), then each row represents a
+ variable, with observations in the columns. Otherwise, the relationship
+ is transposed: each column represents a variable, while the rows
+ contain observations.
+ bias : bool, optional
+ Default normalization (False) is by ``(N-1)``, where ``N`` is the
+ number of observations given (unbiased estimate). If `bias` is True,
+ then normalization is by ``N``. This keyword can be overridden by
+ the keyword ``ddof`` in numpy versions >= 1.5.
+ allow_masked : bool, optional
+ If True, masked values are propagated pair-wise: if a value is masked
+ in `x`, the corresponding value is masked in `y`.
+ If False, raises a `ValueError` exception when some values are missing.
+ ddof : {None, int}, optional
+ If not ``None`` normalization is by ``(N - ddof)``, where ``N`` is
+ the number of observations; this overrides the value implied by
+ ``bias``. The default value is ``None``.
+
+ .. versionadded:: 1.5
+
+ Raises
+ ------
+ ValueError
+ Raised if some values are missing and `allow_masked` is False.
+
+ See Also
+ --------
+ numpy.cov
+
+ """
+ # Check inputs
+ if ddof is not None and ddof != int(ddof):
+ raise ValueError("ddof must be an integer")
+ # Set up ddof
+ if ddof is None:
+ if bias:
+ ddof = 0
+ else:
+ ddof = 1
+
+ (x, xnotmask, rowvar) = _covhelper(x, y, rowvar, allow_masked)
+ if not rowvar:
+ fact = np.dot(xnotmask.T, xnotmask) * 1. - ddof
+ result = (dot(x.T, x.conj(), strict=False) / fact).squeeze()
+ else:
+ fact = np.dot(xnotmask, xnotmask.T) * 1. - ddof
+ result = (dot(x, x.T.conj(), strict=False) / fact).squeeze()
+ return result
+
+
+def corrcoef(x, y=None, rowvar=True, bias=np._NoValue, allow_masked=True,
+ ddof=np._NoValue):
+ """
+ Return Pearson product-moment correlation coefficients.
+
+ Except for the handling of missing data this function does the same as
+ `numpy.corrcoef`. For more details and examples, see `numpy.corrcoef`.
+
+ Parameters
+ ----------
+ x : array_like
+ A 1-D or 2-D array containing multiple variables and observations.
+ Each row of `x` represents a variable, and each column a single
+ observation of all those variables. Also see `rowvar` below.
+ y : array_like, optional
+ An additional set of variables and observations. `y` has the same
+ shape as `x`.
+ rowvar : bool, optional
+ If `rowvar` is True (default), then each row represents a
+ variable, with observations in the columns. Otherwise, the relationship
+ is transposed: each column represents a variable, while the rows
+ contain observations.
+ bias : _NoValue, optional
+ Has no effect, do not use.
+
+ .. deprecated:: 1.10.0
+ allow_masked : bool, optional
+ If True, masked values are propagated pair-wise: if a value is masked
+ in `x`, the corresponding value is masked in `y`.
+ If False, raises an exception. Because `bias` is deprecated, this
+ argument needs to be treated as keyword only to avoid a warning.
+ ddof : _NoValue, optional
+ Has no effect, do not use.
+
+ .. deprecated:: 1.10.0
+
+ See Also
+ --------
+ numpy.corrcoef : Equivalent function in top-level NumPy module.
+ cov : Estimate the covariance matrix.
+
+ Notes
+ -----
+ This function accepts but discards arguments `bias` and `ddof`. This is
+ for backwards compatibility with previous versions of this function. These
+ arguments had no effect on the return values of the function and can be
+ safely ignored in this and previous versions of numpy.
+ """
+ msg = 'bias and ddof have no effect and are deprecated'
+ if bias is not np._NoValue or ddof is not np._NoValue:
+ # 2015-03-15, 1.10
+ warnings.warn(msg, DeprecationWarning, stacklevel=2)
+ # Get the data
+ (x, xnotmask, rowvar) = _covhelper(x, y, rowvar, allow_masked)
+ # Compute the covariance matrix
+ if not rowvar:
+ fact = np.dot(xnotmask.T, xnotmask) * 1.
+ c = (dot(x.T, x.conj(), strict=False) / fact).squeeze()
+ else:
+ fact = np.dot(xnotmask, xnotmask.T) * 1.
+ c = (dot(x, x.T.conj(), strict=False) / fact).squeeze()
+ # Check whether we have a scalar
+ try:
+ diag = ma.diagonal(c)
+ except ValueError:
+ return 1
+ #
+ if xnotmask.all():
+ _denom = ma.sqrt(ma.multiply.outer(diag, diag))
+ else:
+ _denom = diagflat(diag)
+ _denom._sharedmask = False # We know return is always a copy
+ n = x.shape[1 - rowvar]
+ if rowvar:
+ for i in range(n - 1):
+ for j in range(i + 1, n):
+ _x = mask_cols(vstack((x[i], x[j]))).var(axis=1)
+ _denom[i, j] = _denom[j, i] = ma.sqrt(ma.multiply.reduce(_x))
+ else:
+ for i in range(n - 1):
+ for j in range(i + 1, n):
+ _x = mask_cols(
+ vstack((x[:, i], x[:, j]))).var(axis=1)
+ _denom[i, j] = _denom[j, i] = ma.sqrt(ma.multiply.reduce(_x))
+ return c / _denom
+
+#####--------------------------------------------------------------------------
+#---- --- Concatenation helpers ---
+#####--------------------------------------------------------------------------
+
+class MAxisConcatenator(AxisConcatenator):
+ """
+ Translate slice objects to concatenation along an axis.
+
+ For documentation on usage, see `mr_class`.
+
+ See Also
+ --------
+ mr_class
+
+ """
+ concatenate = staticmethod(concatenate)
+
+ @classmethod
+ def makemat(cls, arr):
+ # There used to be a view as np.matrix here, but we may eventually
+ # deprecate that class. In preparation, we use the unmasked version
+ # to construct the matrix (with copy=False for backwards compatibility
+ # with the .view)
+ data = super().makemat(arr.data, copy=False)
+ return array(data, mask=arr.mask)
+
+ def __getitem__(self, key):
+ # matrix builder syntax, like 'a, b; c, d'
+ if isinstance(key, str):
+ raise MAError("Unavailable for masked array.")
+
+ return super().__getitem__(key)
+
+
+class mr_class(MAxisConcatenator):
+ """
+ Translate slice objects to concatenation along the first axis.
+
+ This is the masked array version of `lib.index_tricks.RClass`.
+
+ See Also
+ --------
+ lib.index_tricks.RClass
+
+ Examples
+ --------
+ >>> np.ma.mr_[np.ma.array([1,2,3]), 0, 0, np.ma.array([4,5,6])]
+ masked_array(data=[1, 2, 3, ..., 4, 5, 6],
+ mask=False,
+ fill_value=999999)
+
+ """
+ def __init__(self):
+ MAxisConcatenator.__init__(self, 0)
+
+mr_ = mr_class()
+
+
+#####--------------------------------------------------------------------------
+#---- Find unmasked data ---
+#####--------------------------------------------------------------------------
+
+def ndenumerate(a, compressed=True):
+ """
+ Multidimensional index iterator.
+
+ Return an iterator yielding pairs of array coordinates and values,
+ skipping elements that are masked. With `compressed=False`,
+ `ma.masked` is yielded as the value of masked elements. This
+ behavior differs from that of `numpy.ndenumerate`, which yields the
+ value of the underlying data array.
+
+ Notes
+ -----
+ .. versionadded:: 1.23.0
+
+ Parameters
+ ----------
+ a : array_like
+ An array with (possibly) masked elements.
+ compressed : bool, optional
+ If True (default), masked elements are skipped.
+
+ See Also
+ --------
+ numpy.ndenumerate : Equivalent function ignoring any mask.
+
+ Examples
+ --------
+ >>> a = np.ma.arange(9).reshape((3, 3))
+ >>> a[1, 0] = np.ma.masked
+ >>> a[1, 2] = np.ma.masked
+ >>> a[2, 1] = np.ma.masked
+ >>> a
+ masked_array(
+ data=[[0, 1, 2],
+ [--, 4, --],
+ [6, --, 8]],
+ mask=[[False, False, False],
+ [ True, False, True],
+ [False, True, False]],
+ fill_value=999999)
+ >>> for index, x in np.ma.ndenumerate(a):
+ ... print(index, x)
+ (0, 0) 0
+ (0, 1) 1
+ (0, 2) 2
+ (1, 1) 4
+ (2, 0) 6
+ (2, 2) 8
+
+ >>> for index, x in np.ma.ndenumerate(a, compressed=False):
+ ... print(index, x)
+ (0, 0) 0
+ (0, 1) 1
+ (0, 2) 2
+ (1, 0) --
+ (1, 1) 4
+ (1, 2) --
+ (2, 0) 6
+ (2, 1) --
+ (2, 2) 8
+ """
+ for it, mask in zip(np.ndenumerate(a), getmaskarray(a).flat):
+ if not mask:
+ yield it
+ elif not compressed:
+ yield it[0], masked
+
+
+def flatnotmasked_edges(a):
+ """
+ Find the indices of the first and last unmasked values.
+
+ Expects a 1-D `MaskedArray`, returns None if all values are masked.
+
+ Parameters
+ ----------
+ a : array_like
+ Input 1-D `MaskedArray`
+
+ Returns
+ -------
+ edges : ndarray or None
+ The indices of first and last non-masked value in the array.
+ Returns None if all values are masked.
+
+ See Also
+ --------
+ flatnotmasked_contiguous, notmasked_contiguous, notmasked_edges
+ clump_masked, clump_unmasked
+
+ Notes
+ -----
+ Only accepts 1-D arrays.
+
+ Examples
+ --------
+ >>> a = np.ma.arange(10)
+ >>> np.ma.flatnotmasked_edges(a)
+ array([0, 9])
+
+ >>> mask = (a < 3) | (a > 8) | (a == 5)
+ >>> a[mask] = np.ma.masked
+ >>> np.array(a[~a.mask])
+ array([3, 4, 6, 7, 8])
+
+ >>> np.ma.flatnotmasked_edges(a)
+ array([3, 8])
+
+ >>> a[:] = np.ma.masked
+ >>> print(np.ma.flatnotmasked_edges(a))
+ None
+
+ """
+ m = getmask(a)
+ if m is nomask or not np.any(m):
+ return np.array([0, a.size - 1])
+ unmasked = np.flatnonzero(~m)
+ if len(unmasked) > 0:
+ return unmasked[[0, -1]]
+ else:
+ return None
+
+
+def notmasked_edges(a, axis=None):
+ """
+ Find the indices of the first and last unmasked values along an axis.
+
+ If all values are masked, return None. Otherwise, return a list
+ of two tuples, corresponding to the indices of the first and last
+ unmasked values respectively.
+
+ Parameters
+ ----------
+ a : array_like
+ The input array.
+ axis : int, optional
+ Axis along which to perform the operation.
+ If None (default), applies to a flattened version of the array.
+
+ Returns
+ -------
+ edges : ndarray or list
+ An array of start and end indexes if there are any masked data in
+ the array. If there are no masked data in the array, `edges` is a
+ list of the first and last index.
+
+ See Also
+ --------
+ flatnotmasked_contiguous, flatnotmasked_edges, notmasked_contiguous
+ clump_masked, clump_unmasked
+
+ Examples
+ --------
+ >>> a = np.arange(9).reshape((3, 3))
+ >>> m = np.zeros_like(a)
+ >>> m[1:, 1:] = 1
+
+ >>> am = np.ma.array(a, mask=m)
+ >>> np.array(am[~am.mask])
+ array([0, 1, 2, 3, 6])
+
+ >>> np.ma.notmasked_edges(am)
+ array([0, 6])
+
+ """
+ a = asarray(a)
+ if axis is None or a.ndim == 1:
+ return flatnotmasked_edges(a)
+ m = getmaskarray(a)
+ idx = array(np.indices(a.shape), mask=np.asarray([m] * a.ndim))
+ return [tuple([idx[i].min(axis).compressed() for i in range(a.ndim)]),
+ tuple([idx[i].max(axis).compressed() for i in range(a.ndim)]), ]
+
+
+def flatnotmasked_contiguous(a):
+ """
+ Find contiguous unmasked data in a masked array.
+
+ Parameters
+ ----------
+ a : array_like
+ The input array.
+
+ Returns
+ -------
+ slice_list : list
+ A sorted sequence of `slice` objects (start index, end index).
+
+ .. versionchanged:: 1.15.0
+ Now returns an empty list instead of None for a fully masked array
+
+ See Also
+ --------
+ flatnotmasked_edges, notmasked_contiguous, notmasked_edges
+ clump_masked, clump_unmasked
+
+ Notes
+ -----
+ Only accepts 2-D arrays at most.
+
+ Examples
+ --------
+ >>> a = np.ma.arange(10)
+ >>> np.ma.flatnotmasked_contiguous(a)
+ [slice(0, 10, None)]
+
+ >>> mask = (a < 3) | (a > 8) | (a == 5)
+ >>> a[mask] = np.ma.masked
+ >>> np.array(a[~a.mask])
+ array([3, 4, 6, 7, 8])
+
+ >>> np.ma.flatnotmasked_contiguous(a)
+ [slice(3, 5, None), slice(6, 9, None)]
+ >>> a[:] = np.ma.masked
+ >>> np.ma.flatnotmasked_contiguous(a)
+ []
+
+ """
+ m = getmask(a)
+ if m is nomask:
+ return [slice(0, a.size)]
+ i = 0
+ result = []
+ for (k, g) in itertools.groupby(m.ravel()):
+ n = len(list(g))
+ if not k:
+ result.append(slice(i, i + n))
+ i += n
+ return result
+
+
+def notmasked_contiguous(a, axis=None):
+ """
+ Find contiguous unmasked data in a masked array along the given axis.
+
+ Parameters
+ ----------
+ a : array_like
+ The input array.
+ axis : int, optional
+ Axis along which to perform the operation.
+ If None (default), applies to a flattened version of the array, and this
+ is the same as `flatnotmasked_contiguous`.
+
+ Returns
+ -------
+ endpoints : list
+ A list of slices (start and end indexes) of unmasked indexes
+ in the array.
+
+ If the input is 2d and axis is specified, the result is a list of lists.
+
+ See Also
+ --------
+ flatnotmasked_edges, flatnotmasked_contiguous, notmasked_edges
+ clump_masked, clump_unmasked
+
+ Notes
+ -----
+ Only accepts 2-D arrays at most.
+
+ Examples
+ --------
+ >>> a = np.arange(12).reshape((3, 4))
+ >>> mask = np.zeros_like(a)
+ >>> mask[1:, :-1] = 1; mask[0, 1] = 1; mask[-1, 0] = 0
+ >>> ma = np.ma.array(a, mask=mask)
+ >>> ma
+ masked_array(
+ data=[[0, --, 2, 3],
+ [--, --, --, 7],
+ [8, --, --, 11]],
+ mask=[[False, True, False, False],
+ [ True, True, True, False],
+ [False, True, True, False]],
+ fill_value=999999)
+ >>> np.array(ma[~ma.mask])
+ array([ 0, 2, 3, 7, 8, 11])
+
+ >>> np.ma.notmasked_contiguous(ma)
+ [slice(0, 1, None), slice(2, 4, None), slice(7, 9, None), slice(11, 12, None)]
+
+ >>> np.ma.notmasked_contiguous(ma, axis=0)
+ [[slice(0, 1, None), slice(2, 3, None)], [], [slice(0, 1, None)], [slice(0, 3, None)]]
+
+ >>> np.ma.notmasked_contiguous(ma, axis=1)
+ [[slice(0, 1, None), slice(2, 4, None)], [slice(3, 4, None)], [slice(0, 1, None), slice(3, 4, None)]]
+
+ """
+ a = asarray(a)
+ nd = a.ndim
+ if nd > 2:
+ raise NotImplementedError("Currently limited to at most 2D array.")
+ if axis is None or nd == 1:
+ return flatnotmasked_contiguous(a)
+ #
+ result = []
+ #
+ other = (axis + 1) % 2
+ idx = [0, 0]
+ idx[axis] = slice(None, None)
+ #
+ for i in range(a.shape[other]):
+ idx[other] = i
+ result.append(flatnotmasked_contiguous(a[tuple(idx)]))
+ return result
+
+
+def _ezclump(mask):
+ """
+ Finds the clumps (groups of data with the same values) for a 1D bool array.
+
+ Returns a series of slices.
+ """
+ if mask.ndim > 1:
+ mask = mask.ravel()
+ idx = (mask[1:] ^ mask[:-1]).nonzero()
+ idx = idx[0] + 1
+
+ if mask[0]:
+ if len(idx) == 0:
+ return [slice(0, mask.size)]
+
+ r = [slice(0, idx[0])]
+ r.extend((slice(left, right)
+ for left, right in zip(idx[1:-1:2], idx[2::2])))
+ else:
+ if len(idx) == 0:
+ return []
+
+ r = [slice(left, right) for left, right in zip(idx[:-1:2], idx[1::2])]
+
+ if mask[-1]:
+ r.append(slice(idx[-1], mask.size))
+ return r
+
+
+def clump_unmasked(a):
+ """
+ Return list of slices corresponding to the unmasked clumps of a 1-D array.
+ (A "clump" is defined as a contiguous region of the array).
+
+ Parameters
+ ----------
+ a : ndarray
+ A one-dimensional masked array.
+
+ Returns
+ -------
+ slices : list of slice
+ The list of slices, one for each continuous region of unmasked
+ elements in `a`.
+
+ Notes
+ -----
+ .. versionadded:: 1.4.0
+
+ See Also
+ --------
+ flatnotmasked_edges, flatnotmasked_contiguous, notmasked_edges
+ notmasked_contiguous, clump_masked
+
+ Examples
+ --------
+ >>> a = np.ma.masked_array(np.arange(10))
+ >>> a[[0, 1, 2, 6, 8, 9]] = np.ma.masked
+ >>> np.ma.clump_unmasked(a)
+ [slice(3, 6, None), slice(7, 8, None)]
+
+ """
+ mask = getattr(a, '_mask', nomask)
+ if mask is nomask:
+ return [slice(0, a.size)]
+ return _ezclump(~mask)
+
+
+def clump_masked(a):
+ """
+ Returns a list of slices corresponding to the masked clumps of a 1-D array.
+ (A "clump" is defined as a contiguous region of the array).
+
+ Parameters
+ ----------
+ a : ndarray
+ A one-dimensional masked array.
+
+ Returns
+ -------
+ slices : list of slice
+ The list of slices, one for each continuous region of masked elements
+ in `a`.
+
+ Notes
+ -----
+ .. versionadded:: 1.4.0
+
+ See Also
+ --------
+ flatnotmasked_edges, flatnotmasked_contiguous, notmasked_edges
+ notmasked_contiguous, clump_unmasked
+
+ Examples
+ --------
+ >>> a = np.ma.masked_array(np.arange(10))
+ >>> a[[0, 1, 2, 6, 8, 9]] = np.ma.masked
+ >>> np.ma.clump_masked(a)
+ [slice(0, 3, None), slice(6, 7, None), slice(8, 10, None)]
+
+ """
+ mask = ma.getmask(a)
+ if mask is nomask:
+ return []
+ return _ezclump(mask)
+
+
+###############################################################################
+# Polynomial fit #
+###############################################################################
+
+
+def vander(x, n=None):
+ """
+ Masked values in the input array result in rows of zeros.
+
+ """
+ _vander = np.vander(x, n)
+ m = getmask(x)
+ if m is not nomask:
+ _vander[m] = 0
+ return _vander
+
+vander.__doc__ = ma.doc_note(np.vander.__doc__, vander.__doc__)
+
+
+def polyfit(x, y, deg, rcond=None, full=False, w=None, cov=False):
+ """
+ Any masked values in x is propagated in y, and vice-versa.
+
+ """
+ x = asarray(x)
+ y = asarray(y)
+
+ m = getmask(x)
+ if y.ndim == 1:
+ m = mask_or(m, getmask(y))
+ elif y.ndim == 2:
+ my = getmask(mask_rows(y))
+ if my is not nomask:
+ m = mask_or(m, my[:, 0])
+ else:
+ raise TypeError("Expected a 1D or 2D array for y!")
+
+ if w is not None:
+ w = asarray(w)
+ if w.ndim != 1:
+ raise TypeError("expected a 1-d array for weights")
+ if w.shape[0] != y.shape[0]:
+ raise TypeError("expected w and y to have the same length")
+ m = mask_or(m, getmask(w))
+
+ if m is not nomask:
+ not_m = ~m
+ if w is not None:
+ w = w[not_m]
+ return np.polyfit(x[not_m], y[not_m], deg, rcond, full, w, cov)
+ else:
+ return np.polyfit(x, y, deg, rcond, full, w, cov)
+
+polyfit.__doc__ = ma.doc_note(np.polyfit.__doc__, polyfit.__doc__)
diff --git a/venv/lib/python3.9/site-packages/numpy/ma/extras.pyi b/venv/lib/python3.9/site-packages/numpy/ma/extras.pyi
new file mode 100644
index 00000000..56228b92
--- /dev/null
+++ b/venv/lib/python3.9/site-packages/numpy/ma/extras.pyi
@@ -0,0 +1,85 @@
+from typing import Any
+from numpy.lib.index_tricks import AxisConcatenator
+
+from numpy.ma.core import (
+ dot as dot,
+ mask_rowcols as mask_rowcols,
+)
+
+__all__: list[str]
+
+def count_masked(arr, axis=...): ...
+def masked_all(shape, dtype = ...): ...
+def masked_all_like(arr): ...
+
+class _fromnxfunction:
+ __name__: Any
+ __doc__: Any
+ def __init__(self, funcname): ...
+ def getdoc(self): ...
+ def __call__(self, *args, **params): ...
+
+class _fromnxfunction_single(_fromnxfunction):
+ def __call__(self, x, *args, **params): ...
+
+class _fromnxfunction_seq(_fromnxfunction):
+ def __call__(self, x, *args, **params): ...
+
+class _fromnxfunction_allargs(_fromnxfunction):
+ def __call__(self, *args, **params): ...
+
+atleast_1d: _fromnxfunction_allargs
+atleast_2d: _fromnxfunction_allargs
+atleast_3d: _fromnxfunction_allargs
+
+vstack: _fromnxfunction_seq
+row_stack: _fromnxfunction_seq
+hstack: _fromnxfunction_seq
+column_stack: _fromnxfunction_seq
+dstack: _fromnxfunction_seq
+stack: _fromnxfunction_seq
+
+hsplit: _fromnxfunction_single
+diagflat: _fromnxfunction_single
+
+def apply_along_axis(func1d, axis, arr, *args, **kwargs): ...
+def apply_over_axes(func, a, axes): ...
+def average(a, axis=..., weights=..., returned=..., keepdims=...): ...
+def median(a, axis=..., out=..., overwrite_input=..., keepdims=...): ...
+def compress_nd(x, axis=...): ...
+def compress_rowcols(x, axis=...): ...
+def compress_rows(a): ...
+def compress_cols(a): ...
+def mask_rows(a, axis = ...): ...
+def mask_cols(a, axis = ...): ...
+def ediff1d(arr, to_end=..., to_begin=...): ...
+def unique(ar1, return_index=..., return_inverse=...): ...
+def intersect1d(ar1, ar2, assume_unique=...): ...
+def setxor1d(ar1, ar2, assume_unique=...): ...
+def in1d(ar1, ar2, assume_unique=..., invert=...): ...
+def isin(element, test_elements, assume_unique=..., invert=...): ...
+def union1d(ar1, ar2): ...
+def setdiff1d(ar1, ar2, assume_unique=...): ...
+def cov(x, y=..., rowvar=..., bias=..., allow_masked=..., ddof=...): ...
+def corrcoef(x, y=..., rowvar=..., bias = ..., allow_masked=..., ddof = ...): ...
+
+class MAxisConcatenator(AxisConcatenator):
+ concatenate: Any
+ @classmethod
+ def makemat(cls, arr): ...
+ def __getitem__(self, key): ...
+
+class mr_class(MAxisConcatenator):
+ def __init__(self): ...
+
+mr_: mr_class
+
+def ndenumerate(a, compressed=...): ...
+def flatnotmasked_edges(a): ...
+def notmasked_edges(a, axis=...): ...
+def flatnotmasked_contiguous(a): ...
+def notmasked_contiguous(a, axis=...): ...
+def clump_unmasked(a): ...
+def clump_masked(a): ...
+def vander(x, n=...): ...
+def polyfit(x, y, deg, rcond=..., full=..., w=..., cov=...): ...
diff --git a/venv/lib/python3.9/site-packages/numpy/ma/mrecords.py b/venv/lib/python3.9/site-packages/numpy/ma/mrecords.py
new file mode 100644
index 00000000..1e8103bc
--- /dev/null
+++ b/venv/lib/python3.9/site-packages/numpy/ma/mrecords.py
@@ -0,0 +1,783 @@
+""":mod:`numpy.ma..mrecords`
+
+Defines the equivalent of :class:`numpy.recarrays` for masked arrays,
+where fields can be accessed as attributes.
+Note that :class:`numpy.ma.MaskedArray` already supports structured datatypes
+and the masking of individual fields.
+
+.. moduleauthor:: Pierre Gerard-Marchant
+
+"""
+# We should make sure that no field is called '_mask','mask','_fieldmask',
+# or whatever restricted keywords. An idea would be to no bother in the
+# first place, and then rename the invalid fields with a trailing
+# underscore. Maybe we could just overload the parser function ?
+
+from numpy.ma import (
+ MAError, MaskedArray, masked, nomask, masked_array, getdata,
+ getmaskarray, filled
+)
+import numpy.ma as ma
+import warnings
+
+import numpy as np
+from numpy import (
+ bool_, dtype, ndarray, recarray, array as narray
+)
+from numpy.core.records import (
+ fromarrays as recfromarrays, fromrecords as recfromrecords
+)
+
+_byteorderconv = np.core.records._byteorderconv
+
+
+_check_fill_value = ma.core._check_fill_value
+
+
+__all__ = [
+ 'MaskedRecords', 'mrecarray', 'fromarrays', 'fromrecords',
+ 'fromtextfile', 'addfield',
+]
+
+reserved_fields = ['_data', '_mask', '_fieldmask', 'dtype']
+
+
+def _checknames(descr, names=None):
+ """
+ Checks that field names ``descr`` are not reserved keywords.
+
+ If this is the case, a default 'f%i' is substituted. If the argument
+ `names` is not None, updates the field names to valid names.
+
+ """
+ ndescr = len(descr)
+ default_names = ['f%i' % i for i in range(ndescr)]
+ if names is None:
+ new_names = default_names
+ else:
+ if isinstance(names, (tuple, list)):
+ new_names = names
+ elif isinstance(names, str):
+ new_names = names.split(',')
+ else:
+ raise NameError(f'illegal input names {names!r}')
+ nnames = len(new_names)
+ if nnames < ndescr:
+ new_names += default_names[nnames:]
+ ndescr = []
+ for (n, d, t) in zip(new_names, default_names, descr.descr):
+ if n in reserved_fields:
+ if t[0] in reserved_fields:
+ ndescr.append((d, t[1]))
+ else:
+ ndescr.append(t)
+ else:
+ ndescr.append((n, t[1]))
+ return np.dtype(ndescr)
+
+
+def _get_fieldmask(self):
+ mdescr = [(n, '|b1') for n in self.dtype.names]
+ fdmask = np.empty(self.shape, dtype=mdescr)
+ fdmask.flat = tuple([False] * len(mdescr))
+ return fdmask
+
+
+class MaskedRecords(MaskedArray):
+ """
+
+ Attributes
+ ----------
+ _data : recarray
+ Underlying data, as a record array.
+ _mask : boolean array
+ Mask of the records. A record is masked when all its fields are
+ masked.
+ _fieldmask : boolean recarray
+ Record array of booleans, setting the mask of each individual field
+ of each record.
+ _fill_value : record
+ Filling values for each field.
+
+ """
+
+ def __new__(cls, shape, dtype=None, buf=None, offset=0, strides=None,
+ formats=None, names=None, titles=None,
+ byteorder=None, aligned=False,
+ mask=nomask, hard_mask=False, fill_value=None, keep_mask=True,
+ copy=False,
+ **options):
+
+ self = recarray.__new__(cls, shape, dtype=dtype, buf=buf, offset=offset,
+ strides=strides, formats=formats, names=names,
+ titles=titles, byteorder=byteorder,
+ aligned=aligned,)
+
+ mdtype = ma.make_mask_descr(self.dtype)
+ if mask is nomask or not np.size(mask):
+ if not keep_mask:
+ self._mask = tuple([False] * len(mdtype))
+ else:
+ mask = np.array(mask, copy=copy)
+ if mask.shape != self.shape:
+ (nd, nm) = (self.size, mask.size)
+ if nm == 1:
+ mask = np.resize(mask, self.shape)
+ elif nm == nd:
+ mask = np.reshape(mask, self.shape)
+ else:
+ msg = "Mask and data not compatible: data size is %i, " + \
+ "mask size is %i."
+ raise MAError(msg % (nd, nm))
+ if not keep_mask:
+ self.__setmask__(mask)
+ self._sharedmask = True
+ else:
+ if mask.dtype == mdtype:
+ _mask = mask
+ else:
+ _mask = np.array([tuple([m] * len(mdtype)) for m in mask],
+ dtype=mdtype)
+ self._mask = _mask
+ return self
+
+ def __array_finalize__(self, obj):
+ # Make sure we have a _fieldmask by default
+ _mask = getattr(obj, '_mask', None)
+ if _mask is None:
+ objmask = getattr(obj, '_mask', nomask)
+ _dtype = ndarray.__getattribute__(self, 'dtype')
+ if objmask is nomask:
+ _mask = ma.make_mask_none(self.shape, dtype=_dtype)
+ else:
+ mdescr = ma.make_mask_descr(_dtype)
+ _mask = narray([tuple([m] * len(mdescr)) for m in objmask],
+ dtype=mdescr).view(recarray)
+ # Update some of the attributes
+ _dict = self.__dict__
+ _dict.update(_mask=_mask)
+ self._update_from(obj)
+ if _dict['_baseclass'] == ndarray:
+ _dict['_baseclass'] = recarray
+ return
+
+ @property
+ def _data(self):
+ """
+ Returns the data as a recarray.
+
+ """
+ return ndarray.view(self, recarray)
+
+ @property
+ def _fieldmask(self):
+ """
+ Alias to mask.
+
+ """
+ return self._mask
+
+ def __len__(self):
+ """
+ Returns the length
+
+ """
+ # We have more than one record
+ if self.ndim:
+ return len(self._data)
+ # We have only one record: return the nb of fields
+ return len(self.dtype)
+
+ def __getattribute__(self, attr):
+ try:
+ return object.__getattribute__(self, attr)
+ except AttributeError:
+ # attr must be a fieldname
+ pass
+ fielddict = ndarray.__getattribute__(self, 'dtype').fields
+ try:
+ res = fielddict[attr][:2]
+ except (TypeError, KeyError) as e:
+ raise AttributeError(
+ f'record array has no attribute {attr}') from e
+ # So far, so good
+ _localdict = ndarray.__getattribute__(self, '__dict__')
+ _data = ndarray.view(self, _localdict['_baseclass'])
+ obj = _data.getfield(*res)
+ if obj.dtype.names is not None:
+ raise NotImplementedError("MaskedRecords is currently limited to"
+ "simple records.")
+ # Get some special attributes
+ # Reset the object's mask
+ hasmasked = False
+ _mask = _localdict.get('_mask', None)
+ if _mask is not None:
+ try:
+ _mask = _mask[attr]
+ except IndexError:
+ # Couldn't find a mask: use the default (nomask)
+ pass
+ tp_len = len(_mask.dtype)
+ hasmasked = _mask.view((bool, ((tp_len,) if tp_len else ()))).any()
+ if (obj.shape or hasmasked):
+ obj = obj.view(MaskedArray)
+ obj._baseclass = ndarray
+ obj._isfield = True
+ obj._mask = _mask
+ # Reset the field values
+ _fill_value = _localdict.get('_fill_value', None)
+ if _fill_value is not None:
+ try:
+ obj._fill_value = _fill_value[attr]
+ except ValueError:
+ obj._fill_value = None
+ else:
+ obj = obj.item()
+ return obj
+
+ def __setattr__(self, attr, val):
+ """
+ Sets the attribute attr to the value val.
+
+ """
+ # Should we call __setmask__ first ?
+ if attr in ['mask', 'fieldmask']:
+ self.__setmask__(val)
+ return
+ # Create a shortcut (so that we don't have to call getattr all the time)
+ _localdict = object.__getattribute__(self, '__dict__')
+ # Check whether we're creating a new field
+ newattr = attr not in _localdict
+ try:
+ # Is attr a generic attribute ?
+ ret = object.__setattr__(self, attr, val)
+ except Exception:
+ # Not a generic attribute: exit if it's not a valid field
+ fielddict = ndarray.__getattribute__(self, 'dtype').fields or {}
+ optinfo = ndarray.__getattribute__(self, '_optinfo') or {}
+ if not (attr in fielddict or attr in optinfo):
+ raise
+ else:
+ # Get the list of names
+ fielddict = ndarray.__getattribute__(self, 'dtype').fields or {}
+ # Check the attribute
+ if attr not in fielddict:
+ return ret
+ if newattr:
+ # We just added this one or this setattr worked on an
+ # internal attribute.
+ try:
+ object.__delattr__(self, attr)
+ except Exception:
+ return ret
+ # Let's try to set the field
+ try:
+ res = fielddict[attr][:2]
+ except (TypeError, KeyError) as e:
+ raise AttributeError(
+ f'record array has no attribute {attr}') from e
+
+ if val is masked:
+ _fill_value = _localdict['_fill_value']
+ if _fill_value is not None:
+ dval = _localdict['_fill_value'][attr]
+ else:
+ dval = val
+ mval = True
+ else:
+ dval = filled(val)
+ mval = getmaskarray(val)
+ obj = ndarray.__getattribute__(self, '_data').setfield(dval, *res)
+ _localdict['_mask'].__setitem__(attr, mval)
+ return obj
+
+ def __getitem__(self, indx):
+ """
+ Returns all the fields sharing the same fieldname base.
+
+ The fieldname base is either `_data` or `_mask`.
+
+ """
+ _localdict = self.__dict__
+ _mask = ndarray.__getattribute__(self, '_mask')
+ _data = ndarray.view(self, _localdict['_baseclass'])
+ # We want a field
+ if isinstance(indx, str):
+ # Make sure _sharedmask is True to propagate back to _fieldmask
+ # Don't use _set_mask, there are some copies being made that
+ # break propagation Don't force the mask to nomask, that wreaks
+ # easy masking
+ obj = _data[indx].view(MaskedArray)
+ obj._mask = _mask[indx]
+ obj._sharedmask = True
+ fval = _localdict['_fill_value']
+ if fval is not None:
+ obj._fill_value = fval[indx]
+ # Force to masked if the mask is True
+ if not obj.ndim and obj._mask:
+ return masked
+ return obj
+ # We want some elements.
+ # First, the data.
+ obj = np.array(_data[indx], copy=False).view(mrecarray)
+ obj._mask = np.array(_mask[indx], copy=False).view(recarray)
+ return obj
+
+ def __setitem__(self, indx, value):
+ """
+ Sets the given record to value.
+
+ """
+ MaskedArray.__setitem__(self, indx, value)
+ if isinstance(indx, str):
+ self._mask[indx] = ma.getmaskarray(value)
+
+ def __str__(self):
+ """
+ Calculates the string representation.
+
+ """
+ if self.size > 1:
+ mstr = [f"({','.join([str(i) for i in s])})"
+ for s in zip(*[getattr(self, f) for f in self.dtype.names])]
+ return f"[{', '.join(mstr)}]"
+ else:
+ mstr = [f"{','.join([str(i) for i in s])}"
+ for s in zip([getattr(self, f) for f in self.dtype.names])]
+ return f"({', '.join(mstr)})"
+
+ def __repr__(self):
+ """
+ Calculates the repr representation.
+
+ """
+ _names = self.dtype.names
+ fmt = "%%%is : %%s" % (max([len(n) for n in _names]) + 4,)
+ reprstr = [fmt % (f, getattr(self, f)) for f in self.dtype.names]
+ reprstr.insert(0, 'masked_records(')
+ reprstr.extend([fmt % (' fill_value', self.fill_value),
+ ' )'])
+ return str("\n".join(reprstr))
+
+ def view(self, dtype=None, type=None):
+ """
+ Returns a view of the mrecarray.
+
+ """
+ # OK, basic copy-paste from MaskedArray.view.
+ if dtype is None:
+ if type is None:
+ output = ndarray.view(self)
+ else:
+ output = ndarray.view(self, type)
+ # Here again.
+ elif type is None:
+ try:
+ if issubclass(dtype, ndarray):
+ output = ndarray.view(self, dtype)
+ else:
+ output = ndarray.view(self, dtype)
+ # OK, there's the change
+ except TypeError:
+ dtype = np.dtype(dtype)
+ # we need to revert to MaskedArray, but keeping the possibility
+ # of subclasses (eg, TimeSeriesRecords), so we'll force a type
+ # set to the first parent
+ if dtype.fields is None:
+ basetype = self.__class__.__bases__[0]
+ output = self.__array__().view(dtype, basetype)
+ output._update_from(self)
+ else:
+ output = ndarray.view(self, dtype)
+ output._fill_value = None
+ else:
+ output = ndarray.view(self, dtype, type)
+ # Update the mask, just like in MaskedArray.view
+ if (getattr(output, '_mask', nomask) is not nomask):
+ mdtype = ma.make_mask_descr(output.dtype)
+ output._mask = self._mask.view(mdtype, ndarray)
+ output._mask.shape = output.shape
+ return output
+
+ def harden_mask(self):
+ """
+ Forces the mask to hard.
+
+ """
+ self._hardmask = True
+
+ def soften_mask(self):
+ """
+ Forces the mask to soft
+
+ """
+ self._hardmask = False
+
+ def copy(self):
+ """
+ Returns a copy of the masked record.
+
+ """
+ copied = self._data.copy().view(type(self))
+ copied._mask = self._mask.copy()
+ return copied
+
+ def tolist(self, fill_value=None):
+ """
+ Return the data portion of the array as a list.
+
+ Data items are converted to the nearest compatible Python type.
+ Masked values are converted to fill_value. If fill_value is None,
+ the corresponding entries in the output list will be ``None``.
+
+ """
+ if fill_value is not None:
+ return self.filled(fill_value).tolist()
+ result = narray(self.filled().tolist(), dtype=object)
+ mask = narray(self._mask.tolist())
+ result[mask] = None
+ return result.tolist()
+
+ def __getstate__(self):
+ """Return the internal state of the masked array.
+
+ This is for pickling.
+
+ """
+ state = (1,
+ self.shape,
+ self.dtype,
+ self.flags.fnc,
+ self._data.tobytes(),
+ self._mask.tobytes(),
+ self._fill_value,
+ )
+ return state
+
+ def __setstate__(self, state):
+ """
+ Restore the internal state of the masked array.
+
+ This is for pickling. ``state`` is typically the output of the
+ ``__getstate__`` output, and is a 5-tuple:
+
+ - class name
+ - a tuple giving the shape of the data
+ - a typecode for the data
+ - a binary string for the data
+ - a binary string for the mask.
+
+ """
+ (ver, shp, typ, isf, raw, msk, flv) = state
+ ndarray.__setstate__(self, (shp, typ, isf, raw))
+ mdtype = dtype([(k, bool_) for (k, _) in self.dtype.descr])
+ self.__dict__['_mask'].__setstate__((shp, mdtype, isf, msk))
+ self.fill_value = flv
+
+ def __reduce__(self):
+ """
+ Return a 3-tuple for pickling a MaskedArray.
+
+ """
+ return (_mrreconstruct,
+ (self.__class__, self._baseclass, (0,), 'b',),
+ self.__getstate__())
+
+
+def _mrreconstruct(subtype, baseclass, baseshape, basetype,):
+ """
+ Build a new MaskedArray from the information stored in a pickle.
+
+ """
+ _data = ndarray.__new__(baseclass, baseshape, basetype).view(subtype)
+ _mask = ndarray.__new__(ndarray, baseshape, 'b1')
+ return subtype.__new__(subtype, _data, mask=_mask, dtype=basetype,)
+
+mrecarray = MaskedRecords
+
+
+###############################################################################
+# Constructors #
+###############################################################################
+
+
+def fromarrays(arraylist, dtype=None, shape=None, formats=None,
+ names=None, titles=None, aligned=False, byteorder=None,
+ fill_value=None):
+ """
+ Creates a mrecarray from a (flat) list of masked arrays.
+
+ Parameters
+ ----------
+ arraylist : sequence
+ A list of (masked) arrays. Each element of the sequence is first converted
+ to a masked array if needed. If a 2D array is passed as argument, it is
+ processed line by line
+ dtype : {None, dtype}, optional
+ Data type descriptor.
+ shape : {None, integer}, optional
+ Number of records. If None, shape is defined from the shape of the
+ first array in the list.
+ formats : {None, sequence}, optional
+ Sequence of formats for each individual field. If None, the formats will
+ be autodetected by inspecting the fields and selecting the highest dtype
+ possible.
+ names : {None, sequence}, optional
+ Sequence of the names of each field.
+ fill_value : {None, sequence}, optional
+ Sequence of data to be used as filling values.
+
+ Notes
+ -----
+ Lists of tuples should be preferred over lists of lists for faster processing.
+
+ """
+ datalist = [getdata(x) for x in arraylist]
+ masklist = [np.atleast_1d(getmaskarray(x)) for x in arraylist]
+ _array = recfromarrays(datalist,
+ dtype=dtype, shape=shape, formats=formats,
+ names=names, titles=titles, aligned=aligned,
+ byteorder=byteorder).view(mrecarray)
+ _array._mask.flat = list(zip(*masklist))
+ if fill_value is not None:
+ _array.fill_value = fill_value
+ return _array
+
+
+def fromrecords(reclist, dtype=None, shape=None, formats=None, names=None,
+ titles=None, aligned=False, byteorder=None,
+ fill_value=None, mask=nomask):
+ """
+ Creates a MaskedRecords from a list of records.
+
+ Parameters
+ ----------
+ reclist : sequence
+ A list of records. Each element of the sequence is first converted
+ to a masked array if needed. If a 2D array is passed as argument, it is
+ processed line by line
+ dtype : {None, dtype}, optional
+ Data type descriptor.
+ shape : {None,int}, optional
+ Number of records. If None, ``shape`` is defined from the shape of the
+ first array in the list.
+ formats : {None, sequence}, optional
+ Sequence of formats for each individual field. If None, the formats will
+ be autodetected by inspecting the fields and selecting the highest dtype
+ possible.
+ names : {None, sequence}, optional
+ Sequence of the names of each field.
+ fill_value : {None, sequence}, optional
+ Sequence of data to be used as filling values.
+ mask : {nomask, sequence}, optional.
+ External mask to apply on the data.
+
+ Notes
+ -----
+ Lists of tuples should be preferred over lists of lists for faster processing.
+
+ """
+ # Grab the initial _fieldmask, if needed:
+ _mask = getattr(reclist, '_mask', None)
+ # Get the list of records.
+ if isinstance(reclist, ndarray):
+ # Make sure we don't have some hidden mask
+ if isinstance(reclist, MaskedArray):
+ reclist = reclist.filled().view(ndarray)
+ # Grab the initial dtype, just in case
+ if dtype is None:
+ dtype = reclist.dtype
+ reclist = reclist.tolist()
+ mrec = recfromrecords(reclist, dtype=dtype, shape=shape, formats=formats,
+ names=names, titles=titles,
+ aligned=aligned, byteorder=byteorder).view(mrecarray)
+ # Set the fill_value if needed
+ if fill_value is not None:
+ mrec.fill_value = fill_value
+ # Now, let's deal w/ the mask
+ if mask is not nomask:
+ mask = np.array(mask, copy=False)
+ maskrecordlength = len(mask.dtype)
+ if maskrecordlength:
+ mrec._mask.flat = mask
+ elif mask.ndim == 2:
+ mrec._mask.flat = [tuple(m) for m in mask]
+ else:
+ mrec.__setmask__(mask)
+ if _mask is not None:
+ mrec._mask[:] = _mask
+ return mrec
+
+
+def _guessvartypes(arr):
+ """
+ Tries to guess the dtypes of the str_ ndarray `arr`.
+
+ Guesses by testing element-wise conversion. Returns a list of dtypes.
+ The array is first converted to ndarray. If the array is 2D, the test
+ is performed on the first line. An exception is raised if the file is
+ 3D or more.
+
+ """
+ vartypes = []
+ arr = np.asarray(arr)
+ if arr.ndim == 2:
+ arr = arr[0]
+ elif arr.ndim > 2:
+ raise ValueError("The array should be 2D at most!")
+ # Start the conversion loop.
+ for f in arr:
+ try:
+ int(f)
+ except (ValueError, TypeError):
+ try:
+ float(f)
+ except (ValueError, TypeError):
+ try:
+ complex(f)
+ except (ValueError, TypeError):
+ vartypes.append(arr.dtype)
+ else:
+ vartypes.append(np.dtype(complex))
+ else:
+ vartypes.append(np.dtype(float))
+ else:
+ vartypes.append(np.dtype(int))
+ return vartypes
+
+
+def openfile(fname):
+ """
+ Opens the file handle of file `fname`.
+
+ """
+ # A file handle
+ if hasattr(fname, 'readline'):
+ return fname
+ # Try to open the file and guess its type
+ try:
+ f = open(fname)
+ except FileNotFoundError as e:
+ raise FileNotFoundError(f"No such file: '{fname}'") from e
+ if f.readline()[:2] != "\\x":
+ f.seek(0, 0)
+ return f
+ f.close()
+ raise NotImplementedError("Wow, binary file")
+
+
+def fromtextfile(fname, delimiter=None, commentchar='#', missingchar='',
+ varnames=None, vartypes=None,
+ *, delimitor=np._NoValue): # backwards compatibility
+ """
+ Creates a mrecarray from data stored in the file `filename`.
+
+ Parameters
+ ----------
+ fname : {file name/handle}
+ Handle of an opened file.
+ delimiter : {None, string}, optional
+ Alphanumeric character used to separate columns in the file.
+ If None, any (group of) white spacestring(s) will be used.
+ commentchar : {'#', string}, optional
+ Alphanumeric character used to mark the start of a comment.
+ missingchar : {'', string}, optional
+ String indicating missing data, and used to create the masks.
+ varnames : {None, sequence}, optional
+ Sequence of the variable names. If None, a list will be created from
+ the first non empty line of the file.
+ vartypes : {None, sequence}, optional
+ Sequence of the variables dtypes. If None, it will be estimated from
+ the first non-commented line.
+
+
+ Ultra simple: the varnames are in the header, one line"""
+ if delimitor is not np._NoValue:
+ if delimiter is not None:
+ raise TypeError("fromtextfile() got multiple values for argument "
+ "'delimiter'")
+ # NumPy 1.22.0, 2021-09-23
+ warnings.warn("The 'delimitor' keyword argument of "
+ "numpy.ma.mrecords.fromtextfile() is deprecated "
+ "since NumPy 1.22.0, use 'delimiter' instead.",
+ DeprecationWarning, stacklevel=2)
+ delimiter = delimitor
+
+ # Try to open the file.
+ ftext = openfile(fname)
+
+ # Get the first non-empty line as the varnames
+ while True:
+ line = ftext.readline()
+ firstline = line[:line.find(commentchar)].strip()
+ _varnames = firstline.split(delimiter)
+ if len(_varnames) > 1:
+ break
+ if varnames is None:
+ varnames = _varnames
+
+ # Get the data.
+ _variables = masked_array([line.strip().split(delimiter) for line in ftext
+ if line[0] != commentchar and len(line) > 1])
+ (_, nfields) = _variables.shape
+ ftext.close()
+
+ # Try to guess the dtype.
+ if vartypes is None:
+ vartypes = _guessvartypes(_variables[0])
+ else:
+ vartypes = [np.dtype(v) for v in vartypes]
+ if len(vartypes) != nfields:
+ msg = "Attempting to %i dtypes for %i fields!"
+ msg += " Reverting to default."
+ warnings.warn(msg % (len(vartypes), nfields), stacklevel=2)
+ vartypes = _guessvartypes(_variables[0])
+
+ # Construct the descriptor.
+ mdescr = [(n, f) for (n, f) in zip(varnames, vartypes)]
+ mfillv = [ma.default_fill_value(f) for f in vartypes]
+
+ # Get the data and the mask.
+ # We just need a list of masked_arrays. It's easier to create it like that:
+ _mask = (_variables.T == missingchar)
+ _datalist = [masked_array(a, mask=m, dtype=t, fill_value=f)
+ for (a, m, t, f) in zip(_variables.T, _mask, vartypes, mfillv)]
+
+ return fromarrays(_datalist, dtype=mdescr)
+
+
+def addfield(mrecord, newfield, newfieldname=None):
+ """Adds a new field to the masked record array
+
+ Uses `newfield` as data and `newfieldname` as name. If `newfieldname`
+ is None, the new field name is set to 'fi', where `i` is the number of
+ existing fields.
+
+ """
+ _data = mrecord._data
+ _mask = mrecord._mask
+ if newfieldname is None or newfieldname in reserved_fields:
+ newfieldname = 'f%i' % len(_data.dtype)
+ newfield = ma.array(newfield)
+ # Get the new data.
+ # Create a new empty recarray
+ newdtype = np.dtype(_data.dtype.descr + [(newfieldname, newfield.dtype)])
+ newdata = recarray(_data.shape, newdtype)
+ # Add the existing field
+ [newdata.setfield(_data.getfield(*f), *f)
+ for f in _data.dtype.fields.values()]
+ # Add the new field
+ newdata.setfield(newfield._data, *newdata.dtype.fields[newfieldname])
+ newdata = newdata.view(MaskedRecords)
+ # Get the new mask
+ # Create a new empty recarray
+ newmdtype = np.dtype([(n, bool_) for n in newdtype.names])
+ newmask = recarray(_data.shape, newmdtype)
+ # Add the old masks
+ [newmask.setfield(_mask.getfield(*f), *f)
+ for f in _mask.dtype.fields.values()]
+ # Add the mask of the new field
+ newmask.setfield(getmaskarray(newfield),
+ *newmask.dtype.fields[newfieldname])
+ newdata._mask = newmask
+ return newdata
diff --git a/venv/lib/python3.9/site-packages/numpy/ma/mrecords.pyi b/venv/lib/python3.9/site-packages/numpy/ma/mrecords.pyi
new file mode 100644
index 00000000..264807e0
--- /dev/null
+++ b/venv/lib/python3.9/site-packages/numpy/ma/mrecords.pyi
@@ -0,0 +1,90 @@
+from typing import Any, TypeVar
+
+from numpy import dtype
+from numpy.ma import MaskedArray
+
+__all__: list[str]
+
+# TODO: Set the `bound` to something more suitable once we
+# have proper shape support
+_ShapeType = TypeVar("_ShapeType", bound=Any)
+_DType_co = TypeVar("_DType_co", bound=dtype[Any], covariant=True)
+
+class MaskedRecords(MaskedArray[_ShapeType, _DType_co]):
+ def __new__(
+ cls,
+ shape,
+ dtype=...,
+ buf=...,
+ offset=...,
+ strides=...,
+ formats=...,
+ names=...,
+ titles=...,
+ byteorder=...,
+ aligned=...,
+ mask=...,
+ hard_mask=...,
+ fill_value=...,
+ keep_mask=...,
+ copy=...,
+ **options,
+ ): ...
+ _mask: Any
+ _fill_value: Any
+ @property
+ def _data(self): ...
+ @property
+ def _fieldmask(self): ...
+ def __array_finalize__(self, obj): ...
+ def __len__(self): ...
+ def __getattribute__(self, attr): ...
+ def __setattr__(self, attr, val): ...
+ def __getitem__(self, indx): ...
+ def __setitem__(self, indx, value): ...
+ def view(self, dtype=..., type=...): ...
+ def harden_mask(self): ...
+ def soften_mask(self): ...
+ def copy(self): ...
+ def tolist(self, fill_value=...): ...
+ def __reduce__(self): ...
+
+mrecarray = MaskedRecords
+
+def fromarrays(
+ arraylist,
+ dtype=...,
+ shape=...,
+ formats=...,
+ names=...,
+ titles=...,
+ aligned=...,
+ byteorder=...,
+ fill_value=...,
+): ...
+
+def fromrecords(
+ reclist,
+ dtype=...,
+ shape=...,
+ formats=...,
+ names=...,
+ titles=...,
+ aligned=...,
+ byteorder=...,
+ fill_value=...,
+ mask=...,
+): ...
+
+def fromtextfile(
+ fname,
+ delimiter=...,
+ commentchar=...,
+ missingchar=...,
+ varnames=...,
+ vartypes=...,
+ # NOTE: deprecated: NumPy 1.22.0, 2021-09-23
+ # delimitor=...,
+): ...
+
+def addfield(mrecord, newfield, newfieldname=...): ...
diff --git a/venv/lib/python3.9/site-packages/numpy/ma/setup.py b/venv/lib/python3.9/site-packages/numpy/ma/setup.py
new file mode 100644
index 00000000..018d38cd
--- /dev/null
+++ b/venv/lib/python3.9/site-packages/numpy/ma/setup.py
@@ -0,0 +1,12 @@
+#!/usr/bin/env python3
+def configuration(parent_package='',top_path=None):
+ from numpy.distutils.misc_util import Configuration
+ config = Configuration('ma', parent_package, top_path)
+ config.add_subpackage('tests')
+ config.add_data_files('*.pyi')
+ return config
+
+if __name__ == "__main__":
+ from numpy.distutils.core import setup
+ config = configuration(top_path='').todict()
+ setup(**config)
diff --git a/venv/lib/python3.9/site-packages/numpy/ma/tests/__init__.py b/venv/lib/python3.9/site-packages/numpy/ma/tests/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/venv/lib/python3.9/site-packages/numpy/ma/tests/__init__.py
diff --git a/venv/lib/python3.9/site-packages/numpy/ma/tests/test_core.py b/venv/lib/python3.9/site-packages/numpy/ma/tests/test_core.py
new file mode 100644
index 00000000..6c03e0ba
--- /dev/null
+++ b/venv/lib/python3.9/site-packages/numpy/ma/tests/test_core.py
@@ -0,0 +1,5564 @@
+# pylint: disable-msg=W0400,W0511,W0611,W0612,W0614,R0201,E1102
+"""Tests suite for MaskedArray & subclassing.
+
+:author: Pierre Gerard-Marchant
+:contact: pierregm_at_uga_dot_edu
+"""
+__author__ = "Pierre GF Gerard-Marchant"
+
+import sys
+import warnings
+import operator
+import itertools
+import textwrap
+import pytest
+
+from functools import reduce
+
+
+import numpy as np
+import numpy.ma.core
+import numpy.core.fromnumeric as fromnumeric
+import numpy.core.umath as umath
+from numpy.testing import (
+ assert_raises, assert_warns, suppress_warnings, IS_WASM
+ )
+from numpy.testing._private.utils import requires_memory
+from numpy import ndarray
+from numpy.compat import asbytes
+from numpy.ma.testutils import (
+ assert_, assert_array_equal, assert_equal, assert_almost_equal,
+ assert_equal_records, fail_if_equal, assert_not_equal,
+ assert_mask_equal
+ )
+from numpy.ma.core import (
+ MAError, MaskError, MaskType, MaskedArray, abs, absolute, add, all,
+ allclose, allequal, alltrue, angle, anom, arange, arccos, arccosh, arctan2,
+ arcsin, arctan, argsort, array, asarray, choose, concatenate,
+ conjugate, cos, cosh, count, default_fill_value, diag, divide, doc_note,
+ empty, empty_like, equal, exp, flatten_mask, filled, fix_invalid,
+ flatten_structured_array, fromflex, getmask, getmaskarray, greater,
+ greater_equal, identity, inner, isMaskedArray, less, less_equal, log,
+ log10, make_mask, make_mask_descr, mask_or, masked, masked_array,
+ masked_equal, masked_greater, masked_greater_equal, masked_inside,
+ masked_less, masked_less_equal, masked_not_equal, masked_outside,
+ masked_print_option, masked_values, masked_where, max, maximum,
+ maximum_fill_value, min, minimum, minimum_fill_value, mod, multiply,
+ mvoid, nomask, not_equal, ones, ones_like, outer, power, product, put,
+ putmask, ravel, repeat, reshape, resize, shape, sin, sinh, sometrue, sort,
+ sqrt, subtract, sum, take, tan, tanh, transpose, where, zeros, zeros_like,
+ )
+from numpy.compat import pickle
+
+pi = np.pi
+
+
+suppress_copy_mask_on_assignment = suppress_warnings()
+suppress_copy_mask_on_assignment.filter(
+ numpy.ma.core.MaskedArrayFutureWarning,
+ "setting an item on a masked array which has a shared mask will not copy")
+
+
+# For parametrized numeric testing
+num_dts = [np.dtype(dt_) for dt_ in '?bhilqBHILQefdgFD']
+num_ids = [dt_.char for dt_ in num_dts]
+
+
+class TestMaskedArray:
+ # Base test class for MaskedArrays.
+
+ def setup_method(self):
+ # Base data definition.
+ x = np.array([1., 1., 1., -2., pi/2.0, 4., 5., -10., 10., 1., 2., 3.])
+ y = np.array([5., 0., 3., 2., -1., -4., 0., -10., 10., 1., 0., 3.])
+ a10 = 10.
+ m1 = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
+ m2 = [0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1]
+ xm = masked_array(x, mask=m1)
+ ym = masked_array(y, mask=m2)
+ z = np.array([-.5, 0., .5, .8])
+ zm = masked_array(z, mask=[0, 1, 0, 0])
+ xf = np.where(m1, 1e+20, x)
+ xm.set_fill_value(1e+20)
+ self.d = (x, y, a10, m1, m2, xm, ym, z, zm, xf)
+
+ def test_basicattributes(self):
+ # Tests some basic array attributes.
+ a = array([1, 3, 2])
+ b = array([1, 3, 2], mask=[1, 0, 1])
+ assert_equal(a.ndim, 1)
+ assert_equal(b.ndim, 1)
+ assert_equal(a.size, 3)
+ assert_equal(b.size, 3)
+ assert_equal(a.shape, (3,))
+ assert_equal(b.shape, (3,))
+
+ def test_basic0d(self):
+ # Checks masking a scalar
+ x = masked_array(0)
+ assert_equal(str(x), '0')
+ x = masked_array(0, mask=True)
+ assert_equal(str(x), str(masked_print_option))
+ x = masked_array(0, mask=False)
+ assert_equal(str(x), '0')
+ x = array(0, mask=1)
+ assert_(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
+ assert_(not isMaskedArray(x))
+ assert_(isMaskedArray(xm))
+ assert_((xm - ym).filled(0).any())
+ fail_if_equal(xm.mask.astype(int), ym.mask.astype(int))
+ s = x.shape
+ assert_equal(np.shape(xm), s)
+ assert_equal(xm.shape, s)
+ assert_equal(xm.dtype, x.dtype)
+ assert_equal(zm.dtype, z.dtype)
+ assert_equal(xm.size, reduce(lambda x, y:x * y, s))
+ assert_equal(count(xm), len(m1) - reduce(lambda x, y:x + y, m1))
+ assert_array_equal(xm, xf)
+ assert_array_equal(filled(xm, 1.e20), xf)
+ assert_array_equal(x, xm)
+
+ def test_basic2d(self):
+ # Test of basic array creation and properties in 2 dimensions.
+ (x, y, a10, m1, m2, xm, ym, z, zm, xf) = self.d
+ for s in [(4, 3), (6, 2)]:
+ x.shape = s
+ y.shape = s
+ xm.shape = s
+ ym.shape = s
+ xf.shape = s
+
+ assert_(not isMaskedArray(x))
+ assert_(isMaskedArray(xm))
+ assert_equal(shape(xm), s)
+ assert_equal(xm.shape, s)
+ assert_equal(xm.size, reduce(lambda x, y:x * y, s))
+ assert_equal(count(xm), len(m1) - reduce(lambda x, y:x + y, m1))
+ assert_equal(xm, xf)
+ assert_equal(filled(xm, 1.e20), xf)
+ assert_equal(x, xm)
+
+ def test_concatenate_basic(self):
+ # Tests concatenations.
+ (x, y, a10, m1, m2, xm, ym, z, zm, xf) = self.d
+ # basic concatenation
+ assert_equal(np.concatenate((x, y)), concatenate((xm, ym)))
+ assert_equal(np.concatenate((x, y)), concatenate((x, y)))
+ assert_equal(np.concatenate((x, y)), concatenate((xm, y)))
+ assert_equal(np.concatenate((x, y, x)), concatenate((x, ym, x)))
+
+ def test_concatenate_alongaxis(self):
+ # Tests concatenations.
+ (x, y, a10, m1, m2, xm, ym, z, zm, xf) = self.d
+ # Concatenation along an axis
+ s = (3, 4)
+ x.shape = y.shape = xm.shape = ym.shape = s
+ assert_equal(xm.mask, np.reshape(m1, s))
+ assert_equal(ym.mask, np.reshape(m2, s))
+ xmym = concatenate((xm, ym), 1)
+ assert_equal(np.concatenate((x, y), 1), xmym)
+ assert_equal(np.concatenate((xm.mask, ym.mask), 1), xmym._mask)
+
+ x = zeros(2)
+ y = array(ones(2), mask=[False, True])
+ z = concatenate((x, y))
+ assert_array_equal(z, [0, 0, 1, 1])
+ assert_array_equal(z.mask, [False, False, False, True])
+ z = concatenate((y, x))
+ assert_array_equal(z, [1, 1, 0, 0])
+ assert_array_equal(z.mask, [False, True, False, False])
+
+ def test_concatenate_flexible(self):
+ # Tests the concatenation on flexible arrays.
+ data = masked_array(list(zip(np.random.rand(10),
+ np.arange(10))),
+ dtype=[('a', float), ('b', int)])
+
+ test = concatenate([data[:5], data[5:]])
+ assert_equal_records(test, data)
+
+ def test_creation_ndmin(self):
+ # Check the use of 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]])
+
+ def test_creation_ndmin_from_maskedarray(self):
+ # Make sure we're not losing the original mask w/ ndmin
+ x = array([1, 2, 3])
+ x[-1] = masked
+ xx = array(x, ndmin=2, dtype=float)
+ assert_equal(x.shape, x._mask.shape)
+ assert_equal(xx.shape, xx._mask.shape)
+
+ def test_creation_maskcreation(self):
+ # Tests how masks are initialized at the creation of Maskedarrays.
+ data = arange(24, dtype=float)
+ data[[3, 6, 15]] = masked
+ dma_1 = MaskedArray(data)
+ assert_equal(dma_1.mask, data.mask)
+ dma_2 = MaskedArray(dma_1)
+ assert_equal(dma_2.mask, dma_1.mask)
+ dma_3 = MaskedArray(dma_1, mask=[1, 0, 0, 0] * 6)
+ fail_if_equal(dma_3.mask, dma_1.mask)
+
+ x = array([1, 2, 3], mask=True)
+ assert_equal(x._mask, [True, True, True])
+ x = array([1, 2, 3], mask=False)
+ assert_equal(x._mask, [False, False, False])
+ y = array([1, 2, 3], mask=x._mask, copy=False)
+ assert_(np.may_share_memory(x.mask, y.mask))
+ y = array([1, 2, 3], mask=x._mask, copy=True)
+ assert_(not np.may_share_memory(x.mask, y.mask))
+
+ def test_masked_singleton_array_creation_warns(self):
+ # The first works, but should not (ideally), there may be no way
+ # to solve this, however, as long as `np.ma.masked` is an ndarray.
+ np.array(np.ma.masked)
+ with pytest.warns(UserWarning):
+ # Tries to create a float array, using `float(np.ma.masked)`.
+ # We may want to define this is invalid behaviour in the future!
+ # (requiring np.ma.masked to be a known NumPy scalar probably
+ # with a DType.)
+ np.array([3., np.ma.masked])
+
+ def test_creation_with_list_of_maskedarrays(self):
+ # Tests creating a masked array from a list of masked arrays.
+ x = array(np.arange(5), mask=[1, 0, 0, 0, 0])
+ data = array((x, x[::-1]))
+ assert_equal(data, [[0, 1, 2, 3, 4], [4, 3, 2, 1, 0]])
+ assert_equal(data._mask, [[1, 0, 0, 0, 0], [0, 0, 0, 0, 1]])
+
+ x.mask = nomask
+ data = array((x, x[::-1]))
+ assert_equal(data, [[0, 1, 2, 3, 4], [4, 3, 2, 1, 0]])
+ assert_(data.mask is nomask)
+
+ def test_creation_with_list_of_maskedarrays_no_bool_cast(self):
+ # Tests the regression in gh-18551
+ masked_str = np.ma.masked_array(['a', 'b'], mask=[True, False])
+ normal_int = np.arange(2)
+ res = np.ma.asarray([masked_str, normal_int], dtype="U21")
+ assert_array_equal(res.mask, [[True, False], [False, False]])
+
+ # The above only failed due a long chain of oddity, try also with
+ # an object array that cannot be converted to bool always:
+ class NotBool():
+ def __bool__(self):
+ raise ValueError("not a bool!")
+ masked_obj = np.ma.masked_array([NotBool(), 'b'], mask=[True, False])
+ # Check that the NotBool actually fails like we would expect:
+ with pytest.raises(ValueError, match="not a bool!"):
+ np.asarray([masked_obj], dtype=bool)
+
+ res = np.ma.asarray([masked_obj, normal_int])
+ assert_array_equal(res.mask, [[True, False], [False, False]])
+
+ def test_creation_from_ndarray_with_padding(self):
+ x = np.array([('A', 0)], dtype={'names':['f0','f1'],
+ 'formats':['S4','i8'],
+ 'offsets':[0,8]})
+ array(x) # used to fail due to 'V' padding field in x.dtype.descr
+
+ def test_unknown_keyword_parameter(self):
+ with pytest.raises(TypeError, match="unexpected keyword argument"):
+ MaskedArray([1, 2, 3], maks=[0, 1, 0]) # `mask` is misspelled.
+
+ def test_asarray(self):
+ (x, y, a10, m1, m2, xm, ym, z, zm, xf) = self.d
+ xm.fill_value = -9999
+ xm._hardmask = True
+ xmm = asarray(xm)
+ assert_equal(xmm._data, xm._data)
+ assert_equal(xmm._mask, xm._mask)
+ assert_equal(xmm.fill_value, xm.fill_value)
+ assert_equal(xmm._hardmask, xm._hardmask)
+
+ def test_asarray_default_order(self):
+ # See Issue #6646
+ m = np.eye(3).T
+ assert_(not m.flags.c_contiguous)
+
+ new_m = asarray(m)
+ assert_(new_m.flags.c_contiguous)
+
+ def test_asarray_enforce_order(self):
+ # See Issue #6646
+ m = np.eye(3).T
+ assert_(not m.flags.c_contiguous)
+
+ new_m = asarray(m, order='C')
+ assert_(new_m.flags.c_contiguous)
+
+ def test_fix_invalid(self):
+ # Checks fix_invalid.
+ 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.])
+ assert_equal(data_fixed._mask, [1., 0., 1.])
+
+ def test_maskedelement(self):
+ # Test of masked element
+ x = arange(6)
+ x[1] = masked
+ assert_(str(masked) == '--')
+ assert_(x[1] is masked)
+ assert_equal(filled(x[1], 0), 0)
+
+ def test_set_element_as_object(self):
+ # Tests setting elements with object
+ a = empty(1, dtype=object)
+ x = (1, 2, 3, 4, 5)
+ a[0] = x
+ assert_equal(a[0], x)
+ assert_(a[0] is x)
+
+ import datetime
+ dt = datetime.datetime.now()
+ a[0] = dt
+ assert_(a[0] is dt)
+
+ def test_indexing(self):
+ # Tests conversions and indexing
+ x1 = np.array([1, 2, 4, 3])
+ x2 = array(x1, mask=[1, 0, 0, 0])
+ x3 = array(x1, mask=[0, 1, 0, 1])
+ x4 = array(x1)
+ # test conversion to strings
+ str(x2) # raises?
+ repr(x2) # raises?
+ assert_equal(np.sort(x1), sort(x2, endwith=False))
+ # tests of indexing
+ assert_(type(x2[1]) is type(x1[1]))
+ assert_(x1[1] == x2[1])
+ assert_(x2[0] is masked)
+ assert_equal(x1[2], x2[2])
+ assert_equal(x1[2:5], x2[2:5])
+ assert_equal(x1[:], x2[:])
+ assert_equal(x1[1:], x3[1:])
+ x1[2] = 9
+ x2[2] = 9
+ assert_equal(x1, x2)
+ x1[1:3] = 99
+ x2[1:3] = 99
+ assert_equal(x1, x2)
+ x2[1] = masked
+ assert_equal(x1, x2)
+ x2[1:3] = masked
+ assert_equal(x1, x2)
+ x2[:] = x1
+ x2[1] = masked
+ assert_(allequal(getmask(x2), array([0, 1, 0, 0])))
+ x3[:] = masked_array([1, 2, 3, 4], [0, 1, 1, 0])
+ assert_(allequal(getmask(x3), array([0, 1, 1, 0])))
+ x4[:] = masked_array([1, 2, 3, 4], [0, 1, 1, 0])
+ assert_(allequal(getmask(x4), array([0, 1, 1, 0])))
+ assert_(allequal(x4, array([1, 2, 3, 4])))
+ x1 = np.arange(5) * 1.0
+ x2 = masked_values(x1, 3.0)
+ assert_equal(x1, x2)
+ assert_(allequal(array([0, 0, 0, 1, 0], MaskType), x2.mask))
+ assert_equal(3.0, x2.fill_value)
+ x1 = array([1, 'hello', 2, 3], object)
+ x2 = np.array([1, 'hello', 2, 3], object)
+ s1 = x1[1]
+ s2 = x2[1]
+ assert_equal(type(s2), str)
+ assert_equal(type(s1), str)
+ assert_equal(s1, s2)
+ assert_(x1[1:1].shape == (0,))
+
+ def test_setitem_no_warning(self):
+ # Setitem shouldn't warn, because the assignment might be masked
+ # and warning for a masked assignment is weird (see gh-23000)
+ # (When the value is masked, otherwise a warning would be acceptable
+ # but is not given currently.)
+ x = np.ma.arange(60).reshape((6, 10))
+ index = (slice(1, 5, 2), [7, 5])
+ value = np.ma.masked_all((2, 2))
+ value._data[...] = np.inf # not a valid integer...
+ x[index] = value
+ # The masked scalar is special cased, but test anyway (it's NaN):
+ x[...] = np.ma.masked
+ # Finally, a large value that cannot be cast to the float32 `x`
+ x = np.ma.arange(3., dtype=np.float32)
+ value = np.ma.array([2e234, 1, 1], mask=[True, False, False])
+ x[...] = value
+ x[[0, 1, 2]] = value
+
+ @suppress_copy_mask_on_assignment
+ def test_copy(self):
+ # Tests of some subtle points of copying and sizing.
+ n = [0, 0, 1, 0, 0]
+ m = make_mask(n)
+ m2 = make_mask(m)
+ assert_(m is m2)
+ m3 = make_mask(m, copy=True)
+ assert_(m is not m3)
+
+ x1 = np.arange(5)
+ y1 = array(x1, mask=m)
+ assert_equal(y1._data.__array_interface__, x1.__array_interface__)
+ assert_(allequal(x1, y1.data))
+ assert_equal(y1._mask.__array_interface__, m.__array_interface__)
+
+ y1a = array(y1)
+ # Default for masked array is not to copy; see gh-10318.
+ assert_(y1a._data.__array_interface__ ==
+ y1._data.__array_interface__)
+ assert_(y1a._mask.__array_interface__ ==
+ y1._mask.__array_interface__)
+
+ y2 = array(x1, mask=m3)
+ assert_(y2._data.__array_interface__ == x1.__array_interface__)
+ assert_(y2._mask.__array_interface__ == m3.__array_interface__)
+ assert_(y2[2] is masked)
+ y2[2] = 9
+ assert_(y2[2] is not masked)
+ assert_(y2._mask.__array_interface__ == m3.__array_interface__)
+ assert_(allequal(y2.mask, 0))
+
+ y2a = array(x1, mask=m, copy=1)
+ assert_(y2a._data.__array_interface__ != x1.__array_interface__)
+ #assert_( y2a._mask is not m)
+ assert_(y2a._mask.__array_interface__ != m.__array_interface__)
+ assert_(y2a[2] is masked)
+ y2a[2] = 9
+ assert_(y2a[2] is not masked)
+ #assert_( y2a._mask is not m)
+ assert_(y2a._mask.__array_interface__ != m.__array_interface__)
+ assert_(allequal(y2a.mask, 0))
+
+ y3 = array(x1 * 1.0, mask=m)
+ assert_(filled(y3).dtype is (x1 * 1.0).dtype)
+
+ x4 = arange(4)
+ x4[2] = masked
+ y4 = resize(x4, (8,))
+ assert_equal(concatenate([x4, x4]), y4)
+ assert_equal(getmask(y4), [0, 0, 1, 0, 0, 0, 1, 0])
+ y5 = repeat(x4, (2, 2, 2, 2), axis=0)
+ assert_equal(y5, [0, 0, 1, 1, 2, 2, 3, 3])
+ y6 = repeat(x4, 2, axis=0)
+ assert_equal(y5, y6)
+ y7 = x4.repeat((2, 2, 2, 2), axis=0)
+ assert_equal(y5, y7)
+ y8 = x4.repeat(2, 0)
+ assert_equal(y5, y8)
+
+ y9 = x4.copy()
+ assert_equal(y9._data, x4._data)
+ assert_equal(y9._mask, x4._mask)
+
+ x = masked_array([1, 2, 3], mask=[0, 1, 0])
+ # Copy is False by default
+ y = masked_array(x)
+ assert_equal(y._data.ctypes.data, x._data.ctypes.data)
+ assert_equal(y._mask.ctypes.data, x._mask.ctypes.data)
+ y = masked_array(x, copy=True)
+ assert_not_equal(y._data.ctypes.data, x._data.ctypes.data)
+ assert_not_equal(y._mask.ctypes.data, x._mask.ctypes.data)
+
+ def test_copy_0d(self):
+ # gh-9430
+ x = np.ma.array(43, mask=True)
+ xc = x.copy()
+ assert_equal(xc.mask, True)
+
+ def test_copy_on_python_builtins(self):
+ # Tests copy works on python builtins (issue#8019)
+ assert_(isMaskedArray(np.ma.copy([1,2,3])))
+ assert_(isMaskedArray(np.ma.copy((1,2,3))))
+
+ def test_copy_immutable(self):
+ # Tests that the copy method is immutable, GitHub issue #5247
+ a = np.ma.array([1, 2, 3])
+ b = np.ma.array([4, 5, 6])
+ a_copy_method = a.copy
+ b.copy
+ assert_equal(a_copy_method(), [1, 2, 3])
+
+ def test_deepcopy(self):
+ from copy import deepcopy
+ a = array([0, 1, 2], mask=[False, True, False])
+ copied = deepcopy(a)
+ assert_equal(copied.mask, a.mask)
+ assert_not_equal(id(a._mask), id(copied._mask))
+
+ copied[1] = 1
+ assert_equal(copied.mask, [0, 0, 0])
+ assert_equal(a.mask, [0, 1, 0])
+
+ copied = deepcopy(a)
+ assert_equal(copied.mask, a.mask)
+ copied.mask[1] = False
+ assert_equal(copied.mask, [0, 0, 0])
+ assert_equal(a.mask, [0, 1, 0])
+
+ def test_format(self):
+ a = array([0, 1, 2], mask=[False, True, False])
+ assert_equal(format(a), "[0 -- 2]")
+ assert_equal(format(masked), "--")
+ assert_equal(format(masked, ""), "--")
+
+ # Postponed from PR #15410, perhaps address in the future.
+ # assert_equal(format(masked, " >5"), " --")
+ # assert_equal(format(masked, " <5"), "-- ")
+
+ # Expect a FutureWarning for using format_spec with MaskedElement
+ with assert_warns(FutureWarning):
+ with_format_string = format(masked, " >5")
+ assert_equal(with_format_string, "--")
+
+ def test_str_repr(self):
+ a = array([0, 1, 2], mask=[False, True, False])
+ assert_equal(str(a), '[0 -- 2]')
+ assert_equal(
+ repr(a),
+ textwrap.dedent('''\
+ masked_array(data=[0, --, 2],
+ mask=[False, True, False],
+ fill_value=999999)''')
+ )
+
+ # arrays with a continuation
+ a = np.ma.arange(2000)
+ a[1:50] = np.ma.masked
+ assert_equal(
+ repr(a),
+ textwrap.dedent('''\
+ masked_array(data=[0, --, --, ..., 1997, 1998, 1999],
+ mask=[False, True, True, ..., False, False, False],
+ fill_value=999999)''')
+ )
+
+ # line-wrapped 1d arrays are correctly aligned
+ a = np.ma.arange(20)
+ assert_equal(
+ repr(a),
+ textwrap.dedent('''\
+ masked_array(data=[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19],
+ mask=False,
+ fill_value=999999)''')
+ )
+
+ # 2d arrays cause wrapping
+ a = array([[1, 2, 3], [4, 5, 6]], dtype=np.int8)
+ a[1,1] = np.ma.masked
+ assert_equal(
+ repr(a),
+ textwrap.dedent('''\
+ masked_array(
+ data=[[1, 2, 3],
+ [4, --, 6]],
+ mask=[[False, False, False],
+ [False, True, False]],
+ fill_value=999999,
+ dtype=int8)''')
+ )
+
+ # but not it they're a row vector
+ assert_equal(
+ repr(a[:1]),
+ textwrap.dedent('''\
+ masked_array(data=[[1, 2, 3]],
+ mask=[[False, False, False]],
+ fill_value=999999,
+ dtype=int8)''')
+ )
+
+ # dtype=int is implied, so not shown
+ assert_equal(
+ repr(a.astype(int)),
+ textwrap.dedent('''\
+ masked_array(
+ data=[[1, 2, 3],
+ [4, --, 6]],
+ mask=[[False, False, False],
+ [False, True, False]],
+ fill_value=999999)''')
+ )
+
+ def test_str_repr_legacy(self):
+ oldopts = np.get_printoptions()
+ np.set_printoptions(legacy='1.13')
+ try:
+ 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')
+
+ a = np.ma.arange(2000)
+ a[1:50] = np.ma.masked
+ assert_equal(
+ repr(a),
+ 'masked_array(data = [0 -- -- ..., 1997 1998 1999],\n'
+ ' mask = [False True True ..., False False False],\n'
+ ' fill_value = 999999)\n'
+ )
+ finally:
+ np.set_printoptions(**oldopts)
+
+ def test_0d_unicode(self):
+ u = 'caf\xe9'
+ utype = type(u)
+
+ arr_nomask = np.ma.array(u)
+ arr_masked = np.ma.array(u, mask=True)
+
+ assert_equal(utype(arr_nomask), u)
+ assert_equal(utype(arr_masked), '--')
+
+ def test_pickling(self):
+ # Tests pickling
+ for dtype in (int, float, str, object):
+ a = arange(10).astype(dtype)
+ a.fill_value = 999
+
+ masks = ([0, 0, 0, 1, 0, 1, 0, 1, 0, 1], # partially masked
+ True, # Fully masked
+ False) # Fully unmasked
+
+ for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
+ for mask in masks:
+ a.mask = mask
+ a_pickled = pickle.loads(pickle.dumps(a, protocol=proto))
+ assert_equal(a_pickled._mask, a._mask)
+ assert_equal(a_pickled._data, a._data)
+ if dtype in (object, int):
+ assert_equal(a_pickled.fill_value, 999)
+ else:
+ assert_equal(a_pickled.fill_value, dtype(999))
+ assert_array_equal(a_pickled.mask, mask)
+
+ def test_pickling_subbaseclass(self):
+ # Test pickling w/ a subclass of ndarray
+ x = np.array([(1.0, 2), (3.0, 4)],
+ dtype=[('x', float), ('y', int)]).view(np.recarray)
+ a = masked_array(x, mask=[(True, False), (False, True)])
+ for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
+ a_pickled = pickle.loads(pickle.dumps(a, protocol=proto))
+ assert_equal(a_pickled._mask, a._mask)
+ assert_equal(a_pickled, a)
+ assert_(isinstance(a_pickled._data, np.recarray))
+
+ def test_pickling_maskedconstant(self):
+ # Test pickling MaskedConstant
+ mc = np.ma.masked
+ for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
+ mc_pickled = pickle.loads(pickle.dumps(mc, protocol=proto))
+ assert_equal(mc_pickled._baseclass, mc._baseclass)
+ assert_equal(mc_pickled._mask, mc._mask)
+ assert_equal(mc_pickled._data, mc._data)
+
+ def test_pickling_wstructured(self):
+ # Tests pickling w/ structured array
+ a = array([(1, 1.), (2, 2.)], mask=[(0, 0), (0, 1)],
+ dtype=[('a', int), ('b', float)])
+ for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
+ a_pickled = pickle.loads(pickle.dumps(a, protocol=proto))
+ assert_equal(a_pickled._mask, a._mask)
+ assert_equal(a_pickled, a)
+
+ def test_pickling_keepalignment(self):
+ # Tests pickling w/ F_CONTIGUOUS arrays
+ a = arange(10)
+ a.shape = (-1, 2)
+ b = a.T
+ for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
+ test = pickle.loads(pickle.dumps(b, protocol=proto))
+ assert_equal(test, b)
+
+ def test_single_element_subscript(self):
+ # Tests single element subscripts of Maskedarrays.
+ a = array([1, 3, 2])
+ b = array([1, 3, 2], mask=[1, 0, 1])
+ assert_equal(a[0].shape, ())
+ assert_equal(b[0].shape, ())
+ assert_equal(b[1].shape, ())
+
+ def test_topython(self):
+ # Tests some communication issues with Python.
+ assert_equal(1, int(array(1)))
+ assert_equal(1.0, float(array(1)))
+ assert_equal(1, int(array([[[1]]])))
+ assert_equal(1.0, float(array([[1]])))
+ assert_raises(TypeError, float, array([1, 1]))
+
+ with suppress_warnings() as sup:
+ sup.filter(UserWarning, 'Warning: converting a masked element')
+ assert_(np.isnan(float(array([1], mask=[1]))))
+
+ a = array([1, 2, 3], mask=[1, 0, 0])
+ assert_raises(TypeError, lambda: float(a))
+ assert_equal(float(a[-1]), 3.)
+ assert_(np.isnan(float(a[0])))
+ assert_raises(TypeError, int, a)
+ assert_equal(int(a[-1]), 3)
+ assert_raises(MAError, lambda:int(a[0]))
+
+ def test_oddfeatures_1(self):
+ # Test of other odd features
+ x = arange(20)
+ x = x.reshape(4, 5)
+ x.flat[5] = 12
+ assert_(x[1, 0] == 12)
+ z = x + 10j * x
+ assert_equal(z.real, x)
+ assert_equal(z.imag, 10 * x)
+ assert_equal((z * conjugate(z)).real, 101 * x * x)
+ z.imag[...] = 0.0
+
+ x = arange(10)
+ x[3] = masked
+ assert_(str(x[3]) == str(masked))
+ c = x >= 8
+ assert_(count(where(c, masked, masked)) == 0)
+ assert_(shape(where(c, masked, masked)) == c.shape)
+
+ z = masked_where(c, x)
+ assert_(z.dtype is x.dtype)
+ assert_(z[3] is masked)
+ assert_(z[4] is not masked)
+ assert_(z[7] is not masked)
+ assert_(z[8] is masked)
+ assert_(z[9] is masked)
+ assert_equal(x, z)
+
+ def test_oddfeatures_2(self):
+ # Tests some more features.
+ x = array([1., 2., 3., 4., 5.])
+ c = array([1, 1, 1, 0, 0])
+ x[2] = masked
+ z = where(c, x, -x)
+ assert_equal(z, [1., 2., 0., -4., -5])
+ c[0] = masked
+ z = where(c, x, -x)
+ assert_equal(z, [1., 2., 0., -4., -5])
+ assert_(z[0] is masked)
+ assert_(z[1] is not masked)
+ assert_(z[2] is masked)
+
+ @suppress_copy_mask_on_assignment
+ def test_oddfeatures_3(self):
+ # Tests some generic features
+ atest = array([10], mask=True)
+ btest = array([20])
+ idx = atest.mask
+ atest[idx] = btest[idx]
+ assert_equal(atest, [20])
+
+ def test_filled_with_object_dtype(self):
+ a = np.ma.masked_all(1, dtype='O')
+ assert_equal(a.filled('x')[0], 'x')
+
+ def test_filled_with_flexible_dtype(self):
+ # Test filled w/ flexible dtype
+ flexi = array([(1, 1, 1)],
+ dtype=[('i', int), ('s', '|S8'), ('f', float)])
+ flexi[0] = masked
+ assert_equal(flexi.filled(),
+ np.array([(default_fill_value(0),
+ default_fill_value('0'),
+ default_fill_value(0.),)], dtype=flexi.dtype))
+ flexi[0] = masked
+ assert_equal(flexi.filled(1),
+ np.array([(1, '1', 1.)], dtype=flexi.dtype))
+
+ def test_filled_with_mvoid(self):
+ # Test filled w/ mvoid
+ ndtype = [('a', int), ('b', float)]
+ a = mvoid((1, 2.), mask=[(0, 1)], dtype=ndtype)
+ # Filled using default
+ test = a.filled()
+ assert_equal(tuple(test), (1, default_fill_value(1.)))
+ # Explicit fill_value
+ test = a.filled((-1, -1))
+ assert_equal(tuple(test), (1, -1))
+ # Using predefined filling values
+ a.fill_value = (-999, -999)
+ assert_equal(tuple(a.filled()), (1, -999))
+
+ def test_filled_with_nested_dtype(self):
+ # Test filled w/ nested dtype
+ ndtype = [('A', int), ('B', [('BA', int), ('BB', int)])]
+ a = array([(1, (1, 1)), (2, (2, 2))],
+ mask=[(0, (1, 0)), (0, (0, 1))], dtype=ndtype)
+ test = a.filled(0)
+ control = np.array([(1, (0, 1)), (2, (2, 0))], dtype=ndtype)
+ assert_equal(test, control)
+
+ test = a['B'].filled(0)
+ control = np.array([(0, 1), (2, 0)], dtype=a['B'].dtype)
+ assert_equal(test, control)
+
+ # test if mask gets set correctly (see #6760)
+ Z = numpy.ma.zeros(2, numpy.dtype([("A", "(2,2)i1,(2,2)i1", (2,2))]))
+ assert_equal(Z.data.dtype, numpy.dtype([('A', [('f0', 'i1', (2, 2)),
+ ('f1', 'i1', (2, 2))], (2, 2))]))
+ assert_equal(Z.mask.dtype, numpy.dtype([('A', [('f0', '?', (2, 2)),
+ ('f1', '?', (2, 2))], (2, 2))]))
+
+ def test_filled_with_f_order(self):
+ # Test filled w/ F-contiguous array
+ a = array(np.array([(0, 1, 2), (4, 5, 6)], order='F'),
+ mask=np.array([(0, 0, 1), (1, 0, 0)], order='F'),
+ order='F') # this is currently ignored
+ assert_(a.flags['F_CONTIGUOUS'])
+ assert_(a.filled(0).flags['F_CONTIGUOUS'])
+
+ def test_optinfo_propagation(self):
+ # Checks that _optinfo dictionary isn't back-propagated
+ x = array([1, 2, 3, ], dtype=float)
+ x._optinfo['info'] = '???'
+ y = x.copy()
+ assert_equal(y._optinfo['info'], '???')
+ y._optinfo['info'] = '!!!'
+ assert_equal(x._optinfo['info'], '???')
+
+ def test_optinfo_forward_propagation(self):
+ a = array([1,2,2,4])
+ a._optinfo["key"] = "value"
+ assert_equal(a._optinfo["key"], (a == 2)._optinfo["key"])
+ assert_equal(a._optinfo["key"], (a != 2)._optinfo["key"])
+ assert_equal(a._optinfo["key"], (a > 2)._optinfo["key"])
+ assert_equal(a._optinfo["key"], (a >= 2)._optinfo["key"])
+ assert_equal(a._optinfo["key"], (a <= 2)._optinfo["key"])
+ assert_equal(a._optinfo["key"], (a + 2)._optinfo["key"])
+ assert_equal(a._optinfo["key"], (a - 2)._optinfo["key"])
+ assert_equal(a._optinfo["key"], (a * 2)._optinfo["key"])
+ assert_equal(a._optinfo["key"], (a / 2)._optinfo["key"])
+ assert_equal(a._optinfo["key"], a[:2]._optinfo["key"])
+ assert_equal(a._optinfo["key"], a[[0,0,2]]._optinfo["key"])
+ assert_equal(a._optinfo["key"], np.exp(a)._optinfo["key"])
+ assert_equal(a._optinfo["key"], np.abs(a)._optinfo["key"])
+ assert_equal(a._optinfo["key"], array(a, copy=True)._optinfo["key"])
+ assert_equal(a._optinfo["key"], np.zeros_like(a)._optinfo["key"])
+
+ def test_fancy_printoptions(self):
+ # Test printing a masked array w/ fancy dtype.
+ fancydtype = np.dtype([('x', int), ('y', [('t', int), ('s', float)])])
+ test = array([(1, (2, 3.0)), (4, (5, 6.0))],
+ mask=[(1, (0, 1)), (0, (1, 0))],
+ dtype=fancydtype)
+ control = "[(--, (2, --)) (4, (--, 6.0))]"
+ assert_equal(str(test), control)
+
+ # Test 0-d array with multi-dimensional dtype
+ t_2d0 = masked_array(data = (0, [[0.0, 0.0, 0.0],
+ [0.0, 0.0, 0.0]],
+ 0.0),
+ mask = (False, [[True, False, True],
+ [False, False, True]],
+ False),
+ dtype = "int, (2,3)float, float")
+ control = "(0, [[--, 0.0, --], [0.0, 0.0, --]], 0.0)"
+ assert_equal(str(t_2d0), control)
+
+ def test_flatten_structured_array(self):
+ # Test flatten_structured_array on arrays
+ # On ndarray
+ ndtype = [('a', int), ('b', float)]
+ a = np.array([(1, 1), (2, 2)], dtype=ndtype)
+ test = flatten_structured_array(a)
+ control = np.array([[1., 1.], [2., 2.]], dtype=float)
+ assert_equal(test, control)
+ assert_equal(test.dtype, control.dtype)
+ # On masked_array
+ a = array([(1, 1), (2, 2)], mask=[(0, 1), (1, 0)], dtype=ndtype)
+ test = flatten_structured_array(a)
+ control = array([[1., 1.], [2., 2.]],
+ mask=[[0, 1], [1, 0]], dtype=float)
+ assert_equal(test, control)
+ assert_equal(test.dtype, control.dtype)
+ assert_equal(test.mask, control.mask)
+ # On masked array with nested structure
+ ndtype = [('a', int), ('b', [('ba', int), ('bb', float)])]
+ a = array([(1, (1, 1.1)), (2, (2, 2.2))],
+ mask=[(0, (1, 0)), (1, (0, 1))], dtype=ndtype)
+ test = flatten_structured_array(a)
+ control = array([[1., 1., 1.1], [2., 2., 2.2]],
+ mask=[[0, 1, 0], [1, 0, 1]], dtype=float)
+ assert_equal(test, control)
+ assert_equal(test.dtype, control.dtype)
+ assert_equal(test.mask, control.mask)
+ # Keeping the initial shape
+ ndtype = [('a', int), ('b', float)]
+ a = np.array([[(1, 1), ], [(2, 2), ]], dtype=ndtype)
+ test = flatten_structured_array(a)
+ control = np.array([[[1., 1.], ], [[2., 2.], ]], dtype=float)
+ assert_equal(test, control)
+ assert_equal(test.dtype, control.dtype)
+
+ 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]
+ assert_(isinstance(f, mvoid))
+ assert_equal((f[0], f['a']), (1, 1))
+ assert_equal(f['b'], 2)
+ # w/ mask
+ f = a[1]
+ assert_(isinstance(f, mvoid))
+ assert_(f[0] is masked)
+ assert_(f['a'] is masked)
+ assert_equal(f[1], 4)
+
+ # exotic dtype
+ A = masked_array(data=[([0,1],)],
+ mask=[([True, False],)],
+ dtype=[("A", ">i2", (2,))])
+ assert_equal(A[0]["A"], A["A"][0])
+ assert_equal(A[0]["A"], masked_array(data=[0, 1],
+ mask=[True, False], dtype=">i2"))
+
+ 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])
+
+ def test_mvoid_print(self):
+ # Test printing a mvoid
+ mx = array([(1, 1), (2, 2)], dtype=[('a', int), ('b', int)])
+ assert_equal(str(mx[0]), "(1, 1)")
+ mx['b'][0] = masked
+ ini_display = masked_print_option._display
+ masked_print_option.set_display("-X-")
+ try:
+ assert_equal(str(mx[0]), "(1, -X-)")
+ assert_equal(repr(mx[0]), "(1, -X-)")
+ finally:
+ masked_print_option.set_display(ini_display)
+
+ # also check if there are object datatypes (see gh-7493)
+ mx = array([(1,), (2,)], dtype=[('a', 'O')])
+ assert_equal(str(mx[0]), "(1,)")
+
+ def test_mvoid_multidim_print(self):
+
+ # regression test for gh-6019
+ t_ma = masked_array(data = [([1, 2, 3],)],
+ mask = [([False, True, False],)],
+ fill_value = ([999999, 999999, 999999],),
+ dtype = [('a', '<i4', (3,))])
+ assert_(str(t_ma[0]) == "([1, --, 3],)")
+ assert_(repr(t_ma[0]) == "([1, --, 3],)")
+
+ # additional tests with structured arrays
+
+ t_2d = masked_array(data = [([[1, 2], [3,4]],)],
+ mask = [([[False, True], [True, False]],)],
+ dtype = [('a', '<i4', (2,2))])
+ assert_(str(t_2d[0]) == "([[1, --], [--, 4]],)")
+ assert_(repr(t_2d[0]) == "([[1, --], [--, 4]],)")
+
+ t_0d = masked_array(data = [(1,2)],
+ mask = [(True,False)],
+ dtype = [('a', '<i4'), ('b', '<i4')])
+ assert_(str(t_0d[0]) == "(--, 2)")
+ assert_(repr(t_0d[0]) == "(--, 2)")
+
+ t_2d = masked_array(data = [([[1, 2], [3,4]], 1)],
+ mask = [([[False, True], [True, False]], False)],
+ dtype = [('a', '<i4', (2,2)), ('b', float)])
+ assert_(str(t_2d[0]) == "([[1, --], [--, 4]], 1.0)")
+ assert_(repr(t_2d[0]) == "([[1, --], [--, 4]], 1.0)")
+
+ t_ne = masked_array(data=[(1, (1, 1))],
+ mask=[(True, (True, False))],
+ dtype = [('a', '<i4'), ('b', 'i4,i4')])
+ assert_(str(t_ne[0]) == "(--, (--, 1))")
+ assert_(repr(t_ne[0]) == "(--, (--, 1))")
+
+ def test_object_with_array(self):
+ mx1 = masked_array([1.], mask=[True])
+ mx2 = masked_array([1., 2.])
+ mx = masked_array([mx1, mx2], mask=[False, True], dtype=object)
+ assert_(mx[0] is mx1)
+ assert_(mx[1] is not mx2)
+ assert_(np.all(mx[1].data == mx2.data))
+ assert_(np.all(mx[1].mask))
+ # check that we return a view.
+ mx[1].data[0] = 0.
+ assert_(mx2[0] == 0.)
+
+
+class TestMaskedArrayArithmetic:
+ # Base test class for MaskedArrays.
+
+ def setup_method(self):
+ # Base data definition.
+ x = np.array([1., 1., 1., -2., pi/2.0, 4., 5., -10., 10., 1., 2., 3.])
+ y = np.array([5., 0., 3., 2., -1., -4., 0., -10., 10., 1., 0., 3.])
+ a10 = 10.
+ m1 = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
+ m2 = [0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1]
+ xm = masked_array(x, mask=m1)
+ ym = masked_array(y, mask=m2)
+ z = np.array([-.5, 0., .5, .8])
+ zm = masked_array(z, mask=[0, 1, 0, 0])
+ xf = np.where(m1, 1e+20, x)
+ xm.set_fill_value(1e+20)
+ self.d = (x, y, a10, m1, m2, xm, ym, z, zm, xf)
+ self.err_status = np.geterr()
+ np.seterr(divide='ignore', invalid='ignore')
+
+ def teardown_method(self):
+ np.seterr(**self.err_status)
+
+ def test_basic_arithmetic(self):
+ # Test of basic arithmetic.
+ (x, y, a10, m1, m2, xm, ym, z, zm, xf) = self.d
+ a2d = array([[1, 2], [0, 4]])
+ a2dm = masked_array(a2d, [[0, 0], [1, 0]])
+ assert_equal(a2d * a2d, a2d * a2dm)
+ assert_equal(a2d + a2d, a2d + a2dm)
+ assert_equal(a2d - a2d, a2d - a2dm)
+ for s in [(12,), (4, 3), (2, 6)]:
+ x = x.reshape(s)
+ y = y.reshape(s)
+ xm = xm.reshape(s)
+ ym = ym.reshape(s)
+ xf = xf.reshape(s)
+ assert_equal(-x, -xm)
+ assert_equal(x + y, xm + ym)
+ assert_equal(x - y, xm - ym)
+ assert_equal(x * y, xm * ym)
+ assert_equal(x / y, xm / ym)
+ assert_equal(a10 + y, a10 + ym)
+ assert_equal(a10 - y, a10 - ym)
+ assert_equal(a10 * y, a10 * ym)
+ assert_equal(a10 / y, a10 / ym)
+ assert_equal(x + a10, xm + a10)
+ assert_equal(x - a10, xm - a10)
+ assert_equal(x * a10, xm * a10)
+ assert_equal(x / a10, xm / a10)
+ assert_equal(x ** 2, xm ** 2)
+ assert_equal(abs(x) ** 2.5, abs(xm) ** 2.5)
+ assert_equal(x ** y, xm ** ym)
+ assert_equal(np.add(x, y), add(xm, ym))
+ assert_equal(np.subtract(x, y), subtract(xm, ym))
+ assert_equal(np.multiply(x, y), multiply(xm, ym))
+ assert_equal(np.divide(x, y), divide(xm, ym))
+
+ def test_divide_on_different_shapes(self):
+ x = arange(6, dtype=float)
+ x.shape = (2, 3)
+ y = arange(3, dtype=float)
+
+ z = x / y
+ assert_equal(z, [[-1., 1., 1.], [-1., 4., 2.5]])
+ assert_equal(z.mask, [[1, 0, 0], [1, 0, 0]])
+
+ z = x / y[None,:]
+ assert_equal(z, [[-1., 1., 1.], [-1., 4., 2.5]])
+ assert_equal(z.mask, [[1, 0, 0], [1, 0, 0]])
+
+ y = arange(2, dtype=float)
+ z = x / y[:, None]
+ assert_equal(z, [[-1., -1., -1.], [3., 4., 5.]])
+ assert_equal(z.mask, [[1, 1, 1], [0, 0, 0]])
+
+ def test_mixed_arithmetic(self):
+ # Tests mixed arithmetic.
+ na = np.array([1])
+ ma = array([1])
+ assert_(isinstance(na + ma, MaskedArray))
+ assert_(isinstance(ma + na, MaskedArray))
+
+ def test_limits_arithmetic(self):
+ tiny = np.finfo(float).tiny
+ a = array([tiny, 1. / tiny, 0.])
+ assert_equal(getmaskarray(a / 2), [0, 0, 0])
+ assert_equal(getmaskarray(2 / a), [1, 0, 1])
+
+ def test_masked_singleton_arithmetic(self):
+ # Tests some scalar arithmetic on MaskedArrays.
+ # Masked singleton should remain masked no matter what
+ xm = array(0, mask=1)
+ assert_((1 / array(0)).mask)
+ assert_((1 + xm).mask)
+ assert_((-xm).mask)
+ assert_(maximum(xm, xm).mask)
+ assert_(minimum(xm, xm).mask)
+
+ def test_masked_singleton_equality(self):
+ # Tests (in)equality on masked singleton
+ a = array([1, 2, 3], mask=[1, 1, 0])
+ assert_((a[0] == 0) is masked)
+ assert_((a[0] != 0) is masked)
+ assert_equal((a[-1] == 0), False)
+ assert_equal((a[-1] != 0), True)
+
+ def test_arithmetic_with_masked_singleton(self):
+ # Checks that there's no collapsing to masked
+ x = masked_array([1, 2])
+ y = x * masked
+ assert_equal(y.shape, x.shape)
+ assert_equal(y._mask, [True, True])
+ y = x[0] * masked
+ assert_(y is masked)
+ y = x + masked
+ assert_equal(y.shape, x.shape)
+ assert_equal(y._mask, [True, True])
+
+ def test_arithmetic_with_masked_singleton_on_1d_singleton(self):
+ # Check that we're not losing the shape of a singleton
+ x = masked_array([1, ])
+ y = x + masked
+ assert_equal(y.shape, x.shape)
+ assert_equal(y.mask, [True, ])
+
+ def test_scalar_arithmetic(self):
+ x = array(0, mask=0)
+ assert_equal(x.filled().ctypes.data, x.ctypes.data)
+ # Make sure we don't lose the shape in some circumstances
+ xm = array((0, 0)) / 0.
+ assert_equal(xm.shape, (2,))
+ assert_equal(xm.mask, [1, 1])
+
+ def test_basic_ufuncs(self):
+ # Test various functions such as sin, cos.
+ (x, y, a10, m1, m2, xm, ym, z, zm, xf) = self.d
+ assert_equal(np.cos(x), cos(xm))
+ assert_equal(np.cosh(x), cosh(xm))
+ assert_equal(np.sin(x), sin(xm))
+ assert_equal(np.sinh(x), sinh(xm))
+ assert_equal(np.tan(x), tan(xm))
+ assert_equal(np.tanh(x), tanh(xm))
+ assert_equal(np.sqrt(abs(x)), sqrt(xm))
+ assert_equal(np.log(abs(x)), log(xm))
+ assert_equal(np.log10(abs(x)), log10(xm))
+ assert_equal(np.exp(x), exp(xm))
+ assert_equal(np.arcsin(z), arcsin(zm))
+ assert_equal(np.arccos(z), arccos(zm))
+ assert_equal(np.arctan(z), arctan(zm))
+ assert_equal(np.arctan2(x, y), arctan2(xm, ym))
+ assert_equal(np.absolute(x), absolute(xm))
+ assert_equal(np.angle(x + 1j*y), angle(xm + 1j*ym))
+ assert_equal(np.angle(x + 1j*y, deg=True), angle(xm + 1j*ym, deg=True))
+ assert_equal(np.equal(x, y), equal(xm, ym))
+ assert_equal(np.not_equal(x, y), not_equal(xm, ym))
+ assert_equal(np.less(x, y), less(xm, ym))
+ assert_equal(np.greater(x, y), greater(xm, ym))
+ assert_equal(np.less_equal(x, y), less_equal(xm, ym))
+ assert_equal(np.greater_equal(x, y), greater_equal(xm, ym))
+ assert_equal(np.conjugate(x), conjugate(xm))
+
+ def test_count_func(self):
+ # Tests count
+ 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)
+ assert_(res.dtype.type is np.intp)
+ assert_equal(3, res)
+
+ ott = ott.reshape((2, 2))
+ 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(np.AxisError, ott.count, axis=1)
+
+ def test_count_on_python_builtins(self):
+ # Tests count works on python builtins (issue#8019)
+ assert_equal(3, count([1,2,3]))
+ assert_equal(2, count((1,2)))
+
+ def test_minmax_func(self):
+ # Tests minimum and maximum.
+ (x, y, a10, m1, m2, xm, ym, z, zm, xf) = self.d
+ # max doesn't work if shaped
+ xr = np.ravel(x)
+ xmr = ravel(xm)
+ # following are true because of careful selection of data
+ assert_equal(max(xr), maximum.reduce(xmr))
+ assert_equal(min(xr), minimum.reduce(xmr))
+
+ assert_equal(minimum([1, 2, 3], [4, 0, 9]), [1, 0, 3])
+ assert_equal(maximum([1, 2, 3], [4, 0, 9]), [4, 2, 9])
+ x = arange(5)
+ y = arange(5) - 2
+ x[3] = masked
+ y[0] = masked
+ assert_equal(minimum(x, y), where(less(x, y), x, y))
+ assert_equal(maximum(x, y), where(greater(x, y), x, y))
+ assert_(minimum.reduce(x) == 0)
+ assert_(maximum.reduce(x) == 4)
+
+ x = arange(4).reshape(2, 2)
+ x[-1, -1] = masked
+ assert_equal(maximum.reduce(x, axis=None), 2)
+
+ def test_minimummaximum_func(self):
+ a = np.ones((2, 2))
+ aminimum = minimum(a, a)
+ assert_(isinstance(aminimum, MaskedArray))
+ assert_equal(aminimum, np.minimum(a, a))
+
+ aminimum = minimum.outer(a, a)
+ assert_(isinstance(aminimum, MaskedArray))
+ assert_equal(aminimum, np.minimum.outer(a, a))
+
+ amaximum = maximum(a, a)
+ assert_(isinstance(amaximum, MaskedArray))
+ assert_equal(amaximum, np.maximum(a, a))
+
+ amaximum = maximum.outer(a, a)
+ assert_(isinstance(amaximum, MaskedArray))
+ assert_equal(amaximum, np.maximum.outer(a, a))
+
+ def test_minmax_reduce(self):
+ # Test np.min/maximum.reduce on array w/ full False mask
+ a = array([1, 2, 3], mask=[False, False, False])
+ b = np.maximum.reduce(a)
+ assert_equal(b, 3)
+
+ def test_minmax_funcs_with_output(self):
+ # Tests the min/max functions with explicit outputs
+ mask = np.random.rand(12).round()
+ xm = array(np.random.uniform(0, 10, 12), mask=mask)
+ xm.shape = (3, 4)
+ for funcname in ('min', 'max'):
+ # Initialize
+ npfunc = getattr(np, funcname)
+ mafunc = getattr(numpy.ma.core, funcname)
+ # Use the np version
+ nout = np.empty((4,), dtype=int)
+ try:
+ result = npfunc(xm, axis=0, out=nout)
+ except MaskError:
+ pass
+ nout = np.empty((4,), dtype=float)
+ result = npfunc(xm, axis=0, out=nout)
+ assert_(result is nout)
+ # Use the ma version
+ nout.fill(-999)
+ result = mafunc(xm, axis=0, out=nout)
+ assert_(result is nout)
+
+ def test_minmax_methods(self):
+ # Additional tests on max/min
+ (_, _, _, _, _, xm, _, _, _, _) = self.d
+ xm.shape = (xm.size,)
+ assert_equal(xm.max(), 10)
+ assert_(xm[0].max() is masked)
+ assert_(xm[0].max(0) is masked)
+ assert_(xm[0].max(-1) is masked)
+ assert_equal(xm.min(), -10.)
+ assert_(xm[0].min() is masked)
+ assert_(xm[0].min(0) is masked)
+ assert_(xm[0].min(-1) is masked)
+ assert_equal(xm.ptp(), 20.)
+ assert_(xm[0].ptp() is masked)
+ assert_(xm[0].ptp(0) is masked)
+ assert_(xm[0].ptp(-1) is masked)
+
+ x = array([1, 2, 3], mask=True)
+ assert_(x.min() is masked)
+ assert_(x.max() is masked)
+ assert_(x.ptp() is masked)
+
+ def test_minmax_dtypes(self):
+ # Additional tests on max/min for non-standard float and complex dtypes
+ x = np.array([1., 1., 1., -2., pi/2.0, 4., 5., -10., 10., 1., 2., 3.])
+ a10 = 10.
+ an10 = -10.0
+ m1 = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
+ xm = masked_array(x, mask=m1)
+ xm.set_fill_value(1e+20)
+ float_dtypes = [np.half, np.single, np.double,
+ np.longdouble, np.cfloat, np.cdouble, np.clongdouble]
+ for float_dtype in float_dtypes:
+ assert_equal(masked_array(x, mask=m1, dtype=float_dtype).max(),
+ float_dtype(a10))
+ assert_equal(masked_array(x, mask=m1, dtype=float_dtype).min(),
+ float_dtype(an10))
+
+ assert_equal(xm.min(), an10)
+ assert_equal(xm.max(), a10)
+
+ # Non-complex type only test
+ for float_dtype in float_dtypes[:4]:
+ assert_equal(masked_array(x, mask=m1, dtype=float_dtype).max(),
+ float_dtype(a10))
+ assert_equal(masked_array(x, mask=m1, dtype=float_dtype).min(),
+ float_dtype(an10))
+
+ # Complex types only test
+ for float_dtype in float_dtypes[-3:]:
+ ym = masked_array([1e20+1j, 1e20-2j, 1e20-1j], mask=[0, 1, 0],
+ dtype=float_dtype)
+ assert_equal(ym.min(), float_dtype(1e20-1j))
+ assert_equal(ym.max(), float_dtype(1e20+1j))
+
+ zm = masked_array([np.inf+2j, np.inf+3j, -np.inf-1j], mask=[0, 1, 0],
+ dtype=float_dtype)
+ assert_equal(zm.min(), float_dtype(-np.inf-1j))
+ assert_equal(zm.max(), float_dtype(np.inf+2j))
+
+ cmax = np.inf - 1j * np.finfo(np.float64).max
+ assert masked_array([-cmax, 0], mask=[0, 1]).max() == -cmax
+ assert masked_array([cmax, 0], mask=[0, 1]).min() == cmax
+
+ def test_addsumprod(self):
+ # Tests add, sum, product.
+ (x, y, a10, m1, m2, xm, ym, z, zm, xf) = self.d
+ assert_equal(np.add.reduce(x), add.reduce(x))
+ assert_equal(np.add.accumulate(x), add.accumulate(x))
+ assert_equal(4, sum(array(4), axis=0))
+ assert_equal(4, sum(array(4), axis=0))
+ assert_equal(np.sum(x, axis=0), sum(x, axis=0))
+ assert_equal(np.sum(filled(xm, 0), axis=0), sum(xm, axis=0))
+ assert_equal(np.sum(x, 0), sum(x, 0))
+ assert_equal(np.product(x, axis=0), product(x, axis=0))
+ assert_equal(np.product(x, 0), product(x, 0))
+ assert_equal(np.product(filled(xm, 1), axis=0), product(xm, axis=0))
+ s = (3, 4)
+ x.shape = y.shape = xm.shape = ym.shape = s
+ if len(s) > 1:
+ assert_equal(np.concatenate((x, y), 1), concatenate((xm, ym), 1))
+ assert_equal(np.add.reduce(x, 1), add.reduce(x, 1))
+ assert_equal(np.sum(x, 1), sum(x, 1))
+ assert_equal(np.product(x, 1), product(x, 1))
+
+ def test_binops_d2D(self):
+ # Test binary operations on 2D data
+ a = array([[1.], [2.], [3.]], mask=[[False], [True], [True]])
+ b = array([[2., 3.], [4., 5.], [6., 7.]])
+
+ test = a * b
+ control = array([[2., 3.], [2., 2.], [3., 3.]],
+ mask=[[0, 0], [1, 1], [1, 1]])
+ assert_equal(test, control)
+ assert_equal(test.data, control.data)
+ assert_equal(test.mask, control.mask)
+
+ test = b * a
+ control = array([[2., 3.], [4., 5.], [6., 7.]],
+ mask=[[0, 0], [1, 1], [1, 1]])
+ assert_equal(test, control)
+ assert_equal(test.data, control.data)
+ assert_equal(test.mask, control.mask)
+
+ a = array([[1.], [2.], [3.]])
+ b = array([[2., 3.], [4., 5.], [6., 7.]],
+ mask=[[0, 0], [0, 0], [0, 1]])
+ test = a * b
+ control = array([[2, 3], [8, 10], [18, 3]],
+ mask=[[0, 0], [0, 0], [0, 1]])
+ assert_equal(test, control)
+ assert_equal(test.data, control.data)
+ assert_equal(test.mask, control.mask)
+
+ test = b * a
+ control = array([[2, 3], [8, 10], [18, 7]],
+ mask=[[0, 0], [0, 0], [0, 1]])
+ assert_equal(test, control)
+ assert_equal(test.data, control.data)
+ assert_equal(test.mask, control.mask)
+
+ def test_domained_binops_d2D(self):
+ # Test domained binary operations on 2D data
+ a = array([[1.], [2.], [3.]], mask=[[False], [True], [True]])
+ b = array([[2., 3.], [4., 5.], [6., 7.]])
+
+ test = a / b
+ control = array([[1. / 2., 1. / 3.], [2., 2.], [3., 3.]],
+ mask=[[0, 0], [1, 1], [1, 1]])
+ assert_equal(test, control)
+ assert_equal(test.data, control.data)
+ assert_equal(test.mask, control.mask)
+
+ test = b / a
+ control = array([[2. / 1., 3. / 1.], [4., 5.], [6., 7.]],
+ mask=[[0, 0], [1, 1], [1, 1]])
+ assert_equal(test, control)
+ assert_equal(test.data, control.data)
+ assert_equal(test.mask, control.mask)
+
+ a = array([[1.], [2.], [3.]])
+ b = array([[2., 3.], [4., 5.], [6., 7.]],
+ mask=[[0, 0], [0, 0], [0, 1]])
+ test = a / b
+ control = array([[1. / 2, 1. / 3], [2. / 4, 2. / 5], [3. / 6, 3]],
+ mask=[[0, 0], [0, 0], [0, 1]])
+ assert_equal(test, control)
+ assert_equal(test.data, control.data)
+ assert_equal(test.mask, control.mask)
+
+ test = b / a
+ control = array([[2 / 1., 3 / 1.], [4 / 2., 5 / 2.], [6 / 3., 7]],
+ mask=[[0, 0], [0, 0], [0, 1]])
+ assert_equal(test, control)
+ assert_equal(test.data, control.data)
+ assert_equal(test.mask, control.mask)
+
+ def test_noshrinking(self):
+ # Check that we don't shrink a mask when not wanted
+ # Binary operations
+ a = masked_array([1., 2., 3.], mask=[False, False, False],
+ shrink=False)
+ b = a + 1
+ assert_equal(b.mask, [0, 0, 0])
+ # In place binary operation
+ a += 1
+ assert_equal(a.mask, [0, 0, 0])
+ # Domained binary operation
+ b = a / 1.
+ assert_equal(b.mask, [0, 0, 0])
+ # In place binary operation
+ a /= 1.
+ assert_equal(a.mask, [0, 0, 0])
+
+ def test_ufunc_nomask(self):
+ # check the case ufuncs should set the mask to false
+ m = np.ma.array([1])
+ # check we don't get array([False], dtype=bool)
+ assert_equal(np.true_divide(m, 5).mask.shape, ())
+
+ def test_noshink_on_creation(self):
+ # Check that the mask is not shrunk on array creation when not wanted
+ a = np.ma.masked_values([1., 2.5, 3.1], 1.5, shrink=False)
+ assert_equal(a.mask, [0, 0, 0])
+
+ def test_mod(self):
+ # Tests mod
+ (x, y, a10, m1, m2, xm, ym, z, zm, xf) = self.d
+ assert_equal(mod(x, y), mod(xm, ym))
+ test = mod(ym, xm)
+ assert_equal(test, np.mod(ym, xm))
+ assert_equal(test.mask, mask_or(xm.mask, ym.mask))
+ test = mod(xm, ym)
+ assert_equal(test, np.mod(xm, ym))
+ assert_equal(test.mask, mask_or(mask_or(xm.mask, ym.mask), (ym == 0)))
+
+ def test_TakeTransposeInnerOuter(self):
+ # Test of take, transpose, inner, outer products
+ x = arange(24)
+ y = np.arange(24)
+ x[5:6] = masked
+ x = x.reshape(2, 3, 4)
+ y = y.reshape(2, 3, 4)
+ assert_equal(np.transpose(y, (2, 0, 1)), transpose(x, (2, 0, 1)))
+ assert_equal(np.take(y, (2, 0, 1), 1), take(x, (2, 0, 1), 1))
+ assert_equal(np.inner(filled(x, 0), filled(y, 0)),
+ inner(x, y))
+ assert_equal(np.outer(filled(x, 0), filled(y, 0)),
+ outer(x, y))
+ y = array(['abc', 1, 'def', 2, 3], object)
+ y[2] = masked
+ t = take(y, [0, 3, 4])
+ assert_(t[0] == 'abc')
+ assert_(t[1] == 2)
+ assert_(t[2] == 3)
+
+ def test_imag_real(self):
+ # Check complex
+ xx = array([1 + 10j, 20 + 2j], mask=[1, 0])
+ assert_equal(xx.imag, [10, 2])
+ assert_equal(xx.imag.filled(), [1e+20, 2])
+ assert_equal(xx.imag.dtype, xx._data.imag.dtype)
+ assert_equal(xx.real, [1, 20])
+ assert_equal(xx.real.filled(), [1e+20, 20])
+ assert_equal(xx.real.dtype, xx._data.real.dtype)
+
+ def test_methods_with_output(self):
+ xm = array(np.random.uniform(0, 10, 12)).reshape(3, 4)
+ xm[:, 0] = xm[0] = xm[-1, -1] = masked
+
+ funclist = ('sum', 'prod', 'var', 'std', 'max', 'min', 'ptp', 'mean',)
+
+ for funcname in funclist:
+ npfunc = getattr(np, funcname)
+ xmmeth = getattr(xm, funcname)
+ # A ndarray as explicit input
+ output = np.empty(4, dtype=float)
+ output.fill(-9999)
+ result = npfunc(xm, axis=0, out=output)
+ # ... the result should be the given output
+ assert_(result is output)
+ assert_equal(result, xmmeth(axis=0, out=output))
+
+ output = empty(4, dtype=int)
+ result = xmmeth(axis=0, out=output)
+ assert_(result is output)
+ assert_(output[0] is masked)
+
+ def test_eq_on_structured(self):
+ # Test the equality of structured arrays
+ ndtype = [('A', int), ('B', int)]
+ a = array([(1, 1), (2, 2)], mask=[(0, 1), (0, 0)], dtype=ndtype)
+
+ test = (a == a)
+ assert_equal(test.data, [True, True])
+ assert_equal(test.mask, [False, False])
+ assert_(test.fill_value == True)
+
+ test = (a == a[0])
+ assert_equal(test.data, [True, False])
+ assert_equal(test.mask, [False, False])
+ assert_(test.fill_value == True)
+
+ b = array([(1, 1), (2, 2)], mask=[(1, 0), (0, 0)], dtype=ndtype)
+ test = (a == b)
+ assert_equal(test.data, [False, True])
+ assert_equal(test.mask, [True, False])
+ assert_(test.fill_value == True)
+
+ test = (a[0] == b)
+ assert_equal(test.data, [False, False])
+ assert_equal(test.mask, [True, False])
+ assert_(test.fill_value == True)
+
+ b = array([(1, 1), (2, 2)], mask=[(0, 1), (1, 0)], dtype=ndtype)
+ test = (a == b)
+ assert_equal(test.data, [True, True])
+ assert_equal(test.mask, [False, False])
+ assert_(test.fill_value == True)
+
+ # complicated dtype, 2-dimensional array.
+ ndtype = [('A', int), ('B', [('BA', int), ('BB', int)])]
+ a = array([[(1, (1, 1)), (2, (2, 2))],
+ [(3, (3, 3)), (4, (4, 4))]],
+ mask=[[(0, (1, 0)), (0, (0, 1))],
+ [(1, (0, 0)), (1, (1, 1))]], dtype=ndtype)
+ test = (a[0, 0] == a)
+ assert_equal(test.data, [[True, False], [False, False]])
+ assert_equal(test.mask, [[False, False], [False, True]])
+ assert_(test.fill_value == True)
+
+ def test_ne_on_structured(self):
+ # Test the equality of structured arrays
+ ndtype = [('A', int), ('B', int)]
+ a = array([(1, 1), (2, 2)], mask=[(0, 1), (0, 0)], dtype=ndtype)
+
+ test = (a != a)
+ assert_equal(test.data, [False, False])
+ assert_equal(test.mask, [False, False])
+ assert_(test.fill_value == True)
+
+ test = (a != a[0])
+ assert_equal(test.data, [False, True])
+ assert_equal(test.mask, [False, False])
+ assert_(test.fill_value == True)
+
+ b = array([(1, 1), (2, 2)], mask=[(1, 0), (0, 0)], dtype=ndtype)
+ test = (a != b)
+ assert_equal(test.data, [True, False])
+ assert_equal(test.mask, [True, False])
+ assert_(test.fill_value == True)
+
+ test = (a[0] != b)
+ assert_equal(test.data, [True, True])
+ assert_equal(test.mask, [True, False])
+ assert_(test.fill_value == True)
+
+ b = array([(1, 1), (2, 2)], mask=[(0, 1), (1, 0)], dtype=ndtype)
+ test = (a != b)
+ assert_equal(test.data, [False, False])
+ assert_equal(test.mask, [False, False])
+ assert_(test.fill_value == True)
+
+ # complicated dtype, 2-dimensional array.
+ ndtype = [('A', int), ('B', [('BA', int), ('BB', int)])]
+ a = array([[(1, (1, 1)), (2, (2, 2))],
+ [(3, (3, 3)), (4, (4, 4))]],
+ mask=[[(0, (1, 0)), (0, (0, 1))],
+ [(1, (0, 0)), (1, (1, 1))]], dtype=ndtype)
+ test = (a[0, 0] != a)
+ assert_equal(test.data, [[False, True], [True, True]])
+ assert_equal(test.mask, [[False, False], [False, True]])
+ assert_(test.fill_value == True)
+
+ def test_eq_ne_structured_extra(self):
+ # ensure simple examples are symmetric and make sense.
+ # from https://github.com/numpy/numpy/pull/8590#discussion_r101126465
+ dt = np.dtype('i4,i4')
+ for m1 in (mvoid((1, 2), mask=(0, 0), dtype=dt),
+ mvoid((1, 2), mask=(0, 1), dtype=dt),
+ mvoid((1, 2), mask=(1, 0), dtype=dt),
+ mvoid((1, 2), mask=(1, 1), dtype=dt)):
+ ma1 = m1.view(MaskedArray)
+ r1 = ma1.view('2i4')
+ for m2 in (np.array((1, 1), dtype=dt),
+ mvoid((1, 1), dtype=dt),
+ mvoid((1, 0), mask=(0, 1), dtype=dt),
+ mvoid((3, 2), mask=(0, 1), dtype=dt)):
+ ma2 = m2.view(MaskedArray)
+ r2 = ma2.view('2i4')
+ eq_expected = (r1 == r2).all()
+ assert_equal(m1 == m2, eq_expected)
+ assert_equal(m2 == m1, eq_expected)
+ assert_equal(ma1 == m2, eq_expected)
+ assert_equal(m1 == ma2, eq_expected)
+ assert_equal(ma1 == ma2, eq_expected)
+ # Also check it is the same if we do it element by element.
+ el_by_el = [m1[name] == m2[name] for name in dt.names]
+ assert_equal(array(el_by_el, dtype=bool).all(), eq_expected)
+ ne_expected = (r1 != r2).any()
+ assert_equal(m1 != m2, ne_expected)
+ assert_equal(m2 != m1, ne_expected)
+ assert_equal(ma1 != m2, ne_expected)
+ assert_equal(m1 != ma2, ne_expected)
+ assert_equal(ma1 != ma2, ne_expected)
+ el_by_el = [m1[name] != m2[name] for name in dt.names]
+ assert_equal(array(el_by_el, dtype=bool).any(), ne_expected)
+
+ @pytest.mark.parametrize('dt', ['S', 'U'])
+ @pytest.mark.parametrize('fill', [None, 'A'])
+ def test_eq_for_strings(self, dt, fill):
+ # Test the equality of structured arrays
+ a = array(['a', 'b'], dtype=dt, mask=[0, 1], fill_value=fill)
+
+ test = (a == a)
+ assert_equal(test.data, [True, True])
+ assert_equal(test.mask, [False, True])
+ assert_(test.fill_value == True)
+
+ test = (a == a[0])
+ assert_equal(test.data, [True, False])
+ assert_equal(test.mask, [False, True])
+ assert_(test.fill_value == True)
+
+ b = array(['a', 'b'], dtype=dt, mask=[1, 0], fill_value=fill)
+ test = (a == b)
+ assert_equal(test.data, [False, False])
+ assert_equal(test.mask, [True, True])
+ assert_(test.fill_value == True)
+
+ test = (a[0] == b)
+ assert_equal(test.data, [False, False])
+ assert_equal(test.mask, [True, False])
+ assert_(test.fill_value == True)
+
+ test = (b == a[0])
+ assert_equal(test.data, [False, False])
+ assert_equal(test.mask, [True, False])
+ assert_(test.fill_value == True)
+
+ @pytest.mark.parametrize('dt', ['S', 'U'])
+ @pytest.mark.parametrize('fill', [None, 'A'])
+ def test_ne_for_strings(self, dt, fill):
+ # Test the equality of structured arrays
+ a = array(['a', 'b'], dtype=dt, mask=[0, 1], fill_value=fill)
+
+ test = (a != a)
+ assert_equal(test.data, [False, False])
+ assert_equal(test.mask, [False, True])
+ assert_(test.fill_value == True)
+
+ test = (a != a[0])
+ assert_equal(test.data, [False, True])
+ assert_equal(test.mask, [False, True])
+ assert_(test.fill_value == True)
+
+ b = array(['a', 'b'], dtype=dt, mask=[1, 0], fill_value=fill)
+ test = (a != b)
+ assert_equal(test.data, [True, True])
+ assert_equal(test.mask, [True, True])
+ assert_(test.fill_value == True)
+
+ test = (a[0] != b)
+ assert_equal(test.data, [True, True])
+ assert_equal(test.mask, [True, False])
+ assert_(test.fill_value == True)
+
+ test = (b != a[0])
+ assert_equal(test.data, [True, True])
+ assert_equal(test.mask, [True, False])
+ assert_(test.fill_value == True)
+
+ @pytest.mark.parametrize('dt1', num_dts, ids=num_ids)
+ @pytest.mark.parametrize('dt2', num_dts, ids=num_ids)
+ @pytest.mark.parametrize('fill', [None, 1])
+ def test_eq_for_numeric(self, dt1, dt2, fill):
+ # Test the equality of structured arrays
+ a = array([0, 1], dtype=dt1, mask=[0, 1], fill_value=fill)
+
+ test = (a == a)
+ assert_equal(test.data, [True, True])
+ assert_equal(test.mask, [False, True])
+ assert_(test.fill_value == True)
+
+ test = (a == a[0])
+ assert_equal(test.data, [True, False])
+ assert_equal(test.mask, [False, True])
+ assert_(test.fill_value == True)
+
+ b = array([0, 1], dtype=dt2, mask=[1, 0], fill_value=fill)
+ test = (a == b)
+ assert_equal(test.data, [False, False])
+ assert_equal(test.mask, [True, True])
+ assert_(test.fill_value == True)
+
+ test = (a[0] == b)
+ assert_equal(test.data, [False, False])
+ assert_equal(test.mask, [True, False])
+ assert_(test.fill_value == True)
+
+ test = (b == a[0])
+ assert_equal(test.data, [False, False])
+ assert_equal(test.mask, [True, False])
+ assert_(test.fill_value == True)
+
+ @pytest.mark.parametrize('dt1', num_dts, ids=num_ids)
+ @pytest.mark.parametrize('dt2', num_dts, ids=num_ids)
+ @pytest.mark.parametrize('fill', [None, 1])
+ def test_ne_for_numeric(self, dt1, dt2, fill):
+ # Test the equality of structured arrays
+ a = array([0, 1], dtype=dt1, mask=[0, 1], fill_value=fill)
+
+ test = (a != a)
+ assert_equal(test.data, [False, False])
+ assert_equal(test.mask, [False, True])
+ assert_(test.fill_value == True)
+
+ test = (a != a[0])
+ assert_equal(test.data, [False, True])
+ assert_equal(test.mask, [False, True])
+ assert_(test.fill_value == True)
+
+ b = array([0, 1], dtype=dt2, mask=[1, 0], fill_value=fill)
+ test = (a != b)
+ assert_equal(test.data, [True, True])
+ assert_equal(test.mask, [True, True])
+ assert_(test.fill_value == True)
+
+ test = (a[0] != b)
+ assert_equal(test.data, [True, True])
+ assert_equal(test.mask, [True, False])
+ assert_(test.fill_value == True)
+
+ test = (b != a[0])
+ assert_equal(test.data, [True, True])
+ assert_equal(test.mask, [True, False])
+ assert_(test.fill_value == True)
+
+ @pytest.mark.parametrize('dt1', num_dts, ids=num_ids)
+ @pytest.mark.parametrize('dt2', num_dts, ids=num_ids)
+ @pytest.mark.parametrize('fill', [None, 1])
+ @pytest.mark.parametrize('op',
+ [operator.le, operator.lt, operator.ge, operator.gt])
+ def test_comparisons_for_numeric(self, op, dt1, dt2, fill):
+ # Test the equality of structured arrays
+ a = array([0, 1], dtype=dt1, mask=[0, 1], fill_value=fill)
+
+ test = op(a, a)
+ assert_equal(test.data, op(a._data, a._data))
+ assert_equal(test.mask, [False, True])
+ assert_(test.fill_value == True)
+
+ test = op(a, a[0])
+ assert_equal(test.data, op(a._data, a._data[0]))
+ assert_equal(test.mask, [False, True])
+ assert_(test.fill_value == True)
+
+ b = array([0, 1], dtype=dt2, mask=[1, 0], fill_value=fill)
+ test = op(a, b)
+ assert_equal(test.data, op(a._data, b._data))
+ assert_equal(test.mask, [True, True])
+ assert_(test.fill_value == True)
+
+ test = op(a[0], b)
+ assert_equal(test.data, op(a._data[0], b._data))
+ assert_equal(test.mask, [True, False])
+ assert_(test.fill_value == True)
+
+ test = op(b, a[0])
+ assert_equal(test.data, op(b._data, a._data[0]))
+ assert_equal(test.mask, [True, False])
+ assert_(test.fill_value == True)
+
+ @pytest.mark.parametrize('op',
+ [operator.le, operator.lt, operator.ge, operator.gt])
+ @pytest.mark.parametrize('fill', [None, "N/A"])
+ def test_comparisons_strings(self, op, fill):
+ # See gh-21770, mask propagation is broken for strings (and some other
+ # cases) so we explicitly test strings here.
+ # In principle only == and != may need special handling...
+ ma1 = masked_array(["a", "b", "cde"], mask=[0, 1, 0], fill_value=fill)
+ ma2 = masked_array(["cde", "b", "a"], mask=[0, 1, 0], fill_value=fill)
+ assert_equal(op(ma1, ma2)._data, op(ma1._data, ma2._data))
+
+ def test_eq_with_None(self):
+ # Really, comparisons with None should not be done, but check them
+ # anyway. Note that pep8 will flag these tests.
+ # Deprecation is in place for arrays, and when it happens this
+ # test will fail (and have to be changed accordingly).
+
+ # With partial mask
+ with suppress_warnings() as sup:
+ sup.filter(FutureWarning, "Comparison to `None`")
+ a = array([None, 1], mask=[0, 1])
+ assert_equal(a == None, array([True, False], mask=[0, 1]))
+ assert_equal(a.data == None, [True, False])
+ assert_equal(a != None, array([False, True], mask=[0, 1]))
+ # With nomask
+ a = array([None, 1], mask=False)
+ assert_equal(a == None, [True, False])
+ assert_equal(a != None, [False, True])
+ # With complete mask
+ a = array([None, 2], mask=True)
+ assert_equal(a == None, array([False, True], mask=True))
+ assert_equal(a != None, array([True, False], mask=True))
+ # Fully masked, even comparison to None should return "masked"
+ a = masked
+ assert_equal(a == None, masked)
+
+ def test_eq_with_scalar(self):
+ a = array(1)
+ assert_equal(a == 1, True)
+ assert_equal(a == 0, False)
+ assert_equal(a != 1, False)
+ assert_equal(a != 0, True)
+ b = array(1, mask=True)
+ assert_equal(b == 0, masked)
+ assert_equal(b == 1, masked)
+ assert_equal(b != 0, masked)
+ assert_equal(b != 1, masked)
+
+ def test_eq_different_dimensions(self):
+ m1 = array([1, 1], mask=[0, 1])
+ # test comparison with both masked and regular arrays.
+ for m2 in (array([[0, 1], [1, 2]]),
+ np.array([[0, 1], [1, 2]])):
+ test = (m1 == m2)
+ assert_equal(test.data, [[False, False],
+ [True, False]])
+ assert_equal(test.mask, [[False, True],
+ [False, True]])
+
+ def test_numpyarithmetic(self):
+ # Check that the mask is not back-propagated when using numpy functions
+ a = masked_array([-1, 0, 1, 2, 3], mask=[0, 0, 0, 0, 1])
+ control = masked_array([np.nan, np.nan, 0, np.log(2), -1],
+ mask=[1, 1, 0, 0, 1])
+
+ test = log(a)
+ assert_equal(test, control)
+ assert_equal(test.mask, control.mask)
+ assert_equal(a.mask, [0, 0, 0, 0, 1])
+
+ test = np.log(a)
+ assert_equal(test, control)
+ assert_equal(test.mask, control.mask)
+ assert_equal(a.mask, [0, 0, 0, 0, 1])
+
+
+class TestMaskedArrayAttributes:
+
+ def test_keepmask(self):
+ # Tests the keep mask flag
+ x = masked_array([1, 2, 3], mask=[1, 0, 0])
+ mx = masked_array(x)
+ assert_equal(mx.mask, x.mask)
+ mx = masked_array(x, mask=[0, 1, 0], keep_mask=False)
+ assert_equal(mx.mask, [0, 1, 0])
+ mx = masked_array(x, mask=[0, 1, 0], keep_mask=True)
+ assert_equal(mx.mask, [1, 1, 0])
+ # We default to true
+ mx = masked_array(x, mask=[0, 1, 0])
+ assert_equal(mx.mask, [1, 1, 0])
+
+ def test_hardmask(self):
+ # Test hard_mask
+ d = arange(5)
+ n = [0, 0, 0, 1, 1]
+ m = make_mask(n)
+ xh = array(d, mask=m, hard_mask=True)
+ # We need to copy, to avoid updating d in xh !
+ xs = array(d, mask=m, hard_mask=False, copy=True)
+ xh[[1, 4]] = [10, 40]
+ xs[[1, 4]] = [10, 40]
+ assert_equal(xh._data, [0, 10, 2, 3, 4])
+ assert_equal(xs._data, [0, 10, 2, 3, 40])
+ assert_equal(xs.mask, [0, 0, 0, 1, 0])
+ assert_(xh._hardmask)
+ assert_(not xs._hardmask)
+ xh[1:4] = [10, 20, 30]
+ xs[1:4] = [10, 20, 30]
+ assert_equal(xh._data, [0, 10, 20, 3, 4])
+ assert_equal(xs._data, [0, 10, 20, 30, 40])
+ assert_equal(xs.mask, nomask)
+ xh[0] = masked
+ xs[0] = masked
+ assert_equal(xh.mask, [1, 0, 0, 1, 1])
+ assert_equal(xs.mask, [1, 0, 0, 0, 0])
+ xh[:] = 1
+ xs[:] = 1
+ assert_equal(xh._data, [0, 1, 1, 3, 4])
+ assert_equal(xs._data, [1, 1, 1, 1, 1])
+ assert_equal(xh.mask, [1, 0, 0, 1, 1])
+ assert_equal(xs.mask, nomask)
+ # Switch to soft mask
+ xh.soften_mask()
+ xh[:] = arange(5)
+ assert_equal(xh._data, [0, 1, 2, 3, 4])
+ assert_equal(xh.mask, nomask)
+ # Switch back to hard mask
+ xh.harden_mask()
+ xh[xh < 3] = masked
+ assert_equal(xh._data, [0, 1, 2, 3, 4])
+ assert_equal(xh._mask, [1, 1, 1, 0, 0])
+ xh[filled(xh > 1, False)] = 5
+ assert_equal(xh._data, [0, 1, 2, 5, 5])
+ assert_equal(xh._mask, [1, 1, 1, 0, 0])
+
+ xh = array([[1, 2], [3, 4]], mask=[[1, 0], [0, 0]], hard_mask=True)
+ xh[0] = 0
+ assert_equal(xh._data, [[1, 0], [3, 4]])
+ assert_equal(xh._mask, [[1, 0], [0, 0]])
+ xh[-1, -1] = 5
+ assert_equal(xh._data, [[1, 0], [3, 5]])
+ assert_equal(xh._mask, [[1, 0], [0, 0]])
+ xh[filled(xh < 5, False)] = 2
+ assert_equal(xh._data, [[1, 2], [2, 5]])
+ assert_equal(xh._mask, [[1, 0], [0, 0]])
+
+ def test_hardmask_again(self):
+ # Another test of hardmask
+ d = arange(5)
+ n = [0, 0, 0, 1, 1]
+ m = make_mask(n)
+ xh = array(d, mask=m, hard_mask=True)
+ xh[4:5] = 999
+ xh[0:1] = 999
+ assert_equal(xh._data, [999, 1, 2, 3, 4])
+
+ def test_hardmask_oncemore_yay(self):
+ # OK, yet another test of hardmask
+ # Make sure that harden_mask/soften_mask//unshare_mask returns self
+ a = array([1, 2, 3], mask=[1, 0, 0])
+ b = a.harden_mask()
+ assert_equal(a, b)
+ b[0] = 0
+ assert_equal(a, b)
+ assert_equal(b, array([1, 2, 3], mask=[1, 0, 0]))
+ a = b.soften_mask()
+ a[0] = 0
+ assert_equal(a, b)
+ assert_equal(b, array([0, 2, 3], mask=[0, 0, 0]))
+
+ def test_smallmask(self):
+ # Checks the behaviour of _smallmask
+ a = arange(10)
+ a[1] = masked
+ a[1] = 1
+ assert_equal(a._mask, nomask)
+ a = arange(10)
+ a._smallmask = False
+ a[1] = masked
+ a[1] = 1
+ assert_equal(a._mask, zeros(10))
+
+ def test_shrink_mask(self):
+ # Tests .shrink_mask()
+ a = array([1, 2, 3], mask=[0, 0, 0])
+ b = a.shrink_mask()
+ assert_equal(a, b)
+ assert_equal(a.mask, nomask)
+
+ # Mask cannot be shrunk on structured types, so is a no-op
+ a = np.ma.array([(1, 2.0)], [('a', int), ('b', float)])
+ b = a.copy()
+ a.shrink_mask()
+ assert_equal(a.mask, b.mask)
+
+ def test_flat(self):
+ # Test that flat can return all types of items [#4585, #4615]
+ # 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
+
+ def test_assign_dtype(self):
+ # check that the mask's dtype is updated when dtype is changed
+ a = np.zeros(4, dtype='f4,i4')
+
+ m = np.ma.array(a)
+ m.dtype = np.dtype('f4')
+ repr(m) # raises?
+ assert_equal(m.dtype, np.dtype('f4'))
+
+ # check that dtype changes that change shape of mask too much
+ # are not allowed
+ def assign():
+ m = np.ma.array(a)
+ m.dtype = np.dtype('f8')
+ assert_raises(ValueError, assign)
+
+ b = a.view(dtype='f4', type=np.ma.MaskedArray) # raises?
+ assert_equal(b.dtype, np.dtype('f4'))
+
+ # check that nomask is preserved
+ a = np.zeros(4, dtype='f4')
+ m = np.ma.array(a)
+ m.dtype = np.dtype('f4,i4')
+ assert_equal(m.dtype, np.dtype('f4,i4'))
+ assert_equal(m._mask, np.ma.nomask)
+
+
+class TestFillingValues:
+
+ def test_check_on_scalar(self):
+ # 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)
+ assert_equal(fval, 0)
+ fval = _check_fill_value(None, int)
+ assert_equal(fval, default_fill_value(0))
+
+ fval = _check_fill_value(0, "|S3")
+ assert_equal(fval, b"0")
+ fval = _check_fill_value(None, "|S3")
+ assert_equal(fval, default_fill_value(b"camelot!"))
+ assert_raises(TypeError, _check_fill_value, 1e+20, int)
+ assert_raises(TypeError, _check_fill_value, 'stuff', int)
+
+ def test_check_on_fields(self):
+ # Tests _check_fill_value with records
+ _check_fill_value = np.ma.core._check_fill_value
+ ndtype = [('a', int), ('b', float), ('c', "|S3")]
+ # A check on a list should return a single record
+ fval = _check_fill_value([-999, -12345678.9, "???"], ndtype)
+ assert_(isinstance(fval, ndarray))
+ assert_equal(fval.item(), [-999, -12345678.9, b"???"])
+ # A check on None should output the defaults
+ fval = _check_fill_value(None, ndtype)
+ assert_(isinstance(fval, ndarray))
+ assert_equal(fval.item(), [default_fill_value(0),
+ default_fill_value(0.),
+ asbytes(default_fill_value("0"))])
+ #.....Using a structured type as fill_value should work
+ fill_val = np.array((-999, -12345678.9, "???"), dtype=ndtype)
+ fval = _check_fill_value(fill_val, ndtype)
+ assert_(isinstance(fval, ndarray))
+ assert_equal(fval.item(), [-999, -12345678.9, b"???"])
+
+ #.....Using a flexible type w/ a different type shouldn't matter
+ # BEHAVIOR in 1.5 and earlier, and 1.13 and later: match structured
+ # types by position
+ fill_val = np.array((-999, -12345678.9, "???"),
+ dtype=[("A", int), ("B", float), ("C", "|S3")])
+ fval = _check_fill_value(fill_val, ndtype)
+ assert_(isinstance(fval, ndarray))
+ assert_equal(fval.item(), [-999, -12345678.9, b"???"])
+
+ #.....Using an object-array shouldn't matter either
+ fill_val = np.ndarray(shape=(1,), dtype=object)
+ fill_val[0] = (-999, -12345678.9, b"???")
+ fval = _check_fill_value(fill_val, object)
+ assert_(isinstance(fval, ndarray))
+ assert_equal(fval.item(), [-999, -12345678.9, b"???"])
+ # NOTE: This test was never run properly as "fill_value" rather than
+ # "fill_val" was assigned. Written properly, it fails.
+ #fill_val = np.array((-999, -12345678.9, "???"))
+ #fval = _check_fill_value(fill_val, ndtype)
+ #assert_(isinstance(fval, ndarray))
+ #assert_equal(fval.item(), [-999, -12345678.9, b"???"])
+ #.....One-field-only flexible type should work as well
+ ndtype = [("a", int)]
+ fval = _check_fill_value(-999999999, ndtype)
+ assert_(isinstance(fval, ndarray))
+ assert_equal(fval.item(), (-999999999,))
+
+ def test_fillvalue_conversion(self):
+ # Tests the behavior of fill_value during conversion
+ # We had a tailored comment to make sure special attributes are
+ # properly dealt with
+ a = array([b'3', b'4', b'5'])
+ a._optinfo.update({'comment':"updated!"})
+
+ b = array(a, dtype=int)
+ assert_equal(b._data, [3, 4, 5])
+ assert_equal(b.fill_value, default_fill_value(0))
+
+ b = array(a, dtype=float)
+ assert_equal(b._data, [3, 4, 5])
+ assert_equal(b.fill_value, default_fill_value(0.))
+
+ b = a.astype(int)
+ assert_equal(b._data, [3, 4, 5])
+ assert_equal(b.fill_value, default_fill_value(0))
+ assert_equal(b._optinfo['comment'], "updated!")
+
+ b = a.astype([('a', '|S3')])
+ assert_equal(b['a']._data, a._data)
+ assert_equal(b['a'].fill_value, a.fill_value)
+
+ def test_default_fill_value(self):
+ # check all calling conventions
+ f1 = default_fill_value(1.)
+ f2 = default_fill_value(np.array(1.))
+ f3 = default_fill_value(np.array(1.).dtype)
+ assert_equal(f1, f2)
+ assert_equal(f1, f3)
+
+ def test_default_fill_value_structured(self):
+ fields = array([(1, 1, 1)],
+ dtype=[('i', int), ('s', '|S8'), ('f', float)])
+
+ f1 = default_fill_value(fields)
+ f2 = default_fill_value(fields.dtype)
+ expected = np.array((default_fill_value(0),
+ default_fill_value('0'),
+ default_fill_value(0.)), dtype=fields.dtype)
+ assert_equal(f1, expected)
+ assert_equal(f2, expected)
+
+ def test_default_fill_value_void(self):
+ dt = np.dtype([('v', 'V7')])
+ f = default_fill_value(dt)
+ assert_equal(f['v'], np.array(default_fill_value(dt['v']), dt['v']))
+
+ def test_fillvalue(self):
+ # Yet more fun with the fill_value
+ data = masked_array([1, 2, 3], fill_value=-999)
+ series = data[[0, 2, 1]]
+ assert_equal(series._fill_value, data._fill_value)
+
+ mtype = [('f', float), ('s', '|S3')]
+ x = array([(1, 'a'), (2, 'b'), (pi, 'pi')], dtype=mtype)
+ x.fill_value = 999
+ assert_equal(x.fill_value.item(), [999., b'999'])
+ assert_equal(x['f'].fill_value, 999)
+ assert_equal(x['s'].fill_value, b'999')
+
+ x.fill_value = (9, '???')
+ assert_equal(x.fill_value.item(), (9, b'???'))
+ assert_equal(x['f'].fill_value, 9)
+ assert_equal(x['s'].fill_value, b'???')
+
+ x = array([1, 2, 3.1])
+ x.fill_value = 999
+ assert_equal(np.asarray(x.fill_value).dtype, float)
+ assert_equal(x.fill_value, 999.)
+ assert_equal(x._fill_value, np.array(999.))
+
+ def test_subarray_fillvalue(self):
+ # gh-10483 test multi-field index fill value
+ fields = array([(1, 1, 1)],
+ dtype=[('i', int), ('s', '|S8'), ('f', float)])
+ with suppress_warnings() as sup:
+ sup.filter(FutureWarning, "Numpy has detected")
+ subfields = fields[['i', 'f']]
+ assert_equal(tuple(subfields.fill_value), (999999, 1.e+20))
+ # test comparison does not raise:
+ subfields[1:] == subfields[:-1]
+
+ def test_fillvalue_exotic_dtype(self):
+ # Tests yet more exotic flexible dtypes
+ _check_fill_value = np.ma.core._check_fill_value
+ ndtype = [('i', int), ('s', '|S8'), ('f', float)]
+ control = np.array((default_fill_value(0),
+ default_fill_value('0'),
+ default_fill_value(0.),),
+ dtype=ndtype)
+ assert_equal(_check_fill_value(None, ndtype), control)
+ # The shape shouldn't matter
+ ndtype = [('f0', float, (2, 2))]
+ control = np.array((default_fill_value(0.),),
+ dtype=[('f0', float)]).astype(ndtype)
+ assert_equal(_check_fill_value(None, ndtype), control)
+ control = np.array((0,), dtype=[('f0', float)]).astype(ndtype)
+ assert_equal(_check_fill_value(0, ndtype), control)
+
+ ndtype = np.dtype("int, (2,3)float, float")
+ control = np.array((default_fill_value(0),
+ default_fill_value(0.),
+ default_fill_value(0.),),
+ dtype="int, float, float").astype(ndtype)
+ test = _check_fill_value(None, ndtype)
+ assert_equal(test, control)
+ control = np.array((0, 0, 0), dtype="int, float, float").astype(ndtype)
+ assert_equal(_check_fill_value(0, ndtype), control)
+ # but when indexing, fill value should become scalar not tuple
+ # See issue #6723
+ M = masked_array(control)
+ assert_equal(M["f1"].fill_value.ndim, 0)
+
+ def test_fillvalue_datetime_timedelta(self):
+ # Test default fillvalue for datetime64 and timedelta64 types.
+ # See issue #4476, this would return '?' which would cause errors
+ # elsewhere
+
+ for timecode in ("as", "fs", "ps", "ns", "us", "ms", "s", "m",
+ "h", "D", "W", "M", "Y"):
+ control = numpy.datetime64("NaT", timecode)
+ test = default_fill_value(numpy.dtype("<M8[" + timecode + "]"))
+ np.testing.assert_equal(test, control)
+
+ control = numpy.timedelta64("NaT", timecode)
+ test = default_fill_value(numpy.dtype("<m8[" + timecode + "]"))
+ np.testing.assert_equal(test, control)
+
+ def test_extremum_fill_value(self):
+ # Tests extremum fill values for flexible type.
+ a = array([(1, (2, 3)), (4, (5, 6))],
+ dtype=[('A', int), ('B', [('BA', int), ('BB', int)])])
+ test = a.fill_value
+ assert_equal(test.dtype, a.dtype)
+ assert_equal(test['A'], default_fill_value(a['A']))
+ assert_equal(test['B']['BA'], default_fill_value(a['B']['BA']))
+ assert_equal(test['B']['BB'], default_fill_value(a['B']['BB']))
+
+ test = minimum_fill_value(a)
+ assert_equal(test.dtype, a.dtype)
+ assert_equal(test[0], minimum_fill_value(a['A']))
+ assert_equal(test[1][0], minimum_fill_value(a['B']['BA']))
+ assert_equal(test[1][1], minimum_fill_value(a['B']['BB']))
+ assert_equal(test[1], minimum_fill_value(a['B']))
+
+ test = maximum_fill_value(a)
+ assert_equal(test.dtype, a.dtype)
+ assert_equal(test[0], maximum_fill_value(a['A']))
+ assert_equal(test[1][0], maximum_fill_value(a['B']['BA']))
+ assert_equal(test[1][1], maximum_fill_value(a['B']['BB']))
+ assert_equal(test[1], maximum_fill_value(a['B']))
+
+ def test_extremum_fill_value_subdtype(self):
+ a = array(([2, 3, 4],), dtype=[('value', np.int8, 3)])
+
+ test = minimum_fill_value(a)
+ assert_equal(test.dtype, a.dtype)
+ assert_equal(test[0], np.full(3, minimum_fill_value(a['value'])))
+
+ test = maximum_fill_value(a)
+ assert_equal(test.dtype, a.dtype)
+ assert_equal(test[0], np.full(3, maximum_fill_value(a['value'])))
+
+ def test_fillvalue_individual_fields(self):
+ # Test setting fill_value on individual fields
+ ndtype = [('a', int), ('b', int)]
+ # Explicit fill_value
+ a = array(list(zip([1, 2, 3], [4, 5, 6])),
+ fill_value=(-999, -999), dtype=ndtype)
+ aa = a['a']
+ aa.set_fill_value(10)
+ assert_equal(aa._fill_value, np.array(10))
+ assert_equal(tuple(a.fill_value), (10, -999))
+ a.fill_value['b'] = -10
+ assert_equal(tuple(a.fill_value), (10, -10))
+ # Implicit fill_value
+ t = array(list(zip([1, 2, 3], [4, 5, 6])), dtype=ndtype)
+ tt = t['a']
+ tt.set_fill_value(10)
+ assert_equal(tt._fill_value, np.array(10))
+ assert_equal(tuple(t.fill_value), (10, default_fill_value(0)))
+
+ def test_fillvalue_implicit_structured_array(self):
+ # Check that fill_value is always defined for structured arrays
+ ndtype = ('b', float)
+ adtype = ('a', float)
+ a = array([(1.,), (2.,)], mask=[(False,), (False,)],
+ fill_value=(np.nan,), dtype=np.dtype([adtype]))
+ b = empty(a.shape, dtype=[adtype, ndtype])
+ b['a'] = a['a']
+ b['a'].set_fill_value(a['a'].fill_value)
+ f = b._fill_value[()]
+ assert_(np.isnan(f[0]))
+ assert_equal(f[-1], default_fill_value(1.))
+
+ def test_fillvalue_as_arguments(self):
+ # Test adding a fill_value parameter to empty/ones/zeros
+ a = empty(3, fill_value=999.)
+ assert_equal(a.fill_value, 999.)
+
+ a = ones(3, fill_value=999., dtype=float)
+ assert_equal(a.fill_value, 999.)
+
+ a = zeros(3, fill_value=0., dtype=complex)
+ assert_equal(a.fill_value, 0.)
+
+ a = identity(3, fill_value=0., dtype=complex)
+ assert_equal(a.fill_value, 0.)
+
+ def test_shape_argument(self):
+ # Test that shape can be provides as an argument
+ # GH issue 6106
+ a = empty(shape=(3, ))
+ assert_equal(a.shape, (3, ))
+
+ a = ones(shape=(3, ), dtype=float)
+ assert_equal(a.shape, (3, ))
+
+ a = zeros(shape=(3, ), dtype=complex)
+ assert_equal(a.shape, (3, ))
+
+ 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 overridden with view
+ y = x.view(MaskedArray, fill_value=2)
+ assert_(y.fill_value == 2)
+
+ # Check that fill_value can be overridden 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)
+
+ def test_fillvalue_bytes_or_str(self):
+ # Test whether fill values work as expected for structured dtypes
+ # containing bytes or str. See issue #7259.
+ a = empty(shape=(3, ), dtype="(2)3S,(2)3U")
+ assert_equal(a["f0"].fill_value, default_fill_value(b"spam"))
+ assert_equal(a["f1"].fill_value, default_fill_value("eggs"))
+
+
+class TestUfuncs:
+ # Test class for the application of ufuncs on MaskedArrays.
+
+ def setup_method(self):
+ # Base data definition.
+ self.d = (array([1.0, 0, -1, pi / 2] * 2, mask=[0, 1] + [0] * 6),
+ array([1.0, 0, -1, pi / 2] * 2, mask=[1, 0] + [0] * 6),)
+ self.err_status = np.geterr()
+ np.seterr(divide='ignore', invalid='ignore')
+
+ def teardown_method(self):
+ np.seterr(**self.err_status)
+
+ def test_testUfuncRegression(self):
+ # Tests new ufuncs on MaskedArrays.
+ for f in ['sqrt', 'log', 'log10', 'exp', 'conjugate',
+ 'sin', 'cos', 'tan',
+ 'arcsin', 'arccos', 'arctan',
+ 'sinh', 'cosh', 'tanh',
+ 'arcsinh',
+ 'arccosh',
+ 'arctanh',
+ 'absolute', 'fabs', 'negative',
+ 'floor', 'ceil',
+ 'logical_not',
+ 'add', 'subtract', 'multiply',
+ 'divide', 'true_divide', 'floor_divide',
+ 'remainder', 'fmod', 'hypot', 'arctan2',
+ 'equal', 'not_equal', 'less_equal', 'greater_equal',
+ 'less', 'greater',
+ 'logical_and', 'logical_or', 'logical_xor',
+ ]:
+ try:
+ uf = getattr(umath, f)
+ except AttributeError:
+ uf = getattr(fromnumeric, f)
+ mf = getattr(numpy.ma.core, f)
+ args = self.d[:uf.nin]
+ ur = uf(*args)
+ mr = mf(*args)
+ assert_equal(ur.filled(0), mr.filled(0), f)
+ assert_mask_equal(ur.mask, mr.mask, err_msg=f)
+
+ def test_reduce(self):
+ # Tests reduce on MaskedArrays.
+ a = self.d[0]
+ assert_(not alltrue(a, axis=0))
+ assert_(sometrue(a, axis=0))
+ assert_equal(sum(a[:3], axis=0), 0)
+ assert_equal(product(a, axis=0), 0)
+ assert_equal(add.reduce(a), pi)
+
+ def test_minmax(self):
+ # Tests extrema on MaskedArrays.
+ a = arange(1, 13).reshape(3, 4)
+ amask = masked_where(a < 5, a)
+ assert_equal(amask.max(), a.max())
+ assert_equal(amask.min(), 5)
+ assert_equal(amask.max(0), a.max(0))
+ assert_equal(amask.min(0), [5, 6, 7, 8])
+ assert_(amask.max(1)[0].mask)
+ assert_(amask.min(1)[0].mask)
+
+ def test_ndarray_mask(self):
+ # Check that the mask of the result is a ndarray (not a MaskedArray...)
+ a = masked_array([-1, 0, 1, 2, 3], mask=[0, 0, 0, 0, 1])
+ test = np.sqrt(a)
+ control = masked_array([-1, 0, 1, np.sqrt(2), -1],
+ mask=[1, 0, 0, 0, 1])
+ assert_equal(test, control)
+ assert_equal(test.mask, control.mask)
+ assert_(not isinstance(test.mask, MaskedArray))
+
+ def test_treatment_of_NotImplemented(self):
+ # Check that NotImplemented is returned at appropriate places
+
+ a = masked_array([1., 2.], mask=[1, 0])
+ assert_raises(TypeError, operator.mul, a, "abc")
+ assert_raises(TypeError, operator.truediv, a, "abc")
+
+ class MyClass:
+ __array_priority__ = a.__array_priority__ + 1
+
+ def __mul__(self, other):
+ return "My mul"
+
+ def __rmul__(self, other):
+ return "My rmul"
+
+ me = MyClass()
+ assert_(me * a == "My mul")
+ assert_(a * me == "My rmul")
+
+ # and that __array_priority__ is respected
+ class MyClass2:
+ __array_priority__ = 100
+
+ def __mul__(self, other):
+ return "Me2mul"
+
+ def __rmul__(self, other):
+ return "Me2rmul"
+
+ def __rdiv__(self, other):
+ return "Me2rdiv"
+
+ __rtruediv__ = __rdiv__
+
+ me_too = MyClass2()
+ assert_(a.__mul__(me_too) is NotImplemented)
+ assert_(all(multiply.outer(a, me_too) == "Me2rmul"))
+ assert_(a.__truediv__(me_too) is NotImplemented)
+ assert_(me_too * a == "Me2mul")
+ assert_(a * me_too == "Me2rmul")
+ assert_(a / me_too == "Me2rdiv")
+
+ def test_no_masked_nan_warnings(self):
+ # check that a nan in masked position does not
+ # cause ufunc warnings
+
+ m = np.ma.array([0.5, np.nan], mask=[0,1])
+
+ with warnings.catch_warnings():
+ warnings.filterwarnings("error")
+
+ # test unary and binary ufuncs
+ exp(m)
+ add(m, 1)
+ m > 0
+
+ # test different unary domains
+ sqrt(m)
+ log(m)
+ tan(m)
+ arcsin(m)
+ arccos(m)
+ arccosh(m)
+
+ # test binary domains
+ divide(m, 2)
+
+ # also check that allclose uses ma ufuncs, to avoid warning
+ allclose(m, 0.5)
+
+class TestMaskedArrayInPlaceArithmetic:
+ # Test MaskedArray Arithmetic
+
+ def setup_method(self):
+ x = arange(10)
+ y = arange(10)
+ xm = arange(10)
+ xm[2] = masked
+ self.intdata = (x, y, xm)
+ self.floatdata = (x.astype(float), y.astype(float), xm.astype(float))
+ self.othertypes = np.typecodes['AllInteger'] + np.typecodes['AllFloat']
+ self.othertypes = [np.dtype(_).type for _ in self.othertypes]
+ self.uint8data = (
+ x.astype(np.uint8),
+ y.astype(np.uint8),
+ xm.astype(np.uint8)
+ )
+
+ def test_inplace_addition_scalar(self):
+ # Test of inplace additions
+ (x, y, xm) = self.intdata
+ xm[2] = masked
+ x += 1
+ assert_equal(x, y + 1)
+ xm += 1
+ assert_equal(xm, y + 1)
+
+ (x, _, xm) = self.floatdata
+ id1 = x.data.ctypes.data
+ x += 1.
+ assert_(id1 == x.data.ctypes.data)
+ assert_equal(x, y + 1.)
+
+ def test_inplace_addition_array(self):
+ # Test of inplace additions
+ (x, y, xm) = self.intdata
+ m = xm.mask
+ a = arange(10, dtype=np.int16)
+ a[-1] = masked
+ x += a
+ xm += a
+ assert_equal(x, y + a)
+ assert_equal(xm, y + a)
+ assert_equal(xm.mask, mask_or(m, a.mask))
+
+ def test_inplace_subtraction_scalar(self):
+ # Test of inplace subtractions
+ (x, y, xm) = self.intdata
+ x -= 1
+ assert_equal(x, y - 1)
+ xm -= 1
+ assert_equal(xm, y - 1)
+
+ def test_inplace_subtraction_array(self):
+ # Test of inplace subtractions
+ (x, y, xm) = self.floatdata
+ m = xm.mask
+ a = arange(10, dtype=float)
+ a[-1] = masked
+ x -= a
+ xm -= a
+ assert_equal(x, y - a)
+ assert_equal(xm, y - a)
+ assert_equal(xm.mask, mask_or(m, a.mask))
+
+ def test_inplace_multiplication_scalar(self):
+ # Test of inplace multiplication
+ (x, y, xm) = self.floatdata
+ x *= 2.0
+ assert_equal(x, y * 2)
+ xm *= 2.0
+ assert_equal(xm, y * 2)
+
+ def test_inplace_multiplication_array(self):
+ # Test of inplace multiplication
+ (x, y, xm) = self.floatdata
+ m = xm.mask
+ a = arange(10, dtype=float)
+ a[-1] = masked
+ x *= a
+ xm *= a
+ assert_equal(x, y * a)
+ assert_equal(xm, y * a)
+ assert_equal(xm.mask, mask_or(m, a.mask))
+
+ def test_inplace_division_scalar_int(self):
+ # Test of inplace division
+ (x, y, xm) = self.intdata
+ x = arange(10) * 2
+ xm = arange(10) * 2
+ xm[2] = masked
+ x //= 2
+ assert_equal(x, y)
+ xm //= 2
+ assert_equal(xm, y)
+
+ def test_inplace_division_scalar_float(self):
+ # Test of inplace division
+ (x, y, xm) = self.floatdata
+ x /= 2.0
+ assert_equal(x, y / 2.0)
+ xm /= arange(10)
+ assert_equal(xm, ones((10,)))
+
+ def test_inplace_division_array_float(self):
+ # Test of inplace division
+ (x, y, xm) = self.floatdata
+ m = xm.mask
+ a = arange(10, dtype=float)
+ a[-1] = masked
+ x /= a
+ xm /= a
+ assert_equal(x, y / a)
+ assert_equal(xm, y / a)
+ assert_equal(xm.mask, mask_or(mask_or(m, a.mask), (a == 0)))
+
+ def test_inplace_division_misc(self):
+
+ x = [1., 1., 1., -2., pi / 2., 4., 5., -10., 10., 1., 2., 3.]
+ y = [5., 0., 3., 2., -1., -4., 0., -10., 10., 1., 0., 3.]
+ m1 = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
+ m2 = [0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1]
+ xm = masked_array(x, mask=m1)
+ ym = masked_array(y, mask=m2)
+
+ z = xm / ym
+ assert_equal(z._mask, [1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1])
+ assert_equal(z._data,
+ [1., 1., 1., -1., -pi / 2., 4., 5., 1., 1., 1., 2., 3.])
+
+ xm = xm.copy()
+ xm /= ym
+ assert_equal(xm._mask, [1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1])
+ assert_equal(z._data,
+ [1., 1., 1., -1., -pi / 2., 4., 5., 1., 1., 1., 2., 3.])
+
+ def test_datafriendly_add(self):
+ # Test keeping data w/ (inplace) addition
+ x = array([1, 2, 3], mask=[0, 0, 1])
+ # Test add w/ scalar
+ xx = x + 1
+ assert_equal(xx.data, [2, 3, 3])
+ assert_equal(xx.mask, [0, 0, 1])
+ # Test iadd w/ scalar
+ x += 1
+ assert_equal(x.data, [2, 3, 3])
+ assert_equal(x.mask, [0, 0, 1])
+ # Test add w/ array
+ x = array([1, 2, 3], mask=[0, 0, 1])
+ xx = x + array([1, 2, 3], mask=[1, 0, 0])
+ assert_equal(xx.data, [1, 4, 3])
+ assert_equal(xx.mask, [1, 0, 1])
+ # Test iadd w/ array
+ x = array([1, 2, 3], mask=[0, 0, 1])
+ x += array([1, 2, 3], mask=[1, 0, 0])
+ assert_equal(x.data, [1, 4, 3])
+ assert_equal(x.mask, [1, 0, 1])
+
+ def test_datafriendly_sub(self):
+ # Test keeping data w/ (inplace) subtraction
+ # Test sub w/ scalar
+ x = array([1, 2, 3], mask=[0, 0, 1])
+ xx = x - 1
+ assert_equal(xx.data, [0, 1, 3])
+ assert_equal(xx.mask, [0, 0, 1])
+ # Test isub w/ scalar
+ x = array([1, 2, 3], mask=[0, 0, 1])
+ x -= 1
+ assert_equal(x.data, [0, 1, 3])
+ assert_equal(x.mask, [0, 0, 1])
+ # Test sub w/ array
+ x = array([1, 2, 3], mask=[0, 0, 1])
+ xx = x - array([1, 2, 3], mask=[1, 0, 0])
+ assert_equal(xx.data, [1, 0, 3])
+ assert_equal(xx.mask, [1, 0, 1])
+ # Test isub w/ array
+ x = array([1, 2, 3], mask=[0, 0, 1])
+ x -= array([1, 2, 3], mask=[1, 0, 0])
+ assert_equal(x.data, [1, 0, 3])
+ assert_equal(x.mask, [1, 0, 1])
+
+ def test_datafriendly_mul(self):
+ # Test keeping data w/ (inplace) multiplication
+ # Test mul w/ scalar
+ x = array([1, 2, 3], mask=[0, 0, 1])
+ xx = x * 2
+ assert_equal(xx.data, [2, 4, 3])
+ assert_equal(xx.mask, [0, 0, 1])
+ # Test imul w/ scalar
+ x = array([1, 2, 3], mask=[0, 0, 1])
+ x *= 2
+ assert_equal(x.data, [2, 4, 3])
+ assert_equal(x.mask, [0, 0, 1])
+ # Test mul w/ array
+ x = array([1, 2, 3], mask=[0, 0, 1])
+ xx = x * array([10, 20, 30], mask=[1, 0, 0])
+ assert_equal(xx.data, [1, 40, 3])
+ assert_equal(xx.mask, [1, 0, 1])
+ # Test imul w/ array
+ x = array([1, 2, 3], mask=[0, 0, 1])
+ x *= array([10, 20, 30], mask=[1, 0, 0])
+ assert_equal(x.data, [1, 40, 3])
+ assert_equal(x.mask, [1, 0, 1])
+
+ def test_datafriendly_div(self):
+ # Test keeping data w/ (inplace) division
+ # Test div on scalar
+ x = array([1, 2, 3], mask=[0, 0, 1])
+ xx = x / 2.
+ assert_equal(xx.data, [1 / 2., 2 / 2., 3])
+ assert_equal(xx.mask, [0, 0, 1])
+ # Test idiv on scalar
+ x = array([1., 2., 3.], mask=[0, 0, 1])
+ x /= 2.
+ assert_equal(x.data, [1 / 2., 2 / 2., 3])
+ assert_equal(x.mask, [0, 0, 1])
+ # Test div on array
+ x = array([1., 2., 3.], mask=[0, 0, 1])
+ xx = x / array([10., 20., 30.], mask=[1, 0, 0])
+ assert_equal(xx.data, [1., 2. / 20., 3.])
+ assert_equal(xx.mask, [1, 0, 1])
+ # Test idiv on array
+ x = array([1., 2., 3.], mask=[0, 0, 1])
+ x /= array([10., 20., 30.], mask=[1, 0, 0])
+ assert_equal(x.data, [1., 2 / 20., 3.])
+ assert_equal(x.mask, [1, 0, 1])
+
+ def test_datafriendly_pow(self):
+ # Test keeping data w/ (inplace) power
+ # Test pow on scalar
+ x = array([1., 2., 3.], mask=[0, 0, 1])
+ xx = x ** 2.5
+ assert_equal(xx.data, [1., 2. ** 2.5, 3.])
+ assert_equal(xx.mask, [0, 0, 1])
+ # Test ipow on scalar
+ x **= 2.5
+ assert_equal(x.data, [1., 2. ** 2.5, 3])
+ assert_equal(x.mask, [0, 0, 1])
+
+ def test_datafriendly_add_arrays(self):
+ a = array([[1, 1], [3, 3]])
+ b = array([1, 1], mask=[0, 0])
+ a += b
+ assert_equal(a, [[2, 2], [4, 4]])
+ if a.mask is not nomask:
+ assert_equal(a.mask, [[0, 0], [0, 0]])
+
+ a = array([[1, 1], [3, 3]])
+ b = array([1, 1], mask=[0, 1])
+ a += b
+ assert_equal(a, [[2, 2], [4, 4]])
+ assert_equal(a.mask, [[0, 1], [0, 1]])
+
+ def test_datafriendly_sub_arrays(self):
+ a = array([[1, 1], [3, 3]])
+ b = array([1, 1], mask=[0, 0])
+ a -= b
+ assert_equal(a, [[0, 0], [2, 2]])
+ if a.mask is not nomask:
+ assert_equal(a.mask, [[0, 0], [0, 0]])
+
+ a = array([[1, 1], [3, 3]])
+ b = array([1, 1], mask=[0, 1])
+ a -= b
+ assert_equal(a, [[0, 0], [2, 2]])
+ assert_equal(a.mask, [[0, 1], [0, 1]])
+
+ def test_datafriendly_mul_arrays(self):
+ a = array([[1, 1], [3, 3]])
+ b = array([1, 1], mask=[0, 0])
+ a *= b
+ assert_equal(a, [[1, 1], [3, 3]])
+ if a.mask is not nomask:
+ assert_equal(a.mask, [[0, 0], [0, 0]])
+
+ a = array([[1, 1], [3, 3]])
+ b = array([1, 1], mask=[0, 1])
+ a *= b
+ assert_equal(a, [[1, 1], [3, 3]])
+ assert_equal(a.mask, [[0, 1], [0, 1]])
+
+ def test_inplace_addition_scalar_type(self):
+ # Test of inplace additions
+ for t in self.othertypes:
+ with warnings.catch_warnings():
+ warnings.filterwarnings("error")
+ (x, y, xm) = (_.astype(t) for _ in self.uint8data)
+ xm[2] = masked
+ x += t(1)
+ assert_equal(x, y + t(1))
+ xm += t(1)
+ assert_equal(xm, y + t(1))
+
+ def test_inplace_addition_array_type(self):
+ # Test of inplace additions
+ for t in self.othertypes:
+ with warnings.catch_warnings():
+ warnings.filterwarnings("error")
+ (x, y, xm) = (_.astype(t) for _ in self.uint8data)
+ m = xm.mask
+ a = arange(10, dtype=t)
+ a[-1] = masked
+ x += a
+ xm += a
+ assert_equal(x, y + a)
+ assert_equal(xm, y + a)
+ assert_equal(xm.mask, mask_or(m, a.mask))
+
+ def test_inplace_subtraction_scalar_type(self):
+ # Test of inplace subtractions
+ for t in self.othertypes:
+ with warnings.catch_warnings():
+ warnings.filterwarnings("error")
+ (x, y, xm) = (_.astype(t) for _ in self.uint8data)
+ x -= t(1)
+ assert_equal(x, y - t(1))
+ xm -= t(1)
+ assert_equal(xm, y - t(1))
+
+ def test_inplace_subtraction_array_type(self):
+ # Test of inplace subtractions
+ for t in self.othertypes:
+ with warnings.catch_warnings():
+ warnings.filterwarnings("error")
+ (x, y, xm) = (_.astype(t) for _ in self.uint8data)
+ m = xm.mask
+ a = arange(10, dtype=t)
+ a[-1] = masked
+ x -= a
+ xm -= a
+ assert_equal(x, y - a)
+ assert_equal(xm, y - a)
+ assert_equal(xm.mask, mask_or(m, a.mask))
+
+ def test_inplace_multiplication_scalar_type(self):
+ # Test of inplace multiplication
+ for t in self.othertypes:
+ with warnings.catch_warnings():
+ warnings.filterwarnings("error")
+ (x, y, xm) = (_.astype(t) for _ in self.uint8data)
+ x *= t(2)
+ assert_equal(x, y * t(2))
+ xm *= t(2)
+ assert_equal(xm, y * t(2))
+
+ def test_inplace_multiplication_array_type(self):
+ # Test of inplace multiplication
+ for t in self.othertypes:
+ with warnings.catch_warnings():
+ warnings.filterwarnings("error")
+ (x, y, xm) = (_.astype(t) for _ in self.uint8data)
+ m = xm.mask
+ a = arange(10, dtype=t)
+ a[-1] = masked
+ x *= a
+ xm *= a
+ assert_equal(x, y * a)
+ assert_equal(xm, y * a)
+ assert_equal(xm.mask, mask_or(m, a.mask))
+
+ def test_inplace_floor_division_scalar_type(self):
+ # Test of inplace division
+ # Check for TypeError in case of unsupported types
+ unsupported = {np.dtype(t).type for t in np.typecodes["Complex"]}
+ for t in self.othertypes:
+ with warnings.catch_warnings():
+ warnings.filterwarnings("error")
+ (x, y, xm) = (_.astype(t) for _ in self.uint8data)
+ x = arange(10, dtype=t) * t(2)
+ xm = arange(10, dtype=t) * t(2)
+ xm[2] = masked
+ try:
+ x //= t(2)
+ xm //= t(2)
+ assert_equal(x, y)
+ assert_equal(xm, y)
+ except TypeError:
+ msg = f"Supported type {t} throwing TypeError"
+ assert t in unsupported, msg
+
+ def test_inplace_floor_division_array_type(self):
+ # Test of inplace division
+ # Check for TypeError in case of unsupported types
+ unsupported = {np.dtype(t).type for t in np.typecodes["Complex"]}
+ for t in self.othertypes:
+ with warnings.catch_warnings():
+ warnings.filterwarnings("error")
+ (x, y, xm) = (_.astype(t) for _ in self.uint8data)
+ m = xm.mask
+ a = arange(10, dtype=t)
+ a[-1] = masked
+ try:
+ x //= a
+ xm //= a
+ assert_equal(x, y // a)
+ assert_equal(xm, y // a)
+ assert_equal(
+ xm.mask,
+ mask_or(mask_or(m, a.mask), (a == t(0)))
+ )
+ except TypeError:
+ msg = f"Supported type {t} throwing TypeError"
+ assert t in unsupported, msg
+
+ def test_inplace_division_scalar_type(self):
+ # Test of inplace division
+ for t in self.othertypes:
+ with suppress_warnings() as sup:
+ sup.record(UserWarning)
+
+ (x, y, xm) = (_.astype(t) for _ in self.uint8data)
+ x = arange(10, dtype=t) * t(2)
+ xm = arange(10, dtype=t) * t(2)
+ xm[2] = masked
+
+ # May get a DeprecationWarning or a TypeError.
+ #
+ # This is a consequence of the fact that this is true divide
+ # and will require casting to float for calculation and
+ # casting back to the original type. This will only be raised
+ # with integers. Whether it is an error or warning is only
+ # dependent on how stringent the casting rules are.
+ #
+ # Will handle the same way.
+ try:
+ x /= t(2)
+ assert_equal(x, y)
+ except (DeprecationWarning, TypeError) as e:
+ warnings.warn(str(e), stacklevel=1)
+ try:
+ xm /= t(2)
+ assert_equal(xm, y)
+ except (DeprecationWarning, TypeError) as e:
+ warnings.warn(str(e), stacklevel=1)
+
+ if issubclass(t, np.integer):
+ assert_equal(len(sup.log), 2, f'Failed on type={t}.')
+ else:
+ assert_equal(len(sup.log), 0, f'Failed on type={t}.')
+
+ def test_inplace_division_array_type(self):
+ # Test of inplace division
+ for t in self.othertypes:
+ with suppress_warnings() as sup:
+ sup.record(UserWarning)
+ (x, y, xm) = (_.astype(t) for _ in self.uint8data)
+ m = xm.mask
+ a = arange(10, dtype=t)
+ a[-1] = masked
+
+ # May get a DeprecationWarning or a TypeError.
+ #
+ # This is a consequence of the fact that this is true divide
+ # and will require casting to float for calculation and
+ # casting back to the original type. This will only be raised
+ # with integers. Whether it is an error or warning is only
+ # dependent on how stringent the casting rules are.
+ #
+ # Will handle the same way.
+ try:
+ x /= a
+ assert_equal(x, y / a)
+ except (DeprecationWarning, TypeError) as e:
+ warnings.warn(str(e), stacklevel=1)
+ try:
+ xm /= a
+ assert_equal(xm, y / a)
+ assert_equal(
+ xm.mask,
+ mask_or(mask_or(m, a.mask), (a == t(0)))
+ )
+ except (DeprecationWarning, TypeError) as e:
+ warnings.warn(str(e), stacklevel=1)
+
+ if issubclass(t, np.integer):
+ assert_equal(len(sup.log), 2, f'Failed on type={t}.')
+ else:
+ assert_equal(len(sup.log), 0, f'Failed on type={t}.')
+
+ def test_inplace_pow_type(self):
+ # Test keeping data w/ (inplace) power
+ for t in self.othertypes:
+ with warnings.catch_warnings():
+ warnings.filterwarnings("error")
+ # Test pow on scalar
+ x = array([1, 2, 3], mask=[0, 0, 1], dtype=t)
+ xx = x ** t(2)
+ xx_r = array([1, 2 ** 2, 3], mask=[0, 0, 1], dtype=t)
+ assert_equal(xx.data, xx_r.data)
+ assert_equal(xx.mask, xx_r.mask)
+ # Test ipow on scalar
+ x **= t(2)
+ assert_equal(x.data, xx_r.data)
+ assert_equal(x.mask, xx_r.mask)
+
+
+class TestMaskedArrayMethods:
+ # Test class for miscellaneous MaskedArrays methods.
+ def setup_method(self):
+ # Base data definition.
+ x = np.array([8.375, 7.545, 8.828, 8.5, 1.757, 5.928,
+ 8.43, 7.78, 9.865, 5.878, 8.979, 4.732,
+ 3.012, 6.022, 5.095, 3.116, 5.238, 3.957,
+ 6.04, 9.63, 7.712, 3.382, 4.489, 6.479,
+ 7.189, 9.645, 5.395, 4.961, 9.894, 2.893,
+ 7.357, 9.828, 6.272, 3.758, 6.693, 0.993])
+ X = x.reshape(6, 6)
+ XX = x.reshape(3, 2, 2, 3)
+
+ m = np.array([0, 1, 0, 1, 0, 0,
+ 1, 0, 1, 1, 0, 1,
+ 0, 0, 0, 1, 0, 1,
+ 0, 0, 0, 1, 1, 1,
+ 1, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 1, 0])
+ mx = array(data=x, mask=m)
+ mX = array(data=X, mask=m.reshape(X.shape))
+ mXX = array(data=XX, mask=m.reshape(XX.shape))
+
+ m2 = np.array([1, 1, 0, 1, 0, 0,
+ 1, 1, 1, 1, 0, 1,
+ 0, 0, 1, 1, 0, 1,
+ 0, 0, 0, 1, 1, 1,
+ 1, 0, 0, 1, 1, 0,
+ 0, 0, 1, 0, 1, 1])
+ m2x = array(data=x, mask=m2)
+ m2X = array(data=X, mask=m2.reshape(X.shape))
+ m2XX = array(data=XX, mask=m2.reshape(XX.shape))
+ self.d = (x, X, XX, m, mx, mX, mXX, m2x, m2X, m2XX)
+
+ def test_generic_methods(self):
+ # Tests some MaskedArray methods.
+ a = array([1, 3, 2])
+ assert_equal(a.any(), a._data.any())
+ assert_equal(a.all(), a._data.all())
+ assert_equal(a.argmax(), a._data.argmax())
+ assert_equal(a.argmin(), a._data.argmin())
+ assert_equal(a.choose(0, 1, 2, 3, 4), a._data.choose(0, 1, 2, 3, 4))
+ assert_equal(a.compress([1, 0, 1]), a._data.compress([1, 0, 1]))
+ assert_equal(a.conj(), a._data.conj())
+ assert_equal(a.conjugate(), a._data.conjugate())
+
+ m = array([[1, 2], [3, 4]])
+ assert_equal(m.diagonal(), m._data.diagonal())
+ assert_equal(a.sum(), a._data.sum())
+ assert_equal(a.take([1, 2]), a._data.take([1, 2]))
+ assert_equal(m.transpose(), m._data.transpose())
+
+ def test_allclose(self):
+ # Tests allclose on arrays
+ a = np.random.rand(10)
+ b = a + np.random.rand(10) * 1e-8
+ assert_(allclose(a, b))
+ # Test allclose w/ infs
+ a[0] = np.inf
+ assert_(not allclose(a, b))
+ b[0] = np.inf
+ assert_(allclose(a, b))
+ # Test allclose w/ masked
+ a = masked_array(a)
+ a[-1] = masked
+ assert_(allclose(a, b, masked_equal=True))
+ assert_(not allclose(a, b, masked_equal=False))
+ # Test comparison w/ scalar
+ a *= 1e-8
+ a[0] = 0
+ assert_(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_)
+ assert_(allclose(a, a))
+
+ def test_allclose_timedelta(self):
+ # Allclose currently works for timedelta64 as long as `atol` is
+ # an integer or also a timedelta64
+ a = np.array([[1, 2, 3, 4]], dtype="m8[ns]")
+ assert allclose(a, a, atol=0)
+ assert allclose(a, a, atol=np.timedelta64(1, "ns"))
+
+ def test_allany(self):
+ # Checks the any/all methods/functions.
+ x = np.array([[0.13, 0.26, 0.90],
+ [0.28, 0.33, 0.63],
+ [0.31, 0.87, 0.70]])
+ m = np.array([[True, False, False],
+ [False, False, False],
+ [True, True, False]], dtype=np.bool_)
+ mx = masked_array(x, mask=m)
+ mxbig = (mx > 0.5)
+ mxsmall = (mx < 0.5)
+
+ assert_(not mxbig.all())
+ assert_(mxbig.any())
+ assert_equal(mxbig.all(0), [False, False, True])
+ assert_equal(mxbig.all(1), [False, False, True])
+ assert_equal(mxbig.any(0), [False, False, True])
+ assert_equal(mxbig.any(1), [True, True, True])
+
+ assert_(not mxsmall.all())
+ assert_(mxsmall.any())
+ assert_equal(mxsmall.all(0), [True, True, False])
+ assert_equal(mxsmall.all(1), [False, False, False])
+ assert_equal(mxsmall.any(0), [True, True, False])
+ assert_equal(mxsmall.any(1), [True, True, False])
+
+ def test_allany_oddities(self):
+ # Some fun with all and any
+ store = empty((), dtype=bool)
+ full = array([1, 2, 3], mask=True)
+
+ assert_(full.all() is masked)
+ full.all(out=store)
+ assert_(store)
+ assert_(store._mask, True)
+ assert_(store is not masked)
+
+ store = empty((), dtype=bool)
+ assert_(full.any() is masked)
+ full.any(out=store)
+ assert_(not store)
+ assert_(store._mask, True)
+ assert_(store is not masked)
+
+ def test_argmax_argmin(self):
+ # Tests argmin & argmax on MaskedArrays.
+ (x, X, XX, m, mx, mX, mXX, m2x, m2X, m2XX) = self.d
+
+ assert_equal(mx.argmin(), 35)
+ assert_equal(mX.argmin(), 35)
+ assert_equal(m2x.argmin(), 4)
+ assert_equal(m2X.argmin(), 4)
+ assert_equal(mx.argmax(), 28)
+ assert_equal(mX.argmax(), 28)
+ assert_equal(m2x.argmax(), 31)
+ assert_equal(m2X.argmax(), 31)
+
+ assert_equal(mX.argmin(0), [2, 2, 2, 5, 0, 5])
+ assert_equal(m2X.argmin(0), [2, 2, 4, 5, 0, 4])
+ assert_equal(mX.argmax(0), [0, 5, 0, 5, 4, 0])
+ assert_equal(m2X.argmax(0), [5, 5, 0, 5, 1, 0])
+
+ assert_equal(mX.argmin(1), [4, 1, 0, 0, 5, 5, ])
+ assert_equal(m2X.argmin(1), [4, 4, 0, 0, 5, 3])
+ assert_equal(mX.argmax(1), [2, 4, 1, 1, 4, 1])
+ assert_equal(m2X.argmax(1), [2, 4, 1, 1, 1, 1])
+
+ def test_clip(self):
+ # Tests clip on MaskedArrays.
+ x = np.array([8.375, 7.545, 8.828, 8.5, 1.757, 5.928,
+ 8.43, 7.78, 9.865, 5.878, 8.979, 4.732,
+ 3.012, 6.022, 5.095, 3.116, 5.238, 3.957,
+ 6.04, 9.63, 7.712, 3.382, 4.489, 6.479,
+ 7.189, 9.645, 5.395, 4.961, 9.894, 2.893,
+ 7.357, 9.828, 6.272, 3.758, 6.693, 0.993])
+ m = np.array([0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1,
+ 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1,
+ 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0])
+ mx = array(x, mask=m)
+ clipped = mx.clip(2, 8)
+ assert_equal(clipped.mask, mx.mask)
+ assert_equal(clipped._data, x.clip(2, 8))
+ assert_equal(clipped._data, mx._data.clip(2, 8))
+
+ def test_clip_out(self):
+ # gh-14140
+ a = np.arange(10)
+ m = np.ma.MaskedArray(a, mask=[0, 1] * 5)
+ m.clip(0, 5, out=m)
+ assert_equal(m.mask, [0, 1] * 5)
+
+ def test_compress(self):
+ # test compress
+ a = masked_array([1., 2., 3., 4., 5.], fill_value=9999)
+ condition = (a > 1.5) & (a < 3.5)
+ assert_equal(a.compress(condition), [2., 3.])
+
+ a[[2, 3]] = masked
+ b = a.compress(condition)
+ assert_equal(b._data, [2., 3.])
+ assert_equal(b._mask, [0, 1])
+ assert_equal(b.fill_value, 9999)
+ assert_equal(b, a[condition])
+
+ condition = (a < 4.)
+ b = a.compress(condition)
+ assert_equal(b._data, [1., 2., 3.])
+ assert_equal(b._mask, [0, 0, 1])
+ assert_equal(b.fill_value, 9999)
+ assert_equal(b, a[condition])
+
+ a = masked_array([[10, 20, 30], [40, 50, 60]],
+ mask=[[0, 0, 1], [1, 0, 0]])
+ b = a.compress(a.ravel() >= 22)
+ assert_equal(b._data, [30, 40, 50, 60])
+ assert_equal(b._mask, [1, 1, 0, 0])
+
+ x = np.array([3, 1, 2])
+ b = a.compress(x >= 2, axis=1)
+ assert_equal(b._data, [[10, 30], [40, 60]])
+ assert_equal(b._mask, [[0, 1], [1, 0]])
+
+ def test_compressed(self):
+ # Tests compressed
+ a = array([1, 2, 3, 4], mask=[0, 0, 0, 0])
+ b = a.compressed()
+ assert_equal(b, a)
+ a[0] = masked
+ b = a.compressed()
+ assert_equal(b, [2, 3, 4])
+
+ def test_empty(self):
+ # Tests empty/like
+ datatype = [('a', int), ('b', float), ('c', '|S8')]
+ a = masked_array([(1, 1.1, '1.1'), (2, 2.2, '2.2'), (3, 3.3, '3.3')],
+ dtype=datatype)
+ assert_equal(len(a.fill_value.item()), len(datatype))
+
+ b = empty_like(a)
+ assert_equal(b.shape, a.shape)
+ assert_equal(b.fill_value, a.fill_value)
+
+ b = empty(len(a), dtype=datatype)
+ assert_equal(b.shape, a.shape)
+ assert_equal(b.fill_value, a.fill_value)
+
+ # check empty_like mask handling
+ a = masked_array([1, 2, 3], mask=[False, True, False])
+ b = empty_like(a)
+ assert_(not np.may_share_memory(a.mask, b.mask))
+ b = a.view(masked_array)
+ assert_(np.may_share_memory(a.mask, b.mask))
+
+ def test_zeros(self):
+ # Tests zeros/like
+ datatype = [('a', int), ('b', float), ('c', '|S8')]
+ a = masked_array([(1, 1.1, '1.1'), (2, 2.2, '2.2'), (3, 3.3, '3.3')],
+ dtype=datatype)
+ assert_equal(len(a.fill_value.item()), len(datatype))
+
+ b = zeros(len(a), dtype=datatype)
+ assert_equal(b.shape, a.shape)
+ assert_equal(b.fill_value, a.fill_value)
+
+ b = zeros_like(a)
+ assert_equal(b.shape, a.shape)
+ assert_equal(b.fill_value, a.fill_value)
+
+ # check zeros_like mask handling
+ a = masked_array([1, 2, 3], mask=[False, True, False])
+ b = zeros_like(a)
+ assert_(not np.may_share_memory(a.mask, b.mask))
+ b = a.view()
+ assert_(np.may_share_memory(a.mask, b.mask))
+
+ def test_ones(self):
+ # Tests ones/like
+ datatype = [('a', int), ('b', float), ('c', '|S8')]
+ a = masked_array([(1, 1.1, '1.1'), (2, 2.2, '2.2'), (3, 3.3, '3.3')],
+ dtype=datatype)
+ assert_equal(len(a.fill_value.item()), len(datatype))
+
+ b = ones(len(a), dtype=datatype)
+ assert_equal(b.shape, a.shape)
+ assert_equal(b.fill_value, a.fill_value)
+
+ b = ones_like(a)
+ assert_equal(b.shape, a.shape)
+ assert_equal(b.fill_value, a.fill_value)
+
+ # check ones_like mask handling
+ a = masked_array([1, 2, 3], mask=[False, True, False])
+ b = ones_like(a)
+ assert_(not np.may_share_memory(a.mask, b.mask))
+ b = a.view()
+ assert_(np.may_share_memory(a.mask, b.mask))
+
+ @suppress_copy_mask_on_assignment
+ def test_put(self):
+ # Tests put.
+ d = arange(5)
+ n = [0, 0, 0, 1, 1]
+ m = make_mask(n)
+ x = array(d, mask=m)
+ assert_(x[3] is masked)
+ assert_(x[4] is masked)
+ x[[1, 4]] = [10, 40]
+ assert_(x[3] is masked)
+ assert_(x[4] is not masked)
+ assert_equal(x, [0, 10, 2, -1, 40])
+
+ x = masked_array(arange(10), mask=[1, 0, 0, 0, 0] * 2)
+ i = [0, 2, 4, 6]
+ x.put(i, [6, 4, 2, 0])
+ assert_equal(x, asarray([6, 1, 4, 3, 2, 5, 0, 7, 8, 9, ]))
+ assert_equal(x.mask, [0, 0, 0, 0, 0, 1, 0, 0, 0, 0])
+ x.put(i, masked_array([0, 2, 4, 6], [1, 0, 1, 0]))
+ assert_array_equal(x, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ])
+ assert_equal(x.mask, [1, 0, 0, 0, 1, 1, 0, 0, 0, 0])
+
+ x = masked_array(arange(10), mask=[1, 0, 0, 0, 0] * 2)
+ put(x, i, [6, 4, 2, 0])
+ assert_equal(x, asarray([6, 1, 4, 3, 2, 5, 0, 7, 8, 9, ]))
+ assert_equal(x.mask, [0, 0, 0, 0, 0, 1, 0, 0, 0, 0])
+ put(x, i, masked_array([0, 2, 4, 6], [1, 0, 1, 0]))
+ assert_array_equal(x, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ])
+ assert_equal(x.mask, [1, 0, 0, 0, 1, 1, 0, 0, 0, 0])
+
+ def test_put_nomask(self):
+ # GitHub issue 6425
+ x = zeros(10)
+ z = array([3., -1.], mask=[False, True])
+
+ x.put([1, 2], z)
+ assert_(x[0] is not masked)
+ assert_equal(x[0], 0)
+ assert_(x[1] is not masked)
+ assert_equal(x[1], 3)
+ assert_(x[2] is masked)
+ assert_(x[3] is not masked)
+ assert_equal(x[3], 0)
+
+ def test_put_hardmask(self):
+ # Tests put on hardmask
+ d = arange(5)
+ n = [0, 0, 0, 1, 1]
+ m = make_mask(n)
+ xh = array(d + 1, mask=m, hard_mask=True, copy=True)
+ xh.put([4, 2, 0, 1, 3], [1, 2, 3, 4, 5])
+ assert_equal(xh._data, [3, 4, 2, 4, 5])
+
+ def test_putmask(self):
+ x = arange(6) + 1
+ mx = array(x, mask=[0, 0, 0, 1, 1, 1])
+ mask = [0, 0, 1, 0, 0, 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])
+
+ def test_ravel(self):
+ # Tests ravel
+ a = array([[1, 2, 3, 4, 5]], mask=[[0, 1, 0, 0, 0]])
+ aravel = a.ravel()
+ assert_equal(aravel._mask.shape, aravel.shape)
+ a = array([0, 0], mask=[1, 1])
+ aravel = a.ravel()
+ assert_equal(aravel._mask.shape, a.shape)
+ # Checks that small_mask is preserved
+ a = array([1, 2, 3, 4], mask=[0, 0, 0, 0], shrink=False)
+ assert_equal(a.ravel()._mask, [0, 0, 0, 0])
+ # Test that the fill_value is preserved
+ a.fill_value = -99
+ a.shape = (2, 2)
+ ar = a.ravel()
+ assert_equal(ar._mask, [0, 0, 0, 0])
+ assert_equal(ar._data, [1, 2, 3, 4])
+ assert_equal(ar.fill_value, -99)
+ # Test index ordering
+ assert_equal(a.ravel(order='C'), [1, 2, 3, 4])
+ assert_equal(a.ravel(order='F'), [1, 3, 2, 4])
+
+ @pytest.mark.parametrize("order", "AKCF")
+ @pytest.mark.parametrize("data_order", "CF")
+ def test_ravel_order(self, order, data_order):
+ # Ravelling must ravel mask and data in the same order always to avoid
+ # misaligning the two in the ravel result.
+ arr = np.ones((5, 10), order=data_order)
+ arr[0, :] = 0
+ mask = np.ones((10, 5), dtype=bool, order=data_order).T
+ mask[0, :] = False
+ x = array(arr, mask=mask)
+ assert x._data.flags.fnc != x._mask.flags.fnc
+ assert (x.filled(0) == 0).all()
+ raveled = x.ravel(order)
+ assert (raveled.filled(0) == 0).all()
+
+
+ def test_reshape(self):
+ # Tests reshape
+ x = arange(4)
+ x[0] = masked
+ y = x.reshape(2, 2)
+ assert_equal(y.shape, (2, 2,))
+ assert_equal(y._mask.shape, (2, 2,))
+ assert_equal(x.shape, (4,))
+ assert_equal(x._mask.shape, (4,))
+
+ def test_sort(self):
+ # Test sort
+ x = array([1, 4, 2, 3], mask=[0, 1, 0, 0], dtype=np.uint8)
+
+ sortedx = sort(x)
+ assert_equal(sortedx._data, [1, 2, 3, 4])
+ assert_equal(sortedx._mask, [0, 0, 0, 1])
+
+ sortedx = sort(x, endwith=False)
+ assert_equal(sortedx._data, [4, 1, 2, 3])
+ assert_equal(sortedx._mask, [1, 0, 0, 0])
+
+ x.sort()
+ assert_equal(x._data, [1, 2, 3, 4])
+ assert_equal(x._mask, [0, 0, 0, 1])
+
+ x = array([1, 4, 2, 3], mask=[0, 1, 0, 0], dtype=np.uint8)
+ x.sort(endwith=False)
+ assert_equal(x._data, [4, 1, 2, 3])
+ assert_equal(x._mask, [1, 0, 0, 0])
+
+ x = [1, 4, 2, 3]
+ sortedx = sort(x)
+ assert_(not isinstance(sorted, MaskedArray))
+
+ x = array([0, 1, -1, -2, 2], mask=nomask, dtype=np.int8)
+ sortedx = sort(x, endwith=False)
+ assert_equal(sortedx._data, [-2, -1, 0, 1, 2])
+ x = array([0, 1, -1, -2, 2], mask=[0, 1, 0, 0, 1], dtype=np.int8)
+ sortedx = sort(x, endwith=False)
+ assert_equal(sortedx._data, [1, 2, -2, -1, 0])
+ assert_equal(sortedx._mask, [1, 1, 0, 0, 0])
+
+ x = array([0, -1], dtype=np.int8)
+ sortedx = sort(x, kind="stable")
+ assert_equal(sortedx, array([-1, 0], dtype=np.int8))
+
+ def test_stable_sort(self):
+ x = array([1, 2, 3, 1, 2, 3], dtype=np.uint8)
+ expected = array([0, 3, 1, 4, 2, 5])
+ computed = argsort(x, kind='stable')
+ assert_equal(computed, expected)
+
+ def test_argsort_matches_sort(self):
+ x = array([1, 4, 2, 3], mask=[0, 1, 0, 0], dtype=np.uint8)
+
+ for kwargs in [dict(),
+ dict(endwith=True),
+ dict(endwith=False),
+ dict(fill_value=2),
+ dict(fill_value=2, endwith=True),
+ dict(fill_value=2, endwith=False)]:
+ sortedx = sort(x, **kwargs)
+ argsortedx = x[argsort(x, **kwargs)]
+ assert_equal(sortedx._data, argsortedx._data)
+ assert_equal(sortedx._mask, argsortedx._mask)
+
+ def test_sort_2d(self):
+ # Check sort of 2D array.
+ # 2D array w/o mask
+ a = masked_array([[8, 4, 1], [2, 0, 9]])
+ a.sort(0)
+ assert_equal(a, [[2, 0, 1], [8, 4, 9]])
+ a = masked_array([[8, 4, 1], [2, 0, 9]])
+ a.sort(1)
+ assert_equal(a, [[1, 4, 8], [0, 2, 9]])
+ # 2D array w/mask
+ a = masked_array([[8, 4, 1], [2, 0, 9]], mask=[[1, 0, 0], [0, 0, 1]])
+ a.sort(0)
+ assert_equal(a, [[2, 0, 1], [8, 4, 9]])
+ assert_equal(a._mask, [[0, 0, 0], [1, 0, 1]])
+ a = masked_array([[8, 4, 1], [2, 0, 9]], mask=[[1, 0, 0], [0, 0, 1]])
+ a.sort(1)
+ assert_equal(a, [[1, 4, 8], [0, 2, 9]])
+ assert_equal(a._mask, [[0, 0, 1], [0, 0, 1]])
+ # 3D
+ a = masked_array([[[7, 8, 9], [4, 5, 6], [1, 2, 3]],
+ [[1, 2, 3], [7, 8, 9], [4, 5, 6]],
+ [[7, 8, 9], [1, 2, 3], [4, 5, 6]],
+ [[4, 5, 6], [1, 2, 3], [7, 8, 9]]])
+ a[a % 4 == 0] = masked
+ am = a.copy()
+ an = a.filled(99)
+ am.sort(0)
+ an.sort(0)
+ assert_equal(am, an)
+ am = a.copy()
+ an = a.filled(99)
+ am.sort(1)
+ an.sort(1)
+ assert_equal(am, an)
+ am = a.copy()
+ an = a.filled(99)
+ am.sort(2)
+ an.sort(2)
+ assert_equal(am, an)
+
+ def test_sort_flexible(self):
+ # Test sort on structured dtype.
+ a = array(
+ data=[(3, 3), (3, 2), (2, 2), (2, 1), (1, 0), (1, 1), (1, 2)],
+ mask=[(0, 0), (0, 1), (0, 0), (0, 0), (1, 0), (0, 0), (0, 0)],
+ dtype=[('A', int), ('B', int)])
+ mask_last = array(
+ data=[(1, 1), (1, 2), (2, 1), (2, 2), (3, 3), (3, 2), (1, 0)],
+ mask=[(0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 1), (1, 0)],
+ dtype=[('A', int), ('B', int)])
+ mask_first = array(
+ data=[(1, 0), (1, 1), (1, 2), (2, 1), (2, 2), (3, 2), (3, 3)],
+ mask=[(1, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 1), (0, 0)],
+ dtype=[('A', int), ('B', int)])
+
+ test = sort(a)
+ assert_equal(test, mask_last)
+ assert_equal(test.mask, mask_last.mask)
+
+ test = sort(a, endwith=False)
+ assert_equal(test, mask_first)
+ assert_equal(test.mask, mask_first.mask)
+
+ # Test sort on dtype with subarray (gh-8069)
+ # Just check that the sort does not error, structured array subarrays
+ # are treated as byte strings and that leads to differing behavior
+ # depending on endianness and `endwith`.
+ dt = np.dtype([('v', int, 2)])
+ a = a.view(dt)
+ test = sort(a)
+ test = sort(a, endwith=False)
+
+ def test_argsort(self):
+ # Test argsort
+ a = array([1, 5, 2, 4, 3], mask=[1, 0, 0, 1, 0])
+ assert_equal(np.argsort(a), argsort(a))
+
+ def test_squeeze(self):
+ # Check squeeze
+ data = masked_array([[1, 2, 3]])
+ assert_equal(data.squeeze(), [1, 2, 3])
+ data = masked_array([[1, 2, 3]], mask=[[1, 1, 1]])
+ assert_equal(data.squeeze(), [1, 2, 3])
+ assert_equal(data.squeeze()._mask, [1, 1, 1])
+
+ # normal ndarrays return a view
+ arr = np.array([[1]])
+ arr_sq = arr.squeeze()
+ assert_equal(arr_sq, 1)
+ arr_sq[...] = 2
+ assert_equal(arr[0,0], 2)
+
+ # so maskedarrays should too
+ m_arr = masked_array([[1]], mask=True)
+ m_arr_sq = m_arr.squeeze()
+ assert_(m_arr_sq is not np.ma.masked)
+ assert_equal(m_arr_sq.mask, True)
+ m_arr_sq[...] = 2
+ assert_equal(m_arr[0,0], 2)
+
+ def test_swapaxes(self):
+ # Tests swapaxes on MaskedArrays.
+ x = np.array([8.375, 7.545, 8.828, 8.5, 1.757, 5.928,
+ 8.43, 7.78, 9.865, 5.878, 8.979, 4.732,
+ 3.012, 6.022, 5.095, 3.116, 5.238, 3.957,
+ 6.04, 9.63, 7.712, 3.382, 4.489, 6.479,
+ 7.189, 9.645, 5.395, 4.961, 9.894, 2.893,
+ 7.357, 9.828, 6.272, 3.758, 6.693, 0.993])
+ m = np.array([0, 1, 0, 1, 0, 0,
+ 1, 0, 1, 1, 0, 1,
+ 0, 0, 0, 1, 0, 1,
+ 0, 0, 0, 1, 1, 1,
+ 1, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 1, 0])
+ mX = array(x, mask=m).reshape(6, 6)
+ mXX = mX.reshape(3, 2, 2, 3)
+
+ mXswapped = mX.swapaxes(0, 1)
+ assert_equal(mXswapped[-1], mX[:, -1])
+
+ mXXswapped = mXX.swapaxes(0, 2)
+ assert_equal(mXXswapped.shape, (2, 2, 3, 3))
+
+ def test_take(self):
+ # Tests take
+ x = masked_array([10, 20, 30, 40], [0, 1, 0, 1])
+ assert_equal(x.take([0, 0, 3]), masked_array([10, 10, 40], [0, 0, 1]))
+ assert_equal(x.take([0, 0, 3]), x[[0, 0, 3]])
+ assert_equal(x.take([[0, 1], [0, 1]]),
+ masked_array([[10, 20], [10, 20]], [[0, 1], [0, 1]]))
+
+ # assert_equal crashes when passed np.ma.mask
+ assert_(x[1] is np.ma.masked)
+ assert_(x.take(1) is np.ma.masked)
+
+ x = array([[10, 20, 30], [40, 50, 60]], mask=[[0, 0, 1], [1, 0, 0, ]])
+ assert_equal(x.take([0, 2], axis=1),
+ array([[10, 30], [40, 60]], mask=[[0, 1], [1, 0]]))
+ assert_equal(take(x, [0, 2], axis=1),
+ array([[10, 30], [40, 60]], mask=[[0, 1], [1, 0]]))
+
+ def test_take_masked_indices(self):
+ # Test take w/ masked indices
+ a = np.array((40, 18, 37, 9, 22))
+ indices = np.arange(3)[None,:] + np.arange(5)[:, None]
+ mindices = array(indices, mask=(indices >= len(a)))
+ # No mask
+ test = take(a, mindices, mode='clip')
+ ctrl = array([[40, 18, 37],
+ [18, 37, 9],
+ [37, 9, 22],
+ [9, 22, 22],
+ [22, 22, 22]])
+ assert_equal(test, ctrl)
+ # Masked indices
+ test = take(a, mindices)
+ ctrl = array([[40, 18, 37],
+ [18, 37, 9],
+ [37, 9, 22],
+ [9, 22, 40],
+ [22, 40, 40]])
+ ctrl[3, 2] = ctrl[4, 1] = ctrl[4, 2] = masked
+ assert_equal(test, ctrl)
+ assert_equal(test.mask, ctrl.mask)
+ # Masked input + masked indices
+ a = array((40, 18, 37, 9, 22), mask=(0, 1, 0, 0, 0))
+ test = take(a, mindices)
+ ctrl[0, 1] = ctrl[1, 0] = masked
+ assert_equal(test, ctrl)
+ assert_equal(test.mask, ctrl.mask)
+
+ def test_tolist(self):
+ # Tests to list
+ # ... on 1D
+ x = array(np.arange(12))
+ x[[1, -2]] = masked
+ xlist = x.tolist()
+ assert_(xlist[1] is None)
+ assert_(xlist[-2] is None)
+ # ... on 2D
+ x.shape = (3, 4)
+ xlist = x.tolist()
+ ctrl = [[0, None, 2, 3], [4, 5, 6, 7], [8, 9, None, 11]]
+ assert_equal(xlist[0], [0, None, 2, 3])
+ assert_equal(xlist[1], [4, 5, 6, 7])
+ assert_equal(xlist[2], [8, 9, None, 11])
+ assert_equal(xlist, ctrl)
+ # ... on structured array w/ masked records
+ x = array(list(zip([1, 2, 3],
+ [1.1, 2.2, 3.3],
+ ['one', 'two', 'thr'])),
+ dtype=[('a', int), ('b', float), ('c', '|S8')])
+ x[-1] = masked
+ assert_equal(x.tolist(),
+ [(1, 1.1, b'one'),
+ (2, 2.2, b'two'),
+ (None, None, None)])
+ # ... on structured array w/ masked fields
+ a = array([(1, 2,), (3, 4)], mask=[(0, 1), (0, 0)],
+ dtype=[('a', int), ('b', int)])
+ test = a.tolist()
+ assert_equal(test, [[1, None], [3, 4]])
+ # ... on mvoid
+ a = a[0]
+ test = a.tolist()
+ assert_equal(test, [1, None])
+
+ def test_tolist_specialcase(self):
+ # Test mvoid.tolist: make sure we return a standard Python object
+ a = array([(0, 1), (2, 3)], dtype=[('a', int), ('b', int)])
+ # w/o mask: each entry is a np.void whose elements are standard Python
+ for entry in a:
+ for item in entry.tolist():
+ assert_(not isinstance(item, np.generic))
+ # w/ mask: each entry is a ma.void whose elements should be
+ # standard Python
+ a.mask[0] = (0, 1)
+ for entry in a:
+ for item in entry.tolist():
+ assert_(not isinstance(item, np.generic))
+
+ def test_toflex(self):
+ # Test the conversion to records
+ data = arange(10)
+ record = data.toflex()
+ assert_equal(record['_data'], data._data)
+ assert_equal(record['_mask'], data._mask)
+
+ data[[0, 1, 2, -1]] = masked
+ record = data.toflex()
+ assert_equal(record['_data'], data._data)
+ assert_equal(record['_mask'], data._mask)
+
+ ndtype = [('i', int), ('s', '|S3'), ('f', float)]
+ data = array([(i, s, f) for (i, s, f) in zip(np.arange(10),
+ 'ABCDEFGHIJKLM',
+ np.random.rand(10))],
+ dtype=ndtype)
+ data[[0, 1, 2, -1]] = masked
+ record = data.toflex()
+ assert_equal(record['_data'], data._data)
+ assert_equal(record['_mask'], data._mask)
+
+ ndtype = np.dtype("int, (2,3)float, float")
+ data = array([(i, f, ff) for (i, f, ff) in zip(np.arange(10),
+ np.random.rand(10),
+ np.random.rand(10))],
+ dtype=ndtype)
+ data[[0, 1, 2, -1]] = masked
+ record = data.toflex()
+ assert_equal_records(record['_data'], data._data)
+ assert_equal_records(record['_mask'], data._mask)
+
+ def test_fromflex(self):
+ # Test the reconstruction of a masked_array from a record
+ a = array([1, 2, 3])
+ test = fromflex(a.toflex())
+ assert_equal(test, a)
+ assert_equal(test.mask, a.mask)
+
+ a = array([1, 2, 3], mask=[0, 0, 1])
+ test = fromflex(a.toflex())
+ assert_equal(test, a)
+ assert_equal(test.mask, a.mask)
+
+ a = array([(1, 1.), (2, 2.), (3, 3.)], mask=[(1, 0), (0, 0), (0, 1)],
+ dtype=[('A', int), ('B', float)])
+ test = fromflex(a.toflex())
+ assert_equal(test, a)
+ assert_equal(test.data, a.data)
+
+ def test_arraymethod(self):
+ # Test a _arraymethod w/ n argument
+ marray = masked_array([[1, 2, 3, 4, 5]], mask=[0, 0, 1, 0, 0])
+ control = masked_array([[1], [2], [3], [4], [5]],
+ mask=[0, 0, 1, 0, 0])
+ assert_equal(marray.T, control)
+ assert_equal(marray.transpose(), control)
+
+ assert_equal(MaskedArray.cumsum(marray.T, 0), control.cumsum(0))
+
+ def test_arraymethod_0d(self):
+ # gh-9430
+ x = np.ma.array(42, mask=True)
+ assert_equal(x.T.mask, x.mask)
+ assert_equal(x.T.data, x.data)
+
+ def test_transpose_view(self):
+ x = np.ma.array([[1, 2, 3], [4, 5, 6]])
+ x[0,1] = np.ma.masked
+ xt = x.T
+
+ xt[1,0] = 10
+ xt[0,1] = np.ma.masked
+
+ assert_equal(x.data, xt.T.data)
+ assert_equal(x.mask, xt.T.mask)
+
+ def test_diagonal_view(self):
+ x = np.ma.zeros((3,3))
+ x[0,0] = 10
+ x[1,1] = np.ma.masked
+ x[2,2] = 20
+ xd = x.diagonal()
+ x[1,1] = 15
+ assert_equal(xd.mask, x.diagonal().mask)
+ assert_equal(xd.data, x.diagonal().data)
+
+
+class TestMaskedArrayMathMethods:
+
+ def setup_method(self):
+ # Base data definition.
+ x = np.array([8.375, 7.545, 8.828, 8.5, 1.757, 5.928,
+ 8.43, 7.78, 9.865, 5.878, 8.979, 4.732,
+ 3.012, 6.022, 5.095, 3.116, 5.238, 3.957,
+ 6.04, 9.63, 7.712, 3.382, 4.489, 6.479,
+ 7.189, 9.645, 5.395, 4.961, 9.894, 2.893,
+ 7.357, 9.828, 6.272, 3.758, 6.693, 0.993])
+ X = x.reshape(6, 6)
+ XX = x.reshape(3, 2, 2, 3)
+
+ m = np.array([0, 1, 0, 1, 0, 0,
+ 1, 0, 1, 1, 0, 1,
+ 0, 0, 0, 1, 0, 1,
+ 0, 0, 0, 1, 1, 1,
+ 1, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 1, 0])
+ mx = array(data=x, mask=m)
+ mX = array(data=X, mask=m.reshape(X.shape))
+ mXX = array(data=XX, mask=m.reshape(XX.shape))
+
+ m2 = np.array([1, 1, 0, 1, 0, 0,
+ 1, 1, 1, 1, 0, 1,
+ 0, 0, 1, 1, 0, 1,
+ 0, 0, 0, 1, 1, 1,
+ 1, 0, 0, 1, 1, 0,
+ 0, 0, 1, 0, 1, 1])
+ m2x = array(data=x, mask=m2)
+ m2X = array(data=X, mask=m2.reshape(X.shape))
+ m2XX = array(data=XX, mask=m2.reshape(XX.shape))
+ self.d = (x, X, XX, m, mx, mX, mXX, m2x, m2X, m2XX)
+
+ def test_cumsumprod(self):
+ # Tests cumsum & cumprod on MaskedArrays.
+ (x, X, XX, m, mx, mX, mXX, m2x, m2X, m2XX) = self.d
+ mXcp = mX.cumsum(0)
+ assert_equal(mXcp._data, mX.filled(0).cumsum(0))
+ mXcp = mX.cumsum(1)
+ assert_equal(mXcp._data, mX.filled(0).cumsum(1))
+
+ mXcp = mX.cumprod(0)
+ assert_equal(mXcp._data, mX.filled(1).cumprod(0))
+ mXcp = mX.cumprod(1)
+ assert_equal(mXcp._data, mX.filled(1).cumprod(1))
+
+ def test_cumsumprod_with_output(self):
+ # Tests cumsum/cumprod w/ output
+ xm = array(np.random.uniform(0, 10, 12)).reshape(3, 4)
+ xm[:, 0] = xm[0] = xm[-1, -1] = masked
+
+ for funcname in ('cumsum', 'cumprod'):
+ npfunc = getattr(np, funcname)
+ xmmeth = getattr(xm, funcname)
+
+ # A ndarray as explicit input
+ output = np.empty((3, 4), dtype=float)
+ output.fill(-9999)
+ result = npfunc(xm, axis=0, out=output)
+ # ... the result should be the given output
+ assert_(result is output)
+ assert_equal(result, xmmeth(axis=0, out=output))
+
+ output = empty((3, 4), dtype=int)
+ result = xmmeth(axis=0, out=output)
+ assert_(result is output)
+
+ def test_ptp(self):
+ # Tests ptp on MaskedArrays.
+ (x, X, XX, m, mx, mX, mXX, m2x, m2X, m2XX) = self.d
+ (n, m) = X.shape
+ assert_equal(mx.ptp(), mx.compressed().ptp())
+ rows = np.zeros(n, float)
+ cols = np.zeros(m, float)
+ for k in range(m):
+ cols[k] = mX[:, k].compressed().ptp()
+ for k in range(n):
+ rows[k] = mX[k].compressed().ptp()
+ assert_equal(mX.ptp(0), cols)
+ assert_equal(mX.ptp(1), rows)
+
+ def test_add_object(self):
+ x = masked_array(['a', 'b'], mask=[1, 0], dtype=object)
+ y = x + 'x'
+ assert_equal(y[1], 'bx')
+ assert_(y.mask[0])
+
+ def test_sum_object(self):
+ # Test sum on object dtype
+ a = masked_array([1, 2, 3], mask=[1, 0, 0], dtype=object)
+ assert_equal(a.sum(), 5)
+ a = masked_array([[1, 2, 3], [4, 5, 6]], dtype=object)
+ assert_equal(a.sum(axis=0), [5, 7, 9])
+
+ def test_prod_object(self):
+ # Test prod on object dtype
+ a = masked_array([1, 2, 3], mask=[1, 0, 0], dtype=object)
+ assert_equal(a.prod(), 2 * 3)
+ a = masked_array([[1, 2, 3], [4, 5, 6]], dtype=object)
+ assert_equal(a.prod(axis=0), [4, 10, 18])
+
+ def test_meananom_object(self):
+ # Test mean/anom on object dtype
+ a = masked_array([1, 2, 3], dtype=object)
+ assert_equal(a.mean(), 2)
+ assert_equal(a.anom(), [-1, 0, 1])
+
+ def test_anom_shape(self):
+ a = masked_array([1, 2, 3])
+ assert_equal(a.anom().shape, a.shape)
+ a.mask = True
+ assert_equal(a.anom().shape, a.shape)
+ assert_(np.ma.is_masked(a.anom()))
+
+ def test_anom(self):
+ a = masked_array(np.arange(1, 7).reshape(2, 3))
+ assert_almost_equal(a.anom(),
+ [[-2.5, -1.5, -0.5], [0.5, 1.5, 2.5]])
+ assert_almost_equal(a.anom(axis=0),
+ [[-1.5, -1.5, -1.5], [1.5, 1.5, 1.5]])
+ assert_almost_equal(a.anom(axis=1),
+ [[-1., 0., 1.], [-1., 0., 1.]])
+ a.mask = [[0, 0, 1], [0, 1, 0]]
+ mval = -99
+ assert_almost_equal(a.anom().filled(mval),
+ [[-2.25, -1.25, mval], [0.75, mval, 2.75]])
+ assert_almost_equal(a.anom(axis=0).filled(mval),
+ [[-1.5, 0.0, mval], [1.5, mval, 0.0]])
+ assert_almost_equal(a.anom(axis=1).filled(mval),
+ [[-0.5, 0.5, mval], [-1.0, mval, 1.0]])
+
+ def test_trace(self):
+ # Tests trace on MaskedArrays.
+ (x, X, XX, m, mx, mX, mXX, m2x, m2X, m2XX) = self.d
+ mXdiag = mX.diagonal()
+ assert_equal(mX.trace(), mX.diagonal().compressed().sum())
+ assert_almost_equal(mX.trace(),
+ X.trace() - sum(mXdiag.mask * X.diagonal(),
+ axis=0))
+ assert_equal(np.trace(mX), mX.trace())
+
+ # gh-5560
+ arr = np.arange(2*4*4).reshape(2,4,4)
+ m_arr = np.ma.masked_array(arr, False)
+ assert_equal(arr.trace(axis1=1, axis2=2), m_arr.trace(axis1=1, axis2=2))
+
+ def test_dot(self):
+ # Tests dot on MaskedArrays.
+ (x, X, XX, m, mx, mX, mXX, m2x, m2X, m2XX) = self.d
+ fx = mx.filled(0)
+ r = mx.dot(mx)
+ assert_almost_equal(r.filled(0), fx.dot(fx))
+ assert_(r.mask is nomask)
+
+ fX = mX.filled(0)
+ r = mX.dot(mX)
+ assert_almost_equal(r.filled(0), fX.dot(fX))
+ assert_(r.mask[1,3])
+ r1 = empty_like(r)
+ mX.dot(mX, out=r1)
+ assert_almost_equal(r, r1)
+
+ mYY = mXX.swapaxes(-1, -2)
+ fXX, fYY = mXX.filled(0), mYY.filled(0)
+ r = mXX.dot(mYY)
+ assert_almost_equal(r.filled(0), fXX.dot(fYY))
+ r1 = empty_like(r)
+ mXX.dot(mYY, out=r1)
+ assert_almost_equal(r, r1)
+
+ def test_dot_shape_mismatch(self):
+ # regression test
+ x = masked_array([[1,2],[3,4]], mask=[[0,1],[0,0]])
+ y = masked_array([[1,2],[3,4]], mask=[[0,1],[0,0]])
+ z = masked_array([[0,1],[3,3]])
+ x.dot(y, out=z)
+ assert_almost_equal(z.filled(0), [[1, 0], [15, 16]])
+ assert_almost_equal(z.mask, [[0, 1], [0, 0]])
+
+ def test_varmean_nomask(self):
+ # gh-5769
+ foo = array([1,2,3,4], dtype='f8')
+ bar = array([1,2,3,4], dtype='f8')
+ assert_equal(type(foo.mean()), np.float64)
+ assert_equal(type(foo.var()), np.float64)
+ assert((foo.mean() == bar.mean()) is np.bool_(True))
+
+ # check array type is preserved and out works
+ foo = array(np.arange(16).reshape((4,4)), dtype='f8')
+ bar = empty(4, dtype='f4')
+ assert_equal(type(foo.mean(axis=1)), MaskedArray)
+ assert_equal(type(foo.var(axis=1)), MaskedArray)
+ assert_(foo.mean(axis=1, out=bar) is bar)
+ assert_(foo.var(axis=1, out=bar) is bar)
+
+ def test_varstd(self):
+ # Tests var & std on MaskedArrays.
+ (x, X, XX, m, mx, mX, mXX, m2x, m2X, m2XX) = self.d
+ assert_almost_equal(mX.var(axis=None), mX.compressed().var())
+ assert_almost_equal(mX.std(axis=None), mX.compressed().std())
+ assert_almost_equal(mX.std(axis=None, ddof=1),
+ mX.compressed().std(ddof=1))
+ assert_almost_equal(mX.var(axis=None, ddof=1),
+ mX.compressed().var(ddof=1))
+ assert_equal(mXX.var(axis=3).shape, XX.var(axis=3).shape)
+ assert_equal(mX.var().shape, X.var().shape)
+ (mXvar0, mXvar1) = (mX.var(axis=0), mX.var(axis=1))
+ assert_almost_equal(mX.var(axis=None, ddof=2),
+ mX.compressed().var(ddof=2))
+ assert_almost_equal(mX.std(axis=None, ddof=2),
+ mX.compressed().std(ddof=2))
+ for k in range(6):
+ assert_almost_equal(mXvar1[k], mX[k].compressed().var())
+ assert_almost_equal(mXvar0[k], mX[:, k].compressed().var())
+ assert_almost_equal(np.sqrt(mXvar0[k]),
+ mX[:, k].compressed().std())
+
+ @suppress_copy_mask_on_assignment
+ def test_varstd_specialcases(self):
+ # Test a special case for var
+ nout = np.array(-1, dtype=float)
+ mout = array(-1, dtype=float)
+
+ x = array(arange(10), mask=True)
+ for methodname in ('var', 'std'):
+ method = getattr(x, methodname)
+ assert_(method() is masked)
+ assert_(method(0) is masked)
+ assert_(method(-1) is masked)
+ # Using a masked array as explicit output
+ method(out=mout)
+ assert_(mout is not masked)
+ assert_equal(mout.mask, True)
+ # Using a ndarray as explicit output
+ method(out=nout)
+ assert_(np.isnan(nout))
+
+ x = array(arange(10), mask=True)
+ x[-1] = 9
+ for methodname in ('var', 'std'):
+ method = getattr(x, methodname)
+ assert_(method(ddof=1) is masked)
+ assert_(method(0, ddof=1) is masked)
+ assert_(method(-1, ddof=1) is masked)
+ # Using a masked array as explicit output
+ method(out=mout, ddof=1)
+ assert_(mout is not masked)
+ assert_equal(mout.mask, True)
+ # Using a ndarray as explicit output
+ method(out=nout, ddof=1)
+ assert_(np.isnan(nout))
+
+ def test_varstd_ddof(self):
+ a = array([[1, 1, 0], [1, 1, 0]], mask=[[0, 0, 1], [0, 0, 1]])
+ test = a.std(axis=0, ddof=0)
+ assert_equal(test.filled(0), [0, 0, 0])
+ assert_equal(test.mask, [0, 0, 1])
+ test = a.std(axis=0, ddof=1)
+ assert_equal(test.filled(0), [0, 0, 0])
+ assert_equal(test.mask, [0, 0, 1])
+ test = a.std(axis=0, ddof=2)
+ assert_equal(test.filled(0), [0, 0, 0])
+ assert_equal(test.mask, [1, 1, 1])
+
+ def test_diag(self):
+ # Test diag
+ x = arange(9).reshape((3, 3))
+ x[1, 1] = masked
+ out = np.diag(x)
+ assert_equal(out, [0, 4, 8])
+ out = diag(x)
+ assert_equal(out, [0, 4, 8])
+ assert_equal(out.mask, [0, 1, 0])
+ out = diag(out)
+ control = array([[0, 0, 0], [0, 4, 0], [0, 0, 8]],
+ mask=[[0, 0, 0], [0, 1, 0], [0, 0, 0]])
+ assert_equal(out, control)
+
+ def test_axis_methods_nomask(self):
+ # Test the combination nomask & methods w/ axis
+ a = array([[1, 2, 3], [4, 5, 6]])
+
+ assert_equal(a.sum(0), [5, 7, 9])
+ assert_equal(a.sum(-1), [6, 15])
+ assert_equal(a.sum(1), [6, 15])
+
+ assert_equal(a.prod(0), [4, 10, 18])
+ assert_equal(a.prod(-1), [6, 120])
+ assert_equal(a.prod(1), [6, 120])
+
+ assert_equal(a.min(0), [1, 2, 3])
+ assert_equal(a.min(-1), [1, 4])
+ assert_equal(a.min(1), [1, 4])
+
+ assert_equal(a.max(0), [4, 5, 6])
+ assert_equal(a.max(-1), [3, 6])
+ assert_equal(a.max(1), [3, 6])
+
+ @requires_memory(free_bytes=2 * 10000 * 1000 * 2)
+ def test_mean_overflow(self):
+ # Test overflow in masked arrays
+ # gh-20272
+ a = masked_array(np.full((10000, 10000), 65535, dtype=np.uint16),
+ mask=np.zeros((10000, 10000)))
+ assert_equal(a.mean(), 65535.0)
+
+class TestMaskedArrayMathMethodsComplex:
+ # Test class for miscellaneous MaskedArrays methods.
+ def setup_method(self):
+ # Base data definition.
+ x = np.array([8.375j, 7.545j, 8.828j, 8.5j, 1.757j, 5.928,
+ 8.43, 7.78, 9.865, 5.878, 8.979, 4.732,
+ 3.012, 6.022, 5.095, 3.116, 5.238, 3.957,
+ 6.04, 9.63, 7.712, 3.382, 4.489, 6.479j,
+ 7.189j, 9.645, 5.395, 4.961, 9.894, 2.893,
+ 7.357, 9.828, 6.272, 3.758, 6.693, 0.993j])
+ X = x.reshape(6, 6)
+ XX = x.reshape(3, 2, 2, 3)
+
+ m = np.array([0, 1, 0, 1, 0, 0,
+ 1, 0, 1, 1, 0, 1,
+ 0, 0, 0, 1, 0, 1,
+ 0, 0, 0, 1, 1, 1,
+ 1, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 1, 0])
+ mx = array(data=x, mask=m)
+ mX = array(data=X, mask=m.reshape(X.shape))
+ mXX = array(data=XX, mask=m.reshape(XX.shape))
+
+ m2 = np.array([1, 1, 0, 1, 0, 0,
+ 1, 1, 1, 1, 0, 1,
+ 0, 0, 1, 1, 0, 1,
+ 0, 0, 0, 1, 1, 1,
+ 1, 0, 0, 1, 1, 0,
+ 0, 0, 1, 0, 1, 1])
+ m2x = array(data=x, mask=m2)
+ m2X = array(data=X, mask=m2.reshape(X.shape))
+ m2XX = array(data=XX, mask=m2.reshape(XX.shape))
+ self.d = (x, X, XX, m, mx, mX, mXX, m2x, m2X, m2XX)
+
+ def test_varstd(self):
+ # Tests var & std on MaskedArrays.
+ (x, X, XX, m, mx, mX, mXX, m2x, m2X, m2XX) = self.d
+ assert_almost_equal(mX.var(axis=None), mX.compressed().var())
+ assert_almost_equal(mX.std(axis=None), mX.compressed().std())
+ assert_equal(mXX.var(axis=3).shape, XX.var(axis=3).shape)
+ assert_equal(mX.var().shape, X.var().shape)
+ (mXvar0, mXvar1) = (mX.var(axis=0), mX.var(axis=1))
+ assert_almost_equal(mX.var(axis=None, ddof=2),
+ mX.compressed().var(ddof=2))
+ assert_almost_equal(mX.std(axis=None, ddof=2),
+ mX.compressed().std(ddof=2))
+ for k in range(6):
+ assert_almost_equal(mXvar1[k], mX[k].compressed().var())
+ assert_almost_equal(mXvar0[k], mX[:, k].compressed().var())
+ assert_almost_equal(np.sqrt(mXvar0[k]),
+ mX[:, k].compressed().std())
+
+
+class TestMaskedArrayFunctions:
+ # Test class for miscellaneous functions.
+
+ def setup_method(self):
+ x = np.array([1., 1., 1., -2., pi/2.0, 4., 5., -10., 10., 1., 2., 3.])
+ y = np.array([5., 0., 3., 2., -1., -4., 0., -10., 10., 1., 0., 3.])
+ m1 = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
+ m2 = [0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1]
+ xm = masked_array(x, mask=m1)
+ ym = masked_array(y, mask=m2)
+ xm.set_fill_value(1e+20)
+ self.info = (xm, ym)
+
+ def test_masked_where_bool(self):
+ x = [1, 2]
+ y = masked_where(False, x)
+ assert_equal(y, [1, 2])
+ assert_equal(y[1], 2)
+
+ def test_masked_equal_wlist(self):
+ x = [1, 2, 3]
+ mx = masked_equal(x, 3)
+ assert_equal(mx, x)
+ assert_equal(mx._mask, [0, 0, 1])
+ mx = masked_not_equal(x, 3)
+ assert_equal(mx, x)
+ assert_equal(mx._mask, [1, 1, 0])
+
+ def test_masked_equal_fill_value(self):
+ x = [1, 2, 3]
+ mx = masked_equal(x, 3)
+ assert_equal(mx._mask, [0, 0, 1])
+ assert_equal(mx.fill_value, 3)
+
+ def test_masked_where_condition(self):
+ # Tests masking functions.
+ x = array([1., 2., 3., 4., 5.])
+ x[2] = masked
+ assert_equal(masked_where(greater(x, 2), x), masked_greater(x, 2))
+ assert_equal(masked_where(greater_equal(x, 2), x),
+ masked_greater_equal(x, 2))
+ assert_equal(masked_where(less(x, 2), x), masked_less(x, 2))
+ assert_equal(masked_where(less_equal(x, 2), x),
+ masked_less_equal(x, 2))
+ assert_equal(masked_where(not_equal(x, 2), x), masked_not_equal(x, 2))
+ assert_equal(masked_where(equal(x, 2), x), masked_equal(x, 2))
+ assert_equal(masked_where(not_equal(x, 2), x), masked_not_equal(x, 2))
+ assert_equal(masked_where([1, 1, 0, 0, 0], [1, 2, 3, 4, 5]),
+ [99, 99, 3, 4, 5])
+
+ def test_masked_where_oddities(self):
+ # Tests some generic features.
+ atest = ones((10, 10, 10), dtype=float)
+ btest = zeros(atest.shape, MaskType)
+ ctest = masked_where(btest, atest)
+ assert_equal(atest, ctest)
+
+ def test_masked_where_shape_constraint(self):
+ a = arange(10)
+ with assert_raises(IndexError):
+ masked_equal(1, a)
+ test = masked_equal(a, 1)
+ assert_equal(test.mask, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0])
+
+ def test_masked_where_structured(self):
+ # test that masked_where on a structured array sets a structured
+ # mask (see issue #2972)
+ a = np.zeros(10, dtype=[("A", "<f2"), ("B", "<f4")])
+ with np.errstate(over="ignore"):
+ # NOTE: The float16 "uses" 1e20 as mask, which overflows to inf
+ # and warns. Unrelated to this test, but probably undesired.
+ # But NumPy previously did not warn for this overflow.
+ am = np.ma.masked_where(a["A"] < 5, a)
+ assert_equal(am.mask.dtype.names, am.dtype.names)
+ assert_equal(am["A"],
+ np.ma.masked_array(np.zeros(10), np.ones(10)))
+
+ def test_masked_where_mismatch(self):
+ # gh-4520
+ x = np.arange(10)
+ y = np.arange(5)
+ assert_raises(IndexError, np.ma.masked_where, y > 6, x)
+
+ def test_masked_otherfunctions(self):
+ assert_equal(masked_inside(list(range(5)), 1, 3),
+ [0, 199, 199, 199, 4])
+ assert_equal(masked_outside(list(range(5)), 1, 3), [199, 1, 2, 3, 199])
+ assert_equal(masked_inside(array(list(range(5)),
+ mask=[1, 0, 0, 0, 0]), 1, 3).mask,
+ [1, 1, 1, 1, 0])
+ assert_equal(masked_outside(array(list(range(5)),
+ mask=[0, 1, 0, 0, 0]), 1, 3).mask,
+ [1, 1, 0, 0, 1])
+ assert_equal(masked_equal(array(list(range(5)),
+ mask=[1, 0, 0, 0, 0]), 2).mask,
+ [1, 0, 1, 0, 0])
+ assert_equal(masked_not_equal(array([2, 2, 1, 2, 1],
+ mask=[1, 0, 0, 0, 0]), 2).mask,
+ [1, 0, 1, 0, 1])
+
+ def test_round(self):
+ a = array([1.23456, 2.34567, 3.45678, 4.56789, 5.67890],
+ mask=[0, 1, 0, 0, 0])
+ assert_equal(a.round(), [1., 2., 3., 5., 6.])
+ assert_equal(a.round(1), [1.2, 2.3, 3.5, 4.6, 5.7])
+ assert_equal(a.round(3), [1.235, 2.346, 3.457, 4.568, 5.679])
+ b = empty_like(a)
+ a.round(out=b)
+ assert_equal(b, [1., 2., 3., 5., 6.])
+
+ x = array([1., 2., 3., 4., 5.])
+ c = array([1, 1, 1, 0, 0])
+ x[2] = masked
+ z = where(c, x, -x)
+ assert_equal(z, [1., 2., 0., -4., -5])
+ c[0] = masked
+ z = where(c, x, -x)
+ assert_equal(z, [1., 2., 0., -4., -5])
+ assert_(z[0] is masked)
+ assert_(z[1] is not masked)
+ assert_(z[2] is masked)
+
+ def test_round_with_output(self):
+ # Testing round with an explicit output
+
+ xm = array(np.random.uniform(0, 10, 12)).reshape(3, 4)
+ xm[:, 0] = xm[0] = xm[-1, -1] = masked
+
+ # A ndarray as explicit input
+ output = np.empty((3, 4), dtype=float)
+ output.fill(-9999)
+ result = np.round(xm, decimals=2, out=output)
+ # ... the result should be the given output
+ assert_(result is output)
+ assert_equal(result, xm.round(decimals=2, out=output))
+
+ output = empty((3, 4), dtype=float)
+ result = xm.round(decimals=2, out=output)
+ assert_(result is output)
+
+ def test_round_with_scalar(self):
+ # Testing round with scalar/zero dimension input
+ # GH issue 2244
+ a = array(1.1, mask=[False])
+ assert_equal(a.round(), 1)
+
+ a = array(1.1, mask=[True])
+ assert_(a.round() is masked)
+
+ a = array(1.1, mask=[False])
+ output = np.empty(1, dtype=float)
+ output.fill(-9999)
+ a.round(out=output)
+ assert_equal(output, 1)
+
+ a = array(1.1, mask=[False])
+ output = array(-9999., mask=[True])
+ a.round(out=output)
+ assert_equal(output[()], 1)
+
+ a = array(1.1, mask=[True])
+ output = array(-9999., mask=[False])
+ a.round(out=output)
+ assert_(output[()] is masked)
+
+ def test_identity(self):
+ a = identity(5)
+ assert_(isinstance(a, MaskedArray))
+ assert_equal(a, np.identity(5))
+
+ def test_power(self):
+ x = -1.1
+ assert_almost_equal(power(x, 2.), 1.21)
+ assert_(power(x, masked) is masked)
+ x = array([-1.1, -1.1, 1.1, 1.1, 0.])
+ b = array([0.5, 2., 0.5, 2., -1.], mask=[0, 0, 0, 0, 1])
+ y = power(x, b)
+ assert_almost_equal(y, [0, 1.21, 1.04880884817, 1.21, 0.])
+ assert_equal(y._mask, [1, 0, 0, 0, 1])
+ b.mask = nomask
+ y = power(x, b)
+ assert_equal(y._mask, [1, 0, 0, 0, 1])
+ z = x ** b
+ assert_equal(z._mask, y._mask)
+ assert_almost_equal(z, y)
+ assert_almost_equal(z._data, y._data)
+ x **= b
+ assert_equal(x._mask, y._mask)
+ assert_almost_equal(x, y)
+ assert_almost_equal(x._data, y._data)
+
+ def test_power_with_broadcasting(self):
+ # Test power w/ broadcasting
+ a2 = np.array([[1., 2., 3.], [4., 5., 6.]])
+ a2m = array(a2, mask=[[1, 0, 0], [0, 0, 1]])
+ b1 = np.array([2, 4, 3])
+ b2 = np.array([b1, b1])
+ b2m = array(b2, mask=[[0, 1, 0], [0, 1, 0]])
+
+ ctrl = array([[1 ** 2, 2 ** 4, 3 ** 3], [4 ** 2, 5 ** 4, 6 ** 3]],
+ mask=[[1, 1, 0], [0, 1, 1]])
+ # No broadcasting, base & exp w/ mask
+ test = a2m ** b2m
+ assert_equal(test, ctrl)
+ assert_equal(test.mask, ctrl.mask)
+ # No broadcasting, base w/ mask, exp w/o mask
+ test = a2m ** b2
+ assert_equal(test, ctrl)
+ assert_equal(test.mask, a2m.mask)
+ # No broadcasting, base w/o mask, exp w/ mask
+ test = a2 ** b2m
+ assert_equal(test, ctrl)
+ assert_equal(test.mask, b2m.mask)
+
+ ctrl = array([[2 ** 2, 4 ** 4, 3 ** 3], [2 ** 2, 4 ** 4, 3 ** 3]],
+ mask=[[0, 1, 0], [0, 1, 0]])
+ test = b1 ** b2m
+ assert_equal(test, ctrl)
+ assert_equal(test.mask, ctrl.mask)
+ test = b2m ** b1
+ assert_equal(test, ctrl)
+ assert_equal(test.mask, ctrl.mask)
+
+ @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
+ def test_where(self):
+ # Test the where function
+ x = np.array([1., 1., 1., -2., pi/2.0, 4., 5., -10., 10., 1., 2., 3.])
+ y = np.array([5., 0., 3., 2., -1., -4., 0., -10., 10., 1., 0., 3.])
+ m1 = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
+ m2 = [0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1]
+ xm = masked_array(x, mask=m1)
+ ym = masked_array(y, mask=m2)
+ xm.set_fill_value(1e+20)
+
+ d = where(xm > 2, xm, -9)
+ assert_equal(d, [-9., -9., -9., -9., -9., 4.,
+ -9., -9., 10., -9., -9., 3.])
+ assert_equal(d._mask, xm._mask)
+ d = where(xm > 2, -9, ym)
+ assert_equal(d, [5., 0., 3., 2., -1., -9.,
+ -9., -10., -9., 1., 0., -9.])
+ assert_equal(d._mask, [1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0])
+ d = where(xm > 2, xm, masked)
+ assert_equal(d, [-9., -9., -9., -9., -9., 4.,
+ -9., -9., 10., -9., -9., 3.])
+ tmp = xm._mask.copy()
+ tmp[(xm <= 2).filled(True)] = True
+ assert_equal(d._mask, tmp)
+
+ with np.errstate(invalid="warn"):
+ # The fill value is 1e20, it cannot be converted to `int`:
+ with pytest.warns(RuntimeWarning, match="invalid value"):
+ ixm = xm.astype(int)
+ d = where(ixm > 2, ixm, masked)
+ assert_equal(d, [-9, -9, -9, -9, -9, 4, -9, -9, 10, -9, -9, 3])
+ assert_equal(d.dtype, ixm.dtype)
+
+ def test_where_object(self):
+ a = np.array(None)
+ b = masked_array(None)
+ r = b.copy()
+ assert_equal(np.ma.where(True, a, a), r)
+ assert_equal(np.ma.where(True, b, b), r)
+
+ def test_where_with_masked_choice(self):
+ x = arange(10)
+ x[3] = masked
+ c = x >= 8
+ # Set False to masked
+ z = where(c, x, masked)
+ assert_(z.dtype is x.dtype)
+ assert_(z[3] is masked)
+ assert_(z[4] is masked)
+ assert_(z[7] is masked)
+ assert_(z[8] is not masked)
+ assert_(z[9] is not masked)
+ assert_equal(x, z)
+ # Set True to masked
+ z = where(c, masked, x)
+ assert_(z.dtype is x.dtype)
+ assert_(z[3] is masked)
+ assert_(z[4] is not masked)
+ assert_(z[7] is not masked)
+ assert_(z[8] is masked)
+ assert_(z[9] is masked)
+
+ def test_where_with_masked_condition(self):
+ x = array([1., 2., 3., 4., 5.])
+ c = array([1, 1, 1, 0, 0])
+ x[2] = masked
+ z = where(c, x, -x)
+ assert_equal(z, [1., 2., 0., -4., -5])
+ c[0] = masked
+ z = where(c, x, -x)
+ assert_equal(z, [1., 2., 0., -4., -5])
+ assert_(z[0] is masked)
+ assert_(z[1] is not masked)
+ assert_(z[2] is masked)
+
+ x = arange(1, 6)
+ x[-1] = masked
+ y = arange(1, 6) * 10
+ y[2] = masked
+ c = array([1, 1, 1, 0, 0], mask=[1, 0, 0, 0, 0])
+ cm = c.filled(1)
+ z = where(c, x, y)
+ zm = where(cm, x, y)
+ assert_equal(z, zm)
+ assert_(getmask(zm) is nomask)
+ assert_equal(zm, [1, 2, 3, 40, 50])
+ z = where(c, masked, 1)
+ assert_equal(z, [99, 99, 99, 1, 1])
+ z = where(c, 1, masked)
+ assert_equal(z, [99, 1, 1, 99, 99])
+
+ def test_where_type(self):
+ # Test the type conservation with where
+ x = np.arange(4, dtype=np.int32)
+ y = np.arange(4, dtype=np.float32) * 2.2
+ test = where(x > 1.5, y, x).dtype
+ control = np.find_common_type([np.int32, np.float32], [])
+ assert_equal(test, control)
+
+ def test_where_broadcast(self):
+ # Issue 8599
+ x = np.arange(9).reshape(3, 3)
+ y = np.zeros(3)
+ core = np.where([1, 0, 1], x, y)
+ ma = where([1, 0, 1], x, y)
+
+ assert_equal(core, ma)
+ assert_equal(core.dtype, ma.dtype)
+
+ def test_where_structured(self):
+ # Issue 8600
+ dt = np.dtype([('a', int), ('b', int)])
+ x = np.array([(1, 2), (3, 4), (5, 6)], dtype=dt)
+ y = np.array((10, 20), dtype=dt)
+ core = np.where([0, 1, 1], x, y)
+ ma = np.where([0, 1, 1], x, y)
+
+ assert_equal(core, ma)
+ assert_equal(core.dtype, ma.dtype)
+
+ def test_where_structured_masked(self):
+ dt = np.dtype([('a', int), ('b', int)])
+ x = np.array([(1, 2), (3, 4), (5, 6)], dtype=dt)
+
+ ma = where([0, 1, 1], x, masked)
+ expected = masked_where([1, 0, 0], x)
+
+ assert_equal(ma.dtype, expected.dtype)
+ assert_equal(ma, expected)
+ assert_equal(ma.mask, expected.mask)
+
+ def test_masked_invalid_error(self):
+ a = np.arange(5, dtype=object)
+ a[3] = np.PINF
+ a[2] = np.NaN
+ with pytest.raises(TypeError,
+ match="not supported for the input types"):
+ np.ma.masked_invalid(a)
+
+ def test_masked_invalid_pandas(self):
+ # getdata() used to be bad for pandas series due to its _data
+ # attribute. This test is a regression test mainly and may be
+ # removed if getdata() is adjusted.
+ class Series():
+ _data = "nonsense"
+
+ def __array__(self):
+ return np.array([5, np.nan, np.inf])
+
+ arr = np.ma.masked_invalid(Series())
+ assert_array_equal(arr._data, np.array(Series()))
+ assert_array_equal(arr._mask, [False, True, True])
+
+ @pytest.mark.parametrize("copy", [True, False])
+ def test_masked_invalid_full_mask(self, copy):
+ # Matplotlib relied on masked_invalid always returning a full mask
+ # (Also astropy projects, but were ok with it gh-22720 and gh-22842)
+ a = np.ma.array([1, 2, 3, 4])
+ assert a._mask is nomask
+ res = np.ma.masked_invalid(a, copy=copy)
+ assert res.mask is not nomask
+ # mask of a should not be mutated
+ assert a.mask is nomask
+ assert np.may_share_memory(a._data, res._data) != copy
+
+ def test_choose(self):
+ # Test choose
+ choices = [[0, 1, 2, 3], [10, 11, 12, 13],
+ [20, 21, 22, 23], [30, 31, 32, 33]]
+ chosen = choose([2, 3, 1, 0], choices)
+ assert_equal(chosen, array([20, 31, 12, 3]))
+ chosen = choose([2, 4, 1, 0], choices, mode='clip')
+ assert_equal(chosen, array([20, 31, 12, 3]))
+ chosen = choose([2, 4, 1, 0], choices, mode='wrap')
+ assert_equal(chosen, array([20, 1, 12, 3]))
+ # Check with some masked indices
+ indices_ = array([2, 4, 1, 0], mask=[1, 0, 0, 1])
+ chosen = choose(indices_, choices, mode='wrap')
+ assert_equal(chosen, array([99, 1, 12, 99]))
+ assert_equal(chosen.mask, [1, 0, 0, 1])
+ # Check with some masked choices
+ choices = array(choices, mask=[[0, 0, 0, 1], [1, 1, 0, 1],
+ [1, 0, 0, 0], [0, 0, 0, 0]])
+ indices_ = [2, 3, 1, 0]
+ chosen = choose(indices_, choices, mode='wrap')
+ assert_equal(chosen, array([20, 31, 12, 3]))
+ assert_equal(chosen.mask, [1, 0, 0, 1])
+
+ def test_choose_with_out(self):
+ # Test choose with an explicit out keyword
+ choices = [[0, 1, 2, 3], [10, 11, 12, 13],
+ [20, 21, 22, 23], [30, 31, 32, 33]]
+ store = empty(4, dtype=int)
+ chosen = choose([2, 3, 1, 0], choices, out=store)
+ assert_equal(store, array([20, 31, 12, 3]))
+ assert_(store is chosen)
+ # Check with some masked indices + out
+ store = empty(4, dtype=int)
+ indices_ = array([2, 3, 1, 0], mask=[1, 0, 0, 1])
+ chosen = choose(indices_, choices, mode='wrap', out=store)
+ assert_equal(store, array([99, 31, 12, 99]))
+ assert_equal(store.mask, [1, 0, 0, 1])
+ # Check with some masked choices + out ina ndarray !
+ choices = array(choices, mask=[[0, 0, 0, 1], [1, 1, 0, 1],
+ [1, 0, 0, 0], [0, 0, 0, 0]])
+ indices_ = [2, 3, 1, 0]
+ store = empty(4, dtype=int).view(ndarray)
+ chosen = choose(indices_, choices, mode='wrap', out=store)
+ assert_equal(store, array([999999, 31, 12, 999999]))
+
+ def test_reshape(self):
+ a = arange(10)
+ a[0] = masked
+ # Try the default
+ b = a.reshape((5, 2))
+ assert_equal(b.shape, (5, 2))
+ assert_(b.flags['C'])
+ # Try w/ arguments as list instead of tuple
+ b = a.reshape(5, 2)
+ assert_equal(b.shape, (5, 2))
+ assert_(b.flags['C'])
+ # Try w/ order
+ b = a.reshape((5, 2), order='F')
+ assert_equal(b.shape, (5, 2))
+ assert_(b.flags['F'])
+ # Try w/ order
+ b = a.reshape(5, 2, order='F')
+ assert_equal(b.shape, (5, 2))
+ assert_(b.flags['F'])
+
+ c = np.reshape(a, (2, 5))
+ assert_(isinstance(c, MaskedArray))
+ assert_equal(c.shape, (2, 5))
+ assert_(c[0, 0] is masked)
+ assert_(c.flags['C'])
+
+ def test_make_mask_descr(self):
+ # Flexible
+ ntype = [('a', float), ('b', float)]
+ test = make_mask_descr(ntype)
+ assert_equal(test, [('a', bool), ('b', bool)])
+ assert_(test is make_mask_descr(test))
+
+ # Standard w/ shape
+ ntype = (float, 2)
+ test = make_mask_descr(ntype)
+ assert_equal(test, (bool, 2))
+ assert_(test is make_mask_descr(test))
+
+ # Standard standard
+ ntype = float
+ test = make_mask_descr(ntype)
+ assert_equal(test, np.dtype(bool))
+ assert_(test is make_mask_descr(test))
+
+ # Nested
+ ntype = [('a', float), ('b', [('ba', float), ('bb', float)])]
+ test = make_mask_descr(ntype)
+ control = np.dtype([('a', 'b1'), ('b', [('ba', 'b1'), ('bb', 'b1')])])
+ assert_equal(test, control)
+ assert_(test is make_mask_descr(test))
+
+ # Named+ shape
+ ntype = [('a', (float, 2))]
+ test = make_mask_descr(ntype)
+ assert_equal(test, np.dtype([('a', (bool, 2))]))
+ assert_(test is make_mask_descr(test))
+
+ # 2 names
+ ntype = [(('A', 'a'), float)]
+ test = make_mask_descr(ntype)
+ assert_equal(test, np.dtype([(('A', 'a'), bool)]))
+ assert_(test is make_mask_descr(test))
+
+ # nested boolean types should preserve identity
+ base_type = np.dtype([('a', int, 3)])
+ base_mtype = make_mask_descr(base_type)
+ sub_type = np.dtype([('a', int), ('b', base_mtype)])
+ test = make_mask_descr(sub_type)
+ assert_equal(test, np.dtype([('a', bool), ('b', [('a', bool, 3)])]))
+ assert_(test.fields['b'][0] is base_mtype)
+
+ def test_make_mask(self):
+ # Test make_mask
+ # w/ a list as an input
+ mask = [0, 1]
+ test = make_mask(mask)
+ assert_equal(test.dtype, MaskType)
+ assert_equal(test, [0, 1])
+ # w/ a ndarray as an input
+ mask = np.array([0, 1], dtype=bool)
+ test = make_mask(mask)
+ assert_equal(test.dtype, MaskType)
+ assert_equal(test, [0, 1])
+ # w/ a flexible-type ndarray as an input - use default
+ mdtype = [('a', bool), ('b', bool)]
+ mask = np.array([(0, 0), (0, 1)], dtype=mdtype)
+ test = make_mask(mask)
+ assert_equal(test.dtype, MaskType)
+ assert_equal(test, [1, 1])
+ # w/ a flexible-type ndarray as an input - use input dtype
+ mdtype = [('a', bool), ('b', bool)]
+ mask = np.array([(0, 0), (0, 1)], dtype=mdtype)
+ test = make_mask(mask, dtype=mask.dtype)
+ assert_equal(test.dtype, mdtype)
+ assert_equal(test, mask)
+ # w/ a flexible-type ndarray as an input - use input dtype
+ mdtype = [('a', float), ('b', float)]
+ bdtype = [('a', bool), ('b', bool)]
+ mask = np.array([(0, 0), (0, 1)], dtype=mdtype)
+ test = make_mask(mask, dtype=mask.dtype)
+ assert_equal(test.dtype, bdtype)
+ assert_equal(test, np.array([(0, 0), (0, 1)], dtype=bdtype))
+ # Ensure this also works for void
+ mask = np.array((False, True), dtype='?,?')[()]
+ assert_(isinstance(mask, np.void))
+ test = make_mask(mask, dtype=mask.dtype)
+ assert_equal(test, mask)
+ assert_(test is not mask)
+ mask = np.array((0, 1), dtype='i4,i4')[()]
+ test2 = make_mask(mask, dtype=mask.dtype)
+ assert_equal(test2, test)
+ # test that nomask is returned when m is nomask.
+ bools = [True, False]
+ dtypes = [MaskType, float]
+ msgformat = 'copy=%s, shrink=%s, dtype=%s'
+ for cpy, shr, dt in itertools.product(bools, bools, dtypes):
+ res = make_mask(nomask, copy=cpy, shrink=shr, dtype=dt)
+ assert_(res is nomask, msgformat % (cpy, shr, dt))
+
+ def test_mask_or(self):
+ # Initialize
+ mtype = [('a', bool), ('b', bool)]
+ mask = np.array([(0, 0), (0, 1), (1, 0), (0, 0)], dtype=mtype)
+ # Test using nomask as input
+ test = mask_or(mask, nomask)
+ assert_equal(test, mask)
+ test = mask_or(nomask, mask)
+ assert_equal(test, mask)
+ # Using False as input
+ test = mask_or(mask, False)
+ assert_equal(test, mask)
+ # Using another array w / the same dtype
+ other = np.array([(0, 1), (0, 1), (0, 1), (0, 1)], dtype=mtype)
+ test = mask_or(mask, other)
+ control = np.array([(0, 1), (0, 1), (1, 1), (0, 1)], dtype=mtype)
+ assert_equal(test, control)
+ # Using another array w / a different dtype
+ othertype = [('A', bool), ('B', bool)]
+ other = np.array([(0, 1), (0, 1), (0, 1), (0, 1)], dtype=othertype)
+ try:
+ test = mask_or(mask, other)
+ except ValueError:
+ pass
+ # Using nested arrays
+ dtype = [('a', bool), ('b', [('ba', bool), ('bb', bool)])]
+ amask = np.array([(0, (1, 0)), (0, (1, 0))], dtype=dtype)
+ bmask = np.array([(1, (0, 1)), (0, (0, 0))], dtype=dtype)
+ cntrl = np.array([(1, (1, 1)), (0, (1, 0))], dtype=dtype)
+ assert_equal(mask_or(amask, bmask), cntrl)
+
+ def test_flatten_mask(self):
+ # Tests flatten mask
+ # Standard dtype
+ mask = np.array([0, 0, 1], dtype=bool)
+ assert_equal(flatten_mask(mask), mask)
+ # Flexible dtype
+ mask = np.array([(0, 0), (0, 1)], dtype=[('a', bool), ('b', bool)])
+ test = flatten_mask(mask)
+ control = np.array([0, 0, 0, 1], dtype=bool)
+ assert_equal(test, control)
+
+ mdtype = [('a', bool), ('b', [('ba', bool), ('bb', bool)])]
+ data = [(0, (0, 0)), (0, (0, 1))]
+ mask = np.array(data, dtype=mdtype)
+ test = flatten_mask(mask)
+ control = np.array([0, 0, 0, 0, 0, 1], dtype=bool)
+ assert_equal(test, control)
+
+ def test_on_ndarray(self):
+ # Test functions on ndarrays
+ a = np.array([1, 2, 3, 4])
+ m = array(a, mask=False)
+ test = anom(a)
+ assert_equal(test, m.anom())
+ test = reshape(a, (2, 2))
+ assert_equal(test, m.reshape(2, 2))
+
+ def test_compress(self):
+ # Test compress function on ndarray and masked array
+ # Address Github #2495.
+ arr = np.arange(8)
+ arr.shape = 4, 2
+ cond = np.array([True, False, True, True])
+ control = arr[[0, 2, 3]]
+ test = np.ma.compress(cond, arr, axis=0)
+ assert_equal(test, control)
+ marr = np.ma.array(arr)
+ test = np.ma.compress(cond, marr, axis=0)
+ assert_equal(test, control)
+
+ def test_compressed(self):
+ # Test ma.compressed function.
+ # Address gh-4026
+ a = np.ma.array([1, 2])
+ test = np.ma.compressed(a)
+ assert_(type(test) is np.ndarray)
+
+ # Test case when input data is ndarray subclass
+ class A(np.ndarray):
+ pass
+
+ a = np.ma.array(A(shape=0))
+ test = np.ma.compressed(a)
+ assert_(type(test) is A)
+
+ # Test that compress flattens
+ test = np.ma.compressed([[1],[2]])
+ assert_equal(test.ndim, 1)
+ test = np.ma.compressed([[[[[1]]]]])
+ assert_equal(test.ndim, 1)
+
+ # Test case when input is MaskedArray subclass
+ class M(MaskedArray):
+ pass
+
+ test = np.ma.compressed(M([[[]], [[]]]))
+ assert_equal(test.ndim, 1)
+
+ # with .compressed() overridden
+ class M(MaskedArray):
+ def compressed(self):
+ return 42
+
+ test = np.ma.compressed(M([[[]], [[]]]))
+ assert_equal(test, 42)
+
+ def test_convolve(self):
+ a = masked_equal(np.arange(5), 2)
+ b = np.array([1, 1])
+ test = np.ma.convolve(a, b)
+ assert_equal(test, masked_equal([0, 1, -1, -1, 7, 4], -1))
+
+ test = np.ma.convolve(a, b, propagate_mask=False)
+ assert_equal(test, masked_equal([0, 1, 1, 3, 7, 4], -1))
+
+ test = np.ma.convolve([1, 1], [1, 1, 1])
+ assert_equal(test, masked_equal([1, 2, 2, 1], -1))
+
+ a = [1, 1]
+ b = masked_equal([1, -1, -1, 1], -1)
+ test = np.ma.convolve(a, b, propagate_mask=False)
+ assert_equal(test, masked_equal([1, 1, -1, 1, 1], -1))
+ test = np.ma.convolve(a, b, propagate_mask=True)
+ assert_equal(test, masked_equal([-1, -1, -1, -1, -1], -1))
+
+
+class TestMaskedFields:
+
+ def setup_method(self):
+ ilist = [1, 2, 3, 4, 5]
+ flist = [1.1, 2.2, 3.3, 4.4, 5.5]
+ slist = ['one', 'two', 'three', 'four', 'five']
+ ddtype = [('a', int), ('b', float), ('c', '|S8')]
+ mdtype = [('a', bool), ('b', bool), ('c', bool)]
+ mask = [0, 1, 0, 0, 1]
+ base = array(list(zip(ilist, flist, slist)), mask=mask, dtype=ddtype)
+ self.data = dict(base=base, mask=mask, ddtype=ddtype, mdtype=mdtype)
+
+ def test_set_records_masks(self):
+ base = self.data['base']
+ mdtype = self.data['mdtype']
+ # Set w/ nomask or masked
+ base.mask = nomask
+ assert_equal_records(base._mask, np.zeros(base.shape, dtype=mdtype))
+ base.mask = masked
+ assert_equal_records(base._mask, np.ones(base.shape, dtype=mdtype))
+ # Set w/ simple boolean
+ base.mask = False
+ assert_equal_records(base._mask, np.zeros(base.shape, dtype=mdtype))
+ base.mask = True
+ assert_equal_records(base._mask, np.ones(base.shape, dtype=mdtype))
+ # Set w/ list
+ base.mask = [0, 0, 0, 1, 1]
+ assert_equal_records(base._mask,
+ np.array([(x, x, x) for x in [0, 0, 0, 1, 1]],
+ dtype=mdtype))
+
+ def test_set_record_element(self):
+ # Check setting an element of a record)
+ base = self.data['base']
+ (base_a, base_b, base_c) = (base['a'], base['b'], base['c'])
+ base[0] = (pi, pi, 'pi')
+
+ assert_equal(base_a.dtype, int)
+ assert_equal(base_a._data, [3, 2, 3, 4, 5])
+
+ assert_equal(base_b.dtype, float)
+ assert_equal(base_b._data, [pi, 2.2, 3.3, 4.4, 5.5])
+
+ assert_equal(base_c.dtype, '|S8')
+ assert_equal(base_c._data,
+ [b'pi', b'two', b'three', b'four', b'five'])
+
+ def test_set_record_slice(self):
+ base = self.data['base']
+ (base_a, base_b, base_c) = (base['a'], base['b'], base['c'])
+ base[:3] = (pi, pi, 'pi')
+
+ assert_equal(base_a.dtype, int)
+ assert_equal(base_a._data, [3, 3, 3, 4, 5])
+
+ assert_equal(base_b.dtype, float)
+ assert_equal(base_b._data, [pi, pi, pi, 4.4, 5.5])
+
+ assert_equal(base_c.dtype, '|S8')
+ assert_equal(base_c._data,
+ [b'pi', b'pi', b'pi', b'four', b'five'])
+
+ def test_mask_element(self):
+ "Check record access"
+ base = self.data['base']
+ base[0] = masked
+
+ for n in ('a', 'b', 'c'):
+ assert_equal(base[n].mask, [1, 1, 0, 0, 1])
+ assert_equal(base[n]._data, base._data[n])
+
+ def test_getmaskarray(self):
+ # Test getmaskarray on flexible dtype
+ ndtype = [('a', int), ('b', float)]
+ test = empty(3, dtype=ndtype)
+ assert_equal(getmaskarray(test),
+ np.array([(0, 0), (0, 0), (0, 0)],
+ dtype=[('a', '|b1'), ('b', '|b1')]))
+ test[:] = masked
+ assert_equal(getmaskarray(test),
+ np.array([(1, 1), (1, 1), (1, 1)],
+ dtype=[('a', '|b1'), ('b', '|b1')]))
+
+ def test_view(self):
+ # Test view w/ flexible dtype
+ iterator = list(zip(np.arange(10), np.random.rand(10)))
+ data = np.array(iterator)
+ a = array(iterator, dtype=[('a', float), ('b', float)])
+ a.mask[0] = (1, 0)
+ controlmask = np.array([1] + 19 * [0], dtype=bool)
+ # Transform globally to simple dtype
+ test = a.view(float)
+ assert_equal(test, data.ravel())
+ assert_equal(test.mask, controlmask)
+ # Transform globally to dty
+ test = a.view((float, 2))
+ assert_equal(test, data)
+ assert_equal(test.mask, controlmask.reshape(-1, 2))
+
+ def test_getitem(self):
+ ndtype = [('a', float), ('b', float)]
+ a = array(list(zip(np.random.rand(10), np.arange(10))), dtype=ndtype)
+ a.mask = np.array(list(zip([0, 0, 0, 0, 0, 0, 0, 0, 1, 1],
+ [1, 0, 0, 0, 0, 0, 0, 0, 1, 0])),
+ dtype=[('a', bool), ('b', bool)])
+
+ def _test_index(i):
+ assert_equal(type(a[i]), mvoid)
+ assert_equal_records(a[i]._data, a._data[i])
+ assert_equal_records(a[i]._mask, a._mask[i])
+
+ assert_equal(type(a[i, ...]), MaskedArray)
+ assert_equal_records(a[i,...]._data, a._data[i,...])
+ assert_equal_records(a[i,...]._mask, a._mask[i,...])
+
+ _test_index(1) # No mask
+ _test_index(0) # One element masked
+ _test_index(-2) # All element masked
+
+ def test_setitem(self):
+ # Issue 4866: check that one can set individual items in [record][col]
+ # and [col][record] order
+ ndtype = np.dtype([('a', float), ('b', int)])
+ ma = np.ma.MaskedArray([(1.0, 1), (2.0, 2)], dtype=ndtype)
+ ma['a'][1] = 3.0
+ assert_equal(ma['a'], np.array([1.0, 3.0]))
+ ma[1]['a'] = 4.0
+ assert_equal(ma['a'], np.array([1.0, 4.0]))
+ # Issue 2403
+ mdtype = np.dtype([('a', bool), ('b', bool)])
+ # soft mask
+ control = np.array([(False, True), (True, True)], dtype=mdtype)
+ a = np.ma.masked_all((2,), dtype=ndtype)
+ a['a'][0] = 2
+ assert_equal(a.mask, control)
+ a = np.ma.masked_all((2,), dtype=ndtype)
+ a[0]['a'] = 2
+ assert_equal(a.mask, control)
+ # hard mask
+ control = np.array([(True, True), (True, True)], dtype=mdtype)
+ a = np.ma.masked_all((2,), dtype=ndtype)
+ a.harden_mask()
+ a['a'][0] = 2
+ assert_equal(a.mask, control)
+ a = np.ma.masked_all((2,), dtype=ndtype)
+ a.harden_mask()
+ a[0]['a'] = 2
+ assert_equal(a.mask, control)
+
+ def test_setitem_scalar(self):
+ # 8510
+ mask_0d = np.ma.masked_array(1, mask=True)
+ arr = np.ma.arange(3)
+ arr[0] = mask_0d
+ assert_array_equal(arr.mask, [True, False, False])
+
+ def test_element_len(self):
+ # check that len() works for mvoid (Github issue #576)
+ for rec in self.data['base']:
+ assert_equal(len(rec), len(self.data['ddtype']))
+
+
+class TestMaskedObjectArray:
+
+ def test_getitem(self):
+ arr = np.ma.array([None, None])
+ for dt in [float, object]:
+ a0 = np.eye(2).astype(dt)
+ a1 = np.eye(3).astype(dt)
+ arr[0] = a0
+ arr[1] = a1
+
+ assert_(arr[0] is a0)
+ assert_(arr[1] is a1)
+ assert_(isinstance(arr[0,...], MaskedArray))
+ assert_(isinstance(arr[1,...], MaskedArray))
+ assert_(arr[0,...][()] is a0)
+ assert_(arr[1,...][()] is a1)
+
+ arr[0] = np.ma.masked
+
+ assert_(arr[1] is a1)
+ assert_(isinstance(arr[0,...], MaskedArray))
+ assert_(isinstance(arr[1,...], MaskedArray))
+ assert_equal(arr[0,...].mask, True)
+ assert_(arr[1,...][()] is a1)
+
+ # gh-5962 - object arrays of arrays do something special
+ assert_equal(arr[0].data, a0)
+ assert_equal(arr[0].mask, True)
+ assert_equal(arr[0,...][()].data, a0)
+ assert_equal(arr[0,...][()].mask, True)
+
+ def test_nested_ma(self):
+
+ arr = np.ma.array([None, None])
+ # set the first object to be an unmasked masked constant. A little fiddly
+ arr[0,...] = np.array([np.ma.masked], object)[0,...]
+
+ # check the above line did what we were aiming for
+ assert_(arr.data[0] is np.ma.masked)
+
+ # test that getitem returned the value by identity
+ assert_(arr[0] is np.ma.masked)
+
+ # now mask the masked value!
+ arr[0] = np.ma.masked
+ assert_(arr[0] is np.ma.masked)
+
+
+class TestMaskedView:
+
+ def setup_method(self):
+ iterator = list(zip(np.arange(10), np.random.rand(10)))
+ data = np.array(iterator)
+ a = array(iterator, dtype=[('a', float), ('b', float)])
+ a.mask[0] = (1, 0)
+ controlmask = np.array([1] + 19 * [0], dtype=bool)
+ self.data = (data, a, controlmask)
+
+ def test_view_to_nothing(self):
+ (data, a, controlmask) = self.data
+ test = a.view()
+ assert_(isinstance(test, MaskedArray))
+ assert_equal(test._data, a._data)
+ assert_equal(test._mask, a._mask)
+
+ def test_view_to_type(self):
+ (data, a, controlmask) = self.data
+ test = a.view(np.ndarray)
+ assert_(not isinstance(test, MaskedArray))
+ assert_equal(test, a._data)
+ assert_equal_records(test, data.view(a.dtype).squeeze())
+
+ def test_view_to_simple_dtype(self):
+ (data, a, controlmask) = self.data
+ # View globally
+ test = a.view(float)
+ assert_(isinstance(test, MaskedArray))
+ assert_equal(test, data.ravel())
+ assert_equal(test.mask, controlmask)
+
+ def test_view_to_flexible_dtype(self):
+ (data, a, controlmask) = self.data
+
+ test = a.view([('A', float), ('B', float)])
+ assert_equal(test.mask.dtype.names, ('A', 'B'))
+ assert_equal(test['A'], a['a'])
+ assert_equal(test['B'], a['b'])
+
+ test = a[0].view([('A', float), ('B', float)])
+ assert_(isinstance(test, MaskedArray))
+ assert_equal(test.mask.dtype.names, ('A', 'B'))
+ assert_equal(test['A'], a['a'][0])
+ assert_equal(test['B'], a['b'][0])
+
+ test = a[-1].view([('A', float), ('B', float)])
+ assert_(isinstance(test, MaskedArray))
+ assert_equal(test.dtype.names, ('A', 'B'))
+ assert_equal(test['A'], a['a'][-1])
+ assert_equal(test['B'], a['b'][-1])
+
+ def test_view_to_subdtype(self):
+ (data, a, controlmask) = self.data
+ # View globally
+ test = a.view((float, 2))
+ assert_(isinstance(test, MaskedArray))
+ assert_equal(test, data)
+ assert_equal(test.mask, controlmask.reshape(-1, 2))
+ # View on 1 masked element
+ test = a[0].view((float, 2))
+ assert_(isinstance(test, MaskedArray))
+ assert_equal(test, data[0])
+ assert_equal(test.mask, (1, 0))
+ # View on 1 unmasked element
+ test = a[-1].view((float, 2))
+ assert_(isinstance(test, MaskedArray))
+ assert_equal(test, data[-1])
+
+ def test_view_to_dtype_and_type(self):
+ (data, a, controlmask) = self.data
+
+ test = a.view((float, 2), np.recarray)
+ assert_equal(test, data)
+ assert_(isinstance(test, np.recarray))
+ assert_(not isinstance(test, MaskedArray))
+
+
+class TestOptionalArgs:
+ def test_ndarrayfuncs(self):
+ # test axis arg behaves the same as ndarray (including multiple axes)
+
+ d = np.arange(24.0).reshape((2,3,4))
+ m = np.zeros(24, dtype=bool).reshape((2,3,4))
+ # mask out last element of last dimension
+ m[:,:,-1] = True
+ a = np.ma.array(d, mask=m)
+
+ def testaxis(f, a, d):
+ numpy_f = numpy.__getattribute__(f)
+ ma_f = np.ma.__getattribute__(f)
+
+ # test axis arg
+ assert_equal(ma_f(a, axis=1)[...,:-1], numpy_f(d[...,:-1], axis=1))
+ assert_equal(ma_f(a, axis=(0,1))[...,:-1],
+ numpy_f(d[...,:-1], axis=(0,1)))
+
+ def testkeepdims(f, a, d):
+ numpy_f = numpy.__getattribute__(f)
+ ma_f = np.ma.__getattribute__(f)
+
+ # test keepdims arg
+ assert_equal(ma_f(a, keepdims=True).shape,
+ numpy_f(d, keepdims=True).shape)
+ assert_equal(ma_f(a, keepdims=False).shape,
+ numpy_f(d, keepdims=False).shape)
+
+ # test both at once
+ assert_equal(ma_f(a, axis=1, keepdims=True)[...,:-1],
+ numpy_f(d[...,:-1], axis=1, keepdims=True))
+ assert_equal(ma_f(a, axis=(0,1), keepdims=True)[...,:-1],
+ numpy_f(d[...,:-1], axis=(0,1), keepdims=True))
+
+ for f in ['sum', 'prod', 'mean', 'var', 'std']:
+ testaxis(f, a, d)
+ testkeepdims(f, a, d)
+
+ for f in ['min', 'max']:
+ testaxis(f, a, d)
+
+ d = (np.arange(24).reshape((2,3,4))%2 == 0)
+ a = np.ma.array(d, mask=m)
+ for f in ['all', 'any']:
+ testaxis(f, a, d)
+ testkeepdims(f, a, d)
+
+ def test_count(self):
+ # test np.ma.count specially
+
+ d = np.arange(24.0).reshape((2,3,4))
+ m = np.zeros(24, dtype=bool).reshape((2,3,4))
+ m[:,0,:] = True
+ a = np.ma.array(d, mask=m)
+
+ assert_equal(count(a), 16)
+ assert_equal(count(a, axis=1), 2*ones((2,4)))
+ assert_equal(count(a, axis=(0,1)), 4*ones((4,)))
+ assert_equal(count(a, keepdims=True), 16*ones((1,1,1)))
+ assert_equal(count(a, axis=1, keepdims=True), 2*ones((2,1,4)))
+ assert_equal(count(a, axis=(0,1), keepdims=True), 4*ones((1,1,4)))
+ assert_equal(count(a, axis=-2), 2*ones((2,4)))
+ assert_raises(ValueError, count, a, axis=(1,1))
+ assert_raises(np.AxisError, count, a, axis=3)
+
+ # check the 'nomask' path
+ a = np.ma.array(d, mask=nomask)
+
+ assert_equal(count(a), 24)
+ assert_equal(count(a, axis=1), 3*ones((2,4)))
+ assert_equal(count(a, axis=(0,1)), 6*ones((4,)))
+ assert_equal(count(a, keepdims=True), 24*ones((1,1,1)))
+ assert_equal(np.ndim(count(a, keepdims=True)), 3)
+ assert_equal(count(a, axis=1, keepdims=True), 3*ones((2,1,4)))
+ assert_equal(count(a, axis=(0,1), keepdims=True), 6*ones((1,1,4)))
+ assert_equal(count(a, axis=-2), 3*ones((2,4)))
+ assert_raises(ValueError, count, a, axis=(1,1))
+ assert_raises(np.AxisError, count, a, axis=3)
+
+ # check the 'masked' singleton
+ assert_equal(count(np.ma.masked), 0)
+
+ # check 0-d arrays do not allow axis > 0
+ assert_raises(np.AxisError, count, np.ma.array(1), axis=1)
+
+
+class TestMaskedConstant:
+ def _do_add_test(self, add):
+ # sanity check
+ assert_(add(np.ma.masked, 1) is np.ma.masked)
+
+ # now try with a vector
+ vector = np.array([1, 2, 3])
+ result = add(np.ma.masked, vector)
+
+ # lots of things could go wrong here
+ assert_(result is not np.ma.masked)
+ assert_(not isinstance(result, np.ma.core.MaskedConstant))
+ assert_equal(result.shape, vector.shape)
+ assert_equal(np.ma.getmask(result), np.ones(vector.shape, dtype=bool))
+
+ def test_ufunc(self):
+ self._do_add_test(np.add)
+
+ def test_operator(self):
+ self._do_add_test(lambda a, b: a + b)
+
+ def test_ctor(self):
+ m = np.ma.array(np.ma.masked)
+
+ # most importantly, we do not want to create a new MaskedConstant
+ # instance
+ assert_(not isinstance(m, np.ma.core.MaskedConstant))
+ assert_(m is not np.ma.masked)
+
+ def test_repr(self):
+ # copies should not exist, but if they do, it should be obvious that
+ # something is wrong
+ assert_equal(repr(np.ma.masked), 'masked')
+
+ # create a new instance in a weird way
+ masked2 = np.ma.MaskedArray.__new__(np.ma.core.MaskedConstant)
+ assert_not_equal(repr(masked2), 'masked')
+
+ def test_pickle(self):
+ from io import BytesIO
+
+ for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
+ with BytesIO() as f:
+ pickle.dump(np.ma.masked, f, protocol=proto)
+ f.seek(0)
+ res = pickle.load(f)
+ assert_(res is np.ma.masked)
+
+ def test_copy(self):
+ # gh-9328
+ # copy is a no-op, like it is with np.True_
+ assert_equal(
+ np.ma.masked.copy() is np.ma.masked,
+ np.True_.copy() is np.True_)
+
+ def test__copy(self):
+ import copy
+ assert_(
+ copy.copy(np.ma.masked) is np.ma.masked)
+
+ def test_deepcopy(self):
+ import copy
+ assert_(
+ copy.deepcopy(np.ma.masked) is np.ma.masked)
+
+ def test_immutable(self):
+ orig = np.ma.masked
+ assert_raises(np.ma.core.MaskError, operator.setitem, orig, (), 1)
+ assert_raises(ValueError,operator.setitem, orig.data, (), 1)
+ assert_raises(ValueError, operator.setitem, orig.mask, (), False)
+
+ view = np.ma.masked.view(np.ma.MaskedArray)
+ assert_raises(ValueError, operator.setitem, view, (), 1)
+ assert_raises(ValueError, operator.setitem, view.data, (), 1)
+ assert_raises(ValueError, operator.setitem, view.mask, (), False)
+
+ def test_coercion_int(self):
+ a_i = np.zeros((), int)
+ assert_raises(MaskError, operator.setitem, a_i, (), np.ma.masked)
+ assert_raises(MaskError, int, np.ma.masked)
+
+ def test_coercion_float(self):
+ a_f = np.zeros((), float)
+ assert_warns(UserWarning, operator.setitem, a_f, (), np.ma.masked)
+ assert_(np.isnan(a_f[()]))
+
+ @pytest.mark.xfail(reason="See gh-9750")
+ def test_coercion_unicode(self):
+ a_u = np.zeros((), 'U10')
+ a_u[()] = np.ma.masked
+ assert_equal(a_u[()], '--')
+
+ @pytest.mark.xfail(reason="See gh-9750")
+ def test_coercion_bytes(self):
+ a_b = np.zeros((), 'S10')
+ a_b[()] = np.ma.masked
+ assert_equal(a_b[()], b'--')
+
+ def test_subclass(self):
+ # https://github.com/astropy/astropy/issues/6645
+ class Sub(type(np.ma.masked)): pass
+
+ a = Sub()
+ assert_(a is Sub())
+ assert_(a is not np.ma.masked)
+ assert_not_equal(repr(a), 'masked')
+
+ def test_attributes_readonly(self):
+ assert_raises(AttributeError, setattr, np.ma.masked, 'shape', (1,))
+ assert_raises(AttributeError, setattr, np.ma.masked, 'dtype', np.int64)
+
+
+class TestMaskedWhereAliases:
+
+ # TODO: Test masked_object, masked_equal, ...
+
+ def test_masked_values(self):
+ res = masked_values(np.array([-32768.0]), np.int16(-32768))
+ assert_equal(res.mask, [True])
+
+ res = masked_values(np.inf, np.inf)
+ assert_equal(res.mask, True)
+
+ res = np.ma.masked_values(np.inf, -np.inf)
+ assert_equal(res.mask, False)
+
+ res = np.ma.masked_values([1, 2, 3, 4], 5, shrink=True)
+ assert_(res.mask is np.ma.nomask)
+
+ res = np.ma.masked_values([1, 2, 3, 4], 5, shrink=False)
+ assert_equal(res.mask, [False] * 4)
+
+
+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_masked_array_no_copy():
+ # check nomask array is updated in place
+ a = np.ma.array([1, 2, 3, 4])
+ _ = np.ma.masked_where(a == 3, a, copy=False)
+ assert_array_equal(a.mask, [False, False, True, False])
+ # check masked array is updated in place
+ a = np.ma.array([1, 2, 3, 4], mask=[1, 0, 0, 0])
+ _ = np.ma.masked_where(a == 3, a, copy=False)
+ assert_array_equal(a.mask, [True, False, True, False])
+ # check masked array with masked_invalid is updated in place
+ a = np.ma.array([np.inf, 1, 2, 3, 4])
+ _ = np.ma.masked_invalid(a, copy=False)
+ assert_array_equal(a.mask, [True, False, False, False, False])
+
+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)
+
+def test_default_fill_value_complex():
+ # regression test for Python 3, where 'unicode' was not defined
+ assert_(default_fill_value(1 + 1j) == 1.e20 + 0.0j)
+
+
+def test_ufunc_with_output():
+ # check that giving an output argument always returns that output.
+ # Regression test for gh-8416.
+ x = array([1., 2., 3.], mask=[0, 0, 1])
+ y = np.add(x, 1., out=x)
+ assert_(y is x)
+
+
+def test_ufunc_with_out_varied():
+ """ Test that masked arrays are immune to gh-10459 """
+ # the mask of the output should not affect the result, however it is passed
+ a = array([ 1, 2, 3], mask=[1, 0, 0])
+ b = array([10, 20, 30], mask=[1, 0, 0])
+ out = array([ 0, 0, 0], mask=[0, 0, 1])
+ expected = array([11, 22, 33], mask=[1, 0, 0])
+
+ out_pos = out.copy()
+ res_pos = np.add(a, b, out_pos)
+
+ out_kw = out.copy()
+ res_kw = np.add(a, b, out=out_kw)
+
+ out_tup = out.copy()
+ res_tup = np.add(a, b, out=(out_tup,))
+
+ assert_equal(res_kw.mask, expected.mask)
+ assert_equal(res_kw.data, expected.data)
+ assert_equal(res_tup.mask, expected.mask)
+ assert_equal(res_tup.data, expected.data)
+ assert_equal(res_pos.mask, expected.mask)
+ assert_equal(res_pos.data, expected.data)
+
+
+def test_astype_mask_ordering():
+ descr = np.dtype([('v', int, 3), ('x', [('y', float)])])
+ x = array([
+ [([1, 2, 3], (1.0,)), ([1, 2, 3], (2.0,))],
+ [([1, 2, 3], (3.0,)), ([1, 2, 3], (4.0,))]], dtype=descr)
+ x[0]['v'][0] = np.ma.masked
+
+ x_a = x.astype(descr)
+ assert x_a.dtype.names == np.dtype(descr).names
+ assert x_a.mask.dtype.names == np.dtype(descr).names
+ assert_equal(x, x_a)
+
+ assert_(x is x.astype(x.dtype, copy=False))
+ assert_equal(type(x.astype(x.dtype, subok=False)), np.ndarray)
+
+ x_f = x.astype(x.dtype, order='F')
+ assert_(x_f.flags.f_contiguous)
+ assert_(x_f.mask.flags.f_contiguous)
+
+ # Also test the same indirectly, via np.array
+ x_a2 = np.array(x, dtype=descr, subok=True)
+ assert x_a2.dtype.names == np.dtype(descr).names
+ assert x_a2.mask.dtype.names == np.dtype(descr).names
+ assert_equal(x, x_a2)
+
+ assert_(x is np.array(x, dtype=descr, copy=False, subok=True))
+
+ x_f2 = np.array(x, dtype=x.dtype, order='F', subok=True)
+ assert_(x_f2.flags.f_contiguous)
+ assert_(x_f2.mask.flags.f_contiguous)
+
+
+@pytest.mark.parametrize('dt1', num_dts, ids=num_ids)
+@pytest.mark.parametrize('dt2', num_dts, ids=num_ids)
+@pytest.mark.filterwarnings('ignore::numpy.ComplexWarning')
+def test_astype_basic(dt1, dt2):
+ # See gh-12070
+ src = np.ma.array(ones(3, dt1), fill_value=1)
+ dst = src.astype(dt2)
+
+ assert_(src.fill_value == 1)
+ assert_(src.dtype == dt1)
+ assert_(src.fill_value.dtype == dt1)
+
+ assert_(dst.fill_value == 1)
+ assert_(dst.dtype == dt2)
+ assert_(dst.fill_value.dtype == dt2)
+
+ assert_equal(src, dst)
+
+
+def test_fieldless_void():
+ dt = np.dtype([]) # a void dtype with no fields
+ x = np.empty(4, dt)
+
+ # these arrays contain no values, so there's little to test - but this
+ # shouldn't crash
+ mx = np.ma.array(x)
+ assert_equal(mx.dtype, x.dtype)
+ assert_equal(mx.shape, x.shape)
+
+ mx = np.ma.array(x, mask=x)
+ assert_equal(mx.dtype, x.dtype)
+ assert_equal(mx.shape, x.shape)
+
+
+def test_mask_shape_assignment_does_not_break_masked():
+ a = np.ma.masked
+ b = np.ma.array(1, mask=a.mask)
+ b.shape = (1,)
+ assert_equal(a.mask.shape, ())
+
+@pytest.mark.skipif(sys.flags.optimize > 1,
+ reason="no docstrings present to inspect when PYTHONOPTIMIZE/Py_OptimizeFlag > 1")
+def test_doc_note():
+ def method(self):
+ """This docstring
+
+ Has multiple lines
+
+ And notes
+
+ Notes
+ -----
+ original note
+ """
+ pass
+
+ expected_doc = """This docstring
+
+Has multiple lines
+
+And notes
+
+Notes
+-----
+note
+
+original note"""
+
+ assert_equal(np.ma.core.doc_note(method.__doc__, "note"), expected_doc)
diff --git a/venv/lib/python3.9/site-packages/numpy/ma/tests/test_deprecations.py b/venv/lib/python3.9/site-packages/numpy/ma/tests/test_deprecations.py
new file mode 100644
index 00000000..40c8418f
--- /dev/null
+++ b/venv/lib/python3.9/site-packages/numpy/ma/tests/test_deprecations.py
@@ -0,0 +1,84 @@
+"""Test deprecation and future warnings.
+
+"""
+import pytest
+import numpy as np
+from numpy.testing import assert_warns
+from numpy.ma.testutils import assert_equal
+from numpy.ma.core import MaskedArrayFutureWarning
+import io
+import textwrap
+
+class TestArgsort:
+ """ gh-8701 """
+ def _test_base(self, argsort, cls):
+ arr_0d = np.array(1).view(cls)
+ argsort(arr_0d)
+
+ arr_1d = np.array([1, 2, 3]).view(cls)
+ argsort(arr_1d)
+
+ # argsort has a bad default for >1d arrays
+ arr_2d = np.array([[1, 2], [3, 4]]).view(cls)
+ result = assert_warns(
+ np.ma.core.MaskedArrayFutureWarning, argsort, arr_2d)
+ assert_equal(result, argsort(arr_2d, axis=None))
+
+ # should be no warnings for explicitly specifying it
+ argsort(arr_2d, axis=None)
+ argsort(arr_2d, axis=-1)
+
+ def test_function_ndarray(self):
+ return self._test_base(np.ma.argsort, np.ndarray)
+
+ def test_function_maskedarray(self):
+ return self._test_base(np.ma.argsort, np.ma.MaskedArray)
+
+ def test_method(self):
+ return self._test_base(np.ma.MaskedArray.argsort, np.ma.MaskedArray)
+
+
+class TestMinimumMaximum:
+
+ def test_axis_default(self):
+ # NumPy 1.13, 2017-05-06
+
+ data1d = np.ma.arange(6)
+ data2d = data1d.reshape(2, 3)
+
+ ma_min = np.ma.minimum.reduce
+ ma_max = np.ma.maximum.reduce
+
+ # check that the default axis is still None, but warns on 2d arrays
+ result = assert_warns(MaskedArrayFutureWarning, ma_max, data2d)
+ assert_equal(result, ma_max(data2d, axis=None))
+
+ result = assert_warns(MaskedArrayFutureWarning, ma_min, data2d)
+ assert_equal(result, ma_min(data2d, axis=None))
+
+ # no warnings on 1d, as both new and old defaults are equivalent
+ result = ma_min(data1d)
+ assert_equal(result, ma_min(data1d, axis=None))
+ assert_equal(result, ma_min(data1d, axis=0))
+
+ result = ma_max(data1d)
+ assert_equal(result, ma_max(data1d, axis=None))
+ assert_equal(result, ma_max(data1d, axis=0))
+
+
+class TestFromtextfile:
+ def test_fromtextfile_delimitor(self):
+ # NumPy 1.22.0, 2021-09-23
+
+ textfile = io.StringIO(textwrap.dedent(
+ """
+ A,B,C,D
+ 'string 1';1;1.0;'mixed column'
+ 'string 2';2;2.0;
+ 'string 3';3;3.0;123
+ 'string 4';4;4.0;3.14
+ """
+ ))
+
+ with pytest.warns(DeprecationWarning):
+ result = np.ma.mrecords.fromtextfile(textfile, delimitor=';')
diff --git a/venv/lib/python3.9/site-packages/numpy/ma/tests/test_extras.py b/venv/lib/python3.9/site-packages/numpy/ma/tests/test_extras.py
new file mode 100644
index 00000000..38603fb8
--- /dev/null
+++ b/venv/lib/python3.9/site-packages/numpy/ma/tests/test_extras.py
@@ -0,0 +1,1829 @@
+# pylint: disable-msg=W0611, W0612, W0511
+"""Tests suite for MaskedArray.
+Adapted from the original test_ma by Pierre Gerard-Marchant
+
+:author: Pierre Gerard-Marchant
+:contact: pierregm_at_uga_dot_edu
+:version: $Id: test_extras.py 3473 2007-10-29 15:18:13Z jarrod.millman $
+
+"""
+import warnings
+import itertools
+import pytest
+
+import numpy as np
+from numpy.core.numeric import normalize_axis_tuple
+from numpy.testing import (
+ assert_warns, suppress_warnings
+ )
+from numpy.ma.testutils import (
+ assert_, assert_array_equal, assert_equal, assert_almost_equal
+ )
+from numpy.ma.core import (
+ array, arange, masked, MaskedArray, masked_array, getmaskarray, shape,
+ nomask, ones, zeros, count
+ )
+from numpy.ma.extras import (
+ atleast_1d, atleast_2d, atleast_3d, mr_, dot, polyfit, cov, corrcoef,
+ median, average, unique, setxor1d, setdiff1d, union1d, intersect1d, in1d,
+ ediff1d, apply_over_axes, apply_along_axis, compress_nd, compress_rowcols,
+ mask_rowcols, clump_masked, clump_unmasked, flatnotmasked_contiguous,
+ notmasked_contiguous, notmasked_edges, masked_all, masked_all_like, isin,
+ diagflat, ndenumerate, stack, vstack
+ )
+
+
+class TestGeneric:
+ #
+ def test_masked_all(self):
+ # Tests masked_all
+ # Standard dtype
+ test = masked_all((2,), dtype=float)
+ control = array([1, 1], mask=[1, 1], dtype=float)
+ assert_equal(test, control)
+ # Flexible dtype
+ dt = np.dtype({'names': ['a', 'b'], 'formats': ['f', 'f']})
+ test = masked_all((2,), dtype=dt)
+ control = array([(0, 0), (0, 0)], mask=[(1, 1), (1, 1)], dtype=dt)
+ assert_equal(test, control)
+ test = masked_all((2, 2), dtype=dt)
+ control = array([[(0, 0), (0, 0)], [(0, 0), (0, 0)]],
+ mask=[[(1, 1), (1, 1)], [(1, 1), (1, 1)]],
+ dtype=dt)
+ assert_equal(test, control)
+ # Nested dtype
+ dt = np.dtype([('a', 'f'), ('b', [('ba', 'f'), ('bb', 'f')])])
+ test = masked_all((2,), dtype=dt)
+ control = array([(1, (1, 1)), (1, (1, 1))],
+ mask=[(1, (1, 1)), (1, (1, 1))], dtype=dt)
+ assert_equal(test, control)
+ test = masked_all((2,), dtype=dt)
+ control = array([(1, (1, 1)), (1, (1, 1))],
+ mask=[(1, (1, 1)), (1, (1, 1))], dtype=dt)
+ assert_equal(test, control)
+ test = masked_all((1, 1), dtype=dt)
+ control = array([[(1, (1, 1))]], mask=[[(1, (1, 1))]], dtype=dt)
+ assert_equal(test, control)
+
+ def test_masked_all_with_object_nested(self):
+ # Test masked_all works with nested array with dtype of an 'object'
+ # refers to issue #15895
+ my_dtype = np.dtype([('b', ([('c', object)], (1,)))])
+ masked_arr = np.ma.masked_all((1,), my_dtype)
+
+ assert_equal(type(masked_arr['b']), np.ma.core.MaskedArray)
+ assert_equal(type(masked_arr['b']['c']), np.ma.core.MaskedArray)
+ assert_equal(len(masked_arr['b']['c']), 1)
+ assert_equal(masked_arr['b']['c'].shape, (1, 1))
+ assert_equal(masked_arr['b']['c']._fill_value.shape, ())
+
+ def test_masked_all_with_object(self):
+ # same as above except that the array is not nested
+ my_dtype = np.dtype([('b', (object, (1,)))])
+ masked_arr = np.ma.masked_all((1,), my_dtype)
+
+ assert_equal(type(masked_arr['b']), np.ma.core.MaskedArray)
+ assert_equal(len(masked_arr['b']), 1)
+ assert_equal(masked_arr['b'].shape, (1, 1))
+ assert_equal(masked_arr['b']._fill_value.shape, ())
+
+ def test_masked_all_like(self):
+ # Tests masked_all
+ # Standard dtype
+ base = array([1, 2], dtype=float)
+ test = masked_all_like(base)
+ control = array([1, 1], mask=[1, 1], dtype=float)
+ assert_equal(test, control)
+ # Flexible dtype
+ dt = np.dtype({'names': ['a', 'b'], 'formats': ['f', 'f']})
+ base = array([(0, 0), (0, 0)], mask=[(1, 1), (1, 1)], dtype=dt)
+ test = masked_all_like(base)
+ control = array([(10, 10), (10, 10)], mask=[(1, 1), (1, 1)], dtype=dt)
+ assert_equal(test, control)
+ # Nested dtype
+ dt = np.dtype([('a', 'f'), ('b', [('ba', 'f'), ('bb', 'f')])])
+ control = array([(1, (1, 1)), (1, (1, 1))],
+ mask=[(1, (1, 1)), (1, (1, 1))], dtype=dt)
+ test = masked_all_like(control)
+ assert_equal(test, control)
+
+ def check_clump(self, f):
+ for i in range(1, 7):
+ for j in range(2**i):
+ k = np.arange(i, dtype=int)
+ ja = np.full(i, j, dtype=int)
+ a = masked_array(2**k)
+ a.mask = (ja & (2**k)) != 0
+ s = 0
+ for sl in f(a):
+ s += a.data[sl].sum()
+ if f == clump_unmasked:
+ assert_equal(a.compressed().sum(), s)
+ else:
+ a.mask = ~a.mask
+ assert_equal(a.compressed().sum(), s)
+
+ def test_clump_masked(self):
+ # Test clump_masked
+ a = masked_array(np.arange(10))
+ a[[0, 1, 2, 6, 8, 9]] = masked
+ #
+ test = clump_masked(a)
+ control = [slice(0, 3), slice(6, 7), slice(8, 10)]
+ assert_equal(test, control)
+
+ self.check_clump(clump_masked)
+
+ def test_clump_unmasked(self):
+ # Test clump_unmasked
+ a = masked_array(np.arange(10))
+ a[[0, 1, 2, 6, 8, 9]] = masked
+ test = clump_unmasked(a)
+ control = [slice(3, 6), slice(7, 8), ]
+ assert_equal(test, control)
+
+ self.check_clump(clump_unmasked)
+
+ def test_flatnotmasked_contiguous(self):
+ # Test flatnotmasked_contiguous
+ a = arange(10)
+ # No mask
+ test = flatnotmasked_contiguous(a)
+ assert_equal(test, [slice(0, a.size)])
+ # mask of all false
+ a.mask = np.zeros(10, dtype=bool)
+ assert_equal(test, [slice(0, a.size)])
+ # Some mask
+ a[(a < 3) | (a > 8) | (a == 5)] = masked
+ test = flatnotmasked_contiguous(a)
+ assert_equal(test, [slice(3, 5), slice(6, 9)])
+ #
+ a[:] = masked
+ test = flatnotmasked_contiguous(a)
+ assert_equal(test, [])
+
+
+class TestAverage:
+ # Several tests of average. Why so many ? Good point...
+ def test_testAverage1(self):
+ # Test of average.
+ ott = array([0., 1., 2., 3.], mask=[True, False, False, False])
+ assert_equal(2.0, average(ott, axis=0))
+ assert_equal(2.0, average(ott, weights=[1., 1., 2., 1.]))
+ result, wts = average(ott, weights=[1., 1., 2., 1.], returned=True)
+ assert_equal(2.0, result)
+ assert_(wts == 4.0)
+ ott[:] = masked
+ assert_equal(average(ott, axis=0).mask, [True])
+ ott = array([0., 1., 2., 3.], mask=[True, False, False, False])
+ ott = ott.reshape(2, 2)
+ ott[:, 1] = masked
+ assert_equal(average(ott, axis=0), [2.0, 0.0])
+ assert_equal(average(ott, axis=1).mask[0], [True])
+ assert_equal([2., 0.], average(ott, axis=0))
+ result, wts = average(ott, axis=0, returned=True)
+ assert_equal(wts, [1., 0.])
+
+ def test_testAverage2(self):
+ # More tests of average.
+ w1 = [0, 1, 1, 1, 1, 0]
+ w2 = [[0, 1, 1, 1, 1, 0], [1, 0, 0, 0, 0, 1]]
+ x = arange(6, dtype=np.float_)
+ assert_equal(average(x, axis=0), 2.5)
+ assert_equal(average(x, axis=0, weights=w1), 2.5)
+ y = array([arange(6, dtype=np.float_), 2.0 * arange(6)])
+ assert_equal(average(y, None), np.add.reduce(np.arange(6)) * 3. / 12.)
+ assert_equal(average(y, axis=0), np.arange(6) * 3. / 2.)
+ assert_equal(average(y, axis=1),
+ [average(x, axis=0), average(x, axis=0) * 2.0])
+ assert_equal(average(y, None, weights=w2), 20. / 6.)
+ assert_equal(average(y, axis=0, weights=w2),
+ [0., 1., 2., 3., 4., 10.])
+ assert_equal(average(y, axis=1),
+ [average(x, axis=0), average(x, axis=0) * 2.0])
+ m1 = zeros(6)
+ m2 = [0, 0, 1, 1, 0, 0]
+ m3 = [[0, 0, 1, 1, 0, 0], [0, 1, 1, 1, 1, 0]]
+ m4 = ones(6)
+ m5 = [0, 1, 1, 1, 1, 1]
+ assert_equal(average(masked_array(x, m1), axis=0), 2.5)
+ assert_equal(average(masked_array(x, m2), axis=0), 2.5)
+ assert_equal(average(masked_array(x, m4), axis=0).mask, [True])
+ assert_equal(average(masked_array(x, m5), axis=0), 0.0)
+ assert_equal(count(average(masked_array(x, m4), axis=0)), 0)
+ z = masked_array(y, m3)
+ assert_equal(average(z, None), 20. / 6.)
+ assert_equal(average(z, axis=0), [0., 1., 99., 99., 4.0, 7.5])
+ assert_equal(average(z, axis=1), [2.5, 5.0])
+ assert_equal(average(z, axis=0, weights=w2),
+ [0., 1., 99., 99., 4.0, 10.0])
+
+ def test_testAverage3(self):
+ # Yet more tests of average!
+ a = arange(6)
+ b = arange(6) * 3
+ r1, w1 = average([[a, b], [b, a]], axis=1, returned=True)
+ assert_equal(shape(r1), shape(w1))
+ assert_equal(r1.shape, w1.shape)
+ r2, w2 = average(ones((2, 2, 3)), axis=0, weights=[3, 1], returned=True)
+ assert_equal(shape(w2), shape(r2))
+ r2, w2 = average(ones((2, 2, 3)), returned=True)
+ assert_equal(shape(w2), shape(r2))
+ r2, w2 = average(ones((2, 2, 3)), weights=ones((2, 2, 3)), returned=True)
+ assert_equal(shape(w2), shape(r2))
+ a2d = array([[1, 2], [0, 4]], float)
+ a2dm = masked_array(a2d, [[False, False], [True, False]])
+ a2da = average(a2d, axis=0)
+ assert_equal(a2da, [0.5, 3.0])
+ a2dma = average(a2dm, axis=0)
+ assert_equal(a2dma, [1.0, 3.0])
+ a2dma = average(a2dm, axis=None)
+ assert_equal(a2dma, 7. / 3.)
+ a2dma = average(a2dm, axis=1)
+ assert_equal(a2dma, [1.5, 4.0])
+
+ def test_testAverage4(self):
+ # Test that `keepdims` works with average
+ x = np.array([2, 3, 4]).reshape(3, 1)
+ b = np.ma.array(x, mask=[[False], [False], [True]])
+ w = np.array([4, 5, 6]).reshape(3, 1)
+ actual = average(b, weights=w, axis=1, keepdims=True)
+ desired = masked_array([[2.], [3.], [4.]], [[False], [False], [True]])
+ assert_equal(actual, desired)
+
+ def test_onintegers_with_mask(self):
+ # Test average on integers with mask
+ a = average(array([1, 2]))
+ assert_equal(a, 1.5)
+ a = average(array([1, 2, 3, 4], mask=[False, False, True, True]))
+ assert_equal(a, 1.5)
+
+ def test_complex(self):
+ # Test with complex data.
+ # (Regression test for https://github.com/numpy/numpy/issues/2684)
+ mask = np.array([[0, 0, 0, 1, 0],
+ [0, 1, 0, 0, 0]], dtype=bool)
+ a = masked_array([[0, 1+2j, 3+4j, 5+6j, 7+8j],
+ [9j, 0+1j, 2+3j, 4+5j, 7+7j]],
+ mask=mask)
+
+ av = average(a)
+ expected = np.average(a.compressed())
+ assert_almost_equal(av.real, expected.real)
+ assert_almost_equal(av.imag, expected.imag)
+
+ av0 = average(a, axis=0)
+ expected0 = average(a.real, axis=0) + average(a.imag, axis=0)*1j
+ assert_almost_equal(av0.real, expected0.real)
+ assert_almost_equal(av0.imag, expected0.imag)
+
+ av1 = average(a, axis=1)
+ expected1 = average(a.real, axis=1) + average(a.imag, axis=1)*1j
+ assert_almost_equal(av1.real, expected1.real)
+ assert_almost_equal(av1.imag, expected1.imag)
+
+ # Test with the 'weights' argument.
+ wts = np.array([[0.5, 1.0, 2.0, 1.0, 0.5],
+ [1.0, 1.0, 1.0, 1.0, 1.0]])
+ wav = average(a, weights=wts)
+ expected = np.average(a.compressed(), weights=wts[~mask])
+ assert_almost_equal(wav.real, expected.real)
+ assert_almost_equal(wav.imag, expected.imag)
+
+ wav0 = average(a, weights=wts, axis=0)
+ expected0 = (average(a.real, weights=wts, axis=0) +
+ average(a.imag, weights=wts, axis=0)*1j)
+ assert_almost_equal(wav0.real, expected0.real)
+ assert_almost_equal(wav0.imag, expected0.imag)
+
+ wav1 = average(a, weights=wts, axis=1)
+ expected1 = (average(a.real, weights=wts, axis=1) +
+ average(a.imag, weights=wts, axis=1)*1j)
+ assert_almost_equal(wav1.real, expected1.real)
+ assert_almost_equal(wav1.imag, expected1.imag)
+
+ @pytest.mark.parametrize(
+ 'x, axis, expected_avg, weights, expected_wavg, expected_wsum',
+ [([1, 2, 3], None, [2.0], [3, 4, 1], [1.75], [8.0]),
+ ([[1, 2, 5], [1, 6, 11]], 0, [[1.0, 4.0, 8.0]],
+ [1, 3], [[1.0, 5.0, 9.5]], [[4, 4, 4]])],
+ )
+ def test_basic_keepdims(self, x, axis, expected_avg,
+ weights, expected_wavg, expected_wsum):
+ avg = np.ma.average(x, axis=axis, keepdims=True)
+ assert avg.shape == np.shape(expected_avg)
+ assert_array_equal(avg, expected_avg)
+
+ wavg = np.ma.average(x, axis=axis, weights=weights, keepdims=True)
+ assert wavg.shape == np.shape(expected_wavg)
+ assert_array_equal(wavg, expected_wavg)
+
+ wavg, wsum = np.ma.average(x, axis=axis, weights=weights,
+ returned=True, keepdims=True)
+ assert wavg.shape == np.shape(expected_wavg)
+ assert_array_equal(wavg, expected_wavg)
+ assert wsum.shape == np.shape(expected_wsum)
+ assert_array_equal(wsum, expected_wsum)
+
+ def test_masked_weights(self):
+ # Test with masked weights.
+ # (Regression test for https://github.com/numpy/numpy/issues/10438)
+ a = np.ma.array(np.arange(9).reshape(3, 3),
+ mask=[[1, 0, 0], [1, 0, 0], [0, 0, 0]])
+ weights_unmasked = masked_array([5, 28, 31], mask=False)
+ weights_masked = masked_array([5, 28, 31], mask=[1, 0, 0])
+
+ avg_unmasked = average(a, axis=0,
+ weights=weights_unmasked, returned=False)
+ expected_unmasked = np.array([6.0, 5.21875, 6.21875])
+ assert_almost_equal(avg_unmasked, expected_unmasked)
+
+ avg_masked = average(a, axis=0, weights=weights_masked, returned=False)
+ expected_masked = np.array([6.0, 5.576271186440678, 6.576271186440678])
+ assert_almost_equal(avg_masked, expected_masked)
+
+ # weights should be masked if needed
+ # depending on the array mask. This is to avoid summing
+ # masked nan or other values that are not cancelled by a zero
+ a = np.ma.array([1.0, 2.0, 3.0, 4.0],
+ mask=[False, False, True, True])
+ avg_unmasked = average(a, weights=[1, 1, 1, np.nan])
+
+ assert_almost_equal(avg_unmasked, 1.5)
+
+ a = np.ma.array([
+ [1.0, 2.0, 3.0, 4.0],
+ [5.0, 6.0, 7.0, 8.0],
+ [9.0, 1.0, 2.0, 3.0],
+ ], mask=[
+ [False, True, True, False],
+ [True, False, True, True],
+ [True, False, True, False],
+ ])
+
+ avg_masked = np.ma.average(a, weights=[1, np.nan, 1], axis=0)
+ avg_expected = np.ma.array([1.0, np.nan, np.nan, 3.5],
+ mask=[False, True, True, False])
+
+ assert_almost_equal(avg_masked, avg_expected)
+ assert_equal(avg_masked.mask, avg_expected.mask)
+
+
+class TestConcatenator:
+ # Tests for mr_, the equivalent of r_ for masked arrays.
+
+ def test_1d(self):
+ # Tests mr_ on 1D arrays.
+ assert_array_equal(mr_[1, 2, 3, 4, 5, 6], array([1, 2, 3, 4, 5, 6]))
+ b = ones(5)
+ m = [1, 0, 0, 0, 0]
+ d = masked_array(b, mask=m)
+ c = mr_[d, 0, 0, d]
+ assert_(isinstance(c, MaskedArray))
+ assert_array_equal(c, [1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1])
+ assert_array_equal(c.mask, mr_[m, 0, 0, m])
+
+ def test_2d(self):
+ # Tests mr_ on 2D arrays.
+ a_1 = np.random.rand(5, 5)
+ a_2 = np.random.rand(5, 5)
+ m_1 = np.round_(np.random.rand(5, 5), 0)
+ m_2 = np.round_(np.random.rand(5, 5), 0)
+ b_1 = masked_array(a_1, mask=m_1)
+ b_2 = masked_array(a_2, mask=m_2)
+ # append columns
+ d = mr_['1', b_1, b_2]
+ assert_(d.shape == (5, 10))
+ assert_array_equal(d[:, :5], b_1)
+ assert_array_equal(d[:, 5:], b_2)
+ assert_array_equal(d.mask, np.r_['1', m_1, m_2])
+ d = mr_[b_1, b_2]
+ assert_(d.shape == (10, 5))
+ assert_array_equal(d[:5,:], b_1)
+ assert_array_equal(d[5:,:], b_2)
+ assert_array_equal(d.mask, np.r_[m_1, m_2])
+
+ def test_masked_constant(self):
+ actual = mr_[np.ma.masked, 1]
+ assert_equal(actual.mask, [True, False])
+ assert_equal(actual.data[1], 1)
+
+ actual = mr_[[1, 2], np.ma.masked]
+ assert_equal(actual.mask, [False, False, True])
+ assert_equal(actual.data[:2], [1, 2])
+
+
+class TestNotMasked:
+ # Tests notmasked_edges and notmasked_contiguous.
+
+ def test_edges(self):
+ # Tests unmasked_edges
+ data = masked_array(np.arange(25).reshape(5, 5),
+ mask=[[0, 0, 1, 0, 0],
+ [0, 0, 0, 1, 1],
+ [1, 1, 0, 0, 0],
+ [0, 0, 0, 0, 0],
+ [1, 1, 1, 0, 0]],)
+ test = notmasked_edges(data, None)
+ assert_equal(test, [0, 24])
+ test = notmasked_edges(data, 0)
+ assert_equal(test[0], [(0, 0, 1, 0, 0), (0, 1, 2, 3, 4)])
+ assert_equal(test[1], [(3, 3, 3, 4, 4), (0, 1, 2, 3, 4)])
+ test = notmasked_edges(data, 1)
+ assert_equal(test[0], [(0, 1, 2, 3, 4), (0, 0, 2, 0, 3)])
+ assert_equal(test[1], [(0, 1, 2, 3, 4), (4, 2, 4, 4, 4)])
+ #
+ test = notmasked_edges(data.data, None)
+ assert_equal(test, [0, 24])
+ test = notmasked_edges(data.data, 0)
+ assert_equal(test[0], [(0, 0, 0, 0, 0), (0, 1, 2, 3, 4)])
+ assert_equal(test[1], [(4, 4, 4, 4, 4), (0, 1, 2, 3, 4)])
+ test = notmasked_edges(data.data, -1)
+ assert_equal(test[0], [(0, 1, 2, 3, 4), (0, 0, 0, 0, 0)])
+ assert_equal(test[1], [(0, 1, 2, 3, 4), (4, 4, 4, 4, 4)])
+ #
+ data[-2] = masked
+ test = notmasked_edges(data, 0)
+ assert_equal(test[0], [(0, 0, 1, 0, 0), (0, 1, 2, 3, 4)])
+ assert_equal(test[1], [(1, 1, 2, 4, 4), (0, 1, 2, 3, 4)])
+ test = notmasked_edges(data, -1)
+ assert_equal(test[0], [(0, 1, 2, 4), (0, 0, 2, 3)])
+ assert_equal(test[1], [(0, 1, 2, 4), (4, 2, 4, 4)])
+
+ def test_contiguous(self):
+ # Tests notmasked_contiguous
+ a = masked_array(np.arange(24).reshape(3, 8),
+ mask=[[0, 0, 0, 0, 1, 1, 1, 1],
+ [1, 1, 1, 1, 1, 1, 1, 1],
+ [0, 0, 0, 0, 0, 0, 1, 0]])
+ tmp = notmasked_contiguous(a, None)
+ assert_equal(tmp, [
+ slice(0, 4, None),
+ slice(16, 22, None),
+ slice(23, 24, None)
+ ])
+
+ tmp = notmasked_contiguous(a, 0)
+ assert_equal(tmp, [
+ [slice(0, 1, None), slice(2, 3, None)],
+ [slice(0, 1, None), slice(2, 3, None)],
+ [slice(0, 1, None), slice(2, 3, None)],
+ [slice(0, 1, None), slice(2, 3, None)],
+ [slice(2, 3, None)],
+ [slice(2, 3, None)],
+ [],
+ [slice(2, 3, None)]
+ ])
+ #
+ tmp = notmasked_contiguous(a, 1)
+ assert_equal(tmp, [
+ [slice(0, 4, None)],
+ [],
+ [slice(0, 6, None), slice(7, 8, None)]
+ ])
+
+
+class TestCompressFunctions:
+
+ def test_compress_nd(self):
+ # Tests compress_nd
+ x = np.array(list(range(3*4*5))).reshape(3, 4, 5)
+ m = np.zeros((3,4,5)).astype(bool)
+ m[1,1,1] = True
+ x = array(x, mask=m)
+
+ # axis=None
+ a = compress_nd(x)
+ assert_equal(a, [[[ 0, 2, 3, 4],
+ [10, 12, 13, 14],
+ [15, 17, 18, 19]],
+ [[40, 42, 43, 44],
+ [50, 52, 53, 54],
+ [55, 57, 58, 59]]])
+
+ # axis=0
+ a = compress_nd(x, 0)
+ assert_equal(a, [[[ 0, 1, 2, 3, 4],
+ [ 5, 6, 7, 8, 9],
+ [10, 11, 12, 13, 14],
+ [15, 16, 17, 18, 19]],
+ [[40, 41, 42, 43, 44],
+ [45, 46, 47, 48, 49],
+ [50, 51, 52, 53, 54],
+ [55, 56, 57, 58, 59]]])
+
+ # axis=1
+ a = compress_nd(x, 1)
+ assert_equal(a, [[[ 0, 1, 2, 3, 4],
+ [10, 11, 12, 13, 14],
+ [15, 16, 17, 18, 19]],
+ [[20, 21, 22, 23, 24],
+ [30, 31, 32, 33, 34],
+ [35, 36, 37, 38, 39]],
+ [[40, 41, 42, 43, 44],
+ [50, 51, 52, 53, 54],
+ [55, 56, 57, 58, 59]]])
+
+ a2 = compress_nd(x, (1,))
+ a3 = compress_nd(x, -2)
+ a4 = compress_nd(x, (-2,))
+ assert_equal(a, a2)
+ assert_equal(a, a3)
+ assert_equal(a, a4)
+
+ # axis=2
+ a = compress_nd(x, 2)
+ assert_equal(a, [[[ 0, 2, 3, 4],
+ [ 5, 7, 8, 9],
+ [10, 12, 13, 14],
+ [15, 17, 18, 19]],
+ [[20, 22, 23, 24],
+ [25, 27, 28, 29],
+ [30, 32, 33, 34],
+ [35, 37, 38, 39]],
+ [[40, 42, 43, 44],
+ [45, 47, 48, 49],
+ [50, 52, 53, 54],
+ [55, 57, 58, 59]]])
+
+ a2 = compress_nd(x, (2,))
+ a3 = compress_nd(x, -1)
+ a4 = compress_nd(x, (-1,))
+ assert_equal(a, a2)
+ assert_equal(a, a3)
+ assert_equal(a, a4)
+
+ # axis=(0, 1)
+ a = compress_nd(x, (0, 1))
+ assert_equal(a, [[[ 0, 1, 2, 3, 4],
+ [10, 11, 12, 13, 14],
+ [15, 16, 17, 18, 19]],
+ [[40, 41, 42, 43, 44],
+ [50, 51, 52, 53, 54],
+ [55, 56, 57, 58, 59]]])
+ a2 = compress_nd(x, (0, -2))
+ assert_equal(a, a2)
+
+ # axis=(1, 2)
+ a = compress_nd(x, (1, 2))
+ assert_equal(a, [[[ 0, 2, 3, 4],
+ [10, 12, 13, 14],
+ [15, 17, 18, 19]],
+ [[20, 22, 23, 24],
+ [30, 32, 33, 34],
+ [35, 37, 38, 39]],
+ [[40, 42, 43, 44],
+ [50, 52, 53, 54],
+ [55, 57, 58, 59]]])
+
+ a2 = compress_nd(x, (-2, 2))
+ a3 = compress_nd(x, (1, -1))
+ a4 = compress_nd(x, (-2, -1))
+ assert_equal(a, a2)
+ assert_equal(a, a3)
+ assert_equal(a, a4)
+
+ # axis=(0, 2)
+ a = compress_nd(x, (0, 2))
+ assert_equal(a, [[[ 0, 2, 3, 4],
+ [ 5, 7, 8, 9],
+ [10, 12, 13, 14],
+ [15, 17, 18, 19]],
+ [[40, 42, 43, 44],
+ [45, 47, 48, 49],
+ [50, 52, 53, 54],
+ [55, 57, 58, 59]]])
+
+ a2 = compress_nd(x, (0, -1))
+ assert_equal(a, a2)
+
+ def test_compress_rowcols(self):
+ # Tests compress_rowcols
+ x = array(np.arange(9).reshape(3, 3),
+ mask=[[1, 0, 0], [0, 0, 0], [0, 0, 0]])
+ assert_equal(compress_rowcols(x), [[4, 5], [7, 8]])
+ assert_equal(compress_rowcols(x, 0), [[3, 4, 5], [6, 7, 8]])
+ assert_equal(compress_rowcols(x, 1), [[1, 2], [4, 5], [7, 8]])
+ x = array(x._data, mask=[[0, 0, 0], [0, 1, 0], [0, 0, 0]])
+ assert_equal(compress_rowcols(x), [[0, 2], [6, 8]])
+ assert_equal(compress_rowcols(x, 0), [[0, 1, 2], [6, 7, 8]])
+ assert_equal(compress_rowcols(x, 1), [[0, 2], [3, 5], [6, 8]])
+ x = array(x._data, mask=[[1, 0, 0], [0, 1, 0], [0, 0, 0]])
+ assert_equal(compress_rowcols(x), [[8]])
+ assert_equal(compress_rowcols(x, 0), [[6, 7, 8]])
+ assert_equal(compress_rowcols(x, 1,), [[2], [5], [8]])
+ x = array(x._data, mask=[[1, 0, 0], [0, 1, 0], [0, 0, 1]])
+ assert_equal(compress_rowcols(x).size, 0)
+ assert_equal(compress_rowcols(x, 0).size, 0)
+ assert_equal(compress_rowcols(x, 1).size, 0)
+
+ def test_mask_rowcols(self):
+ # Tests mask_rowcols.
+ x = array(np.arange(9).reshape(3, 3),
+ mask=[[1, 0, 0], [0, 0, 0], [0, 0, 0]])
+ assert_equal(mask_rowcols(x).mask,
+ [[1, 1, 1], [1, 0, 0], [1, 0, 0]])
+ assert_equal(mask_rowcols(x, 0).mask,
+ [[1, 1, 1], [0, 0, 0], [0, 0, 0]])
+ assert_equal(mask_rowcols(x, 1).mask,
+ [[1, 0, 0], [1, 0, 0], [1, 0, 0]])
+ x = array(x._data, mask=[[0, 0, 0], [0, 1, 0], [0, 0, 0]])
+ assert_equal(mask_rowcols(x).mask,
+ [[0, 1, 0], [1, 1, 1], [0, 1, 0]])
+ assert_equal(mask_rowcols(x, 0).mask,
+ [[0, 0, 0], [1, 1, 1], [0, 0, 0]])
+ assert_equal(mask_rowcols(x, 1).mask,
+ [[0, 1, 0], [0, 1, 0], [0, 1, 0]])
+ x = array(x._data, mask=[[1, 0, 0], [0, 1, 0], [0, 0, 0]])
+ assert_equal(mask_rowcols(x).mask,
+ [[1, 1, 1], [1, 1, 1], [1, 1, 0]])
+ assert_equal(mask_rowcols(x, 0).mask,
+ [[1, 1, 1], [1, 1, 1], [0, 0, 0]])
+ assert_equal(mask_rowcols(x, 1,).mask,
+ [[1, 1, 0], [1, 1, 0], [1, 1, 0]])
+ x = array(x._data, mask=[[1, 0, 0], [0, 1, 0], [0, 0, 1]])
+ assert_(mask_rowcols(x).all() is masked)
+ assert_(mask_rowcols(x, 0).all() is masked)
+ assert_(mask_rowcols(x, 1).all() is masked)
+ assert_(mask_rowcols(x).mask.all())
+ assert_(mask_rowcols(x, 0).mask.all())
+ assert_(mask_rowcols(x, 1).mask.all())
+
+ @pytest.mark.parametrize("axis", [None, 0, 1])
+ @pytest.mark.parametrize(["func", "rowcols_axis"],
+ [(np.ma.mask_rows, 0), (np.ma.mask_cols, 1)])
+ def test_mask_row_cols_axis_deprecation(self, axis, func, rowcols_axis):
+ # Test deprecation of the axis argument to `mask_rows` and `mask_cols`
+ x = array(np.arange(9).reshape(3, 3),
+ mask=[[1, 0, 0], [0, 0, 0], [0, 0, 0]])
+
+ with assert_warns(DeprecationWarning):
+ res = func(x, axis=axis)
+ assert_equal(res, mask_rowcols(x, rowcols_axis))
+
+ def test_dot(self):
+ # Tests dot product
+ n = np.arange(1, 7)
+ #
+ m = [1, 0, 0, 0, 0, 0]
+ a = masked_array(n, mask=m).reshape(2, 3)
+ b = masked_array(n, mask=m).reshape(3, 2)
+ c = dot(a, b, strict=True)
+ assert_equal(c.mask, [[1, 1], [1, 0]])
+ c = dot(b, a, strict=True)
+ assert_equal(c.mask, [[1, 1, 1], [1, 0, 0], [1, 0, 0]])
+ c = dot(a, b, strict=False)
+ assert_equal(c, np.dot(a.filled(0), b.filled(0)))
+ c = dot(b, a, strict=False)
+ assert_equal(c, np.dot(b.filled(0), a.filled(0)))
+ #
+ m = [0, 0, 0, 0, 0, 1]
+ a = masked_array(n, mask=m).reshape(2, 3)
+ b = masked_array(n, mask=m).reshape(3, 2)
+ c = dot(a, b, strict=True)
+ assert_equal(c.mask, [[0, 1], [1, 1]])
+ c = dot(b, a, strict=True)
+ assert_equal(c.mask, [[0, 0, 1], [0, 0, 1], [1, 1, 1]])
+ c = dot(a, b, strict=False)
+ assert_equal(c, np.dot(a.filled(0), b.filled(0)))
+ assert_equal(c, dot(a, b))
+ c = dot(b, a, strict=False)
+ assert_equal(c, np.dot(b.filled(0), a.filled(0)))
+ #
+ m = [0, 0, 0, 0, 0, 0]
+ a = masked_array(n, mask=m).reshape(2, 3)
+ b = masked_array(n, mask=m).reshape(3, 2)
+ c = dot(a, b)
+ assert_equal(c.mask, nomask)
+ c = dot(b, a)
+ assert_equal(c.mask, nomask)
+ #
+ a = masked_array(n, mask=[1, 0, 0, 0, 0, 0]).reshape(2, 3)
+ b = masked_array(n, mask=[0, 0, 0, 0, 0, 0]).reshape(3, 2)
+ c = dot(a, b, strict=True)
+ assert_equal(c.mask, [[1, 1], [0, 0]])
+ c = dot(a, b, strict=False)
+ assert_equal(c, np.dot(a.filled(0), b.filled(0)))
+ c = dot(b, a, strict=True)
+ assert_equal(c.mask, [[1, 0, 0], [1, 0, 0], [1, 0, 0]])
+ c = dot(b, a, strict=False)
+ assert_equal(c, np.dot(b.filled(0), a.filled(0)))
+ #
+ a = masked_array(n, mask=[0, 0, 0, 0, 0, 1]).reshape(2, 3)
+ b = masked_array(n, mask=[0, 0, 0, 0, 0, 0]).reshape(3, 2)
+ c = dot(a, b, strict=True)
+ assert_equal(c.mask, [[0, 0], [1, 1]])
+ c = dot(a, b)
+ assert_equal(c, np.dot(a.filled(0), b.filled(0)))
+ c = dot(b, a, strict=True)
+ assert_equal(c.mask, [[0, 0, 1], [0, 0, 1], [0, 0, 1]])
+ c = dot(b, a, strict=False)
+ assert_equal(c, np.dot(b.filled(0), a.filled(0)))
+ #
+ a = masked_array(n, mask=[0, 0, 0, 0, 0, 1]).reshape(2, 3)
+ b = masked_array(n, mask=[0, 0, 1, 0, 0, 0]).reshape(3, 2)
+ c = dot(a, b, strict=True)
+ assert_equal(c.mask, [[1, 0], [1, 1]])
+ c = dot(a, b, strict=False)
+ assert_equal(c, np.dot(a.filled(0), b.filled(0)))
+ c = dot(b, a, strict=True)
+ assert_equal(c.mask, [[0, 0, 1], [1, 1, 1], [0, 0, 1]])
+ c = dot(b, a, strict=False)
+ assert_equal(c, np.dot(b.filled(0), a.filled(0)))
+
+ def test_dot_returns_maskedarray(self):
+ # See gh-6611
+ a = np.eye(3)
+ b = array(a)
+ assert_(type(dot(a, a)) is MaskedArray)
+ assert_(type(dot(a, b)) is MaskedArray)
+ assert_(type(dot(b, a)) is MaskedArray)
+ assert_(type(dot(b, b)) is MaskedArray)
+
+ def test_dot_out(self):
+ a = array(np.eye(3))
+ out = array(np.zeros((3, 3)))
+ res = dot(a, a, out=out)
+ assert_(res is out)
+ assert_equal(a, res)
+
+
+class TestApplyAlongAxis:
+ # Tests 2D functions
+ def test_3d(self):
+ a = arange(12.).reshape(2, 2, 3)
+
+ def myfunc(b):
+ return b[1]
+
+ 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:
+ # Tests apply_over_axes
+ def test_basic(self):
+ a = arange(24).reshape(2, 3, 4)
+ test = apply_over_axes(np.sum, a, [0, 2])
+ ctrl = np.array([[[60], [92], [124]]])
+ assert_equal(test, ctrl)
+ a[(a % 2).astype(bool)] = masked
+ test = apply_over_axes(np.sum, a, [0, 2])
+ ctrl = np.array([[[28], [44], [60]]])
+ assert_equal(test, ctrl)
+
+
+class TestMedian:
+ def test_pytype(self):
+ r = np.ma.median([[np.inf, np.inf], [np.inf, np.inf]], axis=-1)
+ assert_equal(r, np.inf)
+
+ def test_inf(self):
+ # test that even which computes handles inf / x = masked
+ r = np.ma.median(np.ma.masked_array([[np.inf, np.inf],
+ [np.inf, np.inf]]), axis=-1)
+ assert_equal(r, np.inf)
+ r = np.ma.median(np.ma.masked_array([[np.inf, np.inf],
+ [np.inf, np.inf]]), axis=None)
+ assert_equal(r, np.inf)
+ # all masked
+ r = np.ma.median(np.ma.masked_array([[np.inf, np.inf],
+ [np.inf, np.inf]], mask=True),
+ axis=-1)
+ assert_equal(r.mask, True)
+ r = np.ma.median(np.ma.masked_array([[np.inf, np.inf],
+ [np.inf, np.inf]], mask=True),
+ axis=None)
+ assert_equal(r.mask, True)
+
+ def test_non_masked(self):
+ x = np.arange(9)
+ assert_equal(np.ma.median(x), 4.)
+ assert_(type(np.ma.median(x)) is not MaskedArray)
+ x = range(8)
+ assert_equal(np.ma.median(x), 3.5)
+ assert_(type(np.ma.median(x)) is not MaskedArray)
+ x = 5
+ assert_equal(np.ma.median(x), 5.)
+ assert_(type(np.ma.median(x)) is not MaskedArray)
+ # integer
+ x = np.arange(9 * 8).reshape(9, 8)
+ assert_equal(np.ma.median(x, axis=0), np.median(x, axis=0))
+ assert_equal(np.ma.median(x, axis=1), np.median(x, axis=1))
+ assert_(np.ma.median(x, axis=1) is not MaskedArray)
+ # float
+ x = np.arange(9 * 8.).reshape(9, 8)
+ assert_equal(np.ma.median(x, axis=0), np.median(x, axis=0))
+ assert_equal(np.ma.median(x, axis=1), np.median(x, axis=1))
+ assert_(np.ma.median(x, axis=1) is not MaskedArray)
+
+ def test_docstring_examples(self):
+ "test the examples given in the docstring of ma.median"
+ x = array(np.arange(8), mask=[0]*4 + [1]*4)
+ assert_equal(np.ma.median(x), 1.5)
+ assert_equal(np.ma.median(x).shape, (), "shape mismatch")
+ assert_(type(np.ma.median(x)) is not MaskedArray)
+ x = array(np.arange(10).reshape(2, 5), mask=[0]*6 + [1]*4)
+ assert_equal(np.ma.median(x), 2.5)
+ assert_equal(np.ma.median(x).shape, (), "shape mismatch")
+ assert_(type(np.ma.median(x)) is not MaskedArray)
+ ma_x = np.ma.median(x, axis=-1, overwrite_input=True)
+ assert_equal(ma_x, [2., 5.])
+ assert_equal(ma_x.shape, (2,), "shape mismatch")
+ assert_(type(ma_x) is MaskedArray)
+
+ def test_axis_argument_errors(self):
+ msg = "mask = %s, ndim = %s, axis = %s, overwrite_input = %s"
+ for ndmin in range(5):
+ for mask in [False, True]:
+ x = array(1, ndmin=ndmin, mask=mask)
+
+ # Valid axis values should not raise exception
+ args = itertools.product(range(-ndmin, ndmin), [False, True])
+ for axis, over in args:
+ try:
+ np.ma.median(x, axis=axis, overwrite_input=over)
+ except Exception:
+ raise AssertionError(msg % (mask, ndmin, axis, over))
+
+ # Invalid axis values should raise exception
+ args = itertools.product([-(ndmin + 1), ndmin], [False, True])
+ for axis, over in args:
+ try:
+ np.ma.median(x, axis=axis, overwrite_input=over)
+ except np.AxisError:
+ pass
+ else:
+ raise AssertionError(msg % (mask, ndmin, axis, over))
+
+ def test_masked_0d(self):
+ # Check values
+ x = array(1, mask=False)
+ assert_equal(np.ma.median(x), 1)
+ x = array(1, mask=True)
+ assert_equal(np.ma.median(x), np.ma.masked)
+
+ def test_masked_1d(self):
+ x = array(np.arange(5), mask=True)
+ assert_equal(np.ma.median(x), np.ma.masked)
+ assert_equal(np.ma.median(x).shape, (), "shape mismatch")
+ assert_(type(np.ma.median(x)) is np.ma.core.MaskedConstant)
+ x = array(np.arange(5), mask=False)
+ assert_equal(np.ma.median(x), 2.)
+ assert_equal(np.ma.median(x).shape, (), "shape mismatch")
+ assert_(type(np.ma.median(x)) is not MaskedArray)
+ x = array(np.arange(5), mask=[0,1,0,0,0])
+ assert_equal(np.ma.median(x), 2.5)
+ assert_equal(np.ma.median(x).shape, (), "shape mismatch")
+ assert_(type(np.ma.median(x)) is not MaskedArray)
+ x = array(np.arange(5), mask=[0,1,1,1,1])
+ assert_equal(np.ma.median(x), 0.)
+ assert_equal(np.ma.median(x).shape, (), "shape mismatch")
+ assert_(type(np.ma.median(x)) is not MaskedArray)
+ # integer
+ x = array(np.arange(5), mask=[0,1,1,0,0])
+ assert_equal(np.ma.median(x), 3.)
+ assert_equal(np.ma.median(x).shape, (), "shape mismatch")
+ assert_(type(np.ma.median(x)) is not MaskedArray)
+ # float
+ x = array(np.arange(5.), mask=[0,1,1,0,0])
+ assert_equal(np.ma.median(x), 3.)
+ assert_equal(np.ma.median(x).shape, (), "shape mismatch")
+ assert_(type(np.ma.median(x)) is not MaskedArray)
+ # integer
+ x = array(np.arange(6), mask=[0,1,1,1,1,0])
+ assert_equal(np.ma.median(x), 2.5)
+ assert_equal(np.ma.median(x).shape, (), "shape mismatch")
+ assert_(type(np.ma.median(x)) is not MaskedArray)
+ # float
+ x = array(np.arange(6.), mask=[0,1,1,1,1,0])
+ assert_equal(np.ma.median(x), 2.5)
+ assert_equal(np.ma.median(x).shape, (), "shape mismatch")
+ assert_(type(np.ma.median(x)) is not MaskedArray)
+
+ def test_1d_shape_consistency(self):
+ assert_equal(np.ma.median(array([1,2,3],mask=[0,0,0])).shape,
+ np.ma.median(array([1,2,3],mask=[0,1,0])).shape )
+
+ def test_2d(self):
+ # Tests median w/ 2D
+ (n, p) = (101, 30)
+ x = masked_array(np.linspace(-1., 1., n),)
+ x[:10] = x[-10:] = masked
+ z = masked_array(np.empty((n, p), dtype=float))
+ z[:, 0] = x[:]
+ idx = np.arange(len(x))
+ for i in range(1, p):
+ np.random.shuffle(idx)
+ z[:, i] = x[idx]
+ assert_equal(median(z[:, 0]), 0)
+ assert_equal(median(z), 0)
+ assert_equal(median(z, axis=0), np.zeros(p))
+ assert_equal(median(z.T, axis=1), np.zeros(p))
+
+ def test_2d_waxis(self):
+ # Tests median w/ 2D arrays and different axis.
+ x = masked_array(np.arange(30).reshape(10, 3))
+ x[:3] = x[-3:] = masked
+ assert_equal(median(x), 14.5)
+ assert_(type(np.ma.median(x)) is not MaskedArray)
+ assert_equal(median(x, axis=0), [13.5, 14.5, 15.5])
+ assert_(type(np.ma.median(x, axis=0)) is MaskedArray)
+ assert_equal(median(x, axis=1), [0, 0, 0, 10, 13, 16, 19, 0, 0, 0])
+ assert_(type(np.ma.median(x, axis=1)) is MaskedArray)
+ assert_equal(median(x, axis=1).mask, [1, 1, 1, 0, 0, 0, 0, 1, 1, 1])
+
+ def test_3d(self):
+ # Tests median w/ 3D
+ x = np.ma.arange(24).reshape(3, 4, 2)
+ x[x % 3 == 0] = masked
+ assert_equal(median(x, 0), [[12, 9], [6, 15], [12, 9], [18, 15]])
+ x.shape = (4, 3, 2)
+ assert_equal(median(x, 0), [[99, 10], [11, 99], [13, 14]])
+ x = np.ma.arange(24).reshape(4, 3, 2)
+ 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_1d(self):
+ # integer float even odd
+ for v in (30, 30., 31, 31.):
+ x = masked_array(np.arange(v))
+ x[:3] = x[-3:] = masked
+ out = masked_array(np.ones(()))
+ r = median(x, out=out)
+ if v == 30:
+ assert_equal(out, 14.5)
+ else:
+ assert_equal(out, 15.)
+ assert_(r is out)
+ assert_(type(r) is MaskedArray)
+
+ def test_out(self):
+ # integer float even odd
+ for v in (40, 40., 30, 30.):
+ x = masked_array(np.arange(v).reshape(10, -1))
+ x[:3] = x[-3:] = masked
+ out = masked_array(np.ones(10))
+ r = median(x, axis=1, out=out)
+ if v == 30:
+ e = masked_array([0.]*3 + [10, 13, 16, 19] + [0.]*3,
+ mask=[True] * 3 + [False] * 4 + [True] * 3)
+ else:
+ e = masked_array([0.]*3 + [13.5, 17.5, 21.5, 25.5] + [0.]*3,
+ mask=[True]*3 + [False]*4 + [True]*3)
+ assert_equal(r, e)
+ assert_(r is out)
+ assert_(type(r) is MaskedArray)
+
+ @pytest.mark.parametrize(
+ argnames='axis',
+ argvalues=[
+ None,
+ 1,
+ (1, ),
+ (0, 1),
+ (-3, -1),
+ ]
+ )
+ def test_keepdims_out(self, axis):
+ mask = np.zeros((3, 5, 7, 11), dtype=bool)
+ # Randomly set some elements to True:
+ w = np.random.random((4, 200)) * np.array(mask.shape)[:, None]
+ w = w.astype(np.intp)
+ mask[tuple(w)] = np.nan
+ d = masked_array(np.ones(mask.shape), mask=mask)
+ if axis is None:
+ shape_out = (1,) * d.ndim
+ else:
+ axis_norm = normalize_axis_tuple(axis, d.ndim)
+ shape_out = tuple(
+ 1 if i in axis_norm else d.shape[i] for i in range(d.ndim))
+ out = masked_array(np.empty(shape_out))
+ result = median(d, axis=axis, keepdims=True, out=out)
+ assert result is out
+ assert_equal(result.shape, shape_out)
+
+ def test_single_non_masked_value_on_axis(self):
+ data = [[1., 0.],
+ [0., 3.],
+ [0., 0.]]
+ masked_arr = np.ma.masked_equal(data, 0)
+ expected = [1., 3.]
+ assert_array_equal(np.ma.median(masked_arr, axis=0),
+ expected)
+
+ def test_nan(self):
+ for mask in (False, np.zeros(6, dtype=bool)):
+ dm = np.ma.array([[1, np.nan, 3], [1, 2, 3]])
+ dm.mask = mask
+
+ # scalar result
+ r = np.ma.median(dm, axis=None)
+ assert_(np.isscalar(r))
+ assert_array_equal(r, np.nan)
+ r = np.ma.median(dm.ravel(), axis=0)
+ assert_(np.isscalar(r))
+ assert_array_equal(r, np.nan)
+
+ r = np.ma.median(dm, axis=0)
+ assert_equal(type(r), MaskedArray)
+ assert_array_equal(r, [1, np.nan, 3])
+ r = np.ma.median(dm, axis=1)
+ assert_equal(type(r), MaskedArray)
+ assert_array_equal(r, [np.nan, 2])
+ r = np.ma.median(dm, axis=-1)
+ assert_equal(type(r), MaskedArray)
+ assert_array_equal(r, [np.nan, 2])
+
+ dm = np.ma.array([[1, np.nan, 3], [1, 2, 3]])
+ dm[:, 2] = np.ma.masked
+ assert_array_equal(np.ma.median(dm, axis=None), np.nan)
+ assert_array_equal(np.ma.median(dm, axis=0), [1, np.nan, 3])
+ assert_array_equal(np.ma.median(dm, axis=1), [np.nan, 1.5])
+
+ def test_out_nan(self):
+ o = np.ma.masked_array(np.zeros((4,)))
+ d = np.ma.masked_array(np.ones((3, 4)))
+ d[2, 1] = np.nan
+ d[2, 2] = np.ma.masked
+ assert_equal(np.ma.median(d, 0, out=o), o)
+ o = np.ma.masked_array(np.zeros((3,)))
+ assert_equal(np.ma.median(d, 1, out=o), o)
+ o = np.ma.masked_array(np.zeros(()))
+ assert_equal(np.ma.median(d, out=o), o)
+
+ def test_nan_behavior(self):
+ a = np.ma.masked_array(np.arange(24, dtype=float))
+ a[::3] = np.ma.masked
+ a[2] = np.nan
+ assert_array_equal(np.ma.median(a), np.nan)
+ assert_array_equal(np.ma.median(a, axis=0), np.nan)
+
+ a = np.ma.masked_array(np.arange(24, dtype=float).reshape(2, 3, 4))
+ a.mask = np.arange(a.size) % 2 == 1
+ aorig = a.copy()
+ a[1, 2, 3] = np.nan
+ a[1, 1, 2] = np.nan
+
+ # no axis
+ assert_array_equal(np.ma.median(a), np.nan)
+ assert_(np.isscalar(np.ma.median(a)))
+
+ # axis0
+ b = np.ma.median(aorig, axis=0)
+ b[2, 3] = np.nan
+ b[1, 2] = np.nan
+ assert_equal(np.ma.median(a, 0), b)
+
+ # axis1
+ b = np.ma.median(aorig, axis=1)
+ b[1, 3] = np.nan
+ b[1, 2] = np.nan
+ assert_equal(np.ma.median(a, 1), b)
+
+ # axis02
+ b = np.ma.median(aorig, axis=(0, 2))
+ b[1] = np.nan
+ b[2] = np.nan
+ assert_equal(np.ma.median(a, (0, 2)), b)
+
+ def test_ambigous_fill(self):
+ # 255 is max value, used as filler for sort
+ a = np.array([[3, 3, 255], [3, 3, 255]], dtype=np.uint8)
+ a = np.ma.masked_array(a, mask=a == 3)
+ assert_array_equal(np.ma.median(a, axis=1), 255)
+ assert_array_equal(np.ma.median(a, axis=1).mask, False)
+ assert_array_equal(np.ma.median(a, axis=0), a[0])
+ assert_array_equal(np.ma.median(a), 255)
+
+ def test_special(self):
+ for inf in [np.inf, -np.inf]:
+ a = np.array([[inf, np.nan], [np.nan, np.nan]])
+ a = np.ma.masked_array(a, mask=np.isnan(a))
+ assert_equal(np.ma.median(a, axis=0), [inf, np.nan])
+ assert_equal(np.ma.median(a, axis=1), [inf, np.nan])
+ assert_equal(np.ma.median(a), inf)
+
+ a = np.array([[np.nan, np.nan, inf], [np.nan, np.nan, inf]])
+ a = np.ma.masked_array(a, mask=np.isnan(a))
+ assert_array_equal(np.ma.median(a, axis=1), inf)
+ assert_array_equal(np.ma.median(a, axis=1).mask, False)
+ assert_array_equal(np.ma.median(a, axis=0), a[0])
+ assert_array_equal(np.ma.median(a), inf)
+
+ # no mask
+ a = np.array([[inf, inf], [inf, inf]])
+ assert_equal(np.ma.median(a), inf)
+ assert_equal(np.ma.median(a, axis=0), inf)
+ assert_equal(np.ma.median(a, axis=1), inf)
+
+ a = np.array([[inf, 7, -inf, -9],
+ [-10, np.nan, np.nan, 5],
+ [4, np.nan, np.nan, inf]],
+ dtype=np.float32)
+ a = np.ma.masked_array(a, mask=np.isnan(a))
+ if inf > 0:
+ assert_equal(np.ma.median(a, axis=0), [4., 7., -inf, 5.])
+ assert_equal(np.ma.median(a), 4.5)
+ else:
+ assert_equal(np.ma.median(a, axis=0), [-10., 7., -inf, -9.])
+ assert_equal(np.ma.median(a), -2.5)
+ assert_equal(np.ma.median(a, axis=1), [-1., -2.5, inf])
+
+ for i in range(0, 10):
+ for j in range(1, 10):
+ a = np.array([([np.nan] * i) + ([inf] * j)] * 2)
+ a = np.ma.masked_array(a, mask=np.isnan(a))
+ assert_equal(np.ma.median(a), inf)
+ assert_equal(np.ma.median(a, axis=1), inf)
+ assert_equal(np.ma.median(a, axis=0),
+ ([np.nan] * i) + [inf] * j)
+
+ def test_empty(self):
+ # empty arrays
+ a = np.ma.masked_array(np.array([], dtype=float))
+ with suppress_warnings() as w:
+ w.record(RuntimeWarning)
+ assert_array_equal(np.ma.median(a), np.nan)
+ assert_(w.log[0].category is RuntimeWarning)
+
+ # multiple dimensions
+ a = np.ma.masked_array(np.array([], dtype=float, ndmin=3))
+ # no axis
+ with suppress_warnings() as w:
+ w.record(RuntimeWarning)
+ warnings.filterwarnings('always', '', RuntimeWarning)
+ assert_array_equal(np.ma.median(a), np.nan)
+ assert_(w.log[0].category is RuntimeWarning)
+
+ # axis 0 and 1
+ b = np.ma.masked_array(np.array([], dtype=float, ndmin=2))
+ assert_equal(np.ma.median(a, axis=0), b)
+ assert_equal(np.ma.median(a, axis=1), b)
+
+ # axis 2
+ b = np.ma.masked_array(np.array(np.nan, dtype=float, ndmin=2))
+ with warnings.catch_warnings(record=True) as w:
+ warnings.filterwarnings('always', '', RuntimeWarning)
+ assert_equal(np.ma.median(a, axis=2), b)
+ assert_(w[0].category is RuntimeWarning)
+
+ def test_object(self):
+ o = np.ma.masked_array(np.arange(7.))
+ assert_(type(np.ma.median(o.astype(object))), float)
+ o[2] = np.nan
+ assert_(type(np.ma.median(o.astype(object))), float)
+
+
+class TestCov:
+
+ def setup_method(self):
+ self.data = array(np.random.rand(12))
+
+ def test_1d_without_missing(self):
+ # Test cov on 1D variable w/o missing values
+ x = self.data
+ assert_almost_equal(np.cov(x), cov(x))
+ assert_almost_equal(np.cov(x, rowvar=False), cov(x, rowvar=False))
+ assert_almost_equal(np.cov(x, rowvar=False, bias=True),
+ cov(x, rowvar=False, bias=True))
+
+ def test_2d_without_missing(self):
+ # Test cov on 1 2D variable w/o missing values
+ x = self.data.reshape(3, 4)
+ assert_almost_equal(np.cov(x), cov(x))
+ assert_almost_equal(np.cov(x, rowvar=False), cov(x, rowvar=False))
+ assert_almost_equal(np.cov(x, rowvar=False, bias=True),
+ cov(x, rowvar=False, bias=True))
+
+ def test_1d_with_missing(self):
+ # Test cov 1 1D variable w/missing values
+ x = self.data
+ x[-1] = masked
+ x -= x.mean()
+ nx = x.compressed()
+ assert_almost_equal(np.cov(nx), cov(x))
+ assert_almost_equal(np.cov(nx, rowvar=False), cov(x, rowvar=False))
+ assert_almost_equal(np.cov(nx, rowvar=False, bias=True),
+ cov(x, rowvar=False, bias=True))
+ #
+ try:
+ cov(x, allow_masked=False)
+ except ValueError:
+ pass
+ #
+ # 2 1D variables w/ missing values
+ nx = x[1:-1]
+ assert_almost_equal(np.cov(nx, nx[::-1]), cov(x, x[::-1]))
+ assert_almost_equal(np.cov(nx, nx[::-1], rowvar=False),
+ cov(x, x[::-1], rowvar=False))
+ assert_almost_equal(np.cov(nx, nx[::-1], rowvar=False, bias=True),
+ cov(x, x[::-1], rowvar=False, bias=True))
+
+ def test_2d_with_missing(self):
+ # Test cov on 2D variable w/ missing value
+ x = self.data
+ x[-1] = masked
+ x = x.reshape(3, 4)
+ valid = np.logical_not(getmaskarray(x)).astype(int)
+ frac = np.dot(valid, valid.T)
+ xf = (x - x.mean(1)[:, None]).filled(0)
+ assert_almost_equal(cov(x),
+ np.cov(xf) * (x.shape[1] - 1) / (frac - 1.))
+ assert_almost_equal(cov(x, bias=True),
+ np.cov(xf, bias=True) * x.shape[1] / frac)
+ frac = np.dot(valid.T, valid)
+ xf = (x - x.mean(0)).filled(0)
+ assert_almost_equal(cov(x, rowvar=False),
+ (np.cov(xf, rowvar=False) *
+ (x.shape[0] - 1) / (frac - 1.)))
+ assert_almost_equal(cov(x, rowvar=False, bias=True),
+ (np.cov(xf, rowvar=False, bias=True) *
+ x.shape[0] / frac))
+
+
+class TestCorrcoef:
+
+ def setup_method(self):
+ self.data = array(np.random.rand(12))
+ self.data2 = array(np.random.rand(12))
+
+ def test_ddof(self):
+ # ddof raises DeprecationWarning
+ x, y = self.data, self.data2
+ expected = np.corrcoef(x)
+ expected2 = np.corrcoef(x, y)
+ with suppress_warnings() as sup:
+ warnings.simplefilter("always")
+ assert_warns(DeprecationWarning, corrcoef, x, ddof=-1)
+ sup.filter(DeprecationWarning, "bias and ddof have no effect")
+ # ddof has no or negligible effect on the function
+ assert_almost_equal(np.corrcoef(x, ddof=0), corrcoef(x, ddof=0))
+ assert_almost_equal(corrcoef(x, ddof=-1), expected)
+ assert_almost_equal(corrcoef(x, y, ddof=-1), expected2)
+ assert_almost_equal(corrcoef(x, ddof=3), expected)
+ assert_almost_equal(corrcoef(x, y, ddof=3), expected2)
+
+ def test_bias(self):
+ x, y = self.data, self.data2
+ expected = np.corrcoef(x)
+ # bias raises DeprecationWarning
+ with suppress_warnings() as sup:
+ warnings.simplefilter("always")
+ assert_warns(DeprecationWarning, corrcoef, x, y, True, False)
+ assert_warns(DeprecationWarning, corrcoef, x, y, True, True)
+ assert_warns(DeprecationWarning, corrcoef, x, bias=False)
+ sup.filter(DeprecationWarning, "bias and ddof have no effect")
+ # bias has no or negligible effect on the function
+ assert_almost_equal(corrcoef(x, bias=1), expected)
+
+ def test_1d_without_missing(self):
+ # Test cov on 1D variable w/o missing values
+ x = self.data
+ assert_almost_equal(np.corrcoef(x), corrcoef(x))
+ assert_almost_equal(np.corrcoef(x, rowvar=False),
+ corrcoef(x, rowvar=False))
+ with suppress_warnings() as sup:
+ sup.filter(DeprecationWarning, "bias and ddof have no effect")
+ assert_almost_equal(np.corrcoef(x, rowvar=False, bias=True),
+ corrcoef(x, rowvar=False, bias=True))
+
+ def test_2d_without_missing(self):
+ # Test corrcoef on 1 2D variable w/o missing values
+ x = self.data.reshape(3, 4)
+ assert_almost_equal(np.corrcoef(x), corrcoef(x))
+ assert_almost_equal(np.corrcoef(x, rowvar=False),
+ corrcoef(x, rowvar=False))
+ with suppress_warnings() as sup:
+ sup.filter(DeprecationWarning, "bias and ddof have no effect")
+ assert_almost_equal(np.corrcoef(x, rowvar=False, bias=True),
+ corrcoef(x, rowvar=False, bias=True))
+
+ def test_1d_with_missing(self):
+ # Test corrcoef 1 1D variable w/missing values
+ x = self.data
+ x[-1] = masked
+ x -= x.mean()
+ nx = x.compressed()
+ assert_almost_equal(np.corrcoef(nx), corrcoef(x))
+ assert_almost_equal(np.corrcoef(nx, rowvar=False),
+ corrcoef(x, rowvar=False))
+ with suppress_warnings() as sup:
+ sup.filter(DeprecationWarning, "bias and ddof have no effect")
+ assert_almost_equal(np.corrcoef(nx, rowvar=False, bias=True),
+ corrcoef(x, rowvar=False, bias=True))
+ try:
+ corrcoef(x, allow_masked=False)
+ except ValueError:
+ pass
+ # 2 1D variables w/ missing values
+ nx = x[1:-1]
+ assert_almost_equal(np.corrcoef(nx, nx[::-1]), corrcoef(x, x[::-1]))
+ assert_almost_equal(np.corrcoef(nx, nx[::-1], rowvar=False),
+ corrcoef(x, x[::-1], rowvar=False))
+ with suppress_warnings() as sup:
+ sup.filter(DeprecationWarning, "bias and ddof have no effect")
+ # ddof and bias have no or negligible effect on the function
+ assert_almost_equal(np.corrcoef(nx, nx[::-1]),
+ corrcoef(x, x[::-1], bias=1))
+ assert_almost_equal(np.corrcoef(nx, nx[::-1]),
+ corrcoef(x, x[::-1], ddof=2))
+
+ def test_2d_with_missing(self):
+ # Test corrcoef on 2D variable w/ missing value
+ x = self.data
+ x[-1] = masked
+ x = x.reshape(3, 4)
+
+ test = corrcoef(x)
+ control = np.corrcoef(x)
+ assert_almost_equal(test[:-1, :-1], control[:-1, :-1])
+ with suppress_warnings() as sup:
+ sup.filter(DeprecationWarning, "bias and ddof have no effect")
+ # ddof and bias have no or negligible effect on the function
+ assert_almost_equal(corrcoef(x, ddof=-2)[:-1, :-1],
+ control[:-1, :-1])
+ assert_almost_equal(corrcoef(x, ddof=3)[:-1, :-1],
+ control[:-1, :-1])
+ assert_almost_equal(corrcoef(x, bias=1)[:-1, :-1],
+ control[:-1, :-1])
+
+
+class TestPolynomial:
+ #
+ def test_polyfit(self):
+ # Tests polyfit
+ # On ndarrays
+ x = np.random.rand(10)
+ y = np.random.rand(20).reshape(-1, 2)
+ assert_almost_equal(polyfit(x, y, 3), np.polyfit(x, y, 3))
+ # ON 1D maskedarrays
+ x = x.view(MaskedArray)
+ x[0] = masked
+ y = y.view(MaskedArray)
+ y[0, 0] = y[-1, -1] = masked
+ #
+ (C, R, K, S, D) = polyfit(x, y[:, 0], 3, full=True)
+ (c, r, k, s, d) = np.polyfit(x[1:], y[1:, 0].compressed(), 3,
+ full=True)
+ for (a, a_) in zip((C, R, K, S, D), (c, r, k, s, d)):
+ assert_almost_equal(a, a_)
+ #
+ (C, R, K, S, D) = polyfit(x, y[:, -1], 3, full=True)
+ (c, r, k, s, d) = np.polyfit(x[1:-1], y[1:-1, -1], 3, full=True)
+ for (a, a_) in zip((C, R, K, S, D), (c, r, k, s, d)):
+ assert_almost_equal(a, a_)
+ #
+ (C, R, K, S, D) = polyfit(x, y, 3, full=True)
+ (c, r, k, s, d) = np.polyfit(x[1:-1], y[1:-1,:], 3, full=True)
+ for (a, a_) in zip((C, R, K, S, D), (c, r, k, s, d)):
+ assert_almost_equal(a, a_)
+ #
+ w = np.random.rand(10) + 1
+ wo = w.copy()
+ xs = x[1:-1]
+ ys = y[1:-1]
+ ws = w[1:-1]
+ (C, R, K, S, D) = polyfit(x, y, 3, full=True, w=w)
+ (c, r, k, s, d) = np.polyfit(xs, ys, 3, full=True, w=ws)
+ assert_equal(w, wo)
+ for (a, a_) in zip((C, R, K, S, D), (c, r, k, s, d)):
+ assert_almost_equal(a, a_)
+
+ def test_polyfit_with_masked_NaNs(self):
+ x = np.random.rand(10)
+ y = np.random.rand(20).reshape(-1, 2)
+
+ x[0] = np.nan
+ y[-1,-1] = np.nan
+ x = x.view(MaskedArray)
+ y = y.view(MaskedArray)
+ x[0] = masked
+ y[-1,-1] = masked
+
+ (C, R, K, S, D) = polyfit(x, y, 3, full=True)
+ (c, r, k, s, d) = np.polyfit(x[1:-1], y[1:-1,:], 3, full=True)
+ for (a, a_) in zip((C, R, K, S, D), (c, r, k, s, d)):
+ assert_almost_equal(a, a_)
+
+
+class TestArraySetOps:
+
+ def test_unique_onlist(self):
+ # Test unique on list
+ data = [1, 1, 1, 2, 2, 3]
+ test = unique(data, return_index=True, return_inverse=True)
+ assert_(isinstance(test[0], MaskedArray))
+ assert_equal(test[0], masked_array([1, 2, 3], mask=[0, 0, 0]))
+ assert_equal(test[1], [0, 3, 5])
+ assert_equal(test[2], [0, 0, 0, 1, 1, 2])
+
+ def test_unique_onmaskedarray(self):
+ # Test unique on masked data w/use_mask=True
+ data = masked_array([1, 1, 1, 2, 2, 3], mask=[0, 0, 1, 0, 1, 0])
+ test = unique(data, return_index=True, return_inverse=True)
+ assert_equal(test[0], masked_array([1, 2, 3, -1], mask=[0, 0, 0, 1]))
+ assert_equal(test[1], [0, 3, 5, 2])
+ assert_equal(test[2], [0, 0, 3, 1, 3, 2])
+ #
+ data.fill_value = 3
+ data = masked_array(data=[1, 1, 1, 2, 2, 3],
+ mask=[0, 0, 1, 0, 1, 0], fill_value=3)
+ test = unique(data, return_index=True, return_inverse=True)
+ assert_equal(test[0], masked_array([1, 2, 3, -1], mask=[0, 0, 0, 1]))
+ assert_equal(test[1], [0, 3, 5, 2])
+ assert_equal(test[2], [0, 0, 3, 1, 3, 2])
+
+ def test_unique_allmasked(self):
+ # Test all masked
+ data = masked_array([1, 1, 1], mask=True)
+ test = unique(data, return_index=True, return_inverse=True)
+ assert_equal(test[0], masked_array([1, ], mask=[True]))
+ assert_equal(test[1], [0])
+ assert_equal(test[2], [0, 0, 0])
+ #
+ # Test masked
+ data = masked
+ test = unique(data, return_index=True, return_inverse=True)
+ assert_equal(test[0], masked_array(masked))
+ assert_equal(test[1], [0])
+ assert_equal(test[2], [0])
+
+ def test_ediff1d(self):
+ # Tests mediff1d
+ x = masked_array(np.arange(5), mask=[1, 0, 0, 0, 1])
+ control = array([1, 1, 1, 4], mask=[1, 0, 0, 1])
+ test = ediff1d(x)
+ assert_equal(test, control)
+ assert_equal(test.filled(0), control.filled(0))
+ assert_equal(test.mask, control.mask)
+
+ def test_ediff1d_tobegin(self):
+ # Test ediff1d w/ to_begin
+ x = masked_array(np.arange(5), mask=[1, 0, 0, 0, 1])
+ test = ediff1d(x, to_begin=masked)
+ control = array([0, 1, 1, 1, 4], mask=[1, 1, 0, 0, 1])
+ assert_equal(test, control)
+ assert_equal(test.filled(0), control.filled(0))
+ assert_equal(test.mask, control.mask)
+ #
+ test = ediff1d(x, to_begin=[1, 2, 3])
+ control = array([1, 2, 3, 1, 1, 1, 4], mask=[0, 0, 0, 1, 0, 0, 1])
+ assert_equal(test, control)
+ assert_equal(test.filled(0), control.filled(0))
+ assert_equal(test.mask, control.mask)
+
+ def test_ediff1d_toend(self):
+ # Test ediff1d w/ to_end
+ x = masked_array(np.arange(5), mask=[1, 0, 0, 0, 1])
+ test = ediff1d(x, to_end=masked)
+ control = array([1, 1, 1, 4, 0], mask=[1, 0, 0, 1, 1])
+ assert_equal(test, control)
+ assert_equal(test.filled(0), control.filled(0))
+ assert_equal(test.mask, control.mask)
+ #
+ test = ediff1d(x, to_end=[1, 2, 3])
+ control = array([1, 1, 1, 4, 1, 2, 3], mask=[1, 0, 0, 1, 0, 0, 0])
+ assert_equal(test, control)
+ assert_equal(test.filled(0), control.filled(0))
+ assert_equal(test.mask, control.mask)
+
+ def test_ediff1d_tobegin_toend(self):
+ # Test ediff1d w/ to_begin and to_end
+ x = masked_array(np.arange(5), mask=[1, 0, 0, 0, 1])
+ test = ediff1d(x, to_end=masked, to_begin=masked)
+ control = array([0, 1, 1, 1, 4, 0], mask=[1, 1, 0, 0, 1, 1])
+ assert_equal(test, control)
+ assert_equal(test.filled(0), control.filled(0))
+ assert_equal(test.mask, control.mask)
+ #
+ test = ediff1d(x, to_end=[1, 2, 3], to_begin=masked)
+ control = array([0, 1, 1, 1, 4, 1, 2, 3],
+ mask=[1, 1, 0, 0, 1, 0, 0, 0])
+ assert_equal(test, control)
+ assert_equal(test.filled(0), control.filled(0))
+ assert_equal(test.mask, control.mask)
+
+ def test_ediff1d_ndarray(self):
+ # Test ediff1d w/ a ndarray
+ x = np.arange(5)
+ test = ediff1d(x)
+ control = array([1, 1, 1, 1], mask=[0, 0, 0, 0])
+ assert_equal(test, control)
+ assert_(isinstance(test, MaskedArray))
+ assert_equal(test.filled(0), control.filled(0))
+ assert_equal(test.mask, control.mask)
+ #
+ test = ediff1d(x, to_end=masked, to_begin=masked)
+ control = array([0, 1, 1, 1, 1, 0], mask=[1, 0, 0, 0, 0, 1])
+ assert_(isinstance(test, MaskedArray))
+ assert_equal(test.filled(0), control.filled(0))
+ assert_equal(test.mask, control.mask)
+
+ def test_intersect1d(self):
+ # Test intersect1d
+ x = array([1, 3, 3, 3], mask=[0, 0, 0, 1])
+ y = array([3, 1, 1, 1], mask=[0, 0, 0, 1])
+ test = intersect1d(x, y)
+ control = array([1, 3, -1], mask=[0, 0, 1])
+ assert_equal(test, control)
+
+ def test_setxor1d(self):
+ # Test setxor1d
+ a = array([1, 2, 5, 7, -1], mask=[0, 0, 0, 0, 1])
+ b = array([1, 2, 3, 4, 5, -1], mask=[0, 0, 0, 0, 0, 1])
+ test = setxor1d(a, b)
+ assert_equal(test, array([3, 4, 7]))
+ #
+ a = array([1, 2, 5, 7, -1], mask=[0, 0, 0, 0, 1])
+ b = [1, 2, 3, 4, 5]
+ test = setxor1d(a, b)
+ assert_equal(test, array([3, 4, 7, -1], mask=[0, 0, 0, 1]))
+ #
+ a = array([1, 2, 3])
+ b = array([6, 5, 4])
+ test = setxor1d(a, b)
+ assert_(isinstance(test, MaskedArray))
+ assert_equal(test, [1, 2, 3, 4, 5, 6])
+ #
+ a = array([1, 8, 2, 3], mask=[0, 1, 0, 0])
+ b = array([6, 5, 4, 8], mask=[0, 0, 0, 1])
+ test = setxor1d(a, b)
+ assert_(isinstance(test, MaskedArray))
+ assert_equal(test, [1, 2, 3, 4, 5, 6])
+ #
+ assert_array_equal([], setxor1d([], []))
+
+ def test_isin(self):
+ # the tests for in1d cover most of isin's behavior
+ # if in1d is removed, would need to change those tests to test
+ # isin instead.
+ a = np.arange(24).reshape([2, 3, 4])
+ mask = np.zeros([2, 3, 4])
+ mask[1, 2, 0] = 1
+ a = array(a, mask=mask)
+ b = array(data=[0, 10, 20, 30, 1, 3, 11, 22, 33],
+ mask=[0, 1, 0, 1, 0, 1, 0, 1, 0])
+ ec = zeros((2, 3, 4), dtype=bool)
+ ec[0, 0, 0] = True
+ ec[0, 0, 1] = True
+ ec[0, 2, 3] = True
+ c = isin(a, b)
+ assert_(isinstance(c, MaskedArray))
+ assert_array_equal(c, ec)
+ #compare results of np.isin to ma.isin
+ d = np.isin(a, b[~b.mask]) & ~a.mask
+ assert_array_equal(c, d)
+
+ def test_in1d(self):
+ # Test in1d
+ a = array([1, 2, 5, 7, -1], mask=[0, 0, 0, 0, 1])
+ b = array([1, 2, 3, 4, 5, -1], mask=[0, 0, 0, 0, 0, 1])
+ test = in1d(a, b)
+ assert_equal(test, [True, True, True, False, True])
+ #
+ a = array([5, 5, 2, 1, -1], mask=[0, 0, 0, 0, 1])
+ b = array([1, 5, -1], mask=[0, 0, 1])
+ test = in1d(a, b)
+ assert_equal(test, [True, True, False, True, True])
+ #
+ assert_array_equal([], in1d([], []))
+
+ def test_in1d_invert(self):
+ # Test in1d's invert parameter
+ a = array([1, 2, 5, 7, -1], mask=[0, 0, 0, 0, 1])
+ b = array([1, 2, 3, 4, 5, -1], mask=[0, 0, 0, 0, 0, 1])
+ assert_equal(np.invert(in1d(a, b)), in1d(a, b, invert=True))
+
+ a = array([5, 5, 2, 1, -1], mask=[0, 0, 0, 0, 1])
+ b = array([1, 5, -1], mask=[0, 0, 1])
+ assert_equal(np.invert(in1d(a, b)), in1d(a, b, invert=True))
+
+ assert_array_equal([], in1d([], [], invert=True))
+
+ def test_union1d(self):
+ # Test union1d
+ a = array([1, 2, 5, 7, 5, -1], mask=[0, 0, 0, 0, 0, 1])
+ b = array([1, 2, 3, 4, 5, -1], mask=[0, 0, 0, 0, 0, 1])
+ test = union1d(a, b)
+ control = array([1, 2, 3, 4, 5, 7, -1], mask=[0, 0, 0, 0, 0, 0, 1])
+ assert_equal(test, control)
+
+ # Tests gh-10340, arguments to union1d should be
+ # flattened if they are not already 1D
+ x = array([[0, 1, 2], [3, 4, 5]], mask=[[0, 0, 0], [0, 0, 1]])
+ y = array([0, 1, 2, 3, 4], mask=[0, 0, 0, 0, 1])
+ ez = array([0, 1, 2, 3, 4, 5], mask=[0, 0, 0, 0, 0, 1])
+ z = union1d(x, y)
+ assert_equal(z, ez)
+ #
+ assert_array_equal([], union1d([], []))
+
+ def test_setdiff1d(self):
+ # Test setdiff1d
+ a = array([6, 5, 4, 7, 7, 1, 2, 1], mask=[0, 0, 0, 0, 0, 0, 0, 1])
+ b = array([2, 4, 3, 3, 2, 1, 5])
+ test = setdiff1d(a, b)
+ assert_equal(test, array([6, 7, -1], mask=[0, 0, 1]))
+ #
+ a = arange(10)
+ b = arange(8)
+ assert_equal(setdiff1d(a, b), array([8, 9]))
+ a = array([], np.uint32, mask=[])
+ assert_equal(setdiff1d(a, []).dtype, np.uint32)
+
+ def test_setdiff1d_char_array(self):
+ # Test setdiff1d_charray
+ a = np.array(['a', 'b', 'c'])
+ b = np.array(['a', 'b', 's'])
+ assert_array_equal(setdiff1d(a, b), np.array(['c']))
+
+
+class TestShapeBase:
+
+ def test_atleast_2d(self):
+ # Test atleast_2d
+ a = masked_array([0, 1, 2], mask=[0, 1, 0])
+ b = atleast_2d(a)
+ assert_equal(b.shape, (1, 3))
+ assert_equal(b.mask.shape, b.data.shape)
+ assert_equal(a.shape, (3,))
+ assert_equal(a.mask.shape, a.data.shape)
+ assert_equal(b.mask.shape, b.data.shape)
+
+ def test_shape_scalar(self):
+ # the atleast and diagflat function should work with scalars
+ # GitHub issue #3367
+ # Additionally, the atleast functions should accept multiple scalars
+ # correctly
+ b = atleast_1d(1.0)
+ assert_equal(b.shape, (1,))
+ assert_equal(b.mask.shape, b.shape)
+ assert_equal(b.data.shape, b.shape)
+
+ b = atleast_1d(1.0, 2.0)
+ for a in b:
+ assert_equal(a.shape, (1,))
+ assert_equal(a.mask.shape, a.shape)
+ assert_equal(a.data.shape, a.shape)
+
+ b = atleast_2d(1.0)
+ assert_equal(b.shape, (1, 1))
+ assert_equal(b.mask.shape, b.shape)
+ assert_equal(b.data.shape, b.shape)
+
+ b = atleast_2d(1.0, 2.0)
+ for a in b:
+ assert_equal(a.shape, (1, 1))
+ assert_equal(a.mask.shape, a.shape)
+ assert_equal(a.data.shape, a.shape)
+
+ b = atleast_3d(1.0)
+ assert_equal(b.shape, (1, 1, 1))
+ assert_equal(b.mask.shape, b.shape)
+ assert_equal(b.data.shape, b.shape)
+
+ b = atleast_3d(1.0, 2.0)
+ for a in b:
+ assert_equal(a.shape, (1, 1, 1))
+ assert_equal(a.mask.shape, a.shape)
+ assert_equal(a.data.shape, a.shape)
+
+ b = diagflat(1.0)
+ assert_equal(b.shape, (1, 1))
+ assert_equal(b.mask.shape, b.data.shape)
+
+
+class TestNDEnumerate:
+
+ def test_ndenumerate_nomasked(self):
+ ordinary = np.arange(6.).reshape((1, 3, 2))
+ empty_mask = np.zeros_like(ordinary, dtype=bool)
+ with_mask = masked_array(ordinary, mask=empty_mask)
+ assert_equal(list(np.ndenumerate(ordinary)),
+ list(ndenumerate(ordinary)))
+ assert_equal(list(ndenumerate(ordinary)),
+ list(ndenumerate(with_mask)))
+ assert_equal(list(ndenumerate(with_mask)),
+ list(ndenumerate(with_mask, compressed=False)))
+
+ def test_ndenumerate_allmasked(self):
+ a = masked_all(())
+ b = masked_all((100,))
+ c = masked_all((2, 3, 4))
+ assert_equal(list(ndenumerate(a)), [])
+ assert_equal(list(ndenumerate(b)), [])
+ assert_equal(list(ndenumerate(b, compressed=False)),
+ list(zip(np.ndindex((100,)), 100 * [masked])))
+ assert_equal(list(ndenumerate(c)), [])
+ assert_equal(list(ndenumerate(c, compressed=False)),
+ list(zip(np.ndindex((2, 3, 4)), 2 * 3 * 4 * [masked])))
+
+ def test_ndenumerate_mixedmasked(self):
+ a = masked_array(np.arange(12).reshape((3, 4)),
+ mask=[[1, 1, 1, 1],
+ [1, 1, 0, 1],
+ [0, 0, 0, 0]])
+ items = [((1, 2), 6),
+ ((2, 0), 8), ((2, 1), 9), ((2, 2), 10), ((2, 3), 11)]
+ assert_equal(list(ndenumerate(a)), items)
+ assert_equal(len(list(ndenumerate(a, compressed=False))), a.size)
+ for coordinate, value in ndenumerate(a, compressed=False):
+ assert_equal(a[coordinate], value)
+
+
+class TestStack:
+
+ def test_stack_1d(self):
+ a = masked_array([0, 1, 2], mask=[0, 1, 0])
+ b = masked_array([9, 8, 7], mask=[1, 0, 0])
+
+ c = stack([a, b], axis=0)
+ assert_equal(c.shape, (2, 3))
+ assert_array_equal(a.mask, c[0].mask)
+ assert_array_equal(b.mask, c[1].mask)
+
+ d = vstack([a, b])
+ assert_array_equal(c.data, d.data)
+ assert_array_equal(c.mask, d.mask)
+
+ c = stack([a, b], axis=1)
+ assert_equal(c.shape, (3, 2))
+ assert_array_equal(a.mask, c[:, 0].mask)
+ assert_array_equal(b.mask, c[:, 1].mask)
+
+ def test_stack_masks(self):
+ a = masked_array([0, 1, 2], mask=True)
+ b = masked_array([9, 8, 7], mask=False)
+
+ c = stack([a, b], axis=0)
+ assert_equal(c.shape, (2, 3))
+ assert_array_equal(a.mask, c[0].mask)
+ assert_array_equal(b.mask, c[1].mask)
+
+ d = vstack([a, b])
+ assert_array_equal(c.data, d.data)
+ assert_array_equal(c.mask, d.mask)
+
+ c = stack([a, b], axis=1)
+ assert_equal(c.shape, (3, 2))
+ assert_array_equal(a.mask, c[:, 0].mask)
+ assert_array_equal(b.mask, c[:, 1].mask)
+
+ def test_stack_nd(self):
+ # 2D
+ shp = (3, 2)
+ d1 = np.random.randint(0, 10, shp)
+ d2 = np.random.randint(0, 10, shp)
+ m1 = np.random.randint(0, 2, shp).astype(bool)
+ m2 = np.random.randint(0, 2, shp).astype(bool)
+ a1 = masked_array(d1, mask=m1)
+ a2 = masked_array(d2, mask=m2)
+
+ c = stack([a1, a2], axis=0)
+ c_shp = (2,) + shp
+ assert_equal(c.shape, c_shp)
+ assert_array_equal(a1.mask, c[0].mask)
+ assert_array_equal(a2.mask, c[1].mask)
+
+ c = stack([a1, a2], axis=-1)
+ c_shp = shp + (2,)
+ assert_equal(c.shape, c_shp)
+ assert_array_equal(a1.mask, c[..., 0].mask)
+ assert_array_equal(a2.mask, c[..., 1].mask)
+
+ # 4D
+ shp = (3, 2, 4, 5,)
+ d1 = np.random.randint(0, 10, shp)
+ d2 = np.random.randint(0, 10, shp)
+ m1 = np.random.randint(0, 2, shp).astype(bool)
+ m2 = np.random.randint(0, 2, shp).astype(bool)
+ a1 = masked_array(d1, mask=m1)
+ a2 = masked_array(d2, mask=m2)
+
+ c = stack([a1, a2], axis=0)
+ c_shp = (2,) + shp
+ assert_equal(c.shape, c_shp)
+ assert_array_equal(a1.mask, c[0].mask)
+ assert_array_equal(a2.mask, c[1].mask)
+
+ c = stack([a1, a2], axis=-1)
+ c_shp = shp + (2,)
+ assert_equal(c.shape, c_shp)
+ assert_array_equal(a1.mask, c[..., 0].mask)
+ assert_array_equal(a2.mask, c[..., 1].mask)
diff --git a/venv/lib/python3.9/site-packages/numpy/ma/tests/test_mrecords.py b/venv/lib/python3.9/site-packages/numpy/ma/tests/test_mrecords.py
new file mode 100644
index 00000000..77123c3c
--- /dev/null
+++ b/venv/lib/python3.9/site-packages/numpy/ma/tests/test_mrecords.py
@@ -0,0 +1,493 @@
+# pylint: disable-msg=W0611, W0612, W0511,R0201
+"""Tests suite for mrecords.
+
+:author: Pierre Gerard-Marchant
+:contact: pierregm_at_uga_dot_edu
+
+"""
+import numpy as np
+import numpy.ma as ma
+from numpy import recarray
+from numpy.ma import masked, nomask
+from numpy.testing import temppath
+from numpy.core.records import (
+ fromrecords as recfromrecords, fromarrays as recfromarrays
+ )
+from numpy.ma.mrecords import (
+ MaskedRecords, mrecarray, fromarrays, fromtextfile, fromrecords,
+ addfield
+ )
+from numpy.ma.testutils import (
+ assert_, assert_equal,
+ assert_equal_records,
+ )
+from numpy.compat import pickle
+
+
+class TestMRecords:
+
+ ilist = [1, 2, 3, 4, 5]
+ flist = [1.1, 2.2, 3.3, 4.4, 5.5]
+ slist = [b'one', b'two', b'three', b'four', b'five']
+ ddtype = [('a', int), ('b', float), ('c', '|S8')]
+ mask = [0, 1, 0, 0, 1]
+ base = ma.array(list(zip(ilist, flist, slist)), mask=mask, dtype=ddtype)
+
+ def test_byview(self):
+ # Test creation by view
+ base = self.base
+ mbase = base.view(mrecarray)
+ assert_equal(mbase.recordmask, base.recordmask)
+ assert_equal_records(mbase._mask, base._mask)
+ assert_(isinstance(mbase._data, recarray))
+ assert_equal_records(mbase._data, base._data.view(recarray))
+ for field in ('a', 'b', 'c'):
+ assert_equal(base[field], mbase[field])
+ assert_equal_records(mbase.view(mrecarray), mbase)
+
+ def test_get(self):
+ # Tests fields retrieval
+ base = self.base.copy()
+ mbase = base.view(mrecarray)
+ # As fields..........
+ for field in ('a', 'b', 'c'):
+ assert_equal(getattr(mbase, field), mbase[field])
+ assert_equal(base[field], mbase[field])
+ # as elements .......
+ mbase_first = mbase[0]
+ assert_(isinstance(mbase_first, mrecarray))
+ assert_equal(mbase_first.dtype, mbase.dtype)
+ assert_equal(mbase_first.tolist(), (1, 1.1, b'one'))
+ # Used to be mask, now it's recordmask
+ assert_equal(mbase_first.recordmask, nomask)
+ assert_equal(mbase_first._mask.item(), (False, False, False))
+ assert_equal(mbase_first['a'], mbase['a'][0])
+ mbase_last = mbase[-1]
+ assert_(isinstance(mbase_last, mrecarray))
+ assert_equal(mbase_last.dtype, mbase.dtype)
+ assert_equal(mbase_last.tolist(), (None, None, None))
+ # Used to be mask, now it's recordmask
+ assert_equal(mbase_last.recordmask, True)
+ assert_equal(mbase_last._mask.item(), (True, True, True))
+ assert_equal(mbase_last['a'], mbase['a'][-1])
+ assert_((mbase_last['a'] is masked))
+ # as slice ..........
+ mbase_sl = mbase[:2]
+ assert_(isinstance(mbase_sl, mrecarray))
+ assert_equal(mbase_sl.dtype, mbase.dtype)
+ # Used to be mask, now it's recordmask
+ assert_equal(mbase_sl.recordmask, [0, 1])
+ assert_equal_records(mbase_sl.mask,
+ np.array([(False, False, False),
+ (True, True, True)],
+ dtype=mbase._mask.dtype))
+ assert_equal_records(mbase_sl, base[:2].view(mrecarray))
+ for field in ('a', 'b', 'c'):
+ assert_equal(getattr(mbase_sl, field), base[:2][field])
+
+ def test_set_fields(self):
+ # Tests setting fields.
+ base = self.base.copy()
+ mbase = base.view(mrecarray)
+ mbase = mbase.copy()
+ mbase.fill_value = (999999, 1e20, 'N/A')
+ # Change the data, the mask should be conserved
+ mbase.a._data[:] = 5
+ assert_equal(mbase['a']._data, [5, 5, 5, 5, 5])
+ assert_equal(mbase['a']._mask, [0, 1, 0, 0, 1])
+ # Change the elements, and the mask will follow
+ mbase.a = 1
+ assert_equal(mbase['a']._data, [1]*5)
+ assert_equal(ma.getmaskarray(mbase['a']), [0]*5)
+ # Use to be _mask, now it's recordmask
+ assert_equal(mbase.recordmask, [False]*5)
+ assert_equal(mbase._mask.tolist(),
+ np.array([(0, 0, 0),
+ (0, 1, 1),
+ (0, 0, 0),
+ (0, 0, 0),
+ (0, 1, 1)],
+ dtype=bool))
+ # Set a field to mask ........................
+ mbase.c = masked
+ # Use to be mask, and now it's still mask !
+ assert_equal(mbase.c.mask, [1]*5)
+ assert_equal(mbase.c.recordmask, [1]*5)
+ assert_equal(ma.getmaskarray(mbase['c']), [1]*5)
+ assert_equal(ma.getdata(mbase['c']), [b'N/A']*5)
+ assert_equal(mbase._mask.tolist(),
+ np.array([(0, 0, 1),
+ (0, 1, 1),
+ (0, 0, 1),
+ (0, 0, 1),
+ (0, 1, 1)],
+ dtype=bool))
+ # Set fields by slices .......................
+ mbase = base.view(mrecarray).copy()
+ mbase.a[3:] = 5
+ assert_equal(mbase.a, [1, 2, 3, 5, 5])
+ assert_equal(mbase.a._mask, [0, 1, 0, 0, 0])
+ mbase.b[3:] = masked
+ assert_equal(mbase.b, base['b'])
+ assert_equal(mbase.b._mask, [0, 1, 0, 1, 1])
+ # Set fields globally..........................
+ ndtype = [('alpha', '|S1'), ('num', int)]
+ data = ma.array([('a', 1), ('b', 2), ('c', 3)], dtype=ndtype)
+ rdata = data.view(MaskedRecords)
+ val = ma.array([10, 20, 30], mask=[1, 0, 0])
+
+ rdata['num'] = val
+ assert_equal(rdata.num, val)
+ assert_equal(rdata.num.mask, [1, 0, 0])
+
+ def test_set_fields_mask(self):
+ # Tests setting the mask of a field.
+ base = self.base.copy()
+ # This one has already a mask....
+ mbase = base.view(mrecarray)
+ mbase['a'][-2] = masked
+ assert_equal(mbase.a, [1, 2, 3, 4, 5])
+ assert_equal(mbase.a._mask, [0, 1, 0, 1, 1])
+ # This one has not yet
+ mbase = fromarrays([np.arange(5), np.random.rand(5)],
+ dtype=[('a', int), ('b', float)])
+ mbase['a'][-2] = masked
+ assert_equal(mbase.a, [0, 1, 2, 3, 4])
+ assert_equal(mbase.a._mask, [0, 0, 0, 1, 0])
+
+ def test_set_mask(self):
+ base = self.base.copy()
+ mbase = base.view(mrecarray)
+ # Set the mask to True .......................
+ mbase.mask = masked
+ assert_equal(ma.getmaskarray(mbase['b']), [1]*5)
+ assert_equal(mbase['a']._mask, mbase['b']._mask)
+ assert_equal(mbase['a']._mask, mbase['c']._mask)
+ assert_equal(mbase._mask.tolist(),
+ np.array([(1, 1, 1)]*5, dtype=bool))
+ # Delete the mask ............................
+ mbase.mask = nomask
+ assert_equal(ma.getmaskarray(mbase['c']), [0]*5)
+ assert_equal(mbase._mask.tolist(),
+ np.array([(0, 0, 0)]*5, dtype=bool))
+
+ def test_set_mask_fromarray(self):
+ base = self.base.copy()
+ mbase = base.view(mrecarray)
+ # Sets the mask w/ an array
+ mbase.mask = [1, 0, 0, 0, 1]
+ assert_equal(mbase.a.mask, [1, 0, 0, 0, 1])
+ assert_equal(mbase.b.mask, [1, 0, 0, 0, 1])
+ assert_equal(mbase.c.mask, [1, 0, 0, 0, 1])
+ # Yay, once more !
+ mbase.mask = [0, 0, 0, 0, 1]
+ assert_equal(mbase.a.mask, [0, 0, 0, 0, 1])
+ assert_equal(mbase.b.mask, [0, 0, 0, 0, 1])
+ assert_equal(mbase.c.mask, [0, 0, 0, 0, 1])
+
+ def test_set_mask_fromfields(self):
+ mbase = self.base.copy().view(mrecarray)
+
+ nmask = np.array(
+ [(0, 1, 0), (0, 1, 0), (1, 0, 1), (1, 0, 1), (0, 0, 0)],
+ dtype=[('a', bool), ('b', bool), ('c', bool)])
+ mbase.mask = nmask
+ assert_equal(mbase.a.mask, [0, 0, 1, 1, 0])
+ assert_equal(mbase.b.mask, [1, 1, 0, 0, 0])
+ assert_equal(mbase.c.mask, [0, 0, 1, 1, 0])
+ # Reinitialize and redo
+ mbase.mask = False
+ mbase.fieldmask = nmask
+ assert_equal(mbase.a.mask, [0, 0, 1, 1, 0])
+ assert_equal(mbase.b.mask, [1, 1, 0, 0, 0])
+ assert_equal(mbase.c.mask, [0, 0, 1, 1, 0])
+
+ def test_set_elements(self):
+ base = self.base.copy()
+ # Set an element to mask .....................
+ mbase = base.view(mrecarray).copy()
+ mbase[-2] = masked
+ assert_equal(
+ mbase._mask.tolist(),
+ np.array([(0, 0, 0), (1, 1, 1), (0, 0, 0), (1, 1, 1), (1, 1, 1)],
+ dtype=bool))
+ # Used to be mask, now it's recordmask!
+ assert_equal(mbase.recordmask, [0, 1, 0, 1, 1])
+ # Set slices .................................
+ mbase = base.view(mrecarray).copy()
+ mbase[:2] = (5, 5, 5)
+ assert_equal(mbase.a._data, [5, 5, 3, 4, 5])
+ assert_equal(mbase.a._mask, [0, 0, 0, 0, 1])
+ assert_equal(mbase.b._data, [5., 5., 3.3, 4.4, 5.5])
+ assert_equal(mbase.b._mask, [0, 0, 0, 0, 1])
+ assert_equal(mbase.c._data,
+ [b'5', b'5', b'three', b'four', b'five'])
+ assert_equal(mbase.b._mask, [0, 0, 0, 0, 1])
+
+ mbase = base.view(mrecarray).copy()
+ mbase[:2] = masked
+ assert_equal(mbase.a._data, [1, 2, 3, 4, 5])
+ assert_equal(mbase.a._mask, [1, 1, 0, 0, 1])
+ assert_equal(mbase.b._data, [1.1, 2.2, 3.3, 4.4, 5.5])
+ assert_equal(mbase.b._mask, [1, 1, 0, 0, 1])
+ assert_equal(mbase.c._data,
+ [b'one', b'two', b'three', b'four', b'five'])
+ assert_equal(mbase.b._mask, [1, 1, 0, 0, 1])
+
+ def test_setslices_hardmask(self):
+ # Tests setting slices w/ hardmask.
+ base = self.base.copy()
+ mbase = base.view(mrecarray)
+ mbase.harden_mask()
+ try:
+ mbase[-2:] = (5, 5, 5)
+ assert_equal(mbase.a._data, [1, 2, 3, 5, 5])
+ assert_equal(mbase.b._data, [1.1, 2.2, 3.3, 5, 5.5])
+ assert_equal(mbase.c._data,
+ [b'one', b'two', b'three', b'5', b'five'])
+ assert_equal(mbase.a._mask, [0, 1, 0, 0, 1])
+ assert_equal(mbase.b._mask, mbase.a._mask)
+ assert_equal(mbase.b._mask, mbase.c._mask)
+ except NotImplementedError:
+ # OK, not implemented yet...
+ pass
+ except AssertionError:
+ raise
+ else:
+ raise Exception("Flexible hard masks should be supported !")
+ # Not using a tuple should crash
+ try:
+ mbase[-2:] = 3
+ except (NotImplementedError, TypeError):
+ pass
+ else:
+ raise TypeError("Should have expected a readable buffer object!")
+
+ def test_hardmask(self):
+ # Test hardmask
+ base = self.base.copy()
+ mbase = base.view(mrecarray)
+ mbase.harden_mask()
+ assert_(mbase._hardmask)
+ mbase.mask = nomask
+ assert_equal_records(mbase._mask, base._mask)
+ mbase.soften_mask()
+ assert_(not mbase._hardmask)
+ mbase.mask = nomask
+ # So, the mask of a field is no longer set to nomask...
+ assert_equal_records(mbase._mask,
+ ma.make_mask_none(base.shape, base.dtype))
+ assert_(ma.make_mask(mbase['b']._mask) is nomask)
+ assert_equal(mbase['a']._mask, mbase['b']._mask)
+
+ def test_pickling(self):
+ # Test pickling
+ base = self.base.copy()
+ mrec = base.view(mrecarray)
+ for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
+ _ = pickle.dumps(mrec, protocol=proto)
+ mrec_ = pickle.loads(_)
+ assert_equal(mrec_.dtype, mrec.dtype)
+ assert_equal_records(mrec_._data, mrec._data)
+ assert_equal(mrec_._mask, mrec._mask)
+ assert_equal_records(mrec_._mask, mrec._mask)
+
+ def test_filled(self):
+ # Test filling the array
+ _a = ma.array([1, 2, 3], mask=[0, 0, 1], dtype=int)
+ _b = ma.array([1.1, 2.2, 3.3], mask=[0, 0, 1], dtype=float)
+ _c = ma.array(['one', 'two', 'three'], mask=[0, 0, 1], dtype='|S8')
+ ddtype = [('a', int), ('b', float), ('c', '|S8')]
+ mrec = fromarrays([_a, _b, _c], dtype=ddtype,
+ fill_value=(99999, 99999., 'N/A'))
+ mrecfilled = mrec.filled()
+ assert_equal(mrecfilled['a'], np.array((1, 2, 99999), dtype=int))
+ assert_equal(mrecfilled['b'], np.array((1.1, 2.2, 99999.),
+ dtype=float))
+ assert_equal(mrecfilled['c'], np.array(('one', 'two', 'N/A'),
+ dtype='|S8'))
+
+ def test_tolist(self):
+ # Test tolist.
+ _a = ma.array([1, 2, 3], mask=[0, 0, 1], dtype=int)
+ _b = ma.array([1.1, 2.2, 3.3], mask=[0, 0, 1], dtype=float)
+ _c = ma.array(['one', 'two', 'three'], mask=[1, 0, 0], dtype='|S8')
+ ddtype = [('a', int), ('b', float), ('c', '|S8')]
+ mrec = fromarrays([_a, _b, _c], dtype=ddtype,
+ fill_value=(99999, 99999., 'N/A'))
+
+ assert_equal(mrec.tolist(),
+ [(1, 1.1, None), (2, 2.2, b'two'),
+ (None, None, b'three')])
+
+ def test_withnames(self):
+ # Test the creation w/ format and names
+ x = mrecarray(1, formats=float, names='base')
+ x[0]['base'] = 10
+ assert_equal(x['base'][0], 10)
+
+ def test_exotic_formats(self):
+ # Test that 'exotic' formats are processed properly
+ easy = mrecarray(1, dtype=[('i', int), ('s', '|S8'), ('f', float)])
+ easy[0] = masked
+ assert_equal(easy.filled(1).item(), (1, b'1', 1.))
+
+ solo = mrecarray(1, dtype=[('f0', '<f8', (2, 2))])
+ solo[0] = masked
+ assert_equal(solo.filled(1).item(),
+ np.array((1,), dtype=solo.dtype).item())
+
+ mult = mrecarray(2, dtype="i4, (2,3)float, float")
+ mult[0] = masked
+ mult[1] = (1, 1, 1)
+ mult.filled(0)
+ assert_equal_records(mult.filled(0),
+ np.array([(0, 0, 0), (1, 1, 1)],
+ dtype=mult.dtype))
+
+
+class TestView:
+
+ def setup_method(self):
+ (a, b) = (np.arange(10), np.random.rand(10))
+ ndtype = [('a', float), ('b', float)]
+ arr = np.array(list(zip(a, b)), dtype=ndtype)
+
+ mrec = fromarrays([a, b], dtype=ndtype, fill_value=(-9., -99.))
+ mrec.mask[3] = (False, True)
+ self.data = (mrec, a, b, arr)
+
+ def test_view_by_itself(self):
+ (mrec, a, b, arr) = self.data
+ test = mrec.view()
+ assert_(isinstance(test, MaskedRecords))
+ assert_equal_records(test, mrec)
+ assert_equal_records(test._mask, mrec._mask)
+
+ def test_view_simple_dtype(self):
+ (mrec, a, b, arr) = self.data
+ ntype = (float, 2)
+ test = mrec.view(ntype)
+ assert_(isinstance(test, ma.MaskedArray))
+ assert_equal(test, np.array(list(zip(a, b)), dtype=float))
+ assert_(test[3, 1] is ma.masked)
+
+ def test_view_flexible_type(self):
+ (mrec, a, b, arr) = self.data
+ alttype = [('A', float), ('B', float)]
+ test = mrec.view(alttype)
+ assert_(isinstance(test, MaskedRecords))
+ assert_equal_records(test, arr.view(alttype))
+ assert_(test['B'][3] is masked)
+ assert_equal(test.dtype, np.dtype(alttype))
+ assert_(test._fill_value is None)
+
+
+##############################################################################
+class TestMRecordsImport:
+
+ _a = ma.array([1, 2, 3], mask=[0, 0, 1], dtype=int)
+ _b = ma.array([1.1, 2.2, 3.3], mask=[0, 0, 1], dtype=float)
+ _c = ma.array([b'one', b'two', b'three'],
+ mask=[0, 0, 1], dtype='|S8')
+ ddtype = [('a', int), ('b', float), ('c', '|S8')]
+ mrec = fromarrays([_a, _b, _c], dtype=ddtype,
+ fill_value=(b'99999', b'99999.',
+ b'N/A'))
+ nrec = recfromarrays((_a._data, _b._data, _c._data), dtype=ddtype)
+ data = (mrec, nrec, ddtype)
+
+ def test_fromarrays(self):
+ _a = ma.array([1, 2, 3], mask=[0, 0, 1], dtype=int)
+ _b = ma.array([1.1, 2.2, 3.3], mask=[0, 0, 1], dtype=float)
+ _c = ma.array(['one', 'two', 'three'], mask=[0, 0, 1], dtype='|S8')
+ (mrec, nrec, _) = self.data
+ for (f, l) in zip(('a', 'b', 'c'), (_a, _b, _c)):
+ assert_equal(getattr(mrec, f)._mask, l._mask)
+ # One record only
+ _x = ma.array([1, 1.1, 'one'], mask=[1, 0, 0], dtype=object)
+ assert_equal_records(fromarrays(_x, dtype=mrec.dtype), mrec[0])
+
+ def test_fromrecords(self):
+ # Test construction from records.
+ (mrec, nrec, ddtype) = self.data
+ #......
+ palist = [(1, 'abc', 3.7000002861022949, 0),
+ (2, 'xy', 6.6999998092651367, 1),
+ (0, ' ', 0.40000000596046448, 0)]
+ pa = recfromrecords(palist, names='c1, c2, c3, c4')
+ mpa = fromrecords(palist, names='c1, c2, c3, c4')
+ assert_equal_records(pa, mpa)
+ #.....
+ _mrec = fromrecords(nrec)
+ assert_equal(_mrec.dtype, mrec.dtype)
+ for field in _mrec.dtype.names:
+ assert_equal(getattr(_mrec, field), getattr(mrec._data, field))
+
+ _mrec = fromrecords(nrec.tolist(), names='c1,c2,c3')
+ assert_equal(_mrec.dtype, [('c1', int), ('c2', float), ('c3', '|S5')])
+ for (f, n) in zip(('c1', 'c2', 'c3'), ('a', 'b', 'c')):
+ assert_equal(getattr(_mrec, f), getattr(mrec._data, n))
+
+ _mrec = fromrecords(mrec)
+ assert_equal(_mrec.dtype, mrec.dtype)
+ assert_equal_records(_mrec._data, mrec.filled())
+ assert_equal_records(_mrec._mask, mrec._mask)
+
+ def test_fromrecords_wmask(self):
+ # Tests construction from records w/ mask.
+ (mrec, nrec, ddtype) = self.data
+
+ _mrec = fromrecords(nrec.tolist(), dtype=ddtype, mask=[0, 1, 0,])
+ assert_equal_records(_mrec._data, mrec._data)
+ assert_equal(_mrec._mask.tolist(), [(0, 0, 0), (1, 1, 1), (0, 0, 0)])
+
+ _mrec = fromrecords(nrec.tolist(), dtype=ddtype, mask=True)
+ assert_equal_records(_mrec._data, mrec._data)
+ assert_equal(_mrec._mask.tolist(), [(1, 1, 1), (1, 1, 1), (1, 1, 1)])
+
+ _mrec = fromrecords(nrec.tolist(), dtype=ddtype, mask=mrec._mask)
+ assert_equal_records(_mrec._data, mrec._data)
+ assert_equal(_mrec._mask.tolist(), mrec._mask.tolist())
+
+ _mrec = fromrecords(nrec.tolist(), dtype=ddtype,
+ mask=mrec._mask.tolist())
+ assert_equal_records(_mrec._data, mrec._data)
+ assert_equal(_mrec._mask.tolist(), mrec._mask.tolist())
+
+ def test_fromtextfile(self):
+ # Tests reading from a text file.
+ fcontent = (
+"""#
+'One (S)','Two (I)','Three (F)','Four (M)','Five (-)','Six (C)'
+'strings',1,1.0,'mixed column',,1
+'with embedded "double quotes"',2,2.0,1.0,,1
+'strings',3,3.0E5,3,,1
+'strings',4,-1e-10,,,1
+""")
+ with temppath() as path:
+ with open(path, 'w') as f:
+ f.write(fcontent)
+ mrectxt = fromtextfile(path, delimiter=',', varnames='ABCDEFG')
+ assert_(isinstance(mrectxt, MaskedRecords))
+ assert_equal(mrectxt.F, [1, 1, 1, 1])
+ assert_equal(mrectxt.E._mask, [1, 1, 1, 1])
+ assert_equal(mrectxt.C, [1, 2, 3.e+5, -1e-10])
+
+ def test_addfield(self):
+ # Tests addfield
+ (mrec, nrec, ddtype) = self.data
+ (d, m) = ([100, 200, 300], [1, 0, 0])
+ mrec = addfield(mrec, ma.array(d, mask=m))
+ assert_equal(mrec.f3, d)
+ assert_equal(mrec.f3._mask, m)
+
+
+def test_record_array_with_object_field():
+ # Trac #1839
+ y = ma.masked_array(
+ [(1, '2'), (3, '4')],
+ mask=[(0, 0), (0, 1)],
+ dtype=[('a', int), ('b', object)])
+ # getting an item used to fail
+ y[1]
diff --git a/venv/lib/python3.9/site-packages/numpy/ma/tests/test_old_ma.py b/venv/lib/python3.9/site-packages/numpy/ma/tests/test_old_ma.py
new file mode 100644
index 00000000..8465b115
--- /dev/null
+++ b/venv/lib/python3.9/site-packages/numpy/ma/tests/test_old_ma.py
@@ -0,0 +1,874 @@
+from functools import reduce
+
+import pytest
+
+import numpy as np
+import numpy.core.umath as umath
+import numpy.core.fromnumeric as fromnumeric
+from numpy.testing import (
+ assert_, assert_raises, assert_equal,
+ )
+from numpy.ma import (
+ MaskType, MaskedArray, absolute, add, all, allclose, allequal, alltrue,
+ arange, arccos, arcsin, arctan, arctan2, array, average, choose,
+ concatenate, conjugate, cos, cosh, count, divide, equal, exp, filled,
+ getmask, greater, greater_equal, inner, isMaskedArray, less,
+ less_equal, log, log10, make_mask, masked, masked_array, masked_equal,
+ masked_greater, masked_greater_equal, masked_inside, masked_less,
+ masked_less_equal, masked_not_equal, masked_outside,
+ masked_print_option, masked_values, masked_where, maximum, minimum,
+ multiply, nomask, nonzero, not_equal, ones, outer, product, put, ravel,
+ repeat, resize, shape, sin, sinh, sometrue, sort, sqrt, subtract, sum,
+ take, tan, tanh, transpose, where, zeros,
+ )
+from numpy.compat import pickle
+
+pi = np.pi
+
+
+def eq(v, w, msg=''):
+ result = allclose(v, w)
+ if not result:
+ print(f'Not eq:{msg}\n{v}\n----{w}')
+ return result
+
+
+class TestMa:
+
+ def setup_method(self):
+ x = np.array([1., 1., 1., -2., pi/2.0, 4., 5., -10., 10., 1., 2., 3.])
+ y = np.array([5., 0., 3., 2., -1., -4., 0., -10., 10., 1., 0., 3.])
+ a10 = 10.
+ m1 = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
+ m2 = [0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1]
+ xm = array(x, mask=m1)
+ ym = array(y, mask=m2)
+ z = np.array([-.5, 0., .5, .8])
+ zm = array(z, mask=[0, 1, 0, 0])
+ xf = np.where(m1, 1e+20, x)
+ s = x.shape
+ xm.set_fill_value(1e+20)
+ self.d = (x, y, a10, m1, m2, xm, ym, z, zm, xf, s)
+
+ def test_testBasic1d(self):
+ # Test of basic array creation and properties in 1 dimension.
+ (x, y, a10, m1, m2, xm, ym, z, zm, xf, s) = self.d
+ assert_(not isMaskedArray(x))
+ assert_(isMaskedArray(xm))
+ assert_equal(shape(xm), s)
+ assert_equal(xm.shape, s)
+ assert_equal(xm.dtype, x.dtype)
+ assert_equal(xm.size, reduce(lambda x, y:x * y, s))
+ assert_equal(count(xm), len(m1) - reduce(lambda x, y:x + y, m1))
+ assert_(eq(xm, xf))
+ assert_(eq(filled(xm, 1.e20), xf))
+ assert_(eq(x, xm))
+
+ @pytest.mark.parametrize("s", [(4, 3), (6, 2)])
+ def test_testBasic2d(self, s):
+ # Test of basic array creation and properties in 2 dimensions.
+ (x, y, a10, m1, m2, xm, ym, z, zm, xf, s) = self.d
+ x.shape = s
+ y.shape = s
+ xm.shape = s
+ ym.shape = s
+ xf.shape = s
+
+ assert_(not isMaskedArray(x))
+ assert_(isMaskedArray(xm))
+ assert_equal(shape(xm), s)
+ assert_equal(xm.shape, s)
+ assert_equal(xm.size, reduce(lambda x, y: x * y, s))
+ assert_equal(count(xm), len(m1) - reduce(lambda x, y: x + y, m1))
+ assert_(eq(xm, xf))
+ assert_(eq(filled(xm, 1.e20), xf))
+ assert_(eq(x, xm))
+
+ def test_testArithmetic(self):
+ # Test of basic arithmetic.
+ (x, y, a10, m1, m2, xm, ym, z, zm, xf, s) = self.d
+ a2d = array([[1, 2], [0, 4]])
+ a2dm = masked_array(a2d, [[0, 0], [1, 0]])
+ assert_(eq(a2d * a2d, a2d * a2dm))
+ assert_(eq(a2d + a2d, a2d + a2dm))
+ assert_(eq(a2d - a2d, a2d - a2dm))
+ for s in [(12,), (4, 3), (2, 6)]:
+ x = x.reshape(s)
+ y = y.reshape(s)
+ xm = xm.reshape(s)
+ ym = ym.reshape(s)
+ xf = xf.reshape(s)
+ assert_(eq(-x, -xm))
+ assert_(eq(x + y, xm + ym))
+ assert_(eq(x - y, xm - ym))
+ assert_(eq(x * y, xm * ym))
+ with np.errstate(divide='ignore', invalid='ignore'):
+ assert_(eq(x / y, xm / ym))
+ assert_(eq(a10 + y, a10 + ym))
+ assert_(eq(a10 - y, a10 - ym))
+ assert_(eq(a10 * y, a10 * ym))
+ with np.errstate(divide='ignore', invalid='ignore'):
+ assert_(eq(a10 / y, a10 / ym))
+ assert_(eq(x + a10, xm + a10))
+ assert_(eq(x - a10, xm - a10))
+ assert_(eq(x * a10, xm * a10))
+ assert_(eq(x / a10, xm / a10))
+ assert_(eq(x ** 2, xm ** 2))
+ assert_(eq(abs(x) ** 2.5, abs(xm) ** 2.5))
+ assert_(eq(x ** y, xm ** ym))
+ assert_(eq(np.add(x, y), add(xm, ym)))
+ assert_(eq(np.subtract(x, y), subtract(xm, ym)))
+ assert_(eq(np.multiply(x, y), multiply(xm, ym)))
+ with np.errstate(divide='ignore', invalid='ignore'):
+ assert_(eq(np.divide(x, y), divide(xm, ym)))
+
+ def test_testMixedArithmetic(self):
+ na = np.array([1])
+ ma = array([1])
+ assert_(isinstance(na + ma, MaskedArray))
+ assert_(isinstance(ma + na, MaskedArray))
+
+ def test_testUfuncs1(self):
+ # Test various functions such as sin, cos.
+ (x, y, a10, m1, m2, xm, ym, z, zm, xf, s) = self.d
+ assert_(eq(np.cos(x), cos(xm)))
+ assert_(eq(np.cosh(x), cosh(xm)))
+ assert_(eq(np.sin(x), sin(xm)))
+ assert_(eq(np.sinh(x), sinh(xm)))
+ assert_(eq(np.tan(x), tan(xm)))
+ assert_(eq(np.tanh(x), tanh(xm)))
+ with np.errstate(divide='ignore', invalid='ignore'):
+ assert_(eq(np.sqrt(abs(x)), sqrt(xm)))
+ assert_(eq(np.log(abs(x)), log(xm)))
+ assert_(eq(np.log10(abs(x)), log10(xm)))
+ assert_(eq(np.exp(x), exp(xm)))
+ assert_(eq(np.arcsin(z), arcsin(zm)))
+ assert_(eq(np.arccos(z), arccos(zm)))
+ assert_(eq(np.arctan(z), arctan(zm)))
+ assert_(eq(np.arctan2(x, y), arctan2(xm, ym)))
+ assert_(eq(np.absolute(x), absolute(xm)))
+ assert_(eq(np.equal(x, y), equal(xm, ym)))
+ assert_(eq(np.not_equal(x, y), not_equal(xm, ym)))
+ assert_(eq(np.less(x, y), less(xm, ym)))
+ assert_(eq(np.greater(x, y), greater(xm, ym)))
+ assert_(eq(np.less_equal(x, y), less_equal(xm, ym)))
+ assert_(eq(np.greater_equal(x, y), greater_equal(xm, ym)))
+ assert_(eq(np.conjugate(x), conjugate(xm)))
+ assert_(eq(np.concatenate((x, y)), concatenate((xm, ym))))
+ assert_(eq(np.concatenate((x, y)), concatenate((x, y))))
+ assert_(eq(np.concatenate((x, y)), concatenate((xm, y))))
+ assert_(eq(np.concatenate((x, y, x)), concatenate((x, ym, x))))
+
+ def test_xtestCount(self):
+ # Test count
+ ott = array([0., 1., 2., 3.], mask=[1, 0, 0, 0])
+ assert_(count(ott).dtype.type is np.intp)
+ assert_equal(3, count(ott))
+ assert_equal(1, count(1))
+ assert_(eq(0, array(1, mask=[1])))
+ ott = ott.reshape((2, 2))
+ assert_(count(ott).dtype.type is np.intp)
+ assert_(isinstance(count(ott, 0), np.ndarray))
+ assert_(count(ott).dtype.type is np.intp)
+ assert_(eq(3, count(ott)))
+ assert_(getmask(count(ott, 0)) is nomask)
+ assert_(eq([1, 2], count(ott, 0)))
+
+ def test_testMinMax(self):
+ # Test minimum and maximum.
+ (x, y, a10, m1, m2, xm, ym, z, zm, xf, s) = self.d
+ xr = np.ravel(x) # max doesn't work if shaped
+ xmr = ravel(xm)
+
+ # true because of careful selection of data
+ assert_(eq(max(xr), maximum.reduce(xmr)))
+ assert_(eq(min(xr), minimum.reduce(xmr)))
+
+ def test_testAddSumProd(self):
+ # Test add, sum, product.
+ (x, y, a10, m1, m2, xm, ym, z, zm, xf, s) = self.d
+ assert_(eq(np.add.reduce(x), add.reduce(x)))
+ assert_(eq(np.add.accumulate(x), add.accumulate(x)))
+ assert_(eq(4, sum(array(4), axis=0)))
+ assert_(eq(4, sum(array(4), axis=0)))
+ assert_(eq(np.sum(x, axis=0), sum(x, axis=0)))
+ assert_(eq(np.sum(filled(xm, 0), axis=0), sum(xm, axis=0)))
+ assert_(eq(np.sum(x, 0), sum(x, 0)))
+ assert_(eq(np.product(x, axis=0), product(x, axis=0)))
+ assert_(eq(np.product(x, 0), product(x, 0)))
+ assert_(eq(np.product(filled(xm, 1), axis=0),
+ product(xm, axis=0)))
+ if len(s) > 1:
+ assert_(eq(np.concatenate((x, y), 1),
+ concatenate((xm, ym), 1)))
+ assert_(eq(np.add.reduce(x, 1), add.reduce(x, 1)))
+ assert_(eq(np.sum(x, 1), sum(x, 1)))
+ assert_(eq(np.product(x, 1), product(x, 1)))
+
+ def test_testCI(self):
+ # Test of conversions and indexing
+ x1 = np.array([1, 2, 4, 3])
+ x2 = array(x1, mask=[1, 0, 0, 0])
+ x3 = array(x1, mask=[0, 1, 0, 1])
+ x4 = array(x1)
+ # test conversion to strings
+ str(x2) # raises?
+ repr(x2) # raises?
+ assert_(eq(np.sort(x1), sort(x2, fill_value=0)))
+ # tests of indexing
+ assert_(type(x2[1]) is type(x1[1]))
+ assert_(x1[1] == x2[1])
+ assert_(x2[0] is masked)
+ assert_(eq(x1[2], x2[2]))
+ assert_(eq(x1[2:5], x2[2:5]))
+ assert_(eq(x1[:], x2[:]))
+ assert_(eq(x1[1:], x3[1:]))
+ x1[2] = 9
+ x2[2] = 9
+ assert_(eq(x1, x2))
+ x1[1:3] = 99
+ x2[1:3] = 99
+ assert_(eq(x1, x2))
+ x2[1] = masked
+ assert_(eq(x1, x2))
+ x2[1:3] = masked
+ assert_(eq(x1, x2))
+ x2[:] = x1
+ x2[1] = masked
+ assert_(allequal(getmask(x2), array([0, 1, 0, 0])))
+ x3[:] = masked_array([1, 2, 3, 4], [0, 1, 1, 0])
+ assert_(allequal(getmask(x3), array([0, 1, 1, 0])))
+ x4[:] = masked_array([1, 2, 3, 4], [0, 1, 1, 0])
+ assert_(allequal(getmask(x4), array([0, 1, 1, 0])))
+ assert_(allequal(x4, array([1, 2, 3, 4])))
+ x1 = np.arange(5) * 1.0
+ x2 = masked_values(x1, 3.0)
+ assert_(eq(x1, x2))
+ assert_(allequal(array([0, 0, 0, 1, 0], MaskType), x2.mask))
+ assert_(eq(3.0, x2.fill_value))
+ x1 = array([1, 'hello', 2, 3], object)
+ x2 = np.array([1, 'hello', 2, 3], object)
+ s1 = x1[1]
+ s2 = x2[1]
+ assert_equal(type(s2), str)
+ assert_equal(type(s1), str)
+ assert_equal(s1, s2)
+ assert_(x1[1:1].shape == (0,))
+
+ def test_testCopySize(self):
+ # Tests of some subtle points of copying and sizing.
+ n = [0, 0, 1, 0, 0]
+ m = make_mask(n)
+ m2 = make_mask(m)
+ assert_(m is m2)
+ m3 = make_mask(m, copy=True)
+ assert_(m is not m3)
+
+ x1 = np.arange(5)
+ y1 = array(x1, mask=m)
+ assert_(y1._data is not x1)
+ assert_(allequal(x1, y1._data))
+ assert_(y1._mask is m)
+
+ y1a = array(y1, copy=0)
+ # For copy=False, one might expect that the array would just
+ # passed on, i.e., that it would be "is" instead of "==".
+ # See gh-4043 for discussion.
+ assert_(y1a._mask.__array_interface__ ==
+ y1._mask.__array_interface__)
+
+ y2 = array(x1, mask=m3, copy=0)
+ assert_(y2._mask is m3)
+ assert_(y2[2] is masked)
+ y2[2] = 9
+ assert_(y2[2] is not masked)
+ assert_(y2._mask is m3)
+ assert_(allequal(y2.mask, 0))
+
+ y2a = array(x1, mask=m, copy=1)
+ assert_(y2a._mask is not m)
+ assert_(y2a[2] is masked)
+ y2a[2] = 9
+ assert_(y2a[2] is not masked)
+ assert_(y2a._mask is not m)
+ assert_(allequal(y2a.mask, 0))
+
+ y3 = array(x1 * 1.0, mask=m)
+ assert_(filled(y3).dtype is (x1 * 1.0).dtype)
+
+ x4 = arange(4)
+ x4[2] = masked
+ y4 = resize(x4, (8,))
+ assert_(eq(concatenate([x4, x4]), y4))
+ assert_(eq(getmask(y4), [0, 0, 1, 0, 0, 0, 1, 0]))
+ y5 = repeat(x4, (2, 2, 2, 2), axis=0)
+ assert_(eq(y5, [0, 0, 1, 1, 2, 2, 3, 3]))
+ y6 = repeat(x4, 2, axis=0)
+ assert_(eq(y5, y6))
+
+ def test_testPut(self):
+ # Test of put
+ d = arange(5)
+ n = [0, 0, 0, 1, 1]
+ m = make_mask(n)
+ m2 = m.copy()
+ x = array(d, mask=m)
+ assert_(x[3] is masked)
+ assert_(x[4] is masked)
+ x[[1, 4]] = [10, 40]
+ assert_(x._mask is m)
+ assert_(x[3] is masked)
+ assert_(x[4] is not masked)
+ assert_(eq(x, [0, 10, 2, -1, 40]))
+
+ x = array(d, mask=m2, copy=True)
+ x.put([0, 1, 2], [-1, 100, 200])
+ assert_(x._mask is not m2)
+ assert_(x[3] is masked)
+ assert_(x[4] is masked)
+ assert_(eq(x, [-1, 100, 200, 0, 0]))
+
+ def test_testPut2(self):
+ # Test of put
+ d = arange(5)
+ x = array(d, mask=[0, 0, 0, 0, 0])
+ z = array([10, 40], mask=[1, 0])
+ assert_(x[2] is not masked)
+ assert_(x[3] is not masked)
+ x[2:4] = z
+ assert_(x[2] is masked)
+ assert_(x[3] is not masked)
+ assert_(eq(x, [0, 1, 10, 40, 4]))
+
+ d = arange(5)
+ x = array(d, mask=[0, 0, 0, 0, 0])
+ y = x[2:4]
+ z = array([10, 40], mask=[1, 0])
+ assert_(x[2] is not masked)
+ assert_(x[3] is not masked)
+ y[:] = z
+ assert_(y[0] is masked)
+ assert_(y[1] is not masked)
+ assert_(eq(y, [10, 40]))
+ assert_(x[2] is masked)
+ assert_(x[3] is not masked)
+ assert_(eq(x, [0, 1, 10, 40, 4]))
+
+ def test_testMaPut(self):
+ (x, y, a10, m1, m2, xm, ym, z, zm, xf, s) = self.d
+ m = [1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1]
+ i = np.nonzero(m)[0]
+ put(ym, i, zm)
+ assert_(all(take(ym, i, axis=0) == zm))
+
+ def test_testOddFeatures(self):
+ # Test of other odd features
+ x = arange(20)
+ x = x.reshape(4, 5)
+ x.flat[5] = 12
+ assert_(x[1, 0] == 12)
+ z = x + 10j * x
+ assert_(eq(z.real, x))
+ assert_(eq(z.imag, 10 * x))
+ assert_(eq((z * conjugate(z)).real, 101 * x * x))
+ z.imag[...] = 0.0
+
+ x = arange(10)
+ x[3] = masked
+ assert_(str(x[3]) == str(masked))
+ c = x >= 8
+ assert_(count(where(c, masked, masked)) == 0)
+ assert_(shape(where(c, masked, masked)) == c.shape)
+ z = where(c, x, masked)
+ assert_(z.dtype is x.dtype)
+ assert_(z[3] is masked)
+ assert_(z[4] is masked)
+ assert_(z[7] is masked)
+ assert_(z[8] is not masked)
+ assert_(z[9] is not masked)
+ assert_(eq(x, z))
+ z = where(c, masked, x)
+ assert_(z.dtype is x.dtype)
+ assert_(z[3] is masked)
+ assert_(z[4] is not masked)
+ assert_(z[7] is not masked)
+ assert_(z[8] is masked)
+ assert_(z[9] is masked)
+ z = masked_where(c, x)
+ assert_(z.dtype is x.dtype)
+ assert_(z[3] is masked)
+ assert_(z[4] is not masked)
+ assert_(z[7] is not masked)
+ assert_(z[8] is masked)
+ assert_(z[9] is masked)
+ assert_(eq(x, z))
+ x = array([1., 2., 3., 4., 5.])
+ c = array([1, 1, 1, 0, 0])
+ x[2] = masked
+ z = where(c, x, -x)
+ assert_(eq(z, [1., 2., 0., -4., -5]))
+ c[0] = masked
+ z = where(c, x, -x)
+ assert_(eq(z, [1., 2., 0., -4., -5]))
+ assert_(z[0] is masked)
+ assert_(z[1] is not masked)
+ assert_(z[2] is masked)
+ assert_(eq(masked_where(greater(x, 2), x), masked_greater(x, 2)))
+ assert_(eq(masked_where(greater_equal(x, 2), x),
+ masked_greater_equal(x, 2)))
+ assert_(eq(masked_where(less(x, 2), x), masked_less(x, 2)))
+ assert_(eq(masked_where(less_equal(x, 2), x), masked_less_equal(x, 2)))
+ assert_(eq(masked_where(not_equal(x, 2), x), masked_not_equal(x, 2)))
+ assert_(eq(masked_where(equal(x, 2), x), masked_equal(x, 2)))
+ assert_(eq(masked_where(not_equal(x, 2), x), masked_not_equal(x, 2)))
+ assert_(eq(masked_inside(list(range(5)), 1, 3), [0, 199, 199, 199, 4]))
+ assert_(eq(masked_outside(list(range(5)), 1, 3), [199, 1, 2, 3, 199]))
+ assert_(eq(masked_inside(array(list(range(5)),
+ mask=[1, 0, 0, 0, 0]), 1, 3).mask,
+ [1, 1, 1, 1, 0]))
+ assert_(eq(masked_outside(array(list(range(5)),
+ mask=[0, 1, 0, 0, 0]), 1, 3).mask,
+ [1, 1, 0, 0, 1]))
+ assert_(eq(masked_equal(array(list(range(5)),
+ mask=[1, 0, 0, 0, 0]), 2).mask,
+ [1, 0, 1, 0, 0]))
+ assert_(eq(masked_not_equal(array([2, 2, 1, 2, 1],
+ mask=[1, 0, 0, 0, 0]), 2).mask,
+ [1, 0, 1, 0, 1]))
+ assert_(eq(masked_where([1, 1, 0, 0, 0], [1, 2, 3, 4, 5]),
+ [99, 99, 3, 4, 5]))
+ atest = ones((10, 10, 10), dtype=np.float32)
+ btest = zeros(atest.shape, MaskType)
+ ctest = masked_where(btest, atest)
+ assert_(eq(atest, ctest))
+ z = choose(c, (-x, x))
+ assert_(eq(z, [1., 2., 0., -4., -5]))
+ assert_(z[0] is masked)
+ assert_(z[1] is not masked)
+ assert_(z[2] is masked)
+ x = arange(6)
+ x[5] = masked
+ y = arange(6) * 10
+ y[2] = masked
+ c = array([1, 1, 1, 0, 0, 0], mask=[1, 0, 0, 0, 0, 0])
+ cm = c.filled(1)
+ z = where(c, x, y)
+ zm = where(cm, x, y)
+ assert_(eq(z, zm))
+ assert_(getmask(zm) is nomask)
+ assert_(eq(zm, [0, 1, 2, 30, 40, 50]))
+ z = where(c, masked, 1)
+ assert_(eq(z, [99, 99, 99, 1, 1, 1]))
+ z = where(c, 1, masked)
+ assert_(eq(z, [99, 1, 1, 99, 99, 99]))
+
+ def test_testMinMax2(self):
+ # Test of minimum, maximum.
+ assert_(eq(minimum([1, 2, 3], [4, 0, 9]), [1, 0, 3]))
+ assert_(eq(maximum([1, 2, 3], [4, 0, 9]), [4, 2, 9]))
+ x = arange(5)
+ y = arange(5) - 2
+ x[3] = masked
+ y[0] = masked
+ assert_(eq(minimum(x, y), where(less(x, y), x, y)))
+ assert_(eq(maximum(x, y), where(greater(x, y), x, y)))
+ assert_(minimum.reduce(x) == 0)
+ assert_(maximum.reduce(x) == 4)
+
+ def test_testTakeTransposeInnerOuter(self):
+ # Test of take, transpose, inner, outer products
+ x = arange(24)
+ y = np.arange(24)
+ x[5:6] = masked
+ x = x.reshape(2, 3, 4)
+ y = y.reshape(2, 3, 4)
+ assert_(eq(np.transpose(y, (2, 0, 1)), transpose(x, (2, 0, 1))))
+ assert_(eq(np.take(y, (2, 0, 1), 1), take(x, (2, 0, 1), 1)))
+ assert_(eq(np.inner(filled(x, 0), filled(y, 0)),
+ inner(x, y)))
+ assert_(eq(np.outer(filled(x, 0), filled(y, 0)),
+ outer(x, y)))
+ y = array(['abc', 1, 'def', 2, 3], object)
+ y[2] = masked
+ t = take(y, [0, 3, 4])
+ assert_(t[0] == 'abc')
+ assert_(t[1] == 2)
+ assert_(t[2] == 3)
+
+ def test_testInplace(self):
+ # Test of inplace operations and rich comparisons
+ y = arange(10)
+
+ x = arange(10)
+ xm = arange(10)
+ xm[2] = masked
+ x += 1
+ assert_(eq(x, y + 1))
+ xm += 1
+ assert_(eq(x, y + 1))
+
+ x = arange(10)
+ xm = arange(10)
+ xm[2] = masked
+ x -= 1
+ assert_(eq(x, y - 1))
+ xm -= 1
+ assert_(eq(xm, y - 1))
+
+ x = arange(10) * 1.0
+ xm = arange(10) * 1.0
+ xm[2] = masked
+ x *= 2.0
+ assert_(eq(x, y * 2))
+ xm *= 2.0
+ assert_(eq(xm, y * 2))
+
+ x = arange(10) * 2
+ xm = arange(10)
+ xm[2] = masked
+ x //= 2
+ assert_(eq(x, y))
+ xm //= 2
+ assert_(eq(x, y))
+
+ x = arange(10) * 1.0
+ xm = arange(10) * 1.0
+ xm[2] = masked
+ x /= 2.0
+ assert_(eq(x, y / 2.0))
+ xm /= arange(10)
+ assert_(eq(xm, ones((10,))))
+
+ x = arange(10).astype(np.float32)
+ xm = arange(10)
+ xm[2] = masked
+ x += 1.
+ assert_(eq(x, y + 1.))
+
+ def test_testPickle(self):
+ # Test of pickling
+ x = arange(12)
+ x[4:10:2] = masked
+ x = x.reshape(4, 3)
+ for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
+ s = pickle.dumps(x, protocol=proto)
+ y = pickle.loads(s)
+ assert_(eq(x, y))
+
+ def test_testMasked(self):
+ # Test of masked element
+ xx = arange(6)
+ xx[1] = masked
+ assert_(str(masked) == '--')
+ assert_(xx[1] is masked)
+ assert_equal(filled(xx[1], 0), 0)
+
+ def test_testAverage1(self):
+ # Test of average.
+ ott = array([0., 1., 2., 3.], mask=[1, 0, 0, 0])
+ assert_(eq(2.0, average(ott, axis=0)))
+ assert_(eq(2.0, average(ott, weights=[1., 1., 2., 1.])))
+ result, wts = average(ott, weights=[1., 1., 2., 1.], returned=True)
+ assert_(eq(2.0, result))
+ assert_(wts == 4.0)
+ ott[:] = masked
+ assert_(average(ott, axis=0) is masked)
+ ott = array([0., 1., 2., 3.], mask=[1, 0, 0, 0])
+ ott = ott.reshape(2, 2)
+ ott[:, 1] = masked
+ assert_(eq(average(ott, axis=0), [2.0, 0.0]))
+ assert_(average(ott, axis=1)[0] is masked)
+ assert_(eq([2., 0.], average(ott, axis=0)))
+ result, wts = average(ott, axis=0, returned=True)
+ assert_(eq(wts, [1., 0.]))
+
+ def test_testAverage2(self):
+ # More tests of average.
+ w1 = [0, 1, 1, 1, 1, 0]
+ w2 = [[0, 1, 1, 1, 1, 0], [1, 0, 0, 0, 0, 1]]
+ x = arange(6)
+ assert_(allclose(average(x, axis=0), 2.5))
+ assert_(allclose(average(x, axis=0, weights=w1), 2.5))
+ y = array([arange(6), 2.0 * arange(6)])
+ assert_(allclose(average(y, None),
+ np.add.reduce(np.arange(6)) * 3. / 12.))
+ assert_(allclose(average(y, axis=0), np.arange(6) * 3. / 2.))
+ assert_(allclose(average(y, axis=1),
+ [average(x, axis=0), average(x, axis=0)*2.0]))
+ assert_(allclose(average(y, None, weights=w2), 20. / 6.))
+ assert_(allclose(average(y, axis=0, weights=w2),
+ [0., 1., 2., 3., 4., 10.]))
+ assert_(allclose(average(y, axis=1),
+ [average(x, axis=0), average(x, axis=0)*2.0]))
+ m1 = zeros(6)
+ m2 = [0, 0, 1, 1, 0, 0]
+ m3 = [[0, 0, 1, 1, 0, 0], [0, 1, 1, 1, 1, 0]]
+ m4 = ones(6)
+ m5 = [0, 1, 1, 1, 1, 1]
+ assert_(allclose(average(masked_array(x, m1), axis=0), 2.5))
+ assert_(allclose(average(masked_array(x, m2), axis=0), 2.5))
+ assert_(average(masked_array(x, m4), axis=0) is masked)
+ assert_equal(average(masked_array(x, m5), axis=0), 0.0)
+ assert_equal(count(average(masked_array(x, m4), axis=0)), 0)
+ z = masked_array(y, m3)
+ assert_(allclose(average(z, None), 20. / 6.))
+ assert_(allclose(average(z, axis=0),
+ [0., 1., 99., 99., 4.0, 7.5]))
+ assert_(allclose(average(z, axis=1), [2.5, 5.0]))
+ assert_(allclose(average(z, axis=0, weights=w2),
+ [0., 1., 99., 99., 4.0, 10.0]))
+
+ a = arange(6)
+ b = arange(6) * 3
+ r1, w1 = average([[a, b], [b, a]], axis=1, returned=True)
+ assert_equal(shape(r1), shape(w1))
+ assert_equal(r1.shape, w1.shape)
+ r2, w2 = average(ones((2, 2, 3)), axis=0, weights=[3, 1], returned=True)
+ assert_equal(shape(w2), shape(r2))
+ r2, w2 = average(ones((2, 2, 3)), returned=True)
+ assert_equal(shape(w2), shape(r2))
+ r2, w2 = average(ones((2, 2, 3)), weights=ones((2, 2, 3)), returned=True)
+ assert_(shape(w2) == shape(r2))
+ a2d = array([[1, 2], [0, 4]], float)
+ a2dm = masked_array(a2d, [[0, 0], [1, 0]])
+ a2da = average(a2d, axis=0)
+ assert_(eq(a2da, [0.5, 3.0]))
+ a2dma = average(a2dm, axis=0)
+ assert_(eq(a2dma, [1.0, 3.0]))
+ a2dma = average(a2dm, axis=None)
+ assert_(eq(a2dma, 7. / 3.))
+ a2dma = average(a2dm, axis=1)
+ assert_(eq(a2dma, [1.5, 4.0]))
+
+ def test_testToPython(self):
+ assert_equal(1, int(array(1)))
+ assert_equal(1.0, float(array(1)))
+ assert_equal(1, int(array([[[1]]])))
+ assert_equal(1.0, float(array([[1]])))
+ assert_raises(TypeError, float, array([1, 1]))
+ assert_raises(ValueError, bool, array([0, 1]))
+ assert_raises(ValueError, bool, array([0, 0], mask=[0, 1]))
+
+ def test_testScalarArithmetic(self):
+ xm = array(0, mask=1)
+ #TODO FIXME: Find out what the following raises a warning in r8247
+ with np.errstate(divide='ignore'):
+ assert_((1 / array(0)).mask)
+ assert_((1 + xm).mask)
+ assert_((-xm).mask)
+ assert_((-xm).mask)
+ assert_(maximum(xm, xm).mask)
+ assert_(minimum(xm, xm).mask)
+ assert_(xm.filled().dtype is xm._data.dtype)
+ x = array(0, mask=0)
+ assert_(x.filled() == x._data)
+ assert_equal(str(xm), str(masked_print_option))
+
+ def test_testArrayMethods(self):
+ a = array([1, 3, 2])
+ assert_(eq(a.any(), a._data.any()))
+ assert_(eq(a.all(), a._data.all()))
+ assert_(eq(a.argmax(), a._data.argmax()))
+ assert_(eq(a.argmin(), a._data.argmin()))
+ assert_(eq(a.choose(0, 1, 2, 3, 4),
+ a._data.choose(0, 1, 2, 3, 4)))
+ assert_(eq(a.compress([1, 0, 1]), a._data.compress([1, 0, 1])))
+ assert_(eq(a.conj(), a._data.conj()))
+ assert_(eq(a.conjugate(), a._data.conjugate()))
+ m = array([[1, 2], [3, 4]])
+ assert_(eq(m.diagonal(), m._data.diagonal()))
+ assert_(eq(a.sum(), a._data.sum()))
+ assert_(eq(a.take([1, 2]), a._data.take([1, 2])))
+ assert_(eq(m.transpose(), m._data.transpose()))
+
+ def test_testArrayAttributes(self):
+ a = array([1, 3, 2])
+ assert_equal(a.ndim, 1)
+
+ def test_testAPI(self):
+ assert_(not [m for m in dir(np.ndarray)
+ if m not in dir(MaskedArray) and
+ not m.startswith('_')])
+
+ def test_testSingleElementSubscript(self):
+ a = array([1, 3, 2])
+ b = array([1, 3, 2], mask=[1, 0, 1])
+ assert_equal(a[0].shape, ())
+ assert_equal(b[0].shape, ())
+ assert_equal(b[1].shape, ())
+
+ def test_assignment_by_condition(self):
+ # Test for gh-18951
+ a = array([1, 2, 3, 4], mask=[1, 0, 1, 0])
+ c = a >= 3
+ a[c] = 5
+ assert_(a[2] is masked)
+
+ def test_assignment_by_condition_2(self):
+ # gh-19721
+ a = masked_array([0, 1], mask=[False, False])
+ b = masked_array([0, 1], mask=[True, True])
+ mask = a < 1
+ b[mask] = a[mask]
+ expected_mask = [False, True]
+ assert_equal(b.mask, expected_mask)
+
+
+class TestUfuncs:
+ def setup_method(self):
+ self.d = (array([1.0, 0, -1, pi / 2] * 2, mask=[0, 1] + [0] * 6),
+ array([1.0, 0, -1, pi / 2] * 2, mask=[1, 0] + [0] * 6),)
+
+ def test_testUfuncRegression(self):
+ f_invalid_ignore = [
+ 'sqrt', 'arctanh', 'arcsin', 'arccos',
+ 'arccosh', 'arctanh', 'log', 'log10', 'divide',
+ 'true_divide', 'floor_divide', 'remainder', 'fmod']
+ for f in ['sqrt', 'log', 'log10', 'exp', 'conjugate',
+ 'sin', 'cos', 'tan',
+ 'arcsin', 'arccos', 'arctan',
+ 'sinh', 'cosh', 'tanh',
+ 'arcsinh',
+ 'arccosh',
+ 'arctanh',
+ 'absolute', 'fabs', 'negative',
+ 'floor', 'ceil',
+ 'logical_not',
+ 'add', 'subtract', 'multiply',
+ 'divide', 'true_divide', 'floor_divide',
+ 'remainder', 'fmod', 'hypot', 'arctan2',
+ 'equal', 'not_equal', 'less_equal', 'greater_equal',
+ 'less', 'greater',
+ 'logical_and', 'logical_or', 'logical_xor']:
+ try:
+ uf = getattr(umath, f)
+ except AttributeError:
+ uf = getattr(fromnumeric, f)
+ mf = getattr(np.ma, f)
+ args = self.d[:uf.nin]
+ with np.errstate():
+ if f in f_invalid_ignore:
+ np.seterr(invalid='ignore')
+ if f in ['arctanh', 'log', 'log10']:
+ np.seterr(divide='ignore')
+ ur = uf(*args)
+ mr = mf(*args)
+ assert_(eq(ur.filled(0), mr.filled(0), f))
+ assert_(eqmask(ur.mask, mr.mask))
+
+ def test_reduce(self):
+ a = self.d[0]
+ assert_(not alltrue(a, axis=0))
+ assert_(sometrue(a, axis=0))
+ assert_equal(sum(a[:3], axis=0), 0)
+ assert_equal(product(a, axis=0), 0)
+
+ def test_minmax(self):
+ a = arange(1, 13).reshape(3, 4)
+ amask = masked_where(a < 5, a)
+ assert_equal(amask.max(), a.max())
+ assert_equal(amask.min(), 5)
+ assert_((amask.max(0) == a.max(0)).all())
+ assert_((amask.min(0) == [5, 6, 7, 8]).all())
+ assert_(amask.max(1)[0].mask)
+ assert_(amask.min(1)[0].mask)
+
+ def test_nonzero(self):
+ for t in "?bhilqpBHILQPfdgFDGO":
+ x = array([1, 0, 2, 0], mask=[0, 0, 1, 1])
+ assert_(eq(nonzero(x), [0]))
+
+
+class TestArrayMethods:
+
+ def setup_method(self):
+ x = np.array([8.375, 7.545, 8.828, 8.5, 1.757, 5.928,
+ 8.43, 7.78, 9.865, 5.878, 8.979, 4.732,
+ 3.012, 6.022, 5.095, 3.116, 5.238, 3.957,
+ 6.04, 9.63, 7.712, 3.382, 4.489, 6.479,
+ 7.189, 9.645, 5.395, 4.961, 9.894, 2.893,
+ 7.357, 9.828, 6.272, 3.758, 6.693, 0.993])
+ X = x.reshape(6, 6)
+ XX = x.reshape(3, 2, 2, 3)
+
+ m = np.array([0, 1, 0, 1, 0, 0,
+ 1, 0, 1, 1, 0, 1,
+ 0, 0, 0, 1, 0, 1,
+ 0, 0, 0, 1, 1, 1,
+ 1, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 1, 0])
+ mx = array(data=x, mask=m)
+ mX = array(data=X, mask=m.reshape(X.shape))
+ mXX = array(data=XX, mask=m.reshape(XX.shape))
+
+ self.d = (x, X, XX, m, mx, mX, mXX)
+
+ def test_trace(self):
+ (x, X, XX, m, mx, mX, mXX,) = self.d
+ mXdiag = mX.diagonal()
+ assert_equal(mX.trace(), mX.diagonal().compressed().sum())
+ assert_(eq(mX.trace(),
+ X.trace() - sum(mXdiag.mask * X.diagonal(),
+ axis=0)))
+
+ def test_clip(self):
+ (x, X, XX, m, mx, mX, mXX,) = self.d
+ clipped = mx.clip(2, 8)
+ assert_(eq(clipped.mask, mx.mask))
+ assert_(eq(clipped._data, x.clip(2, 8)))
+ assert_(eq(clipped._data, mx._data.clip(2, 8)))
+
+ def test_ptp(self):
+ (x, X, XX, m, mx, mX, mXX,) = self.d
+ (n, m) = X.shape
+ assert_equal(mx.ptp(), mx.compressed().ptp())
+ rows = np.zeros(n, np.float_)
+ cols = np.zeros(m, np.float_)
+ for k in range(m):
+ cols[k] = mX[:, k].compressed().ptp()
+ for k in range(n):
+ rows[k] = mX[k].compressed().ptp()
+ assert_(eq(mX.ptp(0), cols))
+ assert_(eq(mX.ptp(1), rows))
+
+ def test_swapaxes(self):
+ (x, X, XX, m, mx, mX, mXX,) = self.d
+ mXswapped = mX.swapaxes(0, 1)
+ assert_(eq(mXswapped[-1], mX[:, -1]))
+ mXXswapped = mXX.swapaxes(0, 2)
+ assert_equal(mXXswapped.shape, (2, 2, 3, 3))
+
+ def test_cumprod(self):
+ (x, X, XX, m, mx, mX, mXX,) = self.d
+ mXcp = mX.cumprod(0)
+ assert_(eq(mXcp._data, mX.filled(1).cumprod(0)))
+ mXcp = mX.cumprod(1)
+ assert_(eq(mXcp._data, mX.filled(1).cumprod(1)))
+
+ def test_cumsum(self):
+ (x, X, XX, m, mx, mX, mXX,) = self.d
+ mXcp = mX.cumsum(0)
+ assert_(eq(mXcp._data, mX.filled(0).cumsum(0)))
+ mXcp = mX.cumsum(1)
+ assert_(eq(mXcp._data, mX.filled(0).cumsum(1)))
+
+ def test_varstd(self):
+ (x, X, XX, m, mx, mX, mXX,) = self.d
+ assert_(eq(mX.var(axis=None), mX.compressed().var()))
+ assert_(eq(mX.std(axis=None), mX.compressed().std()))
+ assert_(eq(mXX.var(axis=3).shape, XX.var(axis=3).shape))
+ assert_(eq(mX.var().shape, X.var().shape))
+ (mXvar0, mXvar1) = (mX.var(axis=0), mX.var(axis=1))
+ for k in range(6):
+ assert_(eq(mXvar1[k], mX[k].compressed().var()))
+ assert_(eq(mXvar0[k], mX[:, k].compressed().var()))
+ assert_(eq(np.sqrt(mXvar0[k]),
+ mX[:, k].compressed().std()))
+
+
+def eqmask(m1, m2):
+ if m1 is nomask:
+ return m2 is nomask
+ if m2 is nomask:
+ return m1 is nomask
+ return (m1 == m2).all()
diff --git a/venv/lib/python3.9/site-packages/numpy/ma/tests/test_regression.py b/venv/lib/python3.9/site-packages/numpy/ma/tests/test_regression.py
new file mode 100644
index 00000000..cb3d0349
--- /dev/null
+++ b/venv/lib/python3.9/site-packages/numpy/ma/tests/test_regression.py
@@ -0,0 +1,91 @@
+import numpy as np
+from numpy.testing import (
+ assert_, assert_array_equal, assert_allclose, suppress_warnings
+ )
+
+
+class TestRegression:
+ def test_masked_array_create(self):
+ # Ticket #17
+ x = np.ma.masked_array([0, 1, 2, 3, 0, 4, 5, 6],
+ mask=[0, 0, 0, 1, 1, 1, 0, 0])
+ assert_array_equal(np.ma.nonzero(x), [[1, 2, 6, 7]])
+
+ def test_masked_array(self):
+ # Ticket #61
+ np.ma.array(1, mask=[1])
+
+ def test_mem_masked_where(self):
+ # Ticket #62
+ from numpy.ma import masked_where, MaskType
+ a = np.zeros((1, 1))
+ b = np.zeros(a.shape, MaskType)
+ c = masked_where(b, a)
+ a-c
+
+ def test_masked_array_multiply(self):
+ # Ticket #254
+ a = np.ma.zeros((4, 1))
+ a[2, 0] = np.ma.masked
+ b = np.zeros((4, 2))
+ a*b
+ b*a
+
+ def test_masked_array_repeat(self):
+ # Ticket #271
+ np.ma.array([1], mask=False).repeat(10)
+
+ def test_masked_array_repr_unicode(self):
+ # Ticket #1256
+ repr(np.ma.array("Unicode"))
+
+ def test_atleast_2d(self):
+ # Ticket #1559
+ a = np.ma.masked_array([0.0, 1.2, 3.5], mask=[False, True, False])
+ b = np.atleast_2d(a)
+ assert_(a.mask.ndim == 1)
+ assert_(b.mask.ndim == 2)
+
+ def test_set_fill_value_unicode_py3(self):
+ # Ticket #2733
+ a = np.ma.masked_array(['a', 'b', 'c'], mask=[1, 0, 0])
+ a.fill_value = 'X'
+ assert_(a.fill_value == 'X')
+
+ def test_var_sets_maskedarray_scalar(self):
+ # Issue gh-2757
+ a = np.ma.array(np.arange(5), mask=True)
+ mout = np.ma.array(-1, dtype=float)
+ a.var(out=mout)
+ assert_(mout._data == 0)
+
+ def test_ddof_corrcoef(self):
+ # See gh-3336
+ x = np.ma.masked_equal([1, 2, 3, 4, 5], 4)
+ y = np.array([2, 2.5, 3.1, 3, 5])
+ # this test can be removed after deprecation.
+ with suppress_warnings() as sup:
+ sup.filter(DeprecationWarning, "bias and ddof have no effect")
+ r0 = np.ma.corrcoef(x, y, ddof=0)
+ r1 = np.ma.corrcoef(x, y, ddof=1)
+ # ddof should not have an effect (it gets cancelled out)
+ assert_allclose(r0.data, r1.data)
+
+ def test_mask_not_backmangled(self):
+ # See gh-10314. Test case taken from gh-3140.
+ a = np.ma.MaskedArray([1., 2.], mask=[False, False])
+ assert_(a.mask.shape == (2,))
+ b = np.tile(a, (2, 1))
+ # Check that the above no longer changes a.shape to (1, 2)
+ assert_(a.mask.shape == (2,))
+ assert_(b.shape == (2, 2))
+ assert_(b.mask.shape == (2, 2))
+
+ def test_empty_list_on_structured(self):
+ # See gh-12464. Indexing with empty list should give empty result.
+ ma = np.ma.MaskedArray([(1, 1.), (2, 2.), (3, 3.)], dtype='i4,f4')
+ assert_array_equal(ma[[]], ma[:0])
+
+ def test_masked_array_tobytes_fortran(self):
+ ma = np.ma.arange(4).reshape((2,2))
+ assert_array_equal(ma.tobytes(order='F'), ma.T.tobytes())
diff --git a/venv/lib/python3.9/site-packages/numpy/ma/tests/test_subclassing.py b/venv/lib/python3.9/site-packages/numpy/ma/tests/test_subclassing.py
new file mode 100644
index 00000000..64c66eeb
--- /dev/null
+++ b/venv/lib/python3.9/site-packages/numpy/ma/tests/test_subclassing.py
@@ -0,0 +1,450 @@
+# pylint: disable-msg=W0611, W0612, W0511,R0201
+"""Tests suite for MaskedArray & subclassing.
+
+:author: Pierre Gerard-Marchant
+:contact: pierregm_at_uga_dot_edu
+:version: $Id: test_subclassing.py 3473 2007-10-29 15:18:13Z jarrod.millman $
+
+"""
+import numpy as np
+from numpy.lib.mixins import NDArrayOperatorsMixin
+from numpy.testing import assert_, assert_raises
+from numpy.ma.testutils import assert_equal
+from numpy.ma.core import (
+ array, arange, masked, MaskedArray, masked_array, log, add, hypot,
+ divide, asarray, asanyarray, nomask
+ )
+# from numpy.ma.core import (
+
+def assert_startswith(a, b):
+ # produces a better error message than assert_(a.startswith(b))
+ assert_equal(a[:len(b)], b)
+
+class SubArray(np.ndarray):
+ # Defines a generic np.ndarray subclass, that stores some metadata
+ # in the dictionary `info`.
+ def __new__(cls,arr,info={}):
+ x = np.asanyarray(arr).view(cls)
+ x.info = info.copy()
+ return x
+
+ def __array_finalize__(self, obj):
+ super().__array_finalize__(obj)
+ self.info = getattr(obj, 'info', {}).copy()
+ return
+
+ def __add__(self, other):
+ result = super().__add__(other)
+ result.info['added'] = result.info.get('added', 0) + 1
+ return result
+
+ def __iadd__(self, other):
+ result = super().__iadd__(other)
+ result.info['iadded'] = result.info.get('iadded', 0) + 1
+ return result
+
+
+subarray = SubArray
+
+
+class SubMaskedArray(MaskedArray):
+ """Pure subclass of MaskedArray, keeping some info on subclass."""
+ def __new__(cls, info=None, **kwargs):
+ obj = super().__new__(cls, **kwargs)
+ obj._optinfo['info'] = info
+ return obj
+
+
+class MSubArray(SubArray, MaskedArray):
+
+ def __new__(cls, data, info={}, mask=nomask):
+ subarr = SubArray(data, info)
+ _data = MaskedArray.__new__(cls, data=subarr, mask=mask)
+ _data.info = subarr.info
+ return _data
+
+ @property
+ def _series(self):
+ _view = self.view(MaskedArray)
+ _view._sharedmask = False
+ return _view
+
+msubarray = MSubArray
+
+
+# Also a subclass that overrides __str__, __repr__ and __setitem__, disallowing
+# setting to non-class values (and thus np.ma.core.masked_print_option)
+# and overrides __array_wrap__, updating the info dict, to check that this
+# doesn't get destroyed by MaskedArray._update_from. But this one also needs
+# its own iterator...
+class CSAIterator:
+ """
+ Flat iterator object that uses its own setter/getter
+ (works around ndarray.flat not propagating subclass setters/getters
+ see https://github.com/numpy/numpy/issues/4564)
+ roughly following MaskedIterator
+ """
+ def __init__(self, a):
+ self._original = a
+ self._dataiter = a.view(np.ndarray).flat
+
+ def __iter__(self):
+ return self
+
+ def __getitem__(self, indx):
+ out = self._dataiter.__getitem__(indx)
+ if not isinstance(out, np.ndarray):
+ out = out.__array__()
+ out = out.view(type(self._original))
+ return out
+
+ def __setitem__(self, index, value):
+ self._dataiter[index] = self._original._validate_input(value)
+
+ def __next__(self):
+ return next(self._dataiter).__array__().view(type(self._original))
+
+
+class ComplicatedSubArray(SubArray):
+
+ def __str__(self):
+ return f'myprefix {self.view(SubArray)} mypostfix'
+
+ def __repr__(self):
+ # Return a repr that does not start with 'name('
+ return f'<{self.__class__.__name__} {self}>'
+
+ def _validate_input(self, value):
+ if not isinstance(value, ComplicatedSubArray):
+ raise ValueError("Can only set to MySubArray values")
+ return value
+
+ def __setitem__(self, item, value):
+ # validation ensures direct assignment with ndarray or
+ # masked_print_option will fail
+ super().__setitem__(item, self._validate_input(value))
+
+ def __getitem__(self, item):
+ # ensure getter returns our own class also for scalars
+ value = super().__getitem__(item)
+ if not isinstance(value, np.ndarray): # scalar
+ value = value.__array__().view(ComplicatedSubArray)
+ return value
+
+ @property
+ def flat(self):
+ return CSAIterator(self)
+
+ @flat.setter
+ def flat(self, value):
+ y = self.ravel()
+ y[:] = value
+
+ def __array_wrap__(self, obj, context=None):
+ obj = super().__array_wrap__(obj, context)
+ if context is not None and context[0] is np.multiply:
+ obj.info['multiplied'] = obj.info.get('multiplied', 0) + 1
+
+ return obj
+
+
+class WrappedArray(NDArrayOperatorsMixin):
+ """
+ Wrapping a MaskedArray rather than subclassing to test that
+ ufunc deferrals are commutative.
+ See: https://github.com/numpy/numpy/issues/15200)
+ """
+ __array_priority__ = 20
+
+ def __init__(self, array, **attrs):
+ self._array = array
+ self.attrs = attrs
+
+ def __repr__(self):
+ return f"{self.__class__.__name__}(\n{self._array}\n{self.attrs}\n)"
+
+ def __array__(self):
+ return np.asarray(self._array)
+
+ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
+ if method == '__call__':
+ inputs = [arg._array if isinstance(arg, self.__class__) else arg
+ for arg in inputs]
+ return self.__class__(ufunc(*inputs, **kwargs), **self.attrs)
+ else:
+ return NotImplemented
+
+
+class TestSubclassing:
+ # Test suite for masked subclasses of ndarray.
+
+ def setup_method(self):
+ x = np.arange(5, dtype='float')
+ mx = msubarray(x, mask=[0, 1, 0, 0, 0])
+ self.data = (x, mx)
+
+ def test_data_subclassing(self):
+ # Tests whether the subclass is kept.
+ x = np.arange(5)
+ m = [0, 0, 1, 0, 0]
+ xsub = SubArray(x)
+ xmsub = masked_array(xsub, mask=m)
+ assert_(isinstance(xmsub, MaskedArray))
+ assert_equal(xmsub._data, xsub)
+ assert_(isinstance(xmsub._data, SubArray))
+
+ def test_maskedarray_subclassing(self):
+ # Tests subclassing MaskedArray
+ (x, mx) = self.data
+ assert_(isinstance(mx._data, subarray))
+
+ def test_masked_unary_operations(self):
+ # Tests masked_unary_operation
+ (x, mx) = self.data
+ with np.errstate(divide='ignore'):
+ assert_(isinstance(log(mx), msubarray))
+ assert_equal(log(x), np.log(x))
+
+ def test_masked_binary_operations(self):
+ # Tests masked_binary_operation
+ (x, mx) = self.data
+ # Result should be a msubarray
+ assert_(isinstance(add(mx, mx), msubarray))
+ assert_(isinstance(add(mx, x), msubarray))
+ # Result should work
+ assert_equal(add(mx, x), mx+x)
+ assert_(isinstance(add(mx, mx)._data, subarray))
+ assert_(isinstance(add.outer(mx, mx), msubarray))
+ assert_(isinstance(hypot(mx, mx), msubarray))
+ assert_(isinstance(hypot(mx, x), msubarray))
+
+ def test_masked_binary_operations2(self):
+ # Tests domained_masked_binary_operation
+ (x, mx) = self.data
+ xmx = masked_array(mx.data.__array__(), mask=mx.mask)
+ assert_(isinstance(divide(mx, mx), msubarray))
+ assert_(isinstance(divide(mx, x), msubarray))
+ assert_equal(divide(mx, mx), divide(xmx, xmx))
+
+ def test_attributepropagation(self):
+ x = array(arange(5), mask=[0]+[1]*4)
+ my = masked_array(subarray(x))
+ ym = msubarray(x)
+ #
+ z = (my+1)
+ assert_(isinstance(z, MaskedArray))
+ assert_(not isinstance(z, MSubArray))
+ assert_(isinstance(z._data, SubArray))
+ assert_equal(z._data.info, {})
+ #
+ z = (ym+1)
+ assert_(isinstance(z, MaskedArray))
+ assert_(isinstance(z, MSubArray))
+ assert_(isinstance(z._data, SubArray))
+ assert_(z._data.info['added'] > 0)
+ # Test that inplace methods from data get used (gh-4617)
+ ym += 1
+ assert_(isinstance(ym, MaskedArray))
+ assert_(isinstance(ym, MSubArray))
+ assert_(isinstance(ym._data, SubArray))
+ assert_(ym._data.info['iadded'] > 0)
+ #
+ ym._set_mask([1, 0, 0, 0, 1])
+ assert_equal(ym._mask, [1, 0, 0, 0, 1])
+ ym._series._set_mask([0, 0, 0, 0, 1])
+ assert_equal(ym._mask, [0, 0, 0, 0, 1])
+ #
+ xsub = subarray(x, info={'name':'x'})
+ mxsub = masked_array(xsub)
+ assert_(hasattr(mxsub, 'info'))
+ assert_equal(mxsub.info, xsub.info)
+
+ def test_subclasspreservation(self):
+ # Checks that masked_array(...,subok=True) preserves the class.
+ x = np.arange(5)
+ m = [0, 0, 1, 0, 0]
+ xinfo = [(i, j) for (i, j) in zip(x, m)]
+ xsub = MSubArray(x, mask=m, info={'xsub':xinfo})
+ #
+ mxsub = masked_array(xsub, subok=False)
+ assert_(not isinstance(mxsub, MSubArray))
+ assert_(isinstance(mxsub, MaskedArray))
+ assert_equal(mxsub._mask, m)
+ #
+ mxsub = asarray(xsub)
+ assert_(not isinstance(mxsub, MSubArray))
+ assert_(isinstance(mxsub, MaskedArray))
+ assert_equal(mxsub._mask, m)
+ #
+ mxsub = masked_array(xsub, subok=True)
+ assert_(isinstance(mxsub, MSubArray))
+ assert_equal(mxsub.info, xsub.info)
+ assert_equal(mxsub._mask, xsub._mask)
+ #
+ mxsub = asanyarray(xsub)
+ assert_(isinstance(mxsub, MSubArray))
+ assert_equal(mxsub.info, xsub.info)
+ assert_equal(mxsub._mask, m)
+
+ def test_subclass_items(self):
+ """test that getter and setter go via baseclass"""
+ x = np.arange(5)
+ xcsub = ComplicatedSubArray(x)
+ mxcsub = masked_array(xcsub, mask=[True, False, True, False, False])
+ # getter should return a ComplicatedSubArray, even for single item
+ # first check we wrote ComplicatedSubArray correctly
+ assert_(isinstance(xcsub[1], ComplicatedSubArray))
+ assert_(isinstance(xcsub[1,...], ComplicatedSubArray))
+ assert_(isinstance(xcsub[1:4], ComplicatedSubArray))
+
+ # now that it propagates inside the MaskedArray
+ assert_(isinstance(mxcsub[1], ComplicatedSubArray))
+ assert_(isinstance(mxcsub[1,...].data, ComplicatedSubArray))
+ assert_(mxcsub[0] is masked)
+ assert_(isinstance(mxcsub[0,...].data, ComplicatedSubArray))
+ assert_(isinstance(mxcsub[1:4].data, ComplicatedSubArray))
+
+ # also for flattened version (which goes via MaskedIterator)
+ assert_(isinstance(mxcsub.flat[1].data, ComplicatedSubArray))
+ assert_(mxcsub.flat[0] is masked)
+ assert_(isinstance(mxcsub.flat[1:4].base, ComplicatedSubArray))
+
+ # setter should only work with ComplicatedSubArray input
+ # first check we wrote ComplicatedSubArray correctly
+ assert_raises(ValueError, xcsub.__setitem__, 1, x[4])
+ # now that it propagates inside the MaskedArray
+ assert_raises(ValueError, mxcsub.__setitem__, 1, x[4])
+ assert_raises(ValueError, mxcsub.__setitem__, slice(1, 4), x[1:4])
+ mxcsub[1] = xcsub[4]
+ mxcsub[1:4] = xcsub[1:4]
+ # also for flattened version (which goes via MaskedIterator)
+ assert_raises(ValueError, mxcsub.flat.__setitem__, 1, x[4])
+ assert_raises(ValueError, mxcsub.flat.__setitem__, slice(1, 4), x[1:4])
+ mxcsub.flat[1] = xcsub[4]
+ mxcsub.flat[1:4] = xcsub[1:4]
+
+ def test_subclass_nomask_items(self):
+ x = np.arange(5)
+ xcsub = ComplicatedSubArray(x)
+ mxcsub_nomask = masked_array(xcsub)
+
+ assert_(isinstance(mxcsub_nomask[1,...].data, ComplicatedSubArray))
+ assert_(isinstance(mxcsub_nomask[0,...].data, ComplicatedSubArray))
+
+ assert_(isinstance(mxcsub_nomask[1], ComplicatedSubArray))
+ assert_(isinstance(mxcsub_nomask[0], ComplicatedSubArray))
+
+ 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])
+ assert_startswith(repr(mx), 'masked_array')
+ xsub = SubArray(x)
+ mxsub = masked_array(xsub, mask=[True, False, True, False, False])
+ assert_startswith(repr(mxsub),
+ f'masked_{SubArray.__name__}(data=[--, 1, --, 3, 4]')
+
+ 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])
+ assert_equal(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])
+ assert_equal(str(mxcsub), 'myprefix [-- 1 -- 3 4] mypostfix')
+
+ def test_pure_subclass_info_preservation(self):
+ # Test that ufuncs and methods conserve extra information consistently;
+ # see gh-7122.
+ arr1 = SubMaskedArray('test', data=[1,2,3,4,5,6])
+ arr2 = SubMaskedArray(data=[0,1,2,3,4,5])
+ diff1 = np.subtract(arr1, arr2)
+ assert_('info' in diff1._optinfo)
+ assert_(diff1._optinfo['info'] == 'test')
+ diff2 = arr1 - arr2
+ assert_('info' in diff2._optinfo)
+ assert_(diff2._optinfo['info'] == 'test')
+
+
+class ArrayNoInheritance:
+ """Quantity-like class that does not inherit from ndarray"""
+ def __init__(self, data, units):
+ self.magnitude = data
+ self.units = units
+
+ def __getattr__(self, attr):
+ return getattr(self.magnitude, attr)
+
+
+def test_array_no_inheritance():
+ data_masked = np.ma.array([1, 2, 3], mask=[True, False, True])
+ data_masked_units = ArrayNoInheritance(data_masked, 'meters')
+
+ # Get the masked representation of the Quantity-like class
+ new_array = np.ma.array(data_masked_units)
+ assert_equal(data_masked.data, new_array.data)
+ assert_equal(data_masked.mask, new_array.mask)
+ # Test sharing the mask
+ data_masked.mask = [True, False, False]
+ assert_equal(data_masked.mask, new_array.mask)
+ assert_(new_array.sharedmask)
+
+ # Get the masked representation of the Quantity-like class
+ new_array = np.ma.array(data_masked_units, copy=True)
+ assert_equal(data_masked.data, new_array.data)
+ assert_equal(data_masked.mask, new_array.mask)
+ # Test that the mask is not shared when copy=True
+ data_masked.mask = [True, False, True]
+ assert_equal([True, False, False], new_array.mask)
+ assert_(not new_array.sharedmask)
+
+ # Get the masked representation of the Quantity-like class
+ new_array = np.ma.array(data_masked_units, keep_mask=False)
+ assert_equal(data_masked.data, new_array.data)
+ # The change did not affect the original mask
+ assert_equal(data_masked.mask, [True, False, True])
+ # Test that the mask is False and not shared when keep_mask=False
+ assert_(not new_array.mask)
+ assert_(not new_array.sharedmask)
+
+
+class TestClassWrapping:
+ # Test suite for classes that wrap MaskedArrays
+
+ def setup_method(self):
+ m = np.ma.masked_array([1, 3, 5], mask=[False, True, False])
+ wm = WrappedArray(m)
+ self.data = (m, wm)
+
+ def test_masked_unary_operations(self):
+ # Tests masked_unary_operation
+ (m, wm) = self.data
+ with np.errstate(divide='ignore'):
+ assert_(isinstance(np.log(wm), WrappedArray))
+
+ def test_masked_binary_operations(self):
+ # Tests masked_binary_operation
+ (m, wm) = self.data
+ # Result should be a WrappedArray
+ assert_(isinstance(np.add(wm, wm), WrappedArray))
+ assert_(isinstance(np.add(m, wm), WrappedArray))
+ assert_(isinstance(np.add(wm, m), WrappedArray))
+ # add and '+' should call the same ufunc
+ assert_equal(np.add(m, wm), m + wm)
+ assert_(isinstance(np.hypot(m, wm), WrappedArray))
+ assert_(isinstance(np.hypot(wm, m), WrappedArray))
+ # Test domained binary operations
+ assert_(isinstance(np.divide(wm, m), WrappedArray))
+ assert_(isinstance(np.divide(m, wm), WrappedArray))
+ assert_equal(np.divide(wm, m) * m, np.divide(m, m) * wm)
+ # Test broadcasting
+ m2 = np.stack([m, m])
+ assert_(isinstance(np.divide(wm, m2), WrappedArray))
+ assert_(isinstance(np.divide(m2, wm), WrappedArray))
+ assert_equal(np.divide(m2, wm), np.divide(wm, m2))
diff --git a/venv/lib/python3.9/site-packages/numpy/ma/testutils.py b/venv/lib/python3.9/site-packages/numpy/ma/testutils.py
new file mode 100644
index 00000000..2dd479ab
--- /dev/null
+++ b/venv/lib/python3.9/site-packages/numpy/ma/testutils.py
@@ -0,0 +1,288 @@
+"""Miscellaneous functions for testing masked arrays and subclasses
+
+:author: Pierre Gerard-Marchant
+:contact: pierregm_at_uga_dot_edu
+:version: $Id: testutils.py 3529 2007-11-13 08:01:14Z jarrod.millman $
+
+"""
+import operator
+
+import numpy as np
+from numpy import ndarray, float_
+import numpy.core.umath as umath
+import numpy.testing
+from numpy.testing import (
+ assert_, assert_allclose, assert_array_almost_equal_nulp,
+ assert_raises, build_err_msg
+ )
+from .core import mask_or, getmask, masked_array, nomask, masked, filled
+
+__all__masked = [
+ 'almost', 'approx', 'assert_almost_equal', 'assert_array_almost_equal',
+ 'assert_array_approx_equal', 'assert_array_compare',
+ 'assert_array_equal', 'assert_array_less', 'assert_close',
+ 'assert_equal', 'assert_equal_records', 'assert_mask_equal',
+ 'assert_not_equal', 'fail_if_array_equal',
+ ]
+
+# Include some normal test functions to avoid breaking other projects who
+# have mistakenly included them from this file. SciPy is one. That is
+# unfortunate, as some of these functions are not intended to work with
+# masked arrays. But there was no way to tell before.
+from unittest import TestCase
+__some__from_testing = [
+ 'TestCase', 'assert_', 'assert_allclose', 'assert_array_almost_equal_nulp',
+ 'assert_raises'
+ ]
+
+__all__ = __all__masked + __some__from_testing
+
+
+def approx(a, b, fill_value=True, rtol=1e-5, atol=1e-8):
+ """
+ Returns true if all components of a and b are equal to given tolerances.
+
+ If fill_value is True, masked values considered equal. Otherwise,
+ masked values are considered unequal. The relative error rtol should
+ be positive and << 1.0 The absolute error atol comes into play for
+ those elements of b that are very small or zero; it says how small a
+ must be also.
+
+ """
+ m = mask_or(getmask(a), getmask(b))
+ d1 = filled(a)
+ d2 = filled(b)
+ if d1.dtype.char == "O" or d2.dtype.char == "O":
+ return np.equal(d1, d2).ravel()
+ x = filled(masked_array(d1, copy=False, mask=m), fill_value).astype(float_)
+ y = filled(masked_array(d2, copy=False, mask=m), 1).astype(float_)
+ d = np.less_equal(umath.absolute(x - y), atol + rtol * umath.absolute(y))
+ return d.ravel()
+
+
+def almost(a, b, decimal=6, fill_value=True):
+ """
+ Returns True if a and b are equal up to decimal places.
+
+ If fill_value is True, masked values considered equal. Otherwise,
+ masked values are considered unequal.
+
+ """
+ m = mask_or(getmask(a), getmask(b))
+ d1 = filled(a)
+ d2 = filled(b)
+ if d1.dtype.char == "O" or d2.dtype.char == "O":
+ return np.equal(d1, d2).ravel()
+ x = filled(masked_array(d1, copy=False, mask=m), fill_value).astype(float_)
+ y = filled(masked_array(d2, copy=False, mask=m), 1).astype(float_)
+ d = np.around(np.abs(x - y), decimal) <= 10.0 ** (-decimal)
+ return d.ravel()
+
+
+def _assert_equal_on_sequences(actual, desired, err_msg=''):
+ """
+ Asserts the equality of two non-array sequences.
+
+ """
+ assert_equal(len(actual), len(desired), err_msg)
+ for k in range(len(desired)):
+ assert_equal(actual[k], desired[k], f'item={k!r}\n{err_msg}')
+ return
+
+
+def assert_equal_records(a, b):
+ """
+ Asserts that two records are equal.
+
+ Pretty crude for now.
+
+ """
+ assert_equal(a.dtype, b.dtype)
+ for f in a.dtype.names:
+ (af, bf) = (operator.getitem(a, f), operator.getitem(b, f))
+ if not (af is masked) and not (bf is masked):
+ assert_equal(operator.getitem(a, f), operator.getitem(b, f))
+ return
+
+
+def assert_equal(actual, desired, err_msg=''):
+ """
+ Asserts that two items are equal.
+
+ """
+ # Case #1: dictionary .....
+ if isinstance(desired, dict):
+ if not isinstance(actual, dict):
+ raise AssertionError(repr(type(actual)))
+ assert_equal(len(actual), len(desired), err_msg)
+ for k, i in desired.items():
+ if k not in actual:
+ raise AssertionError(f"{k} not in {actual}")
+ assert_equal(actual[k], desired[k], f'key={k!r}\n{err_msg}')
+ return
+ # Case #2: lists .....
+ if isinstance(desired, (list, tuple)) and isinstance(actual, (list, tuple)):
+ return _assert_equal_on_sequences(actual, desired, err_msg='')
+ if not (isinstance(actual, ndarray) or isinstance(desired, ndarray)):
+ msg = build_err_msg([actual, desired], err_msg,)
+ if not desired == actual:
+ raise AssertionError(msg)
+ return
+ # Case #4. arrays or equivalent
+ if ((actual is masked) and not (desired is masked)) or \
+ ((desired is masked) and not (actual is masked)):
+ msg = build_err_msg([actual, desired],
+ err_msg, header='', names=('x', 'y'))
+ raise ValueError(msg)
+ actual = np.asanyarray(actual)
+ desired = np.asanyarray(desired)
+ (actual_dtype, desired_dtype) = (actual.dtype, desired.dtype)
+ if actual_dtype.char == "S" and desired_dtype.char == "S":
+ return _assert_equal_on_sequences(actual.tolist(),
+ desired.tolist(),
+ err_msg='')
+ return assert_array_equal(actual, desired, err_msg)
+
+
+def fail_if_equal(actual, desired, err_msg='',):
+ """
+ Raises an assertion error if two items are equal.
+
+ """
+ if isinstance(desired, dict):
+ if not isinstance(actual, dict):
+ raise AssertionError(repr(type(actual)))
+ fail_if_equal(len(actual), len(desired), err_msg)
+ for k, i in desired.items():
+ if k not in actual:
+ raise AssertionError(repr(k))
+ fail_if_equal(actual[k], desired[k], f'key={k!r}\n{err_msg}')
+ return
+ if isinstance(desired, (list, tuple)) and isinstance(actual, (list, tuple)):
+ fail_if_equal(len(actual), len(desired), err_msg)
+ for k in range(len(desired)):
+ fail_if_equal(actual[k], desired[k], f'item={k!r}\n{err_msg}')
+ return
+ if isinstance(actual, np.ndarray) or isinstance(desired, np.ndarray):
+ return fail_if_array_equal(actual, desired, err_msg)
+ msg = build_err_msg([actual, desired], err_msg)
+ if not desired != actual:
+ raise AssertionError(msg)
+
+
+assert_not_equal = fail_if_equal
+
+
+def assert_almost_equal(actual, desired, decimal=7, err_msg='', verbose=True):
+ """
+ Asserts that two items are almost equal.
+
+ The test is equivalent to abs(desired-actual) < 0.5 * 10**(-decimal).
+
+ """
+ if isinstance(actual, np.ndarray) or isinstance(desired, np.ndarray):
+ return assert_array_almost_equal(actual, desired, decimal=decimal,
+ err_msg=err_msg, verbose=verbose)
+ msg = build_err_msg([actual, desired],
+ err_msg=err_msg, verbose=verbose)
+ if not round(abs(desired - actual), decimal) == 0:
+ raise AssertionError(msg)
+
+
+assert_close = assert_almost_equal
+
+
+def assert_array_compare(comparison, x, y, err_msg='', verbose=True, header='',
+ fill_value=True):
+ """
+ Asserts that comparison between two masked arrays is satisfied.
+
+ The comparison is elementwise.
+
+ """
+ # Allocate a common mask and refill
+ m = mask_or(getmask(x), getmask(y))
+ x = masked_array(x, copy=False, mask=m, keep_mask=False, subok=False)
+ y = masked_array(y, copy=False, mask=m, keep_mask=False, subok=False)
+ if ((x is masked) and not (y is masked)) or \
+ ((y is masked) and not (x is masked)):
+ msg = build_err_msg([x, y], err_msg=err_msg, verbose=verbose,
+ header=header, names=('x', 'y'))
+ raise ValueError(msg)
+ # OK, now run the basic tests on filled versions
+ return np.testing.assert_array_compare(comparison,
+ x.filled(fill_value),
+ y.filled(fill_value),
+ err_msg=err_msg,
+ verbose=verbose, header=header)
+
+
+def assert_array_equal(x, y, err_msg='', verbose=True):
+ """
+ Checks the elementwise equality of two masked arrays.
+
+ """
+ assert_array_compare(operator.__eq__, x, y,
+ err_msg=err_msg, verbose=verbose,
+ header='Arrays are not equal')
+
+
+def fail_if_array_equal(x, y, err_msg='', verbose=True):
+ """
+ Raises an assertion error if two masked arrays are not equal elementwise.
+
+ """
+ def compare(x, y):
+ return (not np.alltrue(approx(x, y)))
+ assert_array_compare(compare, x, y, err_msg=err_msg, verbose=verbose,
+ header='Arrays are not equal')
+
+
+def assert_array_approx_equal(x, y, decimal=6, err_msg='', verbose=True):
+ """
+ Checks the equality of two masked arrays, up to given number odecimals.
+
+ The equality is checked elementwise.
+
+ """
+ def compare(x, y):
+ "Returns the result of the loose comparison between x and y)."
+ return approx(x, y, rtol=10. ** -decimal)
+ assert_array_compare(compare, x, y, err_msg=err_msg, verbose=verbose,
+ header='Arrays are not almost equal')
+
+
+def assert_array_almost_equal(x, y, decimal=6, err_msg='', verbose=True):
+ """
+ Checks the equality of two masked arrays, up to given number odecimals.
+
+ The equality is checked elementwise.
+
+ """
+ def compare(x, y):
+ "Returns the result of the loose comparison between x and y)."
+ return almost(x, y, decimal)
+ assert_array_compare(compare, x, y, err_msg=err_msg, verbose=verbose,
+ header='Arrays are not almost equal')
+
+
+def assert_array_less(x, y, err_msg='', verbose=True):
+ """
+ Checks that x is smaller than y elementwise.
+
+ """
+ assert_array_compare(operator.__lt__, x, y,
+ err_msg=err_msg, verbose=verbose,
+ header='Arrays are not less-ordered')
+
+
+def assert_mask_equal(m1, m2, err_msg=''):
+ """
+ Asserts the equality of two masks.
+
+ """
+ if m1 is nomask:
+ assert_(m2 is nomask)
+ if m2 is nomask:
+ assert_(m1 is nomask)
+ assert_array_equal(m1, m2, err_msg=err_msg)
diff --git a/venv/lib/python3.9/site-packages/numpy/ma/timer_comparison.py b/venv/lib/python3.9/site-packages/numpy/ma/timer_comparison.py
new file mode 100644
index 00000000..9eb1a23c
--- /dev/null
+++ b/venv/lib/python3.9/site-packages/numpy/ma/timer_comparison.py
@@ -0,0 +1,443 @@
+import timeit
+from functools import reduce
+
+import numpy as np
+from numpy import float_
+import numpy.core.fromnumeric as fromnumeric
+
+from numpy.testing import build_err_msg
+
+
+pi = np.pi
+
+class ModuleTester:
+ def __init__(self, module):
+ self.module = module
+ self.allequal = module.allequal
+ self.arange = module.arange
+ self.array = module.array
+ self.concatenate = module.concatenate
+ self.count = module.count
+ self.equal = module.equal
+ self.filled = module.filled
+ self.getmask = module.getmask
+ self.getmaskarray = module.getmaskarray
+ self.id = id
+ self.inner = module.inner
+ self.make_mask = module.make_mask
+ self.masked = module.masked
+ self.masked_array = module.masked_array
+ self.masked_values = module.masked_values
+ self.mask_or = module.mask_or
+ self.nomask = module.nomask
+ self.ones = module.ones
+ self.outer = module.outer
+ self.repeat = module.repeat
+ self.resize = module.resize
+ self.sort = module.sort
+ self.take = module.take
+ self.transpose = module.transpose
+ self.zeros = module.zeros
+ self.MaskType = module.MaskType
+ try:
+ self.umath = module.umath
+ except AttributeError:
+ self.umath = module.core.umath
+ self.testnames = []
+
+ def assert_array_compare(self, comparison, x, y, err_msg='', header='',
+ fill_value=True):
+ """
+ Assert that a comparison of two masked arrays is satisfied elementwise.
+
+ """
+ xf = self.filled(x)
+ yf = self.filled(y)
+ m = self.mask_or(self.getmask(x), self.getmask(y))
+
+ x = self.filled(self.masked_array(xf, mask=m), fill_value)
+ y = self.filled(self.masked_array(yf, mask=m), fill_value)
+ if (x.dtype.char != "O"):
+ x = x.astype(float_)
+ if isinstance(x, np.ndarray) and x.size > 1:
+ x[np.isnan(x)] = 0
+ elif np.isnan(x):
+ x = 0
+ if (y.dtype.char != "O"):
+ y = y.astype(float_)
+ if isinstance(y, np.ndarray) and y.size > 1:
+ y[np.isnan(y)] = 0
+ elif np.isnan(y):
+ y = 0
+ try:
+ cond = (x.shape == () or y.shape == ()) or x.shape == y.shape
+ if not cond:
+ msg = build_err_msg([x, y],
+ err_msg
+ + f'\n(shapes {x.shape}, {y.shape} mismatch)',
+ header=header,
+ names=('x', 'y'))
+ assert cond, msg
+ val = comparison(x, y)
+ if m is not self.nomask and fill_value:
+ val = self.masked_array(val, mask=m)
+ if isinstance(val, bool):
+ cond = val
+ reduced = [0]
+ else:
+ reduced = val.ravel()
+ cond = reduced.all()
+ reduced = reduced.tolist()
+ if not cond:
+ match = 100-100.0*reduced.count(1)/len(reduced)
+ msg = build_err_msg([x, y],
+ err_msg
+ + '\n(mismatch %s%%)' % (match,),
+ header=header,
+ names=('x', 'y'))
+ assert cond, msg
+ except ValueError as e:
+ msg = build_err_msg([x, y], err_msg, header=header, names=('x', 'y'))
+ raise ValueError(msg) from e
+
+ def assert_array_equal(self, x, y, err_msg=''):
+ """
+ Checks the elementwise equality of two masked arrays.
+
+ """
+ self.assert_array_compare(self.equal, x, y, err_msg=err_msg,
+ header='Arrays are not equal')
+
+ @np.errstate(all='ignore')
+ def test_0(self):
+ """
+ Tests creation
+
+ """
+ x = np.array([1., 1., 1., -2., pi/2.0, 4., 5., -10., 10., 1., 2., 3.])
+ m = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
+ xm = self.masked_array(x, mask=m)
+ xm[0]
+
+ @np.errstate(all='ignore')
+ def test_1(self):
+ """
+ Tests creation
+
+ """
+ x = np.array([1., 1., 1., -2., pi/2.0, 4., 5., -10., 10., 1., 2., 3.])
+ y = np.array([5., 0., 3., 2., -1., -4., 0., -10., 10., 1., 0., 3.])
+ m1 = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
+ m2 = [0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1]
+ xm = self.masked_array(x, mask=m1)
+ ym = self.masked_array(y, mask=m2)
+ xf = np.where(m1, 1.e+20, x)
+ xm.set_fill_value(1.e+20)
+
+ assert((xm-ym).filled(0).any())
+ s = x.shape
+ assert(xm.size == reduce(lambda x, y:x*y, s))
+ assert(self.count(xm) == len(m1) - reduce(lambda x, y:x+y, m1))
+
+ for s in [(4, 3), (6, 2)]:
+ x.shape = s
+ y.shape = s
+ xm.shape = s
+ ym.shape = s
+ xf.shape = s
+ assert(self.count(xm) == len(m1) - reduce(lambda x, y:x+y, m1))
+
+ @np.errstate(all='ignore')
+ def test_2(self):
+ """
+ Tests conversions and indexing.
+
+ """
+ x1 = np.array([1, 2, 4, 3])
+ x2 = self.array(x1, mask=[1, 0, 0, 0])
+ x3 = self.array(x1, mask=[0, 1, 0, 1])
+ x4 = self.array(x1)
+ # test conversion to strings, no errors
+ str(x2)
+ repr(x2)
+ # tests of indexing
+ assert type(x2[1]) is type(x1[1])
+ assert x1[1] == x2[1]
+ x1[2] = 9
+ x2[2] = 9
+ self.assert_array_equal(x1, x2)
+ x1[1:3] = 99
+ x2[1:3] = 99
+ x2[1] = self.masked
+ x2[1:3] = self.masked
+ x2[:] = x1
+ x2[1] = self.masked
+ x3[:] = self.masked_array([1, 2, 3, 4], [0, 1, 1, 0])
+ x4[:] = self.masked_array([1, 2, 3, 4], [0, 1, 1, 0])
+ x1 = np.arange(5)*1.0
+ x2 = self.masked_values(x1, 3.0)
+ x1 = self.array([1, 'hello', 2, 3], object)
+ x2 = np.array([1, 'hello', 2, 3], object)
+ # check that no error occurs.
+ x1[1]
+ x2[1]
+ assert x1[1:1].shape == (0,)
+ # Tests copy-size
+ n = [0, 0, 1, 0, 0]
+ m = self.make_mask(n)
+ m2 = self.make_mask(m)
+ assert(m is m2)
+ m3 = self.make_mask(m, copy=1)
+ assert(m is not m3)
+
+ @np.errstate(all='ignore')
+ def test_3(self):
+ """
+ Tests resize/repeat
+
+ """
+ x4 = self.arange(4)
+ x4[2] = self.masked
+ y4 = self.resize(x4, (8,))
+ assert self.allequal(self.concatenate([x4, x4]), y4)
+ assert self.allequal(self.getmask(y4), [0, 0, 1, 0, 0, 0, 1, 0])
+ y5 = self.repeat(x4, (2, 2, 2, 2), axis=0)
+ self.assert_array_equal(y5, [0, 0, 1, 1, 2, 2, 3, 3])
+ y6 = self.repeat(x4, 2, axis=0)
+ assert self.allequal(y5, y6)
+ y7 = x4.repeat((2, 2, 2, 2), axis=0)
+ assert self.allequal(y5, y7)
+ y8 = x4.repeat(2, 0)
+ assert self.allequal(y5, y8)
+
+ @np.errstate(all='ignore')
+ def test_4(self):
+ """
+ Test of take, transpose, inner, outer products.
+
+ """
+ x = self.arange(24)
+ y = np.arange(24)
+ x[5:6] = self.masked
+ x = x.reshape(2, 3, 4)
+ y = y.reshape(2, 3, 4)
+ assert self.allequal(np.transpose(y, (2, 0, 1)), self.transpose(x, (2, 0, 1)))
+ assert self.allequal(np.take(y, (2, 0, 1), 1), self.take(x, (2, 0, 1), 1))
+ assert self.allequal(np.inner(self.filled(x, 0), self.filled(y, 0)),
+ self.inner(x, y))
+ assert self.allequal(np.outer(self.filled(x, 0), self.filled(y, 0)),
+ self.outer(x, y))
+ y = self.array(['abc', 1, 'def', 2, 3], object)
+ y[2] = self.masked
+ t = self.take(y, [0, 3, 4])
+ assert t[0] == 'abc'
+ assert t[1] == 2
+ assert t[2] == 3
+
+ @np.errstate(all='ignore')
+ def test_5(self):
+ """
+ Tests inplace w/ scalar
+
+ """
+ x = self.arange(10)
+ y = self.arange(10)
+ xm = self.arange(10)
+ xm[2] = self.masked
+ x += 1
+ assert self.allequal(x, y+1)
+ xm += 1
+ assert self.allequal(xm, y+1)
+
+ x = self.arange(10)
+ xm = self.arange(10)
+ xm[2] = self.masked
+ x -= 1
+ assert self.allequal(x, y-1)
+ xm -= 1
+ assert self.allequal(xm, y-1)
+
+ x = self.arange(10)*1.0
+ xm = self.arange(10)*1.0
+ xm[2] = self.masked
+ x *= 2.0
+ assert self.allequal(x, y*2)
+ xm *= 2.0
+ assert self.allequal(xm, y*2)
+
+ x = self.arange(10)*2
+ xm = self.arange(10)*2
+ xm[2] = self.masked
+ x /= 2
+ assert self.allequal(x, y)
+ xm /= 2
+ assert self.allequal(xm, y)
+
+ x = self.arange(10)*1.0
+ xm = self.arange(10)*1.0
+ xm[2] = self.masked
+ x /= 2.0
+ assert self.allequal(x, y/2.0)
+ xm /= self.arange(10)
+ self.assert_array_equal(xm, self.ones((10,)))
+
+ x = self.arange(10).astype(float_)
+ xm = self.arange(10)
+ xm[2] = self.masked
+ x += 1.
+ assert self.allequal(x, y + 1.)
+
+ @np.errstate(all='ignore')
+ def test_6(self):
+ """
+ Tests inplace w/ array
+
+ """
+ x = self.arange(10, dtype=float_)
+ y = self.arange(10)
+ xm = self.arange(10, dtype=float_)
+ xm[2] = self.masked
+ m = xm.mask
+ a = self.arange(10, dtype=float_)
+ a[-1] = self.masked
+ x += a
+ xm += a
+ assert self.allequal(x, y+a)
+ assert self.allequal(xm, y+a)
+ assert self.allequal(xm.mask, self.mask_or(m, a.mask))
+
+ x = self.arange(10, dtype=float_)
+ xm = self.arange(10, dtype=float_)
+ xm[2] = self.masked
+ m = xm.mask
+ a = self.arange(10, dtype=float_)
+ a[-1] = self.masked
+ x -= a
+ xm -= a
+ assert self.allequal(x, y-a)
+ assert self.allequal(xm, y-a)
+ assert self.allequal(xm.mask, self.mask_or(m, a.mask))
+
+ x = self.arange(10, dtype=float_)
+ xm = self.arange(10, dtype=float_)
+ xm[2] = self.masked
+ m = xm.mask
+ a = self.arange(10, dtype=float_)
+ a[-1] = self.masked
+ x *= a
+ xm *= a
+ assert self.allequal(x, y*a)
+ assert self.allequal(xm, y*a)
+ assert self.allequal(xm.mask, self.mask_or(m, a.mask))
+
+ x = self.arange(10, dtype=float_)
+ xm = self.arange(10, dtype=float_)
+ xm[2] = self.masked
+ m = xm.mask
+ a = self.arange(10, dtype=float_)
+ a[-1] = self.masked
+ x /= a
+ xm /= a
+
+ @np.errstate(all='ignore')
+ def test_7(self):
+ "Tests ufunc"
+ d = (self.array([1.0, 0, -1, pi/2]*2, mask=[0, 1]+[0]*6),
+ self.array([1.0, 0, -1, pi/2]*2, mask=[1, 0]+[0]*6),)
+ for f in ['sqrt', 'log', 'log10', 'exp', 'conjugate',
+# 'sin', 'cos', 'tan',
+# 'arcsin', 'arccos', 'arctan',
+# 'sinh', 'cosh', 'tanh',
+# 'arcsinh',
+# 'arccosh',
+# 'arctanh',
+# 'absolute', 'fabs', 'negative',
+# # 'nonzero', 'around',
+# 'floor', 'ceil',
+# # 'sometrue', 'alltrue',
+# 'logical_not',
+# 'add', 'subtract', 'multiply',
+# 'divide', 'true_divide', 'floor_divide',
+# 'remainder', 'fmod', 'hypot', 'arctan2',
+# 'equal', 'not_equal', 'less_equal', 'greater_equal',
+# 'less', 'greater',
+# 'logical_and', 'logical_or', 'logical_xor',
+ ]:
+ try:
+ uf = getattr(self.umath, f)
+ except AttributeError:
+ uf = getattr(fromnumeric, f)
+ mf = getattr(self.module, f)
+ args = d[:uf.nin]
+ ur = uf(*args)
+ mr = mf(*args)
+ self.assert_array_equal(ur.filled(0), mr.filled(0), f)
+ self.assert_array_equal(ur._mask, mr._mask)
+
+ @np.errstate(all='ignore')
+ def test_99(self):
+ # test average
+ ott = self.array([0., 1., 2., 3.], mask=[1, 0, 0, 0])
+ self.assert_array_equal(2.0, self.average(ott, axis=0))
+ self.assert_array_equal(2.0, self.average(ott, weights=[1., 1., 2., 1.]))
+ result, wts = self.average(ott, weights=[1., 1., 2., 1.], returned=1)
+ self.assert_array_equal(2.0, result)
+ assert(wts == 4.0)
+ ott[:] = self.masked
+ assert(self.average(ott, axis=0) is self.masked)
+ ott = self.array([0., 1., 2., 3.], mask=[1, 0, 0, 0])
+ ott = ott.reshape(2, 2)
+ ott[:, 1] = self.masked
+ self.assert_array_equal(self.average(ott, axis=0), [2.0, 0.0])
+ assert(self.average(ott, axis=1)[0] is self.masked)
+ self.assert_array_equal([2., 0.], self.average(ott, axis=0))
+ result, wts = self.average(ott, axis=0, returned=1)
+ self.assert_array_equal(wts, [1., 0.])
+ w1 = [0, 1, 1, 1, 1, 0]
+ w2 = [[0, 1, 1, 1, 1, 0], [1, 0, 0, 0, 0, 1]]
+ x = self.arange(6)
+ self.assert_array_equal(self.average(x, axis=0), 2.5)
+ self.assert_array_equal(self.average(x, axis=0, weights=w1), 2.5)
+ y = self.array([self.arange(6), 2.0*self.arange(6)])
+ self.assert_array_equal(self.average(y, None), np.add.reduce(np.arange(6))*3./12.)
+ self.assert_array_equal(self.average(y, axis=0), np.arange(6) * 3./2.)
+ self.assert_array_equal(self.average(y, axis=1), [self.average(x, axis=0), self.average(x, axis=0) * 2.0])
+ self.assert_array_equal(self.average(y, None, weights=w2), 20./6.)
+ self.assert_array_equal(self.average(y, axis=0, weights=w2), [0., 1., 2., 3., 4., 10.])
+ self.assert_array_equal(self.average(y, axis=1), [self.average(x, axis=0), self.average(x, axis=0) * 2.0])
+ m1 = self.zeros(6)
+ m2 = [0, 0, 1, 1, 0, 0]
+ m3 = [[0, 0, 1, 1, 0, 0], [0, 1, 1, 1, 1, 0]]
+ m4 = self.ones(6)
+ m5 = [0, 1, 1, 1, 1, 1]
+ self.assert_array_equal(self.average(self.masked_array(x, m1), axis=0), 2.5)
+ self.assert_array_equal(self.average(self.masked_array(x, m2), axis=0), 2.5)
+ self.assert_array_equal(self.average(self.masked_array(x, m5), axis=0), 0.0)
+ self.assert_array_equal(self.count(self.average(self.masked_array(x, m4), axis=0)), 0)
+ z = self.masked_array(y, m3)
+ self.assert_array_equal(self.average(z, None), 20./6.)
+ self.assert_array_equal(self.average(z, axis=0), [0., 1., 99., 99., 4.0, 7.5])
+ self.assert_array_equal(self.average(z, axis=1), [2.5, 5.0])
+ self.assert_array_equal(self.average(z, axis=0, weights=w2), [0., 1., 99., 99., 4.0, 10.0])
+
+ @np.errstate(all='ignore')
+ def test_A(self):
+ x = self.arange(24)
+ x[5:6] = self.masked
+ x = x.reshape(2, 3, 4)
+
+
+if __name__ == '__main__':
+ setup_base = ("from __main__ import ModuleTester \n"
+ "import numpy\n"
+ "tester = ModuleTester(module)\n")
+ setup_cur = "import numpy.ma.core as module\n" + setup_base
+ (nrepeat, nloop) = (10, 10)
+
+ for i in range(1, 8):
+ func = 'tester.test_%i()' % i
+ cur = timeit.Timer(func, setup_cur).repeat(nrepeat, nloop*10)
+ cur = np.sort(cur)
+ print("#%i" % i + 50*'.')
+ print(eval("ModuleTester.test_%i.__doc__" % i))
+ print(f'core_current : {cur[0]:.3f} - {cur[1]:.3f}')