1"""

2 numpy.ma : a package to handle missing or invalid values.

3

4 This package was initially written for numarray by Paul F. Dubois

5 at Lawrence Livermore National Laboratory.

6 In 2006, the package was completely rewritten by Pierre Gerard-Marchant

7(University of Georgia) to make the MaskedArray class a subclass of ndarray,

8 and to improve support of structured arrays.

9

10

11 Copyright 1999, 2000, 2001 Regents of the University of California.

12 Released for unlimited redistribution.

13

14* Adapted for numpy_core 2005 by Travis Oliphant and (mainly) Paul Dubois.

15* Subclassing of the base `ndarray` 2006 by Pierre Gerard-Marchant

16 (pgmdevlist_AT_gmail_DOT_com)

17* Improvements suggested by Reggie Dugard (reggie_AT_merfinllc_DOT_com)

18

19.. moduleauthor:: Pierre Gerard-Marchant

20

21"""

22# pylint: disable-msg=E1002

23 import builtins

24 import inspect

25 import operator

26 import warnings

27 import textwrap

28 import re

29 from functools import reduce

30

31 import numpy as np

32 import numpy.core.umath as umath

33 import numpy.core.numerictypes as ntypes

34 from numpy.core import multiarray as mu

35 from numpy import ndarray, amax, amin, iscomplexobj, bool_, _NoValue

36 from numpy import array as narray

37 from numpy.lib.function_base import angle

38 from numpy.compat import (

39 getargspec, formatargspec, long, unicode, bytes

40 )

41 from numpy import expand_dims

42 from numpy.core.numeric import normalize_axis_tuple

43

44

45__all__ = [

46 'MAError', 'MaskError', 'MaskType', 'MaskedArray', 'abs', 'absolute',

47 'add', 'all', 'allclose', 'allequal', 'alltrue', 'amax', 'amin',

48 'angle', 'anom', 'anomalies', 'any', 'append', 'arange', 'arccos',

49 'arccosh', 'arcsin', 'arcsinh', 'arctan', 'arctan2', 'arctanh',

50 'argmax', 'argmin', 'argsort', 'around', 'array', 'asanyarray',

51 'asarray', 'bitwise_and', 'bitwise_or', 'bitwise_xor', 'bool_', 'ceil',

52 'choose', 'clip', 'common_fill_value', 'compress', 'compressed',

53 'concatenate', 'conjugate', 'convolve', 'copy', 'correlate', 'cos', 'cosh',

54 'count', 'cumprod', 'cumsum', 'default_fill_value', 'diag', 'diagonal',

55 'diff', 'divide', 'empty', 'empty_like', 'equal', 'exp',

56 'expand_dims', 'fabs', 'filled', 'fix_invalid', 'flatten_mask',

57 'flatten_structured_array', 'floor', 'floor_divide', 'fmod',

58 'frombuffer', 'fromflex', 'fromfunction', 'getdata', 'getmask',

59 'getmaskarray', 'greater', 'greater_equal', 'harden_mask', 'hypot',

60 'identity', 'ids', 'indices', 'inner', 'innerproduct', 'isMA',

61 'isMaskedArray', 'is_mask', 'is_masked', 'isarray', 'left_shift',

62 'less', 'less_equal', 'log', 'log10', 'log2',

63 'logical_and', 'logical_not', 'logical_or', 'logical_xor', 'make_mask',

64 'make_mask_descr', 'make_mask_none', 'mask_or', 'masked',

65 'masked_array', 'masked_equal', 'masked_greater',

66 'masked_greater_equal', 'masked_inside', 'masked_invalid',

67 'masked_less', 'masked_less_equal', 'masked_not_equal',

68 'masked_object', 'masked_outside', 'masked_print_option',

69 'masked_singleton', 'masked_values', 'masked_where', 'max', 'maximum',

70 'maximum_fill_value', 'mean', 'min', 'minimum', 'minimum_fill_value',

71 'mod', 'multiply', 'mvoid', 'ndim', 'negative', 'nomask', 'nonzero',

72 'not_equal', 'ones', 'ones_like', 'outer', 'outerproduct', 'power', 'prod',

73 'product', 'ptp', 'put', 'putmask', 'ravel', 'remainder',

74 'repeat', 'reshape', 'resize', 'right_shift', 'round', 'round_',

75 'set_fill_value', 'shape', 'sin', 'sinh', 'size', 'soften_mask',

76 'sometrue', 'sort', 'sqrt', 'squeeze', 'std', 'subtract', 'sum',

77 'swapaxes', 'take', 'tan', 'tanh', 'trace', 'transpose', 'true_divide',

78 'var', 'where', 'zeros', 'zeros_like',

79 ]

80

81 MaskType = np.bool_

82 nomask = MaskType(0)

83

84 class MaskedArrayFutureWarning(FutureWarning):

85 pass

86

87 def _deprecate_argsort_axis(arr):

88 """

89 Adjust the axis passed to argsort, warning if necessary

90

91 Parameters

92 ----------

93 arr

94 The array which argsort was called on

95

96 np.ma.argsort has a long-term bug where the default of the axis argument

97 is wrong (gh-8701), which now must be kept for backwards compatibility.

98 Thankfully, this only makes a difference when arrays are 2- or more-

99 dimensional, so we only need a warning then.

100 """

101 if arr.ndim <= 1:

102 # no warning needed - but switch to -1 anyway, to avoid surprising

103 # subclasses, which are more likely to implement scalar axes.

104 return -1

105 else:

106 # 2017-04-11, Numpy 1.13.0, gh-8701: warn on axis default

107 warnings.warn(

108 "In the future the default for argsort will be axis=-1, not the "

109 "current None, to match its documentation and np.argsort. "

110 "Explicitly pass -1 or None to silence this warning.",

111 MaskedArrayFutureWarning, stacklevel=3)

112 return None

113

114

115 def doc_note(initialdoc, note):

116 """

117 Adds a Notes section to an existing docstring.

118

119 """

120 if initialdoc is None:

121 return

122 if note is None:

123 return initialdoc

124

125 notesplit = re.split(r'\n\s*?Notes\n\s*?-----', inspect.cleandoc(initialdoc))

126 notedoc = "\n\nNotes\n-----\n%s\n" % inspect.cleandoc(note)

127

128 return ''.join(notesplit[:1] + [notedoc] + notesplit[1:])

129

130

131 def get_object_signature(obj):

132 """

133 Get the signature from obj

134

135 """

136 try:

137 sig = formatargspec(*getargspec(obj))

138 except TypeError:

139 sig = ''

140 return sig

141

142

143###############################################################################

144# Exceptions #

145###############################################################################

146

147

148 class MAError(Exception):

149 """

150 Class for masked array related errors.

151

152 """

153 pass

154

155

156 class MaskError(MAError):

157 """

158 Class for mask related errors.

159

160 """

161 pass

162

163

164###############################################################################

165# Filling options #

166###############################################################################

167

168

169# b: boolean - c: complex - f: floats - i: integer - O: object - S: string

170 default_filler = {'b': True,

171 'c': 1.e20 + 0.0j,

172 'f': 1.e20,

173 'i': 999999,

174 'O': '?',

175 'S': b'N/A',

176 'u': 999999,

177 'V': b'???',

178 'U': 'N/A'

179 }

180

181# Add datetime64 and timedelta64 types

182 for v in ["Y", "M", "W", "D", "h", "m", "s", "ms", "us", "ns", "ps",

183 "fs", "as"]:

184 default_filler["M8[" + v + "]"] = np.datetime64("NaT", v)

185 default_filler["m8[" + v + "]"] = np.timedelta64("NaT", v)

186

187 float_types_list = [np.half, np.single, np.double, np.longdouble,

188 np.csingle, np.cdouble, np.clongdouble]

189 max_filler = ntypes._minvals

190 max_filler.update([(k, -np.inf) for k in float_types_list[:4]])

191 max_filler.update([(k, complex(-np.inf, -np.inf)) for k in float_types_list[-3:]])

192

193 min_filler = ntypes._maxvals

194 min_filler.update([(k, +np.inf) for k in float_types_list[:4]])

195 min_filler.update([(k, complex(+np.inf, +np.inf)) for k in float_types_list[-3:]])

196

197 del float_types_list

198

199 def _recursive_fill_value(dtype, f):

200 """

201 Recursively produce a fill value for `dtype`, calling f on scalar dtypes

202 """

203 if dtype.names is not None:

204 # We wrap into `array` here, which ensures we use NumPy cast rules

205 # for integer casts, this allows the use of 99999 as a fill value

206 # for int8.

207 # TODO: This is probably a mess, but should best preserve behavior?

208 vals = tuple(

209 np.array(_recursive_fill_value(dtype[name], f))

210 for name in dtype.names)

211 return np.array(vals, dtype=dtype)[()] # decay to void scalar from 0d

212 elif dtype.subdtype:

213 subtype, shape = dtype.subdtype

214 subval = _recursive_fill_value(subtype, f)

215 return np.full(shape, subval)

216 else:

217 return f(dtype)

218

219

220 def _get_dtype_of(obj):

221 """ Convert the argument for *_fill_value into a dtype """

222 if isinstance(obj, np.dtype):

223 return obj

224 elif hasattr(obj, 'dtype'):

225 return obj.dtype

226 else:

227 return np.asanyarray(obj).dtype

228

229

230 def default_fill_value(obj):

231 """

232 Return the default fill value for the argument object.

233

234 The default filling value depends on the datatype of the input

235 array or the type of the input scalar:

236

237 ======== ========

238 datatype default

239 ======== ========

240 bool True

241 int 999999

242 float 1.e20

243 complex 1.e20+0j

244 object '?'

245 string 'N/A'

246 ======== ========

247

248 For structured types, a structured scalar is returned, with each field the

249 default fill value for its type.

250

251 For subarray types, the fill value is an array of the same size containing

252 the default scalar fill value.

253

254 Parameters

255 ----------

256 obj : ndarray, dtype or scalar

257 The array data-type or scalar for which the default fill value

258 is returned.

259

260 Returns

261 -------

262 fill_value : scalar

263 The default fill value.

264

265 Examples

266 --------

267 >>> np.ma.default_fill_value(1)

268 999999

269 >>> np.ma.default_fill_value(np.array([1.1, 2., np.pi]))

270 1e+20

271 >>> np.ma.default_fill_value(np.dtype(complex))

272 (1e+20+0j)

273

274 """

275 def _scalar_fill_value(dtype):

276 if dtype.kind in 'Mm':

277 return default_filler.get(dtype.str[1:], '?')

278 else:

279 return default_filler.get(dtype.kind, '?')

280

281 dtype = _get_dtype_of(obj)

282 return _recursive_fill_value(dtype, _scalar_fill_value)

283

284

285 def _extremum_fill_value(obj, extremum, extremum_name):

286

287 def _scalar_fill_value(dtype):

288 try:

289 return extremum[dtype]

290 except KeyError as e:

291 raise TypeError(

292 f"Unsuitable type {dtype} for calculating {extremum_name}."

293 ) from None

294

295 dtype = _get_dtype_of(obj)

296 return _recursive_fill_value(dtype, _scalar_fill_value)

297

298

299 def minimum_fill_value(obj):

300 """

301 Return the maximum value that can be represented by the dtype of an object.

302

303 This function is useful for calculating a fill value suitable for

304 taking the minimum of an array with a given dtype.

305

306 Parameters

307 ----------

308 obj : ndarray, dtype or scalar

309 An object that can be queried for it's numeric type.

310

311 Returns

312 -------

313 val : scalar

314 The maximum representable value.

315

316 Raises

317 ------

318 TypeError

319 If `obj` isn't a suitable numeric type.

320

321 See Also

322 --------

323 maximum_fill_value : The inverse function.

324 set_fill_value : Set the filling value of a masked array.

325 MaskedArray.fill_value : Return current fill value.

326

327 Examples

328 --------

329 >>> import numpy.ma as ma

330 >>> a = np.int8()

331 >>> ma.minimum_fill_value(a)

332 127

333 >>> a = np.int32()

334 >>> ma.minimum_fill_value(a)

335 2147483647

336

337 An array of numeric data can also be passed.

338

339 >>> a = np.array([1, 2, 3], dtype=np.int8)

340 >>> ma.minimum_fill_value(a)

341 127

342 >>> a = np.array([1, 2, 3], dtype=np.float32)

343 >>> ma.minimum_fill_value(a)

344 inf

345

346 """

347 return _extremum_fill_value(obj, min_filler, "minimum")

348

349

350 def maximum_fill_value(obj):

351 """

352 Return the minimum value that can be represented by the dtype of an object.

353

354 This function is useful for calculating a fill value suitable for

355 taking the maximum of an array with a given dtype.

356

357 Parameters

358 ----------

359 obj : ndarray, dtype or scalar

360 An object that can be queried for it's numeric type.

361

362 Returns

363 -------

364 val : scalar

365 The minimum representable value.

366

367 Raises

368 ------

369 TypeError

370 If `obj` isn't a suitable numeric type.

371

372 See Also

373 --------

374 minimum_fill_value : The inverse function.

375 set_fill_value : Set the filling value of a masked array.

376 MaskedArray.fill_value : Return current fill value.

377

378 Examples

379 --------

380 >>> import numpy.ma as ma

381 >>> a = np.int8()

382 >>> ma.maximum_fill_value(a)

383 -128

384 >>> a = np.int32()

385 >>> ma.maximum_fill_value(a)

386 -2147483648

387

388 An array of numeric data can also be passed.

389

390 >>> a = np.array([1, 2, 3], dtype=np.int8)

391 >>> ma.maximum_fill_value(a)

392 -128

393 >>> a = np.array([1, 2, 3], dtype=np.float32)

394 >>> ma.maximum_fill_value(a)

395 -inf

396

397 """

398 return _extremum_fill_value(obj, max_filler, "maximum")

399

400

401 def _recursive_set_fill_value(fillvalue, dt):

402 """

403 Create a fill value for a structured dtype.

404

405 Parameters

406 ----------

407 fillvalue : scalar or array_like

408 Scalar or array representing the fill value. If it is of shorter

409 length than the number of fields in dt, it will be resized.

410 dt : dtype

411 The structured dtype for which to create the fill value.

412

413 Returns

414 -------

415 val : tuple

416 A tuple of values corresponding to the structured fill value.

417

418 """

419 fillvalue = np.resize(fillvalue, len(dt.names))

420 output_value = []

421 for (fval, name) in zip(fillvalue, dt.names):

422 cdtype = dt[name]

423 if cdtype.subdtype:

424 cdtype = cdtype.subdtype[0]

425

426 if cdtype.names is not None:

427 output_value.append(tuple(_recursive_set_fill_value(fval, cdtype)))

428 else:

429 output_value.append(np.array(fval, dtype=cdtype).item())

430 return tuple(output_value)

431

432

433 def _check_fill_value(fill_value, ndtype):

434 """

435 Private function validating the given `fill_value` for the given dtype.

436

437 If fill_value is None, it is set to the default corresponding to the dtype.

438

439 If fill_value is not None, its value is forced to the given dtype.

440

441 The result is always a 0d array.

442

443 """

444 ndtype = np.dtype(ndtype)

445 if fill_value is None:

446 fill_value = default_fill_value(ndtype)

447 elif ndtype.names is not None:

448 if isinstance(fill_value, (ndarray, np.void)):

449 try:

450 fill_value = np.array(fill_value, copy=False, dtype=ndtype)

451 except ValueError as e:

452 err_msg = "Unable to transform %s to dtype %s"

453 raise ValueError(err_msg % (fill_value, ndtype)) from e

454 else:

455 fill_value = np.asarray(fill_value, dtype=object)

456 fill_value = np.array(_recursive_set_fill_value(fill_value, ndtype),

457 dtype=ndtype)

458 else:

459 if isinstance(fill_value, str) and (ndtype.char not in 'OSVU'):

460 # Note this check doesn't work if fill_value is not a scalar

461 err_msg = "Cannot set fill value of string with array of dtype %s"

462 raise TypeError(err_msg % ndtype)

463 else:

464 # In case we want to convert 1e20 to int.

465 # Also in case of converting string arrays.

466 try:

467 fill_value = np.array(fill_value, copy=False, dtype=ndtype)

468 except (OverflowError, ValueError) as e:

469 # Raise TypeError instead of OverflowError or ValueError.

470 # OverflowError is seldom used, and the real problem here is

471 # that the passed fill_value is not compatible with the ndtype.

472 err_msg = "Cannot convert fill_value %s to dtype %s"

473 raise TypeError(err_msg % (fill_value, ndtype)) from e

474 return np.array(fill_value)

475

476

477 def set_fill_value(a, fill_value):

478 """

479 Set the filling value of a, if a is a masked array.

480

481 This function changes the fill value of the masked array `a` in place.

482 If `a` is not a masked array, the function returns silently, without

483 doing anything.

484

485 Parameters

486 ----------

487 a : array_like

488 Input array.

489 fill_value : dtype

490 Filling value. A consistency test is performed to make sure

491 the value is compatible with the dtype of `a`.

492

493 Returns

494 -------

495 None

496 Nothing returned by this function.

497

498 See Also

499 --------

500 maximum_fill_value : Return the default fill value for a dtype.

501 MaskedArray.fill_value : Return current fill value.

502 MaskedArray.set_fill_value : Equivalent method.

503

504 Examples

505 --------

506 >>> import numpy.ma as ma

507 >>> a = np.arange(5)

508 >>> a

509 array([0, 1, 2, 3, 4])

510 >>> a = ma.masked_where(a < 3, a)

511 >>> a

512 masked_array(data=[--, --, --, 3, 4],

513 mask=[ True, True, True, False, False],

514 fill_value=999999)

515 >>> ma.set_fill_value(a, -999)

516 >>> a

517 masked_array(data=[--, --, --, 3, 4],

518 mask=[ True, True, True, False, False],

519 fill_value=-999)

520

521 Nothing happens if `a` is not a masked array.

522

523 >>> a = list(range(5))

524 >>> a

525 [0, 1, 2, 3, 4]

526 >>> ma.set_fill_value(a, 100)

527 >>> a

528 [0, 1, 2, 3, 4]

529 >>> a = np.arange(5)

530 >>> a

531 array([0, 1, 2, 3, 4])

532 >>> ma.set_fill_value(a, 100)

533 >>> a

534 array([0, 1, 2, 3, 4])

535

536 """

537 if isinstance(a, MaskedArray):

538 a.set_fill_value(fill_value)

539 return

540

541

542 def get_fill_value(a):

543 """

544 Return the filling value of a, if any. Otherwise, returns the

545 default filling value for that type.

546

547 """

548 if isinstance(a, MaskedArray):

549 result = a.fill_value

550 else:

551 result = default_fill_value(a)

552 return result

553

554

555 def common_fill_value(a, b):

556 """

557 Return the common filling value of two masked arrays, if any.

558

559 If ``a.fill_value == b.fill_value``, return the fill value,

560 otherwise return None.

561

562 Parameters

563 ----------

564 a, b : MaskedArray

565 The masked arrays for which to compare fill values.

566

567 Returns

568 -------

569 fill_value : scalar or None

570 The common fill value, or None.

571

572 Examples

573 --------

574 >>> x = np.ma.array([0, 1.], fill_value=3)

575 >>> y = np.ma.array([0, 1.], fill_value=3)

576 >>> np.ma.common_fill_value(x, y)

577 3.0

578

579 """

580 t1 = get_fill_value(a)

581 t2 = get_fill_value(b)

582 if t1 == t2:

583 return t1

584 return None

585

586

587 def filled(a, fill_value=None):

588 """

589 Return input as an array with masked data replaced by a fill value.

590

591 If `a` is not a `MaskedArray`, `a` itself is returned.

592 If `a` is a `MaskedArray` and `fill_value` is None, `fill_value` is set to

593 ``a.fill_value``.

594

595 Parameters

596 ----------

597 a : MaskedArray or array_like

598 An input object.

599 fill_value : array_like, optional.

600 Can be scalar or non-scalar. If non-scalar, the

601 resulting filled array should be broadcastable

602 over input array. Default is None.

603

604 Returns

605 -------

606 a : ndarray

607 The filled array.

608

609 See Also

610 --------

611 compressed

612

613 Examples

614 --------

615 >>> x = np.ma.array(np.arange(9).reshape(3, 3), mask=[[1, 0, 0],

616 ... [1, 0, 0],

617 ... [0, 0, 0]])

618 >>> x.filled()

619 array([[999999, 1, 2],

620 [999999, 4, 5],

621 [ 6, 7, 8]])

622 >>> x.filled(fill_value=333)

623 array([[333, 1, 2],

624 [333, 4, 5],

625 [ 6, 7, 8]])

626 >>> x.filled(fill_value=np.arange(3))

627 array([[0, 1, 2],

628 [0, 4, 5],

629 [6, 7, 8]])

630

631 """

632 if hasattr(a, 'filled'):

633 return a.filled(fill_value)

634

635 elif isinstance(a, ndarray):

636 # Should we check for contiguity ? and a.flags['CONTIGUOUS']:

637 return a

638 elif isinstance(a, dict):

639 return np.array(a, 'O')

640 else:

641 return np.array(a)

642

643

644 def get_masked_subclass(*arrays):

645 """

646 Return the youngest subclass of MaskedArray from a list of (masked) arrays.

647

648 In case of siblings, the first listed takes over.

649

650 """

651 if len(arrays) == 1:

652 arr = arrays[0]

653 if isinstance(arr, MaskedArray):

654 rcls = type(arr)

655 else:

656 rcls = MaskedArray

657 else:

658 arrcls = [type(a) for a in arrays]

659 rcls = arrcls[0]

660 if not issubclass(rcls, MaskedArray):

661 rcls = MaskedArray

662 for cls in arrcls[1:]:

663 if issubclass(cls, rcls):

664 rcls = cls

665 # Don't return MaskedConstant as result: revert to MaskedArray

666 if rcls.__name__ == 'MaskedConstant':

667 return MaskedArray

668 return rcls

669

670

671 def getdata(a, subok=True):

672 """

673 Return the data of a masked array as an ndarray.

674

675 Return the data of `a` (if any) as an ndarray if `a` is a ``MaskedArray``,

676 else return `a` as a ndarray or subclass (depending on `subok`) if not.

677

678 Parameters

679 ----------

680 a : array_like

681 Input ``MaskedArray``, alternatively a ndarray or a subclass thereof.

682 subok : bool

683 Whether to force the output to be a `pure` ndarray (False) or to

684 return a subclass of ndarray if appropriate (True, default).

685

686 See Also

687 --------

688 getmask : Return the mask of a masked array, or nomask.

689 getmaskarray : Return the mask of a masked array, or full array of False.

690

691 Examples

692 --------

693 >>> import numpy.ma as ma

694 >>> a = ma.masked_equal([[1,2],[3,4]], 2)

695 >>> a

696 masked_array(

697 data=[[1, --],

698 [3, 4]],

699 mask=[[False, True],

700 [False, False]],

701 fill_value=2)

702 >>> ma.getdata(a)

703 array([[1, 2],

704 [3, 4]])

705

706 Equivalently use the ``MaskedArray`` `data` attribute.

707

708 >>> a.data

709 array([[1, 2],

710 [3, 4]])

711

712 """

713 try:

714 data = a._data

715 except AttributeError:

716 data = np.array(a, copy=False, subok=subok)

717 if not subok:

718 return data.view(ndarray)

719 return data

720

721

722 get_data = getdata

723

724

725 def fix_invalid(a, mask=nomask, copy=True, fill_value=None):

726 """

727 Return input with invalid data masked and replaced by a fill value.

728

729 Invalid data means values of `nan`, `inf`, etc.

730

731 Parameters

732 ----------

733 a : array_like

734 Input array, a (subclass of) ndarray.

735 mask : sequence, optional

736 Mask. Must be convertible to an array of booleans with the same

737 shape as `data`. True indicates a masked (i.e. invalid) data.

738 copy : bool, optional

739 Whether to use a copy of `a` (True) or to fix `a` in place (False).

740 Default is True.

741 fill_value : scalar, optional

742 Value used for fixing invalid data. Default is None, in which case

743 the ``a.fill_value`` is used.

744

745 Returns

746 -------

747 b : MaskedArray

748 The input array with invalid entries fixed.

749

750 Notes

751 -----

752 A copy is performed by default.

753

754 Examples

755 --------

756 >>> x = np.ma.array([1., -1, np.nan, np.inf], mask=[1] + [0]*3)

757 >>> x

758 masked_array(data=[--, -1.0, nan, inf],

759 mask=[ True, False, False, False],

760 fill_value=1e+20)

761 >>> np.ma.fix_invalid(x)

762 masked_array(data=[--, -1.0, --, --],

763 mask=[ True, False, True, True],

764 fill_value=1e+20)

765

766 >>> fixed = np.ma.fix_invalid(x)

767 >>> fixed.data

768 array([ 1.e+00, -1.e+00, 1.e+20, 1.e+20])

769 >>> x.data

770 array([ 1., -1., nan, inf])

771

772 """

773 a = masked_array(a, copy=copy, mask=mask, subok=True)

774 invalid = np.logical_not(np.isfinite(a._data))

775 if not invalid.any():

776 return a

777 a._mask |= invalid

778 if fill_value is None:

779 fill_value = a.fill_value

780 a._data[invalid] = fill_value

781 return a

782

783 def is_string_or_list_of_strings(val):

784 return (isinstance(val, str) or

785 (isinstance(val, list) and val and

786 builtins.all(isinstance(s, str) for s in val)))

787

788###############################################################################

789# Ufuncs #

790###############################################################################

791

792

793 ufunc_domain = {}

794 ufunc_fills = {}

795

796

797 class _DomainCheckInterval:

798 """

799 Define a valid interval, so that :

800

801 ``domain_check_interval(a,b)(x) == True`` where

802 ``x < a`` or ``x > b``.

803

804 """

805

806 def __init__(self, a, b):

807 "domain_check_interval(a,b)(x) = true where x < a or y > b"

808 if a > b:

809 (a, b) = (b, a)

810 self.a = a

811 self.b = b

812

813 def __call__(self, x):

814 "Execute the call behavior."

815 # nans at masked positions cause RuntimeWarnings, even though

816 # they are masked. To avoid this we suppress warnings.

817 with np.errstate(invalid='ignore'):

818 return umath.logical_or(umath.greater(x, self.b),

819 umath.less(x, self.a))

820

821

822 class _DomainTan:

823 """

824 Define a valid interval for the `tan` function, so that:

825

826 ``domain_tan(eps) = True`` where ``abs(cos(x)) < eps``

827

828 """

829

830 def __init__(self, eps):

831 "domain_tan(eps) = true where abs(cos(x)) < eps)"

832 self.eps = eps

833

834 def __call__(self, x):

835 "Executes the call behavior."

836 with np.errstate(invalid='ignore'):

837 return umath.less(umath.absolute(umath.cos(x)), self.eps)

838

839

840 class _DomainSafeDivide:

841 """

842 Define a domain for safe division.

843

844 """

845

846 def __init__(self, tolerance=None):

847 self.tolerance = tolerance

848

849 def __call__(self, a, b):

850 # Delay the selection of the tolerance to here in order to reduce numpy

851 # import times. The calculation of these parameters is a substantial

852 # component of numpy's import time.

853 if self.tolerance is None:

854 self.tolerance = np.finfo(float).tiny

855 # don't call ma ufuncs from __array_wrap__ which would fail for scalars

856 a, b = np.asarray(a), np.asarray(b)

857 with np.errstate(invalid='ignore'):

858 return umath.absolute(a) * self.tolerance >= umath.absolute(b)

859

860

861 class _DomainGreater:

862 """

863 DomainGreater(v)(x) is True where x <= v.

864

865 """

866

867 def __init__(self, critical_value):

868 "DomainGreater(v)(x) = true where x <= v"

869 self.critical_value = critical_value

870

871 def __call__(self, x):

872 "Executes the call behavior."

873 with np.errstate(invalid='ignore'):

874 return umath.less_equal(x, self.critical_value)

875

876

877 class _DomainGreaterEqual:

878 """

879 DomainGreaterEqual(v)(x) is True where x < v.

880

881 """

882

883 def __init__(self, critical_value):

884 "DomainGreaterEqual(v)(x) = true where x < v"

885 self.critical_value = critical_value

886

887 def __call__(self, x):

888 "Executes the call behavior."

889 with np.errstate(invalid='ignore'):

890 return umath.less(x, self.critical_value)

891

892

893 class _MaskedUFunc:

894 def __init__(self, ufunc):

895 self.f = ufunc

896 self.__doc__ = ufunc.__doc__

897 self.__name__ = ufunc.__name__

898

899 def __str__(self):

900 return f"Masked version of {self.f}"

901

902

903 class _MaskedUnaryOperation(_MaskedUFunc):

904 """

905 Defines masked version of unary operations, where invalid values are

906 pre-masked.

907

908 Parameters

909 ----------

910 mufunc : callable

911 The function for which to define a masked version. Made available

912 as ``_MaskedUnaryOperation.f``.

913 fill : scalar, optional

914 Filling value, default is 0.

915 domain : class instance

916 Domain for the function. Should be one of the ``_Domain*``

917 classes. Default is None.

918

919 """

920

921 def __init__(self, mufunc, fill=0, domain=None):

922 super().__init__(mufunc)

923 self.fill = fill

924 self.domain = domain

925 ufunc_domain[mufunc] = domain

926 ufunc_fills[mufunc] = fill

927

928 def __call__(self, a, *args, **kwargs):

929 """

930 Execute the call behavior.

931

932 """

933 d = getdata(a)

934 # Deal with domain

935 if self.domain is not None:

936 # Case 1.1. : Domained function

937 # nans at masked positions cause RuntimeWarnings, even though

938 # they are masked. To avoid this we suppress warnings.

939 with np.errstate(divide='ignore', invalid='ignore'):

940 result = self.f(d, *args, **kwargs)

941 # Make a mask

942 m = ~umath.isfinite(result)

943 m |= self.domain(d)

944 m |= getmask(a)

945 else:

946 # Case 1.2. : Function without a domain

947 # Get the result and the mask

948 with np.errstate(divide='ignore', invalid='ignore'):

949 result = self.f(d, *args, **kwargs)

950 m = getmask(a)

951

952 if not result.ndim:

953 # Case 2.1. : The result is scalarscalar

954 if m:

955 return masked

956 return result

957

958 if m is not nomask:

959 # Case 2.2. The result is an array

960 # We need to fill the invalid data back w/ the input Now,

961 # that's plain silly: in C, we would just skip the element and

962 # keep the original, but we do have to do it that way in Python

963

964 # In case result has a lower dtype than the inputs (as in

965 # equal)

966 try:

967 np.copyto(result, d, where=m)

968 except TypeError:

969 pass

970 # Transform to

971 masked_result = result.view(get_masked_subclass(a))

972 masked_result._mask = m

973 masked_result._update_from(a)

974 return masked_result

975

976

977 class _MaskedBinaryOperation(_MaskedUFunc):

978 """

979 Define masked version of binary operations, where invalid

980 values are pre-masked.

981

982 Parameters

983 ----------

984 mbfunc : function

985 The function for which to define a masked version. Made available

986 as ``_MaskedBinaryOperation.f``.

987 domain : class instance

988 Default domain for the function. Should be one of the ``_Domain*``

989 classes. Default is None.

990 fillx : scalar, optional

991 Filling value for the first argument, default is 0.

992 filly : scalar, optional

993 Filling value for the second argument, default is 0.

994

995 """

996

997 def __init__(self, mbfunc, fillx=0, filly=0):

998 """

999 abfunc(fillx, filly) must be defined.

1000

1001 abfunc(x, filly) = x for all x to enable reduce.

1002

1003 """

1004 super().__init__(mbfunc)

1005 self.fillx = fillx

1006 self.filly = filly

1007 ufunc_domain[mbfunc] = None

1008 ufunc_fills[mbfunc] = (fillx, filly)

1009

1010 def __call__(self, a, b, *args, **kwargs):

1011 """

1012 Execute the call behavior.

1013

1014 """

1015 # Get the data, as ndarray

1016 (da, db) = (getdata(a), getdata(b))

1017 # Get the result

1018 with np.errstate():

1019 np.seterr(divide='ignore', invalid='ignore')

1020 result = self.f(da, db, *args, **kwargs)

1021 # Get the mask for the result

1022 (ma, mb) = (getmask(a), getmask(b))

1023 if ma is nomask:

1024 if mb is nomask:

1025 m = nomask

1026 else:

1027 m = umath.logical_or(getmaskarray(a), mb)

1028 elif mb is nomask:

1029 m = umath.logical_or(ma, getmaskarray(b))

1030 else:

1031 m = umath.logical_or(ma, mb)

1032

1033 # Case 1. : scalar

1034 if not result.ndim:

1035 if m:

1036 return masked

1037 return result

1038

1039 # Case 2. : array

1040 # Revert result to da where masked

1041 if m is not nomask and m.any():

1042 # any errors, just abort; impossible to guarantee masked values

1043 try:

1044 np.copyto(result, da, casting='unsafe', where=m)

1045 except Exception:

1046 pass

1047

1048 # Transforms to a (subclass of) MaskedArray

1049 masked_result = result.view(get_masked_subclass(a, b))

1050 masked_result._mask = m

1051 if isinstance(a, MaskedArray):

1052 masked_result._update_from(a)

1053 elif isinstance(b, MaskedArray):

1054 masked_result._update_from(b)

1055 return masked_result

1056

1057 def reduce(self, target, axis=0, dtype=None):

1058 """

1059 Reduce `target` along the given `axis`.

1060

1061 """

1062 tclass = get_masked_subclass(target)

1063 m = getmask(target)

1064 t = filled(target, self.filly)

1065 if t.shape == ():

1066 t = t.reshape(1)

1067 if m is not nomask:

1068 m = make_mask(m, copy=True)

1069 m.shape = (1,)

1070

1071 if m is nomask:

1072 tr = self.f.reduce(t, axis)

1073 mr = nomask

1074 else:

1075 tr = self.f.reduce(t, axis, dtype=dtype)

1076 mr = umath.logical_and.reduce(m, axis)

1077

1078 if not tr.shape:

1079 if mr:

1080 return masked

1081 else:

1082 return tr

1083 masked_tr = tr.view(tclass)

1084 masked_tr._mask = mr

1085 return masked_tr

1086

1087 def outer(self, a, b):

1088 """

1089 Return the function applied to the outer product of a and b.

1090

1091 """

1092 (da, db) = (getdata(a), getdata(b))

1093 d = self.f.outer(da, db)

1094 ma = getmask(a)

1095 mb = getmask(b)

1096 if ma is nomask and mb is nomask:

1097 m = nomask

1098 else:

1099 ma = getmaskarray(a)

1100 mb = getmaskarray(b)

1101 m = umath.logical_or.outer(ma, mb)

1102 if (not m.ndim) and m:

1103 return masked

1104 if m is not nomask:

1105 np.copyto(d, da, where=m)

1106 if not d.shape:

1107 return d

1108 masked_d = d.view(get_masked_subclass(a, b))

1109 masked_d._mask = m

1110 return masked_d

1111

1112 def accumulate(self, target, axis=0):

1113 """Accumulate `target` along `axis` after filling with y fill

1114 value.

1115

1116 """

1117 tclass = get_masked_subclass(target)

1118 t = filled(target, self.filly)

1119 result = self.f.accumulate(t, axis)

1120 masked_result = result.view(tclass)

1121 return masked_result

1122

1123

1124

1125 class _DomainedBinaryOperation(_MaskedUFunc):

1126 """

1127 Define binary operations that have a domain, like divide.

1128

1129 They have no reduce, outer or accumulate.

1130

1131 Parameters

1132 ----------

1133 mbfunc : function

1134 The function for which to define a masked version. Made available

1135 as ``_DomainedBinaryOperation.f``.

1136 domain : class instance

1137 Default domain for the function. Should be one of the ``_Domain*``

1138 classes.

1139 fillx : scalar, optional

1140 Filling value for the first argument, default is 0.

1141 filly : scalar, optional

1142 Filling value for the second argument, default is 0.

1143

1144 """

1145

1146 def __init__(self, dbfunc, domain, fillx=0, filly=0):

1147 """abfunc(fillx, filly) must be defined.

1148 abfunc(x, filly) = x for all x to enable reduce.

1149 """

1150 super().__init__(dbfunc)

1151 self.domain = domain

1152 self.fillx = fillx

1153 self.filly = filly

1154 ufunc_domain[dbfunc] = domain

1155 ufunc_fills[dbfunc] = (fillx, filly)

1156

1157 def __call__(self, a, b, *args, **kwargs):

1158 "Execute the call behavior."

1159 # Get the data

1160 (da, db) = (getdata(a), getdata(b))

1161 # Get the result

1162 with np.errstate(divide='ignore', invalid='ignore'):

1163 result = self.f(da, db, *args, **kwargs)

1164 # Get the mask as a combination of the source masks and invalid

1165 m = ~umath.isfinite(result)

1166 m |= getmask(a)

1167 m |= getmask(b)

1168 # Apply the domain

1169 domain = ufunc_domain.get(self.f, None)

1170 if domain is not None:

1171 m |= domain(da, db)

1172 # Take care of the scalar case first

1173 if not m.ndim:

1174 if m:

1175 return masked

1176 else:

1177 return result

1178 # When the mask is True, put back da if possible

1179 # any errors, just abort; impossible to guarantee masked values

1180 try:

1181 np.copyto(result, 0, casting='unsafe', where=m)

1182 # avoid using "*" since this may be overlaid

1183 masked_da = umath.multiply(m, da)

1184 # only add back if it can be cast safely

1185 if np.can_cast(masked_da.dtype, result.dtype, casting='safe'):

1186 result += masked_da

1187 except Exception:

1188 pass

1189

1190 # Transforms to a (subclass of) MaskedArray

1191 masked_result = result.view(get_masked_subclass(a, b))

1192 masked_result._mask = m

1193 if isinstance(a, MaskedArray):

1194 masked_result._update_from(a)

1195 elif isinstance(b, MaskedArray):

1196 masked_result._update_from(b)

1197 return masked_result

1198

1199

1200# Unary ufuncs

1201 exp = _MaskedUnaryOperation(umath.exp)

1202 conjugate = _MaskedUnaryOperation(umath.conjugate)

1203 sin = _MaskedUnaryOperation(umath.sin)

1204 cos = _MaskedUnaryOperation(umath.cos)

1205 arctan = _MaskedUnaryOperation(umath.arctan)

1206 arcsinh = _MaskedUnaryOperation(umath.arcsinh)

1207 sinh = _MaskedUnaryOperation(umath.sinh)

1208 cosh = _MaskedUnaryOperation(umath.cosh)

1209 tanh = _MaskedUnaryOperation(umath.tanh)

1210 abs = absolute = _MaskedUnaryOperation(umath.absolute)

1211 angle = _MaskedUnaryOperation(angle) # from numpy.lib.function_base

1212 fabs = _MaskedUnaryOperation(umath.fabs)

1213 negative = _MaskedUnaryOperation(umath.negative)

1214 floor = _MaskedUnaryOperation(umath.floor)

1215 ceil = _MaskedUnaryOperation(umath.ceil)

1216 around = _MaskedUnaryOperation(np.round_)

1217 logical_not = _MaskedUnaryOperation(umath.logical_not)

1218

1219# Domained unary ufuncs

1220 sqrt = _MaskedUnaryOperation(umath.sqrt, 0.0,

1221 _DomainGreaterEqual(0.0))

1222 log = _MaskedUnaryOperation(umath.log, 1.0,

1223 _DomainGreater(0.0))

1224 log2 = _MaskedUnaryOperation(umath.log2, 1.0,

1225 _DomainGreater(0.0))

1226 log10 = _MaskedUnaryOperation(umath.log10, 1.0,

1227 _DomainGreater(0.0))

1228 tan = _MaskedUnaryOperation(umath.tan, 0.0,

1229 _DomainTan(1e-35))

1230 arcsin = _MaskedUnaryOperation(umath.arcsin, 0.0,

1231 _DomainCheckInterval(-1.0, 1.0))

1232 arccos = _MaskedUnaryOperation(umath.arccos, 0.0,

1233 _DomainCheckInterval(-1.0, 1.0))

1234 arccosh = _MaskedUnaryOperation(umath.arccosh, 1.0,

1235 _DomainGreaterEqual(1.0))

1236 arctanh = _MaskedUnaryOperation(umath.arctanh, 0.0,

1237 _DomainCheckInterval(-1.0 + 1e-15, 1.0 - 1e-15))

1238

1239# Binary ufuncs

1240 add = _MaskedBinaryOperation(umath.add)

1241 subtract = _MaskedBinaryOperation(umath.subtract)

1242 multiply = _MaskedBinaryOperation(umath.multiply, 1, 1)

1243 arctan2 = _MaskedBinaryOperation(umath.arctan2, 0.0, 1.0)

1244 equal = _MaskedBinaryOperation(umath.equal)

1245 equal.reduce = None

1246 not_equal = _MaskedBinaryOperation(umath.not_equal)

1247 not_equal.reduce = None

1248 less_equal = _MaskedBinaryOperation(umath.less_equal)

1249 less_equal.reduce = None

1250 greater_equal = _MaskedBinaryOperation(umath.greater_equal)

1251 greater_equal.reduce = None

1252 less = _MaskedBinaryOperation(umath.less)

1253 less.reduce = None

1254 greater = _MaskedBinaryOperation(umath.greater)

1255 greater.reduce = None

1256 logical_and = _MaskedBinaryOperation(umath.logical_and)

1257 alltrue = _MaskedBinaryOperation(umath.logical_and, 1, 1).reduce

1258 logical_or = _MaskedBinaryOperation(umath.logical_or)

1259 sometrue = logical_or.reduce

1260 logical_xor = _MaskedBinaryOperation(umath.logical_xor)

1261 bitwise_and = _MaskedBinaryOperation(umath.bitwise_and)

1262 bitwise_or = _MaskedBinaryOperation(umath.bitwise_or)

1263 bitwise_xor = _MaskedBinaryOperation(umath.bitwise_xor)

1264 hypot = _MaskedBinaryOperation(umath.hypot)

1265

1266# Domained binary ufuncs

1267 divide = _DomainedBinaryOperation(umath.divide, _DomainSafeDivide(), 0, 1)

1268 true_divide = _DomainedBinaryOperation(umath.true_divide,

1269 _DomainSafeDivide(), 0, 1)

1270 floor_divide = _DomainedBinaryOperation(umath.floor_divide,

1271 _DomainSafeDivide(), 0, 1)

1272 remainder = _DomainedBinaryOperation(umath.remainder,

1273 _DomainSafeDivide(), 0, 1)

1274 fmod = _DomainedBinaryOperation(umath.fmod, _DomainSafeDivide(), 0, 1)

1275 mod = _DomainedBinaryOperation(umath.mod, _DomainSafeDivide(), 0, 1)

1276

1277

1278###############################################################################

1279# Mask creation functions #

1280###############################################################################

1281

1282

1283 def _replace_dtype_fields_recursive(dtype, primitive_dtype):

1284 "Private function allowing recursion in _replace_dtype_fields."

1285 _recurse = _replace_dtype_fields_recursive

1286

1287 # Do we have some name fields ?

1288 if dtype.names is not None:

1289 descr = []

1290 for name in dtype.names:

1291 field = dtype.fields[name]

1292 if len(field) == 3:

1293 # Prepend the title to the name

1294 name = (field[-1], name)

1295 descr.append((name, _recurse(field[0], primitive_dtype)))

1296 new_dtype = np.dtype(descr)

1297

1298 # Is this some kind of composite a la (float,2)

1299 elif dtype.subdtype:

1300 descr = list(dtype.subdtype)

1301 descr[0] = _recurse(dtype.subdtype[0], primitive_dtype)

1302 new_dtype = np.dtype(tuple(descr))

1303

1304 # this is a primitive type, so do a direct replacement

1305 else:

1306 new_dtype = primitive_dtype

1307

1308 # preserve identity of dtypes

1309 if new_dtype == dtype:

1310 new_dtype = dtype

1311

1312 return new_dtype

1313

1314

1315 def _replace_dtype_fields(dtype, primitive_dtype):

1316 """

1317 Construct a dtype description list from a given dtype.

1318

1319 Returns a new dtype object, with all fields and subtypes in the given type

1320 recursively replaced with `primitive_dtype`.

1321

1322 Arguments are coerced to dtypes first.

1323 """

1324 dtype = np.dtype(dtype)

1325 primitive_dtype = np.dtype(primitive_dtype)

1326 return _replace_dtype_fields_recursive(dtype, primitive_dtype)

1327

1328

1329 def make_mask_descr(ndtype):

1330 """

1331 Construct a dtype description list from a given dtype.

1332

1333 Returns a new dtype object, with the type of all fields in `ndtype` to a

1334 boolean type. Field names are not altered.

1335

1336 Parameters

1337 ----------

1338 ndtype : dtype

1339 The dtype to convert.

1340

1341 Returns

1342 -------

1343 result : dtype

1344 A dtype that looks like `ndtype`, the type of all fields is boolean.

1345

1346 Examples

1347 --------

1348 >>> import numpy.ma as ma

1349 >>> dtype = np.dtype({'names':['foo', 'bar'],

1350 ... 'formats':[np.float32, np.int64]})

1351 >>> dtype

1352 dtype([('foo', '<f4'), ('bar', '<i8')])

1353 >>> ma.make_mask_descr(dtype)

1354 dtype([('foo', '|b1'), ('bar', '|b1')])

1355 >>> ma.make_mask_descr(np.float32)

1356 dtype('bool')

1357

1358 """

1359 return _replace_dtype_fields(ndtype, MaskType)

1360

1361

1362 def getmask(a):

1363 """

1364 Return the mask of a masked array, or nomask.

1365

1366 Return the mask of `a` as an ndarray if `a` is a `MaskedArray` and the

1367 mask is not `nomask`, else return `nomask`. To guarantee a full array

1368 of booleans of the same shape as a, use `getmaskarray`.

1369

1370 Parameters

1371 ----------

1372 a : array_like

1373 Input `MaskedArray` for which the mask is required.

1374

1375 See Also

1376 --------

1377 getdata : Return the data of a masked array as an ndarray.

1378 getmaskarray : Return the mask of a masked array, or full array of False.

1379

1380 Examples

1381 --------

1382 >>> import numpy.ma as ma

1383 >>> a = ma.masked_equal([[1,2],[3,4]], 2)

1384 >>> a

1385 masked_array(

1386 data=[[1, --],

1387 [3, 4]],

1388 mask=[[False, True],

1389 [False, False]],

1390 fill_value=2)

1391 >>> ma.getmask(a)

1392 array([[False, True],

1393 [False, False]])

1394

1395 Equivalently use the `MaskedArray` `mask` attribute.

1396

1397 >>> a.mask

1398 array([[False, True],

1399 [False, False]])

1400

1401 Result when mask == `nomask`

1402

1403 >>> b = ma.masked_array([[1,2],[3,4]])

1404 >>> b

1405 masked_array(

1406 data=[[1, 2],

1407 [3, 4]],

1408 mask=False,

1409 fill_value=999999)

1410 >>> ma.nomask

1411 False

1412 >>> ma.getmask(b) == ma.nomask

1413 True

1414 >>> b.mask == ma.nomask

1415 True

1416

1417 """

1418 return getattr(a, '_mask', nomask)

1419

1420

1421 get_mask = getmask

1422

1423

1424 def getmaskarray(arr):

1425 """

1426 Return the mask of a masked array, or full boolean array of False.

1427

1428 Return the mask of `arr` as an ndarray if `arr` is a `MaskedArray` and

1429 the mask is not `nomask`, else return a full boolean array of False of

1430 the same shape as `arr`.

1431

1432 Parameters

1433 ----------

1434 arr : array_like

1435 Input `MaskedArray` for which the mask is required.

1436

1437 See Also

1438 --------

1439 getmask : Return the mask of a masked array, or nomask.

1440 getdata : Return the data of a masked array as an ndarray.

1441

1442 Examples

1443 --------

1444 >>> import numpy.ma as ma

1445 >>> a = ma.masked_equal([[1,2],[3,4]], 2)

1446 >>> a

1447 masked_array(

1448 data=[[1, --],

1449 [3, 4]],

1450 mask=[[False, True],

1451 [False, False]],

1452 fill_value=2)

1453 >>> ma.getmaskarray(a)

1454 array([[False, True],

1455 [False, False]])

1456

1457 Result when mask == ``nomask``

1458

1459 >>> b = ma.masked_array([[1,2],[3,4]])

1460 >>> b

1461 masked_array(

1462 data=[[1, 2],

1463 [3, 4]],

1464 mask=False,

1465 fill_value=999999)

1466 >>> ma.getmaskarray(b)

1467 array([[False, False],

1468 [False, False]])

1469

1470 """

1471 mask = getmask(arr)

1472 if mask is nomask:

1473 mask = make_mask_none(np.shape(arr), getattr(arr, 'dtype', None))

1474 return mask

1475

1476

1477 def is_mask(m):

1478 """

1479 Return True if m is a valid, standard mask.

1480

1481 This function does not check the contents of the input, only that the

1482 type is MaskType. In particular, this function returns False if the

1483 mask has a flexible dtype.

1484

1485 Parameters

1486 ----------

1487 m : array_like

1488 Array to test.

1489

1490 Returns

1491 -------

1492 result : bool

1493 True if `m.dtype.type` is MaskType, False otherwise.

1494

1495 See Also

1496 --------

1497 ma.isMaskedArray : Test whether input is an instance of MaskedArray.

1498

1499 Examples

1500 --------

1501 >>> import numpy.ma as ma

1502 >>> m = ma.masked_equal([0, 1, 0, 2, 3], 0)

1503 >>> m

1504 masked_array(data=[--, 1, --, 2, 3],

1505 mask=[ True, False, True, False, False],

1506 fill_value=0)

1507 >>> ma.is_mask(m)

1508 False

1509 >>> ma.is_mask(m.mask)

1510 True

1511

1512 Input must be an ndarray (or have similar attributes)

1513 for it to be considered a valid mask.

1514

1515 >>> m = [False, True, False]

1516 >>> ma.is_mask(m)

1517 False

1518 >>> m = np.array([False, True, False])

1519 >>> m

1520 array([False, True, False])

1521 >>> ma.is_mask(m)

1522 True

1523

1524 Arrays with complex dtypes don't return True.

1525

1526 >>> dtype = np.dtype({'names':['monty', 'pithon'],

1527 ... 'formats':[bool, bool]})

1528 >>> dtype

1529 dtype([('monty', '|b1'), ('pithon', '|b1')])

1530 >>> m = np.array([(True, False), (False, True), (True, False)],

1531 ... dtype=dtype)

1532 >>> m

1533 array([( True, False), (False, True), ( True, False)],

1534 dtype=[('monty', '?'), ('pithon', '?')])

1535 >>> ma.is_mask(m)

1536 False

1537

1538 """

1539 try:

1540 return m.dtype.type is MaskType

1541 except AttributeError:

1542 return False

1543

1544

1545 def _shrink_mask(m):

1546 """

1547 Shrink a mask to nomask if possible

1548 """

1549 if m.dtype.names is None and not m.any():

1550 return nomask

1551 else:

1552 return m

1553

1554

1555 def make_mask(m, copy=False, shrink=True, dtype=MaskType):

1556 """

1557 Create a boolean mask from an array.

1558

1559 Return `m` as a boolean mask, creating a copy if necessary or requested.

1560 The function can accept any sequence that is convertible to integers,

1561 or ``nomask``. Does not require that contents must be 0s and 1s, values

1562 of 0 are interpreted as False, everything else as True.

1563

1564 Parameters

1565 ----------

1566 m : array_like

1567 Potential mask.

1568 copy : bool, optional

1569 Whether to return a copy of `m` (True) or `m` itself (False).

1570 shrink : bool, optional

1571 Whether to shrink `m` to ``nomask`` if all its values are False.

1572 dtype : dtype, optional

1573 Data-type of the output mask. By default, the output mask has a

1574 dtype of MaskType (bool). If the dtype is flexible, each field has

1575 a boolean dtype. This is ignored when `m` is ``nomask``, in which

1576 case ``nomask`` is always returned.

1577

1578 Returns

1579 -------

1580 result : ndarray

1581 A boolean mask derived from `m`.

1582

1583 Examples

1584 --------

1585 >>> import numpy.ma as ma

1586 >>> m = [True, False, True, True]

1587 >>> ma.make_mask(m)

1588 array([ True, False, True, True])

1589 >>> m = [1, 0, 1, 1]

1590 >>> ma.make_mask(m)

1591 array([ True, False, True, True])

1592 >>> m = [1, 0, 2, -3]

1593 >>> ma.make_mask(m)

1594 array([ True, False, True, True])

1595

1596 Effect of the `shrink` parameter.

1597

1598 >>> m = np.zeros(4)

1599 >>> m

1600 array([0., 0., 0., 0.])

1601 >>> ma.make_mask(m)

1602 False

1603 >>> ma.make_mask(m, shrink=False)

1604 array([False, False, False, False])

1605

1606 Using a flexible `dtype`.

1607

1608 >>> m = [1, 0, 1, 1]

1609 >>> n = [0, 1, 0, 0]

1610 >>> arr = []

1611 >>> for man, mouse in zip(m, n):

1612 ... arr.append((man, mouse))

1613 >>> arr

1614 [(1, 0), (0, 1), (1, 0), (1, 0)]

1615 >>> dtype = np.dtype({'names':['man', 'mouse'],

1616 ... 'formats':[np.int64, np.int64]})

1617 >>> arr = np.array(arr, dtype=dtype)

1618 >>> arr

1619 array([(1, 0), (0, 1), (1, 0), (1, 0)],

1620 dtype=[('man', '<i8'), ('mouse', '<i8')])

1621 >>> ma.make_mask(arr, dtype=dtype)

1622 array([(True, False), (False, True), (True, False), (True, False)],

1623 dtype=[('man', '|b1'), ('mouse', '|b1')])

1624

1625 """

1626 if m is nomask:

1627 return nomask

1628

1629 # Make sure the input dtype is valid.

1630 dtype = make_mask_descr(dtype)

1631

1632 # legacy boolean special case: "existence of fields implies true"

1633 if isinstance(m, ndarray) and m.dtype.fields and dtype == np.bool_:

1634 return np.ones(m.shape, dtype=dtype)

1635

1636 # Fill the mask in case there are missing data; turn it into an ndarray.

1637 result = np.array(filled(m, True), copy=copy, dtype=dtype, subok=True)

1638 # Bas les masques !

1639 if shrink:

1640 result = _shrink_mask(result)

1641 return result

1642

1643

1644 def make_mask_none(newshape, dtype=None):

1645 """

1646 Return a boolean mask of the given shape, filled with False.

1647

1648 This function returns a boolean ndarray with all entries False, that can

1649 be used in common mask manipulations. If a complex dtype is specified, the

1650 type of each field is converted to a boolean type.

1651

1652 Parameters

1653 ----------

1654 newshape : tuple

1655 A tuple indicating the shape of the mask.

1656 dtype : {None, dtype}, optional

1657 If None, use a MaskType instance. Otherwise, use a new datatype with

1658 the same fields as `dtype`, converted to boolean types.

1659

1660 Returns

1661 -------

1662 result : ndarray

1663 An ndarray of appropriate shape and dtype, filled with False.

1664

1665 See Also

1666 --------

1667 make_mask : Create a boolean mask from an array.

1668 make_mask_descr : Construct a dtype description list from a given dtype.

1669

1670 Examples

1671 --------

1672 >>> import numpy.ma as ma

1673 >>> ma.make_mask_none((3,))

1674 array([False, False, False])

1675

1676 Defining a more complex dtype.

1677

1678 >>> dtype = np.dtype({'names':['foo', 'bar'],

1679 ... 'formats':[np.float32, np.int64]})

1680 >>> dtype

1681 dtype([('foo', '<f4'), ('bar', '<i8')])

1682 >>> ma.make_mask_none((3,), dtype=dtype)

1683 array([(False, False), (False, False), (False, False)],

1684 dtype=[('foo', '|b1'), ('bar', '|b1')])

1685

1686 """

1687 if dtype is None:

1688 result = np.zeros(newshape, dtype=MaskType)

1689 else:

1690 result = np.zeros(newshape, dtype=make_mask_descr(dtype))

1691 return result

1692

1693

1694 def _recursive_mask_or(m1, m2, newmask):

1695 names = m1.dtype.names

1696 for name in names:

1697 current1 = m1[name]

1698 if current1.dtype.names is not None:

1699 _recursive_mask_or(current1, m2[name], newmask[name])

1700 else:

1701 umath.logical_or(current1, m2[name], newmask[name])

1702

1703

1704 def mask_or(m1, m2, copy=False, shrink=True):

1705 """

1706 Combine two masks with the ``logical_or`` operator.

1707

1708 The result may be a view on `m1` or `m2` if the other is `nomask`

1709 (i.e. False).

1710

1711 Parameters

1712 ----------

1713 m1, m2 : array_like

1714 Input masks.

1715 copy : bool, optional

1716 If copy is False and one of the inputs is `nomask`, return a view

1717 of the other input mask. Defaults to False.

1718 shrink : bool, optional

1719 Whether to shrink the output to `nomask` if all its values are

1720 False. Defaults to True.

1721

1722 Returns

1723 -------

1724 mask : output mask

1725 The result masks values that are masked in either `m1` or `m2`.

1726

1727 Raises

1728 ------

1729 ValueError

1730 If `m1` and `m2` have different flexible dtypes.

1731

1732 Examples

1733 --------

1734 >>> m1 = np.ma.make_mask([0, 1, 1, 0])

1735 >>> m2 = np.ma.make_mask([1, 0, 0, 0])

1736 >>> np.ma.mask_or(m1, m2)

1737 array([ True, True, True, False])

1738

1739 """

1740

1741 if (m1 is nomask) or (m1 is False):

1742 dtype = getattr(m2, 'dtype', MaskType)

1743 return make_mask(m2, copy=copy, shrink=shrink, dtype=dtype)

1744 if (m2 is nomask) or (m2 is False):

1745 dtype = getattr(m1, 'dtype', MaskType)

1746 return make_mask(m1, copy=copy, shrink=shrink, dtype=dtype)

1747 if m1 is m2 and is_mask(m1):

1748 return m1

1749 (dtype1, dtype2) = (getattr(m1, 'dtype', None), getattr(m2, 'dtype', None))

1750 if dtype1 != dtype2:

1751 raise ValueError("Incompatible dtypes '%s'<>'%s'" % (dtype1, dtype2))

1752 if dtype1.names is not None:

1753 # Allocate an output mask array with the properly broadcast shape.

1754 newmask = np.empty(np.broadcast(m1, m2).shape, dtype1)

1755 _recursive_mask_or(m1, m2, newmask)

1756 return newmask

1757 return make_mask(umath.logical_or(m1, m2), copy=copy, shrink=shrink)

1758

1759

1760 def flatten_mask(mask):

1761 """

1762 Returns a completely flattened version of the mask, where nested fields

1763 are collapsed.

1764

1765 Parameters

1766 ----------

1767 mask : array_like

1768 Input array, which will be interpreted as booleans.

1769

1770 Returns

1771 -------

1772 flattened_mask : ndarray of bools

1773 The flattened input.

1774

1775 Examples

1776 --------

1777 >>> mask = np.array([0, 0, 1])

1778 >>> np.ma.flatten_mask(mask)

1779 array([False, False, True])

1780

1781 >>> mask = np.array([(0, 0), (0, 1)], dtype=[('a', bool), ('b', bool)])

1782 >>> np.ma.flatten_mask(mask)

1783 array([False, False, False, True])

1784

1785 >>> mdtype = [('a', bool), ('b', [('ba', bool), ('bb', bool)])]

1786 >>> mask = np.array([(0, (0, 0)), (0, (0, 1))], dtype=mdtype)

1787 >>> np.ma.flatten_mask(mask)

1788 array([False, False, False, False, False, True])

1789

1790 """

1791

1792 def _flatmask(mask):

1793 "Flatten the mask and returns a (maybe nested) sequence of booleans."

1794 mnames = mask.dtype.names

1795 if mnames is not None:

1796 return [flatten_mask(mask[name]) for name in mnames]

1797 else:

1798 return mask

1799

1800 def _flatsequence(sequence):

1801 "Generates a flattened version of the sequence."

1802 try:

1803 for element in sequence:

1804 if hasattr(element, '__iter__'):

1805 yield from _flatsequence(element)

1806 else:

1807 yield element

1808 except TypeError:

1809 yield sequence

1810

1811 mask = np.asarray(mask)

1812 flattened = _flatsequence(_flatmask(mask))

1813 return np.array([_ for _ in flattened], dtype=bool)

1814

1815

1816 def _check_mask_axis(mask, axis, keepdims=np._NoValue):

1817 "Check whether there are masked values along the given axis"

1818 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}

1819 if mask is not nomask:

1820 return mask.all(axis=axis, **kwargs)

1821 return nomask

1822

1823

1824###############################################################################

1825# Masking functions #

1826###############################################################################

1827

1828 def masked_where(condition, a, copy=True):

1829 """

1830 Mask an array where a condition is met.

1831

1832 Return `a` as an array masked where `condition` is True.

1833 Any masked values of `a` or `condition` are also masked in the output.

1834

1835 Parameters

1836 ----------

1837 condition : array_like

1838 Masking condition. When `condition` tests floating point values for

1839 equality, consider using ``masked_values`` instead.

1840 a : array_like

1841 Array to mask.

1842 copy : bool

1843 If True (default) make a copy of `a` in the result. If False modify

1844 `a` in place and return a view.

1845

1846 Returns

1847 -------

1848 result : MaskedArray

1849 The result of masking `a` where `condition` is True.

1850

1851 See Also

1852 --------

1853 masked_values : Mask using floating point equality.

1854 masked_equal : Mask where equal to a given value.

1855 masked_not_equal : Mask where `not` equal to a given value.

1856 masked_less_equal : Mask where less than or equal to a given value.

1857 masked_greater_equal : Mask where greater than or equal to a given value.

1858 masked_less : Mask where less than a given value.

1859 masked_greater : Mask where greater than a given value.

1860 masked_inside : Mask inside a given interval.

1861 masked_outside : Mask outside a given interval.

1862 masked_invalid : Mask invalid values (NaNs or infs).

1863

1864 Examples

1865 --------

1866 >>> import numpy.ma as ma

1867 >>> a = np.arange(4)

1868 >>> a

1869 array([0, 1, 2, 3])

1870 >>> ma.masked_where(a <= 2, a)

1871 masked_array(data=[--, --, --, 3],

1872 mask=[ True, True, True, False],

1873 fill_value=999999)

1874

1875 Mask array `b` conditional on `a`.

1876

1877 >>> b = ['a', 'b', 'c', 'd']

1878 >>> ma.masked_where(a == 2, b)

1879 masked_array(data=['a', 'b', --, 'd'],

1880 mask=[False, False, True, False],

1881 fill_value='N/A',

1882 dtype='<U1')

1883

1884 Effect of the `copy` argument.

1885

1886 >>> c = ma.masked_where(a <= 2, a)

1887 >>> c

1888 masked_array(data=[--, --, --, 3],

1889 mask=[ True, True, True, False],

1890 fill_value=999999)

1891 >>> c[0] = 99

1892 >>> c

1893 masked_array(data=[99, --, --, 3],

1894 mask=[False, True, True, False],

1895 fill_value=999999)

1896 >>> a

1897 array([0, 1, 2, 3])

1898 >>> c = ma.masked_where(a <= 2, a, copy=False)

1899 >>> c[0] = 99

1900 >>> c

1901 masked_array(data=[99, --, --, 3],

1902 mask=[False, True, True, False],

1903 fill_value=999999)

1904 >>> a

1905 array([99, 1, 2, 3])

1906

1907 When `condition` or `a` contain masked values.

1908

1909 >>> a = np.arange(4)

1910 >>> a = ma.masked_where(a == 2, a)

1911 >>> a

1912 masked_array(data=[0, 1, --, 3],

1913 mask=[False, False, True, False],

1914 fill_value=999999)

1915 >>> b = np.arange(4)

1916 >>> b = ma.masked_where(b == 0, b)

1917 >>> b

1918 masked_array(data=[--, 1, 2, 3],

1919 mask=[ True, False, False, False],

1920 fill_value=999999)

1921 >>> ma.masked_where(a == 3, b)

1922 masked_array(data=[--, 1, --, --],

1923 mask=[ True, False, True, True],

1924 fill_value=999999)

1925

1926 """

1927 # Make sure that condition is a valid standard-type mask.

1928 cond = make_mask(condition, shrink=False)

1929 a = np.array(a, copy=copy, subok=True)

1930

1931 (cshape, ashape) = (cond.shape, a.shape)

1932 if cshape and cshape != ashape:

1933 raise IndexError("Inconsistent shape between the condition and the input"

1934 " (got %s and %s)" % (cshape, ashape))

1935 if hasattr(a, '_mask'):

1936 cond = mask_or(cond, a._mask)

1937 cls = type(a)

1938 else:

1939 cls = MaskedArray

1940 result = a.view(cls)

1941 # Assign to *.mask so that structured masks are handled correctly.

1942 result.mask = _shrink_mask(cond)

1943 # There is no view of a boolean so when 'a' is a MaskedArray with nomask

1944 # the update to the result's mask has no effect.

1945 if not copy and hasattr(a, '_mask') and getmask(a) is nomask:

1946 a._mask = result._mask.view()

1947 return result

1948

1949

1950 def masked_greater(x, value, copy=True):

1951 """

1952 Mask an array where greater than a given value.

1953

1954 This function is a shortcut to ``masked_where``, with

1955 `condition` = (x > value).

1956

1957 See Also

1958 --------

1959 masked_where : Mask where a condition is met.

1960

1961 Examples

1962 --------

1963 >>> import numpy.ma as ma

1964 >>> a = np.arange(4)

1965 >>> a

1966 array([0, 1, 2, 3])

1967 >>> ma.masked_greater(a, 2)

1968 masked_array(data=[0, 1, 2, --],

1969 mask=[False, False, False, True],

1970 fill_value=999999)

1971

1972 """

1973 return masked_where(greater(x, value), x, copy=copy)

1974

1975

1976 def masked_greater_equal(x, value, copy=True):

1977 """

1978 Mask an array where greater than or equal to a given value.

1979

1980 This function is a shortcut to ``masked_where``, with

1981 `condition` = (x >= value).

1982

1983 See Also

1984 --------

1985 masked_where : Mask where a condition is met.

1986

1987 Examples

1988 --------

1989 >>> import numpy.ma as ma

1990 >>> a = np.arange(4)

1991 >>> a

1992 array([0, 1, 2, 3])

1993 >>> ma.masked_greater_equal(a, 2)

1994 masked_array(data=[0, 1, --, --],

1995 mask=[False, False, True, True],

1996 fill_value=999999)

1997

1998 """

1999 return masked_where(greater_equal(x, value), x, copy=copy)

2000

2001

2002 def masked_less(x, value, copy=True):

2003 """

2004 Mask an array where less than a given value.

2005

2006 This function is a shortcut to ``masked_where``, with

2007 `condition` = (x < value).

2008

2009 See Also

2010 --------

2011 masked_where : Mask where a condition is met.

2012

2013 Examples

2014 --------

2015 >>> import numpy.ma as ma

2016 >>> a = np.arange(4)

2017 >>> a

2018 array([0, 1, 2, 3])

2019 >>> ma.masked_less(a, 2)

2020 masked_array(data=[--, --, 2, 3],

2021 mask=[ True, True, False, False],

2022 fill_value=999999)

2023

2024 """

2025 return masked_where(less(x, value), x, copy=copy)

2026

2027

2028 def masked_less_equal(x, value, copy=True):

2029 """

2030 Mask an array where less than or equal to a given value.

2031

2032 This function is a shortcut to ``masked_where``, with

2033 `condition` = (x <= value).

2034

2035 See Also

2036 --------

2037 masked_where : Mask where a condition is met.

2038

2039 Examples

2040 --------

2041 >>> import numpy.ma as ma

2042 >>> a = np.arange(4)

2043 >>> a

2044 array([0, 1, 2, 3])

2045 >>> ma.masked_less_equal(a, 2)

2046 masked_array(data=[--, --, --, 3],

2047 mask=[ True, True, True, False],

2048 fill_value=999999)

2049

2050 """

2051 return masked_where(less_equal(x, value), x, copy=copy)

2052

2053

2054 def masked_not_equal(x, value, copy=True):

2055 """

2056 Mask an array where `not` equal to a given value.

2057

2058 This function is a shortcut to ``masked_where``, with

2059 `condition` = (x != value).

2060

2061 See Also

2062 --------

2063 masked_where : Mask where a condition is met.

2064

2065 Examples

2066 --------

2067 >>> import numpy.ma as ma

2068 >>> a = np.arange(4)

2069 >>> a

2070 array([0, 1, 2, 3])

2071 >>> ma.masked_not_equal(a, 2)

2072 masked_array(data=[--, --, 2, --],

2073 mask=[ True, True, False, True],

2074 fill_value=999999)

2075

2076 """

2077 return masked_where(not_equal(x, value), x, copy=copy)

2078

2079

2080 def masked_equal(x, value, copy=True):

2081 """

2082 Mask an array where equal to a given value.

2083

2084 Return a MaskedArray, masked where the data in array `x` are

2085 equal to `value`. The fill_value of the returned MaskedArray

2086 is set to `value`.

2087

2088 For floating point arrays, consider using ``masked_values(x, value)``.

2089

2090 See Also

2091 --------

2092 masked_where : Mask where a condition is met.

2093 masked_values : Mask using floating point equality.

2094

2095 Examples

2096 --------

2097 >>> import numpy.ma as ma

2098 >>> a = np.arange(4)

2099 >>> a

2100 array([0, 1, 2, 3])

2101 >>> ma.masked_equal(a, 2)

2102 masked_array(data=[0, 1, --, 3],

2103 mask=[False, False, True, False],

2104 fill_value=2)

2105

2106 """

2107 output = masked_where(equal(x, value), x, copy=copy)

2108 output.fill_value = value

2109 return output

2110

2111

2112 def masked_inside(x, v1, v2, copy=True):

2113 """

2114 Mask an array inside a given interval.

2115

2116 Shortcut to ``masked_where``, where `condition` is True for `x` inside

2117 the interval [v1,v2] (v1 <= x <= v2). The boundaries `v1` and `v2`

2118 can be given in either order.

2119

2120 See Also

2121 --------

2122 masked_where : Mask where a condition is met.

2123

2124 Notes

2125 -----

2126 The array `x` is prefilled with its filling value.

2127

2128 Examples

2129 --------

2130 >>> import numpy.ma as ma

2131 >>> x = [0.31, 1.2, 0.01, 0.2, -0.4, -1.1]

2132 >>> ma.masked_inside(x, -0.3, 0.3)

2133 masked_array(data=[0.31, 1.2, --, --, -0.4, -1.1],

2134 mask=[False, False, True, True, False, False],

2135 fill_value=1e+20)

2136

2137 The order of `v1` and `v2` doesn't matter.

2138

2139 >>> ma.masked_inside(x, 0.3, -0.3)

2140 masked_array(data=[0.31, 1.2, --, --, -0.4, -1.1],

2141 mask=[False, False, True, True, False, False],

2142 fill_value=1e+20)

2143

2144 """

2145 if v2 < v1:

2146 (v1, v2) = (v2, v1)

2147 xf = filled(x)

2148 condition = (xf >= v1) & (xf <= v2)

2149 return masked_where(condition, x, copy=copy)

2150

2151

2152 def masked_outside(x, v1, v2, copy=True):

2153 """

2154 Mask an array outside a given interval.

2155

2156 Shortcut to ``masked_where``, where `condition` is True for `x` outside

2157 the interval [v1,v2] (x < v1)|(x > v2).

2158 The boundaries `v1` and `v2` can be given in either order.

2159

2160 See Also

2161 --------

2162 masked_where : Mask where a condition is met.

2163

2164 Notes

2165 -----

2166 The array `x` is prefilled with its filling value.

2167

2168 Examples

2169 --------

2170 >>> import numpy.ma as ma

2171 >>> x = [0.31, 1.2, 0.01, 0.2, -0.4, -1.1]

2172 >>> ma.masked_outside(x, -0.3, 0.3)

2173 masked_array(data=[--, --, 0.01, 0.2, --, --],

2174 mask=[ True, True, False, False, True, True],

2175 fill_value=1e+20)

2176

2177 The order of `v1` and `v2` doesn't matter.

2178

2179 >>> ma.masked_outside(x, 0.3, -0.3)

2180 masked_array(data=[--, --, 0.01, 0.2, --, --],

2181 mask=[ True, True, False, False, True, True],

2182 fill_value=1e+20)

2183

2184 """

2185 if v2 < v1:

2186 (v1, v2) = (v2, v1)

2187 xf = filled(x)

2188 condition = (xf < v1) | (xf > v2)

2189 return masked_where(condition, x, copy=copy)

2190

2191

2192 def masked_object(x, value, copy=True, shrink=True):

2193 """

2194 Mask the array `x` where the data are exactly equal to value.

2195

2196 This function is similar to `masked_values`, but only suitable

2197 for object arrays: for floating point, use `masked_values` instead.

2198

2199 Parameters

2200 ----------

2201 x : array_like

2202 Array to mask

2203 value : object

2204 Comparison value

2205 copy : {True, False}, optional

2206 Whether to return a copy of `x`.

2207 shrink : {True, False}, optional

2208 Whether to collapse a mask full of False to nomask

2209

2210 Returns

2211 -------

2212 result : MaskedArray

2213 The result of masking `x` where equal to `value`.

2214

2215 See Also

2216 --------

2217 masked_where : Mask where a condition is met.

2218 masked_equal : Mask where equal to a given value (integers).

2219 masked_values : Mask using floating point equality.

2220

2221 Examples

2222 --------

2223 >>> import numpy.ma as ma

2224 >>> food = np.array(['green_eggs', 'ham'], dtype=object)

2225 >>> # don't eat spoiled food

2226 >>> eat = ma.masked_object(food, 'green_eggs')

2227 >>> eat

2228 masked_array(data=[--, 'ham'],

2229 mask=[ True, False],

2230 fill_value='green_eggs',

2231 dtype=object)

2232 >>> # plain ol` ham is boring

2233 >>> fresh_food = np.array(['cheese', 'ham', 'pineapple'], dtype=object)

2234 >>> eat = ma.masked_object(fresh_food, 'green_eggs')

2235 >>> eat

2236 masked_array(data=['cheese', 'ham', 'pineapple'],

2237 mask=False,

2238 fill_value='green_eggs',

2239 dtype=object)

2240

2241 Note that `mask` is set to ``nomask`` if possible.

2242

2243 >>> eat

2244 masked_array(data=['cheese', 'ham', 'pineapple'],

2245 mask=False,

2246 fill_value='green_eggs',

2247 dtype=object)

2248

2249 """

2250 if isMaskedArray(x):

2251 condition = umath.equal(x._data, value)

2252 mask = x._mask

2253 else:

2254 condition = umath.equal(np.asarray(x), value)

2255 mask = nomask

2256 mask = mask_or(mask, make_mask(condition, shrink=shrink))

2257 return masked_array(x, mask=mask, copy=copy, fill_value=value)

2258

2259

2260 def masked_values(x, value, rtol=1e-5, atol=1e-8, copy=True, shrink=True):

2261 """

2262 Mask using floating point equality.

2263

2264 Return a MaskedArray, masked where the data in array `x` are approximately

2265 equal to `value`, determined using `isclose`. The default tolerances for

2266 `masked_values` are the same as those for `isclose`.

2267

2268 For integer types, exact equality is used, in the same way as

2269 `masked_equal`.

2270

2271 The fill_value is set to `value` and the mask is set to ``nomask`` if

2272 possible.

2273

2274 Parameters

2275 ----------

2276 x : array_like

2277 Array to mask.

2278 value : float

2279 Masking value.

2280 rtol, atol : float, optional

2281 Tolerance parameters passed on to `isclose`

2282 copy : bool, optional

2283 Whether to return a copy of `x`.

2284 shrink : bool, optional

2285 Whether to collapse a mask full of False to ``nomask``.

2286

2287 Returns

2288 -------

2289 result : MaskedArray

2290 The result of masking `x` where approximately equal to `value`.

2291

2292 See Also

2293 --------

2294 masked_where : Mask where a condition is met.

2295 masked_equal : Mask where equal to a given value (integers).

2296

2297 Examples

2298 --------

2299 >>> import numpy.ma as ma

2300 >>> x = np.array([1, 1.1, 2, 1.1, 3])

2301 >>> ma.masked_values(x, 1.1)

2302 masked_array(data=[1.0, --, 2.0, --, 3.0],

2303 mask=[False, True, False, True, False],

2304 fill_value=1.1)

2305

2306 Note that `mask` is set to ``nomask`` if possible.

2307

2308 >>> ma.masked_values(x, 2.1)

2309 masked_array(data=[1. , 1.1, 2. , 1.1, 3. ],

2310 mask=False,

2311 fill_value=2.1)

2312

2313 Unlike `masked_equal`, `masked_values` can perform approximate equalities.

2314

2315 >>> ma.masked_values(x, 2.1, atol=1e-1)

2316 masked_array(data=[1.0, 1.1, --, 1.1, 3.0],

2317 mask=[False, False, True, False, False],

2318 fill_value=2.1)

2319

2320 """

2321 xnew = filled(x, value)

2322 if np.issubdtype(xnew.dtype, np.floating):

2323 mask = np.isclose(xnew, value, atol=atol, rtol=rtol)

2324 else:

2325 mask = umath.equal(xnew, value)

2326 ret = masked_array(xnew, mask=mask, copy=copy, fill_value=value)

2327 if shrink:

2328 ret.shrink_mask()

2329 return ret

2330

2331

2332 def masked_invalid(a, copy=True):

2333 """

2334 Mask an array where invalid values occur (NaNs or infs).

2335

2336 This function is a shortcut to ``masked_where``, with

2337 `condition` = ~(np.isfinite(a)). Any pre-existing mask is conserved.

2338 Only applies to arrays with a dtype where NaNs or infs make sense

2339 (i.e. floating point types), but accepts any array_like object.

2340

2341 See Also

2342 --------

2343 masked_where : Mask where a condition is met.

2344

2345 Examples

2346 --------

2347 >>> import numpy.ma as ma

2348 >>> a = np.arange(5, dtype=float)

2349 >>> a[2] = np.NaN

2350 >>> a[3] = np.PINF

2351 >>> a

2352 array([ 0., 1., nan, inf, 4.])

2353 >>> ma.masked_invalid(a)

2354 masked_array(data=[0.0, 1.0, --, --, 4.0],

2355 mask=[False, False, True, True, False],

2356 fill_value=1e+20)

2357

2358 """

2359 a = np.array(a, copy=False, subok=True)

2360 res = masked_where(~(np.isfinite(a)), a, copy=copy)

2361 # masked_invalid previously never returned nomask as a mask and doing so

2362 # threw off matplotlib (gh-22842). So use shrink=False:

2363 if res._mask is nomask:

2364 res._mask = make_mask_none(res.shape, res.dtype)

2365 return res

2366

2367###############################################################################

2368# Printing options #

2369###############################################################################

2370

2371

2372 class _MaskedPrintOption:

2373 """

2374 Handle the string used to represent missing data in a masked array.

2375

2376 """

2377

2378 def __init__(self, display):

2379 """

2380 Create the masked_print_option object.

2381

2382 """

2383 self._display = display

2384 self._enabled = True

2385

2386 def display(self):

2387 """

2388 Display the string to print for masked values.

2389

2390 """

2391 return self._display

2392

2393 def set_display(self, s):

2394 """

2395 Set the string to print for masked values.

2396

2397 """

2398 self._display = s

2399

2400 def enabled(self):

2401 """

2402 Is the use of the display value enabled?

2403

2404 """

2405 return self._enabled

2406

2407 def enable(self, shrink=1):

2408 """

2409 Set the enabling shrink to `shrink`.

2410

2411 """

2412 self._enabled = shrink

2413

2414 def __str__(self):

2415 return str(self._display)

2416

2417 __repr__ = __str__

2418

2419# if you single index into a masked location you get this object.

2420 masked_print_option = _MaskedPrintOption('--')

2421

2422

2423 def _recursive_printoption(result, mask, printopt):

2424 """

2425 Puts printoptions in result where mask is True.

2426

2427 Private function allowing for recursion

2428

2429 """

2430 names = result.dtype.names

2431 if names is not None:

2432 for name in names:

2433 curdata = result[name]

2434 curmask = mask[name]

2435 _recursive_printoption(curdata, curmask, printopt)

2436 else:

2437 np.copyto(result, printopt, where=mask)

2438 return

2439

2440# For better or worse, these end in a newline

2441_legacy_print_templates = dict(

2442 long_std=textwrap.dedent("""\

2443 masked_%(name)s(data =

2444 %(data)s,

2445 %(nlen)s mask =

2446 %(mask)s,

2447 %(nlen)s fill_value = %(fill)s)

2448 """),

2449 long_flx=textwrap.dedent("""\

2450 masked_%(name)s(data =

2451 %(data)s,

2452 %(nlen)s mask =

2453 %(mask)s,

2454 %(nlen)s fill_value = %(fill)s,

2455 %(nlen)s dtype = %(dtype)s)

2456 """),

2457 short_std=textwrap.dedent("""\

2458 masked_%(name)s(data = %(data)s,

2459 %(nlen)s mask = %(mask)s,

2460 %(nlen)s fill_value = %(fill)s)

2461 """),

2462 short_flx=textwrap.dedent("""\

2463 masked_%(name)s(data = %(data)s,

2464 %(nlen)s mask = %(mask)s,

2465 %(nlen)s fill_value = %(fill)s,

2466 %(nlen)s dtype = %(dtype)s)

2467 """)

2468)

2469

2470###############################################################################

2471# MaskedArray class #

2472###############################################################################

2473

2474

2475 def _recursive_filled(a, mask, fill_value):

2476 """

2477 Recursively fill `a` with `fill_value`.

2478

2479 """

2480 names = a.dtype.names

2481 for name in names:

2482 current = a[name]

2483 if current.dtype.names is not None:

2484 _recursive_filled(current, mask[name], fill_value[name])

2485 else:

2486 np.copyto(current, fill_value[name], where=mask[name])

2487

2488

2489 def flatten_structured_array(a):

2490 """

2491 Flatten a structured array.

2492

2493 The data type of the output is chosen such that it can represent all of the

2494 (nested) fields.

2495

2496 Parameters

2497 ----------

2498 a : structured array

2499

2500 Returns

2501 -------

2502 output : masked array or ndarray

2503 A flattened masked array if the input is a masked array, otherwise a

2504 standard ndarray.

2505

2506 Examples

2507 --------

2508 >>> ndtype = [('a', int), ('b', float)]

2509 >>> a = np.array([(1, 1), (2, 2)], dtype=ndtype)

2510 >>> np.ma.flatten_structured_array(a)

2511 array([[1., 1.],

2512 [2., 2.]])

2513

2514 """

2515

2516 def flatten_sequence(iterable):

2517 """

2518 Flattens a compound of nested iterables.

2519

2520 """

2521 for elm in iter(iterable):

2522 if hasattr(elm, '__iter__'):

2523 yield from flatten_sequence(elm)

2524 else:

2525 yield elm

2526

2527 a = np.asanyarray(a)

2528 inishape = a.shape

2529 a = a.ravel()

2530 if isinstance(a, MaskedArray):

2531 out = np.array([tuple(flatten_sequence(d.item())) for d in a._data])

2532 out = out.view(MaskedArray)

2533 out._mask = np.array([tuple(flatten_sequence(d.item()))

2534 for d in getmaskarray(a)])

2535 else:

2536 out = np.array([tuple(flatten_sequence(d.item())) for d in a])

2537 if len(inishape) > 1:

2538 newshape = list(out.shape)

2539 newshape[0] = inishape

2540 out.shape = tuple(flatten_sequence(newshape))

2541 return out

2542

2543

2544 def _arraymethod(funcname, onmask=True):

2545 """

2546 Return a class method wrapper around a basic array method.

2547

2548 Creates a class method which returns a masked array, where the new

2549 ``_data`` array is the output of the corresponding basic method called

2550 on the original ``_data``.

2551

2552 If `onmask` is True, the new mask is the output of the method called

2553 on the initial mask. Otherwise, the new mask is just a reference

2554 to the initial mask.

2555

2556 Parameters

2557 ----------

2558 funcname : str

2559 Name of the function to apply on data.

2560 onmask : bool

2561 Whether the mask must be processed also (True) or left

2562 alone (False). Default is True. Make available as `_onmask`

2563 attribute.

2564

2565 Returns

2566 -------

2567 method : instancemethod

2568 Class method wrapper of the specified basic array method.

2569

2570 """

2571 def wrapped_method(self, *args, **params):

2572 result = getattr(self._data, funcname)(*args, **params)

2573 result = result.view(type(self))

2574 result._update_from(self)

2575 mask = self._mask

2576 if not onmask:

2577 result.__setmask__(mask)

2578 elif mask is not nomask:

2579 # __setmask__ makes a copy, which we don't want

2580 result._mask = getattr(mask, funcname)(*args, **params)

2581 return result

2582 methdoc = getattr(ndarray, funcname, None) or getattr(np, funcname, None)

2583 if methdoc is not None:

2584 wrapped_method.__doc__ = methdoc.__doc__

2585 wrapped_method.__name__ = funcname

2586 return wrapped_method

2587

2588

2589 class MaskedIterator:

2590 """

2591 Flat iterator object to iterate over masked arrays.

2592

2593 A `MaskedIterator` iterator is returned by ``x.flat`` for any masked array

2594 `x`. It allows iterating over the array as if it were a 1-D array,

2595 either in a for-loop or by calling its `next` method.

2596

2597 Iteration is done in C-contiguous style, with the last index varying the

2598 fastest. The iterator can also be indexed using basic slicing or

2599 advanced indexing.

2600

2601 See Also

2602 --------

2603 MaskedArray.flat : Return a flat iterator over an array.

2604 MaskedArray.flatten : Returns a flattened copy of an array.

2605

2606 Notes

2607 -----

2608 `MaskedIterator` is not exported by the `ma` module. Instead of

2609 instantiating a `MaskedIterator` directly, use `MaskedArray.flat`.

2610

2611 Examples

2612 --------

2613 >>> x = np.ma.array(arange(6).reshape(2, 3))

2614 >>> fl = x.flat

2615 >>> type(fl)

2616 <class 'numpy.ma.core.MaskedIterator'>

2617 >>> for item in fl:

2618 ... print(item)

2619 ...

2620 0

2621 1

2622 2

2623 3

2624 4

2625 5

2626

2627 Extracting more than a single element b indexing the `MaskedIterator`

2628 returns a masked array:

2629

2630 >>> fl[2:4]

2631 masked_array(data = [2 3],

2632 mask = False,

2633 fill_value = 999999)

2634

2635 """

2636

2637 def __init__(self, ma):

2638 self.ma = ma

2639 self.dataiter = ma._data.flat

2640

2641 if ma._mask is nomask:

2642 self.maskiter = None

2643 else:

2644 self.maskiter = ma._mask.flat

2645

2646 def __iter__(self):

2647 return self

2648

2649 def __getitem__(self, indx):

2650 result = self.dataiter.__getitem__(indx).view(type(self.ma))

2651 if self.maskiter is not None:

2652 _mask = self.maskiter.__getitem__(indx)

2653 if isinstance(_mask, ndarray):

2654 # set shape to match that of data; this is needed for matrices

2655 _mask.shape = result.shape

2656 result._mask = _mask

2657 elif isinstance(_mask, np.void):

2658 return mvoid(result, mask=_mask, hardmask=self.ma._hardmask)

2659 elif _mask: # Just a scalar, masked

2660 return masked

2661 return result

2662

2663 # This won't work if ravel makes a copy

2664 def __setitem__(self, index, value):

2665 self.dataiter[index] = getdata(value)

2666 if self.maskiter is not None:

2667 self.maskiter[index] = getmaskarray(value)

2668

2669 def __next__(self):

2670 """

2671 Return the next value, or raise StopIteration.

2672

2673 Examples

2674 --------

2675 >>> x = np.ma.array([3, 2], mask=[0, 1])

2676 >>> fl = x.flat

2677 >>> next(fl)

2678 3

2679 >>> next(fl)

2680 masked

2681 >>> next(fl)

2682 Traceback (most recent call last):

2683 ...

2684 StopIteration

2685

2686 """

2687 d = next(self.dataiter)

2688 if self.maskiter is not None:

2689 m = next(self.maskiter)

2690 if isinstance(m, np.void):

2691 return mvoid(d, mask=m, hardmask=self.ma._hardmask)

2692 elif m: # Just a scalar, masked

2693 return masked

2694 return d

2695

2696

2697 class MaskedArray(ndarray):

2698 """

2699 An array class with possibly masked values.

2700

2701 Masked values of True exclude the corresponding element from any

2702 computation.

2703

2704 Construction::

2705

2706 x = MaskedArray(data, mask=nomask, dtype=None, copy=False, subok=True,

2707 ndmin=0, fill_value=None, keep_mask=True, hard_mask=None,

2708 shrink=True, order=None)

2709

2710 Parameters

2711 ----------

2712 data : array_like

2713 Input data.

2714 mask : sequence, optional

2715 Mask. Must be convertible to an array of booleans with the same

2716 shape as `data`. True indicates a masked (i.e. invalid) data.

2717 dtype : dtype, optional

2718 Data type of the output.

2719 If `dtype` is None, the type of the data argument (``data.dtype``)

2720 is used. If `dtype` is not None and different from ``data.dtype``,

2721 a copy is performed.

2722 copy : bool, optional

2723 Whether to copy the input data (True), or to use a reference instead.

2724 Default is False.

2725 subok : bool, optional

2726 Whether to return a subclass of `MaskedArray` if possible (True) or a

2727 plain `MaskedArray`. Default is True.

2728 ndmin : int, optional

2729 Minimum number of dimensions. Default is 0.

2730 fill_value : scalar, optional

2731 Value used to fill in the masked values when necessary.

2732 If None, a default based on the data-type is used.

2733 keep_mask : bool, optional

2734 Whether to combine `mask` with the mask of the input data, if any

2735 (True), or to use only `mask` for the output (False). Default is True.

2736 hard_mask : bool, optional

2737 Whether to use a hard mask or not. With a hard mask, masked values

2738 cannot be unmasked. Default is False.

2739 shrink : bool, optional

2740 Whether to force compression of an empty mask. Default is True.

2741 order : {'C', 'F', 'A'}, optional

2742 Specify the order of the array. If order is 'C', then the array

2743 will be in C-contiguous order (last-index varies the fastest).

2744 If order is 'F', then the returned array will be in

2745 Fortran-contiguous order (first-index varies the fastest).

2746 If order is 'A' (default), then the returned array may be

2747 in any order (either C-, Fortran-contiguous, or even discontiguous),

2748 unless a copy is required, in which case it will be C-contiguous.

2749

2750 Examples

2751 --------

2752

2753 The ``mask`` can be initialized with an array of boolean values

2754 with the same shape as ``data``.

2755

2756 >>> data = np.arange(6).reshape((2, 3))

2757 >>> np.ma.MaskedArray(data, mask=[[False, True, False],

2758 ... [False, False, True]])

2759 masked_array(

2760 data=[[0, --, 2],

2761 [3, 4, --]],

2762 mask=[[False, True, False],

2763 [False, False, True]],

2764 fill_value=999999)

2765

2766 Alternatively, the ``mask`` can be initialized to homogeneous boolean

2767 array with the same shape as ``data`` by passing in a scalar

2768 boolean value:

2769

2770 >>> np.ma.MaskedArray(data, mask=False)

2771 masked_array(

2772 data=[[0, 1, 2],

2773 [3, 4, 5]],

2774 mask=[[False, False, False],

2775 [False, False, False]],

2776 fill_value=999999)

2777

2778 >>> np.ma.MaskedArray(data, mask=True)

2779 masked_array(

2780 data=[[--, --, --],

2781 [--, --, --]],

2782 mask=[[ True, True, True],

2783 [ True, True, True]],

2784 fill_value=999999,

2785 dtype=int64)

2786

2787 .. note::

2788 The recommended practice for initializing ``mask`` with a scalar

2789 boolean value is to use ``True``/``False`` rather than

2790 ``np.True_``/``np.False_``. The reason is :attr:`nomask`

2791 is represented internally as ``np.False_``.

2792

2793 >>> np.False_ is np.ma.nomask

2794 True

2795

2796 """

2797

2798 __array_priority__ = 15

2799 _defaultmask = nomask

2800 _defaulthardmask = False

2801 _baseclass = ndarray

2802

2803 # Maximum number of elements per axis used when printing an array. The

2804 # 1d case is handled separately because we need more values in this case.

2805 _print_width = 100

2806 _print_width_1d = 1500

2807

2808 def __new__(cls, data=None, mask=nomask, dtype=None, copy=False,

2809 subok=True, ndmin=0, fill_value=None, keep_mask=True,

2810 hard_mask=None, shrink=True, order=None):

2811 """

2812 Create a new masked array from scratch.

2813

2814 Notes

2815 -----

2816 A masked array can also be created by taking a .view(MaskedArray).

2817

2818 """

2819 # Process data.

2820 _data = np.array(data, dtype=dtype, copy=copy,

2821 order=order, subok=True, ndmin=ndmin)

2822 _baseclass = getattr(data, '_baseclass', type(_data))

2823 # Check that we're not erasing the mask.

2824 if isinstance(data, MaskedArray) and (data.shape != _data.shape):

2825 copy = True

2826

2827 # Here, we copy the _view_, so that we can attach new properties to it

2828 # we must never do .view(MaskedConstant), as that would create a new

2829 # instance of np.ma.masked, which make identity comparison fail

2830 if isinstance(data, cls) and subok and not isinstance(data, MaskedConstant):

2831 _data = ndarray.view(_data, type(data))

2832 else:

2833 _data = ndarray.view(_data, cls)

2834

2835 # Handle the case where data is not a subclass of ndarray, but

2836 # still has the _mask attribute like MaskedArrays

2837 if hasattr(data, '_mask') and not isinstance(data, ndarray):

2838 _data._mask = data._mask

2839 # FIXME: should we set `_data._sharedmask = True`?

2840 # Process mask.

2841 # Type of the mask

2842 mdtype = make_mask_descr(_data.dtype)

2843

2844 if mask is nomask:

2845 # Case 1. : no mask in input.

2846 # Erase the current mask ?

2847 if not keep_mask:

2848 # With a reduced version

2849 if shrink:

2850 _data._mask = nomask

2851 # With full version

2852 else:

2853 _data._mask = np.zeros(_data.shape, dtype=mdtype)

2854 # Check whether we missed something

2855 elif isinstance(data, (tuple, list)):

2856 try:

2857 # If data is a sequence of masked array

2858 mask = np.array(

2859 [getmaskarray(np.asanyarray(m, dtype=_data.dtype))

2860 for m in data], dtype=mdtype)

2861 except ValueError:

2862 # If data is nested

2863 mask = nomask

2864 # Force shrinking of the mask if needed (and possible)

2865 if (mdtype == MaskType) and mask.any():

2866 _data._mask = mask

2867 _data._sharedmask = False

2868 else:

2869 _data._sharedmask = not copy

2870 if copy:

2871 _data._mask = _data._mask.copy()

2872 # Reset the shape of the original mask

2873 if getmask(data) is not nomask:

2874 data._mask.shape = data.shape

2875 else:

2876 # Case 2. : With a mask in input.

2877 # If mask is boolean, create an array of True or False

2878 if mask is True and mdtype == MaskType:

2879 mask = np.ones(_data.shape, dtype=mdtype)

2880 elif mask is False and mdtype == MaskType:

2881 mask = np.zeros(_data.shape, dtype=mdtype)

2882 else:

2883 # Read the mask with the current mdtype

2884 try:

2885 mask = np.array(mask, copy=copy, dtype=mdtype)

2886 # Or assume it's a sequence of bool/int

2887 except TypeError:

2888 mask = np.array([tuple([m] * len(mdtype)) for m in mask],

2889 dtype=mdtype)

2890 # Make sure the mask and the data have the same shape

2891 if mask.shape != _data.shape:

2892 (nd, nm) = (_data.size, mask.size)

2893 if nm == 1:

2894 mask = np.resize(mask, _data.shape)

2895 elif nm == nd:

2896 mask = np.reshape(mask, _data.shape)

2897 else:

2898 msg = "Mask and data not compatible: data size is %i, " + \

2899 "mask size is %i."

2900 raise MaskError(msg % (nd, nm))

2901 copy = True

2902 # Set the mask to the new value

2903 if _data._mask is nomask:

2904 _data._mask = mask

2905 _data._sharedmask = not copy

2906 else:

2907 if not keep_mask:

2908 _data._mask = mask

2909 _data._sharedmask = not copy

2910 else:

2911 if _data.dtype.names is not None:

2912 def _recursive_or(a, b):

2913 "do a|=b on each field of a, recursively"

2914 for name in a.dtype.names:

2915 (af, bf) = (a[name], b[name])

2916 if af.dtype.names is not None:

2917 _recursive_or(af, bf)

2918 else:

2919 af |= bf

2920

2921 _recursive_or(_data._mask, mask)

2922 else:

2923 _data._mask = np.logical_or(mask, _data._mask)

2924 _data._sharedmask = False

2925 # Update fill_value.

2926 if fill_value is None:

2927 fill_value = getattr(data, '_fill_value', None)

2928 # But don't run the check unless we have something to check.

2929 if fill_value is not None:

2930 _data._fill_value = _check_fill_value(fill_value, _data.dtype)

2931 # Process extra options ..

2932 if hard_mask is None:

2933 _data._hardmask = getattr(data, '_hardmask', False)

2934 else:

2935 _data._hardmask = hard_mask

2936 _data._baseclass = _baseclass

2937 return _data

2938

2939

2940 def _update_from(self, obj):

2941 """

2942 Copies some attributes of obj to self.

2943

2944 """

2945 if isinstance(obj, ndarray):

2946 _baseclass = type(obj)

2947 else:

2948 _baseclass = ndarray

2949 # We need to copy the _basedict to avoid backward propagation

2950 _optinfo = {}

2951 _optinfo.update(getattr(obj, '_optinfo', {}))

2952 _optinfo.update(getattr(obj, '_basedict', {}))

2953 if not isinstance(obj, MaskedArray):

2954 _optinfo.update(getattr(obj, '__dict__', {}))

2955 _dict = dict(_fill_value=getattr(obj, '_fill_value', None),

2956 _hardmask=getattr(obj, '_hardmask', False),

2957 _sharedmask=getattr(obj, '_sharedmask', False),

2958 _isfield=getattr(obj, '_isfield', False),

2959 _baseclass=getattr(obj, '_baseclass', _baseclass),

2960 _optinfo=_optinfo,

2961 _basedict=_optinfo)

2962 self.__dict__.update(_dict)

2963 self.__dict__.update(_optinfo)

2964 return

2965

2966 def __array_finalize__(self, obj):

2967 """

2968 Finalizes the masked array.

2969

2970 """

2971 # Get main attributes.

2972 self._update_from(obj)

2973

2974 # We have to decide how to initialize self.mask, based on

2975 # obj.mask. This is very difficult. There might be some

2976 # correspondence between the elements in the array we are being

2977 # created from (= obj) and us. Or there might not. This method can

2978 # be called in all kinds of places for all kinds of reasons -- could

2979 # be empty_like, could be slicing, could be a ufunc, could be a view.

2980 # The numpy subclassing interface simply doesn't give us any way

2981 # to know, which means that at best this method will be based on

2982 # guesswork and heuristics. To make things worse, there isn't even any

2983 # clear consensus about what the desired behavior is. For instance,

2984 # most users think that np.empty_like(marr) -- which goes via this

2985 # method -- should return a masked array with an empty mask (see

2986 # gh-3404 and linked discussions), but others disagree, and they have

2987 # existing code which depends on empty_like returning an array that

2988 # matches the input mask.

2989 #

2990 # Historically our algorithm was: if the template object mask had the

2991 # same *number of elements* as us, then we used *it's mask object

2992 # itself* as our mask, so that writes to us would also write to the

2993 # original array. This is horribly broken in multiple ways.

2994 #

2995 # Now what we do instead is, if the template object mask has the same

2996 # number of elements as us, and we do not have the same base pointer

2997 # as the template object (b/c views like arr[...] should keep the same

2998 # mask), then we make a copy of the template object mask and use

2999 # that. This is also horribly broken but somewhat less so. Maybe.

3000 if isinstance(obj, ndarray):

3001 # XX: This looks like a bug -- shouldn't it check self.dtype

3002 # instead?

3003 if obj.dtype.names is not None:

3004 _mask = getmaskarray(obj)

3005 else:

3006 _mask = getmask(obj)

3007

3008 # If self and obj point to exactly the same data, then probably

3009 # self is a simple view of obj (e.g., self = obj[...]), so they

3010 # should share the same mask. (This isn't 100% reliable, e.g. self

3011 # could be the first row of obj, or have strange strides, but as a

3012 # heuristic it's not bad.) In all other cases, we make a copy of

3013 # the mask, so that future modifications to 'self' do not end up

3014 # side-effecting 'obj' as well.

3015 if (_mask is not nomask and obj.__array_interface__["data"][0]

3016 != self.__array_interface__["data"][0]):

3017 # We should make a copy. But we could get here via astype,

3018 # in which case the mask might need a new dtype as well

3019 # (e.g., changing to or from a structured dtype), and the

3020 # order could have changed. So, change the mask type if

3021 # needed and use astype instead of copy.

3022 if self.dtype == obj.dtype:

3023 _mask_dtype = _mask.dtype

3024 else:

3025 _mask_dtype = make_mask_descr(self.dtype)

3026

3027 if self.flags.c_contiguous:

3028 order = "C"

3029 elif self.flags.f_contiguous:

3030 order = "F"

3031 else:

3032 order = "K"

3033

3034 _mask = _mask.astype(_mask_dtype, order)

3035 else:

3036 # Take a view so shape changes, etc., do not propagate back.

3037 _mask = _mask.view()

3038 else:

3039 _mask = nomask

3040

3041 self._mask = _mask

3042 # Finalize the mask

3043 if self._mask is not nomask:

3044 try:

3045 self._mask.shape = self.shape

3046 except ValueError:

3047 self._mask = nomask

3048 except (TypeError, AttributeError):

3049 # When _mask.shape is not writable (because it's a void)

3050 pass

3051

3052 # Finalize the fill_value

3053 if self._fill_value is not None:

3054 self._fill_value = _check_fill_value(self._fill_value, self.dtype)

3055 elif self.dtype.names is not None:

3056 # Finalize the default fill_value for structured arrays

3057 self._fill_value = _check_fill_value(None, self.dtype)

3058

3059 def __array_wrap__(self, obj, context=None):

3060 """

3061 Special hook for ufuncs.

3062

3063 Wraps the numpy array and sets the mask according to context.

3064

3065 """

3066 if obj is self: # for in-place operations

3067 result = obj

3068 else:

3069 result = obj.view(type(self))

3070 result._update_from(self)

3071

3072 if context is not None:

3073 result._mask = result._mask.copy()

3074 func, args, out_i = context

3075 # args sometimes contains outputs (gh-10459), which we don't want

3076 input_args = args[:func.nin]

3077 m = reduce(mask_or, [getmaskarray(arg) for arg in input_args])

3078 # Get the domain mask

3079 domain = ufunc_domain.get(func, None)

3080 if domain is not None:

3081 # Take the domain, and make sure it's a ndarray

3082 with np.errstate(divide='ignore', invalid='ignore'):

3083 d = filled(domain(*input_args), True)

3084

3085 if d.any():

3086 # Fill the result where the domain is wrong

3087 try:

3088 # Binary domain: take the last value

3089 fill_value = ufunc_fills[func][-1]

3090 except TypeError:

3091 # Unary domain: just use this one

3092 fill_value = ufunc_fills[func]

3093 except KeyError:

3094 # Domain not recognized, use fill_value instead

3095 fill_value = self.fill_value

3096

3097 np.copyto(result, fill_value, where=d)

3098

3099 # Update the mask

3100 if m is nomask:

3101 m = d

3102 else:

3103 # Don't modify inplace, we risk back-propagation

3104 m = (m | d)

3105

3106 # Make sure the mask has the proper size

3107 if result is not self and result.shape == () and m:

3108 return masked

3109 else:

3110 result._mask = m

3111 result._sharedmask = False

3112

3113 return result

3114

3115 def view(self, dtype=None, type=None, fill_value=None):

3116 """

3117 Return a view of the MaskedArray data.

3118

3119 Parameters

3120 ----------

3121 dtype : data-type or ndarray sub-class, optional

3122 Data-type descriptor of the returned view, e.g., float32 or int16.

3123 The default, None, results in the view having the same data-type

3124 as `a`. As with ``ndarray.view``, dtype can also be specified as

3125 an ndarray sub-class, which then specifies the type of the

3126 returned object (this is equivalent to setting the ``type``

3127 parameter).

3128 type : Python type, optional

3129 Type of the returned view, either ndarray or a subclass. The

3130 default None results in type preservation.

3131 fill_value : scalar, optional

3132 The value to use for invalid entries (None by default).

3133 If None, then this argument is inferred from the passed `dtype`, or

3134 in its absence the original array, as discussed in the notes below.

3135

3136 See Also

3137 --------

3138 numpy.ndarray.view : Equivalent method on ndarray object.

3139

3140 Notes

3141 -----

3142

3143 ``a.view()`` is used two different ways:

3144

3145 ``a.view(some_dtype)`` or ``a.view(dtype=some_dtype)`` constructs a view

3146 of the array's memory with a different data-type. This can cause a

3147 reinterpretation of the bytes of memory.

3148

3149 ``a.view(ndarray_subclass)`` or ``a.view(type=ndarray_subclass)`` just

3150 returns an instance of `ndarray_subclass` that looks at the same array

3151 (same shape, dtype, etc.) This does not cause a reinterpretation of the

3152 memory.

3153

3154 If `fill_value` is not specified, but `dtype` is specified (and is not

3155 an ndarray sub-class), the `fill_value` of the MaskedArray will be

3156 reset. If neither `fill_value` nor `dtype` are specified (or if

3157 `dtype` is an ndarray sub-class), then the fill value is preserved.

3158 Finally, if `fill_value` is specified, but `dtype` is not, the fill

3159 value is set to the specified value.

3160

3161 For ``a.view(some_dtype)``, if ``some_dtype`` has a different number of

3162 bytes per entry than the previous dtype (for example, converting a

3163 regular array to a structured array), then the behavior of the view

3164 cannot be predicted just from the superficial appearance of ``a`` (shown

3165 by ``print(a)``). It also depends on exactly how ``a`` is stored in

3166 memory. Therefore if ``a`` is C-ordered versus fortran-ordered, versus

3167 defined as a slice or transpose, etc., the view may give different

3168 results.

3169 """

3170

3171 if dtype is None:

3172 if type is None:

3173 output = ndarray.view(self)

3174 else:

3175 output = ndarray.view(self, type)

3176 elif type is None:

3177 try:

3178 if issubclass(dtype, ndarray):

3179 output = ndarray.view(self, dtype)

3180 dtype = None

3181 else:

3182 output = ndarray.view(self, dtype)

3183 except TypeError:

3184 output = ndarray.view(self, dtype)

3185 else:

3186 output = ndarray.view(self, dtype, type)

3187

3188 # also make the mask be a view (so attr changes to the view's

3189 # mask do no affect original object's mask)

3190 # (especially important to avoid affecting np.masked singleton)

3191 if getmask(output) is not nomask:

3192 output._mask = output._mask.view()

3193

3194 # Make sure to reset the _fill_value if needed

3195 if getattr(output, '_fill_value', None) is not None:

3196 if fill_value is None:

3197 if dtype is None:

3198 pass # leave _fill_value as is

3199 else:

3200 output._fill_value = None

3201 else:

3202 output.fill_value = fill_value

3203 return output

3204

3205 def __getitem__(self, indx):

3206 """

3207 x.__getitem__(y) <==> x[y]

3208

3209 Return the item described by i, as a masked array.

3210

3211 """

3212 # We could directly use ndarray.__getitem__ on self.

3213 # But then we would have to modify __array_finalize__ to prevent the

3214 # mask of being reshaped if it hasn't been set up properly yet

3215 # So it's easier to stick to the current version

3216 dout = self.data[indx]

3217 _mask = self._mask

3218

3219 def _is_scalar(m):

3220 return not isinstance(m, np.ndarray)

3221

3222 def _scalar_heuristic(arr, elem):

3223 """

3224 Return whether `elem` is a scalar result of indexing `arr`, or None

3225 if undecidable without promoting nomask to a full mask

3226 """

3227 # obviously a scalar

3228 if not isinstance(elem, np.ndarray):

3229 return True

3230

3231 # object array scalar indexing can return anything

3232 elif arr.dtype.type is np.object_:

3233 if arr.dtype is not elem.dtype:

3234 # elem is an array, but dtypes do not match, so must be

3235 # an element

3236 return True

3237

3238 # well-behaved subclass that only returns 0d arrays when

3239 # expected - this is not a scalar

3240 elif type(arr).__getitem__ == ndarray.__getitem__:

3241 return False

3242

3243 return None

3244

3245 if _mask is not nomask:

3246 # _mask cannot be a subclass, so it tells us whether we should

3247 # expect a scalar. It also cannot be of dtype object.

3248 mout = _mask[indx]

3249 scalar_expected = _is_scalar(mout)

3250

3251 else:

3252 # attempt to apply the heuristic to avoid constructing a full mask

3253 mout = nomask

3254 scalar_expected = _scalar_heuristic(self.data, dout)

3255 if scalar_expected is None:

3256 # heuristics have failed

3257 # construct a full array, so we can be certain. This is costly.

3258 # we could also fall back on ndarray.__getitem__(self.data, indx)

3259 scalar_expected = _is_scalar(getmaskarray(self)[indx])

3260

3261 # Did we extract a single item?

3262 if scalar_expected:

3263 # A record

3264 if isinstance(dout, np.void):

3265 # We should always re-cast to mvoid, otherwise users can

3266 # change masks on rows that already have masked values, but not

3267 # on rows that have no masked values, which is inconsistent.

3268 return mvoid(dout, mask=mout, hardmask=self._hardmask)

3269

3270 # special case introduced in gh-5962

3271 elif (self.dtype.type is np.object_ and

3272 isinstance(dout, np.ndarray) and

3273 dout is not masked):

3274 # If masked, turn into a MaskedArray, with everything masked.

3275 if mout:

3276 return MaskedArray(dout, mask=True)

3277 else:

3278 return dout

3279

3280 # Just a scalar

3281 else:

3282 if mout:

3283 return masked

3284 else:

3285 return dout

3286 else:

3287 # Force dout to MA

3288 dout = dout.view(type(self))

3289 # Inherit attributes from self

3290 dout._update_from(self)

3291 # Check the fill_value

3292 if is_string_or_list_of_strings(indx):

3293 if self._fill_value is not None:

3294 dout._fill_value = self._fill_value[indx]

3295

3296 # Something like gh-15895 has happened if this check fails.

3297 # _fill_value should always be an ndarray.

3298 if not isinstance(dout._fill_value, np.ndarray):

3299 raise RuntimeError('Internal NumPy error.')

3300 # If we're indexing a multidimensional field in a

3301 # structured array (such as dtype("(2,)i2,(2,)i1")),

3302 # dimensionality goes up (M[field].ndim == M.ndim +

3303 # M.dtype[field].ndim). That's fine for

3304 # M[field] but problematic for M[field].fill_value

3305 # which should have shape () to avoid breaking several

3306 # methods. There is no great way out, so set to

3307 # first element. See issue #6723.

3308 if dout._fill_value.ndim > 0:

3309 if not (dout._fill_value ==

3310 dout._fill_value.flat[0]).all():

3311 warnings.warn(

3312 "Upon accessing multidimensional field "

3313 f"{indx!s}, need to keep dimensionality "

3314 "of fill_value at 0. Discarding "

3315 "heterogeneous fill_value and setting "

3316 f"all to {dout._fill_value[0]!s}.",

3317 stacklevel=2)

3318 # Need to use `.flat[0:1].squeeze(...)` instead of just

3319 # `.flat[0]` to ensure the result is a 0d array and not

3320 # a scalar.

3321 dout._fill_value = dout._fill_value.flat[0:1].squeeze(axis=0)

3322 dout._isfield = True

3323 # Update the mask if needed

3324 if mout is not nomask:

3325 # set shape to match that of data; this is needed for matrices

3326 dout._mask = reshape(mout, dout.shape)

3327 dout._sharedmask = True

3328 # Note: Don't try to check for m.any(), that'll take too long

3329 return dout

3330

3331 def __setitem__(self, indx, value):

3332 """

3333 x.__setitem__(i, y) <==> x[i]=y

3334

3335 Set item described by index. If value is masked, masks those

3336 locations.

3337

3338 """

3339 if self is masked:

3340 raise MaskError('Cannot alter the masked element.')

3341 _data = self._data

3342 _mask = self._mask

3343 if isinstance(indx, str):

3344 _data[indx] = value

3345 if _mask is nomask:

3346 self._mask = _mask = make_mask_none(self.shape, self.dtype)

3347 _mask[indx] = getmask(value)

3348 return

3349

3350 _dtype = _data.dtype

3351

3352 if value is masked:

3353 # The mask wasn't set: create a full version.

3354 if _mask is nomask:

3355 _mask = self._mask = make_mask_none(self.shape, _dtype)

3356 # Now, set the mask to its value.

3357 if _dtype.names is not None:

3358 _mask[indx] = tuple([True] * len(_dtype.names))

3359 else:

3360 _mask[indx] = True

3361 return

3362

3363 # Get the _data part of the new value

3364 dval = getattr(value, '_data', value)

3365 # Get the _mask part of the new value

3366 mval = getmask(value)

3367 if _dtype.names is not None and mval is nomask:

3368 mval = tuple([False] * len(_dtype.names))

3369 if _mask is nomask:

3370 # Set the data, then the mask

3371 _data[indx] = dval

3372 if mval is not nomask:

3373 _mask = self._mask = make_mask_none(self.shape, _dtype)

3374 _mask[indx] = mval

3375 elif not self._hardmask:

3376 # Set the data, then the mask

3377 if (isinstance(indx, masked_array) and

3378 not isinstance(value, masked_array)):

3379 _data[indx.data] = dval

3380 else:

3381 _data[indx] = dval

3382 _mask[indx] = mval

3383 elif hasattr(indx, 'dtype') and (indx.dtype == MaskType):

3384 indx = indx * umath.logical_not(_mask)

3385 _data[indx] = dval

3386 else:

3387 if _dtype.names is not None:

3388 err_msg = "Flexible 'hard' masks are not yet supported."

3389 raise NotImplementedError(err_msg)

3390 mindx = mask_or(_mask[indx], mval, copy=True)

3391 dindx = self._data[indx]

3392 if dindx.size > 1:

3393 np.copyto(dindx, dval, where=~mindx)

3394 elif mindx is nomask:

3395 dindx = dval

3396 _data[indx] = dindx

3397 _mask[indx] = mindx

3398 return

3399

3400 # Define so that we can overwrite the setter.

3401 @property

3402 def dtype(self):

3403 return super().dtype

3404

3405 @dtype.setter

3406 def dtype(self, dtype):

3407 super(MaskedArray, type(self)).dtype.__set__(self, dtype)

3408 if self._mask is not nomask:

3409 self._mask = self._mask.view(make_mask_descr(dtype), ndarray)

3410 # Try to reset the shape of the mask (if we don't have a void).

3411 # This raises a ValueError if the dtype change won't work.

3412 try:

3413 self._mask.shape = self.shape

3414 except (AttributeError, TypeError):

3415 pass

3416

3417 @property

3418 def shape(self):

3419 return super().shape

3420

3421 @shape.setter

3422 def shape(self, shape):

3423 super(MaskedArray, type(self)).shape.__set__(self, shape)

3424 # Cannot use self._mask, since it may not (yet) exist when a

3425 # masked matrix sets the shape.

3426 if getmask(self) is not nomask:

3427 self._mask.shape = self.shape

3428

3429 def __setmask__(self, mask, copy=False):

3430 """

3431 Set the mask.

3432

3433 """

3434 idtype = self.dtype

3435 current_mask = self._mask

3436 if mask is masked:

3437 mask = True

3438

3439 if current_mask is nomask:

3440 # Make sure the mask is set

3441 # Just don't do anything if there's nothing to do.

3442 if mask is nomask:

3443 return

3444 current_mask = self._mask = make_mask_none(self.shape, idtype)

3445

3446 if idtype.names is None:

3447 # No named fields.

3448 # Hardmask: don't unmask the data

3449 if self._hardmask:

3450 current_mask |= mask

3451 # Softmask: set everything to False

3452 # If it's obviously a compatible scalar, use a quick update

3453 # method.

3454 elif isinstance(mask, (int, float, np.bool_, np.number)):

3455 current_mask[...] = mask

3456 # Otherwise fall back to the slower, general purpose way.

3457 else:

3458 current_mask.flat = mask

3459 else:

3460 # Named fields w/

3461 mdtype = current_mask.dtype

3462 mask = np.array(mask, copy=False)

3463 # Mask is a singleton

3464 if not mask.ndim:

3465 # It's a boolean : make a record

3466 if mask.dtype.kind == 'b':

3467 mask = np.array(tuple([mask.item()] * len(mdtype)),

3468 dtype=mdtype)

3469 # It's a record: make sure the dtype is correct

3470 else:

3471 mask = mask.astype(mdtype)

3472 # Mask is a sequence

3473 else:

3474 # Make sure the new mask is a ndarray with the proper dtype

3475 try:

3476 mask = np.array(mask, copy=copy, dtype=mdtype)

3477 # Or assume it's a sequence of bool/int

3478 except TypeError:

3479 mask = np.array([tuple([m] * len(mdtype)) for m in mask],

3480 dtype=mdtype)

3481 # Hardmask: don't unmask the data

3482 if self._hardmask:

3483 for n in idtype.names:

3484 current_mask[n] |= mask[n]

3485 # Softmask: set everything to False

3486 # If it's obviously a compatible scalar, use a quick update

3487 # method.

3488 elif isinstance(mask, (int, float, np.bool_, np.number)):

3489 current_mask[...] = mask

3490 # Otherwise fall back to the slower, general purpose way.

3491 else:

3492 current_mask.flat = mask

3493 # Reshape if needed

3494 if current_mask.shape:

3495 current_mask.shape = self.shape

3496 return

3497

3498 _set_mask = __setmask__

3499

3500 @property

3501 def mask(self):

3502 """ Current mask. """

3503

3504 # We could try to force a reshape, but that wouldn't work in some

3505 # cases.

3506 # Return a view so that the dtype and shape cannot be changed in place

3507 # This still preserves nomask by identity

3508 return self._mask.view()

3509

3510 @mask.setter

3511 def mask(self, value):

3512 self.__setmask__(value)

3513

3514 @property

3515 def recordmask(self):

3516 """

3517 Get or set the mask of the array if it has no named fields. For

3518 structured arrays, returns a ndarray of booleans where entries are

3519 ``True`` if **all** the fields are masked, ``False`` otherwise:

3520

3521 >>> x = np.ma.array([(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)],

3522 ... mask=[(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)],

3523 ... dtype=[('a', int), ('b', int)])

3524 >>> x.recordmask

3525 array([False, False, True, False, False])

3526 """

3527

3528 _mask = self._mask.view(ndarray)

3529 if _mask.dtype.names is None:

3530 return _mask

3531 return np.all(flatten_structured_array(_mask), axis=-1)

3532

3533 @recordmask.setter

3534 def recordmask(self, mask):

3535 raise NotImplementedError("Coming soon: setting the mask per records!")

3536

3537 def harden_mask(self):

3538 """

3539 Force the mask to hard, preventing unmasking by assignment.

3540

3541 Whether the mask of a masked array is hard or soft is determined by

3542 its `~ma.MaskedArray.hardmask` property. `harden_mask` sets

3543 `~ma.MaskedArray.hardmask` to ``True`` (and returns the modified

3544 self).

3545

3546 See Also

3547 --------

3548 ma.MaskedArray.hardmask

3549 ma.MaskedArray.soften_mask

3550

3551 """

3552 self._hardmask = True

3553 return self

3554

3555 def soften_mask(self):

3556 """

3557 Force the mask to soft (default), allowing unmasking by assignment.

3558

3559 Whether the mask of a masked array is hard or soft is determined by

3560 its `~ma.MaskedArray.hardmask` property. `soften_mask` sets

3561 `~ma.MaskedArray.hardmask` to ``False`` (and returns the modified

3562 self).

3563

3564 See Also

3565 --------

3566 ma.MaskedArray.hardmask

3567 ma.MaskedArray.harden_mask

3568

3569 """

3570 self._hardmask = False

3571 return self

3572

3573 @property

3574 def hardmask(self):

3575 """

3576 Specifies whether values can be unmasked through assignments.

3577

3578 By default, assigning definite values to masked array entries will

3579 unmask them. When `hardmask` is ``True``, the mask will not change

3580 through assignments.

3581

3582 See Also

3583 --------

3584 ma.MaskedArray.harden_mask

3585 ma.MaskedArray.soften_mask

3586

3587 Examples

3588 --------

3589 >>> x = np.arange(10)

3590 >>> m = np.ma.masked_array(x, x>5)

3591 >>> assert not m.hardmask

3592

3593 Since `m` has a soft mask, assigning an element value unmasks that

3594 element:

3595

3596 >>> m[8] = 42

3597 >>> m

3598 masked_array(data=[0, 1, 2, 3, 4, 5, --, --, 42, --],

3599 mask=[False, False, False, False, False, False,

3600 True, True, False, True],

3601 fill_value=999999)

3602

3603 After hardening, the mask is not affected by assignments:

3604

3605 >>> hardened = np.ma.harden_mask(m)

3606 >>> assert m.hardmask and hardened is m

3607 >>> m[:] = 23

3608 >>> m

3609 masked_array(data=[23, 23, 23, 23, 23, 23, --, --, 23, --],

3610 mask=[False, False, False, False, False, False,

3611 True, True, False, True],

3612 fill_value=999999)

3613

3614 """

3615 return self._hardmask

3616

3617 def unshare_mask(self):

3618 """

3619 Copy the mask and set the `sharedmask` flag to ``False``.

3620

3621 Whether the mask is shared between masked arrays can be seen from

3622 the `sharedmask` property. `unshare_mask` ensures the mask is not

3623 shared. A copy of the mask is only made if it was shared.

3624

3625 See Also

3626 --------

3627 sharedmask

3628

3629 """

3630 if self._sharedmask:

3631 self._mask = self._mask.copy()

3632 self._sharedmask = False

3633 return self

3634

3635 @property

3636 def sharedmask(self):

3637 """ Share status of the mask (read-only). """

3638 return self._sharedmask

3639

3640 def shrink_mask(self):

3641 """

3642 Reduce a mask to nomask when possible.

3643

3644 Parameters

3645 ----------

3646 None

3647

3648 Returns

3649 -------

3650 None

3651

3652 Examples

3653 --------

3654 >>> x = np.ma.array([[1,2 ], [3, 4]], mask=[0]*4)

3655 >>> x.mask

3656 array([[False, False],

3657 [False, False]])

3658 >>> x.shrink_mask()

3659 masked_array(

3660 data=[[1, 2],

3661 [3, 4]],

3662 mask=False,

3663 fill_value=999999)

3664 >>> x.mask

3665 False

3666

3667 """

3668 self._mask = _shrink_mask(self._mask)

3669 return self

3670

3671 @property

3672 def baseclass(self):

3673 """ Class of the underlying data (read-only). """

3674 return self._baseclass

3675

3676 def _get_data(self):

3677 """

3678 Returns the underlying data, as a view of the masked array.

3679

3680 If the underlying data is a subclass of :class:`numpy.ndarray`, it is

3681 returned as such.

3682

3683 >>> x = np.ma.array(np.matrix([[1, 2], [3, 4]]), mask=[[0, 1], [1, 0]])

3684 >>> x.data

3685 matrix([[1, 2],

3686 [3, 4]])

3687

3688 The type of the data can be accessed through the :attr:`baseclass`

3689 attribute.

3690 """

3691 return ndarray.view(self, self._baseclass)

3692

3693 _data = property(fget=_get_data)

3694 data = property(fget=_get_data)

3695

3696 @property

3697 def flat(self):

3698 """ Return a flat iterator, or set a flattened version of self to value. """

3699 return MaskedIterator(self)

3700

3701 @flat.setter

3702 def flat(self, value):

3703 y = self.ravel()

3704 y[:] = value

3705

3706 @property

3707 def fill_value(self):

3708 """

3709 The filling value of the masked array is a scalar. When setting, None

3710 will set to a default based on the data type.

3711

3712 Examples

3713 --------

3714 >>> for dt in [np.int32, np.int64, np.float64, np.complex128]:

3715 ... np.ma.array([0, 1], dtype=dt).get_fill_value()

3716 ...

3717 999999

3718 999999

3719 1e+20

3720 (1e+20+0j)

3721

3722 >>> x = np.ma.array([0, 1.], fill_value=-np.inf)

3723 >>> x.fill_value

3724 -inf

3725 >>> x.fill_value = np.pi

3726 >>> x.fill_value

3727 3.1415926535897931 # may vary

3728

3729 Reset to default:

3730

3731 >>> x.fill_value = None

3732 >>> x.fill_value

3733 1e+20

3734

3735 """

3736 if self._fill_value is None:

3737 self._fill_value = _check_fill_value(None, self.dtype)

3738

3739 # Temporary workaround to account for the fact that str and bytes

3740 # scalars cannot be indexed with (), whereas all other numpy

3741 # scalars can. See issues #7259 and #7267.

3742 # The if-block can be removed after #7267 has been fixed.

3743 if isinstance(self._fill_value, ndarray):

3744 return self._fill_value[()]

3745 return self._fill_value

3746

3747 @fill_value.setter

3748 def fill_value(self, value=None):

3749 target = _check_fill_value(value, self.dtype)

3750 if not target.ndim == 0:

3751 # 2019-11-12, 1.18.0

3752 warnings.warn(

3753 "Non-scalar arrays for the fill value are deprecated. Use "

3754 "arrays with scalar values instead. The filled function "

3755 "still supports any array as `fill_value`.",

3756 DeprecationWarning, stacklevel=2)

3757

3758 _fill_value = self._fill_value

3759 if _fill_value is None:

3760 # Create the attribute if it was undefined

3761 self._fill_value = target

3762 else:

3763 # Don't overwrite the attribute, just fill it (for propagation)

3764 _fill_value[()] = target

3765

3766 # kept for compatibility

3767 get_fill_value = fill_value.fget

3768 set_fill_value = fill_value.fset

3769

3770 def filled(self, fill_value=None):

3771 """

3772 Return a copy of self, with masked values filled with a given value.

3773 **However**, if there are no masked values to fill, self will be

3774 returned instead as an ndarray.

3775

3776 Parameters

3777 ----------

3778 fill_value : array_like, optional

3779 The value to use for invalid entries. Can be scalar or non-scalar.

3780 If non-scalar, the resulting ndarray must be broadcastable over

3781 input array. Default is None, in which case, the `fill_value`

3782 attribute of the array is used instead.

3783

3784 Returns

3785 -------

3786 filled_array : ndarray

3787 A copy of ``self`` with invalid entries replaced by *fill_value*

3788 (be it the function argument or the attribute of ``self``), or

3789 ``self`` itself as an ndarray if there are no invalid entries to

3790 be replaced.

3791

3792 Notes

3793 -----

3794 The result is **not** a MaskedArray!

3795

3796 Examples

3797 --------

3798 >>> x = np.ma.array([1,2,3,4,5], mask=[0,0,1,0,1], fill_value=-999)

3799 >>> x.filled()

3800 array([ 1, 2, -999, 4, -999])

3801 >>> x.filled(fill_value=1000)

3802 array([ 1, 2, 1000, 4, 1000])

3803 >>> type(x.filled())

3804 <class 'numpy.ndarray'>

3805

3806 Subclassing is preserved. This means that if, e.g., the data part of

3807 the masked array is a recarray, `filled` returns a recarray:

3808

3809 >>> x = np.array([(-1, 2), (-3, 4)], dtype='i8,i8').view(np.recarray)

3810 >>> m = np.ma.array(x, mask=[(True, False), (False, True)])

3811 >>> m.filled()

3812 rec.array([(999999, 2), ( -3, 999999)],

3813 dtype=[('f0', '<i8'), ('f1', '<i8')])

3814 """

3815 m = self._mask

3816 if m is nomask:

3817 return self._data

3818

3819 if fill_value is None:

3820 fill_value = self.fill_value

3821 else:

3822 fill_value = _check_fill_value(fill_value, self.dtype)

3823

3824 if self is masked_singleton:

3825 return np.asanyarray(fill_value)

3826

3827 if m.dtype.names is not None:

3828 result = self._data.copy('K')

3829 _recursive_filled(result, self._mask, fill_value)

3830 elif not m.any():

3831 return self._data

3832 else:

3833 result = self._data.copy('K')

3834 try:

3835 np.copyto(result, fill_value, where=m)

3836 except (TypeError, AttributeError):

3837 fill_value = narray(fill_value, dtype=object)

3838 d = result.astype(object)

3839 result = np.choose(m, (d, fill_value))

3840 except IndexError:

3841 # ok, if scalar

3842 if self._data.shape:

3843 raise

3844 elif m:

3845 result = np.array(fill_value, dtype=self.dtype)

3846 else:

3847 result = self._data

3848 return result

3849

3850 def compressed(self):

3851 """

3852 Return all the non-masked data as a 1-D array.

3853

3854 Returns

3855 -------

3856 data : ndarray

3857 A new `ndarray` holding the non-masked data is returned.

3858

3859 Notes

3860 -----

3861 The result is **not** a MaskedArray!

3862

3863 Examples

3864 --------

3865 >>> x = np.ma.array(np.arange(5), mask=[0]*2 + [1]*3)

3866 >>> x.compressed()

3867 array([0, 1])

3868 >>> type(x.compressed())

3869 <class 'numpy.ndarray'>

3870

3871 """

3872 data = ndarray.ravel(self._data)

3873 if self._mask is not nomask:

3874 data = data.compress(np.logical_not(ndarray.ravel(self._mask)))

3875 return data

3876

3877 def compress(self, condition, axis=None, out=None):

3878 """

3879 Return `a` where condition is ``True``.

3880

3881 If condition is a `~ma.MaskedArray`, missing values are considered

3882 as ``False``.

3883

3884 Parameters

3885 ----------

3886 condition : var

3887 Boolean 1-d array selecting which entries to return. If len(condition)

3888 is less than the size of a along the axis, then output is truncated

3889 to length of condition array.

3890 axis : {None, int}, optional

3891 Axis along which the operation must be performed.

3892 out : {None, ndarray}, optional

3893 Alternative output array in which to place the result. It must have

3894 the same shape as the expected output but the type will be cast if

3895 necessary.

3896

3897 Returns

3898 -------

3899 result : MaskedArray

3900 A :class:`~ma.MaskedArray` object.

3901

3902 Notes

3903 -----

3904 Please note the difference with :meth:`compressed` !

3905 The output of :meth:`compress` has a mask, the output of

3906 :meth:`compressed` does not.

3907

3908 Examples

3909 --------

3910 >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4)

3911 >>> x

3912 masked_array(

3913 data=[[1, --, 3],

3914 [--, 5, --],

3915 [7, --, 9]],

3916 mask=[[False, True, False],

3917 [ True, False, True],

3918 [False, True, False]],

3919 fill_value=999999)

3920 >>> x.compress([1, 0, 1])

3921 masked_array(data=[1, 3],

3922 mask=[False, False],

3923 fill_value=999999)

3924

3925 >>> x.compress([1, 0, 1], axis=1)

3926 masked_array(

3927 data=[[1, 3],

3928 [--, --],

3929 [7, 9]],

3930 mask=[[False, False],

3931 [ True, True],

3932 [False, False]],

3933 fill_value=999999)

3934

3935 """

3936 # Get the basic components

3937 (_data, _mask) = (self._data, self._mask)

3938

3939 # Force the condition to a regular ndarray and forget the missing

3940 # values.

3941 condition = np.asarray(condition)

3942

3943 _new = _data.compress(condition, axis=axis, out=out).view(type(self))

3944 _new._update_from(self)

3945 if _mask is not nomask:

3946 _new._mask = _mask.compress(condition, axis=axis)

3947 return _new

3948

3949 def _insert_masked_print(self):

3950 """

3951 Replace masked values with masked_print_option, casting all innermost

3952 dtypes to object.

3953 """

3954 if masked_print_option.enabled():

3955 mask = self._mask

3956 if mask is nomask:

3957 res = self._data

3958 else:

3959 # convert to object array to make filled work

3960 data = self._data

3961 # For big arrays, to avoid a costly conversion to the

3962 # object dtype, extract the corners before the conversion.

3963 print_width = (self._print_width if self.ndim > 1

3964 else self._print_width_1d)

3965 for axis in range(self.ndim):

3966 if data.shape[axis] > print_width:

3967 ind = print_width // 2

3968 arr = np.split(data, (ind, -ind), axis=axis)

3969 data = np.concatenate((arr[0], arr[2]), axis=axis)

3970 arr = np.split(mask, (ind, -ind), axis=axis)

3971 mask = np.concatenate((arr[0], arr[2]), axis=axis)

3972

3973 rdtype = _replace_dtype_fields(self.dtype, "O")

3974 res = data.astype(rdtype)

3975 _recursive_printoption(res, mask, masked_print_option)

3976 else:

3977 res = self.filled(self.fill_value)

3978 return res

3979

3980 def __str__(self):

3981 return str(self._insert_masked_print())

3982

3983 def __repr__(self):

3984 """

3985 Literal string representation.

3986

3987 """

3988 if self._baseclass is np.ndarray:

3989 name = 'array'

3990 else:

3991 name = self._baseclass.__name__

3992

3993

3994 # 2016-11-19: Demoted to legacy format

3995 if np.core.arrayprint._get_legacy_print_mode() <= 113:

3996 is_long = self.ndim > 1

3997 parameters = dict(

3998 name=name,

3999 nlen=" " * len(name),

4000 data=str(self),

4001 mask=str(self._mask),

4002 fill=str(self.fill_value),

4003 dtype=str(self.dtype)

4004 )

4005 is_structured = bool(self.dtype.names)

4006 key = '{}_{}'.format(

4007 'long' if is_long else 'short',

4008 'flx' if is_structured else 'std'

4009 )

4010 return _legacy_print_templates[key] % parameters

4011

4012 prefix = f"masked_{name}("

4013

4014 dtype_needed = (

4015 not np.core.arrayprint.dtype_is_implied(self.dtype) or

4016 np.all(self.mask) or

4017 self.size == 0

4018 )

4019

4020 # determine which keyword args need to be shown

4021 keys = ['data', 'mask', 'fill_value']

4022 if dtype_needed:

4023 keys.append('dtype')

4024

4025 # array has only one row (non-column)

4026 is_one_row = builtins.all(dim == 1 for dim in self.shape[:-1])

4027

4028 # choose what to indent each keyword with

4029 min_indent = 2

4030 if is_one_row:

4031 # first key on the same line as the type, remaining keys

4032 # aligned by equals

4033 indents = {}

4034 indents[keys[0]] = prefix

4035 for k in keys[1:]:

4036 n = builtins.max(min_indent, len(prefix + keys[0]) - len(k))

4037 indents[k] = ' ' * n

4038 prefix = '' # absorbed into the first indent

4039 else:

4040 # each key on its own line, indented by two spaces

4041 indents = {k: ' ' * min_indent for k in keys}

4042 prefix = prefix + '\n' # first key on the next line

4043

4044 # format the field values

4045 reprs = {}

4046 reprs['data'] = np.array2string(

4047 self._insert_masked_print(),

4048 separator=", ",

4049 prefix=indents['data'] + 'data=',

4050 suffix=',')

4051 reprs['mask'] = np.array2string(

4052 self._mask,

4053 separator=", ",

4054 prefix=indents['mask'] + 'mask=',

4055 suffix=',')

4056 reprs['fill_value'] = repr(self.fill_value)

4057 if dtype_needed:

4058 reprs['dtype'] = np.core.arrayprint.dtype_short_repr(self.dtype)

4059

4060 # join keys with values and indentations

4061 result = ',\n'.join(

4062 '{}{}={}'.format(indents[k], k, reprs[k])

4063 for k in keys

4064 )

4065 return prefix + result + ')'

4066

4067 def _delegate_binop(self, other):

4068 # This emulates the logic in

4069 # private/binop_override.h:forward_binop_should_defer

4070 if isinstance(other, type(self)):

4071 return False

4072 array_ufunc = getattr(other, "__array_ufunc__", False)

4073 if array_ufunc is False:

4074 other_priority = getattr(other, "__array_priority__", -1000000)

4075 return self.__array_priority__ < other_priority

4076 else:

4077 # If array_ufunc is not None, it will be called inside the ufunc;

4078 # None explicitly tells us to not call the ufunc, i.e., defer.

4079 return array_ufunc is None

4080

4081 def _comparison(self, other, compare):

4082 """Compare self with other using operator.eq or operator.ne.

4083

4084 When either of the elements is masked, the result is masked as well,

4085 but the underlying boolean data are still set, with self and other

4086 considered equal if both are masked, and unequal otherwise.

4087

4088 For structured arrays, all fields are combined, with masked values

4089 ignored. The result is masked if all fields were masked, with self

4090 and other considered equal only if both were fully masked.

4091 """

4092 omask = getmask(other)

4093 smask = self.mask

4094 mask = mask_or(smask, omask, copy=True)

4095

4096 odata = getdata(other)

4097 if mask.dtype.names is not None:

4098 # only == and != are reasonably defined for structured dtypes,

4099 # so give up early for all other comparisons:

4100 if compare not in (operator.eq, operator.ne):

4101 return NotImplemented

4102 # For possibly masked structured arrays we need to be careful,

4103 # since the standard structured array comparison will use all

4104 # fields, masked or not. To avoid masked fields influencing the

4105 # outcome, we set all masked fields in self to other, so they'll

4106 # count as equal. To prepare, we ensure we have the right shape.

4107 broadcast_shape = np.broadcast(self, odata).shape

4108 sbroadcast = np.broadcast_to(self, broadcast_shape, subok=True)

4109 sbroadcast._mask = mask

4110 sdata = sbroadcast.filled(odata)

4111 # Now take care of the mask; the merged mask should have an item

4112 # masked if all fields were masked (in one and/or other).

4113 mask = (mask == np.ones((), mask.dtype))

4114

4115 else:

4116 # For regular arrays, just use the data as they come.

4117 sdata = self.data

4118

4119 check = compare(sdata, odata)

4120

4121 if isinstance(check, (np.bool_, bool)):

4122 return masked if mask else check

4123

4124 if mask is not nomask and compare in (operator.eq, operator.ne):

4125 # Adjust elements that were masked, which should be treated

4126 # as equal if masked in both, unequal if masked in one.

4127 # Note that this works automatically for structured arrays too.

4128 # Ignore this for operations other than `==` and `!=`

4129 check = np.where(mask, compare(smask, omask), check)

4130 if mask.shape != check.shape:

4131 # Guarantee consistency of the shape, making a copy since the

4132 # the mask may need to get written to later.

4133 mask = np.broadcast_to(mask, check.shape).copy()

4134

4135 check = check.view(type(self))

4136 check._update_from(self)

4137 check._mask = mask

4138

4139 # Cast fill value to bool_ if needed. If it cannot be cast, the

4140 # default boolean fill value is used.

4141 if check._fill_value is not None:

4142 try:

4143 fill = _check_fill_value(check._fill_value, np.bool_)

4144 except (TypeError, ValueError):

4145 fill = _check_fill_value(None, np.bool_)

4146 check._fill_value = fill

4147

4148 return check

4149

4150 def __eq__(self, other):

4151 """Check whether other equals self elementwise.

4152

4153 When either of the elements is masked, the result is masked as well,

4154 but the underlying boolean data are still set, with self and other

4155 considered equal if both are masked, and unequal otherwise.

4156

4157 For structured arrays, all fields are combined, with masked values

4158 ignored. The result is masked if all fields were masked, with self

4159 and other considered equal only if both were fully masked.

4160 """

4161 return self._comparison(other, operator.eq)

4162

4163 def __ne__(self, other):

4164 """Check whether other does not equal self elementwise.

4165

4166 When either of the elements is masked, the result is masked as well,

4167 but the underlying boolean data are still set, with self and other

4168 considered equal if both are masked, and unequal otherwise.

4169

4170 For structured arrays, all fields are combined, with masked values

4171 ignored. The result is masked if all fields were masked, with self

4172 and other considered equal only if both were fully masked.

4173 """

4174 return self._comparison(other, operator.ne)

4175

4176 # All other comparisons:

4177 def __le__(self, other):

4178 return self._comparison(other, operator.le)

4179

4180 def __lt__(self, other):

4181 return self._comparison(other, operator.lt)

4182

4183 def __ge__(self, other):

4184 return self._comparison(other, operator.ge)

4185

4186 def __gt__(self, other):

4187 return self._comparison(other, operator.gt)

4188

4189 def __add__(self, other):

4190 """

4191 Add self to other, and return a new masked array.

4192

4193 """

4194 if self._delegate_binop(other):

4195 return NotImplemented

4196 return add(self, other)

4197

4198 def __radd__(self, other):

4199 """

4200 Add other to self, and return a new masked array.

4201

4202 """

4203 # In analogy with __rsub__ and __rdiv__, use original order:

4204 # we get here from `other + self`.

4205 return add(other, self)

4206

4207 def __sub__(self, other):

4208 """

4209 Subtract other from self, and return a new masked array.

4210

4211 """

4212 if self._delegate_binop(other):

4213 return NotImplemented

4214 return subtract(self, other)

4215

4216 def __rsub__(self, other):

4217 """

4218 Subtract self from other, and return a new masked array.

4219

4220 """

4221 return subtract(other, self)

4222

4223 def __mul__(self, other):

4224 "Multiply self by other, and return a new masked array."

4225 if self._delegate_binop(other):

4226 return NotImplemented

4227 return multiply(self, other)

4228

4229 def __rmul__(self, other):

4230 """

4231 Multiply other by self, and return a new masked array.

4232

4233 """

4234 # In analogy with __rsub__ and __rdiv__, use original order:

4235 # we get here from `other * self`.

4236 return multiply(other, self)

4237

4238 def __div__(self, other):

4239 """

4240 Divide other into self, and return a new masked array.

4241

4242 """

4243 if self._delegate_binop(other):

4244 return NotImplemented

4245 return divide(self, other)

4246

4247 def __truediv__(self, other):

4248 """

4249 Divide other into self, and return a new masked array.

4250

4251 """

4252 if self._delegate_binop(other):

4253 return NotImplemented

4254 return true_divide(self, other)

4255

4256 def __rtruediv__(self, other):

4257 """

4258 Divide self into other, and return a new masked array.

4259

4260 """

4261 return true_divide(other, self)

4262

4263 def __floordiv__(self, other):

4264 """

4265 Divide other into self, and return a new masked array.

4266

4267 """

4268 if self._delegate_binop(other):

4269 return NotImplemented

4270 return floor_divide(self, other)

4271

4272 def __rfloordiv__(self, other):

4273 """

4274 Divide self into other, and return a new masked array.

4275

4276 """

4277 return floor_divide(other, self)

4278

4279 def __pow__(self, other):

4280 """

4281 Raise self to the power other, masking the potential NaNs/Infs

4282

4283 """

4284 if self._delegate_binop(other):

4285 return NotImplemented

4286 return power(self, other)

4287

4288 def __rpow__(self, other):

4289 """

4290 Raise other to the power self, masking the potential NaNs/Infs

4291

4292 """

4293 return power(other, self)

4294

4295 def __iadd__(self, other):

4296 """

4297 Add other to self in-place.

4298

4299 """

4300 m = getmask(other)

4301 if self._mask is nomask:

4302 if m is not nomask and m.any():

4303 self._mask = make_mask_none(self.shape, self.dtype)

4304 self._mask += m

4305 else:

4306 if m is not nomask:

4307 self._mask += m

4308 other_data = getdata(other)

4309 other_data = np.where(self._mask, other_data.dtype.type(0), other_data)

4310 self._data.__iadd__(other_data)

4311 return self

4312

4313 def __isub__(self, other):

4314 """

4315 Subtract other from self in-place.

4316

4317 """

4318 m = getmask(other)

4319 if self._mask is nomask:

4320 if m is not nomask and m.any():

4321 self._mask = make_mask_none(self.shape, self.dtype)

4322 self._mask += m

4323 elif m is not nomask:

4324 self._mask += m

4325 other_data = getdata(other)

4326 other_data = np.where(self._mask, other_data.dtype.type(0), other_data)

4327 self._data.__isub__(other_data)

4328 return self

4329

4330 def __imul__(self, other):

4331 """

4332 Multiply self by other in-place.

4333

4334 """

4335 m = getmask(other)

4336 if self._mask is nomask:

4337 if m is not nomask and m.any():

4338 self._mask = make_mask_none(self.shape, self.dtype)

4339 self._mask += m

4340 elif m is not nomask:

4341 self._mask += m

4342 other_data = getdata(other)

4343 other_data = np.where(self._mask, other_data.dtype.type(1), other_data)

4344 self._data.__imul__(other_data)

4345 return self

4346

4347 def __idiv__(self, other):

4348 """

4349 Divide self by other in-place.

4350

4351 """

4352 other_data = getdata(other)

4353 dom_mask = _DomainSafeDivide().__call__(self._data, other_data)

4354 other_mask = getmask(other)

4355 new_mask = mask_or(other_mask, dom_mask)

4356 # The following 4 lines control the domain filling

4357 if dom_mask.any():

4358 (_, fval) = ufunc_fills[np.divide]

4359 other_data = np.where(

4360 dom_mask, other_data.dtype.type(fval), other_data)

4361 self._mask |= new_mask

4362 other_data = np.where(self._mask, other_data.dtype.type(1), other_data)

4363 self._data.__idiv__(other_data)

4364 return self

4365

4366 def __ifloordiv__(self, other):

4367 """

4368 Floor divide self by other in-place.

4369

4370 """

4371 other_data = getdata(other)

4372 dom_mask = _DomainSafeDivide().__call__(self._data, other_data)

4373 other_mask = getmask(other)

4374 new_mask = mask_or(other_mask, dom_mask)

4375 # The following 3 lines control the domain filling

4376 if dom_mask.any():

4377 (_, fval) = ufunc_fills[np.floor_divide]

4378 other_data = np.where(

4379 dom_mask, other_data.dtype.type(fval), other_data)

4380 self._mask |= new_mask

4381 other_data = np.where(self._mask, other_data.dtype.type(1), other_data)

4382 self._data.__ifloordiv__(other_data)

4383 return self

4384

4385 def __itruediv__(self, other):

4386 """

4387 True divide self by other in-place.

4388

4389 """

4390 other_data = getdata(other)

4391 dom_mask = _DomainSafeDivide().__call__(self._data, other_data)

4392 other_mask = getmask(other)

4393 new_mask = mask_or(other_mask, dom_mask)

4394 # The following 3 lines control the domain filling

4395 if dom_mask.any():

4396 (_, fval) = ufunc_fills[np.true_divide]

4397 other_data = np.where(

4398 dom_mask, other_data.dtype.type(fval), other_data)

4399 self._mask |= new_mask

4400 other_data = np.where(self._mask, other_data.dtype.type(1), other_data)

4401 self._data.__itruediv__(other_data)

4402 return self

4403

4404 def __ipow__(self, other):

4405 """

4406 Raise self to the power other, in place.

4407

4408 """

4409 other_data = getdata(other)

4410 other_data = np.where(self._mask, other_data.dtype.type(1), other_data)

4411 other_mask = getmask(other)

4412 with np.errstate(divide='ignore', invalid='ignore'):

4413 self._data.__ipow__(other_data)

4414 invalid = np.logical_not(np.isfinite(self._data))

4415 if invalid.any():

4416 if self._mask is not nomask:

4417 self._mask |= invalid

4418 else:

4419 self._mask = invalid

4420 np.copyto(self._data, self.fill_value, where=invalid)

4421 new_mask = mask_or(other_mask, invalid)

4422 self._mask = mask_or(self._mask, new_mask)

4423 return self

4424

4425 def __float__(self):

4426 """

4427 Convert to float.

4428

4429 """

4430 if self.size > 1:

4431 raise TypeError("Only length-1 arrays can be converted "

4432 "to Python scalars")

4433 elif self._mask:

4434 warnings.warn("Warning: converting a masked element to nan.", stacklevel=2)

4435 return np.nan

4436 return float(self.item())

4437

4438 def __int__(self):

4439 """

4440 Convert to int.

4441

4442 """

4443 if self.size > 1:

4444 raise TypeError("Only length-1 arrays can be converted "

4445 "to Python scalars")

4446 elif self._mask:

4447 raise MaskError('Cannot convert masked element to a Python int.')

4448 return int(self.item())

4449

4450 @property

4451 def imag(self):

4452 """

4453 The imaginary part of the masked array.

4454

4455 This property is a view on the imaginary part of this `MaskedArray`.

4456

4457 See Also

4458 --------

4459 real

4460

4461 Examples

4462 --------

4463 >>> x = np.ma.array([1+1.j, -2j, 3.45+1.6j], mask=[False, True, False])

4464 >>> x.imag

4465 masked_array(data=[1.0, --, 1.6],

4466 mask=[False, True, False],

4467 fill_value=1e+20)

4468

4469 """

4470 result = self._data.imag.view(type(self))

4471 result.__setmask__(self._mask)

4472 return result

4473

4474 # kept for compatibility

4475 get_imag = imag.fget

4476

4477 @property

4478 def real(self):

4479 """

4480 The real part of the masked array.

4481

4482 This property is a view on the real part of this `MaskedArray`.

4483

4484 See Also

4485 --------

4486 imag

4487

4488 Examples

4489 --------

4490 >>> x = np.ma.array([1+1.j, -2j, 3.45+1.6j], mask=[False, True, False])

4491 >>> x.real

4492 masked_array(data=[1.0, --, 3.45],

4493 mask=[False, True, False],

4494 fill_value=1e+20)

4495

4496 """

4497 result = self._data.real.view(type(self))

4498 result.__setmask__(self._mask)

4499 return result

4500

4501 # kept for compatibility

4502 get_real = real.fget

4503

4504 def count(self, axis=None, keepdims=np._NoValue):

4505 """

4506 Count the non-masked elements of the array along the given axis.

4507

4508 Parameters

4509 ----------

4510 axis : None or int or tuple of ints, optional

4511 Axis or axes along which the count is performed.

4512 The default, None, performs the count over all

4513 the dimensions of the input array. `axis` may be negative, in

4514 which case it counts from the last to the first axis.

4515

4516 .. versionadded:: 1.10.0

4517

4518 If this is a tuple of ints, the count is performed on multiple

4519 axes, instead of a single axis or all the axes as before.

4520 keepdims : bool, optional

4521 If this is set to True, the axes which are reduced are left

4522 in the result as dimensions with size one. With this option,

4523 the result will broadcast correctly against the array.

4524

4525 Returns

4526 -------

4527 result : ndarray or scalar

4528 An array with the same shape as the input array, with the specified

4529 axis removed. If the array is a 0-d array, or if `axis` is None, a

4530 scalar is returned.

4531

4532 See Also

4533 --------

4534 ma.count_masked : Count masked elements in array or along a given axis.

4535

4536 Examples

4537 --------

4538 >>> import numpy.ma as ma

4539 >>> a = ma.arange(6).reshape((2, 3))

4540 >>> a[1, :] = ma.masked

4541 >>> a

4542 masked_array(

4543 data=[[0, 1, 2],

4544 [--, --, --]],

4545 mask=[[False, False, False],

4546 [ True, True, True]],

4547 fill_value=999999)

4548 >>> a.count()

4549 3

4550

4551 When the `axis` keyword is specified an array of appropriate size is

4552 returned.

4553

4554 >>> a.count(axis=0)

4555 array([1, 1, 1])

4556 >>> a.count(axis=1)

4557 array([3, 0])

4558

4559 """

4560 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}

4561

4562 m = self._mask

4563 # special case for matrices (we assume no other subclasses modify

4564 # their dimensions)

4565 if isinstance(self.data, np.matrix):

4566 if m is nomask:

4567 m = np.zeros(self.shape, dtype=np.bool_)

4568 m = m.view(type(self.data))

4569

4570 if m is nomask:

4571 # compare to _count_reduce_items in _methods.py

4572

4573 if self.shape == ():

4574 if axis not in (None, 0):

4575 raise np.AxisError(axis=axis, ndim=self.ndim)

4576 return 1

4577 elif axis is None:

4578 if kwargs.get('keepdims', False):

4579 return np.array(self.size, dtype=np.intp, ndmin=self.ndim)

4580 return self.size

4581

4582 axes = normalize_axis_tuple(axis, self.ndim)

4583 items = 1

4584 for ax in axes:

4585 items *= self.shape[ax]

4586

4587 if kwargs.get('keepdims', False):

4588 out_dims = list(self.shape)

4589 for a in axes:

4590 out_dims[a] = 1

4591 else:

4592 out_dims = [d for n, d in enumerate(self.shape)

4593 if n not in axes]

4594 # make sure to return a 0-d array if axis is supplied

4595 return np.full(out_dims, items, dtype=np.intp)

4596

4597 # take care of the masked singleton

4598 if self is masked:

4599 return 0

4600

4601 return (~m).sum(axis=axis, dtype=np.intp, **kwargs)

4602

4603 def ravel(self, order='C'):

4604 """

4605 Returns a 1D version of self, as a view.

4606

4607 Parameters

4608 ----------

4609 order : {'C', 'F', 'A', 'K'}, optional

4610 The elements of `a` are read using this index order. 'C' means to

4611 index the elements in C-like order, with the last axis index

4612 changing fastest, back to the first axis index changing slowest.

4613 'F' means to index the elements in Fortran-like index order, with

4614 the first index changing fastest, and the last index changing

4615 slowest. Note that the 'C' and 'F' options take no account of the

4616 memory layout of the underlying array, and only refer to the order

4617 of axis indexing. 'A' means to read the elements in Fortran-like

4618 index order if `m` is Fortran *contiguous* in memory, C-like order

4619 otherwise. 'K' means to read the elements in the order they occur

4620 in memory, except for reversing the data when strides are negative.

4621 By default, 'C' index order is used.

4622

4623 Returns

4624 -------

4625 MaskedArray

4626 Output view is of shape ``(self.size,)`` (or

4627 ``(np.ma.product(self.shape),)``).

4628

4629 Examples

4630 --------

4631 >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4)

4632 >>> x

4633 masked_array(

4634 data=[[1, --, 3],

4635 [--, 5, --],

4636 [7, --, 9]],

4637 mask=[[False, True, False],

4638 [ True, False, True],

4639 [False, True, False]],

4640 fill_value=999999)

4641 >>> x.ravel()

4642 masked_array(data=[1, --, 3, --, 5, --, 7, --, 9],

4643 mask=[False, True, False, True, False, True, False, True,

4644 False],

4645 fill_value=999999)

4646

4647 """

4648 r = ndarray.ravel(self._data, order=order).view(type(self))

4649 r._update_from(self)

4650 if self._mask is not nomask:

4651 r._mask = ndarray.ravel(self._mask, order=order).reshape(r.shape)

4652 else:

4653 r._mask = nomask

4654 return r

4655

4656

4657 def reshape(self, *s, **kwargs):

4658 """

4659 Give a new shape to the array without changing its data.

4660

4661 Returns a masked array containing the same data, but with a new shape.

4662 The result is a view on the original array; if this is not possible, a

4663 ValueError is raised.

4664

4665 Parameters

4666 ----------

4667 shape : int or tuple of ints

4668 The new shape should be compatible with the original shape. If an

4669 integer is supplied, then the result will be a 1-D array of that

4670 length.

4671 order : {'C', 'F'}, optional

4672 Determines whether the array data should be viewed as in C

4673 (row-major) or FORTRAN (column-major) order.

4674

4675 Returns

4676 -------

4677 reshaped_array : array

4678 A new view on the array.

4679

4680 See Also

4681 --------

4682 reshape : Equivalent function in the masked array module.

4683 numpy.ndarray.reshape : Equivalent method on ndarray object.

4684 numpy.reshape : Equivalent function in the NumPy module.

4685

4686 Notes

4687 -----

4688 The reshaping operation cannot guarantee that a copy will not be made,

4689 to modify the shape in place, use ``a.shape = s``

4690

4691 Examples

4692 --------

4693 >>> x = np.ma.array([[1,2],[3,4]], mask=[1,0,0,1])

4694 >>> x

4695 masked_array(

4696 data=[[--, 2],

4697 [3, --]],

4698 mask=[[ True, False],

4699 [False, True]],

4700 fill_value=999999)

4701 >>> x = x.reshape((4,1))

4702 >>> x

4703 masked_array(

4704 data=[[--],

4705 [2],

4706 [3],

4707 [--]],

4708 mask=[[ True],

4709 [False],

4710 [False],

4711 [ True]],

4712 fill_value=999999)

4713

4714 """

4715 kwargs.update(order=kwargs.get('order', 'C'))

4716 result = self._data.reshape(*s, **kwargs).view(type(self))

4717 result._update_from(self)

4718 mask = self._mask

4719 if mask is not nomask:

4720 result._mask = mask.reshape(*s, **kwargs)

4721 return result

4722

4723 def resize(self, newshape, refcheck=True, order=False):

4724 """

4725 .. warning::

4726

4727 This method does nothing, except raise a ValueError exception. A

4728 masked array does not own its data and therefore cannot safely be

4729 resized in place. Use the `numpy.ma.resize` function instead.

4730

4731 This method is difficult to implement safely and may be deprecated in

4732 future releases of NumPy.

4733

4734 """

4735 # Note : the 'order' keyword looks broken, let's just drop it

4736 errmsg = "A masked array does not own its data "\

4737 "and therefore cannot be resized.\n" \

4738 "Use the numpy.ma.resize function instead."

4739 raise ValueError(errmsg)

4740

4741 def put(self, indices, values, mode='raise'):

4742 """

4743 Set storage-indexed locations to corresponding values.

4744

4745 Sets self._data.flat[n] = values[n] for each n in indices.

4746 If `values` is shorter than `indices` then it will repeat.

4747 If `values` has some masked values, the initial mask is updated

4748 in consequence, else the corresponding values are unmasked.

4749

4750 Parameters

4751 ----------

4752 indices : 1-D array_like

4753 Target indices, interpreted as integers.

4754 values : array_like

4755 Values to place in self._data copy at target indices.

4756 mode : {'raise', 'wrap', 'clip'}, optional

4757 Specifies how out-of-bounds indices will behave.

4758 'raise' : raise an error.

4759 'wrap' : wrap around.

4760 'clip' : clip to the range.

4761

4762 Notes

4763 -----

4764 `values` can be a scalar or length 1 array.

4765

4766 Examples

4767 --------

4768 >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4)

4769 >>> x

4770 masked_array(

4771 data=[[1, --, 3],

4772 [--, 5, --],

4773 [7, --, 9]],

4774 mask=[[False, True, False],

4775 [ True, False, True],

4776 [False, True, False]],

4777 fill_value=999999)

4778 >>> x.put([0,4,8],[10,20,30])

4779 >>> x

4780 masked_array(

4781 data=[[10, --, 3],

4782 [--, 20, --],

4783 [7, --, 30]],

4784 mask=[[False, True, False],

4785 [ True, False, True],

4786 [False, True, False]],

4787 fill_value=999999)

4788

4789 >>> x.put(4,999)

4790 >>> x

4791 masked_array(

4792 data=[[10, --, 3],

4793 [--, 999, --],

4794 [7, --, 30]],

4795 mask=[[False, True, False],

4796 [ True, False, True],

4797 [False, True, False]],

4798 fill_value=999999)

4799

4800 """

4801 # Hard mask: Get rid of the values/indices that fall on masked data

4802 if self._hardmask and self._mask is not nomask:

4803 mask = self._mask[indices]

4804 indices = narray(indices, copy=False)

4805 values = narray(values, copy=False, subok=True)

4806 values.resize(indices.shape)

4807 indices = indices[~mask]

4808 values = values[~mask]

4809

4810 self._data.put(indices, values, mode=mode)

4811

4812 # short circuit if neither self nor values are masked

4813 if self._mask is nomask and getmask(values) is nomask:

4814 return

4815

4816 m = getmaskarray(self)

4817

4818 if getmask(values) is nomask:

4819 m.put(indices, False, mode=mode)

4820 else:

4821 m.put(indices, values._mask, mode=mode)

4822 m = make_mask(m, copy=False, shrink=True)

4823 self._mask = m

4824 return

4825

4826 def ids(self):

4827 """

4828 Return the addresses of the data and mask areas.

4829

4830 Parameters

4831 ----------

4832 None

4833

4834 Examples

4835 --------

4836 >>> x = np.ma.array([1, 2, 3], mask=[0, 1, 1])

4837 >>> x.ids()

4838 (166670640, 166659832) # may vary

4839

4840 If the array has no mask, the address of `nomask` is returned. This address

4841 is typically not close to the data in memory:

4842

4843 >>> x = np.ma.array([1, 2, 3])

4844 >>> x.ids()

4845 (166691080, 3083169284) # may vary

4846

4847 """

4848 if self._mask is nomask:

4849 return (self.ctypes.data, id(nomask))

4850 return (self.ctypes.data, self._mask.ctypes.data)

4851

4852 def iscontiguous(self):

4853 """

4854 Return a boolean indicating whether the data is contiguous.

4855

4856 Parameters

4857 ----------

4858 None

4859

4860 Examples

4861 --------

4862 >>> x = np.ma.array([1, 2, 3])

4863 >>> x.iscontiguous()

4864 True

4865

4866 `iscontiguous` returns one of the flags of the masked array:

4867

4868 >>> x.flags

4869 C_CONTIGUOUS : True

4870 F_CONTIGUOUS : True

4871 OWNDATA : False

4872 WRITEABLE : True

4873 ALIGNED : True

4874 WRITEBACKIFCOPY : False

4875

4876 """

4877 return self.flags['CONTIGUOUS']

4878

4879 def all(self, axis=None, out=None, keepdims=np._NoValue):

4880 """

4881 Returns True if all elements evaluate to True.

4882

4883 The output array is masked where all the values along the given axis

4884 are masked: if the output would have been a scalar and that all the

4885 values are masked, then the output is `masked`.

4886

4887 Refer to `numpy.all` for full documentation.

4888

4889 See Also

4890 --------

4891 numpy.ndarray.all : corresponding function for ndarrays

4892 numpy.all : equivalent function

4893

4894 Examples

4895 --------

4896 >>> np.ma.array([1,2,3]).all()

4897 True

4898 >>> a = np.ma.array([1,2,3], mask=True)

4899 >>> (a.all() is np.ma.masked)

4900 True

4901

4902 """

4903 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}

4904

4905 mask = _check_mask_axis(self._mask, axis, **kwargs)

4906 if out is None:

4907 d = self.filled(True).all(axis=axis, **kwargs).view(type(self))

4908 if d.ndim:

4909 d.__setmask__(mask)

4910 elif mask:

4911 return masked

4912 return d

4913 self.filled(True).all(axis=axis, out=out, **kwargs)

4914 if isinstance(out, MaskedArray):

4915 if out.ndim or mask:

4916 out.__setmask__(mask)

4917 return out

4918

4919 def any(self, axis=None, out=None, keepdims=np._NoValue):

4920 """

4921 Returns True if any of the elements of `a` evaluate to True.

4922

4923 Masked values are considered as False during computation.

4924

4925 Refer to `numpy.any` for full documentation.

4926

4927 See Also

4928 --------

4929 numpy.ndarray.any : corresponding function for ndarrays

4930 numpy.any : equivalent function

4931

4932 """

4933 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}

4934

4935 mask = _check_mask_axis(self._mask, axis, **kwargs)

4936 if out is None:

4937 d = self.filled(False).any(axis=axis, **kwargs).view(type(self))

4938 if d.ndim:

4939 d.__setmask__(mask)

4940 elif mask:

4941 d = masked

4942 return d

4943 self.filled(False).any(axis=axis, out=out, **kwargs)

4944 if isinstance(out, MaskedArray):

4945 if out.ndim or mask:

4946 out.__setmask__(mask)

4947 return out

4948

4949 def nonzero(self):

4950 """

4951 Return the indices of unmasked elements that are not zero.

4952

4953 Returns a tuple of arrays, one for each dimension, containing the

4954 indices of the non-zero elements in that dimension. The corresponding

4955 non-zero values can be obtained with::

4956

4957 a[a.nonzero()]

4958

4959 To group the indices by element, rather than dimension, use

4960 instead::

4961

4962 np.transpose(a.nonzero())

4963

4964 The result of this is always a 2d array, with a row for each non-zero

4965 element.

4966

4967 Parameters

4968 ----------

4969 None

4970

4971 Returns

4972 -------

4973 tuple_of_arrays : tuple

4974 Indices of elements that are non-zero.

4975

4976 See Also

4977 --------

4978 numpy.nonzero :

4979 Function operating on ndarrays.

4980 flatnonzero :

4981 Return indices that are non-zero in the flattened version of the input

4982 array.

4983 numpy.ndarray.nonzero :

4984 Equivalent ndarray method.

4985 count_nonzero :

4986 Counts the number of non-zero elements in the input array.

4987

4988 Examples

4989 --------

4990 >>> import numpy.ma as ma

4991 >>> x = ma.array(np.eye(3))

4992 >>> x

4993 masked_array(

4994 data=[[1., 0., 0.],

4995 [0., 1., 0.],

4996 [0., 0., 1.]],

4997 mask=False,

4998 fill_value=1e+20)

4999 >>> x.nonzero()

5000 (array([0, 1, 2]), array([0, 1, 2]))

5001

5002 Masked elements are ignored.

5003

5004 >>> x[1, 1] = ma.masked

5005 >>> x

5006 masked_array(

5007 data=[[1.0, 0.0, 0.0],

5008 [0.0, --, 0.0],

5009 [0.0, 0.0, 1.0]],

5010 mask=[[False, False, False],

5011 [False, True, False],

5012 [False, False, False]],

5013 fill_value=1e+20)

5014 >>> x.nonzero()

5015 (array([0, 2]), array([0, 2]))

5016

5017 Indices can also be grouped by element.

5018

5019 >>> np.transpose(x.nonzero())

5020 array([[0, 0],

5021 [2, 2]])

5022

5023 A common use for ``nonzero`` is to find the indices of an array, where

5024 a condition is True. Given an array `a`, the condition `a` > 3 is a

5025 boolean array and since False is interpreted as 0, ma.nonzero(a > 3)

5026 yields the indices of the `a` where the condition is true.

5027

5028 >>> a = ma.array([[1,2,3],[4,5,6],[7,8,9]])

5029 >>> a > 3

5030 masked_array(

5031 data=[[False, False, False],

5032 [ True, True, True],

5033 [ True, True, True]],

5034 mask=False,

5035 fill_value=True)

5036 >>> ma.nonzero(a > 3)

5037 (array([1, 1, 1, 2, 2, 2]), array([0, 1, 2, 0, 1, 2]))

5038

5039 The ``nonzero`` method of the condition array can also be called.

5040

5041 >>> (a > 3).nonzero()

5042 (array([1, 1, 1, 2, 2, 2]), array([0, 1, 2, 0, 1, 2]))

5043

5044 """

5045 return narray(self.filled(0), copy=False).nonzero()

5046

5047 def trace(self, offset=0, axis1=0, axis2=1, dtype=None, out=None):

5048 """

5049 (this docstring should be overwritten)

5050 """

5051 #!!!: implement out + test!

5052 m = self._mask

5053 if m is nomask:

5054 result = super().trace(offset=offset, axis1=axis1, axis2=axis2,

5055 out=out)

5056 return result.astype(dtype)

5057 else:

5058 D = self.diagonal(offset=offset, axis1=axis1, axis2=axis2)

5059 return D.astype(dtype).filled(0).sum(axis=-1, out=out)

5060 trace.__doc__ = ndarray.trace.__doc__

5061

5062 def dot(self, b, out=None, strict=False):

5063 """

5064 a.dot(b, out=None)

5065

5066 Masked dot product of two arrays. Note that `out` and `strict` are

5067 located in different positions than in `ma.dot`. In order to

5068 maintain compatibility with the functional version, it is

5069 recommended that the optional arguments be treated as keyword only.

5070 At some point that may be mandatory.

5071

5072 .. versionadded:: 1.10.0

5073

5074 Parameters

5075 ----------

5076 b : masked_array_like

5077 Inputs array.

5078 out : masked_array, optional

5079 Output argument. This must have the exact kind that would be

5080 returned if it was not used. In particular, it must have the

5081 right type, must be C-contiguous, and its dtype must be the

5082 dtype that would be returned for `ma.dot(a,b)`. This is a

5083 performance feature. Therefore, if these conditions are not

5084 met, an exception is raised, instead of attempting to be

5085 flexible.

5086 strict : bool, optional

5087 Whether masked data are propagated (True) or set to 0 (False)

5088 for the computation. Default is False. Propagating the mask

5089 means that if a masked value appears in a row or column, the

5090 whole row or column is considered masked.

5091

5092 .. versionadded:: 1.10.2

5093

5094 See Also

5095 --------

5096 numpy.ma.dot : equivalent function

5097

5098 """

5099 return dot(self, b, out=out, strict=strict)

5100

5101 def sum(self, axis=None, dtype=None, out=None, keepdims=np._NoValue):

5102 """

5103 Return the sum of the array elements over the given axis.

5104

5105 Masked elements are set to 0 internally.

5106

5107 Refer to `numpy.sum` for full documentation.

5108

5109 See Also

5110 --------

5111 numpy.ndarray.sum : corresponding function for ndarrays

5112 numpy.sum : equivalent function

5113

5114 Examples

5115 --------

5116 >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4)

5117 >>> x

5118 masked_array(

5119 data=[[1, --, 3],

5120 [--, 5, --],

5121 [7, --, 9]],

5122 mask=[[False, True, False],

5123 [ True, False, True],

5124 [False, True, False]],

5125 fill_value=999999)

5126 >>> x.sum()

5127 25

5128 >>> x.sum(axis=1)

5129 masked_array(data=[4, 5, 16],

5130 mask=[False, False, False],

5131 fill_value=999999)

5132 >>> x.sum(axis=0)

5133 masked_array(data=[8, 5, 12],

5134 mask=[False, False, False],

5135 fill_value=999999)

5136 >>> print(type(x.sum(axis=0, dtype=np.int64)[0]))

5137 <class 'numpy.int64'>

5138

5139 """

5140 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}

5141

5142 _mask = self._mask

5143 newmask = _check_mask_axis(_mask, axis, **kwargs)

5144 # No explicit output

5145 if out is None:

5146 result = self.filled(0).sum(axis, dtype=dtype, **kwargs)

5147 rndim = getattr(result, 'ndim', 0)

5148 if rndim:

5149 result = result.view(type(self))

5150 result.__setmask__(newmask)

5151 elif newmask:

5152 result = masked

5153 return result

5154 # Explicit output

5155 result = self.filled(0).sum(axis, dtype=dtype, out=out, **kwargs)

5156 if isinstance(out, MaskedArray):

5157 outmask = getmask(out)

5158 if outmask is nomask:

5159 outmask = out._mask = make_mask_none(out.shape)

5160 outmask.flat = newmask

5161 return out

5162

5163 def cumsum(self, axis=None, dtype=None, out=None):

5164 """

5165 Return the cumulative sum of the array elements over the given axis.

5166

5167 Masked values are set to 0 internally during the computation.

5168 However, their position is saved, and the result will be masked at

5169 the same locations.

5170

5171 Refer to `numpy.cumsum` for full documentation.

5172

5173 Notes

5174 -----

5175 The mask is lost if `out` is not a valid :class:`ma.MaskedArray` !

5176

5177 Arithmetic is modular when using integer types, and no error is

5178 raised on overflow.

5179

5180 See Also

5181 --------

5182 numpy.ndarray.cumsum : corresponding function for ndarrays

5183 numpy.cumsum : equivalent function

5184

5185 Examples

5186 --------

5187 >>> marr = np.ma.array(np.arange(10), mask=[0,0,0,1,1,1,0,0,0,0])

5188 >>> marr.cumsum()

5189 masked_array(data=[0, 1, 3, --, --, --, 9, 16, 24, 33],

5190 mask=[False, False, False, True, True, True, False, False,

5191 False, False],

5192 fill_value=999999)

5193

5194 """

5195 result = self.filled(0).cumsum(axis=axis, dtype=dtype, out=out)

5196 if out is not None:

5197 if isinstance(out, MaskedArray):

5198 out.__setmask__(self.mask)

5199 return out

5200 result = result.view(type(self))

5201 result.__setmask__(self._mask)

5202 return result

5203

5204 def prod(self, axis=None, dtype=None, out=None, keepdims=np._NoValue):

5205 """

5206 Return the product of the array elements over the given axis.

5207

5208 Masked elements are set to 1 internally for computation.

5209

5210 Refer to `numpy.prod` for full documentation.

5211

5212 Notes

5213 -----

5214 Arithmetic is modular when using integer types, and no error is raised

5215 on overflow.

5216

5217 See Also

5218 --------

5219 numpy.ndarray.prod : corresponding function for ndarrays

5220 numpy.prod : equivalent function

5221 """

5222 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}

5223

5224 _mask = self._mask

5225 newmask = _check_mask_axis(_mask, axis, **kwargs)

5226 # No explicit output

5227 if out is None:

5228 result = self.filled(1).prod(axis, dtype=dtype, **kwargs)

5229 rndim = getattr(result, 'ndim', 0)

5230 if rndim:

5231 result = result.view(type(self))

5232 result.__setmask__(newmask)

5233 elif newmask:

5234 result = masked

5235 return result

5236 # Explicit output

5237 result = self.filled(1).prod(axis, dtype=dtype, out=out, **kwargs)

5238 if isinstance(out, MaskedArray):

5239 outmask = getmask(out)

5240 if outmask is nomask:

5241 outmask = out._mask = make_mask_none(out.shape)

5242 outmask.flat = newmask

5243 return out

5244 product = prod

5245

5246 def cumprod(self, axis=None, dtype=None, out=None):

5247 """

5248 Return the cumulative product of the array elements over the given axis.

5249

5250 Masked values are set to 1 internally during the computation.

5251 However, their position is saved, and the result will be masked at

5252 the same locations.

5253

5254 Refer to `numpy.cumprod` for full documentation.

5255

5256 Notes

5257 -----

5258 The mask is lost if `out` is not a valid MaskedArray !

5259

5260 Arithmetic is modular when using integer types, and no error is

5261 raised on overflow.

5262

5263 See Also

5264 --------

5265 numpy.ndarray.cumprod : corresponding function for ndarrays

5266 numpy.cumprod : equivalent function

5267 """

5268 result = self.filled(1).cumprod(axis=axis, dtype=dtype, out=out)

5269 if out is not None:

5270 if isinstance(out, MaskedArray):

5271 out.__setmask__(self._mask)

5272 return out

5273 result = result.view(type(self))

5274 result.__setmask__(self._mask)

5275 return result

5276

5277 def mean(self, axis=None, dtype=None, out=None, keepdims=np._NoValue):

5278 """

5279 Returns the average of the array elements along given axis.

5280

5281 Masked entries are ignored, and result elements which are not

5282 finite will be masked.

5283

5284 Refer to `numpy.mean` for full documentation.

5285

5286 See Also

5287 --------

5288 numpy.ndarray.mean : corresponding function for ndarrays

5289 numpy.mean : Equivalent function

5290 numpy.ma.average : Weighted average.

5291

5292 Examples

5293 --------

5294 >>> a = np.ma.array([1,2,3], mask=[False, False, True])

5295 >>> a

5296 masked_array(data=[1, 2, --],

5297 mask=[False, False, True],

5298 fill_value=999999)

5299 >>> a.mean()

5300 1.5

5301

5302 """

5303 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}

5304 if self._mask is nomask:

5305 result = super().mean(axis=axis, dtype=dtype, **kwargs)[()]

5306 else:

5307 is_float16_result = False

5308 if dtype is None:

5309 if issubclass(self.dtype.type, (ntypes.integer, ntypes.bool_)):

5310 dtype = mu.dtype('f8')

5311 elif issubclass(self.dtype.type, ntypes.float16):

5312 dtype = mu.dtype('f4')

5313 is_float16_result = True

5314 dsum = self.sum(axis=axis, dtype=dtype, **kwargs)

5315 cnt = self.count(axis=axis, **kwargs)

5316 if cnt.shape == () and (cnt == 0):

5317 result = masked

5318 elif is_float16_result:

5319 result = self.dtype.type(dsum * 1. / cnt)

5320 else:

5321 result = dsum * 1. / cnt

5322 if out is not None:

5323 out.flat = result

5324 if isinstance(out, MaskedArray):

5325 outmask = getmask(out)

5326 if outmask is nomask:

5327 outmask = out._mask = make_mask_none(out.shape)

5328 outmask.flat = getmask(result)

5329 return out

5330 return result

5331

5332 def anom(self, axis=None, dtype=None):

5333 """

5334 Compute the anomalies (deviations from the arithmetic mean)

5335 along the given axis.

5336

5337 Returns an array of anomalies, with the same shape as the input and

5338 where the arithmetic mean is computed along the given axis.

5339

5340 Parameters

5341 ----------

5342 axis : int, optional

5343 Axis over which the anomalies are taken.

5344 The default is to use the mean of the flattened array as reference.

5345 dtype : dtype, optional

5346 Type to use in computing the variance. For arrays of integer type

5347 the default is float32; for arrays of float types it is the same as

5348 the array type.

5349

5350 See Also

5351 --------

5352 mean : Compute the mean of the array.

5353

5354 Examples

5355 --------

5356 >>> a = np.ma.array([1,2,3])

5357 >>> a.anom()

5358 masked_array(data=[-1., 0., 1.],

5359 mask=False,

5360 fill_value=1e+20)

5361

5362 """

5363 m = self.mean(axis, dtype)

5364 if not axis:

5365 return self - m

5366 else:

5367 return self - expand_dims(m, axis)

5368

5369 def var(self, axis=None, dtype=None, out=None, ddof=0,

5370 keepdims=np._NoValue):

5371 """

5372 Returns the variance of the array elements along given axis.

5373

5374 Masked entries are ignored, and result elements which are not

5375 finite will be masked.

5376

5377 Refer to `numpy.var` for full documentation.

5378

5379 See Also

5380 --------

5381 numpy.ndarray.var : corresponding function for ndarrays

5382 numpy.var : Equivalent function

5383 """

5384 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}

5385

5386 # Easy case: nomask, business as usual

5387 if self._mask is nomask:

5388 ret = super().var(axis=axis, dtype=dtype, out=out, ddof=ddof,

5389 **kwargs)[()]

5390 if out is not None:

5391 if isinstance(out, MaskedArray):

5392 out.__setmask__(nomask)

5393 return out

5394 return ret

5395

5396 # Some data are masked, yay!

5397 cnt = self.count(axis=axis, **kwargs) - ddof

5398 danom = self - self.mean(axis, dtype, keepdims=True)

5399 if iscomplexobj(self):

5400 danom = umath.absolute(danom) ** 2

5401 else:

5402 danom *= danom

5403 dvar = divide(danom.sum(axis, **kwargs), cnt).view(type(self))

5404 # Apply the mask if it's not a scalar

5405 if dvar.ndim:

5406 dvar._mask = mask_or(self._mask.all(axis, **kwargs), (cnt <= 0))

5407 dvar._update_from(self)

5408 elif getmask(dvar):

5409 # Make sure that masked is returned when the scalar is masked.

5410 dvar = masked

5411 if out is not None:

5412 if isinstance(out, MaskedArray):

5413 out.flat = 0

5414 out.__setmask__(True)

5415 elif out.dtype.kind in 'biu':

5416 errmsg = "Masked data information would be lost in one or "\

5417 "more location."

5418 raise MaskError(errmsg)

5419 else:

5420 out.flat = np.nan

5421 return out

5422 # In case with have an explicit output

5423 if out is not None:

5424 # Set the data

5425 out.flat = dvar

5426 # Set the mask if needed

5427 if isinstance(out, MaskedArray):

5428 out.__setmask__(dvar.mask)

5429 return out

5430 return dvar

5431 var.__doc__ = np.var.__doc__

5432

5433 def std(self, axis=None, dtype=None, out=None, ddof=0,

5434 keepdims=np._NoValue):

5435 """

5436 Returns the standard deviation of the array elements along given axis.

5437

5438 Masked entries are ignored.

5439

5440 Refer to `numpy.std` for full documentation.

5441

5442 See Also

5443 --------

5444 numpy.ndarray.std : corresponding function for ndarrays

5445 numpy.std : Equivalent function

5446 """

5447 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}

5448

5449 dvar = self.var(axis, dtype, out, ddof, **kwargs)

5450 if dvar is not masked:

5451 if out is not None:

5452 np.power(out, 0.5, out=out, casting='unsafe')

5453 return out

5454 dvar = sqrt(dvar)

5455 return dvar

5456

5457 def round(self, decimals=0, out=None):

5458 """

5459 Return each element rounded to the given number of decimals.

5460

5461 Refer to `numpy.around` for full documentation.

5462

5463 See Also

5464 --------

5465 numpy.ndarray.round : corresponding function for ndarrays

5466 numpy.around : equivalent function

5467 """

5468 result = self._data.round(decimals=decimals, out=out).view(type(self))

5469 if result.ndim > 0:

5470 result._mask = self._mask

5471 result._update_from(self)

5472 elif self._mask:

5473 # Return masked when the scalar is masked

5474 result = masked

5475 # No explicit output: we're done

5476 if out is None:

5477 return result

5478 if isinstance(out, MaskedArray):

5479 out.__setmask__(self._mask)

5480 return out

5481

5482 def argsort(self, axis=np._NoValue, kind=None, order=None,

5483 endwith=True, fill_value=None):

5484 """

5485 Return an ndarray of indices that sort the array along the

5486 specified axis. Masked values are filled beforehand to

5487 `fill_value`.

5488

5489 Parameters

5490 ----------

5491 axis : int, optional

5492 Axis along which to sort. If None, the default, the flattened array

5493 is used.

5494

5495 .. versionchanged:: 1.13.0

5496 Previously, the default was documented to be -1, but that was

5497 in error. At some future date, the default will change to -1, as

5498 originally intended.

5499 Until then, the axis should be given explicitly when

5500 ``arr.ndim > 1``, to avoid a FutureWarning.

5501 kind : {'quicksort', 'mergesort', 'heapsort', 'stable'}, optional

5502 The sorting algorithm used.

5503 order : list, optional

5504 When `a` is an array with fields defined, this argument specifies

5505 which fields to compare first, second, etc. Not all fields need be

5506 specified.

5507 endwith : {True, False}, optional

5508 Whether missing values (if any) should be treated as the largest values

5509 (True) or the smallest values (False)

5510 When the array contains unmasked values at the same extremes of the

5511 datatype, the ordering of these values and the masked values is

5512 undefined.

5513 fill_value : scalar or None, optional

5514 Value used internally for the masked values.

5515 If ``fill_value`` is not None, it supersedes ``endwith``.

5516

5517 Returns

5518 -------

5519 index_array : ndarray, int

5520 Array of indices that sort `a` along the specified axis.

5521 In other words, ``a[index_array]`` yields a sorted `a`.

5522

5523 See Also

5524 --------

5525 ma.MaskedArray.sort : Describes sorting algorithms used.

5526 lexsort : Indirect stable sort with multiple keys.

5527 numpy.ndarray.sort : Inplace sort.

5528

5529 Notes

5530 -----

5531 See `sort` for notes on the different sorting algorithms.

5532

5533 Examples

5534 --------

5535 >>> a = np.ma.array([3,2,1], mask=[False, False, True])

5536 >>> a

5537 masked_array(data=[3, 2, --],

5538 mask=[False, False, True],

5539 fill_value=999999)

5540 >>> a.argsort()

5541 array([1, 0, 2])

5542

5543 """

5544

5545 # 2017-04-11, Numpy 1.13.0, gh-8701: warn on axis default

5546 if axis is np._NoValue:

5547 axis = _deprecate_argsort_axis(self)

5548

5549 if fill_value is None:

5550 if endwith:

5551 # nan > inf

5552 if np.issubdtype(self.dtype, np.floating):

5553 fill_value = np.nan

5554 else:

5555 fill_value = minimum_fill_value(self)

5556 else:

5557 fill_value = maximum_fill_value(self)

5558

5559 filled = self.filled(fill_value)

5560 return filled.argsort(axis=axis, kind=kind, order=order)

5561

5562 def argmin(self, axis=None, fill_value=None, out=None, *,

5563 keepdims=np._NoValue):

5564 """

5565 Return array of indices to the minimum values along the given axis.

5566

5567 Parameters

5568 ----------

5569 axis : {None, integer}

5570 If None, the index is into the flattened array, otherwise along

5571 the specified axis

5572 fill_value : scalar or None, optional

5573 Value used to fill in the masked values. If None, the output of

5574 minimum_fill_value(self._data) is used instead.

5575 out : {None, array}, optional

5576 Array into which the result can be placed. Its type is preserved

5577 and it must be of the right shape to hold the output.

5578

5579 Returns

5580 -------

5581 ndarray or scalar

5582 If multi-dimension input, returns a new ndarray of indices to the

5583 minimum values along the given axis. Otherwise, returns a scalar

5584 of index to the minimum values along the given axis.

5585

5586 Examples

5587 --------

5588 >>> x = np.ma.array(np.arange(4), mask=[1,1,0,0])

5589 >>> x.shape = (2,2)

5590 >>> x

5591 masked_array(

5592 data=[[--, --],

5593 [2, 3]],

5594 mask=[[ True, True],

5595 [False, False]],

5596 fill_value=999999)

5597 >>> x.argmin(axis=0, fill_value=-1)

5598 array([0, 0])

5599 >>> x.argmin(axis=0, fill_value=9)

5600 array([1, 1])

5601

5602 """

5603 if fill_value is None:

5604 fill_value = minimum_fill_value(self)

5605 d = self.filled(fill_value).view(ndarray)

5606 keepdims = False if keepdims is np._NoValue else bool(keepdims)

5607 return d.argmin(axis, out=out, keepdims=keepdims)

5608

5609 def argmax(self, axis=None, fill_value=None, out=None, *,

5610 keepdims=np._NoValue):

5611 """

5612 Returns array of indices of the maximum values along the given axis.

5613 Masked values are treated as if they had the value fill_value.

5614

5615 Parameters

5616 ----------

5617 axis : {None, integer}

5618 If None, the index is into the flattened array, otherwise along

5619 the specified axis

5620 fill_value : scalar or None, optional

5621 Value used to fill in the masked values. If None, the output of

5622 maximum_fill_value(self._data) is used instead.

5623 out : {None, array}, optional

5624 Array into which the result can be placed. Its type is preserved

5625 and it must be of the right shape to hold the output.

5626

5627 Returns

5628 -------

5629 index_array : {integer_array}

5630

5631 Examples

5632 --------

5633 >>> a = np.arange(6).reshape(2,3)

5634 >>> a.argmax()

5635 5

5636 >>> a.argmax(0)

5637 array([1, 1, 1])

5638 >>> a.argmax(1)

5639 array([2, 2])

5640

5641 """

5642 if fill_value is None:

5643 fill_value = maximum_fill_value(self._data)

5644 d = self.filled(fill_value).view(ndarray)

5645 keepdims = False if keepdims is np._NoValue else bool(keepdims)

5646 return d.argmax(axis, out=out, keepdims=keepdims)

5647

5648 def sort(self, axis=-1, kind=None, order=None,

5649 endwith=True, fill_value=None):

5650 """

5651 Sort the array, in-place

5652

5653 Parameters

5654 ----------

5655 a : array_like

5656 Array to be sorted.

5657 axis : int, optional

5658 Axis along which to sort. If None, the array is flattened before

5659 sorting. The default is -1, which sorts along the last axis.

5660 kind : {'quicksort', 'mergesort', 'heapsort', 'stable'}, optional

5661 The sorting algorithm used.

5662 order : list, optional

5663 When `a` is a structured array, this argument specifies which fields

5664 to compare first, second, and so on. This list does not need to

5665 include all of the fields.

5666 endwith : {True, False}, optional

5667 Whether missing values (if any) should be treated as the largest values

5668 (True) or the smallest values (False)

5669 When the array contains unmasked values sorting at the same extremes of the

5670 datatype, the ordering of these values and the masked values is

5671 undefined.

5672 fill_value : scalar or None, optional

5673 Value used internally for the masked values.

5674 If ``fill_value`` is not None, it supersedes ``endwith``.

5675

5676 Returns

5677 -------

5678 sorted_array : ndarray

5679 Array of the same type and shape as `a`.

5680

5681 See Also

5682 --------

5683 numpy.ndarray.sort : Method to sort an array in-place.

5684 argsort : Indirect sort.

5685 lexsort : Indirect stable sort on multiple keys.

5686 searchsorted : Find elements in a sorted array.

5687

5688 Notes

5689 -----

5690 See ``sort`` for notes on the different sorting algorithms.

5691

5692 Examples

5693 --------

5694 >>> a = np.ma.array([1, 2, 5, 4, 3],mask=[0, 1, 0, 1, 0])

5695 >>> # Default

5696 >>> a.sort()

5697 >>> a

5698 masked_array(data=[1, 3, 5, --, --],

5699 mask=[False, False, False, True, True],

5700 fill_value=999999)

5701

5702 >>> a = np.ma.array([1, 2, 5, 4, 3],mask=[0, 1, 0, 1, 0])

5703 >>> # Put missing values in the front

5704 >>> a.sort(endwith=False)

5705 >>> a

5706 masked_array(data=[--, --, 1, 3, 5],

5707 mask=[ True, True, False, False, False],

5708 fill_value=999999)

5709

5710 >>> a = np.ma.array([1, 2, 5, 4, 3],mask=[0, 1, 0, 1, 0])

5711 >>> # fill_value takes over endwith

5712 >>> a.sort(endwith=False, fill_value=3)

5713 >>> a

5714 masked_array(data=[1, --, --, 3, 5],

5715 mask=[False, True, True, False, False],

5716 fill_value=999999)

5717

5718 """

5719 if self._mask is nomask:

5720 ndarray.sort(self, axis=axis, kind=kind, order=order)

5721 return

5722

5723 if self is masked:

5724 return

5725

5726 sidx = self.argsort(axis=axis, kind=kind, order=order,

5727 fill_value=fill_value, endwith=endwith)

5728

5729 self[...] = np.take_along_axis(self, sidx, axis=axis)

5730

5731 def min(self, axis=None, out=None, fill_value=None, keepdims=np._NoValue):

5732 """

5733 Return the minimum along a given axis.

5734

5735 Parameters

5736 ----------

5737 axis : None or int or tuple of ints, optional

5738 Axis along which to operate. By default, ``axis`` is None and the

5739 flattened input is used.

5740 .. versionadded:: 1.7.0

5741 If this is a tuple of ints, the minimum is selected over multiple

5742 axes, instead of a single axis or all the axes as before.

5743 out : array_like, optional

5744 Alternative output array in which to place the result. Must be of

5745 the same shape and buffer length as the expected output.

5746 fill_value : scalar or None, optional

5747 Value used to fill in the masked values.

5748 If None, use the output of `minimum_fill_value`.

5749 keepdims : bool, optional

5750 If this is set to True, the axes which are reduced are left

5751 in the result as dimensions with size one. With this option,

5752 the result will broadcast correctly against the array.

5753

5754 Returns

5755 -------

5756 amin : array_like

5757 New array holding the result.

5758 If ``out`` was specified, ``out`` is returned.

5759

5760 See Also

5761 --------

5762 ma.minimum_fill_value

5763 Returns the minimum filling value for a given datatype.

5764

5765 Examples

5766 --------

5767 >>> import numpy.ma as ma

5768 >>> x = [[1., -2., 3.], [0.2, -0.7, 0.1]]

5769 >>> mask = [[1, 1, 0], [0, 0, 1]]

5770 >>> masked_x = ma.masked_array(x, mask)

5771 >>> masked_x

5772 masked_array(

5773 data=[[--, --, 3.0],

5774 [0.2, -0.7, --]],

5775 mask=[[ True, True, False],

5776 [False, False, True]],

5777 fill_value=1e+20)

5778 >>> ma.min(masked_x)

5779 -0.7

5780 >>> ma.min(masked_x, axis=-1)

5781 masked_array(data=[3.0, -0.7],

5782 mask=[False, False],

5783 fill_value=1e+20)

5784 >>> ma.min(masked_x, axis=0, keepdims=True)

5785 masked_array(data=[[0.2, -0.7, 3.0]],

5786 mask=[[False, False, False]],

5787 fill_value=1e+20)

5788 >>> mask = [[1, 1, 1,], [1, 1, 1]]

5789 >>> masked_x = ma.masked_array(x, mask)

5790 >>> ma.min(masked_x, axis=0)

5791 masked_array(data=[--, --, --],

5792 mask=[ True, True, True],

5793 fill_value=1e+20,

5794 dtype=float64)

5795 """

5796 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}

5797

5798 _mask = self._mask

5799 newmask = _check_mask_axis(_mask, axis, **kwargs)

5800 if fill_value is None:

5801 fill_value = minimum_fill_value(self)

5802 # No explicit output

5803 if out is None:

5804 result = self.filled(fill_value).min(

5805 axis=axis, out=out, **kwargs).view(type(self))

5806 if result.ndim:

5807 # Set the mask

5808 result.__setmask__(newmask)

5809 # Get rid of Infs

5810 if newmask.ndim:

5811 np.copyto(result, result.fill_value, where=newmask)

5812 elif newmask:

5813 result = masked

5814 return result

5815 # Explicit output

5816 result = self.filled(fill_value).min(axis=axis, out=out, **kwargs)

5817 if isinstance(out, MaskedArray):

5818 outmask = getmask(out)

5819 if outmask is nomask:

5820 outmask = out._mask = make_mask_none(out.shape)

5821 outmask.flat = newmask

5822 else:

5823 if out.dtype.kind in 'biu':

5824 errmsg = "Masked data information would be lost in one or more"\

5825 " location."

5826 raise MaskError(errmsg)

5827 np.copyto(out, np.nan, where=newmask)

5828 return out

5829

5830 def max(self, axis=None, out=None, fill_value=None, keepdims=np._NoValue):

5831 """

5832 Return the maximum along a given axis.

5833

5834 Parameters

5835 ----------

5836 axis : None or int or tuple of ints, optional

5837 Axis along which to operate. By default, ``axis`` is None and the

5838 flattened input is used.

5839 .. versionadded:: 1.7.0

5840 If this is a tuple of ints, the maximum is selected over multiple

5841 axes, instead of a single axis or all the axes as before.

5842 out : array_like, optional

5843 Alternative output array in which to place the result. Must

5844 be of the same shape and buffer length as the expected output.

5845 fill_value : scalar or None, optional

5846 Value used to fill in the masked values.

5847 If None, use the output of maximum_fill_value().

5848 keepdims : bool, optional

5849 If this is set to True, the axes which are reduced are left

5850 in the result as dimensions with size one. With this option,

5851 the result will broadcast correctly against the array.

5852

5853 Returns

5854 -------

5855 amax : array_like

5856 New array holding the result.

5857 If ``out`` was specified, ``out`` is returned.

5858

5859 See Also

5860 --------

5861 ma.maximum_fill_value

5862 Returns the maximum filling value for a given datatype.

5863

5864 Examples

5865 --------

5866 >>> import numpy.ma as ma

5867 >>> x = [[-1., 2.5], [4., -2.], [3., 0.]]

5868 >>> mask = [[0, 0], [1, 0], [1, 0]]

5869 >>> masked_x = ma.masked_array(x, mask)

5870 >>> masked_x

5871 masked_array(

5872 data=[[-1.0, 2.5],

5873 [--, -2.0],

5874 [--, 0.0]],

5875 mask=[[False, False],

5876 [ True, False],

5877 [ True, False]],

5878 fill_value=1e+20)

5879 >>> ma.max(masked_x)

5880 2.5

5881 >>> ma.max(masked_x, axis=0)

5882 masked_array(data=[-1.0, 2.5],

5883 mask=[False, False],

5884 fill_value=1e+20)

5885 >>> ma.max(masked_x, axis=1, keepdims=True)

5886 masked_array(

5887 data=[[2.5],

5888 [-2.0],

5889 [0.0]],

5890 mask=[[False],

5891 [False],

5892 [False]],

5893 fill_value=1e+20)

5894 >>> mask = [[1, 1], [1, 1], [1, 1]]

5895 >>> masked_x = ma.masked_array(x, mask)

5896 >>> ma.max(masked_x, axis=1)

5897 masked_array(data=[--, --, --],

5898 mask=[ True, True, True],

5899 fill_value=1e+20,

5900 dtype=float64)

5901 """

5902 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}

5903

5904 _mask = self._mask

5905 newmask = _check_mask_axis(_mask, axis, **kwargs)

5906 if fill_value is None:

5907 fill_value = maximum_fill_value(self)

5908 # No explicit output

5909 if out is None:

5910 result = self.filled(fill_value).max(

5911 axis=axis, out=out, **kwargs).view(type(self))

5912 if result.ndim:

5913 # Set the mask

5914 result.__setmask__(newmask)

5915 # Get rid of Infs

5916 if newmask.ndim:

5917 np.copyto(result, result.fill_value, where=newmask)

5918 elif newmask:

5919 result = masked

5920 return result

5921 # Explicit output

5922 result = self.filled(fill_value).max(axis=axis, out=out, **kwargs)

5923 if isinstance(out, MaskedArray):

5924 outmask = getmask(out)

5925 if outmask is nomask:

5926 outmask = out._mask = make_mask_none(out.shape)

5927 outmask.flat = newmask

5928 else:

5929

5930 if out.dtype.kind in 'biu':

5931 errmsg = "Masked data information would be lost in one or more"\

5932 " location."

5933 raise MaskError(errmsg)

5934 np.copyto(out, np.nan, where=newmask)

5935 return out

5936

5937 def ptp(self, axis=None, out=None, fill_value=None, keepdims=False):

5938 """

5939 Return (maximum - minimum) along the given dimension

5940 (i.e. peak-to-peak value).

5941

5942 .. warning::

5943 `ptp` preserves the data type of the array. This means the

5944 return value for an input of signed integers with n bits

5945 (e.g. `np.int8`, `np.int16`, etc) is also a signed integer

5946 with n bits. In that case, peak-to-peak values greater than

5947 ``2**(n-1)-1`` will be returned as negative values. An example

5948 with a work-around is shown below.

5949

5950 Parameters

5951 ----------

5952 axis : {None, int}, optional

5953 Axis along which to find the peaks. If None (default) the

5954 flattened array is used.

5955 out : {None, array_like}, optional

5956 Alternative output array in which to place the result. It must

5957 have the same shape and buffer length as the expected output

5958 but the type will be cast if necessary.

5959 fill_value : scalar or None, optional

5960 Value used to fill in the masked values.

5961 keepdims : bool, optional

5962 If this is set to True, the axes which are reduced are left

5963 in the result as dimensions with size one. With this option,

5964 the result will broadcast correctly against the array.

5965

5966 Returns

5967 -------

5968 ptp : ndarray.

5969 A new array holding the result, unless ``out`` was

5970 specified, in which case a reference to ``out`` is returned.

5971

5972 Examples

5973 --------

5974 >>> x = np.ma.MaskedArray([[4, 9, 2, 10],

5975 ... [6, 9, 7, 12]])

5976

5977 >>> x.ptp(axis=1)

5978 masked_array(data=[8, 6],

5979 mask=False,

5980 fill_value=999999)

5981

5982 >>> x.ptp(axis=0)

5983 masked_array(data=[2, 0, 5, 2],

5984 mask=False,

5985 fill_value=999999)

5986

5987 >>> x.ptp()

5988 10

5989

5990 This example shows that a negative value can be returned when

5991 the input is an array of signed integers.

5992

5993 >>> y = np.ma.MaskedArray([[1, 127],

5994 ... [0, 127],

5995 ... [-1, 127],

5996 ... [-2, 127]], dtype=np.int8)

5997 >>> y.ptp(axis=1)

5998 masked_array(data=[ 126, 127, -128, -127],

5999 mask=False,

6000 fill_value=999999,

6001 dtype=int8)

6002

6003 A work-around is to use the `view()` method to view the result as

6004 unsigned integers with the same bit width:

6005

6006 >>> y.ptp(axis=1).view(np.uint8)

6007 masked_array(data=[126, 127, 128, 129],

6008 mask=False,

6009 fill_value=999999,

6010 dtype=uint8)

6011 """

6012 if out is None:

6013 result = self.max(axis=axis, fill_value=fill_value,

6014 keepdims=keepdims)

6015 result -= self.min(axis=axis, fill_value=fill_value,

6016 keepdims=keepdims)

6017 return result

6018 out.flat = self.max(axis=axis, out=out, fill_value=fill_value,

6019 keepdims=keepdims)

6020 min_value = self.min(axis=axis, fill_value=fill_value,

6021 keepdims=keepdims)

6022 np.subtract(out, min_value, out=out, casting='unsafe')

6023 return out

6024

6025 def partition(self, *args, **kwargs):

6026 warnings.warn("Warning: 'partition' will ignore the 'mask' "

6027 f"of the {self.__class__.__name__}.",

6028 stacklevel=2)

6029 return super().partition(*args, **kwargs)

6030

6031 def argpartition(self, *args, **kwargs):

6032 warnings.warn("Warning: 'argpartition' will ignore the 'mask' "

6033 f"of the {self.__class__.__name__}.",

6034 stacklevel=2)

6035 return super().argpartition(*args, **kwargs)

6036

6037 def take(self, indices, axis=None, out=None, mode='raise'):

6038 """

6039 """

6040 (_data, _mask) = (self._data, self._mask)

6041 cls = type(self)

6042 # Make sure the indices are not masked

6043 maskindices = getmask(indices)

6044 if maskindices is not nomask:

6045 indices = indices.filled(0)

6046 # Get the data, promoting scalars to 0d arrays with [...] so that

6047 # .view works correctly

6048 if out is None:

6049 out = _data.take(indices, axis=axis, mode=mode)[...].view(cls)

6050 else:

6051 np.take(_data, indices, axis=axis, mode=mode, out=out)

6052 # Get the mask

6053 if isinstance(out, MaskedArray):

6054 if _mask is nomask:

6055 outmask = maskindices

6056 else:

6057 outmask = _mask.take(indices, axis=axis, mode=mode)

6058 outmask |= maskindices

6059 out.__setmask__(outmask)

6060 # demote 0d arrays back to scalars, for consistency with ndarray.take

6061 return out[()]

6062

6063 # Array methods

6064 copy = _arraymethod('copy')

6065 diagonal = _arraymethod('diagonal')

6066 flatten = _arraymethod('flatten')

6067 repeat = _arraymethod('repeat')

6068 squeeze = _arraymethod('squeeze')

6069 swapaxes = _arraymethod('swapaxes')

6070 T = property(fget=lambda self: self.transpose())

6071 transpose = _arraymethod('transpose')

6072

6073 def tolist(self, fill_value=None):

6074 """

6075 Return the data portion of the masked array as a hierarchical Python list.

6076

6077 Data items are converted to the nearest compatible Python type.

6078 Masked values are converted to `fill_value`. If `fill_value` is None,

6079 the corresponding entries in the output list will be ``None``.

6080

6081 Parameters

6082 ----------

6083 fill_value : scalar, optional

6084 The value to use for invalid entries. Default is None.

6085

6086 Returns

6087 -------

6088 result : list

6089 The Python list representation of the masked array.

6090

6091 Examples

6092 --------

6093 >>> x = np.ma.array([[1,2,3], [4,5,6], [7,8,9]], mask=[0] + [1,0]*4)

6094 >>> x.tolist()

6095 [[1, None, 3], [None, 5, None], [7, None, 9]]

6096 >>> x.tolist(-999)

6097 [[1, -999, 3], [-999, 5, -999], [7, -999, 9]]

6098

6099 """

6100 _mask = self._mask

6101 # No mask ? Just return .data.tolist ?

6102 if _mask is nomask:

6103 return self._data.tolist()

6104 # Explicit fill_value: fill the array and get the list

6105 if fill_value is not None:

6106 return self.filled(fill_value).tolist()

6107 # Structured array.

6108 names = self.dtype.names

6109 if names:

6110 result = self._data.astype([(_, object) for _ in names])

6111 for n in names:

6112 result[n][_mask[n]] = None

6113 return result.tolist()

6114 # Standard arrays.

6115 if _mask is nomask:

6116 return [None]

6117 # Set temps to save time when dealing w/ marrays.

6118 inishape = self.shape

6119 result = np.array(self._data.ravel(), dtype=object)

6120 result[_mask.ravel()] = None

6121 result.shape = inishape

6122 return result.tolist()

6123

6124 def tostring(self, fill_value=None, order='C'):

6125 r"""

6126 A compatibility alias for `tobytes`, with exactly the same behavior.

6127

6128 Despite its name, it returns `bytes` not `str`\ s.

6129

6130 .. deprecated:: 1.19.0

6131 """

6132 # 2020-03-30, Numpy 1.19.0

6133 warnings.warn(

6134 "tostring() is deprecated. Use tobytes() instead.",

6135 DeprecationWarning, stacklevel=2)

6136

6137 return self.tobytes(fill_value, order=order)

6138

6139 def tobytes(self, fill_value=None, order='C'):

6140 """

6141 Return the array data as a string containing the raw bytes in the array.

6142

6143 The array is filled with a fill value before the string conversion.

6144

6145 .. versionadded:: 1.9.0

6146

6147 Parameters

6148 ----------

6149 fill_value : scalar, optional

6150 Value used to fill in the masked values. Default is None, in which

6151 case `MaskedArray.fill_value` is used.

6152 order : {'C','F','A'}, optional

6153 Order of the data item in the copy. Default is 'C'.

6154

6155 - 'C' -- C order (row major).

6156 - 'F' -- Fortran order (column major).

6157 - 'A' -- Any, current order of array.

6158 - None -- Same as 'A'.

6159

6160 See Also

6161 --------

6162 numpy.ndarray.tobytes

6163 tolist, tofile

6164

6165 Notes

6166 -----

6167 As for `ndarray.tobytes`, information about the shape, dtype, etc.,

6168 but also about `fill_value`, will be lost.

6169

6170 Examples

6171 --------

6172 >>> x = np.ma.array(np.array([[1, 2], [3, 4]]), mask=[[0, 1], [1, 0]])

6173 >>> x.tobytes()

6174 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'

6175

6176 """

6177 return self.filled(fill_value).tobytes(order=order)

6178

6179 def tofile(self, fid, sep="", format="%s"):

6180 """

6181 Save a masked array to a file in binary format.

6182

6183 .. warning::

6184 This function is not implemented yet.

6185

6186 Raises

6187 ------

6188 NotImplementedError

6189 When `tofile` is called.

6190

6191 """

6192 raise NotImplementedError("MaskedArray.tofile() not implemented yet.")

6193

6194 def toflex(self):

6195 """

6196 Transforms a masked array into a flexible-type array.

6197

6198 The flexible type array that is returned will have two fields:

6199

6200 * the ``_data`` field stores the ``_data`` part of the array.

6201 * the ``_mask`` field stores the ``_mask`` part of the array.

6202

6203 Parameters

6204 ----------

6205 None

6206

6207 Returns

6208 -------

6209 record : ndarray

6210 A new flexible-type `ndarray` with two fields: the first element

6211 containing a value, the second element containing the corresponding

6212 mask boolean. The returned record shape matches self.shape.

6213

6214 Notes

6215 -----

6216 A side-effect of transforming a masked array into a flexible `ndarray` is

6217 that meta information (``fill_value``, ...) will be lost.

6218

6219 Examples

6220 --------

6221 >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4)

6222 >>> x

6223 masked_array(

6224 data=[[1, --, 3],

6225 [--, 5, --],

6226 [7, --, 9]],

6227 mask=[[False, True, False],

6228 [ True, False, True],

6229 [False, True, False]],

6230 fill_value=999999)

6231 >>> x.toflex()

6232 array([[(1, False), (2, True), (3, False)],

6233 [(4, True), (5, False), (6, True)],

6234 [(7, False), (8, True), (9, False)]],

6235 dtype=[('_data', '<i8'), ('_mask', '?')])

6236

6237 """

6238 # Get the basic dtype.

6239 ddtype = self.dtype

6240 # Make sure we have a mask

6241 _mask = self._mask

6242 if _mask is None:

6243 _mask = make_mask_none(self.shape, ddtype)

6244 # And get its dtype

6245 mdtype = self._mask.dtype

6246

6247 record = np.ndarray(shape=self.shape,

6248 dtype=[('_data', ddtype), ('_mask', mdtype)])

6249 record['_data'] = self._data

6250 record['_mask'] = self._mask

6251 return record

6252 torecords = toflex

6253

6254 # Pickling

6255 def __getstate__(self):

6256 """Return the internal state of the masked array, for pickling

6257 purposes.

6258

6259 """

6260 cf = 'CF'[self.flags.fnc]

6261 data_state = super().__reduce__()[2]

6262 return data_state + (getmaskarray(self).tobytes(cf), self._fill_value)

6263

6264 def __setstate__(self, state):

6265 """Restore the internal state of the masked array, for

6266 pickling purposes. ``state`` is typically the output of the

6267 ``__getstate__`` output, and is a 5-tuple:

6268

6269 - class name

6270 - a tuple giving the shape of the data

6271 - a typecode for the data

6272 - a binary string for the data

6273 - a binary string for the mask.

6274

6275 """

6276 (_, shp, typ, isf, raw, msk, flv) = state

6277 super().__setstate__((shp, typ, isf, raw))

6278 self._mask.__setstate__((shp, make_mask_descr(typ), isf, msk))

6279 self.fill_value = flv

6280

6281 def __reduce__(self):

6282 """Return a 3-tuple for pickling a MaskedArray.

6283

6284 """

6285 return (_mareconstruct,

6286 (self.__class__, self._baseclass, (0,), 'b',),

6287 self.__getstate__())

6288

6289 def __deepcopy__(self, memo=None):

6290 from copy import deepcopy

6291 copied = MaskedArray.__new__(type(self), self, copy=True)

6292 if memo is None:

6293 memo = {}

6294 memo[id(self)] = copied

6295 for (k, v) in self.__dict__.items():

6296 copied.__dict__[k] = deepcopy(v, memo)

6297 return copied

6298

6299

6300 def _mareconstruct(subtype, baseclass, baseshape, basetype,):

6301 """Internal function that builds a new MaskedArray from the

6302 information stored in a pickle.

6303

6304 """

6305 _data = ndarray.__new__(baseclass, baseshape, basetype)

6306 _mask = ndarray.__new__(ndarray, baseshape, make_mask_descr(basetype))

6307 return subtype.__new__(subtype, _data, mask=_mask, dtype=basetype,)

6308

6309

6310 class mvoid(MaskedArray):

6311 """

6312 Fake a 'void' object to use for masked array with structured dtypes.

6313 """

6314

6315 def __new__(self, data, mask=nomask, dtype=None, fill_value=None,

6316 hardmask=False, copy=False, subok=True):

6317 _data = np.array(data, copy=copy, subok=subok, dtype=dtype)

6318 _data = _data.view(self)

6319 _data._hardmask = hardmask

6320 if mask is not nomask:

6321 if isinstance(mask, np.void):

6322 _data._mask = mask

6323 else:

6324 try:

6325 # Mask is already a 0D array

6326 _data._mask = np.void(mask)

6327 except TypeError:

6328 # Transform the mask to a void

6329 mdtype = make_mask_descr(dtype)

6330 _data._mask = np.array(mask, dtype=mdtype)[()]

6331 if fill_value is not None:

6332 _data.fill_value = fill_value

6333 return _data

6334

6335 @property

6336 def _data(self):

6337 # Make sure that the _data part is a np.void

6338 return super()._data[()]

6339

6340 def __getitem__(self, indx):

6341 """

6342 Get the index.

6343

6344 """

6345 m = self._mask

6346 if isinstance(m[indx], ndarray):

6347 # Can happen when indx is a multi-dimensional field:

6348 # A = ma.masked_array(data=[([0,1],)], mask=[([True,

6349 # False],)], dtype=[("A", ">i2", (2,))])

6350 # x = A[0]; y = x["A"]; then y.mask["A"].size==2

6351 # and we can not say masked/unmasked.

6352 # The result is no longer mvoid!

6353 # See also issue #6724.

6354 return masked_array(

6355 data=self._data[indx], mask=m[indx],

6356 fill_value=self._fill_value[indx],

6357 hard_mask=self._hardmask)

6358 if m is not nomask and m[indx]:

6359 return masked

6360 return self._data[indx]

6361

6362 def __setitem__(self, indx, value):

6363 self._data[indx] = value

6364 if self._hardmask:

6365 self._mask[indx] |= getattr(value, "_mask", False)

6366 else:

6367 self._mask[indx] = getattr(value, "_mask", False)

6368

6369 def __str__(self):

6370 m = self._mask

6371 if m is nomask:

6372 return str(self._data)

6373

6374 rdtype = _replace_dtype_fields(self._data.dtype, "O")

6375 data_arr = super()._data

6376 res = data_arr.astype(rdtype)

6377 _recursive_printoption(res, self._mask, masked_print_option)

6378 return str(res)

6379

6380 __repr__ = __str__

6381

6382 def __iter__(self):

6383 "Defines an iterator for mvoid"

6384 (_data, _mask) = (self._data, self._mask)

6385 if _mask is nomask:

6386 yield from _data

6387 else:

6388 for (d, m) in zip(_data, _mask):

6389 if m:

6390 yield masked

6391 else:

6392 yield d

6393

6394 def __len__(self):

6395 return self._data.__len__()

6396

6397 def filled(self, fill_value=None):

6398 """

6399 Return a copy with masked fields filled with a given value.

6400

6401 Parameters

6402 ----------

6403 fill_value : array_like, optional

6404 The value to use for invalid entries. Can be scalar or

6405 non-scalar. If latter is the case, the filled array should

6406 be broadcastable over input array. Default is None, in

6407 which case the `fill_value` attribute is used instead.

6408

6409 Returns

6410 -------

6411 filled_void

6412 A `np.void` object

6413

6414 See Also

6415 --------

6416 MaskedArray.filled

6417

6418 """

6419 return asarray(self).filled(fill_value)[()]

6420

6421 def tolist(self):

6422 """

6423 Transforms the mvoid object into a tuple.

6424

6425 Masked fields are replaced by None.

6426

6427 Returns

6428 -------

6429 returned_tuple

6430 Tuple of fields

6431 """

6432 _mask = self._mask

6433 if _mask is nomask:

6434 return self._data.tolist()

6435 result = []

6436 for (d, m) in zip(self._data, self._mask):

6437 if m:

6438 result.append(None)

6439 else:

6440 # .item() makes sure we return a standard Python object

6441 result.append(d.item())

6442 return tuple(result)

6443

6444

6445##############################################################################

6446# Shortcuts #

6447##############################################################################

6448

6449

6450 def isMaskedArray(x):

6451 """

6452 Test whether input is an instance of MaskedArray.

6453

6454 This function returns True if `x` is an instance of MaskedArray

6455 and returns False otherwise. Any object is accepted as input.

6456

6457 Parameters

6458 ----------

6459 x : object

6460 Object to test.

6461

6462 Returns

6463 -------

6464 result : bool

6465 True if `x` is a MaskedArray.

6466

6467 See Also

6468 --------

6469 isMA : Alias to isMaskedArray.

6470 isarray : Alias to isMaskedArray.

6471

6472 Examples

6473 --------

6474 >>> import numpy.ma as ma

6475 >>> a = np.eye(3, 3)

6476 >>> a

6477 array([[ 1., 0., 0.],

6478 [ 0., 1., 0.],

6479 [ 0., 0., 1.]])

6480 >>> m = ma.masked_values(a, 0)

6481 >>> m

6482 masked_array(

6483 data=[[1.0, --, --],

6484 [--, 1.0, --],

6485 [--, --, 1.0]],

6486 mask=[[False, True, True],

6487 [ True, False, True],

6488 [ True, True, False]],

6489 fill_value=0.0)

6490 >>> ma.isMaskedArray(a)

6491 False

6492 >>> ma.isMaskedArray(m)

6493 True

6494 >>> ma.isMaskedArray([0, 1, 2])

6495 False

6496

6497 """

6498 return isinstance(x, MaskedArray)

6499

6500

6501 isarray = isMaskedArray

6502 isMA = isMaskedArray # backward compatibility

6503

6504

6505 class MaskedConstant(MaskedArray):

6506 # the lone np.ma.masked instance

6507 __singleton = None

6508

6509 @classmethod

6510 def __has_singleton(cls):

6511 # second case ensures `cls.__singleton` is not just a view on the

6512 # superclass singleton

6513 return cls.__singleton is not None and type(cls.__singleton) is cls

6514

6515 def __new__(cls):

6516 if not cls.__has_singleton():

6517 # We define the masked singleton as a float for higher precedence.

6518 # Note that it can be tricky sometimes w/ type comparison

6519 data = np.array(0.)

6520 mask = np.array(True)

6521

6522 # prevent any modifications

6523 data.flags.writeable = False

6524 mask.flags.writeable = False

6525

6526 # don't fall back on MaskedArray.__new__(MaskedConstant), since

6527 # that might confuse it - this way, the construction is entirely

6528 # within our control

6529 cls.__singleton = MaskedArray(data, mask=mask).view(cls)

6530

6531 return cls.__singleton

6532

6533 def __array_finalize__(self, obj):

6534 if not self.__has_singleton():

6535 # this handles the `.view` in __new__, which we want to copy across

6536 # properties normally

6537 return super().__array_finalize__(obj)

6538 elif self is self.__singleton:

6539 # not clear how this can happen, play it safe

6540 pass

6541 else:

6542 # everywhere else, we want to downcast to MaskedArray, to prevent a

6543 # duplicate maskedconstant.

6544 self.__class__ = MaskedArray

6545 MaskedArray.__array_finalize__(self, obj)

6546

6547 def __array_prepare__(self, obj, context=None):

6548 return self.view(MaskedArray).__array_prepare__(obj, context)

6549

6550 def __array_wrap__(self, obj, context=None):

6551 return self.view(MaskedArray).__array_wrap__(obj, context)

6552

6553 def __str__(self):

6554 return str(masked_print_option._display)

6555

6556 def __repr__(self):

6557 if self is MaskedConstant.__singleton:

6558 return 'masked'

6559 else:

6560 # it's a subclass, or something is wrong, make it obvious

6561 return object.__repr__(self)

6562

6563 def __format__(self, format_spec):

6564 # Replace ndarray.__format__ with the default, which supports no format characters.

6565 # Supporting format characters is unwise here, because we do not know what type

6566 # the user was expecting - better to not guess.

6567 try:

6568 return object.__format__(self, format_spec)

6569 except TypeError:

6570 # 2020-03-23, NumPy 1.19.0

6571 warnings.warn(

6572 "Format strings passed to MaskedConstant are ignored, but in future may "

6573 "error or produce different behavior",

6574 FutureWarning, stacklevel=2

6575 )

6576 return object.__format__(self, "")

6577

6578 def __reduce__(self):

6579 """Override of MaskedArray's __reduce__.

6580 """

6581 return (self.__class__, ())

6582

6583 # inplace operations have no effect. We have to override them to avoid

6584 # trying to modify the readonly data and mask arrays

6585 def __iop__(self, other):

6586 return self

6587 __iadd__ = \

6588 __isub__ = \

6589 __imul__ = \

6590 __ifloordiv__ = \

6591 __itruediv__ = \

6592 __ipow__ = \

6593 __iop__

6594 del __iop__ # don't leave this around

6595

6596 def copy(self, *args, **kwargs):

6597 """ Copy is a no-op on the maskedconstant, as it is a scalar """

6598 # maskedconstant is a scalar, so copy doesn't need to copy. There's

6599 # precedent for this with `np.bool_` scalars.

6600 return self

6601

6602 def __copy__(self):

6603 return self

6604

6605 def __deepcopy__(self, memo):

6606 return self

6607

6608 def __setattr__(self, attr, value):

6609 if not self.__has_singleton():

6610 # allow the singleton to be initialized

6611 return super().__setattr__(attr, value)

6612 elif self is self.__singleton:

6613 raise AttributeError(

6614 f"attributes of {self!r} are not writeable")

6615 else:

6616 # duplicate instance - we can end up here from __array_finalize__,

6617 # where we set the __class__ attribute

6618 return super().__setattr__(attr, value)

6619

6620

6621 masked = masked_singleton = MaskedConstant()

6622 masked_array = MaskedArray

6623

6624

6625 def array(data, dtype=None, copy=False, order=None,

6626 mask=nomask, fill_value=None, keep_mask=True,

6627 hard_mask=False, shrink=True, subok=True, ndmin=0):

6628 """

6629 Shortcut to MaskedArray.

6630

6631 The options are in a different order for convenience and backwards

6632 compatibility.

6633

6634 """

6635 return MaskedArray(data, mask=mask, dtype=dtype, copy=copy,

6636 subok=subok, keep_mask=keep_mask,

6637 hard_mask=hard_mask, fill_value=fill_value,

6638 ndmin=ndmin, shrink=shrink, order=order)

6639 array.__doc__ = masked_array.__doc__

6640

6641

6642 def is_masked(x):

6643 """

6644 Determine whether input has masked values.

6645

6646 Accepts any object as input, but always returns False unless the

6647 input is a MaskedArray containing masked values.

6648

6649 Parameters

6650 ----------

6651 x : array_like

6652 Array to check for masked values.

6653

6654 Returns

6655 -------

6656 result : bool

6657 True if `x` is a MaskedArray with masked values, False otherwise.

6658

6659 Examples

6660 --------

6661 >>> import numpy.ma as ma

6662 >>> x = ma.masked_equal([0, 1, 0, 2, 3], 0)

6663 >>> x

6664 masked_array(data=[--, 1, --, 2, 3],

6665 mask=[ True, False, True, False, False],

6666 fill_value=0)

6667 >>> ma.is_masked(x)

6668 True

6669 >>> x = ma.masked_equal([0, 1, 0, 2, 3], 42)

6670 >>> x

6671 masked_array(data=[0, 1, 0, 2, 3],

6672 mask=False,

6673 fill_value=42)

6674 >>> ma.is_masked(x)

6675 False

6676

6677 Always returns False if `x` isn't a MaskedArray.

6678

6679 >>> x = [False, True, False]

6680 >>> ma.is_masked(x)

6681 False

6682 >>> x = 'a string'

6683 >>> ma.is_masked(x)

6684 False

6685

6686 """

6687 m = getmask(x)

6688 if m is nomask:

6689 return False

6690 elif m.any():

6691 return True

6692 return False

6693

6694

6695##############################################################################

6696# Extrema functions #

6697##############################################################################

6698

6699

6700 class _extrema_operation(_MaskedUFunc):

6701 """

6702 Generic class for maximum/minimum functions.

6703

6704 .. note::

6705 This is the base class for `_maximum_operation` and

6706 `_minimum_operation`.

6707

6708 """

6709 def __init__(self, ufunc, compare, fill_value):

6710 super().__init__(ufunc)

6711 self.compare = compare

6712 self.fill_value_func = fill_value

6713

6714 def __call__(self, a, b):

6715 "Executes the call behavior."

6716

6717 return where(self.compare(a, b), a, b)

6718

6719 def reduce(self, target, axis=np._NoValue):

6720 "Reduce target along the given axis."

6721 target = narray(target, copy=False, subok=True)

6722 m = getmask(target)

6723

6724 if axis is np._NoValue and target.ndim > 1:

6725 # 2017-05-06, Numpy 1.13.0: warn on axis default

6726 warnings.warn(

6727 f"In the future the default for ma.{self.__name__}.reduce will be axis=0, "

6728 f"not the current None, to match np.{self.__name__}.reduce. "

6729 "Explicitly pass 0 or None to silence this warning.",

6730 MaskedArrayFutureWarning, stacklevel=2)

6731 axis = None

6732

6733 if axis is not np._NoValue:

6734 kwargs = dict(axis=axis)

6735 else:

6736 kwargs = dict()

6737

6738 if m is nomask:

6739 t = self.f.reduce(target, **kwargs)

6740 else:

6741 target = target.filled(

6742 self.fill_value_func(target)).view(type(target))

6743 t = self.f.reduce(target, **kwargs)

6744 m = umath.logical_and.reduce(m, **kwargs)

6745 if hasattr(t, '_mask'):

6746 t._mask = m

6747 elif m:

6748 t = masked

6749 return t

6750

6751 def outer(self, a, b):

6752 "Return the function applied to the outer product of a and b."

6753 ma = getmask(a)

6754 mb = getmask(b)

6755 if ma is nomask and mb is nomask:

6756 m = nomask

6757 else:

6758 ma = getmaskarray(a)

6759 mb = getmaskarray(b)

6760 m = logical_or.outer(ma, mb)

6761 result = self.f.outer(filled(a), filled(b))

6762 if not isinstance(result, MaskedArray):

6763 result = result.view(MaskedArray)

6764 result._mask = m

6765 return result

6766

6767 def min(obj, axis=None, out=None, fill_value=None, keepdims=np._NoValue):

6768 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}

6769

6770 try:

6771 return obj.min(axis=axis, fill_value=fill_value, out=out, **kwargs)

6772 except (AttributeError, TypeError):

6773 # If obj doesn't have a min method, or if the method doesn't accept a

6774 # fill_value argument

6775 return asanyarray(obj).min(axis=axis, fill_value=fill_value,

6776 out=out, **kwargs)

6777 min.__doc__ = MaskedArray.min.__doc__

6778

6779 def max(obj, axis=None, out=None, fill_value=None, keepdims=np._NoValue):

6780 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}

6781

6782 try:

6783 return obj.max(axis=axis, fill_value=fill_value, out=out, **kwargs)

6784 except (AttributeError, TypeError):

6785 # If obj doesn't have a max method, or if the method doesn't accept a

6786 # fill_value argument

6787 return asanyarray(obj).max(axis=axis, fill_value=fill_value,

6788 out=out, **kwargs)

6789 max.__doc__ = MaskedArray.max.__doc__

6790

6791

6792 def ptp(obj, axis=None, out=None, fill_value=None, keepdims=np._NoValue):

6793 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}

6794 try:

6795 return obj.ptp(axis, out=out, fill_value=fill_value, **kwargs)

6796 except (AttributeError, TypeError):

6797 # If obj doesn't have a ptp method or if the method doesn't accept

6798 # a fill_value argument

6799 return asanyarray(obj).ptp(axis=axis, fill_value=fill_value,

6800 out=out, **kwargs)

6801 ptp.__doc__ = MaskedArray.ptp.__doc__

6802

6803

6804##############################################################################

6805# Definition of functions from the corresponding methods #

6806##############################################################################

6807

6808

6809 class _frommethod:

6810 """

6811 Define functions from existing MaskedArray methods.

6812

6813 Parameters

6814 ----------

6815 methodname : str

6816 Name of the method to transform.

6817

6818 """

6819

6820 def __init__(self, methodname, reversed=False):

6821 self.__name__ = methodname

6822 self.__doc__ = self.getdoc()

6823 self.reversed = reversed

6824

6825 def getdoc(self):

6826 "Return the doc of the function (from the doc of the method)."

6827 meth = getattr(MaskedArray, self.__name__, None) or\

6828 getattr(np, self.__name__, None)

6829 signature = self.__name__ + get_object_signature(meth)

6830 if meth is not None:

6831 doc = """ %s\n%s""" % (

6832 signature, getattr(meth, '__doc__', None))

6833 return doc

6834

6835 def __call__(self, a, *args, **params):

6836 if self.reversed:

6837 args = list(args)

6838 a, args[0] = args[0], a

6839

6840 marr = asanyarray(a)

6841 method_name = self.__name__

6842 method = getattr(type(marr), method_name, None)

6843 if method is None:

6844 # use the corresponding np function

6845 method = getattr(np, method_name)

6846

6847 return method(marr, *args, **params)

6848

6849

6850 all = _frommethod('all')

6851 anomalies = anom = _frommethod('anom')

6852 any = _frommethod('any')

6853 compress = _frommethod('compress', reversed=True)

6854 cumprod = _frommethod('cumprod')

6855 cumsum = _frommethod('cumsum')

6856 copy = _frommethod('copy')

6857 diagonal = _frommethod('diagonal')

6858 harden_mask = _frommethod('harden_mask')

6859 ids = _frommethod('ids')

6860 maximum = _extrema_operation(umath.maximum, greater, maximum_fill_value)

6861 mean = _frommethod('mean')

6862 minimum = _extrema_operation(umath.minimum, less, minimum_fill_value)

6863 nonzero = _frommethod('nonzero')

6864 prod = _frommethod('prod')

6865 product = _frommethod('prod')

6866 ravel = _frommethod('ravel')

6867 repeat = _frommethod('repeat')

6868 shrink_mask = _frommethod('shrink_mask')

6869 soften_mask = _frommethod('soften_mask')

6870 std = _frommethod('std')

6871 sum = _frommethod('sum')

6872 swapaxes = _frommethod('swapaxes')

6873#take = _frommethod('take')

6874 trace = _frommethod('trace')

6875 var = _frommethod('var')

6876

6877 count = _frommethod('count')

6878

6879 def take(a, indices, axis=None, out=None, mode='raise'):

6880 """

6881 """

6882 a = masked_array(a)

6883 return a.take(indices, axis=axis, out=out, mode=mode)

6884

6885

6886 def power(a, b, third=None):

6887 """

6888 Returns element-wise base array raised to power from second array.

6889

6890 This is the masked array version of `numpy.power`. For details see

6891 `numpy.power`.

6892

6893 See Also

6894 --------

6895 numpy.power

6896

6897 Notes

6898 -----

6899 The *out* argument to `numpy.power` is not supported, `third` has to be

6900 None.

6901

6902 Examples

6903 --------

6904 >>> import numpy.ma as ma

6905 >>> x = [11.2, -3.973, 0.801, -1.41]

6906 >>> mask = [0, 0, 0, 1]

6907 >>> masked_x = ma.masked_array(x, mask)

6908 >>> masked_x

6909 masked_array(data=[11.2, -3.973, 0.801, --],

6910 mask=[False, False, False, True],

6911 fill_value=1e+20)

6912 >>> ma.power(masked_x, 2)

6913 masked_array(data=[125.43999999999998, 15.784728999999999,

6914 0.6416010000000001, --],

6915 mask=[False, False, False, True],

6916 fill_value=1e+20)

6917 >>> y = [-0.5, 2, 0, 17]

6918 >>> masked_y = ma.masked_array(y, mask)

6919 >>> masked_y

6920 masked_array(data=[-0.5, 2.0, 0.0, --],

6921 mask=[False, False, False, True],

6922 fill_value=1e+20)

6923 >>> ma.power(masked_x, masked_y)

6924 masked_array(data=[0.29880715233359845, 15.784728999999999, 1.0, --],

6925 mask=[False, False, False, True],

6926 fill_value=1e+20)

6927

6928 """

6929 if third is not None:

6930 raise MaskError("3-argument power not supported.")

6931 # Get the masks

6932 ma = getmask(a)

6933 mb = getmask(b)

6934 m = mask_or(ma, mb)

6935 # Get the rawdata

6936 fa = getdata(a)

6937 fb = getdata(b)

6938 # Get the type of the result (so that we preserve subclasses)

6939 if isinstance(a, MaskedArray):

6940 basetype = type(a)

6941 else:

6942 basetype = MaskedArray

6943 # Get the result and view it as a (subclass of) MaskedArray

6944 with np.errstate(divide='ignore', invalid='ignore'):

6945 result = np.where(m, fa, umath.power(fa, fb)).view(basetype)

6946 result._update_from(a)

6947 # Find where we're in trouble w/ NaNs and Infs

6948 invalid = np.logical_not(np.isfinite(result.view(ndarray)))

6949 # Add the initial mask

6950 if m is not nomask:

6951 if not result.ndim:

6952 return masked

6953 result._mask = np.logical_or(m, invalid)

6954 # Fix the invalid parts

6955 if invalid.any():

6956 if not result.ndim:

6957 return masked

6958 elif result._mask is nomask:

6959 result._mask = invalid

6960 result._data[invalid] = result.fill_value

6961 return result

6962

6963 argmin = _frommethod('argmin')

6964 argmax = _frommethod('argmax')

6965

6966 def argsort(a, axis=np._NoValue, kind=None, order=None, endwith=True, fill_value=None):

6967 "Function version of the eponymous method."

6968 a = np.asanyarray(a)

6969

6970 # 2017-04-11, Numpy 1.13.0, gh-8701: warn on axis default

6971 if axis is np._NoValue:

6972 axis = _deprecate_argsort_axis(a)

6973

6974 if isinstance(a, MaskedArray):

6975 return a.argsort(axis=axis, kind=kind, order=order,

6976 endwith=endwith, fill_value=fill_value)

6977 else:

6978 return a.argsort(axis=axis, kind=kind, order=order)

6979 argsort.__doc__ = MaskedArray.argsort.__doc__

6980

6981 def sort(a, axis=-1, kind=None, order=None, endwith=True, fill_value=None):

6982 """

6983 Return a sorted copy of the masked array.

6984

6985 Equivalent to creating a copy of the array

6986 and applying the MaskedArray ``sort()`` method.

6987

6988 Refer to ``MaskedArray.sort`` for the full documentation

6989

6990 See Also

6991 --------

6992 MaskedArray.sort : equivalent method

6993 """

6994 a = np.array(a, copy=True, subok=True)

6995 if axis is None:

6996 a = a.flatten()

6997 axis = 0

6998

6999 if isinstance(a, MaskedArray):

7000 a.sort(axis=axis, kind=kind, order=order,

7001 endwith=endwith, fill_value=fill_value)

7002 else:

7003 a.sort(axis=axis, kind=kind, order=order)

7004 return a

7005

7006

7007 def compressed(x):

7008 """

7009 Return all the non-masked data as a 1-D array.

7010

7011 This function is equivalent to calling the "compressed" method of a

7012 `ma.MaskedArray`, see `ma.MaskedArray.compressed` for details.

7013

7014 See Also

7015 --------

7016 ma.MaskedArray.compressed : Equivalent method.

7017

7018 """

7019 return asanyarray(x).compressed()

7020

7021

7022 def concatenate(arrays, axis=0):

7023 """

7024 Concatenate a sequence of arrays along the given axis.

7025

7026 Parameters

7027 ----------

7028 arrays : sequence of array_like

7029 The arrays must have the same shape, except in the dimension

7030 corresponding to `axis` (the first, by default).

7031 axis : int, optional

7032 The axis along which the arrays will be joined. Default is 0.

7033

7034 Returns

7035 -------

7036 result : MaskedArray

7037 The concatenated array with any masked entries preserved.

7038

7039 See Also

7040 --------

7041 numpy.concatenate : Equivalent function in the top-level NumPy module.

7042

7043 Examples

7044 --------

7045 >>> import numpy.ma as ma

7046 >>> a = ma.arange(3)

7047 >>> a[1] = ma.masked

7048 >>> b = ma.arange(2, 5)

7049 >>> a

7050 masked_array(data=[0, --, 2],

7051 mask=[False, True, False],

7052 fill_value=999999)

7053 >>> b

7054 masked_array(data=[2, 3, 4],

7055 mask=False,

7056 fill_value=999999)

7057 >>> ma.concatenate([a, b])

7058 masked_array(data=[0, --, 2, 2, 3, 4],

7059 mask=[False, True, False, False, False, False],

7060 fill_value=999999)

7061

7062 """

7063 d = np.concatenate([getdata(a) for a in arrays], axis)

7064 rcls = get_masked_subclass(*arrays)

7065 data = d.view(rcls)

7066 # Check whether one of the arrays has a non-empty mask.

7067 for x in arrays:

7068 if getmask(x) is not nomask:

7069 break

7070 else:

7071 return data

7072 # OK, so we have to concatenate the masks

7073 dm = np.concatenate([getmaskarray(a) for a in arrays], axis)

7074 dm = dm.reshape(d.shape)

7075

7076 # If we decide to keep a '_shrinkmask' option, we want to check that

7077 # all of them are True, and then check for dm.any()

7078 data._mask = _shrink_mask(dm)

7079 return data

7080

7081

7082 def diag(v, k=0):

7083 """

7084 Extract a diagonal or construct a diagonal array.

7085

7086 This function is the equivalent of `numpy.diag` that takes masked

7087 values into account, see `numpy.diag` for details.

7088

7089 See Also

7090 --------

7091 numpy.diag : Equivalent function for ndarrays.

7092

7093 """

7094 output = np.diag(v, k).view(MaskedArray)

7095 if getmask(v) is not nomask:

7096 output._mask = np.diag(v._mask, k)

7097 return output

7098

7099

7100 def left_shift(a, n):

7101 """

7102 Shift the bits of an integer to the left.

7103

7104 This is the masked array version of `numpy.left_shift`, for details

7105 see that function.

7106

7107 See Also

7108 --------

7109 numpy.left_shift

7110

7111 """

7112 m = getmask(a)

7113 if m is nomask:

7114 d = umath.left_shift(filled(a), n)

7115 return masked_array(d)

7116 else:

7117 d = umath.left_shift(filled(a, 0), n)

7118 return masked_array(d, mask=m)

7119

7120

7121 def right_shift(a, n):

7122 """

7123 Shift the bits of an integer to the right.

7124

7125 This is the masked array version of `numpy.right_shift`, for details

7126 see that function.

7127

7128 See Also

7129 --------

7130 numpy.right_shift

7131

7132 """

7133 m = getmask(a)

7134 if m is nomask:

7135 d = umath.right_shift(filled(a), n)

7136 return masked_array(d)

7137 else:

7138 d = umath.right_shift(filled(a, 0), n)

7139 return masked_array(d, mask=m)

7140

7141

7142 def put(a, indices, values, mode='raise'):

7143 """

7144 Set storage-indexed locations to corresponding values.

7145

7146 This function is equivalent to `MaskedArray.put`, see that method

7147 for details.

7148

7149 See Also

7150 --------

7151 MaskedArray.put

7152

7153 """

7154 # We can't use 'frommethod', the order of arguments is different

7155 try:

7156 return a.put(indices, values, mode=mode)

7157 except AttributeError:

7158 return narray(a, copy=False).put(indices, values, mode=mode)

7159

7160

7161 def putmask(a, mask, values): # , mode='raise'):

7162 """

7163 Changes elements of an array based on conditional and input values.

7164

7165 This is the masked array version of `numpy.putmask`, for details see

7166 `numpy.putmask`.

7167

7168 See Also

7169 --------

7170 numpy.putmask

7171

7172 Notes

7173 -----

7174 Using a masked array as `values` will **not** transform a `ndarray` into

7175 a `MaskedArray`.

7176

7177 """

7178 # We can't use 'frommethod', the order of arguments is different

7179 if not isinstance(a, MaskedArray):

7180 a = a.view(MaskedArray)

7181 (valdata, valmask) = (getdata(values), getmask(values))

7182 if getmask(a) is nomask:

7183 if valmask is not nomask:

7184 a._sharedmask = True

7185 a._mask = make_mask_none(a.shape, a.dtype)

7186 np.copyto(a._mask, valmask, where=mask)

7187 elif a._hardmask:

7188 if valmask is not nomask:

7189 m = a._mask.copy()

7190 np.copyto(m, valmask, where=mask)

7191 a.mask |= m

7192 else:

7193 if valmask is nomask:

7194 valmask = getmaskarray(values)

7195 np.copyto(a._mask, valmask, where=mask)

7196 np.copyto(a._data, valdata, where=mask)

7197 return

7198

7199

7200 def transpose(a, axes=None):

7201 """

7202 Permute the dimensions of an array.

7203

7204 This function is exactly equivalent to `numpy.transpose`.

7205

7206 See Also

7207 --------

7208 numpy.transpose : Equivalent function in top-level NumPy module.

7209

7210 Examples

7211 --------

7212 >>> import numpy.ma as ma

7213 >>> x = ma.arange(4).reshape((2,2))

7214 >>> x[1, 1] = ma.masked

7215 >>> x

7216 masked_array(

7217 data=[[0, 1],

7218 [2, --]],

7219 mask=[[False, False],

7220 [False, True]],

7221 fill_value=999999)

7222

7223 >>> ma.transpose(x)

7224 masked_array(

7225 data=[[0, 2],

7226 [1, --]],

7227 mask=[[False, False],

7228 [False, True]],

7229 fill_value=999999)

7230 """

7231 # We can't use 'frommethod', as 'transpose' doesn't take keywords

7232 try:

7233 return a.transpose(axes)

7234 except AttributeError:

7235 return narray(a, copy=False).transpose(axes).view(MaskedArray)

7236

7237

7238 def reshape(a, new_shape, order='C'):

7239 """

7240 Returns an array containing the same data with a new shape.

7241

7242 Refer to `MaskedArray.reshape` for full documentation.

7243

7244 See Also

7245 --------

7246 MaskedArray.reshape : equivalent function

7247

7248 """

7249 # We can't use 'frommethod', it whine about some parameters. Dmmit.

7250 try:

7251 return a.reshape(new_shape, order=order)

7252 except AttributeError:

7253 _tmp = narray(a, copy=False).reshape(new_shape, order=order)

7254 return _tmp.view(MaskedArray)

7255

7256

7257 def resize(x, new_shape):

7258 """

7259 Return a new masked array with the specified size and shape.

7260

7261 This is the masked equivalent of the `numpy.resize` function. The new

7262 array is filled with repeated copies of `x` (in the order that the

7263 data are stored in memory). If `x` is masked, the new array will be

7264 masked, and the new mask will be a repetition of the old one.

7265

7266 See Also

7267 --------

7268 numpy.resize : Equivalent function in the top level NumPy module.

7269

7270 Examples

7271 --------

7272 >>> import numpy.ma as ma

7273 >>> a = ma.array([[1, 2] ,[3, 4]])

7274 >>> a[0, 1] = ma.masked

7275 >>> a

7276 masked_array(

7277 data=[[1, --],

7278 [3, 4]],

7279 mask=[[False, True],

7280 [False, False]],

7281 fill_value=999999)

7282 >>> np.resize(a, (3, 3))

7283 masked_array(

7284 data=[[1, 2, 3],

7285 [4, 1, 2],

7286 [3, 4, 1]],

7287 mask=False,

7288 fill_value=999999)

7289 >>> ma.resize(a, (3, 3))

7290 masked_array(

7291 data=[[1, --, 3],

7292 [4, 1, --],

7293 [3, 4, 1]],

7294 mask=[[False, True, False],

7295 [False, False, True],

7296 [False, False, False]],

7297 fill_value=999999)

7298

7299 A MaskedArray is always returned, regardless of the input type.

7300

7301 >>> a = np.array([[1, 2] ,[3, 4]])

7302 >>> ma.resize(a, (3, 3))

7303 masked_array(

7304 data=[[1, 2, 3],

7305 [4, 1, 2],

7306 [3, 4, 1]],

7307 mask=False,

7308 fill_value=999999)

7309

7310 """

7311 # We can't use _frommethods here, as N.resize is notoriously whiny.

7312 m = getmask(x)

7313 if m is not nomask:

7314 m = np.resize(m, new_shape)

7315 result = np.resize(x, new_shape).view(get_masked_subclass(x))

7316 if result.ndim:

7317 result._mask = m

7318 return result

7319

7320

7321 def ndim(obj):

7322 """

7323 maskedarray version of the numpy function.

7324

7325 """

7326 return np.ndim(getdata(obj))

7327

7328 ndim.__doc__ = np.ndim.__doc__

7329

7330

7331 def shape(obj):

7332 "maskedarray version of the numpy function."

7333 return np.shape(getdata(obj))

7334 shape.__doc__ = np.shape.__doc__

7335

7336

7337 def size(obj, axis=None):

7338 "maskedarray version of the numpy function."

7339 return np.size(getdata(obj), axis)

7340 size.__doc__ = np.size.__doc__

7341

7342

7343##############################################################################

7344# Extra functions #

7345##############################################################################

7346

7347

7348 def where(condition, x=_NoValue, y=_NoValue):

7349 """

7350 Return a masked array with elements from `x` or `y`, depending on condition.

7351

7352 .. note::

7353 When only `condition` is provided, this function is identical to

7354 `nonzero`. The rest of this documentation covers only the case where

7355 all three arguments are provided.

7356

7357 Parameters

7358 ----------

7359 condition : array_like, bool

7360 Where True, yield `x`, otherwise yield `y`.

7361 x, y : array_like, optional

7362 Values from which to choose. `x`, `y` and `condition` need to be

7363 broadcastable to some shape.

7364

7365 Returns

7366 -------

7367 out : MaskedArray

7368 An masked array with `masked` elements where the condition is masked,

7369 elements from `x` where `condition` is True, and elements from `y`

7370 elsewhere.

7371

7372 See Also

7373 --------

7374 numpy.where : Equivalent function in the top-level NumPy module.

7375 nonzero : The function that is called when x and y are omitted

7376

7377 Examples

7378 --------

7379 >>> x = np.ma.array(np.arange(9.).reshape(3, 3), mask=[[0, 1, 0],

7380 ... [1, 0, 1],

7381 ... [0, 1, 0]])

7382 >>> x

7383 masked_array(

7384 data=[[0.0, --, 2.0],

7385 [--, 4.0, --],

7386 [6.0, --, 8.0]],

7387 mask=[[False, True, False],

7388 [ True, False, True],

7389 [False, True, False]],

7390 fill_value=1e+20)

7391 >>> np.ma.where(x > 5, x, -3.1416)

7392 masked_array(

7393 data=[[-3.1416, --, -3.1416],

7394 [--, -3.1416, --],

7395 [6.0, --, 8.0]],

7396 mask=[[False, True, False],

7397 [ True, False, True],

7398 [False, True, False]],

7399 fill_value=1e+20)

7400

7401 """

7402

7403 # handle the single-argument case

7404 missing = (x is _NoValue, y is _NoValue).count(True)

7405 if missing == 1:

7406 raise ValueError("Must provide both 'x' and 'y' or neither.")

7407 if missing == 2:

7408 return nonzero(condition)

7409

7410 # we only care if the condition is true - false or masked pick y

7411 cf = filled(condition, False)

7412 xd = getdata(x)

7413 yd = getdata(y)

7414

7415 # we need the full arrays here for correct final dimensions

7416 cm = getmaskarray(condition)

7417 xm = getmaskarray(x)

7418 ym = getmaskarray(y)

7419

7420 # deal with the fact that masked.dtype == float64, but we don't actually

7421 # want to treat it as that.

7422 if x is masked and y is not masked:

7423 xd = np.zeros((), dtype=yd.dtype)

7424 xm = np.ones((), dtype=ym.dtype)

7425 elif y is masked and x is not masked:

7426 yd = np.zeros((), dtype=xd.dtype)

7427 ym = np.ones((), dtype=xm.dtype)

7428

7429 data = np.where(cf, xd, yd)

7430 mask = np.where(cf, xm, ym)

7431 mask = np.where(cm, np.ones((), dtype=mask.dtype), mask)

7432

7433 # collapse the mask, for backwards compatibility

7434 mask = _shrink_mask(mask)

7435

7436 return masked_array(data, mask=mask)

7437

7438

7439 def choose(indices, choices, out=None, mode='raise'):

7440 """

7441 Use an index array to construct a new array from a list of choices.

7442

7443 Given an array of integers and a list of n choice arrays, this method

7444 will create a new array that merges each of the choice arrays. Where a

7445 value in `index` is i, the new array will have the value that choices[i]

7446 contains in the same place.

7447

7448 Parameters

7449 ----------

7450 indices : ndarray of ints

7451 This array must contain integers in ``[0, n-1]``, where n is the

7452 number of choices.

7453 choices : sequence of arrays

7454 Choice arrays. The index array and all of the choices should be

7455 broadcastable to the same shape.

7456 out : array, optional

7457 If provided, the result will be inserted into this array. It should

7458 be of the appropriate shape and `dtype`.

7459 mode : {'raise', 'wrap', 'clip'}, optional

7460 Specifies how out-of-bounds indices will behave.

7461

7462 * 'raise' : raise an error

7463 * 'wrap' : wrap around

7464 * 'clip' : clip to the range

7465

7466 Returns

7467 -------

7468 merged_array : array

7469

7470 See Also

7471 --------

7472 choose : equivalent function

7473

7474 Examples

7475 --------

7476 >>> choice = np.array([[1,1,1], [2,2,2], [3,3,3]])

7477 >>> a = np.array([2, 1, 0])

7478 >>> np.ma.choose(a, choice)

7479 masked_array(data=[3, 2, 1],

7480 mask=False,

7481 fill_value=999999)

7482

7483 """

7484 def fmask(x):

7485 "Returns the filled array, or True if masked."

7486 if x is masked:

7487 return True

7488 return filled(x)

7489

7490 def nmask(x):

7491 "Returns the mask, True if ``masked``, False if ``nomask``."

7492 if x is masked:

7493 return True

7494 return getmask(x)

7495 # Get the indices.

7496 c = filled(indices, 0)

7497 # Get the masks.

7498 masks = [nmask(x) for x in choices]

7499 data = [fmask(x) for x in choices]

7500 # Construct the mask

7501 outputmask = np.choose(c, masks, mode=mode)

7502 outputmask = make_mask(mask_or(outputmask, getmask(indices)),

7503 copy=False, shrink=True)

7504 # Get the choices.

7505 d = np.choose(c, data, mode=mode, out=out).view(MaskedArray)

7506 if out is not None:

7507 if isinstance(out, MaskedArray):

7508 out.__setmask__(outputmask)

7509 return out

7510 d.__setmask__(outputmask)

7511 return d

7512

7513

7514 def round_(a, decimals=0, out=None):

7515 """

7516 Return a copy of a, rounded to 'decimals' places.

7517

7518 When 'decimals' is negative, it specifies the number of positions

7519 to the left of the decimal point. The real and imaginary parts of

7520 complex numbers are rounded separately. Nothing is done if the

7521 array is not of float type and 'decimals' is greater than or equal

7522 to 0.

7523

7524 Parameters

7525 ----------

7526 decimals : int

7527 Number of decimals to round to. May be negative.

7528 out : array_like

7529 Existing array to use for output.

7530 If not given, returns a default copy of a.

7531

7532 Notes

7533 -----

7534 If out is given and does not have a mask attribute, the mask of a

7535 is lost!

7536

7537 Examples

7538 --------

7539 >>> import numpy.ma as ma

7540 >>> x = [11.2, -3.973, 0.801, -1.41]

7541 >>> mask = [0, 0, 0, 1]

7542 >>> masked_x = ma.masked_array(x, mask)

7543 >>> masked_x

7544 masked_array(data=[11.2, -3.973, 0.801, --],

7545 mask=[False, False, False, True],

7546 fill_value=1e+20)

7547 >>> ma.round_(masked_x)

7548 masked_array(data=[11.0, -4.0, 1.0, --],

7549 mask=[False, False, False, True],

7550 fill_value=1e+20)

7551 >>> ma.round(masked_x, decimals=1)

7552 masked_array(data=[11.2, -4.0, 0.8, --],

7553 mask=[False, False, False, True],

7554 fill_value=1e+20)

7555 >>> ma.round_(masked_x, decimals=-1)

7556 masked_array(data=[10.0, -0.0, 0.0, --],

7557 mask=[False, False, False, True],

7558 fill_value=1e+20)

7559 """

7560 if out is None:

7561 return np.round_(a, decimals, out)

7562 else:

7563 np.round_(getdata(a), decimals, out)

7564 if hasattr(out, '_mask'):

7565 out._mask = getmask(a)

7566 return out

7567 round = round_

7568

7569

7570# Needed by dot, so move here from extras.py. It will still be exported

7571# from extras.py for compatibility.

7572 def mask_rowcols(a, axis=None):

7573 """

7574 Mask rows and/or columns of a 2D array that contain masked values.

7575

7576 Mask whole rows and/or columns of a 2D array that contain

7577 masked values. The masking behavior is selected using the

7578 `axis` parameter.

7579

7580 - If `axis` is None, rows *and* columns are masked.

7581 - If `axis` is 0, only rows are masked.

7582 - If `axis` is 1 or -1, only columns are masked.

7583

7584 Parameters

7585 ----------

7586 a : array_like, MaskedArray

7587 The array to mask. If not a MaskedArray instance (or if no array

7588 elements are masked). The result is a MaskedArray with `mask` set

7589 to `nomask` (False). Must be a 2D array.

7590 axis : int, optional

7591 Axis along which to perform the operation. If None, applies to a

7592 flattened version of the array.

7593

7594 Returns

7595 -------

7596 a : MaskedArray

7597 A modified version of the input array, masked depending on the value

7598 of the `axis` parameter.

7599

7600 Raises

7601 ------

7602 NotImplementedError

7603 If input array `a` is not 2D.

7604

7605 See Also

7606 --------

7607 mask_rows : Mask rows of a 2D array that contain masked values.

7608 mask_cols : Mask cols of a 2D array that contain masked values.

7609 masked_where : Mask where a condition is met.

7610

7611 Notes

7612 -----

7613 The input array's mask is modified by this function.

7614

7615 Examples

7616 --------

7617 >>> import numpy.ma as ma

7618 >>> a = np.zeros((3, 3), dtype=int)

7619 >>> a[1, 1] = 1

7620 >>> a

7621 array([[0, 0, 0],

7622 [0, 1, 0],

7623 [0, 0, 0]])

7624 >>> a = ma.masked_equal(a, 1)

7625 >>> a

7626 masked_array(

7627 data=[[0, 0, 0],

7628 [0, --, 0],

7629 [0, 0, 0]],

7630 mask=[[False, False, False],

7631 [False, True, False],

7632 [False, False, False]],

7633 fill_value=1)

7634 >>> ma.mask_rowcols(a)

7635 masked_array(

7636 data=[[0, --, 0],

7637 [--, --, --],

7638 [0, --, 0]],

7639 mask=[[False, True, False],

7640 [ True, True, True],

7641 [False, True, False]],

7642 fill_value=1)

7643

7644 """

7645 a = array(a, subok=False)

7646 if a.ndim != 2:

7647 raise NotImplementedError("mask_rowcols works for 2D arrays only.")

7648 m = getmask(a)

7649 # Nothing is masked: return a

7650 if m is nomask or not m.any():

7651 return a

7652 maskedval = m.nonzero()

7653 a._mask = a._mask.copy()

7654 if not axis:

7655 a[np.unique(maskedval[0])] = masked

7656 if axis in [None, 1, -1]:

7657 a[:, np.unique(maskedval[1])] = masked

7658 return a

7659

7660

7661# Include masked dot here to avoid import problems in getting it from

7662# extras.py. Note that it is not included in __all__, but rather exported

7663# from extras in order to avoid backward compatibility problems.

7664 def dot(a, b, strict=False, out=None):

7665 """

7666 Return the dot product of two arrays.

7667

7668 This function is the equivalent of `numpy.dot` that takes masked values

7669 into account. Note that `strict` and `out` are in different position

7670 than in the method version. In order to maintain compatibility with the

7671 corresponding method, it is recommended that the optional arguments be

7672 treated as keyword only. At some point that may be mandatory.

7673

7674 .. note::

7675 Works only with 2-D arrays at the moment.

7676

7677

7678 Parameters

7679 ----------

7680 a, b : masked_array_like

7681 Inputs arrays.

7682 strict : bool, optional

7683 Whether masked data are propagated (True) or set to 0 (False) for

7684 the computation. Default is False. Propagating the mask means that

7685 if a masked value appears in a row or column, the whole row or

7686 column is considered masked.

7687 out : masked_array, optional

7688 Output argument. This must have the exact kind that would be returned

7689 if it was not used. In particular, it must have the right type, must be

7690 C-contiguous, and its dtype must be the dtype that would be returned

7691 for `dot(a,b)`. This is a performance feature. Therefore, if these

7692 conditions are not met, an exception is raised, instead of attempting

7693 to be flexible.

7694

7695 .. versionadded:: 1.10.2

7696

7697 See Also

7698 --------

7699 numpy.dot : Equivalent function for ndarrays.

7700

7701 Examples

7702 --------

7703 >>> a = np.ma.array([[1, 2, 3], [4, 5, 6]], mask=[[1, 0, 0], [0, 0, 0]])

7704 >>> b = np.ma.array([[1, 2], [3, 4], [5, 6]], mask=[[1, 0], [0, 0], [0, 0]])

7705 >>> np.ma.dot(a, b)

7706 masked_array(

7707 data=[[21, 26],

7708 [45, 64]],

7709 mask=[[False, False],

7710 [False, False]],

7711 fill_value=999999)

7712 >>> np.ma.dot(a, b, strict=True)

7713 masked_array(

7714 data=[[--, --],

7715 [--, 64]],

7716 mask=[[ True, True],

7717 [ True, False]],

7718 fill_value=999999)

7719

7720 """

7721 # !!!: Works only with 2D arrays. There should be a way to get it to run

7722 # with higher dimension

7723 if strict and (a.ndim == 2) and (b.ndim == 2):

7724 a = mask_rowcols(a, 0)

7725 b = mask_rowcols(b, 1)

7726 am = ~getmaskarray(a)

7727 bm = ~getmaskarray(b)

7728

7729 if out is None:

7730 d = np.dot(filled(a, 0), filled(b, 0))

7731 m = ~np.dot(am, bm)

7732 if d.ndim == 0:

7733 d = np.asarray(d)

7734 r = d.view(get_masked_subclass(a, b))

7735 r.__setmask__(m)

7736 return r

7737 else:

7738 d = np.dot(filled(a, 0), filled(b, 0), out._data)

7739 if out.mask.shape != d.shape:

7740 out._mask = np.empty(d.shape, MaskType)

7741 np.dot(am, bm, out._mask)

7742 np.logical_not(out._mask, out._mask)

7743 return out

7744

7745

7746 def inner(a, b):

7747 """

7748 Returns the inner product of a and b for arrays of floating point types.

7749

7750 Like the generic NumPy equivalent the product sum is over the last dimension

7751 of a and b. The first argument is not conjugated.

7752

7753 """

7754 fa = filled(a, 0)

7755 fb = filled(b, 0)

7756 if fa.ndim == 0:

7757 fa.shape = (1,)

7758 if fb.ndim == 0:

7759 fb.shape = (1,)

7760 return np.inner(fa, fb).view(MaskedArray)

7761 inner.__doc__ = doc_note(np.inner.__doc__,

7762 "Masked values are replaced by 0.")

7763 innerproduct = inner

7764

7765

7766 def outer(a, b):

7767 "maskedarray version of the numpy function."

7768 fa = filled(a, 0).ravel()

7769 fb = filled(b, 0).ravel()

7770 d = np.outer(fa, fb)

7771 ma = getmask(a)

7772 mb = getmask(b)

7773 if ma is nomask and mb is nomask:

7774 return masked_array(d)

7775 ma = getmaskarray(a)

7776 mb = getmaskarray(b)

7777 m = make_mask(1 - np.outer(1 - ma, 1 - mb), copy=False)

7778 return masked_array(d, mask=m)

7779 outer.__doc__ = doc_note(np.outer.__doc__,

7780 "Masked values are replaced by 0.")

7781 outerproduct = outer

7782

7783

7784 def _convolve_or_correlate(f, a, v, mode, propagate_mask):

7785 """

7786 Helper function for ma.correlate and ma.convolve

7787 """

7788 if propagate_mask:

7789 # results which are contributed to by either item in any pair being invalid

7790 mask = (

7791 f(getmaskarray(a), np.ones(np.shape(v), dtype=bool), mode=mode)

7792 | f(np.ones(np.shape(a), dtype=bool), getmaskarray(v), mode=mode)

7793 )

7794 data = f(getdata(a), getdata(v), mode=mode)

7795 else:

7796 # results which are not contributed to by any pair of valid elements

7797 mask = ~f(~getmaskarray(a), ~getmaskarray(v))

7798 data = f(filled(a, 0), filled(v, 0), mode=mode)

7799

7800 return masked_array(data, mask=mask)

7801

7802

7803 def correlate(a, v, mode='valid', propagate_mask=True):

7804 """

7805 Cross-correlation of two 1-dimensional sequences.

7806

7807 Parameters

7808 ----------

7809 a, v : array_like

7810 Input sequences.

7811 mode : {'valid', 'same', 'full'}, optional

7812 Refer to the `np.convolve` docstring. Note that the default

7813 is 'valid', unlike `convolve`, which uses 'full'.

7814 propagate_mask : bool

7815 If True, then a result element is masked if any masked element contributes towards it.

7816 If False, then a result element is only masked if no non-masked element

7817 contribute towards it

7818

7819 Returns

7820 -------

7821 out : MaskedArray

7822 Discrete cross-correlation of `a` and `v`.

7823

7824 See Also

7825 --------

7826 numpy.correlate : Equivalent function in the top-level NumPy module.

7827 """

7828 return _convolve_or_correlate(np.correlate, a, v, mode, propagate_mask)

7829

7830

7831 def convolve(a, v, mode='full', propagate_mask=True):

7832 """

7833 Returns the discrete, linear convolution of two one-dimensional sequences.

7834

7835 Parameters

7836 ----------

7837 a, v : array_like

7838 Input sequences.

7839 mode : {'valid', 'same', 'full'}, optional

7840 Refer to the `np.convolve` docstring.

7841 propagate_mask : bool

7842 If True, then if any masked element is included in the sum for a result

7843 element, then the result is masked.

7844 If False, then the result element is only masked if no non-masked cells

7845 contribute towards it

7846

7847 Returns

7848 -------

7849 out : MaskedArray

7850 Discrete, linear convolution of `a` and `v`.

7851

7852 See Also

7853 --------

7854 numpy.convolve : Equivalent function in the top-level NumPy module.

7855 """

7856 return _convolve_or_correlate(np.convolve, a, v, mode, propagate_mask)

7857

7858

7859 def allequal(a, b, fill_value=True):

7860 """

7861 Return True if all entries of a and b are equal, using

7862 fill_value as a truth value where either or both are masked.

7863

7864 Parameters

7865 ----------

7866 a, b : array_like

7867 Input arrays to compare.

7868 fill_value : bool, optional

7869 Whether masked values in a or b are considered equal (True) or not

7870 (False).

7871

7872 Returns

7873 -------

7874 y : bool

7875 Returns True if the two arrays are equal within the given

7876 tolerance, False otherwise. If either array contains NaN,

7877 then False is returned.

7878

7879 See Also

7880 --------

7881 all, any

7882 numpy.ma.allclose

7883

7884 Examples

7885 --------

7886 >>> a = np.ma.array([1e10, 1e-7, 42.0], mask=[0, 0, 1])

7887 >>> a

7888 masked_array(data=[10000000000.0, 1e-07, --],

7889 mask=[False, False, True],

7890 fill_value=1e+20)

7891

7892 >>> b = np.array([1e10, 1e-7, -42.0])

7893 >>> b

7894 array([ 1.00000000e+10, 1.00000000e-07, -4.20000000e+01])

7895 >>> np.ma.allequal(a, b, fill_value=False)

7896 False

7897 >>> np.ma.allequal(a, b)

7898 True

7899

7900 """

7901 m = mask_or(getmask(a), getmask(b))

7902 if m is nomask:

7903 x = getdata(a)

7904 y = getdata(b)

7905 d = umath.equal(x, y)

7906 return d.all()

7907 elif fill_value:

7908 x = getdata(a)

7909 y = getdata(b)

7910 d = umath.equal(x, y)

7911 dm = array(d, mask=m, copy=False)

7912 return dm.filled(True).all(None)

7913 else:

7914 return False

7915

7916

7917 def allclose(a, b, masked_equal=True, rtol=1e-5, atol=1e-8):

7918 """

7919 Returns True if two arrays are element-wise equal within a tolerance.

7920

7921 This function is equivalent to `allclose` except that masked values

7922 are treated as equal (default) or unequal, depending on the `masked_equal`

7923 argument.

7924

7925 Parameters

7926 ----------

7927 a, b : array_like

7928 Input arrays to compare.

7929 masked_equal : bool, optional

7930 Whether masked values in `a` and `b` are considered equal (True) or not

7931 (False). They are considered equal by default.

7932 rtol : float, optional

7933 Relative tolerance. The relative difference is equal to ``rtol * b``.

7934 Default is 1e-5.

7935 atol : float, optional

7936 Absolute tolerance. The absolute difference is equal to `atol`.

7937 Default is 1e-8.

7938

7939 Returns

7940 -------

7941 y : bool

7942 Returns True if the two arrays are equal within the given

7943 tolerance, False otherwise. If either array contains NaN, then

7944 False is returned.

7945

7946 See Also

7947 --------

7948 all, any

7949 numpy.allclose : the non-masked `allclose`.

7950

7951 Notes

7952 -----

7953 If the following equation is element-wise True, then `allclose` returns

7954 True::

7955

7956 absolute(`a` - `b`) <= (`atol` + `rtol` * absolute(`b`))

7957

7958 Return True if all elements of `a` and `b` are equal subject to

7959 given tolerances.

7960

7961 Examples

7962 --------

7963 >>> a = np.ma.array([1e10, 1e-7, 42.0], mask=[0, 0, 1])

7964 >>> a

7965 masked_array(data=[10000000000.0, 1e-07, --],

7966 mask=[False, False, True],

7967 fill_value=1e+20)

7968 >>> b = np.ma.array([1e10, 1e-8, -42.0], mask=[0, 0, 1])

7969 >>> np.ma.allclose(a, b)

7970 False

7971

7972 >>> a = np.ma.array([1e10, 1e-8, 42.0], mask=[0, 0, 1])

7973 >>> b = np.ma.array([1.00001e10, 1e-9, -42.0], mask=[0, 0, 1])

7974 >>> np.ma.allclose(a, b)

7975 True

7976 >>> np.ma.allclose(a, b, masked_equal=False)

7977 False

7978

7979 Masked values are not compared directly.

7980

7981 >>> a = np.ma.array([1e10, 1e-8, 42.0], mask=[0, 0, 1])

7982 >>> b = np.ma.array([1.00001e10, 1e-9, 42.0], mask=[0, 0, 1])

7983 >>> np.ma.allclose(a, b)

7984 True

7985 >>> np.ma.allclose(a, b, masked_equal=False)

7986 False

7987

7988 """

7989 x = masked_array(a, copy=False)

7990 y = masked_array(b, copy=False)

7991

7992 # make sure y is an inexact type to avoid abs(MIN_INT); will cause

7993 # casting of x later.

7994 # NOTE: We explicitly allow timedelta, which used to work. This could

7995 # possibly be deprecated. See also gh-18286.

7996 # timedelta works if `atol` is an integer or also a timedelta.

7997 # Although, the default tolerances are unlikely to be useful

7998 if y.dtype.kind != "m":

7999 dtype = np.result_type(y, 1.)

8000 if y.dtype != dtype:

8001 y = masked_array(y, dtype=dtype, copy=False)

8002

8003 m = mask_or(getmask(x), getmask(y))

8004 xinf = np.isinf(masked_array(x, copy=False, mask=m)).filled(False)

8005 # If we have some infs, they should fall at the same place.

8006 if not np.all(xinf == filled(np.isinf(y), False)):

8007 return False

8008 # No infs at all

8009 if not np.any(xinf):

8010 d = filled(less_equal(absolute(x - y), atol + rtol * absolute(y)),

8011 masked_equal)

8012 return np.all(d)

8013

8014 if not np.all(filled(x[xinf] == y[xinf], masked_equal)):

8015 return False

8016 x = x[~xinf]

8017 y = y[~xinf]

8018

8019 d = filled(less_equal(absolute(x - y), atol + rtol * absolute(y)),

8020 masked_equal)

8021

8022 return np.all(d)

8023

8024

8025 def asarray(a, dtype=None, order=None):

8026 """

8027 Convert the input to a masked array of the given data-type.

8028

8029 No copy is performed if the input is already an `ndarray`. If `a` is

8030 a subclass of `MaskedArray`, a base class `MaskedArray` is returned.

8031

8032 Parameters

8033 ----------

8034 a : array_like

8035 Input data, in any form that can be converted to a masked array. This

8036 includes lists, lists of tuples, tuples, tuples of tuples, tuples

8037 of lists, ndarrays and masked arrays.

8038 dtype : dtype, optional

8039 By default, the data-type is inferred from the input data.

8040 order : {'C', 'F'}, optional

8041 Whether to use row-major ('C') or column-major ('FORTRAN') memory

8042 representation. Default is 'C'.

8043

8044 Returns

8045 -------

8046 out : MaskedArray

8047 Masked array interpretation of `a`.

8048

8049 See Also

8050 --------

8051 asanyarray : Similar to `asarray`, but conserves subclasses.

8052

8053 Examples

8054 --------

8055 >>> x = np.arange(10.).reshape(2, 5)

8056 >>> x

8057 array([[0., 1., 2., 3., 4.],

8058 [5., 6., 7., 8., 9.]])

8059 >>> np.ma.asarray(x)

8060 masked_array(

8061 data=[[0., 1., 2., 3., 4.],

8062 [5., 6., 7., 8., 9.]],

8063 mask=False,

8064 fill_value=1e+20)

8065 >>> type(np.ma.asarray(x))

8066 <class 'numpy.ma.core.MaskedArray'>

8067

8068 """

8069 order = order or 'C'

8070 return masked_array(a, dtype=dtype, copy=False, keep_mask=True,

8071 subok=False, order=order)

8072

8073

8074 def asanyarray(a, dtype=None):

8075 """

8076 Convert the input to a masked array, conserving subclasses.

8077

8078 If `a` is a subclass of `MaskedArray`, its class is conserved.

8079 No copy is performed if the input is already an `ndarray`.

8080

8081 Parameters

8082 ----------

8083 a : array_like

8084 Input data, in any form that can be converted to an array.

8085 dtype : dtype, optional

8086 By default, the data-type is inferred from the input data.

8087 order : {'C', 'F'}, optional

8088 Whether to use row-major ('C') or column-major ('FORTRAN') memory

8089 representation. Default is 'C'.

8090

8091 Returns

8092 -------

8093 out : MaskedArray

8094 MaskedArray interpretation of `a`.

8095

8096 See Also

8097 --------

8098 asarray : Similar to `asanyarray`, but does not conserve subclass.

8099

8100 Examples

8101 --------

8102 >>> x = np.arange(10.).reshape(2, 5)

8103 >>> x

8104 array([[0., 1., 2., 3., 4.],

8105 [5., 6., 7., 8., 9.]])

8106 >>> np.ma.asanyarray(x)

8107 masked_array(

8108 data=[[0., 1., 2., 3., 4.],

8109 [5., 6., 7., 8., 9.]],

8110 mask=False,

8111 fill_value=1e+20)

8112 >>> type(np.ma.asanyarray(x))

8113 <class 'numpy.ma.core.MaskedArray'>

8114

8115 """

8116 # workaround for #8666, to preserve identity. Ideally the bottom line

8117 # would handle this for us.

8118 if isinstance(a, MaskedArray) and (dtype is None or dtype == a.dtype):

8119 return a

8120 return masked_array(a, dtype=dtype, copy=False, keep_mask=True, subok=True)

8121

8122

8123##############################################################################

8124# Pickling #

8125##############################################################################

8126

8127

8128 def fromfile(file, dtype=float, count=-1, sep=''):

8129 raise NotImplementedError(

8130 "fromfile() not yet implemented for a MaskedArray.")

8131

8132

8133 def fromflex(fxarray):

8134 """

8135 Build a masked array from a suitable flexible-type array.

8136

8137 The input array has to have a data-type with ``_data`` and ``_mask``

8138 fields. This type of array is output by `MaskedArray.toflex`.

8139

8140 Parameters

8141 ----------

8142 fxarray : ndarray

8143 The structured input array, containing ``_data`` and ``_mask``

8144 fields. If present, other fields are discarded.

8145

8146 Returns

8147 -------

8148 result : MaskedArray

8149 The constructed masked array.

8150

8151 See Also

8152 --------

8153 MaskedArray.toflex : Build a flexible-type array from a masked array.

8154

8155 Examples

8156 --------

8157 >>> x = np.ma.array(np.arange(9).reshape(3, 3), mask=[0] + [1, 0] * 4)

8158 >>> rec = x.toflex()

8159 >>> rec

8160 array([[(0, False), (1, True), (2, False)],

8161 [(3, True), (4, False), (5, True)],

8162 [(6, False), (7, True), (8, False)]],

8163 dtype=[('_data', '<i8'), ('_mask', '?')])

8164 >>> x2 = np.ma.fromflex(rec)

8165 >>> x2

8166 masked_array(

8167 data=[[0, --, 2],

8168 [--, 4, --],

8169 [6, --, 8]],

8170 mask=[[False, True, False],

8171 [ True, False, True],

8172 [False, True, False]],

8173 fill_value=999999)

8174

8175 Extra fields can be present in the structured array but are discarded:

8176

8177 >>> dt = [('_data', '<i4'), ('_mask', '|b1'), ('field3', '<f4')]

8178 >>> rec2 = np.zeros((2, 2), dtype=dt)

8179 >>> rec2

8180 array([[(0, False, 0.), (0, False, 0.)],

8181 [(0, False, 0.), (0, False, 0.)]],

8182 dtype=[('_data', '<i4'), ('_mask', '?'), ('field3', '<f4')])

8183 >>> y = np.ma.fromflex(rec2)

8184 >>> y

8185 masked_array(

8186 data=[[0, 0],

8187 [0, 0]],

8188 mask=[[False, False],

8189 [False, False]],

8190 fill_value=999999,

8191 dtype=int32)

8192

8193 """

8194 return masked_array(fxarray['_data'], mask=fxarray['_mask'])

8195

8196

8197 class _convert2ma:

8198

8199 """

8200 Convert functions from numpy to numpy.ma.

8201

8202 Parameters

8203 ----------

8204 _methodname : string

8205 Name of the method to transform.

8206

8207 """

8208 __doc__ = None

8209

8210 def __init__(self, funcname, np_ret, np_ma_ret, params=None):

8211 self._func = getattr(np, funcname)

8212 self.__doc__ = self.getdoc(np_ret, np_ma_ret)

8213 self._extras = params or {}

8214

8215 def getdoc(self, np_ret, np_ma_ret):

8216 "Return the doc of the function (from the doc of the method)."

8217 doc = getattr(self._func, '__doc__', None)

8218 sig = get_object_signature(self._func)

8219 if doc:

8220 doc = self._replace_return_type(doc, np_ret, np_ma_ret)

8221 # Add the signature of the function at the beginning of the doc

8222 if sig:

8223 sig = "%s%s\n" % (self._func.__name__, sig)

8224 doc = sig + doc

8225 return doc

8226

8227 def _replace_return_type(self, doc, np_ret, np_ma_ret):

8228 """

8229 Replace documentation of ``np`` function's return type.

8230

8231 Replaces it with the proper type for the ``np.ma`` function.

8232

8233 Parameters

8234 ----------

8235 doc : str

8236 The documentation of the ``np`` method.

8237 np_ret : str

8238 The return type string of the ``np`` method that we want to

8239 replace. (e.g. "out : ndarray")

8240 np_ma_ret : str

8241 The return type string of the ``np.ma`` method.

8242 (e.g. "out : MaskedArray")

8243 """

8244 if np_ret not in doc:

8245 raise RuntimeError(

8246 f"Failed to replace `{np_ret}` with `{np_ma_ret}`. "

8247 f"The documentation string for return type, {np_ret}, is not "

8248 f"found in the docstring for `np.{self._func.__name__}`. "

8249 f"Fix the docstring for `np.{self._func.__name__}` or "

8250 "update the expected string for return type."

8251 )

8252

8253 return doc.replace(np_ret, np_ma_ret)

8254

8255 def __call__(self, *args, **params):

8256 # Find the common parameters to the call and the definition

8257 _extras = self._extras

8258 common_params = set(params).intersection(_extras)

8259 # Drop the common parameters from the call

8260 for p in common_params:

8261 _extras[p] = params.pop(p)

8262 # Get the result

8263 result = self._func.__call__(*args, **params).view(MaskedArray)

8264 if "fill_value" in common_params:

8265 result.fill_value = _extras.get("fill_value", None)

8266 if "hardmask" in common_params:

8267 result._hardmask = bool(_extras.get("hard_mask", False))

8268 return result

8269

8270

8271 arange = _convert2ma(

8272 'arange',

8273 params=dict(fill_value=None, hardmask=False),

8274 np_ret='arange : ndarray',

8275 np_ma_ret='arange : MaskedArray',

8276)

8277 clip = _convert2ma(

8278 'clip',

8279 params=dict(fill_value=None, hardmask=False),

8280 np_ret='clipped_array : ndarray',

8281 np_ma_ret='clipped_array : MaskedArray',

8282)

8283 diff = _convert2ma(

8284 'diff',

8285 params=dict(fill_value=None, hardmask=False),

8286 np_ret='diff : ndarray',

8287 np_ma_ret='diff : MaskedArray',

8288)

8289 empty = _convert2ma(

8290 'empty',

8291 params=dict(fill_value=None, hardmask=False),

8292 np_ret='out : ndarray',

8293 np_ma_ret='out : MaskedArray',

8294)

8295 empty_like = _convert2ma(

8296 'empty_like',

8297 np_ret='out : ndarray',

8298 np_ma_ret='out : MaskedArray',

8299)

8300 frombuffer = _convert2ma(

8301 'frombuffer',

8302 np_ret='out : ndarray',

8303 np_ma_ret='out: MaskedArray',

8304)

8305 fromfunction = _convert2ma(

8306 'fromfunction',

8307 np_ret='fromfunction : any',

8308 np_ma_ret='fromfunction: MaskedArray',

8309)

8310 identity = _convert2ma(

8311 'identity',

8312 params=dict(fill_value=None, hardmask=False),

8313 np_ret='out : ndarray',

8314 np_ma_ret='out : MaskedArray',

8315)

8316 indices = _convert2ma(

8317 'indices',

8318 params=dict(fill_value=None, hardmask=False),

8319 np_ret='grid : one ndarray or tuple of ndarrays',

8320 np_ma_ret='grid : one MaskedArray or tuple of MaskedArrays',

8321)

8322 ones = _convert2ma(

8323 'ones',

8324 params=dict(fill_value=None, hardmask=False),

8325 np_ret='out : ndarray',

8326 np_ma_ret='out : MaskedArray',

8327)

8328 ones_like = _convert2ma(

8329 'ones_like',

8330 np_ret='out : ndarray',

8331 np_ma_ret='out : MaskedArray',

8332)

8333 squeeze = _convert2ma(

8334 'squeeze',

8335 params=dict(fill_value=None, hardmask=False),

8336 np_ret='squeezed : ndarray',

8337 np_ma_ret='squeezed : MaskedArray',

8338)

8339 zeros = _convert2ma(

8340 'zeros',

8341 params=dict(fill_value=None, hardmask=False),

8342 np_ret='out : ndarray',

8343 np_ma_ret='out : MaskedArray',

8344)

8345 zeros_like = _convert2ma(

8346 'zeros_like',

8347 np_ret='out : ndarray',

8348 np_ma_ret='out : MaskedArray',

8349)

8350

8351

8352 def append(a, b, axis=None):

8353 """Append values to the end of an array.

8354

8355 .. versionadded:: 1.9.0

8356

8357 Parameters

8358 ----------

8359 a : array_like

8360 Values are appended to a copy of this array.

8361 b : array_like

8362 These values are appended to a copy of `a`. It must be of the

8363 correct shape (the same shape as `a`, excluding `axis`). If `axis`

8364 is not specified, `b` can be any shape and will be flattened

8365 before use.

8366 axis : int, optional

8367 The axis along which `v` are appended. If `axis` is not given,

8368 both `a` and `b` are flattened before use.

8369

8370 Returns

8371 -------

8372 append : MaskedArray

8373 A copy of `a` with `b` appended to `axis`. Note that `append`

8374 does not occur in-place: a new array is allocated and filled. If

8375 `axis` is None, the result is a flattened array.

8376

8377 See Also

8378 --------

8379 numpy.append : Equivalent function in the top-level NumPy module.

8380

8381 Examples

8382 --------

8383 >>> import numpy.ma as ma

8384 >>> a = ma.masked_values([1, 2, 3], 2)

8385 >>> b = ma.masked_values([[4, 5, 6], [7, 8, 9]], 7)

8386 >>> ma.append(a, b)

8387 masked_array(data=[1, --, 3, 4, 5, 6, --, 8, 9],

8388 mask=[False, True, False, False, False, False, True, False,

8389 False],

8390 fill_value=999999)

8391 """

8392 return concatenate([a, b], axis)