Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/numpy/ma/core.py: 27%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

2480 statements  

1""" 

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

3 

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

5at Lawrence Livermore National Laboratory. 

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

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

8and to improve support of structured arrays. 

9 

10 

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

12Released 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""" 

22import builtins 

23import functools 

24import inspect 

25import operator 

26import re 

27import textwrap 

28import warnings 

29 

30import numpy as np 

31import numpy._core.numerictypes as ntypes 

32import numpy._core.umath as umath 

33from numpy import ( 

34 _NoValue, 

35 amax, 

36 amin, 

37 angle, 

38 array as narray, # noqa: F401 

39 bool_, 

40 expand_dims, 

41 finfo, # noqa: F401 

42 iinfo, # noqa: F401 

43 iscomplexobj, 

44 ndarray, 

45) 

46from numpy._core import multiarray as mu 

47from numpy._core.numeric import normalize_axis_tuple 

48from numpy._utils import set_module 

49 

50__all__ = [ 

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

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

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

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

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

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

57 'choose', 'clip', 'common_fill_value', 'compress', 'compressed', 

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

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

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

61 'expand_dims', 'fabs', 'filled', 'fix_invalid', 'flatten_mask', 

62 'flatten_structured_array', 'floor', 'floor_divide', 'fmod', 

63 'frombuffer', 'fromflex', 'fromfunction', 'getdata', 'getmask', 

64 'getmaskarray', 'greater', 'greater_equal', 'harden_mask', 'hypot', 

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

66 'isMaskedArray', 'is_mask', 'is_masked', 'isarray', 'left_shift', 

67 'less', 'less_equal', 'log', 'log10', 'log2', 

68 'logical_and', 'logical_not', 'logical_or', 'logical_xor', 'make_mask', 

69 'make_mask_descr', 'make_mask_none', 'mask_or', 'masked', 

70 'masked_array', 'masked_equal', 'masked_greater', 

71 'masked_greater_equal', 'masked_inside', 'masked_invalid', 

72 'masked_less', 'masked_less_equal', 'masked_not_equal', 

73 'masked_object', 'masked_outside', 'masked_print_option', 

74 'masked_singleton', 'masked_values', 'masked_where', 'max', 'maximum', 

75 'maximum_fill_value', 'mean', 'min', 'minimum', 'minimum_fill_value', 

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

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

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

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

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

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

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

83 'var', 'where', 'zeros', 'zeros_like', 

84 ] 

85 

86MaskType = np.bool 

87nomask = MaskType(0) 

88 

89class MaskedArrayFutureWarning(FutureWarning): 

90 pass 

91 

92def _deprecate_argsort_axis(arr): 

93 """ 

94 Adjust the axis passed to argsort, warning if necessary 

95 

96 Parameters 

97 ---------- 

98 arr 

99 The array which argsort was called on 

100 

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

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

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

104 dimensional, so we only need a warning then. 

105 """ 

106 if arr.ndim <= 1: 

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

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

109 return -1 

110 else: 

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

112 warnings.warn( 

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

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

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

116 MaskedArrayFutureWarning, stacklevel=3) 

117 return None 

118 

119 

120def doc_note(initialdoc, note): 

121 """ 

122 Adds a Notes section to an existing docstring. 

123 

124 """ 

125 if initialdoc is None: 

126 return 

127 if note is None: 

128 return initialdoc 

129 

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

131 notedoc = f"\n\nNotes\n-----\n{inspect.cleandoc(note)}\n" 

132 

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

134 

135 

136############################################################################### 

137# Exceptions # 

138############################################################################### 

139 

140 

141class MAError(Exception): 

142 """ 

143 Class for masked array related errors. 

144 

145 """ 

146 pass 

147 

148 

149class MaskError(MAError): 

150 """ 

151 Class for mask related errors. 

152 

153 """ 

154 pass 

155 

156 

157############################################################################### 

158# Filling options # 

159############################################################################### 

160 

161 

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

163default_filler = {'b': True, 

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

165 'f': 1.e20, 

166 'i': 999999, 

167 'O': '?', 

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

169 'u': 999999, 

170 'V': b'???', 

171 'U': 'N/A', 

172 'T': 'N/A' 

173 } 

174 

175# Add datetime64 and timedelta64 types 

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

177 "fs", "as"]: 

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

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

180 

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

182 np.csingle, np.cdouble, np.clongdouble] 

183 

184_minvals: dict[type, int] = {} 

185_maxvals: dict[type, int] = {} 

186 

187for sctype in ntypes.sctypeDict.values(): 

188 scalar_dtype = np.dtype(sctype) 

189 

190 if scalar_dtype.kind in "Mm": 

191 info = np.iinfo(np.int64) 

192 min_val, max_val = info.min + 1, info.max 

193 elif np.issubdtype(scalar_dtype, np.integer): 

194 info = np.iinfo(sctype) 

195 min_val, max_val = info.min, info.max 

196 elif np.issubdtype(scalar_dtype, np.floating): 

197 info = np.finfo(sctype) 

198 min_val, max_val = info.min, info.max 

199 elif scalar_dtype.kind == "b": 

200 min_val, max_val = 0, 1 

201 else: 

202 min_val, max_val = None, None 

203 

204 _minvals[sctype] = min_val 

205 _maxvals[sctype] = max_val 

206 

207max_filler = _minvals 

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

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

210 

211min_filler = _maxvals 

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

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

214 

215del float_types_list 

216 

217def _recursive_fill_value(dtype, f): 

218 """ 

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

220 """ 

221 if dtype.names is not None: 

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

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

224 # for int8. 

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

226 vals = tuple( 

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

228 for name in dtype.names) 

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

230 elif dtype.subdtype: 

231 subtype, shape = dtype.subdtype 

232 subval = _recursive_fill_value(subtype, f) 

233 return np.full(shape, subval) 

234 else: 

235 return f(dtype) 

236 

237 

238def _get_dtype_of(obj): 

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

240 if isinstance(obj, np.dtype): 

241 return obj 

242 elif hasattr(obj, 'dtype'): 

243 return obj.dtype 

244 else: 

245 return np.asanyarray(obj).dtype 

246 

247 

248def default_fill_value(obj): 

249 """ 

250 Return the default fill value for the argument object. 

251 

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

253 array or the type of the input scalar: 

254 

255 =========== ======== 

256 datatype default 

257 =========== ======== 

258 bool True 

259 int 999999 

260 float 1.e20 

261 complex 1.e20+0j 

262 object '?' 

263 string 'N/A' 

264 StringDType 'N/A' 

265 =========== ======== 

266 

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

268 default fill value for its type. 

269 

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

271 the default scalar fill value. 

272 

273 Parameters 

274 ---------- 

275 obj : ndarray, dtype or scalar 

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

277 is returned. 

278 

279 Returns 

280 ------- 

281 fill_value : scalar 

282 The default fill value. 

283 

284 Examples 

285 -------- 

286 >>> import numpy as np 

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

288 999999 

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

290 1e+20 

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

292 (1e+20+0j) 

293 

294 """ 

295 def _scalar_fill_value(dtype): 

296 if dtype.kind in 'Mm': 

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

298 else: 

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

300 

301 dtype = _get_dtype_of(obj) 

302 return _recursive_fill_value(dtype, _scalar_fill_value) 

303 

304 

305def _extremum_fill_value(obj, extremum, extremum_name): 

306 

307 def _scalar_fill_value(dtype): 

308 try: 

309 return extremum[dtype.type] 

310 except KeyError as e: 

311 raise TypeError( 

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

313 ) from None 

314 

315 dtype = _get_dtype_of(obj) 

316 return _recursive_fill_value(dtype, _scalar_fill_value) 

317 

318 

319def minimum_fill_value(obj): 

320 """ 

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

322 

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

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

325 

326 Parameters 

327 ---------- 

328 obj : ndarray, dtype or scalar 

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

330 

331 Returns 

332 ------- 

333 val : scalar 

334 The maximum representable value. 

335 

336 Raises 

337 ------ 

338 TypeError 

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

340 

341 See Also 

342 -------- 

343 maximum_fill_value : The inverse function. 

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

345 MaskedArray.fill_value : Return current fill value. 

346 

347 Examples 

348 -------- 

349 >>> import numpy as np 

350 >>> import numpy.ma as ma 

351 >>> a = np.int8() 

352 >>> ma.minimum_fill_value(a) 

353 127 

354 >>> a = np.int32() 

355 >>> ma.minimum_fill_value(a) 

356 2147483647 

357 

358 An array of numeric data can also be passed. 

359 

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

361 >>> ma.minimum_fill_value(a) 

362 127 

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

364 >>> ma.minimum_fill_value(a) 

365 inf 

366 

367 """ 

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

369 

370 

371def maximum_fill_value(obj): 

372 """ 

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

374 

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

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

377 

378 Parameters 

379 ---------- 

380 obj : ndarray, dtype or scalar 

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

382 

383 Returns 

384 ------- 

385 val : scalar 

386 The minimum representable value. 

387 

388 Raises 

389 ------ 

390 TypeError 

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

392 

393 See Also 

394 -------- 

395 minimum_fill_value : The inverse function. 

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

397 MaskedArray.fill_value : Return current fill value. 

398 

399 Examples 

400 -------- 

401 >>> import numpy as np 

402 >>> import numpy.ma as ma 

403 >>> a = np.int8() 

404 >>> ma.maximum_fill_value(a) 

405 -128 

406 >>> a = np.int32() 

407 >>> ma.maximum_fill_value(a) 

408 -2147483648 

409 

410 An array of numeric data can also be passed. 

411 

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

413 >>> ma.maximum_fill_value(a) 

414 -128 

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

416 >>> ma.maximum_fill_value(a) 

417 -inf 

418 

419 """ 

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

421 

422 

423def _recursive_set_fill_value(fillvalue, dt): 

424 """ 

425 Create a fill value for a structured dtype. 

426 

427 Parameters 

428 ---------- 

429 fillvalue : scalar or array_like 

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

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

432 dt : dtype 

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

434 

435 Returns 

436 ------- 

437 val : tuple 

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

439 

440 """ 

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

442 output_value = [] 

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

444 cdtype = dt[name] 

445 if cdtype.subdtype: 

446 cdtype = cdtype.subdtype[0] 

447 

448 if cdtype.names is not None: 

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

450 else: 

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

452 return tuple(output_value) 

453 

454 

455def _check_fill_value(fill_value, ndtype): 

456 """ 

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

458 

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

460 

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

462 

463 The result is always a 0d array. 

464 

465 """ 

466 ndtype = np.dtype(ndtype) 

467 if fill_value is None: 

468 fill_value = default_fill_value(ndtype) 

469 # TODO: It seems better to always store a valid fill_value, the oddity 

470 # about is that `_fill_value = None` would behave even more 

471 # different then. 

472 # (e.g. this allows arr_uint8.astype(int64) to have the default 

473 # fill value again...) 

474 # The one thing that changed in 2.0/2.1 around cast safety is that the 

475 # default `int(99...)` is not a same-kind cast anymore, so if we 

476 # have a uint, use the default uint. 

477 if ndtype.kind == "u": 

478 fill_value = np.uint(fill_value) 

479 elif ndtype.names is not None: 

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

481 try: 

482 fill_value = np.asarray(fill_value, dtype=ndtype) 

483 except ValueError as e: 

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

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

486 else: 

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

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

489 dtype=ndtype) 

490 elif isinstance(fill_value, str) and (ndtype.char not in 'OSTVU'): 

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

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

493 raise TypeError(err_msg % ndtype) 

494 else: 

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

496 # Also in case of converting string arrays. 

497 try: 

498 fill_value = np.asarray(fill_value, dtype=ndtype) 

499 except (OverflowError, ValueError) as e: 

500 # Raise TypeError instead of OverflowError or ValueError. 

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

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

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

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

505 return np.array(fill_value) 

506 

507 

508def set_fill_value(a, fill_value): 

509 """ 

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

511 

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

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

514 doing anything. 

515 

516 Parameters 

517 ---------- 

518 a : array_like 

519 Input array. 

520 fill_value : dtype 

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

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

523 

524 Returns 

525 ------- 

526 None 

527 Nothing returned by this function. 

528 

529 See Also 

530 -------- 

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

532 MaskedArray.fill_value : Return current fill value. 

533 MaskedArray.set_fill_value : Equivalent method. 

534 

535 Examples 

536 -------- 

537 >>> import numpy as np 

538 >>> import numpy.ma as ma 

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

540 >>> a 

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

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

543 >>> a 

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

545 mask=[ True, True, True, False, False], 

546 fill_value=999999) 

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

548 >>> a 

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

550 mask=[ True, True, True, False, False], 

551 fill_value=-999) 

552 

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

554 

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

556 >>> a 

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

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

559 >>> a 

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

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

562 >>> a 

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

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

565 >>> a 

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

567 

568 """ 

569 if isinstance(a, MaskedArray): 

570 a.set_fill_value(fill_value) 

571 

572 

573def get_fill_value(a): 

574 """ 

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

576 default filling value for that type. 

577 

578 """ 

579 if isinstance(a, MaskedArray): 

580 result = a.fill_value 

581 else: 

582 result = default_fill_value(a) 

583 return result 

584 

585 

586def common_fill_value(a, b): 

587 """ 

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

589 

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

591 otherwise return None. 

592 

593 Parameters 

594 ---------- 

595 a, b : MaskedArray 

596 The masked arrays for which to compare fill values. 

597 

598 Returns 

599 ------- 

600 fill_value : scalar or None 

601 The common fill value, or None. 

602 

603 Examples 

604 -------- 

605 >>> import numpy as np 

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

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

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

609 3.0 

610 

611 """ 

612 t1 = get_fill_value(a) 

613 t2 = get_fill_value(b) 

614 if t1 == t2: 

615 return t1 

616 return None 

617 

618 

619def filled(a, fill_value=None): 

620 """ 

621 Return input as an `~numpy.ndarray`, with masked values replaced by 

622 `fill_value`. 

623 

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

625 If `a` is a `MaskedArray` with no masked values, then ``a.data`` is 

626 returned. 

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

628 ``a.fill_value``. 

629 

630 Parameters 

631 ---------- 

632 a : MaskedArray or array_like 

633 An input object. 

634 fill_value : array_like, optional. 

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

636 resulting filled array should be broadcastable 

637 over input array. Default is None. 

638 

639 Returns 

640 ------- 

641 a : ndarray 

642 The filled array. 

643 

644 See Also 

645 -------- 

646 compressed 

647 

648 Examples 

649 -------- 

650 >>> import numpy as np 

651 >>> import numpy.ma as ma 

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

653 ... [1, 0, 0], 

654 ... [0, 0, 0]]) 

655 >>> x.filled() 

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

657 [999999, 4, 5], 

658 [ 6, 7, 8]]) 

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

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

661 [333, 4, 5], 

662 [ 6, 7, 8]]) 

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

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

665 [0, 4, 5], 

666 [6, 7, 8]]) 

667 

668 """ 

669 if hasattr(a, 'filled'): 

670 return a.filled(fill_value) 

671 

672 elif isinstance(a, ndarray): 

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

674 return a 

675 elif isinstance(a, dict): 

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

677 else: 

678 return np.array(a) 

679 

680 

681def get_masked_subclass(*arrays): 

682 """ 

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

684 

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

686 

687 """ 

688 if len(arrays) == 1: 

689 arr = arrays[0] 

690 if isinstance(arr, MaskedArray): 

691 rcls = type(arr) 

692 else: 

693 rcls = MaskedArray 

694 else: 

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

696 rcls = arrcls[0] 

697 if not issubclass(rcls, MaskedArray): 

698 rcls = MaskedArray 

699 for cls in arrcls[1:]: 

700 if issubclass(cls, rcls): 

701 rcls = cls 

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

703 if rcls.__name__ == 'MaskedConstant': 

704 return MaskedArray 

705 return rcls 

706 

707 

708def getdata(a, subok=True): 

709 """ 

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

711 

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

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

714 

715 Parameters 

716 ---------- 

717 a : array_like 

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

719 subok : bool 

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

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

722 

723 See Also 

724 -------- 

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

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

727 

728 Examples 

729 -------- 

730 >>> import numpy as np 

731 >>> import numpy.ma as ma 

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

733 >>> a 

734 masked_array( 

735 data=[[1, --], 

736 [3, 4]], 

737 mask=[[False, True], 

738 [False, False]], 

739 fill_value=2) 

740 >>> ma.getdata(a) 

741 array([[1, 2], 

742 [3, 4]]) 

743 

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

745 

746 >>> a.data 

747 array([[1, 2], 

748 [3, 4]]) 

749 

750 """ 

751 try: 

752 data = a._data 

753 except AttributeError: 

754 data = np.array(a, copy=None, subok=subok) 

755 if not subok: 

756 return data.view(ndarray) 

757 return data 

758 

759 

760get_data = getdata 

761 

762 

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

764 """ 

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

766 

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

768 

769 Parameters 

770 ---------- 

771 a : array_like 

772 Input array, a (subclass of) ndarray. 

773 mask : sequence, optional 

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

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

776 copy : bool, optional 

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

778 Default is True. 

779 fill_value : scalar, optional 

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

781 the ``a.fill_value`` is used. 

782 

783 Returns 

784 ------- 

785 b : MaskedArray 

786 The input array with invalid entries fixed. 

787 

788 Notes 

789 ----- 

790 A copy is performed by default. 

791 

792 Examples 

793 -------- 

794 >>> import numpy as np 

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

796 >>> x 

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

798 mask=[ True, False, False, False], 

799 fill_value=1e+20) 

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

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

802 mask=[ True, False, True, True], 

803 fill_value=1e+20) 

804 

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

806 >>> fixed.data 

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

808 >>> x.data 

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

810 

811 """ 

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

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

814 if not invalid.any(): 

815 return a 

816 a._mask |= invalid 

817 if fill_value is None: 

818 fill_value = a.fill_value 

819 a._data[invalid] = fill_value 

820 return a 

821 

822def is_string_or_list_of_strings(val): 

823 return (isinstance(val, str) or 

824 (isinstance(val, list) and val and 

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

826 

827############################################################################### 

828# Ufuncs # 

829############################################################################### 

830 

831 

832ufunc_domain = {} 

833ufunc_fills = {} 

834 

835 

836class _DomainCheckInterval: 

837 """ 

838 Define a valid interval, so that : 

839 

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

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

842 

843 """ 

844 

845 def __init__(self, a, b): 

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

847 if a > b: 

848 (a, b) = (b, a) 

849 self.a = a 

850 self.b = b 

851 

852 def __call__(self, x): 

853 "Execute the call behavior." 

854 # nans at masked positions cause RuntimeWarnings, even though 

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

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

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

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

859 

860 

861class _DomainTan: 

862 """ 

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

864 

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

866 

867 """ 

868 

869 def __init__(self, eps): 

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

871 self.eps = eps 

872 

873 def __call__(self, x): 

874 "Executes the call behavior." 

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

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

877 

878 

879class _DomainSafeDivide: 

880 """ 

881 Define a domain for safe division. 

882 

883 """ 

884 

885 def __init__(self, tolerance=None): 

886 self.tolerance = tolerance 

887 

888 def __call__(self, a, b): 

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

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

891 # component of numpy's import time. 

892 if self.tolerance is None: 

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

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

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

896 with np.errstate(all='ignore'): 

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

898 

899 

900class _DomainGreater: 

901 """ 

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

903 

904 """ 

905 

906 def __init__(self, critical_value): 

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

908 self.critical_value = critical_value 

909 

910 def __call__(self, x): 

911 "Executes the call behavior." 

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

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

914 

915 

916class _DomainGreaterEqual: 

917 """ 

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

919 

920 """ 

921 

922 def __init__(self, critical_value): 

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

924 self.critical_value = critical_value 

925 

926 def __call__(self, x): 

927 "Executes the call behavior." 

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

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

930 

931 

932class _MaskedUFunc: 

933 def __init__(self, ufunc): 

934 self.f = ufunc 

935 self.__doc__ = ufunc.__doc__ 

936 self.__name__ = ufunc.__name__ 

937 self.__qualname__ = ufunc.__qualname__ 

938 

939 def __str__(self): 

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

941 

942 

943class _MaskedUnaryOperation(_MaskedUFunc): 

944 """ 

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

946 pre-masked. 

947 

948 Parameters 

949 ---------- 

950 mufunc : callable 

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

952 as ``_MaskedUnaryOperation.f``. 

953 fill : scalar, optional 

954 Filling value, default is 0. 

955 domain : class instance 

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

957 classes. Default is None. 

958 

959 """ 

960 

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

962 super().__init__(mufunc) 

963 self.fill = fill 

964 self.domain = domain 

965 ufunc_domain[mufunc] = domain 

966 ufunc_fills[mufunc] = fill 

967 

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

969 """ 

970 Execute the call behavior. 

971 

972 """ 

973 d = getdata(a) 

974 # Deal with domain 

975 if self.domain is not None: 

976 # Case 1.1. : Domained function 

977 # nans at masked positions cause RuntimeWarnings, even though 

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

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

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

981 # Make a mask 

982 m = ~umath.isfinite(result) 

983 m |= self.domain(d) 

984 m |= getmask(a) 

985 else: 

986 # Case 1.2. : Function without a domain 

987 # Get the result and the mask 

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

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

990 m = getmask(a) 

991 

992 if not result.ndim: 

993 # Case 2.1. : The result is scalarscalar 

994 if m: 

995 return masked 

996 return result 

997 

998 if m is not nomask: 

999 # Case 2.2. The result is an array 

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

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

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

1003 

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

1005 # equal) 

1006 try: 

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

1008 except TypeError: 

1009 pass 

1010 # Transform to 

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

1012 masked_result._mask = m 

1013 masked_result._update_from(a) 

1014 return masked_result 

1015 

1016 

1017class _MaskedBinaryOperation(_MaskedUFunc): 

1018 """ 

1019 Define masked version of binary operations, where invalid 

1020 values are pre-masked. 

1021 

1022 Parameters 

1023 ---------- 

1024 mbfunc : function 

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

1026 as ``_MaskedBinaryOperation.f``. 

1027 domain : class instance 

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

1029 classes. Default is None. 

1030 fillx : scalar, optional 

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

1032 filly : scalar, optional 

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

1034 

1035 """ 

1036 

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

1038 """ 

1039 abfunc(fillx, filly) must be defined. 

1040 

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

1042 

1043 """ 

1044 super().__init__(mbfunc) 

1045 self.fillx = fillx 

1046 self.filly = filly 

1047 ufunc_domain[mbfunc] = None 

1048 ufunc_fills[mbfunc] = (fillx, filly) 

1049 

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

1051 """ 

1052 Execute the call behavior. 

1053 

1054 """ 

1055 # Get the data, as ndarray 

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

1057 # Get the result 

1058 with np.errstate(): 

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

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

1061 # Get the mask for the result 

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

1063 if ma is nomask: 

1064 if mb is nomask: 

1065 m = nomask 

1066 else: 

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

1068 elif mb is nomask: 

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

1070 else: 

1071 m = umath.logical_or(ma, mb) 

1072 

1073 # Case 1. : scalar 

1074 if not result.ndim: 

1075 if m: 

1076 return masked 

1077 return result 

1078 

1079 # Case 2. : array 

1080 # Revert result to da where masked 

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

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

1083 try: 

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

1085 except Exception: 

1086 pass 

1087 

1088 # Transforms to a (subclass of) MaskedArray 

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

1090 masked_result._mask = m 

1091 if isinstance(a, MaskedArray): 

1092 masked_result._update_from(a) 

1093 elif isinstance(b, MaskedArray): 

1094 masked_result._update_from(b) 

1095 return masked_result 

1096 

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

1098 """ 

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

1100 

1101 """ 

1102 tclass = get_masked_subclass(target) 

1103 m = getmask(target) 

1104 t = filled(target, self.filly) 

1105 if t.shape == (): 

1106 t = t.reshape(1) 

1107 if m is not nomask: 

1108 m = make_mask(m, copy=True) 

1109 m.shape = (1,) 

1110 

1111 if m is nomask: 

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

1113 mr = nomask 

1114 else: 

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

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

1117 

1118 if not tr.shape: 

1119 if mr: 

1120 return masked 

1121 else: 

1122 return tr 

1123 masked_tr = tr.view(tclass) 

1124 masked_tr._mask = mr 

1125 return masked_tr 

1126 

1127 def outer(self, a, b): 

1128 """ 

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

1130 

1131 """ 

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

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

1134 ma = getmask(a) 

1135 mb = getmask(b) 

1136 if ma is nomask and mb is nomask: 

1137 m = nomask 

1138 else: 

1139 ma = getmaskarray(a) 

1140 mb = getmaskarray(b) 

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

1142 if (not m.ndim) and m: 

1143 return masked 

1144 if m is not nomask: 

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

1146 if not d.shape: 

1147 return d 

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

1149 masked_d._mask = m 

1150 return masked_d 

1151 

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

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

1154 value. 

1155 

1156 """ 

1157 tclass = get_masked_subclass(target) 

1158 t = filled(target, self.filly) 

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

1160 masked_result = result.view(tclass) 

1161 return masked_result 

1162 

1163 

1164class _DomainedBinaryOperation(_MaskedUFunc): 

1165 """ 

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

1167 

1168 They have no reduce, outer or accumulate. 

1169 

1170 Parameters 

1171 ---------- 

1172 mbfunc : function 

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

1174 as ``_DomainedBinaryOperation.f``. 

1175 domain : class instance 

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

1177 classes. 

1178 fillx : scalar, optional 

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

1180 filly : scalar, optional 

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

1182 

1183 """ 

1184 

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

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

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

1188 """ 

1189 super().__init__(dbfunc) 

1190 self.domain = domain 

1191 self.fillx = fillx 

1192 self.filly = filly 

1193 ufunc_domain[dbfunc] = domain 

1194 ufunc_fills[dbfunc] = (fillx, filly) 

1195 

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

1197 "Execute the call behavior." 

1198 # Get the data 

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

1200 # Get the result 

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

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

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

1204 m = ~umath.isfinite(result) 

1205 m |= getmask(a) 

1206 m |= getmask(b) 

1207 # Apply the domain 

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

1209 if domain is not None: 

1210 m |= domain(da, db) 

1211 # Take care of the scalar case first 

1212 if not m.ndim: 

1213 if m: 

1214 return masked 

1215 else: 

1216 return result 

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

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

1219 try: 

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

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

1222 masked_da = umath.multiply(m, da) 

1223 # only add back if it can be cast safely 

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

1225 result += masked_da 

1226 except Exception: 

1227 pass 

1228 

1229 # Transforms to a (subclass of) MaskedArray 

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

1231 masked_result._mask = m 

1232 if isinstance(a, MaskedArray): 

1233 masked_result._update_from(a) 

1234 elif isinstance(b, MaskedArray): 

1235 masked_result._update_from(b) 

1236 return masked_result 

1237 

1238 

1239# Unary ufuncs 

1240exp = _MaskedUnaryOperation(umath.exp) 

1241conjugate = _MaskedUnaryOperation(umath.conjugate) 

1242sin = _MaskedUnaryOperation(umath.sin) 

1243cos = _MaskedUnaryOperation(umath.cos) 

1244arctan = _MaskedUnaryOperation(umath.arctan) 

1245arcsinh = _MaskedUnaryOperation(umath.arcsinh) 

1246sinh = _MaskedUnaryOperation(umath.sinh) 

1247cosh = _MaskedUnaryOperation(umath.cosh) 

1248tanh = _MaskedUnaryOperation(umath.tanh) 

1249abs = absolute = _MaskedUnaryOperation(umath.absolute) 

1250angle = _MaskedUnaryOperation(angle) 

1251fabs = _MaskedUnaryOperation(umath.fabs) 

1252negative = _MaskedUnaryOperation(umath.negative) 

1253floor = _MaskedUnaryOperation(umath.floor) 

1254ceil = _MaskedUnaryOperation(umath.ceil) 

1255around = _MaskedUnaryOperation(np.around) 

1256logical_not = _MaskedUnaryOperation(umath.logical_not) 

1257 

1258# Domained unary ufuncs 

1259sqrt = _MaskedUnaryOperation(umath.sqrt, 0.0, 

1260 _DomainGreaterEqual(0.0)) 

1261log = _MaskedUnaryOperation(umath.log, 1.0, 

1262 _DomainGreater(0.0)) 

1263log2 = _MaskedUnaryOperation(umath.log2, 1.0, 

1264 _DomainGreater(0.0)) 

1265log10 = _MaskedUnaryOperation(umath.log10, 1.0, 

1266 _DomainGreater(0.0)) 

1267tan = _MaskedUnaryOperation(umath.tan, 0.0, 

1268 _DomainTan(1e-35)) 

1269arcsin = _MaskedUnaryOperation(umath.arcsin, 0.0, 

1270 _DomainCheckInterval(-1.0, 1.0)) 

1271arccos = _MaskedUnaryOperation(umath.arccos, 0.0, 

1272 _DomainCheckInterval(-1.0, 1.0)) 

1273arccosh = _MaskedUnaryOperation(umath.arccosh, 1.0, 

1274 _DomainGreaterEqual(1.0)) 

1275arctanh = _MaskedUnaryOperation(umath.arctanh, 0.0, 

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

1277 

1278# Binary ufuncs 

1279add = _MaskedBinaryOperation(umath.add) 

1280subtract = _MaskedBinaryOperation(umath.subtract) 

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

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

1283equal = _MaskedBinaryOperation(umath.equal) 

1284equal.reduce = None 

1285not_equal = _MaskedBinaryOperation(umath.not_equal) 

1286not_equal.reduce = None 

1287less_equal = _MaskedBinaryOperation(umath.less_equal) 

1288less_equal.reduce = None 

1289greater_equal = _MaskedBinaryOperation(umath.greater_equal) 

1290greater_equal.reduce = None 

1291less = _MaskedBinaryOperation(umath.less) 

1292less.reduce = None 

1293greater = _MaskedBinaryOperation(umath.greater) 

1294greater.reduce = None 

1295logical_and = _MaskedBinaryOperation(umath.logical_and) 

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

1297logical_or = _MaskedBinaryOperation(umath.logical_or) 

1298sometrue = logical_or.reduce 

1299logical_xor = _MaskedBinaryOperation(umath.logical_xor) 

1300bitwise_and = _MaskedBinaryOperation(umath.bitwise_and) 

1301bitwise_or = _MaskedBinaryOperation(umath.bitwise_or) 

1302bitwise_xor = _MaskedBinaryOperation(umath.bitwise_xor) 

1303hypot = _MaskedBinaryOperation(umath.hypot) 

1304 

1305# Domained binary ufuncs 

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

1307true_divide = divide # Just an alias for divide. 

1308floor_divide = _DomainedBinaryOperation(umath.floor_divide, 

1309 _DomainSafeDivide(), 0, 1) 

1310remainder = _DomainedBinaryOperation(umath.remainder, 

1311 _DomainSafeDivide(), 0, 1) 

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

1313mod = remainder 

1314 

1315############################################################################### 

1316# Mask creation functions # 

1317############################################################################### 

1318 

1319 

1320def _replace_dtype_fields_recursive(dtype, primitive_dtype): 

1321 "Private function allowing recursion in _replace_dtype_fields." 

1322 _recurse = _replace_dtype_fields_recursive 

1323 

1324 # Do we have some name fields ? 

1325 if dtype.names is not None: 

1326 descr = [] 

1327 for name in dtype.names: 

1328 field = dtype.fields[name] 

1329 if len(field) == 3: 

1330 # Prepend the title to the name 

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

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

1333 new_dtype = np.dtype(descr) 

1334 

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

1336 elif dtype.subdtype: 

1337 descr = list(dtype.subdtype) 

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

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

1340 

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

1342 else: 

1343 new_dtype = primitive_dtype 

1344 

1345 # preserve identity of dtypes 

1346 if new_dtype == dtype: 

1347 new_dtype = dtype 

1348 

1349 return new_dtype 

1350 

1351 

1352def _replace_dtype_fields(dtype, primitive_dtype): 

1353 """ 

1354 Construct a dtype description list from a given dtype. 

1355 

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

1357 recursively replaced with `primitive_dtype`. 

1358 

1359 Arguments are coerced to dtypes first. 

1360 """ 

1361 dtype = np.dtype(dtype) 

1362 primitive_dtype = np.dtype(primitive_dtype) 

1363 return _replace_dtype_fields_recursive(dtype, primitive_dtype) 

1364 

1365 

1366def make_mask_descr(ndtype): 

1367 """ 

1368 Construct a dtype description list from a given dtype. 

1369 

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

1371 boolean type. Field names are not altered. 

1372 

1373 Parameters 

1374 ---------- 

1375 ndtype : dtype 

1376 The dtype to convert. 

1377 

1378 Returns 

1379 ------- 

1380 result : dtype 

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

1382 

1383 Examples 

1384 -------- 

1385 >>> import numpy as np 

1386 >>> import numpy.ma as ma 

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

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

1389 >>> dtype 

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

1391 >>> ma.make_mask_descr(dtype) 

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

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

1394 dtype('bool') 

1395 

1396 """ 

1397 return _replace_dtype_fields(ndtype, MaskType) 

1398 

1399 

1400def getmask(a): 

1401 """ 

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

1403 

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

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

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

1407 

1408 Parameters 

1409 ---------- 

1410 a : array_like 

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

1412 

1413 See Also 

1414 -------- 

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

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

1417 

1418 Examples 

1419 -------- 

1420 >>> import numpy as np 

1421 >>> import numpy.ma as ma 

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

1423 >>> a 

1424 masked_array( 

1425 data=[[1, --], 

1426 [3, 4]], 

1427 mask=[[False, True], 

1428 [False, False]], 

1429 fill_value=2) 

1430 >>> ma.getmask(a) 

1431 array([[False, True], 

1432 [False, False]]) 

1433 

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

1435 

1436 >>> a.mask 

1437 array([[False, True], 

1438 [False, False]]) 

1439 

1440 Result when mask == `nomask` 

1441 

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

1443 >>> b 

1444 masked_array( 

1445 data=[[1, 2], 

1446 [3, 4]], 

1447 mask=False, 

1448 fill_value=999999) 

1449 >>> ma.nomask 

1450 False 

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

1452 True 

1453 >>> b.mask == ma.nomask 

1454 True 

1455 

1456 """ 

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

1458 

1459 

1460get_mask = getmask 

1461 

1462 

1463def getmaskarray(arr): 

1464 """ 

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

1466 

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

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

1469 the same shape as `arr`. 

1470 

1471 Parameters 

1472 ---------- 

1473 arr : array_like 

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

1475 

1476 See Also 

1477 -------- 

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

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

1480 

1481 Examples 

1482 -------- 

1483 >>> import numpy as np 

1484 >>> import numpy.ma as ma 

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

1486 >>> a 

1487 masked_array( 

1488 data=[[1, --], 

1489 [3, 4]], 

1490 mask=[[False, True], 

1491 [False, False]], 

1492 fill_value=2) 

1493 >>> ma.getmaskarray(a) 

1494 array([[False, True], 

1495 [False, False]]) 

1496 

1497 Result when mask == ``nomask`` 

1498 

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

1500 >>> b 

1501 masked_array( 

1502 data=[[1, 2], 

1503 [3, 4]], 

1504 mask=False, 

1505 fill_value=999999) 

1506 >>> ma.getmaskarray(b) 

1507 array([[False, False], 

1508 [False, False]]) 

1509 

1510 """ 

1511 mask = getmask(arr) 

1512 if mask is nomask: 

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

1514 return mask 

1515 

1516 

1517def is_mask(m): 

1518 """ 

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

1520 

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

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

1523 mask has a flexible dtype. 

1524 

1525 Parameters 

1526 ---------- 

1527 m : array_like 

1528 Array to test. 

1529 

1530 Returns 

1531 ------- 

1532 result : bool 

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

1534 

1535 See Also 

1536 -------- 

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

1538 

1539 Examples 

1540 -------- 

1541 >>> import numpy as np 

1542 >>> import numpy.ma as ma 

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

1544 >>> m 

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

1546 mask=[ True, False, True, False, False], 

1547 fill_value=0) 

1548 >>> ma.is_mask(m) 

1549 False 

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

1551 True 

1552 

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

1554 for it to be considered a valid mask. 

1555 

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

1557 >>> ma.is_mask(m) 

1558 False 

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

1560 >>> m 

1561 array([False, True, False]) 

1562 >>> ma.is_mask(m) 

1563 True 

1564 

1565 Arrays with complex dtypes don't return True. 

1566 

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

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

1569 >>> dtype 

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

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

1572 ... dtype=dtype) 

1573 >>> m 

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

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

1576 >>> ma.is_mask(m) 

1577 False 

1578 

1579 """ 

1580 try: 

1581 return m.dtype.type is MaskType 

1582 except AttributeError: 

1583 return False 

1584 

1585 

1586def _shrink_mask(m): 

1587 """ 

1588 Shrink a mask to nomask if possible 

1589 """ 

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

1591 return nomask 

1592 else: 

1593 return m 

1594 

1595 

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

1597 """ 

1598 Create a boolean mask from an array. 

1599 

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

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

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

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

1604 

1605 Parameters 

1606 ---------- 

1607 m : array_like 

1608 Potential mask. 

1609 copy : bool, optional 

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

1611 shrink : bool, optional 

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

1613 dtype : dtype, optional 

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

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

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

1617 case ``nomask`` is always returned. 

1618 

1619 Returns 

1620 ------- 

1621 result : ndarray 

1622 A boolean mask derived from `m`. 

1623 

1624 Examples 

1625 -------- 

1626 >>> import numpy as np 

1627 >>> import numpy.ma as ma 

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

1629 >>> ma.make_mask(m) 

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

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

1632 >>> ma.make_mask(m) 

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

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

1635 >>> ma.make_mask(m) 

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

1637 

1638 Effect of the `shrink` parameter. 

1639 

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

1641 >>> m 

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

1643 >>> ma.make_mask(m) 

1644 False 

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

1646 array([False, False, False, False]) 

1647 

1648 Using a flexible `dtype`. 

1649 

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

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

1652 >>> arr = [] 

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

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

1655 >>> arr 

1656 [(1, 0), (0, 1), (1, 0), (1, 0)] 

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

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

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

1660 >>> arr 

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

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

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

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

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

1666 

1667 """ 

1668 if m is nomask: 

1669 return nomask 

1670 

1671 # Make sure the input dtype is valid. 

1672 dtype = make_mask_descr(dtype) 

1673 

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

1675 if isinstance(m, ndarray) and m.dtype.fields and dtype == np.bool: 

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

1677 

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

1679 copy = None if not copy else True 

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

1681 # Bas les masques ! 

1682 if shrink: 

1683 result = _shrink_mask(result) 

1684 return result 

1685 

1686 

1687def make_mask_none(newshape, dtype=None): 

1688 """ 

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

1690 

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

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

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

1694 

1695 Parameters 

1696 ---------- 

1697 newshape : tuple 

1698 A tuple indicating the shape of the mask. 

1699 dtype : {None, dtype}, optional 

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

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

1702 

1703 Returns 

1704 ------- 

1705 result : ndarray 

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

1707 

1708 See Also 

1709 -------- 

1710 make_mask : Create a boolean mask from an array. 

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

1712 

1713 Examples 

1714 -------- 

1715 >>> import numpy as np 

1716 >>> import numpy.ma as ma 

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

1718 array([False, False, False]) 

1719 

1720 Defining a more complex dtype. 

1721 

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

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

1724 >>> dtype 

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

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

1727 array([(False, False), (False, False), (False, False)], 

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

1729 

1730 """ 

1731 if dtype is None: 

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

1733 else: 

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

1735 return result 

1736 

1737 

1738def _recursive_mask_or(m1, m2, newmask): 

1739 names = m1.dtype.names 

1740 for name in names: 

1741 current1 = m1[name] 

1742 if current1.dtype.names is not None: 

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

1744 else: 

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

1746 

1747 

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

1749 """ 

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

1751 

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

1753 (i.e. False). 

1754 

1755 Parameters 

1756 ---------- 

1757 m1, m2 : array_like 

1758 Input masks. 

1759 copy : bool, optional 

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

1761 of the other input mask. Defaults to False. 

1762 shrink : bool, optional 

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

1764 False. Defaults to True. 

1765 

1766 Returns 

1767 ------- 

1768 mask : output mask 

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

1770 

1771 Raises 

1772 ------ 

1773 ValueError 

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

1775 

1776 Examples 

1777 -------- 

1778 >>> import numpy as np 

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

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

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

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

1783 

1784 """ 

1785 

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

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

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

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

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

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

1792 if m1 is m2 and is_mask(m1): 

1793 return _shrink_mask(m1) if shrink else m1 

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

1795 if dtype1 != dtype2: 

1796 raise ValueError(f"Incompatible dtypes '{dtype1}'<>'{dtype2}'") 

1797 if dtype1.names is not None: 

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

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

1800 _recursive_mask_or(m1, m2, newmask) 

1801 return newmask 

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

1803 

1804 

1805def flatten_mask(mask): 

1806 """ 

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

1808 are collapsed. 

1809 

1810 Parameters 

1811 ---------- 

1812 mask : array_like 

1813 Input array, which will be interpreted as booleans. 

1814 

1815 Returns 

1816 ------- 

1817 flattened_mask : ndarray of bools 

1818 The flattened input. 

1819 

1820 Examples 

1821 -------- 

1822 >>> import numpy as np 

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

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

1825 array([False, False, True]) 

1826 

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

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

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

1830 

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

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

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

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

1835 

1836 """ 

1837 

1838 def _flatmask(mask): 

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

1840 mnames = mask.dtype.names 

1841 if mnames is not None: 

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

1843 else: 

1844 return mask 

1845 

1846 def _flatsequence(sequence): 

1847 "Generates a flattened version of the sequence." 

1848 try: 

1849 for element in sequence: 

1850 if hasattr(element, '__iter__'): 

1851 yield from _flatsequence(element) 

1852 else: 

1853 yield element 

1854 except TypeError: 

1855 yield sequence 

1856 

1857 mask = np.asarray(mask) 

1858 flattened = _flatsequence(_flatmask(mask)) 

1859 return np.array(list(flattened), dtype=bool) 

1860 

1861 

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

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

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

1865 if mask is not nomask: 

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

1867 return nomask 

1868 

1869 

1870############################################################################### 

1871# Masking functions # 

1872############################################################################### 

1873 

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

1875 """ 

1876 Mask an array where a condition is met. 

1877 

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

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

1880 

1881 Parameters 

1882 ---------- 

1883 condition : array_like 

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

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

1886 a : array_like 

1887 Array to mask. 

1888 copy : bool 

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

1890 `a` in place and return a view. 

1891 

1892 Returns 

1893 ------- 

1894 result : MaskedArray 

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

1896 

1897 See Also 

1898 -------- 

1899 masked_values : Mask using floating point equality. 

1900 masked_equal : Mask where equal to a given value. 

1901 masked_not_equal : Mask where *not* equal to a given value. 

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

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

1904 masked_less : Mask where less than a given value. 

1905 masked_greater : Mask where greater than a given value. 

1906 masked_inside : Mask inside a given interval. 

1907 masked_outside : Mask outside a given interval. 

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

1909 

1910 Examples 

1911 -------- 

1912 >>> import numpy as np 

1913 >>> import numpy.ma as ma 

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

1915 >>> a 

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

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

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

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

1920 fill_value=999999) 

1921 

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

1923 

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

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

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

1927 mask=[False, False, True, False], 

1928 fill_value='N/A', 

1929 dtype='<U1') 

1930 

1931 Effect of the `copy` argument. 

1932 

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

1934 >>> c 

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

1936 mask=[ True, True, True, False], 

1937 fill_value=999999) 

1938 >>> c[0] = 99 

1939 >>> c 

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

1941 mask=[False, True, True, False], 

1942 fill_value=999999) 

1943 >>> a 

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

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

1946 >>> c[0] = 99 

1947 >>> c 

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

1949 mask=[False, True, True, False], 

1950 fill_value=999999) 

1951 >>> a 

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

1953 

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

1955 

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

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

1958 >>> a 

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

1960 mask=[False, False, True, False], 

1961 fill_value=999999) 

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

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

1964 >>> b 

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

1966 mask=[ True, False, False, False], 

1967 fill_value=999999) 

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

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

1970 mask=[ True, False, True, True], 

1971 fill_value=999999) 

1972 

1973 """ 

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

1975 cond = make_mask(condition, shrink=False) 

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

1977 

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

1979 if cshape and cshape != ashape: 

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

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

1982 if hasattr(a, '_mask'): 

1983 cond = mask_or(cond, a._mask) 

1984 cls = type(a) 

1985 else: 

1986 cls = MaskedArray 

1987 result = a.view(cls) 

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

1989 result.mask = _shrink_mask(cond) 

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

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

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

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

1994 return result 

1995 

1996 

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

1998 """ 

1999 Mask an array where greater than a given value. 

2000 

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

2002 `condition` = (x > value). 

2003 

2004 See Also 

2005 -------- 

2006 masked_where : Mask where a condition is met. 

2007 

2008 Examples 

2009 -------- 

2010 >>> import numpy as np 

2011 >>> import numpy.ma as ma 

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

2013 >>> a 

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

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

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

2017 mask=[False, False, False, True], 

2018 fill_value=999999) 

2019 

2020 """ 

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

2022 

2023 

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

2025 """ 

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

2027 

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

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

2030 

2031 See Also 

2032 -------- 

2033 masked_where : Mask where a condition is met. 

2034 

2035 Examples 

2036 -------- 

2037 >>> import numpy as np 

2038 >>> import numpy.ma as ma 

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

2040 >>> a 

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

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

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

2044 mask=[False, False, True, True], 

2045 fill_value=999999) 

2046 

2047 """ 

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

2049 

2050 

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

2052 """ 

2053 Mask an array where less than a given value. 

2054 

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

2056 `condition` = (x < value). 

2057 

2058 See Also 

2059 -------- 

2060 masked_where : Mask where a condition is met. 

2061 

2062 Examples 

2063 -------- 

2064 >>> import numpy as np 

2065 >>> import numpy.ma as ma 

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

2067 >>> a 

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

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

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

2071 mask=[ True, True, False, False], 

2072 fill_value=999999) 

2073 

2074 """ 

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

2076 

2077 

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

2079 """ 

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

2081 

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

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

2084 

2085 See Also 

2086 -------- 

2087 masked_where : Mask where a condition is met. 

2088 

2089 Examples 

2090 -------- 

2091 >>> import numpy as np 

2092 >>> import numpy.ma as ma 

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

2094 >>> a 

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

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

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

2098 mask=[ True, True, True, False], 

2099 fill_value=999999) 

2100 

2101 """ 

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

2103 

2104 

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

2106 """ 

2107 Mask an array where *not* equal to a given value. 

2108 

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

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

2111 

2112 See Also 

2113 -------- 

2114 masked_where : Mask where a condition is met. 

2115 

2116 Examples 

2117 -------- 

2118 >>> import numpy as np 

2119 >>> import numpy.ma as ma 

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

2121 >>> a 

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

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

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

2125 mask=[ True, True, False, True], 

2126 fill_value=999999) 

2127 

2128 """ 

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

2130 

2131 

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

2133 """ 

2134 Mask an array where equal to a given value. 

2135 

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

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

2138 is set to `value`. 

2139 

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

2141 

2142 See Also 

2143 -------- 

2144 masked_where : Mask where a condition is met. 

2145 masked_values : Mask using floating point equality. 

2146 

2147 Examples 

2148 -------- 

2149 >>> import numpy as np 

2150 >>> import numpy.ma as ma 

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

2152 >>> a 

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

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

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

2156 mask=[False, False, True, False], 

2157 fill_value=2) 

2158 

2159 """ 

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

2161 output.fill_value = value 

2162 return output 

2163 

2164 

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

2166 """ 

2167 Mask an array inside a given interval. 

2168 

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

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

2171 can be given in either order. 

2172 

2173 See Also 

2174 -------- 

2175 masked_where : Mask where a condition is met. 

2176 

2177 Notes 

2178 ----- 

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

2180 

2181 Examples 

2182 -------- 

2183 >>> import numpy as np 

2184 >>> import numpy.ma as ma 

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

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

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

2188 mask=[False, False, True, True, False, False], 

2189 fill_value=1e+20) 

2190 

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

2192 

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

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

2195 mask=[False, False, True, True, False, False], 

2196 fill_value=1e+20) 

2197 

2198 """ 

2199 if v2 < v1: 

2200 (v1, v2) = (v2, v1) 

2201 xf = filled(x) 

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

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

2204 

2205 

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

2207 """ 

2208 Mask an array outside a given interval. 

2209 

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

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

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

2213 

2214 See Also 

2215 -------- 

2216 masked_where : Mask where a condition is met. 

2217 

2218 Notes 

2219 ----- 

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

2221 

2222 Examples 

2223 -------- 

2224 >>> import numpy as np 

2225 >>> import numpy.ma as ma 

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

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

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

2229 mask=[ True, True, False, False, True, True], 

2230 fill_value=1e+20) 

2231 

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

2233 

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

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

2236 mask=[ True, True, False, False, True, True], 

2237 fill_value=1e+20) 

2238 

2239 """ 

2240 if v2 < v1: 

2241 (v1, v2) = (v2, v1) 

2242 xf = filled(x) 

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

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

2245 

2246 

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

2248 """ 

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

2250 

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

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

2253 

2254 Parameters 

2255 ---------- 

2256 x : array_like 

2257 Array to mask 

2258 value : object 

2259 Comparison value 

2260 copy : {True, False}, optional 

2261 Whether to return a copy of `x`. 

2262 shrink : {True, False}, optional 

2263 Whether to collapse a mask full of False to nomask 

2264 

2265 Returns 

2266 ------- 

2267 result : MaskedArray 

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

2269 

2270 See Also 

2271 -------- 

2272 masked_where : Mask where a condition is met. 

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

2274 masked_values : Mask using floating point equality. 

2275 

2276 Examples 

2277 -------- 

2278 >>> import numpy as np 

2279 >>> import numpy.ma as ma 

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

2281 >>> # don't eat spoiled food 

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

2283 >>> eat 

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

2285 mask=[ True, False], 

2286 fill_value='green_eggs', 

2287 dtype=object) 

2288 >>> # plain ol` ham is boring 

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

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

2291 >>> eat 

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

2293 mask=False, 

2294 fill_value='green_eggs', 

2295 dtype=object) 

2296 

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

2298 

2299 >>> eat 

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

2301 mask=False, 

2302 fill_value='green_eggs', 

2303 dtype=object) 

2304 

2305 """ 

2306 if isMaskedArray(x): 

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

2308 mask = x._mask 

2309 else: 

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

2311 mask = nomask 

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

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

2314 

2315 

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

2317 """ 

2318 Mask using floating point equality. 

2319 

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

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

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

2323 

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

2325 `masked_equal`. 

2326 

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

2328 possible. 

2329 

2330 Parameters 

2331 ---------- 

2332 x : array_like 

2333 Array to mask. 

2334 value : float 

2335 Masking value. 

2336 rtol, atol : float, optional 

2337 Tolerance parameters passed on to `isclose` 

2338 copy : bool, optional 

2339 Whether to return a copy of `x`. 

2340 shrink : bool, optional 

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

2342 

2343 Returns 

2344 ------- 

2345 result : MaskedArray 

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

2347 

2348 See Also 

2349 -------- 

2350 masked_where : Mask where a condition is met. 

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

2352 

2353 Examples 

2354 -------- 

2355 >>> import numpy as np 

2356 >>> import numpy.ma as ma 

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

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

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

2360 mask=[False, True, False, True, False], 

2361 fill_value=1.1) 

2362 

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

2364 

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

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

2367 mask=False, 

2368 fill_value=2.1) 

2369 

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

2371 

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

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

2374 mask=[False, False, True, False, False], 

2375 fill_value=2.1) 

2376 

2377 """ 

2378 xnew = filled(x, value) 

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

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

2381 else: 

2382 mask = umath.equal(xnew, value) 

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

2384 if shrink: 

2385 ret.shrink_mask() 

2386 return ret 

2387 

2388 

2389def masked_invalid(a, copy=True): 

2390 """ 

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

2392 

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

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

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

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

2397 

2398 See Also 

2399 -------- 

2400 masked_where : Mask where a condition is met. 

2401 

2402 Examples 

2403 -------- 

2404 >>> import numpy as np 

2405 >>> import numpy.ma as ma 

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

2407 >>> a[2] = np.nan 

2408 >>> a[3] = np.inf 

2409 >>> a 

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

2411 >>> ma.masked_invalid(a) 

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

2413 mask=[False, False, True, True, False], 

2414 fill_value=1e+20) 

2415 

2416 """ 

2417 a = np.array(a, copy=None, subok=True) 

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

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

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

2421 if res._mask is nomask: 

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

2423 return res 

2424 

2425############################################################################### 

2426# Printing options # 

2427############################################################################### 

2428 

2429 

2430class _MaskedPrintOption: 

2431 """ 

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

2433 

2434 """ 

2435 

2436 def __init__(self, display): 

2437 """ 

2438 Create the masked_print_option object. 

2439 

2440 """ 

2441 self._display = display 

2442 self._enabled = True 

2443 

2444 def display(self): 

2445 """ 

2446 Display the string to print for masked values. 

2447 

2448 """ 

2449 return self._display 

2450 

2451 def set_display(self, s): 

2452 """ 

2453 Set the string to print for masked values. 

2454 

2455 """ 

2456 self._display = s 

2457 

2458 def enabled(self): 

2459 """ 

2460 Is the use of the display value enabled? 

2461 

2462 """ 

2463 return self._enabled 

2464 

2465 def enable(self, shrink=1): 

2466 """ 

2467 Set the enabling shrink to `shrink`. 

2468 

2469 """ 

2470 self._enabled = shrink 

2471 

2472 def __str__(self): 

2473 return str(self._display) 

2474 

2475 __repr__ = __str__ 

2476 

2477 

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

2479masked_print_option = _MaskedPrintOption('--') 

2480 

2481 

2482def _recursive_printoption(result, mask, printopt): 

2483 """ 

2484 Puts printoptions in result where mask is True. 

2485 

2486 Private function allowing for recursion 

2487 

2488 """ 

2489 names = result.dtype.names 

2490 if names is not None: 

2491 for name in names: 

2492 curdata = result[name] 

2493 curmask = mask[name] 

2494 _recursive_printoption(curdata, curmask, printopt) 

2495 else: 

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

2497 

2498 

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

2500_legacy_print_templates = { 

2501 'long_std': textwrap.dedent("""\ 

2502 masked_%(name)s(data = 

2503 %(data)s, 

2504 %(nlen)s mask = 

2505 %(mask)s, 

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

2507 """), 

2508 'long_flx': textwrap.dedent("""\ 

2509 masked_%(name)s(data = 

2510 %(data)s, 

2511 %(nlen)s mask = 

2512 %(mask)s, 

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

2514 %(nlen)s dtype = %(dtype)s) 

2515 """), 

2516 'short_std': textwrap.dedent("""\ 

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

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

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

2520 """), 

2521 'short_flx': textwrap.dedent("""\ 

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

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

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

2525 %(nlen)s dtype = %(dtype)s) 

2526 """) 

2527} 

2528 

2529############################################################################### 

2530# MaskedArray class # 

2531############################################################################### 

2532 

2533 

2534def _recursive_filled(a, mask, fill_value): 

2535 """ 

2536 Recursively fill `a` with `fill_value`. 

2537 

2538 """ 

2539 names = a.dtype.names 

2540 for name in names: 

2541 current = a[name] 

2542 if current.dtype.names is not None: 

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

2544 else: 

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

2546 

2547 

2548def flatten_structured_array(a): 

2549 """ 

2550 Flatten a structured array. 

2551 

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

2553 (nested) fields. 

2554 

2555 Parameters 

2556 ---------- 

2557 a : structured array 

2558 

2559 Returns 

2560 ------- 

2561 output : masked array or ndarray 

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

2563 standard ndarray. 

2564 

2565 Examples 

2566 -------- 

2567 >>> import numpy as np 

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

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

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

2571 array([[1., 1.], 

2572 [2., 2.]]) 

2573 

2574 """ 

2575 

2576 def flatten_sequence(iterable): 

2577 """ 

2578 Flattens a compound of nested iterables. 

2579 

2580 """ 

2581 for elm in iter(iterable): 

2582 if hasattr(elm, "__iter__") and not isinstance(elm, (str, bytes)): 

2583 yield from flatten_sequence(elm) 

2584 else: 

2585 yield elm 

2586 

2587 a = np.asanyarray(a) 

2588 inishape = a.shape 

2589 a = a.ravel() 

2590 if isinstance(a, MaskedArray): 

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

2592 out = out.view(MaskedArray) 

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

2594 for d in getmaskarray(a)]) 

2595 else: 

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

2597 if len(inishape) > 1: 

2598 newshape = list(out.shape) 

2599 newshape[0] = inishape 

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

2601 return out 

2602 

2603 

2604def _arraymethod(funcname, onmask=True): 

2605 """ 

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

2607 

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

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

2610 on the original ``_data``. 

2611 

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

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

2614 to the initial mask. 

2615 

2616 Parameters 

2617 ---------- 

2618 funcname : str 

2619 Name of the function to apply on data. 

2620 onmask : bool 

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

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

2623 attribute. 

2624 

2625 Returns 

2626 ------- 

2627 method : instancemethod 

2628 Class method wrapper of the specified basic array method. 

2629 

2630 """ 

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

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

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

2634 result._update_from(self) 

2635 mask = self._mask 

2636 if not onmask: 

2637 result.__setmask__(mask) 

2638 elif mask is not nomask: 

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

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

2641 return result 

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

2643 if methdoc is not None: 

2644 wrapped_method.__doc__ = methdoc.__doc__ 

2645 wrapped_method.__name__ = funcname 

2646 return wrapped_method 

2647 

2648 

2649class MaskedIterator: 

2650 """ 

2651 Flat iterator object to iterate over masked arrays. 

2652 

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

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

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

2656 

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

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

2659 advanced indexing. 

2660 

2661 See Also 

2662 -------- 

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

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

2665 

2666 Notes 

2667 ----- 

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

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

2670 

2671 Examples 

2672 -------- 

2673 >>> import numpy as np 

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

2675 >>> fl = x.flat 

2676 >>> type(fl) 

2677 <class 'numpy.ma.MaskedIterator'> 

2678 >>> for item in fl: 

2679 ... print(item) 

2680 ... 

2681 0 

2682 1 

2683 2 

2684 3 

2685 4 

2686 5 

2687 

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

2689 returns a masked array: 

2690 

2691 >>> fl[2:4] 

2692 masked_array(data = [2 3], 

2693 mask = False, 

2694 fill_value = 999999) 

2695 

2696 """ 

2697 

2698 def __init__(self, ma): 

2699 self.ma = ma 

2700 self.dataiter = ma._data.flat 

2701 

2702 if ma._mask is nomask: 

2703 self.maskiter = None 

2704 else: 

2705 self.maskiter = ma._mask.flat 

2706 

2707 def __iter__(self): 

2708 return self 

2709 

2710 def __getitem__(self, indx): 

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

2712 if self.maskiter is not None: 

2713 _mask = self.maskiter.__getitem__(indx) 

2714 if isinstance(_mask, ndarray): 

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

2716 _mask.shape = result.shape 

2717 result._mask = _mask 

2718 elif isinstance(_mask, np.void): 

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

2720 elif _mask: # Just a scalar, masked 

2721 return masked 

2722 return result 

2723 

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

2725 def __setitem__(self, index, value): 

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

2727 if self.maskiter is not None: 

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

2729 

2730 def __next__(self): 

2731 """ 

2732 Return the next value, or raise StopIteration. 

2733 

2734 Examples 

2735 -------- 

2736 >>> import numpy as np 

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

2738 >>> fl = x.flat 

2739 >>> next(fl) 

2740 3 

2741 >>> next(fl) 

2742 masked 

2743 >>> next(fl) 

2744 Traceback (most recent call last): 

2745 ... 

2746 StopIteration 

2747 

2748 """ 

2749 d = next(self.dataiter) 

2750 if self.maskiter is not None: 

2751 m = next(self.maskiter) 

2752 if isinstance(m, np.void): 

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

2754 elif m: # Just a scalar, masked 

2755 return masked 

2756 return d 

2757 

2758 

2759@set_module("numpy.ma") 

2760class MaskedArray(ndarray): 

2761 """ 

2762 An array class with possibly masked values. 

2763 

2764 Masked values of True exclude the corresponding element from any 

2765 computation. 

2766 

2767 Construction:: 

2768 

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

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

2771 shrink=True, order=None) 

2772 

2773 Parameters 

2774 ---------- 

2775 data : array_like 

2776 Input data. 

2777 mask : sequence, optional 

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

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

2780 dtype : dtype, optional 

2781 Data type of the output. 

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

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

2784 a copy is performed. 

2785 copy : bool, optional 

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

2787 Default is False. 

2788 subok : bool, optional 

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

2790 plain `MaskedArray`. Default is True. 

2791 ndmin : int, optional 

2792 Minimum number of dimensions. Default is 0. 

2793 fill_value : scalar, optional 

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

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

2796 keep_mask : bool, optional 

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

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

2799 hard_mask : bool, optional 

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

2801 cannot be unmasked. Default is False. 

2802 shrink : bool, optional 

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

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

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

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

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

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

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

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

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

2812 

2813 Examples 

2814 -------- 

2815 >>> import numpy as np 

2816 

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

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

2819 

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

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

2822 ... [False, False, True]]) 

2823 masked_array( 

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

2825 [3, 4, --]], 

2826 mask=[[False, True, False], 

2827 [False, False, True]], 

2828 fill_value=999999) 

2829 

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

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

2832 boolean value: 

2833 

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

2835 masked_array( 

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

2837 [3, 4, 5]], 

2838 mask=[[False, False, False], 

2839 [False, False, False]], 

2840 fill_value=999999) 

2841 

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

2843 masked_array( 

2844 data=[[--, --, --], 

2845 [--, --, --]], 

2846 mask=[[ True, True, True], 

2847 [ True, True, True]], 

2848 fill_value=999999, 

2849 dtype=int64) 

2850 

2851 .. note:: 

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

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

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

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

2856 

2857 >>> np.False_ is np.ma.nomask 

2858 True 

2859 

2860 """ 

2861 

2862 __array_priority__ = 15 

2863 _defaultmask = nomask 

2864 _defaulthardmask = False 

2865 _baseclass = ndarray 

2866 

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

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

2869 _print_width = 100 

2870 _print_width_1d = 1500 

2871 

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

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

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

2875 """ 

2876 Create a new masked array from scratch. 

2877 

2878 Notes 

2879 ----- 

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

2881 

2882 """ 

2883 # Process data. 

2884 copy = None if not copy else True 

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

2886 order=order, subok=True, ndmin=ndmin) 

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

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

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

2890 copy = True 

2891 

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

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

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

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

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

2897 else: 

2898 _data = ndarray.view(_data, cls) 

2899 

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

2901 # still has the _mask attribute like MaskedArrays 

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

2903 _data._mask = data._mask 

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

2905 # Process mask. 

2906 # Type of the mask 

2907 mdtype = make_mask_descr(_data.dtype) 

2908 if mask is nomask: 

2909 # Case 1. : no mask in input. 

2910 # Erase the current mask ? 

2911 if not keep_mask: 

2912 # With a reduced version 

2913 if shrink: 

2914 _data._mask = nomask 

2915 # With full version 

2916 else: 

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

2918 # Check whether we missed something 

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

2920 try: 

2921 # If data is a sequence of masked array 

2922 mask = np.array( 

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

2924 for m in data], dtype=mdtype) 

2925 except (ValueError, TypeError): 

2926 # If data is nested 

2927 mask = nomask 

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

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

2930 _data._mask = mask 

2931 _data._sharedmask = False 

2932 else: 

2933 _data._sharedmask = not copy 

2934 if copy: 

2935 _data._mask = _data._mask.copy() 

2936 # Reset the shape of the original mask 

2937 if getmask(data) is not nomask: 

2938 # gh-21022 encounters an issue here 

2939 # because data._mask.shape is not writeable, but 

2940 # the op was also pointless in that case, because 

2941 # the shapes were the same, so we can at least 

2942 # avoid that path 

2943 if data._mask.shape != data.shape: 

2944 data._mask.shape = data.shape 

2945 else: 

2946 # Case 2. : With a mask in input. 

2947 # If mask is boolean, create an array of True or False 

2948 

2949 # if users pass `mask=None` be forgiving here and cast it False 

2950 # for speed; although the default is `mask=nomask` and can differ. 

2951 if mask is None: 

2952 mask = False 

2953 

2954 if mask is True and mdtype == MaskType: 

2955 mask = np.ones(_data.shape, dtype=mdtype) 

2956 elif mask is False and mdtype == MaskType: 

2957 mask = np.zeros(_data.shape, dtype=mdtype) 

2958 else: 

2959 # Read the mask with the current mdtype 

2960 try: 

2961 mask = np.array(mask, copy=copy, dtype=mdtype) 

2962 # Or assume it's a sequence of bool/int 

2963 except TypeError: 

2964 mask = np.array([tuple([m] * len(mdtype)) for m in mask], 

2965 dtype=mdtype) 

2966 # Make sure the mask and the data have the same shape 

2967 if mask.shape != _data.shape: 

2968 (nd, nm) = (_data.size, mask.size) 

2969 if nm == 1: 

2970 mask = np.resize(mask, _data.shape) 

2971 elif nm == nd: 

2972 mask = np.reshape(mask, _data.shape) 

2973 else: 

2974 msg = (f"Mask and data not compatible:" 

2975 f" data size is {nd}, mask size is {nm}.") 

2976 raise MaskError(msg) 

2977 copy = True 

2978 # Set the mask to the new value 

2979 if _data._mask is nomask: 

2980 _data._mask = mask 

2981 _data._sharedmask = not copy 

2982 elif not keep_mask: 

2983 _data._mask = mask 

2984 _data._sharedmask = not copy 

2985 else: 

2986 if _data.dtype.names is not None: 

2987 def _recursive_or(a, b): 

2988 "do a|=b on each field of a, recursively" 

2989 for name in a.dtype.names: 

2990 (af, bf) = (a[name], b[name]) 

2991 if af.dtype.names is not None: 

2992 _recursive_or(af, bf) 

2993 else: 

2994 af |= bf 

2995 

2996 _recursive_or(_data._mask, mask) 

2997 else: 

2998 _data._mask = np.logical_or(mask, _data._mask) 

2999 _data._sharedmask = False 

3000 

3001 # Update fill_value. 

3002 if fill_value is None: 

3003 fill_value = getattr(data, '_fill_value', None) 

3004 # But don't run the check unless we have something to check. 

3005 if fill_value is not None: 

3006 _data._fill_value = _check_fill_value(fill_value, _data.dtype) 

3007 # Process extra options .. 

3008 if hard_mask is None: 

3009 _data._hardmask = getattr(data, '_hardmask', False) 

3010 else: 

3011 _data._hardmask = hard_mask 

3012 _data._baseclass = _baseclass 

3013 return _data 

3014 

3015 def _update_from(self, obj): 

3016 """ 

3017 Copies some attributes of obj to self. 

3018 

3019 """ 

3020 if isinstance(obj, ndarray): 

3021 _baseclass = type(obj) 

3022 else: 

3023 _baseclass = ndarray 

3024 # We need to copy the _basedict to avoid backward propagation 

3025 _optinfo = {} 

3026 _optinfo.update(getattr(obj, '_optinfo', {})) 

3027 _optinfo.update(getattr(obj, '_basedict', {})) 

3028 if not isinstance(obj, MaskedArray): 

3029 _optinfo.update(getattr(obj, '__dict__', {})) 

3030 _dict = {'_fill_value': getattr(obj, '_fill_value', None), 

3031 '_hardmask': getattr(obj, '_hardmask', False), 

3032 '_sharedmask': getattr(obj, '_sharedmask', False), 

3033 '_isfield': getattr(obj, '_isfield', False), 

3034 '_baseclass': getattr(obj, '_baseclass', _baseclass), 

3035 '_optinfo': _optinfo, 

3036 '_basedict': _optinfo} 

3037 self.__dict__.update(_dict) 

3038 self.__dict__.update(_optinfo) 

3039 

3040 def __array_finalize__(self, obj): 

3041 """ 

3042 Finalizes the masked array. 

3043 

3044 """ 

3045 # Get main attributes. 

3046 self._update_from(obj) 

3047 

3048 # We have to decide how to initialize self.mask, based on 

3049 # obj.mask. This is very difficult. There might be some 

3050 # correspondence between the elements in the array we are being 

3051 # created from (= obj) and us. Or there might not. This method can 

3052 # be called in all kinds of places for all kinds of reasons -- could 

3053 # be empty_like, could be slicing, could be a ufunc, could be a view. 

3054 # The numpy subclassing interface simply doesn't give us any way 

3055 # to know, which means that at best this method will be based on 

3056 # guesswork and heuristics. To make things worse, there isn't even any 

3057 # clear consensus about what the desired behavior is. For instance, 

3058 # most users think that np.empty_like(marr) -- which goes via this 

3059 # method -- should return a masked array with an empty mask (see 

3060 # gh-3404 and linked discussions), but others disagree, and they have 

3061 # existing code which depends on empty_like returning an array that 

3062 # matches the input mask. 

3063 # 

3064 # Historically our algorithm was: if the template object mask had the 

3065 # same *number of elements* as us, then we used *it's mask object 

3066 # itself* as our mask, so that writes to us would also write to the 

3067 # original array. This is horribly broken in multiple ways. 

3068 # 

3069 # Now what we do instead is, if the template object mask has the same 

3070 # number of elements as us, and we do not have the same base pointer 

3071 # as the template object (b/c views like arr[...] should keep the same 

3072 # mask), then we make a copy of the template object mask and use 

3073 # that. This is also horribly broken but somewhat less so. Maybe. 

3074 if isinstance(obj, ndarray): 

3075 # XX: This looks like a bug -- shouldn't it check self.dtype 

3076 # instead? 

3077 if obj.dtype.names is not None: 

3078 _mask = getmaskarray(obj) 

3079 else: 

3080 _mask = getmask(obj) 

3081 

3082 # If self and obj point to exactly the same data, then probably 

3083 # self is a simple view of obj (e.g., self = obj[...]), so they 

3084 # should share the same mask. (This isn't 100% reliable, e.g. self 

3085 # could be the first row of obj, or have strange strides, but as a 

3086 # heuristic it's not bad.) In all other cases, we make a copy of 

3087 # the mask, so that future modifications to 'self' do not end up 

3088 # side-effecting 'obj' as well. 

3089 if (_mask is not nomask and obj.__array_interface__["data"][0] 

3090 != self.__array_interface__["data"][0]): 

3091 # We should make a copy. But we could get here via astype, 

3092 # in which case the mask might need a new dtype as well 

3093 # (e.g., changing to or from a structured dtype), and the 

3094 # order could have changed. So, change the mask type if 

3095 # needed and use astype instead of copy. 

3096 if self.dtype == obj.dtype: 

3097 _mask_dtype = _mask.dtype 

3098 else: 

3099 _mask_dtype = make_mask_descr(self.dtype) 

3100 

3101 if self.flags.c_contiguous: 

3102 order = "C" 

3103 elif self.flags.f_contiguous: 

3104 order = "F" 

3105 else: 

3106 order = "K" 

3107 

3108 _mask = _mask.astype(_mask_dtype, order) 

3109 else: 

3110 # Take a view so shape changes, etc., do not propagate back. 

3111 _mask = _mask.view() 

3112 else: 

3113 _mask = nomask 

3114 

3115 self._mask = _mask 

3116 # Finalize the mask 

3117 if self._mask is not nomask: 

3118 try: 

3119 self._mask.shape = self.shape 

3120 except ValueError: 

3121 self._mask = nomask 

3122 except (TypeError, AttributeError): 

3123 # When _mask.shape is not writable (because it's a void) 

3124 pass 

3125 

3126 # Finalize the fill_value 

3127 if self._fill_value is not None: 

3128 self._fill_value = _check_fill_value(self._fill_value, self.dtype) 

3129 elif self.dtype.names is not None: 

3130 # Finalize the default fill_value for structured arrays 

3131 self._fill_value = _check_fill_value(None, self.dtype) 

3132 

3133 def __array_wrap__(self, obj, context=None, return_scalar=False): 

3134 """ 

3135 Special hook for ufuncs. 

3136 

3137 Wraps the numpy array and sets the mask according to context. 

3138 

3139 """ 

3140 if obj is self: # for in-place operations 

3141 result = obj 

3142 else: 

3143 result = obj.view(type(self)) 

3144 result._update_from(self) 

3145 

3146 if context is not None: 

3147 result._mask = result._mask.copy() 

3148 func, args, out_i = context 

3149 # args sometimes contains outputs (gh-10459), which we don't want 

3150 input_args = args[:func.nin] 

3151 m = functools.reduce(mask_or, [getmaskarray(arg) for arg in input_args]) 

3152 # Get the domain mask 

3153 domain = ufunc_domain.get(func) 

3154 if domain is not None: 

3155 # Take the domain, and make sure it's a ndarray 

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

3157 # The result may be masked for two (unary) domains. 

3158 # That can't really be right as some domains drop 

3159 # the mask and some don't behaving differently here. 

3160 d = domain(*input_args).astype(bool, copy=False) 

3161 d = filled(d, True) 

3162 

3163 if d.any(): 

3164 # Fill the result where the domain is wrong 

3165 try: 

3166 # Binary domain: take the last value 

3167 fill_value = ufunc_fills[func][-1] 

3168 except TypeError: 

3169 # Unary domain: just use this one 

3170 fill_value = ufunc_fills[func] 

3171 except KeyError: 

3172 # Domain not recognized, use fill_value instead 

3173 fill_value = self.fill_value 

3174 

3175 np.copyto(result, fill_value, where=d) 

3176 

3177 # Update the mask 

3178 if m is nomask: 

3179 m = d 

3180 else: 

3181 # Don't modify inplace, we risk back-propagation 

3182 m = (m | d) 

3183 

3184 # Make sure the mask has the proper size 

3185 if result is not self and result.shape == () and m: 

3186 return masked 

3187 else: 

3188 result._mask = m 

3189 result._sharedmask = False 

3190 

3191 return result 

3192 

3193 def view(self, dtype=None, type=None, fill_value=None): 

3194 """ 

3195 Return a view of the MaskedArray data. 

3196 

3197 Parameters 

3198 ---------- 

3199 dtype : data-type or ndarray sub-class, optional 

3200 Data-type descriptor of the returned view, e.g., float32 or int16. 

3201 The default, None, results in the view having the same data-type 

3202 as `a`. As with ``ndarray.view``, dtype can also be specified as 

3203 an ndarray sub-class, which then specifies the type of the 

3204 returned object (this is equivalent to setting the ``type`` 

3205 parameter). 

3206 type : Python type, optional 

3207 Type of the returned view, either ndarray or a subclass. The 

3208 default None results in type preservation. 

3209 fill_value : scalar, optional 

3210 The value to use for invalid entries (None by default). 

3211 If None, then this argument is inferred from the passed `dtype`, or 

3212 in its absence the original array, as discussed in the notes below. 

3213 

3214 See Also 

3215 -------- 

3216 numpy.ndarray.view : Equivalent method on ndarray object. 

3217 

3218 Notes 

3219 ----- 

3220 

3221 ``a.view()`` is used two different ways: 

3222 

3223 ``a.view(some_dtype)`` or ``a.view(dtype=some_dtype)`` constructs a view 

3224 of the array's memory with a different data-type. This can cause a 

3225 reinterpretation of the bytes of memory. 

3226 

3227 ``a.view(ndarray_subclass)`` or ``a.view(type=ndarray_subclass)`` just 

3228 returns an instance of `ndarray_subclass` that looks at the same array 

3229 (same shape, dtype, etc.) This does not cause a reinterpretation of the 

3230 memory. 

3231 

3232 If `fill_value` is not specified, but `dtype` is specified (and is not 

3233 an ndarray sub-class), the `fill_value` of the MaskedArray will be 

3234 reset. If neither `fill_value` nor `dtype` are specified (or if 

3235 `dtype` is an ndarray sub-class), then the fill value is preserved. 

3236 Finally, if `fill_value` is specified, but `dtype` is not, the fill 

3237 value is set to the specified value. 

3238 

3239 For ``a.view(some_dtype)``, if ``some_dtype`` has a different number of 

3240 bytes per entry than the previous dtype (for example, converting a 

3241 regular array to a structured array), then the behavior of the view 

3242 cannot be predicted just from the superficial appearance of ``a`` (shown 

3243 by ``print(a)``). It also depends on exactly how ``a`` is stored in 

3244 memory. Therefore if ``a`` is C-ordered versus fortran-ordered, versus 

3245 defined as a slice or transpose, etc., the view may give different 

3246 results. 

3247 """ 

3248 

3249 if dtype is None: 

3250 if type is None: 

3251 output = ndarray.view(self) 

3252 else: 

3253 output = ndarray.view(self, type) 

3254 elif type is None: 

3255 try: 

3256 if issubclass(dtype, ndarray): 

3257 output = ndarray.view(self, dtype) 

3258 dtype = None 

3259 else: 

3260 output = ndarray.view(self, dtype) 

3261 except TypeError: 

3262 output = ndarray.view(self, dtype) 

3263 else: 

3264 output = ndarray.view(self, dtype, type) 

3265 

3266 # also make the mask be a view (so attr changes to the view's 

3267 # mask do no affect original object's mask) 

3268 # (especially important to avoid affecting np.masked singleton) 

3269 if getmask(output) is not nomask: 

3270 output._mask = output._mask.view() 

3271 

3272 # Make sure to reset the _fill_value if needed 

3273 if getattr(output, '_fill_value', None) is not None: 

3274 if fill_value is None: 

3275 if dtype is None: 

3276 pass # leave _fill_value as is 

3277 else: 

3278 output._fill_value = None 

3279 else: 

3280 output.fill_value = fill_value 

3281 return output 

3282 

3283 def __getitem__(self, indx): 

3284 """ 

3285 x.__getitem__(y) <==> x[y] 

3286 

3287 Return the item described by i, as a masked array. 

3288 

3289 """ 

3290 # We could directly use ndarray.__getitem__ on self. 

3291 # But then we would have to modify __array_finalize__ to prevent the 

3292 # mask of being reshaped if it hasn't been set up properly yet 

3293 # So it's easier to stick to the current version 

3294 dout = self.data[indx] 

3295 _mask = self._mask 

3296 

3297 def _is_scalar(m): 

3298 return not isinstance(m, np.ndarray) 

3299 

3300 def _scalar_heuristic(arr, elem): 

3301 """ 

3302 Return whether `elem` is a scalar result of indexing `arr`, or None 

3303 if undecidable without promoting nomask to a full mask 

3304 """ 

3305 # obviously a scalar 

3306 if not isinstance(elem, np.ndarray): 

3307 return True 

3308 

3309 # object array scalar indexing can return anything 

3310 elif arr.dtype.type is np.object_: 

3311 if arr.dtype is not elem.dtype: 

3312 # elem is an array, but dtypes do not match, so must be 

3313 # an element 

3314 return True 

3315 

3316 # well-behaved subclass that only returns 0d arrays when 

3317 # expected - this is not a scalar 

3318 elif type(arr).__getitem__ == ndarray.__getitem__: 

3319 return False 

3320 

3321 return None 

3322 

3323 if _mask is not nomask: 

3324 # _mask cannot be a subclass, so it tells us whether we should 

3325 # expect a scalar. It also cannot be of dtype object. 

3326 mout = _mask[indx] 

3327 scalar_expected = _is_scalar(mout) 

3328 

3329 else: 

3330 # attempt to apply the heuristic to avoid constructing a full mask 

3331 mout = nomask 

3332 scalar_expected = _scalar_heuristic(self.data, dout) 

3333 if scalar_expected is None: 

3334 # heuristics have failed 

3335 # construct a full array, so we can be certain. This is costly. 

3336 # we could also fall back on ndarray.__getitem__(self.data, indx) 

3337 scalar_expected = _is_scalar(getmaskarray(self)[indx]) 

3338 

3339 # Did we extract a single item? 

3340 if scalar_expected: 

3341 # A record 

3342 if isinstance(dout, np.void): 

3343 # We should always re-cast to mvoid, otherwise users can 

3344 # change masks on rows that already have masked values, but not 

3345 # on rows that have no masked values, which is inconsistent. 

3346 return mvoid(dout, mask=mout, hardmask=self._hardmask) 

3347 

3348 # special case introduced in gh-5962 

3349 elif (self.dtype.type is np.object_ and 

3350 isinstance(dout, np.ndarray) and 

3351 dout is not masked): 

3352 # If masked, turn into a MaskedArray, with everything masked. 

3353 if mout: 

3354 return MaskedArray(dout, mask=True) 

3355 else: 

3356 return dout 

3357 

3358 # Just a scalar 

3359 elif mout: 

3360 return masked 

3361 else: 

3362 return dout 

3363 else: 

3364 # Force dout to MA 

3365 dout = dout.view(type(self)) 

3366 # Inherit attributes from self 

3367 dout._update_from(self) 

3368 # Check the fill_value 

3369 if is_string_or_list_of_strings(indx): 

3370 if self._fill_value is not None: 

3371 dout._fill_value = self._fill_value[indx] 

3372 

3373 # Something like gh-15895 has happened if this check fails. 

3374 # _fill_value should always be an ndarray. 

3375 if not isinstance(dout._fill_value, np.ndarray): 

3376 raise RuntimeError('Internal NumPy error.') 

3377 # If we're indexing a multidimensional field in a 

3378 # structured array (such as dtype("(2,)i2,(2,)i1")), 

3379 # dimensionality goes up (M[field].ndim == M.ndim + 

3380 # M.dtype[field].ndim). That's fine for 

3381 # M[field] but problematic for M[field].fill_value 

3382 # which should have shape () to avoid breaking several 

3383 # methods. There is no great way out, so set to 

3384 # first element. See issue #6723. 

3385 if dout._fill_value.ndim > 0: 

3386 if not (dout._fill_value == 

3387 dout._fill_value.flat[0]).all(): 

3388 warnings.warn( 

3389 "Upon accessing multidimensional field " 

3390 f"{indx!s}, need to keep dimensionality " 

3391 "of fill_value at 0. Discarding " 

3392 "heterogeneous fill_value and setting " 

3393 f"all to {dout._fill_value[0]!s}.", 

3394 stacklevel=2) 

3395 # Need to use `.flat[0:1].squeeze(...)` instead of just 

3396 # `.flat[0]` to ensure the result is a 0d array and not 

3397 # a scalar. 

3398 dout._fill_value = dout._fill_value.flat[0:1].squeeze(axis=0) 

3399 dout._isfield = True 

3400 # Update the mask if needed 

3401 if mout is not nomask: 

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

3403 dout._mask = reshape(mout, dout.shape) 

3404 dout._sharedmask = True 

3405 # Note: Don't try to check for m.any(), that'll take too long 

3406 return dout 

3407 

3408 # setitem may put NaNs into integer arrays or occasionally overflow a 

3409 # float. But this may happen in masked values, so avoid otherwise 

3410 # correct warnings (as is typical also in masked calculations). 

3411 @np.errstate(over='ignore', invalid='ignore') 

3412 def __setitem__(self, indx, value): 

3413 """ 

3414 x.__setitem__(i, y) <==> x[i]=y 

3415 

3416 Set item described by index. If value is masked, masks those 

3417 locations. 

3418 

3419 """ 

3420 if self is masked: 

3421 raise MaskError('Cannot alter the masked element.') 

3422 _data = self._data 

3423 _mask = self._mask 

3424 if isinstance(indx, str): 

3425 _data[indx] = value 

3426 if _mask is nomask: 

3427 self._mask = _mask = make_mask_none(self.shape, self.dtype) 

3428 _mask[indx] = getmask(value) 

3429 return 

3430 

3431 _dtype = _data.dtype 

3432 

3433 if value is masked: 

3434 # The mask wasn't set: create a full version. 

3435 if _mask is nomask: 

3436 _mask = self._mask = make_mask_none(self.shape, _dtype) 

3437 # Now, set the mask to its value. 

3438 if _dtype.names is not None: 

3439 _mask[indx] = tuple([True] * len(_dtype.names)) 

3440 else: 

3441 _mask[indx] = True 

3442 return 

3443 

3444 # Get the _data part of the new value 

3445 dval = getattr(value, '_data', value) 

3446 # Get the _mask part of the new value 

3447 mval = getmask(value) 

3448 if _dtype.names is not None and mval is nomask: 

3449 mval = tuple([False] * len(_dtype.names)) 

3450 if _mask is nomask: 

3451 # Set the data, then the mask 

3452 _data[indx] = dval 

3453 if mval is not nomask: 

3454 _mask = self._mask = make_mask_none(self.shape, _dtype) 

3455 _mask[indx] = mval 

3456 elif not self._hardmask: 

3457 # Set the data, then the mask 

3458 if (isinstance(indx, masked_array) and 

3459 not isinstance(value, masked_array)): 

3460 _data[indx.data] = dval 

3461 else: 

3462 _data[indx] = dval 

3463 _mask[indx] = mval 

3464 elif hasattr(indx, 'dtype') and (indx.dtype == MaskType): 

3465 indx = indx * umath.logical_not(_mask) 

3466 _data[indx] = dval 

3467 else: 

3468 if _dtype.names is not None: 

3469 err_msg = "Flexible 'hard' masks are not yet supported." 

3470 raise NotImplementedError(err_msg) 

3471 mindx = mask_or(_mask[indx], mval, copy=True) 

3472 dindx = self._data[indx] 

3473 if dindx.size > 1: 

3474 np.copyto(dindx, dval, where=~mindx) 

3475 elif mindx is nomask: 

3476 dindx = dval 

3477 _data[indx] = dindx 

3478 _mask[indx] = mindx 

3479 return 

3480 

3481 # Define so that we can overwrite the setter. 

3482 @property 

3483 def dtype(self): 

3484 return super().dtype 

3485 

3486 @dtype.setter 

3487 def dtype(self, dtype): 

3488 super(MaskedArray, type(self)).dtype.__set__(self, dtype) 

3489 if self._mask is not nomask: 

3490 self._mask = self._mask.view(make_mask_descr(dtype), ndarray) 

3491 # Try to reset the shape of the mask (if we don't have a void). 

3492 # This raises a ValueError if the dtype change won't work. 

3493 try: 

3494 self._mask.shape = self.shape 

3495 except (AttributeError, TypeError): 

3496 pass 

3497 

3498 @property 

3499 def shape(self): 

3500 return super().shape 

3501 

3502 @shape.setter 

3503 def shape(self, shape): 

3504 super(MaskedArray, type(self)).shape.__set__(self, shape) 

3505 # Cannot use self._mask, since it may not (yet) exist when a 

3506 # masked matrix sets the shape. 

3507 if getmask(self) is not nomask: 

3508 self._mask.shape = self.shape 

3509 

3510 def __setmask__(self, mask, copy=False): 

3511 """ 

3512 Set the mask. 

3513 

3514 """ 

3515 idtype = self.dtype 

3516 current_mask = self._mask 

3517 if mask is masked: 

3518 mask = True 

3519 

3520 if current_mask is nomask: 

3521 # Make sure the mask is set 

3522 # Just don't do anything if there's nothing to do. 

3523 if mask is nomask: 

3524 return 

3525 current_mask = self._mask = make_mask_none(self.shape, idtype) 

3526 

3527 if idtype.names is None: 

3528 # No named fields. 

3529 # Hardmask: don't unmask the data 

3530 if self._hardmask: 

3531 current_mask |= mask 

3532 # Softmask: set everything to False 

3533 # If it's obviously a compatible scalar, use a quick update 

3534 # method. 

3535 elif isinstance(mask, (int, float, np.bool, np.number)): 

3536 current_mask[...] = mask 

3537 # Otherwise fall back to the slower, general purpose way. 

3538 else: 

3539 current_mask.flat = mask 

3540 else: 

3541 # Named fields w/ 

3542 mdtype = current_mask.dtype 

3543 mask = np.asarray(mask) 

3544 # Mask is a singleton 

3545 if not mask.ndim: 

3546 # It's a boolean : make a record 

3547 if mask.dtype.kind == 'b': 

3548 mask = np.array(tuple([mask.item()] * len(mdtype)), 

3549 dtype=mdtype) 

3550 # It's a record: make sure the dtype is correct 

3551 else: 

3552 mask = mask.astype(mdtype) 

3553 # Mask is a sequence 

3554 else: 

3555 # Make sure the new mask is a ndarray with the proper dtype 

3556 try: 

3557 copy = None if not copy else True 

3558 mask = np.array(mask, copy=copy, dtype=mdtype) 

3559 # Or assume it's a sequence of bool/int 

3560 except TypeError: 

3561 mask = np.array([tuple([m] * len(mdtype)) for m in mask], 

3562 dtype=mdtype) 

3563 # Hardmask: don't unmask the data 

3564 if self._hardmask: 

3565 for n in idtype.names: 

3566 current_mask[n] |= mask[n] 

3567 # Softmask: set everything to False 

3568 # If it's obviously a compatible scalar, use a quick update 

3569 # method. 

3570 elif isinstance(mask, (int, float, np.bool, np.number)): 

3571 current_mask[...] = mask 

3572 # Otherwise fall back to the slower, general purpose way. 

3573 else: 

3574 current_mask.flat = mask 

3575 # Reshape if needed 

3576 if current_mask.shape: 

3577 current_mask.shape = self.shape 

3578 return 

3579 

3580 _set_mask = __setmask__ 

3581 

3582 @property 

3583 def mask(self): 

3584 """ Current mask. """ 

3585 

3586 # We could try to force a reshape, but that wouldn't work in some 

3587 # cases. 

3588 # Return a view so that the dtype and shape cannot be changed in place 

3589 # This still preserves nomask by identity 

3590 return self._mask.view() 

3591 

3592 @mask.setter 

3593 def mask(self, value): 

3594 self.__setmask__(value) 

3595 

3596 @property 

3597 def recordmask(self): 

3598 """ 

3599 Get or set the mask of the array if it has no named fields. For 

3600 structured arrays, returns a ndarray of booleans where entries are 

3601 ``True`` if **all** the fields are masked, ``False`` otherwise: 

3602 

3603 >>> x = np.ma.array([(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)], 

3604 ... mask=[(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)], 

3605 ... dtype=[('a', int), ('b', int)]) 

3606 >>> x.recordmask 

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

3608 """ 

3609 

3610 _mask = self._mask.view(ndarray) 

3611 if _mask.dtype.names is None: 

3612 return _mask 

3613 return np.all(flatten_structured_array(_mask), axis=-1) 

3614 

3615 @recordmask.setter 

3616 def recordmask(self, mask): 

3617 raise NotImplementedError("Coming soon: setting the mask per records!") 

3618 

3619 def harden_mask(self): 

3620 """ 

3621 Force the mask to hard, preventing unmasking by assignment. 

3622 

3623 Whether the mask of a masked array is hard or soft is determined by 

3624 its `~ma.MaskedArray.hardmask` property. `harden_mask` sets 

3625 `~ma.MaskedArray.hardmask` to ``True`` (and returns the modified 

3626 self). 

3627 

3628 See Also 

3629 -------- 

3630 ma.MaskedArray.hardmask 

3631 ma.MaskedArray.soften_mask 

3632 

3633 """ 

3634 self._hardmask = True 

3635 return self 

3636 

3637 def soften_mask(self): 

3638 """ 

3639 Force the mask to soft (default), allowing unmasking by assignment. 

3640 

3641 Whether the mask of a masked array is hard or soft is determined by 

3642 its `~ma.MaskedArray.hardmask` property. `soften_mask` sets 

3643 `~ma.MaskedArray.hardmask` to ``False`` (and returns the modified 

3644 self). 

3645 

3646 See Also 

3647 -------- 

3648 ma.MaskedArray.hardmask 

3649 ma.MaskedArray.harden_mask 

3650 

3651 """ 

3652 self._hardmask = False 

3653 return self 

3654 

3655 @property 

3656 def hardmask(self): 

3657 """ 

3658 Specifies whether values can be unmasked through assignments. 

3659 

3660 By default, assigning definite values to masked array entries will 

3661 unmask them. When `hardmask` is ``True``, the mask will not change 

3662 through assignments. 

3663 

3664 See Also 

3665 -------- 

3666 ma.MaskedArray.harden_mask 

3667 ma.MaskedArray.soften_mask 

3668 

3669 Examples 

3670 -------- 

3671 >>> import numpy as np 

3672 >>> x = np.arange(10) 

3673 >>> m = np.ma.masked_array(x, x>5) 

3674 >>> assert not m.hardmask 

3675 

3676 Since `m` has a soft mask, assigning an element value unmasks that 

3677 element: 

3678 

3679 >>> m[8] = 42 

3680 >>> m 

3681 masked_array(data=[0, 1, 2, 3, 4, 5, --, --, 42, --], 

3682 mask=[False, False, False, False, False, False, 

3683 True, True, False, True], 

3684 fill_value=999999) 

3685 

3686 After hardening, the mask is not affected by assignments: 

3687 

3688 >>> hardened = np.ma.harden_mask(m) 

3689 >>> assert m.hardmask and hardened is m 

3690 >>> m[:] = 23 

3691 >>> m 

3692 masked_array(data=[23, 23, 23, 23, 23, 23, --, --, 23, --], 

3693 mask=[False, False, False, False, False, False, 

3694 True, True, False, True], 

3695 fill_value=999999) 

3696 

3697 """ 

3698 return self._hardmask 

3699 

3700 def unshare_mask(self): 

3701 """ 

3702 Copy the mask and set the `sharedmask` flag to ``False``. 

3703 

3704 Whether the mask is shared between masked arrays can be seen from 

3705 the `sharedmask` property. `unshare_mask` ensures the mask is not 

3706 shared. A copy of the mask is only made if it was shared. 

3707 

3708 See Also 

3709 -------- 

3710 sharedmask 

3711 

3712 """ 

3713 if self._sharedmask: 

3714 self._mask = self._mask.copy() 

3715 self._sharedmask = False 

3716 return self 

3717 

3718 @property 

3719 def sharedmask(self): 

3720 """ Share status of the mask (read-only). """ 

3721 return self._sharedmask 

3722 

3723 def shrink_mask(self): 

3724 """ 

3725 Reduce a mask to nomask when possible. 

3726 

3727 Parameters 

3728 ---------- 

3729 None 

3730 

3731 Returns 

3732 ------- 

3733 result : MaskedArray 

3734 A :class:`~ma.MaskedArray` object. 

3735 

3736 Examples 

3737 -------- 

3738 >>> import numpy as np 

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

3740 >>> x.mask 

3741 array([[False, False], 

3742 [False, False]]) 

3743 >>> x.shrink_mask() 

3744 masked_array( 

3745 data=[[1, 2], 

3746 [3, 4]], 

3747 mask=False, 

3748 fill_value=999999) 

3749 >>> x.mask 

3750 False 

3751 

3752 """ 

3753 self._mask = _shrink_mask(self._mask) 

3754 return self 

3755 

3756 @property 

3757 def baseclass(self): 

3758 """ Class of the underlying data (read-only). """ 

3759 return self._baseclass 

3760 

3761 def _get_data(self): 

3762 """ 

3763 Returns the underlying data, as a view of the masked array. 

3764 

3765 If the underlying data is a subclass of :class:`numpy.ndarray`, it is 

3766 returned as such. 

3767 

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

3769 >>> x.data 

3770 matrix([[1, 2], 

3771 [3, 4]]) 

3772 

3773 The type of the data can be accessed through the :attr:`baseclass` 

3774 attribute. 

3775 """ 

3776 return ndarray.view(self, self._baseclass) 

3777 

3778 _data = property(fget=_get_data) 

3779 data = property(fget=_get_data) 

3780 

3781 @property 

3782 def flat(self): 

3783 """ Return a flat iterator, or set a flattened version of self to value. """ 

3784 return MaskedIterator(self) 

3785 

3786 @flat.setter 

3787 def flat(self, value): 

3788 y = self.ravel() 

3789 y[:] = value 

3790 

3791 @property 

3792 def fill_value(self): 

3793 """ 

3794 The filling value of the masked array is a scalar. When setting, None 

3795 will set to a default based on the data type. 

3796 

3797 Examples 

3798 -------- 

3799 >>> import numpy as np 

3800 >>> for dt in [np.int32, np.int64, np.float64, np.complex128]: 

3801 ... np.ma.array([0, 1], dtype=dt).get_fill_value() 

3802 ... 

3803 np.int64(999999) 

3804 np.int64(999999) 

3805 np.float64(1e+20) 

3806 np.complex128(1e+20+0j) 

3807 

3808 >>> x = np.ma.array([0, 1.], fill_value=-np.inf) 

3809 >>> x.fill_value 

3810 np.float64(-inf) 

3811 >>> x.fill_value = np.pi 

3812 >>> x.fill_value 

3813 np.float64(3.1415926535897931) 

3814 

3815 Reset to default: 

3816 

3817 >>> x.fill_value = None 

3818 >>> x.fill_value 

3819 np.float64(1e+20) 

3820 

3821 """ 

3822 if self._fill_value is None: 

3823 self._fill_value = _check_fill_value(None, self.dtype) 

3824 

3825 # Temporary workaround to account for the fact that str and bytes 

3826 # scalars cannot be indexed with (), whereas all other numpy 

3827 # scalars can. See issues #7259 and #7267. 

3828 # The if-block can be removed after #7267 has been fixed. 

3829 if isinstance(self._fill_value, ndarray): 

3830 return self._fill_value[()] 

3831 return self._fill_value 

3832 

3833 @fill_value.setter 

3834 def fill_value(self, value=None): 

3835 target = _check_fill_value(value, self.dtype) 

3836 if not target.ndim == 0: 

3837 # 2019-11-12, 1.18.0 

3838 warnings.warn( 

3839 "Non-scalar arrays for the fill value are deprecated. Use " 

3840 "arrays with scalar values instead. The filled function " 

3841 "still supports any array as `fill_value`.", 

3842 DeprecationWarning, stacklevel=2) 

3843 

3844 _fill_value = self._fill_value 

3845 if _fill_value is None: 

3846 # Create the attribute if it was undefined 

3847 self._fill_value = target 

3848 else: 

3849 # Don't overwrite the attribute, just fill it (for propagation) 

3850 _fill_value[()] = target 

3851 

3852 # kept for compatibility 

3853 get_fill_value = fill_value.fget 

3854 set_fill_value = fill_value.fset 

3855 

3856 def filled(self, fill_value=None): 

3857 """ 

3858 Return a copy of self, with masked values filled with a given value. 

3859 **However**, if there are no masked values to fill, self will be 

3860 returned instead as an ndarray. 

3861 

3862 Parameters 

3863 ---------- 

3864 fill_value : array_like, optional 

3865 The value to use for invalid entries. Can be scalar or non-scalar. 

3866 If non-scalar, the resulting ndarray must be broadcastable over 

3867 input array. Default is None, in which case, the `fill_value` 

3868 attribute of the array is used instead. 

3869 

3870 Returns 

3871 ------- 

3872 filled_array : ndarray 

3873 A copy of ``self`` with invalid entries replaced by *fill_value* 

3874 (be it the function argument or the attribute of ``self``), or 

3875 ``self`` itself as an ndarray if there are no invalid entries to 

3876 be replaced. 

3877 

3878 Notes 

3879 ----- 

3880 The result is **not** a MaskedArray! 

3881 

3882 Examples 

3883 -------- 

3884 >>> import numpy as np 

3885 >>> x = np.ma.array([1,2,3,4,5], mask=[0,0,1,0,1], fill_value=-999) 

3886 >>> x.filled() 

3887 array([ 1, 2, -999, 4, -999]) 

3888 >>> x.filled(fill_value=1000) 

3889 array([ 1, 2, 1000, 4, 1000]) 

3890 >>> type(x.filled()) 

3891 <class 'numpy.ndarray'> 

3892 

3893 Subclassing is preserved. This means that if, e.g., the data part of 

3894 the masked array is a recarray, `filled` returns a recarray: 

3895 

3896 >>> x = np.array([(-1, 2), (-3, 4)], dtype='i8,i8').view(np.recarray) 

3897 >>> m = np.ma.array(x, mask=[(True, False), (False, True)]) 

3898 >>> m.filled() 

3899 rec.array([(999999, 2), ( -3, 999999)], 

3900 dtype=[('f0', '<i8'), ('f1', '<i8')]) 

3901 """ 

3902 m = self._mask 

3903 if m is nomask: 

3904 return self._data 

3905 

3906 if fill_value is None: 

3907 fill_value = self.fill_value 

3908 else: 

3909 fill_value = _check_fill_value(fill_value, self.dtype) 

3910 

3911 if self is masked_singleton: 

3912 return np.asanyarray(fill_value) 

3913 

3914 if m.dtype.names is not None: 

3915 result = self._data.copy('K') 

3916 _recursive_filled(result, self._mask, fill_value) 

3917 elif not m.any(): 

3918 return self._data 

3919 else: 

3920 result = self._data.copy('K') 

3921 try: 

3922 np.copyto(result, fill_value, where=m) 

3923 except (TypeError, AttributeError): 

3924 fill_value = narray(fill_value, dtype=object) 

3925 d = result.astype(object) 

3926 result = np.choose(m, (d, fill_value)) 

3927 except IndexError: 

3928 # ok, if scalar 

3929 if self._data.shape: 

3930 raise 

3931 elif m: 

3932 result = np.array(fill_value, dtype=self.dtype) 

3933 else: 

3934 result = self._data 

3935 return result 

3936 

3937 def compressed(self): 

3938 """ 

3939 Return all the non-masked data as a 1-D array. 

3940 

3941 Returns 

3942 ------- 

3943 data : ndarray 

3944 A new `ndarray` holding the non-masked data is returned. 

3945 

3946 Notes 

3947 ----- 

3948 The result is **not** a MaskedArray! 

3949 

3950 Examples 

3951 -------- 

3952 >>> import numpy as np 

3953 >>> x = np.ma.array(np.arange(5), mask=[0]*2 + [1]*3) 

3954 >>> x.compressed() 

3955 array([0, 1]) 

3956 >>> type(x.compressed()) 

3957 <class 'numpy.ndarray'> 

3958 

3959 N-D arrays are compressed to 1-D. 

3960 

3961 >>> arr = [[1, 2], [3, 4]] 

3962 >>> mask = [[1, 0], [0, 1]] 

3963 >>> x = np.ma.array(arr, mask=mask) 

3964 >>> x.compressed() 

3965 array([2, 3]) 

3966 

3967 """ 

3968 data = ndarray.ravel(self._data) 

3969 if self._mask is not nomask: 

3970 data = data.compress(np.logical_not(ndarray.ravel(self._mask))) 

3971 return data 

3972 

3973 def compress(self, condition, axis=None, out=None): 

3974 """ 

3975 Return `a` where condition is ``True``. 

3976 

3977 If condition is a `~ma.MaskedArray`, missing values are considered 

3978 as ``False``. 

3979 

3980 Parameters 

3981 ---------- 

3982 condition : var 

3983 Boolean 1-d array selecting which entries to return. If len(condition) 

3984 is less than the size of a along the axis, then output is truncated 

3985 to length of condition array. 

3986 axis : {None, int}, optional 

3987 Axis along which the operation must be performed. 

3988 out : {None, ndarray}, optional 

3989 Alternative output array in which to place the result. It must have 

3990 the same shape as the expected output but the type will be cast if 

3991 necessary. 

3992 

3993 Returns 

3994 ------- 

3995 result : MaskedArray 

3996 A :class:`~ma.MaskedArray` object. 

3997 

3998 Notes 

3999 ----- 

4000 Please note the difference with :meth:`compressed` ! 

4001 The output of :meth:`compress` has a mask, the output of 

4002 :meth:`compressed` does not. 

4003 

4004 Examples 

4005 -------- 

4006 >>> import numpy as np 

4007 >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4) 

4008 >>> x 

4009 masked_array( 

4010 data=[[1, --, 3], 

4011 [--, 5, --], 

4012 [7, --, 9]], 

4013 mask=[[False, True, False], 

4014 [ True, False, True], 

4015 [False, True, False]], 

4016 fill_value=999999) 

4017 >>> x.compress([1, 0, 1]) 

4018 masked_array(data=[1, 3], 

4019 mask=[False, False], 

4020 fill_value=999999) 

4021 

4022 >>> x.compress([1, 0, 1], axis=1) 

4023 masked_array( 

4024 data=[[1, 3], 

4025 [--, --], 

4026 [7, 9]], 

4027 mask=[[False, False], 

4028 [ True, True], 

4029 [False, False]], 

4030 fill_value=999999) 

4031 

4032 """ 

4033 # Get the basic components 

4034 (_data, _mask) = (self._data, self._mask) 

4035 

4036 # Force the condition to a regular ndarray and forget the missing 

4037 # values. 

4038 condition = np.asarray(condition) 

4039 

4040 _new = _data.compress(condition, axis=axis, out=out).view(type(self)) 

4041 _new._update_from(self) 

4042 if _mask is not nomask: 

4043 _new._mask = _mask.compress(condition, axis=axis) 

4044 return _new 

4045 

4046 def _insert_masked_print(self): 

4047 """ 

4048 Replace masked values with masked_print_option, casting all innermost 

4049 dtypes to object. 

4050 """ 

4051 if masked_print_option.enabled(): 

4052 mask = self._mask 

4053 if mask is nomask: 

4054 res = self._data 

4055 else: 

4056 # convert to object array to make filled work 

4057 data = self._data 

4058 # For big arrays, to avoid a costly conversion to the 

4059 # object dtype, extract the corners before the conversion. 

4060 print_width = (self._print_width if self.ndim > 1 

4061 else self._print_width_1d) 

4062 for axis in range(self.ndim): 

4063 if data.shape[axis] > print_width: 

4064 ind = print_width // 2 

4065 arr = np.split(data, (ind, -ind), axis=axis) 

4066 data = np.concatenate((arr[0], arr[2]), axis=axis) 

4067 arr = np.split(mask, (ind, -ind), axis=axis) 

4068 mask = np.concatenate((arr[0], arr[2]), axis=axis) 

4069 

4070 rdtype = _replace_dtype_fields(self.dtype, "O") 

4071 res = data.astype(rdtype) 

4072 _recursive_printoption(res, mask, masked_print_option) 

4073 else: 

4074 res = self.filled(self.fill_value) 

4075 return res 

4076 

4077 def __str__(self): 

4078 return str(self._insert_masked_print()) 

4079 

4080 def __repr__(self): 

4081 """ 

4082 Literal string representation. 

4083 

4084 """ 

4085 if self._baseclass is np.ndarray: 

4086 name = 'array' 

4087 else: 

4088 name = self._baseclass.__name__ 

4089 

4090 # 2016-11-19: Demoted to legacy format 

4091 if np._core.arrayprint._get_legacy_print_mode() <= 113: 

4092 is_long = self.ndim > 1 

4093 parameters = { 

4094 'name': name, 

4095 'nlen': " " * len(name), 

4096 'data': str(self), 

4097 'mask': str(self._mask), 

4098 'fill': str(self.fill_value), 

4099 'dtype': str(self.dtype) 

4100 } 

4101 is_structured = bool(self.dtype.names) 

4102 key = '{}_{}'.format( 

4103 'long' if is_long else 'short', 

4104 'flx' if is_structured else 'std' 

4105 ) 

4106 return _legacy_print_templates[key] % parameters 

4107 

4108 prefix = f"masked_{name}(" 

4109 

4110 dtype_needed = ( 

4111 not np._core.arrayprint.dtype_is_implied(self.dtype) or 

4112 np.all(self.mask) or 

4113 self.size == 0 

4114 ) 

4115 

4116 # determine which keyword args need to be shown 

4117 keys = ['data', 'mask', 'fill_value'] 

4118 if dtype_needed: 

4119 keys.append('dtype') 

4120 

4121 # array has only one row (non-column) 

4122 is_one_row = builtins.all(dim == 1 for dim in self.shape[:-1]) 

4123 

4124 # choose what to indent each keyword with 

4125 min_indent = 2 

4126 if is_one_row: 

4127 # first key on the same line as the type, remaining keys 

4128 # aligned by equals 

4129 indents = {} 

4130 indents[keys[0]] = prefix 

4131 for k in keys[1:]: 

4132 n = builtins.max(min_indent, len(prefix + keys[0]) - len(k)) 

4133 indents[k] = ' ' * n 

4134 prefix = '' # absorbed into the first indent 

4135 else: 

4136 # each key on its own line, indented by two spaces 

4137 indents = dict.fromkeys(keys, ' ' * min_indent) 

4138 prefix = prefix + '\n' # first key on the next line 

4139 

4140 # format the field values 

4141 reprs = {} 

4142 reprs['data'] = np.array2string( 

4143 self._insert_masked_print(), 

4144 separator=", ", 

4145 prefix=indents['data'] + 'data=', 

4146 suffix=',') 

4147 reprs['mask'] = np.array2string( 

4148 self._mask, 

4149 separator=", ", 

4150 prefix=indents['mask'] + 'mask=', 

4151 suffix=',') 

4152 

4153 if self._fill_value is None: 

4154 self.fill_value # initialize fill_value # noqa: B018 

4155 

4156 if (self._fill_value.dtype.kind in ("S", "U") 

4157 and self.dtype.kind == self._fill_value.dtype.kind): 

4158 # Allow strings: "N/A" has length 3 so would mismatch. 

4159 fill_repr = repr(self.fill_value.item()) 

4160 elif self._fill_value.dtype == self.dtype and not self.dtype == object: 

4161 # Guess that it is OK to use the string as item repr. To really 

4162 # fix this, it needs new logic (shared with structured scalars) 

4163 fill_repr = str(self.fill_value) 

4164 else: 

4165 fill_repr = repr(self.fill_value) 

4166 

4167 reprs['fill_value'] = fill_repr 

4168 if dtype_needed: 

4169 reprs['dtype'] = np._core.arrayprint.dtype_short_repr(self.dtype) 

4170 

4171 # join keys with values and indentations 

4172 result = ',\n'.join( 

4173 f'{indents[k]}{k}={reprs[k]}' 

4174 for k in keys 

4175 ) 

4176 return prefix + result + ')' 

4177 

4178 def _delegate_binop(self, other): 

4179 # This emulates the logic in 

4180 # private/binop_override.h:forward_binop_should_defer 

4181 if isinstance(other, type(self)): 

4182 return False 

4183 array_ufunc = getattr(other, "__array_ufunc__", False) 

4184 if array_ufunc is False: 

4185 other_priority = getattr(other, "__array_priority__", -1000000) 

4186 return self.__array_priority__ < other_priority 

4187 else: 

4188 # If array_ufunc is not None, it will be called inside the ufunc; 

4189 # None explicitly tells us to not call the ufunc, i.e., defer. 

4190 return array_ufunc is None 

4191 

4192 def _comparison(self, other, compare): 

4193 """Compare self with other using operator.eq or operator.ne. 

4194 

4195 When either of the elements is masked, the result is masked as well, 

4196 but the underlying boolean data are still set, with self and other 

4197 considered equal if both are masked, and unequal otherwise. 

4198 

4199 For structured arrays, all fields are combined, with masked values 

4200 ignored. The result is masked if all fields were masked, with self 

4201 and other considered equal only if both were fully masked. 

4202 """ 

4203 omask = getmask(other) 

4204 smask = self.mask 

4205 mask = mask_or(smask, omask, copy=True) 

4206 

4207 odata = getdata(other) 

4208 if mask.dtype.names is not None: 

4209 # only == and != are reasonably defined for structured dtypes, 

4210 # so give up early for all other comparisons: 

4211 if compare not in (operator.eq, operator.ne): 

4212 return NotImplemented 

4213 # For possibly masked structured arrays we need to be careful, 

4214 # since the standard structured array comparison will use all 

4215 # fields, masked or not. To avoid masked fields influencing the 

4216 # outcome, we set all masked fields in self to other, so they'll 

4217 # count as equal. To prepare, we ensure we have the right shape. 

4218 broadcast_shape = np.broadcast(self, odata).shape 

4219 sbroadcast = np.broadcast_to(self, broadcast_shape, subok=True) 

4220 sbroadcast._mask = mask 

4221 sdata = sbroadcast.filled(odata) 

4222 # Now take care of the mask; the merged mask should have an item 

4223 # masked if all fields were masked (in one and/or other). 

4224 mask = (mask == np.ones((), mask.dtype)) 

4225 # Ensure we can compare masks below if other was not masked. 

4226 if omask is np.False_: 

4227 omask = np.zeros((), smask.dtype) 

4228 

4229 else: 

4230 # For regular arrays, just use the data as they come. 

4231 sdata = self.data 

4232 

4233 check = compare(sdata, odata) 

4234 

4235 if isinstance(check, (np.bool, bool)): 

4236 return masked if mask else check 

4237 

4238 if mask is not nomask: 

4239 if compare in (operator.eq, operator.ne): 

4240 # Adjust elements that were masked, which should be treated 

4241 # as equal if masked in both, unequal if masked in one. 

4242 # Note that this works automatically for structured arrays too. 

4243 # Ignore this for operations other than `==` and `!=` 

4244 check = np.where(mask, compare(smask, omask), check) 

4245 

4246 if mask.shape != check.shape: 

4247 # Guarantee consistency of the shape, making a copy since the 

4248 # the mask may need to get written to later. 

4249 mask = np.broadcast_to(mask, check.shape).copy() 

4250 

4251 check = check.view(type(self)) 

4252 check._update_from(self) 

4253 check._mask = mask 

4254 

4255 # Cast fill value to np.bool if needed. If it cannot be cast, the 

4256 # default boolean fill value is used. 

4257 if check._fill_value is not None: 

4258 try: 

4259 fill = _check_fill_value(check._fill_value, np.bool) 

4260 except (TypeError, ValueError): 

4261 fill = _check_fill_value(None, np.bool) 

4262 check._fill_value = fill 

4263 

4264 return check 

4265 

4266 def __eq__(self, other): 

4267 """Check whether other equals self elementwise. 

4268 

4269 When either of the elements is masked, the result is masked as well, 

4270 but the underlying boolean data are still set, with self and other 

4271 considered equal if both are masked, and unequal otherwise. 

4272 

4273 For structured arrays, all fields are combined, with masked values 

4274 ignored. The result is masked if all fields were masked, with self 

4275 and other considered equal only if both were fully masked. 

4276 """ 

4277 return self._comparison(other, operator.eq) 

4278 

4279 def __ne__(self, other): 

4280 """Check whether other does not equal self elementwise. 

4281 

4282 When either of the elements is masked, the result is masked as well, 

4283 but the underlying boolean data are still set, with self and other 

4284 considered equal if both are masked, and unequal otherwise. 

4285 

4286 For structured arrays, all fields are combined, with masked values 

4287 ignored. The result is masked if all fields were masked, with self 

4288 and other considered equal only if both were fully masked. 

4289 """ 

4290 return self._comparison(other, operator.ne) 

4291 

4292 # All other comparisons: 

4293 def __le__(self, other): 

4294 return self._comparison(other, operator.le) 

4295 

4296 def __lt__(self, other): 

4297 return self._comparison(other, operator.lt) 

4298 

4299 def __ge__(self, other): 

4300 return self._comparison(other, operator.ge) 

4301 

4302 def __gt__(self, other): 

4303 return self._comparison(other, operator.gt) 

4304 

4305 def __add__(self, other): 

4306 """ 

4307 Add self to other, and return a new masked array. 

4308 

4309 """ 

4310 if self._delegate_binop(other): 

4311 return NotImplemented 

4312 return add(self, other) 

4313 

4314 def __radd__(self, other): 

4315 """ 

4316 Add other to self, and return a new masked array. 

4317 

4318 """ 

4319 # In analogy with __rsub__ and __rdiv__, use original order: 

4320 # we get here from `other + self`. 

4321 return add(other, self) 

4322 

4323 def __sub__(self, other): 

4324 """ 

4325 Subtract other from self, and return a new masked array. 

4326 

4327 """ 

4328 if self._delegate_binop(other): 

4329 return NotImplemented 

4330 return subtract(self, other) 

4331 

4332 def __rsub__(self, other): 

4333 """ 

4334 Subtract self from other, and return a new masked array. 

4335 

4336 """ 

4337 return subtract(other, self) 

4338 

4339 def __mul__(self, other): 

4340 "Multiply self by other, and return a new masked array." 

4341 if self._delegate_binop(other): 

4342 return NotImplemented 

4343 return multiply(self, other) 

4344 

4345 def __rmul__(self, other): 

4346 """ 

4347 Multiply other by self, and return a new masked array. 

4348 

4349 """ 

4350 # In analogy with __rsub__ and __rdiv__, use original order: 

4351 # we get here from `other * self`. 

4352 return multiply(other, self) 

4353 

4354 def __truediv__(self, other): 

4355 """ 

4356 Divide other into self, and return a new masked array. 

4357 

4358 """ 

4359 if self._delegate_binop(other): 

4360 return NotImplemented 

4361 return true_divide(self, other) 

4362 

4363 def __rtruediv__(self, other): 

4364 """ 

4365 Divide self into other, and return a new masked array. 

4366 

4367 """ 

4368 return true_divide(other, self) 

4369 

4370 def __floordiv__(self, other): 

4371 """ 

4372 Divide other into self, and return a new masked array. 

4373 

4374 """ 

4375 if self._delegate_binop(other): 

4376 return NotImplemented 

4377 return floor_divide(self, other) 

4378 

4379 def __rfloordiv__(self, other): 

4380 """ 

4381 Divide self into other, and return a new masked array. 

4382 

4383 """ 

4384 return floor_divide(other, self) 

4385 

4386 def __pow__(self, other): 

4387 """ 

4388 Raise self to the power other, masking the potential NaNs/Infs 

4389 

4390 """ 

4391 if self._delegate_binop(other): 

4392 return NotImplemented 

4393 return power(self, other) 

4394 

4395 def __rpow__(self, other): 

4396 """ 

4397 Raise other to the power self, masking the potential NaNs/Infs 

4398 

4399 """ 

4400 return power(other, self) 

4401 

4402 def __iadd__(self, other): 

4403 """ 

4404 Add other to self in-place. 

4405 

4406 """ 

4407 m = getmask(other) 

4408 if self._mask is nomask: 

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

4410 self._mask = make_mask_none(self.shape, self.dtype) 

4411 self._mask += m 

4412 elif m is not nomask: 

4413 self._mask += m 

4414 other_data = getdata(other) 

4415 other_data = np.where(self._mask, other_data.dtype.type(0), other_data) 

4416 self._data.__iadd__(other_data) 

4417 return self 

4418 

4419 def __isub__(self, other): 

4420 """ 

4421 Subtract other from self in-place. 

4422 

4423 """ 

4424 m = getmask(other) 

4425 if self._mask is nomask: 

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

4427 self._mask = make_mask_none(self.shape, self.dtype) 

4428 self._mask += m 

4429 elif m is not nomask: 

4430 self._mask += m 

4431 other_data = getdata(other) 

4432 other_data = np.where(self._mask, other_data.dtype.type(0), other_data) 

4433 self._data.__isub__(other_data) 

4434 return self 

4435 

4436 def __imul__(self, other): 

4437 """ 

4438 Multiply self by other in-place. 

4439 

4440 """ 

4441 m = getmask(other) 

4442 if self._mask is nomask: 

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

4444 self._mask = make_mask_none(self.shape, self.dtype) 

4445 self._mask += m 

4446 elif m is not nomask: 

4447 self._mask += m 

4448 other_data = getdata(other) 

4449 other_data = np.where(self._mask, other_data.dtype.type(1), other_data) 

4450 self._data.__imul__(other_data) 

4451 return self 

4452 

4453 def __ifloordiv__(self, other): 

4454 """ 

4455 Floor divide self by other in-place. 

4456 

4457 """ 

4458 other_data = getdata(other) 

4459 dom_mask = _DomainSafeDivide().__call__(self._data, other_data) 

4460 other_mask = getmask(other) 

4461 new_mask = mask_or(other_mask, dom_mask) 

4462 # The following 3 lines control the domain filling 

4463 if dom_mask.any(): 

4464 (_, fval) = ufunc_fills[np.floor_divide] 

4465 other_data = np.where( 

4466 dom_mask, other_data.dtype.type(fval), other_data) 

4467 self._mask |= new_mask 

4468 other_data = np.where(self._mask, other_data.dtype.type(1), other_data) 

4469 self._data.__ifloordiv__(other_data) 

4470 return self 

4471 

4472 def __itruediv__(self, other): 

4473 """ 

4474 True divide self by other in-place. 

4475 

4476 """ 

4477 other_data = getdata(other) 

4478 dom_mask = _DomainSafeDivide().__call__(self._data, other_data) 

4479 other_mask = getmask(other) 

4480 new_mask = mask_or(other_mask, dom_mask) 

4481 # The following 3 lines control the domain filling 

4482 if dom_mask.any(): 

4483 (_, fval) = ufunc_fills[np.true_divide] 

4484 other_data = np.where( 

4485 dom_mask, other_data.dtype.type(fval), other_data) 

4486 self._mask |= new_mask 

4487 other_data = np.where(self._mask, other_data.dtype.type(1), other_data) 

4488 self._data.__itruediv__(other_data) 

4489 return self 

4490 

4491 def __ipow__(self, other): 

4492 """ 

4493 Raise self to the power other, in place. 

4494 

4495 """ 

4496 other_data = getdata(other) 

4497 other_data = np.where(self._mask, other_data.dtype.type(1), other_data) 

4498 other_mask = getmask(other) 

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

4500 self._data.__ipow__(other_data) 

4501 invalid = np.logical_not(np.isfinite(self._data)) 

4502 if invalid.any(): 

4503 if self._mask is not nomask: 

4504 self._mask |= invalid 

4505 else: 

4506 self._mask = invalid 

4507 np.copyto(self._data, self.fill_value, where=invalid) 

4508 new_mask = mask_or(other_mask, invalid) 

4509 self._mask = mask_or(self._mask, new_mask) 

4510 return self 

4511 

4512 def __float__(self): 

4513 """ 

4514 Convert to float. 

4515 

4516 """ 

4517 if self.size > 1: 

4518 raise TypeError("Only length-1 arrays can be converted " 

4519 "to Python scalars") 

4520 elif self._mask: 

4521 warnings.warn("Warning: converting a masked element to nan.", stacklevel=2) 

4522 return np.nan 

4523 return float(self.item()) 

4524 

4525 def __int__(self): 

4526 """ 

4527 Convert to int. 

4528 

4529 """ 

4530 if self.size > 1: 

4531 raise TypeError("Only length-1 arrays can be converted " 

4532 "to Python scalars") 

4533 elif self._mask: 

4534 raise MaskError('Cannot convert masked element to a Python int.') 

4535 return int(self.item()) 

4536 

4537 @property 

4538 def imag(self): 

4539 """ 

4540 The imaginary part of the masked array. 

4541 

4542 This property is a view on the imaginary part of this `MaskedArray`. 

4543 

4544 See Also 

4545 -------- 

4546 real 

4547 

4548 Examples 

4549 -------- 

4550 >>> import numpy as np 

4551 >>> x = np.ma.array([1+1.j, -2j, 3.45+1.6j], mask=[False, True, False]) 

4552 >>> x.imag 

4553 masked_array(data=[1.0, --, 1.6], 

4554 mask=[False, True, False], 

4555 fill_value=1e+20) 

4556 

4557 """ 

4558 result = self._data.imag.view(type(self)) 

4559 result.__setmask__(self._mask) 

4560 return result 

4561 

4562 # kept for compatibility 

4563 get_imag = imag.fget 

4564 

4565 @property 

4566 def real(self): 

4567 """ 

4568 The real part of the masked array. 

4569 

4570 This property is a view on the real part of this `MaskedArray`. 

4571 

4572 See Also 

4573 -------- 

4574 imag 

4575 

4576 Examples 

4577 -------- 

4578 >>> import numpy as np 

4579 >>> x = np.ma.array([1+1.j, -2j, 3.45+1.6j], mask=[False, True, False]) 

4580 >>> x.real 

4581 masked_array(data=[1.0, --, 3.45], 

4582 mask=[False, True, False], 

4583 fill_value=1e+20) 

4584 

4585 """ 

4586 result = self._data.real.view(type(self)) 

4587 result.__setmask__(self._mask) 

4588 return result 

4589 

4590 # kept for compatibility 

4591 get_real = real.fget 

4592 

4593 def count(self, axis=None, keepdims=np._NoValue): 

4594 """ 

4595 Count the non-masked elements of the array along the given axis. 

4596 

4597 Parameters 

4598 ---------- 

4599 axis : None or int or tuple of ints, optional 

4600 Axis or axes along which the count is performed. 

4601 The default, None, performs the count over all 

4602 the dimensions of the input array. `axis` may be negative, in 

4603 which case it counts from the last to the first axis. 

4604 If this is a tuple of ints, the count is performed on multiple 

4605 axes, instead of a single axis or all the axes as before. 

4606 keepdims : bool, optional 

4607 If this is set to True, the axes which are reduced are left 

4608 in the result as dimensions with size one. With this option, 

4609 the result will broadcast correctly against the array. 

4610 

4611 Returns 

4612 ------- 

4613 result : ndarray or scalar 

4614 An array with the same shape as the input array, with the specified 

4615 axis removed. If the array is a 0-d array, or if `axis` is None, a 

4616 scalar is returned. 

4617 

4618 See Also 

4619 -------- 

4620 ma.count_masked : Count masked elements in array or along a given axis. 

4621 

4622 Examples 

4623 -------- 

4624 >>> import numpy.ma as ma 

4625 >>> a = ma.arange(6).reshape((2, 3)) 

4626 >>> a[1, :] = ma.masked 

4627 >>> a 

4628 masked_array( 

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

4630 [--, --, --]], 

4631 mask=[[False, False, False], 

4632 [ True, True, True]], 

4633 fill_value=999999) 

4634 >>> a.count() 

4635 3 

4636 

4637 When the `axis` keyword is specified an array of appropriate size is 

4638 returned. 

4639 

4640 >>> a.count(axis=0) 

4641 array([1, 1, 1]) 

4642 >>> a.count(axis=1) 

4643 array([3, 0]) 

4644 

4645 """ 

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

4647 

4648 m = self._mask 

4649 # special case for matrices (we assume no other subclasses modify 

4650 # their dimensions) 

4651 if isinstance(self.data, np.matrix): 

4652 if m is nomask: 

4653 m = np.zeros(self.shape, dtype=np.bool) 

4654 m = m.view(type(self.data)) 

4655 

4656 if m is nomask: 

4657 # compare to _count_reduce_items in _methods.py 

4658 

4659 if self.shape == (): 

4660 if axis not in (None, 0): 

4661 raise np.exceptions.AxisError(axis=axis, ndim=self.ndim) 

4662 return 1 

4663 elif axis is None: 

4664 if kwargs.get('keepdims'): 

4665 return np.array(self.size, dtype=np.intp, ndmin=self.ndim) 

4666 return self.size 

4667 

4668 axes = normalize_axis_tuple(axis, self.ndim) 

4669 items = 1 

4670 for ax in axes: 

4671 items *= self.shape[ax] 

4672 

4673 if kwargs.get('keepdims'): 

4674 out_dims = list(self.shape) 

4675 for a in axes: 

4676 out_dims[a] = 1 

4677 else: 

4678 out_dims = [d for n, d in enumerate(self.shape) 

4679 if n not in axes] 

4680 # make sure to return a 0-d array if axis is supplied 

4681 return np.full(out_dims, items, dtype=np.intp) 

4682 

4683 # take care of the masked singleton 

4684 if self is masked: 

4685 return 0 

4686 

4687 return (~m).sum(axis=axis, dtype=np.intp, **kwargs) 

4688 

4689 def ravel(self, order='C'): 

4690 """ 

4691 Returns a 1D version of self, as a view. 

4692 

4693 Parameters 

4694 ---------- 

4695 order : {'C', 'F', 'A', 'K'}, optional 

4696 The elements of `a` are read using this index order. 'C' means to 

4697 index the elements in C-like order, with the last axis index 

4698 changing fastest, back to the first axis index changing slowest. 

4699 'F' means to index the elements in Fortran-like index order, with 

4700 the first index changing fastest, and the last index changing 

4701 slowest. Note that the 'C' and 'F' options take no account of the 

4702 memory layout of the underlying array, and only refer to the order 

4703 of axis indexing. 'A' means to read the elements in Fortran-like 

4704 index order if `m` is Fortran *contiguous* in memory, C-like order 

4705 otherwise. 'K' means to read the elements in the order they occur 

4706 in memory, except for reversing the data when strides are negative. 

4707 By default, 'C' index order is used. 

4708 (Masked arrays currently use 'A' on the data when 'K' is passed.) 

4709 

4710 Returns 

4711 ------- 

4712 MaskedArray 

4713 Output view is of shape ``(self.size,)`` (or 

4714 ``(np.ma.product(self.shape),)``). 

4715 

4716 Examples 

4717 -------- 

4718 >>> import numpy as np 

4719 >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4) 

4720 >>> x 

4721 masked_array( 

4722 data=[[1, --, 3], 

4723 [--, 5, --], 

4724 [7, --, 9]], 

4725 mask=[[False, True, False], 

4726 [ True, False, True], 

4727 [False, True, False]], 

4728 fill_value=999999) 

4729 >>> x.ravel() 

4730 masked_array(data=[1, --, 3, --, 5, --, 7, --, 9], 

4731 mask=[False, True, False, True, False, True, False, True, 

4732 False], 

4733 fill_value=999999) 

4734 

4735 """ 

4736 # The order of _data and _mask could be different (it shouldn't be 

4737 # normally). Passing order `K` or `A` would be incorrect. 

4738 # So we ignore the mask memory order. 

4739 # TODO: We don't actually support K, so use A instead. We could 

4740 # try to guess this correct by sorting strides or deprecate. 

4741 if order in "kKaA": 

4742 order = "F" if self._data.flags.fnc else "C" 

4743 r = ndarray.ravel(self._data, order=order).view(type(self)) 

4744 r._update_from(self) 

4745 if self._mask is not nomask: 

4746 r._mask = ndarray.ravel(self._mask, order=order).reshape(r.shape) 

4747 else: 

4748 r._mask = nomask 

4749 return r 

4750 

4751 def reshape(self, *s, **kwargs): 

4752 """ 

4753 Give a new shape to the array without changing its data. 

4754 

4755 Returns a masked array containing the same data, but with a new shape. 

4756 The result is a view on the original array; if this is not possible, a 

4757 ValueError is raised. 

4758 

4759 Parameters 

4760 ---------- 

4761 shape : int or tuple of ints 

4762 The new shape should be compatible with the original shape. If an 

4763 integer is supplied, then the result will be a 1-D array of that 

4764 length. 

4765 order : {'C', 'F'}, optional 

4766 Determines whether the array data should be viewed as in C 

4767 (row-major) or FORTRAN (column-major) order. 

4768 

4769 Returns 

4770 ------- 

4771 reshaped_array : array 

4772 A new view on the array. 

4773 

4774 See Also 

4775 -------- 

4776 reshape : Equivalent function in the masked array module. 

4777 numpy.ndarray.reshape : Equivalent method on ndarray object. 

4778 numpy.reshape : Equivalent function in the NumPy module. 

4779 

4780 Notes 

4781 ----- 

4782 The reshaping operation cannot guarantee that a copy will not be made, 

4783 to modify the shape in place, use ``a.shape = s`` 

4784 

4785 Examples 

4786 -------- 

4787 >>> import numpy as np 

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

4789 >>> x 

4790 masked_array( 

4791 data=[[--, 2], 

4792 [3, --]], 

4793 mask=[[ True, False], 

4794 [False, True]], 

4795 fill_value=999999) 

4796 >>> x = x.reshape((4,1)) 

4797 >>> x 

4798 masked_array( 

4799 data=[[--], 

4800 [2], 

4801 [3], 

4802 [--]], 

4803 mask=[[ True], 

4804 [False], 

4805 [False], 

4806 [ True]], 

4807 fill_value=999999) 

4808 

4809 """ 

4810 result = self._data.reshape(*s, **kwargs).view(type(self)) 

4811 result._update_from(self) 

4812 mask = self._mask 

4813 if mask is not nomask: 

4814 result._mask = mask.reshape(*s, **kwargs) 

4815 return result 

4816 

4817 def resize(self, newshape, refcheck=True, order=False): 

4818 """ 

4819 .. warning:: 

4820 

4821 This method does nothing, except raise a ValueError exception. A 

4822 masked array does not own its data and therefore cannot safely be 

4823 resized in place. Use the `numpy.ma.resize` function instead. 

4824 

4825 This method is difficult to implement safely and may be deprecated in 

4826 future releases of NumPy. 

4827 

4828 """ 

4829 # Note : the 'order' keyword looks broken, let's just drop it 

4830 errmsg = "A masked array does not own its data "\ 

4831 "and therefore cannot be resized.\n" \ 

4832 "Use the numpy.ma.resize function instead." 

4833 raise ValueError(errmsg) 

4834 

4835 def put(self, indices, values, mode='raise'): 

4836 """ 

4837 Set storage-indexed locations to corresponding values. 

4838 

4839 Sets self._data.flat[n] = values[n] for each n in indices. 

4840 If `values` is shorter than `indices` then it will repeat. 

4841 If `values` has some masked values, the initial mask is updated 

4842 in consequence, else the corresponding values are unmasked. 

4843 

4844 Parameters 

4845 ---------- 

4846 indices : 1-D array_like 

4847 Target indices, interpreted as integers. 

4848 values : array_like 

4849 Values to place in self._data copy at target indices. 

4850 mode : {'raise', 'wrap', 'clip'}, optional 

4851 Specifies how out-of-bounds indices will behave. 

4852 'raise' : raise an error. 

4853 'wrap' : wrap around. 

4854 'clip' : clip to the range. 

4855 

4856 Notes 

4857 ----- 

4858 `values` can be a scalar or length 1 array. 

4859 

4860 Examples 

4861 -------- 

4862 >>> import numpy as np 

4863 >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4) 

4864 >>> x 

4865 masked_array( 

4866 data=[[1, --, 3], 

4867 [--, 5, --], 

4868 [7, --, 9]], 

4869 mask=[[False, True, False], 

4870 [ True, False, True], 

4871 [False, True, False]], 

4872 fill_value=999999) 

4873 >>> x.put([0,4,8],[10,20,30]) 

4874 >>> x 

4875 masked_array( 

4876 data=[[10, --, 3], 

4877 [--, 20, --], 

4878 [7, --, 30]], 

4879 mask=[[False, True, False], 

4880 [ True, False, True], 

4881 [False, True, False]], 

4882 fill_value=999999) 

4883 

4884 >>> x.put(4,999) 

4885 >>> x 

4886 masked_array( 

4887 data=[[10, --, 3], 

4888 [--, 999, --], 

4889 [7, --, 30]], 

4890 mask=[[False, True, False], 

4891 [ True, False, True], 

4892 [False, True, False]], 

4893 fill_value=999999) 

4894 

4895 """ 

4896 # Hard mask: Get rid of the values/indices that fall on masked data 

4897 if self._hardmask and self._mask is not nomask: 

4898 mask = self._mask[indices] 

4899 indices = narray(indices, copy=None) 

4900 values = narray(values, copy=None, subok=True) 

4901 values.resize(indices.shape) 

4902 indices = indices[~mask] 

4903 values = values[~mask] 

4904 

4905 self._data.put(indices, values, mode=mode) 

4906 

4907 # short circuit if neither self nor values are masked 

4908 if self._mask is nomask and getmask(values) is nomask: 

4909 return 

4910 

4911 m = getmaskarray(self) 

4912 

4913 if getmask(values) is nomask: 

4914 m.put(indices, False, mode=mode) 

4915 else: 

4916 m.put(indices, values._mask, mode=mode) 

4917 m = make_mask(m, copy=False, shrink=True) 

4918 self._mask = m 

4919 return 

4920 

4921 def ids(self): 

4922 """ 

4923 Return the addresses of the data and mask areas. 

4924 

4925 Parameters 

4926 ---------- 

4927 None 

4928 

4929 Examples 

4930 -------- 

4931 >>> import numpy as np 

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

4933 >>> x.ids() 

4934 (166670640, 166659832) # may vary 

4935 

4936 If the array has no mask, the address of `nomask` is returned. This address 

4937 is typically not close to the data in memory: 

4938 

4939 >>> x = np.ma.array([1, 2, 3]) 

4940 >>> x.ids() 

4941 (166691080, 3083169284) # may vary 

4942 

4943 """ 

4944 if self._mask is nomask: 

4945 return (self.ctypes.data, id(nomask)) 

4946 return (self.ctypes.data, self._mask.ctypes.data) 

4947 

4948 def iscontiguous(self): 

4949 """ 

4950 Return a boolean indicating whether the data is contiguous. 

4951 

4952 Parameters 

4953 ---------- 

4954 None 

4955 

4956 Examples 

4957 -------- 

4958 >>> import numpy as np 

4959 >>> x = np.ma.array([1, 2, 3]) 

4960 >>> x.iscontiguous() 

4961 True 

4962 

4963 `iscontiguous` returns one of the flags of the masked array: 

4964 

4965 >>> x.flags 

4966 C_CONTIGUOUS : True 

4967 F_CONTIGUOUS : True 

4968 OWNDATA : False 

4969 WRITEABLE : True 

4970 ALIGNED : True 

4971 WRITEBACKIFCOPY : False 

4972 

4973 """ 

4974 return self.flags['CONTIGUOUS'] 

4975 

4976 def all(self, axis=None, out=None, keepdims=np._NoValue): 

4977 """ 

4978 Returns True if all elements evaluate to True. 

4979 

4980 The output array is masked where all the values along the given axis 

4981 are masked: if the output would have been a scalar and that all the 

4982 values are masked, then the output is `masked`. 

4983 

4984 Refer to `numpy.all` for full documentation. 

4985 

4986 See Also 

4987 -------- 

4988 numpy.ndarray.all : corresponding function for ndarrays 

4989 numpy.all : equivalent function 

4990 

4991 Examples 

4992 -------- 

4993 >>> import numpy as np 

4994 >>> np.ma.array([1,2,3]).all() 

4995 True 

4996 >>> a = np.ma.array([1,2,3], mask=True) 

4997 >>> (a.all() is np.ma.masked) 

4998 True 

4999 

5000 """ 

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

5002 

5003 mask = _check_mask_axis(self._mask, axis, **kwargs) 

5004 if out is None: 

5005 d = self.filled(True).all(axis=axis, **kwargs).view(type(self)) 

5006 if d.ndim: 

5007 d.__setmask__(mask) 

5008 elif mask: 

5009 return masked 

5010 return d 

5011 self.filled(True).all(axis=axis, out=out, **kwargs) 

5012 if isinstance(out, MaskedArray): 

5013 if out.ndim or mask: 

5014 out.__setmask__(mask) 

5015 return out 

5016 

5017 def any(self, axis=None, out=None, keepdims=np._NoValue): 

5018 """ 

5019 Returns True if any of the elements of `a` evaluate to True. 

5020 

5021 Masked values are considered as False during computation. 

5022 

5023 Refer to `numpy.any` for full documentation. 

5024 

5025 See Also 

5026 -------- 

5027 numpy.ndarray.any : corresponding function for ndarrays 

5028 numpy.any : equivalent function 

5029 

5030 """ 

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

5032 

5033 mask = _check_mask_axis(self._mask, axis, **kwargs) 

5034 if out is None: 

5035 d = self.filled(False).any(axis=axis, **kwargs).view(type(self)) 

5036 if d.ndim: 

5037 d.__setmask__(mask) 

5038 elif mask: 

5039 d = masked 

5040 return d 

5041 self.filled(False).any(axis=axis, out=out, **kwargs) 

5042 if isinstance(out, MaskedArray): 

5043 if out.ndim or mask: 

5044 out.__setmask__(mask) 

5045 return out 

5046 

5047 def nonzero(self): 

5048 """ 

5049 Return the indices of unmasked elements that are not zero. 

5050 

5051 Returns a tuple of arrays, one for each dimension, containing the 

5052 indices of the non-zero elements in that dimension. The corresponding 

5053 non-zero values can be obtained with:: 

5054 

5055 a[a.nonzero()] 

5056 

5057 To group the indices by element, rather than dimension, use 

5058 instead:: 

5059 

5060 np.transpose(a.nonzero()) 

5061 

5062 The result of this is always a 2d array, with a row for each non-zero 

5063 element. 

5064 

5065 Parameters 

5066 ---------- 

5067 None 

5068 

5069 Returns 

5070 ------- 

5071 tuple_of_arrays : tuple 

5072 Indices of elements that are non-zero. 

5073 

5074 See Also 

5075 -------- 

5076 numpy.nonzero : 

5077 Function operating on ndarrays. 

5078 flatnonzero : 

5079 Return indices that are non-zero in the flattened version of the input 

5080 array. 

5081 numpy.ndarray.nonzero : 

5082 Equivalent ndarray method. 

5083 count_nonzero : 

5084 Counts the number of non-zero elements in the input array. 

5085 

5086 Examples 

5087 -------- 

5088 >>> import numpy as np 

5089 >>> import numpy.ma as ma 

5090 >>> x = ma.array(np.eye(3)) 

5091 >>> x 

5092 masked_array( 

5093 data=[[1., 0., 0.], 

5094 [0., 1., 0.], 

5095 [0., 0., 1.]], 

5096 mask=False, 

5097 fill_value=1e+20) 

5098 >>> x.nonzero() 

5099 (array([0, 1, 2]), array([0, 1, 2])) 

5100 

5101 Masked elements are ignored. 

5102 

5103 >>> x[1, 1] = ma.masked 

5104 >>> x 

5105 masked_array( 

5106 data=[[1.0, 0.0, 0.0], 

5107 [0.0, --, 0.0], 

5108 [0.0, 0.0, 1.0]], 

5109 mask=[[False, False, False], 

5110 [False, True, False], 

5111 [False, False, False]], 

5112 fill_value=1e+20) 

5113 >>> x.nonzero() 

5114 (array([0, 2]), array([0, 2])) 

5115 

5116 Indices can also be grouped by element. 

5117 

5118 >>> np.transpose(x.nonzero()) 

5119 array([[0, 0], 

5120 [2, 2]]) 

5121 

5122 A common use for ``nonzero`` is to find the indices of an array, where 

5123 a condition is True. Given an array `a`, the condition `a` > 3 is a 

5124 boolean array and since False is interpreted as 0, ma.nonzero(a > 3) 

5125 yields the indices of the `a` where the condition is true. 

5126 

5127 >>> a = ma.array([[1,2,3],[4,5,6],[7,8,9]]) 

5128 >>> a > 3 

5129 masked_array( 

5130 data=[[False, False, False], 

5131 [ True, True, True], 

5132 [ True, True, True]], 

5133 mask=False, 

5134 fill_value=True) 

5135 >>> ma.nonzero(a > 3) 

5136 (array([1, 1, 1, 2, 2, 2]), array([0, 1, 2, 0, 1, 2])) 

5137 

5138 The ``nonzero`` method of the condition array can also be called. 

5139 

5140 >>> (a > 3).nonzero() 

5141 (array([1, 1, 1, 2, 2, 2]), array([0, 1, 2, 0, 1, 2])) 

5142 

5143 """ 

5144 return np.asarray(self.filled(0)).nonzero() 

5145 

5146 def trace(self, offset=0, axis1=0, axis2=1, dtype=None, out=None): 

5147 """ 

5148 (this docstring should be overwritten) 

5149 """ 

5150 # !!!: implement out + test! 

5151 m = self._mask 

5152 if m is nomask: 

5153 result = super().trace(offset=offset, axis1=axis1, axis2=axis2, 

5154 out=out) 

5155 return result.astype(dtype) 

5156 else: 

5157 D = self.diagonal(offset=offset, axis1=axis1, axis2=axis2) 

5158 return D.astype(dtype).filled(0).sum(axis=-1, out=out) 

5159 trace.__doc__ = ndarray.trace.__doc__ 

5160 

5161 def dot(self, b, out=None, strict=False): 

5162 """ 

5163 a.dot(b, out=None) 

5164 

5165 Masked dot product of two arrays. Note that `out` and `strict` are 

5166 located in different positions than in `ma.dot`. In order to 

5167 maintain compatibility with the functional version, it is 

5168 recommended that the optional arguments be treated as keyword only. 

5169 At some point that may be mandatory. 

5170 

5171 Parameters 

5172 ---------- 

5173 b : masked_array_like 

5174 Inputs array. 

5175 out : masked_array, optional 

5176 Output argument. This must have the exact kind that would be 

5177 returned if it was not used. In particular, it must have the 

5178 right type, must be C-contiguous, and its dtype must be the 

5179 dtype that would be returned for `ma.dot(a,b)`. This is a 

5180 performance feature. Therefore, if these conditions are not 

5181 met, an exception is raised, instead of attempting to be 

5182 flexible. 

5183 strict : bool, optional 

5184 Whether masked data are propagated (True) or set to 0 (False) 

5185 for the computation. Default is False. Propagating the mask 

5186 means that if a masked value appears in a row or column, the 

5187 whole row or column is considered masked. 

5188 

5189 See Also 

5190 -------- 

5191 numpy.ma.dot : equivalent function 

5192 

5193 """ 

5194 return dot(self, b, out=out, strict=strict) 

5195 

5196 def sum(self, axis=None, dtype=None, out=None, keepdims=np._NoValue): 

5197 """ 

5198 Return the sum of the array elements over the given axis. 

5199 

5200 Masked elements are set to 0 internally. 

5201 

5202 Refer to `numpy.sum` for full documentation. 

5203 

5204 See Also 

5205 -------- 

5206 numpy.ndarray.sum : corresponding function for ndarrays 

5207 numpy.sum : equivalent function 

5208 

5209 Examples 

5210 -------- 

5211 >>> import numpy as np 

5212 >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4) 

5213 >>> x 

5214 masked_array( 

5215 data=[[1, --, 3], 

5216 [--, 5, --], 

5217 [7, --, 9]], 

5218 mask=[[False, True, False], 

5219 [ True, False, True], 

5220 [False, True, False]], 

5221 fill_value=999999) 

5222 >>> x.sum() 

5223 25 

5224 >>> x.sum(axis=1) 

5225 masked_array(data=[4, 5, 16], 

5226 mask=[False, False, False], 

5227 fill_value=999999) 

5228 >>> x.sum(axis=0) 

5229 masked_array(data=[8, 5, 12], 

5230 mask=[False, False, False], 

5231 fill_value=999999) 

5232 >>> print(type(x.sum(axis=0, dtype=np.int64)[0])) 

5233 <class 'numpy.int64'> 

5234 

5235 """ 

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

5237 

5238 _mask = self._mask 

5239 newmask = _check_mask_axis(_mask, axis, **kwargs) 

5240 # No explicit output 

5241 if out is None: 

5242 result = self.filled(0).sum(axis, dtype=dtype, **kwargs) 

5243 rndim = getattr(result, 'ndim', 0) 

5244 if rndim: 

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

5246 result.__setmask__(newmask) 

5247 elif newmask: 

5248 result = masked 

5249 return result 

5250 # Explicit output 

5251 result = self.filled(0).sum(axis, dtype=dtype, out=out, **kwargs) 

5252 if isinstance(out, MaskedArray): 

5253 outmask = getmask(out) 

5254 if outmask is nomask: 

5255 outmask = out._mask = make_mask_none(out.shape) 

5256 outmask.flat = newmask 

5257 return out 

5258 

5259 def cumsum(self, axis=None, dtype=None, out=None): 

5260 """ 

5261 Return the cumulative sum of the array elements over the given axis. 

5262 

5263 Masked values are set to 0 internally during the computation. 

5264 However, their position is saved, and the result will be masked at 

5265 the same locations. 

5266 

5267 Refer to `numpy.cumsum` for full documentation. 

5268 

5269 Notes 

5270 ----- 

5271 The mask is lost if `out` is not a valid :class:`ma.MaskedArray` ! 

5272 

5273 Arithmetic is modular when using integer types, and no error is 

5274 raised on overflow. 

5275 

5276 See Also 

5277 -------- 

5278 numpy.ndarray.cumsum : corresponding function for ndarrays 

5279 numpy.cumsum : equivalent function 

5280 

5281 Examples 

5282 -------- 

5283 >>> import numpy as np 

5284 >>> marr = np.ma.array(np.arange(10), mask=[0,0,0,1,1,1,0,0,0,0]) 

5285 >>> marr.cumsum() 

5286 masked_array(data=[0, 1, 3, --, --, --, 9, 16, 24, 33], 

5287 mask=[False, False, False, True, True, True, False, False, 

5288 False, False], 

5289 fill_value=999999) 

5290 

5291 """ 

5292 result = self.filled(0).cumsum(axis=axis, dtype=dtype, out=out) 

5293 if out is not None: 

5294 if isinstance(out, MaskedArray): 

5295 out.__setmask__(self.mask) 

5296 return out 

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

5298 result.__setmask__(self._mask) 

5299 return result 

5300 

5301 def prod(self, axis=None, dtype=None, out=None, keepdims=np._NoValue): 

5302 """ 

5303 Return the product of the array elements over the given axis. 

5304 

5305 Masked elements are set to 1 internally for computation. 

5306 

5307 Refer to `numpy.prod` for full documentation. 

5308 

5309 Notes 

5310 ----- 

5311 Arithmetic is modular when using integer types, and no error is raised 

5312 on overflow. 

5313 

5314 See Also 

5315 -------- 

5316 numpy.ndarray.prod : corresponding function for ndarrays 

5317 numpy.prod : equivalent function 

5318 """ 

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

5320 

5321 _mask = self._mask 

5322 newmask = _check_mask_axis(_mask, axis, **kwargs) 

5323 # No explicit output 

5324 if out is None: 

5325 result = self.filled(1).prod(axis, dtype=dtype, **kwargs) 

5326 rndim = getattr(result, 'ndim', 0) 

5327 if rndim: 

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

5329 result.__setmask__(newmask) 

5330 elif newmask: 

5331 result = masked 

5332 return result 

5333 # Explicit output 

5334 result = self.filled(1).prod(axis, dtype=dtype, out=out, **kwargs) 

5335 if isinstance(out, MaskedArray): 

5336 outmask = getmask(out) 

5337 if outmask is nomask: 

5338 outmask = out._mask = make_mask_none(out.shape) 

5339 outmask.flat = newmask 

5340 return out 

5341 product = prod 

5342 

5343 def cumprod(self, axis=None, dtype=None, out=None): 

5344 """ 

5345 Return the cumulative product of the array elements over the given axis. 

5346 

5347 Masked values are set to 1 internally during the computation. 

5348 However, their position is saved, and the result will be masked at 

5349 the same locations. 

5350 

5351 Refer to `numpy.cumprod` for full documentation. 

5352 

5353 Notes 

5354 ----- 

5355 The mask is lost if `out` is not a valid MaskedArray ! 

5356 

5357 Arithmetic is modular when using integer types, and no error is 

5358 raised on overflow. 

5359 

5360 See Also 

5361 -------- 

5362 numpy.ndarray.cumprod : corresponding function for ndarrays 

5363 numpy.cumprod : equivalent function 

5364 """ 

5365 result = self.filled(1).cumprod(axis=axis, dtype=dtype, out=out) 

5366 if out is not None: 

5367 if isinstance(out, MaskedArray): 

5368 out.__setmask__(self._mask) 

5369 return out 

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

5371 result.__setmask__(self._mask) 

5372 return result 

5373 

5374 def mean(self, axis=None, dtype=None, out=None, keepdims=np._NoValue): 

5375 """ 

5376 Returns the average of the array elements along given axis. 

5377 

5378 Masked entries are ignored, and result elements which are not 

5379 finite will be masked. 

5380 

5381 Refer to `numpy.mean` for full documentation. 

5382 

5383 See Also 

5384 -------- 

5385 numpy.ndarray.mean : corresponding function for ndarrays 

5386 numpy.mean : Equivalent function 

5387 numpy.ma.average : Weighted average. 

5388 

5389 Examples 

5390 -------- 

5391 >>> import numpy as np 

5392 >>> a = np.ma.array([1,2,3], mask=[False, False, True]) 

5393 >>> a 

5394 masked_array(data=[1, 2, --], 

5395 mask=[False, False, True], 

5396 fill_value=999999) 

5397 >>> a.mean() 

5398 1.5 

5399 

5400 """ 

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

5402 if self._mask is nomask: 

5403 result = super().mean(axis=axis, dtype=dtype, **kwargs)[()] 

5404 else: 

5405 is_float16_result = False 

5406 if dtype is None: 

5407 if issubclass(self.dtype.type, (ntypes.integer, ntypes.bool)): 

5408 dtype = mu.dtype('f8') 

5409 elif issubclass(self.dtype.type, ntypes.float16): 

5410 dtype = mu.dtype('f4') 

5411 is_float16_result = True 

5412 dsum = self.sum(axis=axis, dtype=dtype, **kwargs) 

5413 cnt = self.count(axis=axis, **kwargs) 

5414 if cnt.shape == () and (cnt == 0): 

5415 result = masked 

5416 elif is_float16_result: 

5417 result = self.dtype.type(dsum * 1. / cnt) 

5418 else: 

5419 result = dsum * 1. / cnt 

5420 if out is not None: 

5421 out.flat = result 

5422 if isinstance(out, MaskedArray): 

5423 outmask = getmask(out) 

5424 if outmask is nomask: 

5425 outmask = out._mask = make_mask_none(out.shape) 

5426 outmask.flat = getmask(result) 

5427 return out 

5428 return result 

5429 

5430 def anom(self, axis=None, dtype=None): 

5431 """ 

5432 Compute the anomalies (deviations from the arithmetic mean) 

5433 along the given axis. 

5434 

5435 Returns an array of anomalies, with the same shape as the input and 

5436 where the arithmetic mean is computed along the given axis. 

5437 

5438 Parameters 

5439 ---------- 

5440 axis : int, optional 

5441 Axis over which the anomalies are taken. 

5442 The default is to use the mean of the flattened array as reference. 

5443 dtype : dtype, optional 

5444 Type to use in computing the variance. For arrays of integer type 

5445 the default is float32; for arrays of float types it is the same as 

5446 the array type. 

5447 

5448 See Also 

5449 -------- 

5450 mean : Compute the mean of the array. 

5451 

5452 Examples 

5453 -------- 

5454 >>> import numpy as np 

5455 >>> a = np.ma.array([1,2,3]) 

5456 >>> a.anom() 

5457 masked_array(data=[-1., 0., 1.], 

5458 mask=False, 

5459 fill_value=1e+20) 

5460 

5461 """ 

5462 m = self.mean(axis, dtype) 

5463 if not axis: 

5464 return self - m 

5465 else: 

5466 return self - expand_dims(m, axis) 

5467 

5468 def var(self, axis=None, dtype=None, out=None, ddof=0, 

5469 keepdims=np._NoValue, mean=np._NoValue): 

5470 """ 

5471 Returns the variance of the array elements along given axis. 

5472 

5473 Masked entries are ignored, and result elements which are not 

5474 finite will be masked. 

5475 

5476 Refer to `numpy.var` for full documentation. 

5477 

5478 See Also 

5479 -------- 

5480 numpy.ndarray.var : corresponding function for ndarrays 

5481 numpy.var : Equivalent function 

5482 """ 

5483 kwargs = {} 

5484 

5485 if keepdims is not np._NoValue: 

5486 kwargs['keepdims'] = keepdims 

5487 

5488 # Easy case: nomask, business as usual 

5489 if self._mask is nomask: 

5490 

5491 if mean is not np._NoValue: 

5492 kwargs['mean'] = mean 

5493 

5494 ret = super().var(axis=axis, dtype=dtype, out=out, ddof=ddof, 

5495 **kwargs)[()] 

5496 if out is not None: 

5497 if isinstance(out, MaskedArray): 

5498 out.__setmask__(nomask) 

5499 return out 

5500 return ret 

5501 

5502 # Some data are masked, yay! 

5503 cnt = self.count(axis=axis, **kwargs) - ddof 

5504 

5505 if mean is not np._NoValue: 

5506 danom = self - mean 

5507 else: 

5508 danom = self - self.mean(axis, dtype, keepdims=True) 

5509 

5510 if iscomplexobj(self): 

5511 danom = umath.absolute(danom) ** 2 

5512 else: 

5513 danom *= danom 

5514 dvar = divide(danom.sum(axis, **kwargs), cnt).view(type(self)) 

5515 # Apply the mask if it's not a scalar 

5516 if dvar.ndim: 

5517 dvar._mask = mask_or(self._mask.all(axis, **kwargs), (cnt <= 0)) 

5518 dvar._update_from(self) 

5519 elif getmask(dvar): 

5520 # Make sure that masked is returned when the scalar is masked. 

5521 dvar = masked 

5522 if out is not None: 

5523 if isinstance(out, MaskedArray): 

5524 out.flat = 0 

5525 out.__setmask__(True) 

5526 elif out.dtype.kind in 'biu': 

5527 errmsg = "Masked data information would be lost in one or "\ 

5528 "more location." 

5529 raise MaskError(errmsg) 

5530 else: 

5531 out.flat = np.nan 

5532 return out 

5533 # In case with have an explicit output 

5534 if out is not None: 

5535 # Set the data 

5536 out.flat = dvar 

5537 # Set the mask if needed 

5538 if isinstance(out, MaskedArray): 

5539 out.__setmask__(dvar.mask) 

5540 return out 

5541 return dvar 

5542 var.__doc__ = np.var.__doc__ 

5543 

5544 def std(self, axis=None, dtype=None, out=None, ddof=0, 

5545 keepdims=np._NoValue, mean=np._NoValue): 

5546 """ 

5547 Returns the standard deviation of the array elements along given axis. 

5548 

5549 Masked entries are ignored. 

5550 

5551 Refer to `numpy.std` for full documentation. 

5552 

5553 See Also 

5554 -------- 

5555 numpy.ndarray.std : corresponding function for ndarrays 

5556 numpy.std : Equivalent function 

5557 """ 

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

5559 

5560 dvar = self.var(axis, dtype, out, ddof, **kwargs) 

5561 if dvar is not masked: 

5562 if out is not None: 

5563 np.power(out, 0.5, out=out, casting='unsafe') 

5564 return out 

5565 dvar = sqrt(dvar) 

5566 return dvar 

5567 

5568 def round(self, decimals=0, out=None): 

5569 """ 

5570 Return each element rounded to the given number of decimals. 

5571 

5572 Refer to `numpy.around` for full documentation. 

5573 

5574 See Also 

5575 -------- 

5576 numpy.ndarray.round : corresponding function for ndarrays 

5577 numpy.around : equivalent function 

5578 

5579 Examples 

5580 -------- 

5581 >>> import numpy as np 

5582 >>> import numpy.ma as ma 

5583 >>> x = ma.array([1.35, 2.5, 1.5, 1.75, 2.25, 2.75], 

5584 ... mask=[0, 0, 0, 1, 0, 0]) 

5585 >>> ma.round(x) 

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

5587 mask=[False, False, False, True, False, False], 

5588 fill_value=1e+20) 

5589 

5590 """ 

5591 result = self._data.round(decimals=decimals, out=out).view(type(self)) 

5592 if result.ndim > 0: 

5593 result._mask = self._mask 

5594 result._update_from(self) 

5595 elif self._mask: 

5596 # Return masked when the scalar is masked 

5597 result = masked 

5598 # No explicit output: we're done 

5599 if out is None: 

5600 return result 

5601 if isinstance(out, MaskedArray): 

5602 out.__setmask__(self._mask) 

5603 return out 

5604 

5605 def argsort(self, axis=np._NoValue, kind=None, order=None, endwith=True, 

5606 fill_value=None, *, stable=False): 

5607 """ 

5608 Return an ndarray of indices that sort the array along the 

5609 specified axis. Masked values are filled beforehand to 

5610 `fill_value`. 

5611 

5612 Parameters 

5613 ---------- 

5614 axis : int, optional 

5615 Axis along which to sort. If None, the default, the flattened array 

5616 is used. 

5617 kind : {'quicksort', 'mergesort', 'heapsort', 'stable'}, optional 

5618 The sorting algorithm used. 

5619 order : str or list of str, optional 

5620 When `a` is an array with fields defined, this argument specifies 

5621 which fields to compare first, second, etc. Not all fields need be 

5622 specified. 

5623 endwith : {True, False}, optional 

5624 Whether missing values (if any) should be treated as the largest values 

5625 (True) or the smallest values (False) 

5626 When the array contains unmasked values at the same extremes of the 

5627 datatype, the ordering of these values and the masked values is 

5628 undefined. 

5629 fill_value : scalar or None, optional 

5630 Value used internally for the masked values. 

5631 If ``fill_value`` is not None, it supersedes ``endwith``. 

5632 stable : bool, optional 

5633 Only for compatibility with ``np.argsort``. Ignored. 

5634 

5635 Returns 

5636 ------- 

5637 index_array : ndarray, int 

5638 Array of indices that sort `a` along the specified axis. 

5639 In other words, ``a[index_array]`` yields a sorted `a`. 

5640 

5641 See Also 

5642 -------- 

5643 ma.MaskedArray.sort : Describes sorting algorithms used. 

5644 lexsort : Indirect stable sort with multiple keys. 

5645 numpy.ndarray.sort : Inplace sort. 

5646 

5647 Notes 

5648 ----- 

5649 See `sort` for notes on the different sorting algorithms. 

5650 

5651 Examples 

5652 -------- 

5653 >>> import numpy as np 

5654 >>> a = np.ma.array([3,2,1], mask=[False, False, True]) 

5655 >>> a 

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

5657 mask=[False, False, True], 

5658 fill_value=999999) 

5659 >>> a.argsort() 

5660 array([1, 0, 2]) 

5661 

5662 """ 

5663 if stable: 

5664 raise ValueError( 

5665 "`stable` parameter is not supported for masked arrays." 

5666 ) 

5667 

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

5669 if axis is np._NoValue: 

5670 axis = _deprecate_argsort_axis(self) 

5671 

5672 if fill_value is None: 

5673 if endwith: 

5674 # nan > inf 

5675 if np.issubdtype(self.dtype, np.floating): 

5676 fill_value = np.nan 

5677 else: 

5678 fill_value = minimum_fill_value(self) 

5679 else: 

5680 fill_value = maximum_fill_value(self) 

5681 

5682 filled = self.filled(fill_value) 

5683 return filled.argsort(axis=axis, kind=kind, order=order) 

5684 

5685 def argmin(self, axis=None, fill_value=None, out=None, *, 

5686 keepdims=np._NoValue): 

5687 """ 

5688 Return array of indices to the minimum values along the given axis. 

5689 

5690 Parameters 

5691 ---------- 

5692 axis : {None, integer} 

5693 If None, the index is into the flattened array, otherwise along 

5694 the specified axis 

5695 fill_value : scalar or None, optional 

5696 Value used to fill in the masked values. If None, the output of 

5697 minimum_fill_value(self._data) is used instead. 

5698 out : {None, array}, optional 

5699 Array into which the result can be placed. Its type is preserved 

5700 and it must be of the right shape to hold the output. 

5701 

5702 Returns 

5703 ------- 

5704 ndarray or scalar 

5705 If multi-dimension input, returns a new ndarray of indices to the 

5706 minimum values along the given axis. Otherwise, returns a scalar 

5707 of index to the minimum values along the given axis. 

5708 

5709 Examples 

5710 -------- 

5711 >>> import numpy as np 

5712 >>> x = np.ma.array(np.arange(4), mask=[1,1,0,0]) 

5713 >>> x.shape = (2,2) 

5714 >>> x 

5715 masked_array( 

5716 data=[[--, --], 

5717 [2, 3]], 

5718 mask=[[ True, True], 

5719 [False, False]], 

5720 fill_value=999999) 

5721 >>> x.argmin(axis=0, fill_value=-1) 

5722 array([0, 0]) 

5723 >>> x.argmin(axis=0, fill_value=9) 

5724 array([1, 1]) 

5725 

5726 """ 

5727 if fill_value is None: 

5728 fill_value = minimum_fill_value(self) 

5729 d = self.filled(fill_value).view(ndarray) 

5730 keepdims = False if keepdims is np._NoValue else bool(keepdims) 

5731 return d.argmin(axis, out=out, keepdims=keepdims) 

5732 

5733 def argmax(self, axis=None, fill_value=None, out=None, *, 

5734 keepdims=np._NoValue): 

5735 """ 

5736 Returns array of indices of the maximum values along the given axis. 

5737 Masked values are treated as if they had the value fill_value. 

5738 

5739 Parameters 

5740 ---------- 

5741 axis : {None, integer} 

5742 If None, the index is into the flattened array, otherwise along 

5743 the specified axis 

5744 fill_value : scalar or None, optional 

5745 Value used to fill in the masked values. If None, the output of 

5746 maximum_fill_value(self._data) is used instead. 

5747 out : {None, array}, optional 

5748 Array into which the result can be placed. Its type is preserved 

5749 and it must be of the right shape to hold the output. 

5750 

5751 Returns 

5752 ------- 

5753 index_array : {integer_array} 

5754 

5755 Examples 

5756 -------- 

5757 >>> import numpy as np 

5758 >>> a = np.arange(6).reshape(2,3) 

5759 >>> a.argmax() 

5760 5 

5761 >>> a.argmax(0) 

5762 array([1, 1, 1]) 

5763 >>> a.argmax(1) 

5764 array([2, 2]) 

5765 

5766 """ 

5767 if fill_value is None: 

5768 fill_value = maximum_fill_value(self._data) 

5769 d = self.filled(fill_value).view(ndarray) 

5770 keepdims = False if keepdims is np._NoValue else bool(keepdims) 

5771 return d.argmax(axis, out=out, keepdims=keepdims) 

5772 

5773 def sort(self, axis=-1, kind=None, order=None, endwith=True, 

5774 fill_value=None, *, stable=False): 

5775 """ 

5776 Sort the array, in-place 

5777 

5778 Parameters 

5779 ---------- 

5780 a : array_like 

5781 Array to be sorted. 

5782 axis : int, optional 

5783 Axis along which to sort. If None, the array is flattened before 

5784 sorting. The default is -1, which sorts along the last axis. 

5785 kind : {'quicksort', 'mergesort', 'heapsort', 'stable'}, optional 

5786 The sorting algorithm used. 

5787 order : list, optional 

5788 When `a` is a structured array, this argument specifies which fields 

5789 to compare first, second, and so on. This list does not need to 

5790 include all of the fields. 

5791 endwith : {True, False}, optional 

5792 Whether missing values (if any) should be treated as the largest values 

5793 (True) or the smallest values (False) 

5794 When the array contains unmasked values sorting at the same extremes of the 

5795 datatype, the ordering of these values and the masked values is 

5796 undefined. 

5797 fill_value : scalar or None, optional 

5798 Value used internally for the masked values. 

5799 If ``fill_value`` is not None, it supersedes ``endwith``. 

5800 stable : bool, optional 

5801 Only for compatibility with ``np.sort``. Ignored. 

5802 

5803 See Also 

5804 -------- 

5805 numpy.ndarray.sort : Method to sort an array in-place. 

5806 argsort : Indirect sort. 

5807 lexsort : Indirect stable sort on multiple keys. 

5808 searchsorted : Find elements in a sorted array. 

5809 

5810 Notes 

5811 ----- 

5812 See ``sort`` for notes on the different sorting algorithms. 

5813 

5814 Examples 

5815 -------- 

5816 >>> import numpy as np 

5817 >>> a = np.ma.array([1, 2, 5, 4, 3],mask=[0, 1, 0, 1, 0]) 

5818 >>> # Default 

5819 >>> a.sort() 

5820 >>> a 

5821 masked_array(data=[1, 3, 5, --, --], 

5822 mask=[False, False, False, True, True], 

5823 fill_value=999999) 

5824 

5825 >>> a = np.ma.array([1, 2, 5, 4, 3],mask=[0, 1, 0, 1, 0]) 

5826 >>> # Put missing values in the front 

5827 >>> a.sort(endwith=False) 

5828 >>> a 

5829 masked_array(data=[--, --, 1, 3, 5], 

5830 mask=[ True, True, False, False, False], 

5831 fill_value=999999) 

5832 

5833 >>> a = np.ma.array([1, 2, 5, 4, 3],mask=[0, 1, 0, 1, 0]) 

5834 >>> # fill_value takes over endwith 

5835 >>> a.sort(endwith=False, fill_value=3) 

5836 >>> a 

5837 masked_array(data=[1, --, --, 3, 5], 

5838 mask=[False, True, True, False, False], 

5839 fill_value=999999) 

5840 

5841 """ 

5842 if stable: 

5843 raise ValueError( 

5844 "`stable` parameter is not supported for masked arrays." 

5845 ) 

5846 

5847 if self._mask is nomask: 

5848 ndarray.sort(self, axis=axis, kind=kind, order=order) 

5849 return 

5850 

5851 if self is masked: 

5852 return 

5853 

5854 sidx = self.argsort(axis=axis, kind=kind, order=order, 

5855 fill_value=fill_value, endwith=endwith) 

5856 

5857 self[...] = np.take_along_axis(self, sidx, axis=axis) 

5858 

5859 def min(self, axis=None, out=None, fill_value=None, keepdims=np._NoValue): 

5860 """ 

5861 Return the minimum along a given axis. 

5862 

5863 Parameters 

5864 ---------- 

5865 axis : None or int or tuple of ints, optional 

5866 Axis along which to operate. By default, ``axis`` is None and the 

5867 flattened input is used. 

5868 If this is a tuple of ints, the minimum is selected over multiple 

5869 axes, instead of a single axis or all the axes as before. 

5870 out : array_like, optional 

5871 Alternative output array in which to place the result. Must be of 

5872 the same shape and buffer length as the expected output. 

5873 fill_value : scalar or None, optional 

5874 Value used to fill in the masked values. 

5875 If None, use the output of `minimum_fill_value`. 

5876 keepdims : bool, optional 

5877 If this is set to True, the axes which are reduced are left 

5878 in the result as dimensions with size one. With this option, 

5879 the result will broadcast correctly against the array. 

5880 

5881 Returns 

5882 ------- 

5883 amin : array_like 

5884 New array holding the result. 

5885 If ``out`` was specified, ``out`` is returned. 

5886 

5887 See Also 

5888 -------- 

5889 ma.minimum_fill_value 

5890 Returns the minimum filling value for a given datatype. 

5891 

5892 Examples 

5893 -------- 

5894 >>> import numpy.ma as ma 

5895 >>> x = [[1., -2., 3.], [0.2, -0.7, 0.1]] 

5896 >>> mask = [[1, 1, 0], [0, 0, 1]] 

5897 >>> masked_x = ma.masked_array(x, mask) 

5898 >>> masked_x 

5899 masked_array( 

5900 data=[[--, --, 3.0], 

5901 [0.2, -0.7, --]], 

5902 mask=[[ True, True, False], 

5903 [False, False, True]], 

5904 fill_value=1e+20) 

5905 >>> ma.min(masked_x) 

5906 -0.7 

5907 >>> ma.min(masked_x, axis=-1) 

5908 masked_array(data=[3.0, -0.7], 

5909 mask=[False, False], 

5910 fill_value=1e+20) 

5911 >>> ma.min(masked_x, axis=0, keepdims=True) 

5912 masked_array(data=[[0.2, -0.7, 3.0]], 

5913 mask=[[False, False, False]], 

5914 fill_value=1e+20) 

5915 >>> mask = [[1, 1, 1,], [1, 1, 1]] 

5916 >>> masked_x = ma.masked_array(x, mask) 

5917 >>> ma.min(masked_x, axis=0) 

5918 masked_array(data=[--, --, --], 

5919 mask=[ True, True, True], 

5920 fill_value=1e+20, 

5921 dtype=float64) 

5922 """ 

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

5924 

5925 _mask = self._mask 

5926 newmask = _check_mask_axis(_mask, axis, **kwargs) 

5927 if fill_value is None: 

5928 fill_value = minimum_fill_value(self) 

5929 # No explicit output 

5930 if out is None: 

5931 result = self.filled(fill_value).min( 

5932 axis=axis, out=out, **kwargs).view(type(self)) 

5933 if result.ndim: 

5934 # Set the mask 

5935 result.__setmask__(newmask) 

5936 # Get rid of Infs 

5937 if newmask.ndim: 

5938 np.copyto(result, result.fill_value, where=newmask) 

5939 elif newmask: 

5940 result = masked 

5941 return result 

5942 # Explicit output 

5943 self.filled(fill_value).min(axis=axis, out=out, **kwargs) 

5944 if isinstance(out, MaskedArray): 

5945 outmask = getmask(out) 

5946 if outmask is nomask: 

5947 outmask = out._mask = make_mask_none(out.shape) 

5948 outmask.flat = newmask 

5949 else: 

5950 if out.dtype.kind in 'biu': 

5951 errmsg = "Masked data information would be lost in one or more"\ 

5952 " location." 

5953 raise MaskError(errmsg) 

5954 np.copyto(out, np.nan, where=newmask) 

5955 return out 

5956 

5957 def max(self, axis=None, out=None, fill_value=None, keepdims=np._NoValue): 

5958 """ 

5959 Return the maximum along a given axis. 

5960 

5961 Parameters 

5962 ---------- 

5963 axis : None or int or tuple of ints, optional 

5964 Axis along which to operate. By default, ``axis`` is None and the 

5965 flattened input is used. 

5966 If this is a tuple of ints, the maximum is selected over multiple 

5967 axes, instead of a single axis or all the axes as before. 

5968 out : array_like, optional 

5969 Alternative output array in which to place the result. Must 

5970 be of the same shape and buffer length as the expected output. 

5971 fill_value : scalar or None, optional 

5972 Value used to fill in the masked values. 

5973 If None, use the output of maximum_fill_value(). 

5974 keepdims : bool, optional 

5975 If this is set to True, the axes which are reduced are left 

5976 in the result as dimensions with size one. With this option, 

5977 the result will broadcast correctly against the array. 

5978 

5979 Returns 

5980 ------- 

5981 amax : array_like 

5982 New array holding the result. 

5983 If ``out`` was specified, ``out`` is returned. 

5984 

5985 See Also 

5986 -------- 

5987 ma.maximum_fill_value 

5988 Returns the maximum filling value for a given datatype. 

5989 

5990 Examples 

5991 -------- 

5992 >>> import numpy.ma as ma 

5993 >>> x = [[-1., 2.5], [4., -2.], [3., 0.]] 

5994 >>> mask = [[0, 0], [1, 0], [1, 0]] 

5995 >>> masked_x = ma.masked_array(x, mask) 

5996 >>> masked_x 

5997 masked_array( 

5998 data=[[-1.0, 2.5], 

5999 [--, -2.0], 

6000 [--, 0.0]], 

6001 mask=[[False, False], 

6002 [ True, False], 

6003 [ True, False]], 

6004 fill_value=1e+20) 

6005 >>> ma.max(masked_x) 

6006 2.5 

6007 >>> ma.max(masked_x, axis=0) 

6008 masked_array(data=[-1.0, 2.5], 

6009 mask=[False, False], 

6010 fill_value=1e+20) 

6011 >>> ma.max(masked_x, axis=1, keepdims=True) 

6012 masked_array( 

6013 data=[[2.5], 

6014 [-2.0], 

6015 [0.0]], 

6016 mask=[[False], 

6017 [False], 

6018 [False]], 

6019 fill_value=1e+20) 

6020 >>> mask = [[1, 1], [1, 1], [1, 1]] 

6021 >>> masked_x = ma.masked_array(x, mask) 

6022 >>> ma.max(masked_x, axis=1) 

6023 masked_array(data=[--, --, --], 

6024 mask=[ True, True, True], 

6025 fill_value=1e+20, 

6026 dtype=float64) 

6027 """ 

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

6029 

6030 _mask = self._mask 

6031 newmask = _check_mask_axis(_mask, axis, **kwargs) 

6032 if fill_value is None: 

6033 fill_value = maximum_fill_value(self) 

6034 # No explicit output 

6035 if out is None: 

6036 result = self.filled(fill_value).max( 

6037 axis=axis, out=out, **kwargs).view(type(self)) 

6038 if result.ndim: 

6039 # Set the mask 

6040 result.__setmask__(newmask) 

6041 # Get rid of Infs 

6042 if newmask.ndim: 

6043 np.copyto(result, result.fill_value, where=newmask) 

6044 elif newmask: 

6045 result = masked 

6046 return result 

6047 # Explicit output 

6048 self.filled(fill_value).max(axis=axis, out=out, **kwargs) 

6049 if isinstance(out, MaskedArray): 

6050 outmask = getmask(out) 

6051 if outmask is nomask: 

6052 outmask = out._mask = make_mask_none(out.shape) 

6053 outmask.flat = newmask 

6054 else: 

6055 

6056 if out.dtype.kind in 'biu': 

6057 errmsg = "Masked data information would be lost in one or more"\ 

6058 " location." 

6059 raise MaskError(errmsg) 

6060 np.copyto(out, np.nan, where=newmask) 

6061 return out 

6062 

6063 def ptp(self, axis=None, out=None, fill_value=None, keepdims=False): 

6064 """ 

6065 Return (maximum - minimum) along the given dimension 

6066 (i.e. peak-to-peak value). 

6067 

6068 .. warning:: 

6069 `ptp` preserves the data type of the array. This means the 

6070 return value for an input of signed integers with n bits 

6071 (e.g. `np.int8`, `np.int16`, etc) is also a signed integer 

6072 with n bits. In that case, peak-to-peak values greater than 

6073 ``2**(n-1)-1`` will be returned as negative values. An example 

6074 with a work-around is shown below. 

6075 

6076 Parameters 

6077 ---------- 

6078 axis : {None, int}, optional 

6079 Axis along which to find the peaks. If None (default) the 

6080 flattened array is used. 

6081 out : {None, array_like}, optional 

6082 Alternative output array in which to place the result. It must 

6083 have the same shape and buffer length as the expected output 

6084 but the type will be cast if necessary. 

6085 fill_value : scalar or None, optional 

6086 Value used to fill in the masked values. 

6087 keepdims : bool, optional 

6088 If this is set to True, the axes which are reduced are left 

6089 in the result as dimensions with size one. With this option, 

6090 the result will broadcast correctly against the array. 

6091 

6092 Returns 

6093 ------- 

6094 ptp : ndarray. 

6095 A new array holding the result, unless ``out`` was 

6096 specified, in which case a reference to ``out`` is returned. 

6097 

6098 Examples 

6099 -------- 

6100 >>> import numpy as np 

6101 >>> x = np.ma.MaskedArray([[4, 9, 2, 10], 

6102 ... [6, 9, 7, 12]]) 

6103 

6104 >>> x.ptp(axis=1) 

6105 masked_array(data=[8, 6], 

6106 mask=False, 

6107 fill_value=999999) 

6108 

6109 >>> x.ptp(axis=0) 

6110 masked_array(data=[2, 0, 5, 2], 

6111 mask=False, 

6112 fill_value=999999) 

6113 

6114 >>> x.ptp() 

6115 10 

6116 

6117 This example shows that a negative value can be returned when 

6118 the input is an array of signed integers. 

6119 

6120 >>> y = np.ma.MaskedArray([[1, 127], 

6121 ... [0, 127], 

6122 ... [-1, 127], 

6123 ... [-2, 127]], dtype=np.int8) 

6124 >>> y.ptp(axis=1) 

6125 masked_array(data=[ 126, 127, -128, -127], 

6126 mask=False, 

6127 fill_value=np.int64(999999), 

6128 dtype=int8) 

6129 

6130 A work-around is to use the `view()` method to view the result as 

6131 unsigned integers with the same bit width: 

6132 

6133 >>> y.ptp(axis=1).view(np.uint8) 

6134 masked_array(data=[126, 127, 128, 129], 

6135 mask=False, 

6136 fill_value=np.uint64(999999), 

6137 dtype=uint8) 

6138 """ 

6139 if out is None: 

6140 result = self.max(axis=axis, fill_value=fill_value, 

6141 keepdims=keepdims) 

6142 result -= self.min(axis=axis, fill_value=fill_value, 

6143 keepdims=keepdims) 

6144 return result 

6145 out.flat = self.max(axis=axis, out=out, fill_value=fill_value, 

6146 keepdims=keepdims) 

6147 min_value = self.min(axis=axis, fill_value=fill_value, 

6148 keepdims=keepdims) 

6149 np.subtract(out, min_value, out=out, casting='unsafe') 

6150 return out 

6151 

6152 def partition(self, *args, **kwargs): 

6153 warnings.warn("Warning: 'partition' will ignore the 'mask' " 

6154 f"of the {self.__class__.__name__}.", 

6155 stacklevel=2) 

6156 return super().partition(*args, **kwargs) 

6157 

6158 def argpartition(self, *args, **kwargs): 

6159 warnings.warn("Warning: 'argpartition' will ignore the 'mask' " 

6160 f"of the {self.__class__.__name__}.", 

6161 stacklevel=2) 

6162 return super().argpartition(*args, **kwargs) 

6163 

6164 def take(self, indices, axis=None, out=None, mode='raise'): 

6165 """ 

6166 Take elements from a masked array along an axis. 

6167 

6168 This function does the same thing as "fancy" indexing (indexing arrays 

6169 using arrays) for masked arrays. It can be easier to use if you need 

6170 elements along a given axis. 

6171 

6172 Parameters 

6173 ---------- 

6174 a : masked_array 

6175 The source masked array. 

6176 indices : array_like 

6177 The indices of the values to extract. Also allow scalars for indices. 

6178 axis : int, optional 

6179 The axis over which to select values. By default, the flattened 

6180 input array is used. 

6181 out : MaskedArray, optional 

6182 If provided, the result will be placed in this array. It should 

6183 be of the appropriate shape and dtype. Note that `out` is always 

6184 buffered if `mode='raise'`; use other modes for better performance. 

6185 mode : {'raise', 'wrap', 'clip'}, optional 

6186 Specifies how out-of-bounds indices will behave. 

6187 

6188 * 'raise' -- raise an error (default) 

6189 * 'wrap' -- wrap around 

6190 * 'clip' -- clip to the range 

6191 

6192 'clip' mode means that all indices that are too large are replaced 

6193 by the index that addresses the last element along that axis. Note 

6194 that this disables indexing with negative numbers. 

6195 

6196 Returns 

6197 ------- 

6198 out : MaskedArray 

6199 The returned array has the same type as `a`. 

6200 

6201 See Also 

6202 -------- 

6203 numpy.take : Equivalent function for ndarrays. 

6204 compress : Take elements using a boolean mask. 

6205 take_along_axis : Take elements by matching the array and the index arrays. 

6206 

6207 Notes 

6208 ----- 

6209 This function behaves similarly to `numpy.take`, but it handles masked 

6210 values. The mask is retained in the output array, and masked values 

6211 in the input array remain masked in the output. 

6212 

6213 Examples 

6214 -------- 

6215 >>> import numpy as np 

6216 >>> a = np.ma.array([4, 3, 5, 7, 6, 8], mask=[0, 0, 1, 0, 1, 0]) 

6217 >>> indices = [0, 1, 4] 

6218 >>> np.ma.take(a, indices) 

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

6220 mask=[False, False, True], 

6221 fill_value=999999) 

6222 

6223 When `indices` is not one-dimensional, the output also has these dimensions: 

6224 

6225 >>> np.ma.take(a, [[0, 1], [2, 3]]) 

6226 masked_array(data=[[4, 3], 

6227 [--, 7]], 

6228 mask=[[False, False], 

6229 [ True, False]], 

6230 fill_value=999999) 

6231 """ 

6232 (_data, _mask) = (self._data, self._mask) 

6233 cls = type(self) 

6234 # Make sure the indices are not masked 

6235 maskindices = getmask(indices) 

6236 if maskindices is not nomask: 

6237 indices = indices.filled(0) 

6238 # Get the data, promoting scalars to 0d arrays with [...] so that 

6239 # .view works correctly 

6240 if out is None: 

6241 out = _data.take(indices, axis=axis, mode=mode)[...].view(cls) 

6242 else: 

6243 np.take(_data, indices, axis=axis, mode=mode, out=out) 

6244 # Get the mask 

6245 if isinstance(out, MaskedArray): 

6246 if _mask is nomask: 

6247 outmask = maskindices 

6248 else: 

6249 outmask = _mask.take(indices, axis=axis, mode=mode) 

6250 outmask |= maskindices 

6251 out.__setmask__(outmask) 

6252 # demote 0d arrays back to scalars, for consistency with ndarray.take 

6253 return out[()] 

6254 

6255 # Array methods 

6256 copy = _arraymethod('copy') 

6257 diagonal = _arraymethod('diagonal') 

6258 flatten = _arraymethod('flatten') 

6259 repeat = _arraymethod('repeat') 

6260 squeeze = _arraymethod('squeeze') 

6261 swapaxes = _arraymethod('swapaxes') 

6262 T = property(fget=lambda self: self.transpose()) 

6263 transpose = _arraymethod('transpose') 

6264 

6265 @property 

6266 def mT(self): 

6267 """ 

6268 Return the matrix-transpose of the masked array. 

6269 

6270 The matrix transpose is the transpose of the last two dimensions, even 

6271 if the array is of higher dimension. 

6272 

6273 .. versionadded:: 2.0 

6274 

6275 Returns 

6276 ------- 

6277 result: MaskedArray 

6278 The masked array with the last two dimensions transposed 

6279 

6280 Raises 

6281 ------ 

6282 ValueError 

6283 If the array is of dimension less than 2. 

6284 

6285 See Also 

6286 -------- 

6287 ndarray.mT: 

6288 Equivalent method for arrays 

6289 """ 

6290 

6291 if self.ndim < 2: 

6292 raise ValueError("matrix transpose with ndim < 2 is undefined") 

6293 

6294 if self._mask is nomask: 

6295 return masked_array(data=self._data.mT) 

6296 else: 

6297 return masked_array(data=self.data.mT, mask=self.mask.mT) 

6298 

6299 def tolist(self, fill_value=None): 

6300 """ 

6301 Return the data portion of the masked array as a hierarchical Python list. 

6302 

6303 Data items are converted to the nearest compatible Python type. 

6304 Masked values are converted to `fill_value`. If `fill_value` is None, 

6305 the corresponding entries in the output list will be ``None``. 

6306 

6307 Parameters 

6308 ---------- 

6309 fill_value : scalar, optional 

6310 The value to use for invalid entries. Default is None. 

6311 

6312 Returns 

6313 ------- 

6314 result : list 

6315 The Python list representation of the masked array. 

6316 

6317 Examples 

6318 -------- 

6319 >>> import numpy as np 

6320 >>> x = np.ma.array([[1,2,3], [4,5,6], [7,8,9]], mask=[0] + [1,0]*4) 

6321 >>> x.tolist() 

6322 [[1, None, 3], [None, 5, None], [7, None, 9]] 

6323 >>> x.tolist(-999) 

6324 [[1, -999, 3], [-999, 5, -999], [7, -999, 9]] 

6325 

6326 """ 

6327 _mask = self._mask 

6328 # No mask ? Just return .data.tolist ? 

6329 if _mask is nomask: 

6330 return self._data.tolist() 

6331 # Explicit fill_value: fill the array and get the list 

6332 if fill_value is not None: 

6333 return self.filled(fill_value).tolist() 

6334 # Structured array. 

6335 names = self.dtype.names 

6336 if names: 

6337 result = self._data.astype([(_, object) for _ in names]) 

6338 for n in names: 

6339 result[n][_mask[n]] = None 

6340 return result.tolist() 

6341 # Standard arrays. 

6342 if _mask is nomask: 

6343 return [None] 

6344 # Set temps to save time when dealing w/ marrays. 

6345 inishape = self.shape 

6346 result = np.array(self._data.ravel(), dtype=object) 

6347 result[_mask.ravel()] = None 

6348 result.shape = inishape 

6349 return result.tolist() 

6350 

6351 def tobytes(self, fill_value=None, order='C'): 

6352 """ 

6353 Return the array data as a string containing the raw bytes in the array. 

6354 

6355 The array is filled with a fill value before the string conversion. 

6356 

6357 Parameters 

6358 ---------- 

6359 fill_value : scalar, optional 

6360 Value used to fill in the masked values. Default is None, in which 

6361 case `MaskedArray.fill_value` is used. 

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

6363 Order of the data item in the copy. Default is 'C'. 

6364 

6365 - 'C' -- C order (row major). 

6366 - 'F' -- Fortran order (column major). 

6367 - 'A' -- Any, current order of array. 

6368 - None -- Same as 'A'. 

6369 

6370 See Also 

6371 -------- 

6372 numpy.ndarray.tobytes 

6373 tolist, tofile 

6374 

6375 Notes 

6376 ----- 

6377 As for `ndarray.tobytes`, information about the shape, dtype, etc., 

6378 but also about `fill_value`, will be lost. 

6379 

6380 Examples 

6381 -------- 

6382 >>> import numpy as np 

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

6384 >>> x.tobytes() 

6385 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' 

6386 

6387 """ 

6388 return self.filled(fill_value).tobytes(order=order) 

6389 

6390 def tofile(self, fid, sep="", format="%s"): 

6391 """ 

6392 Save a masked array to a file in binary format. 

6393 

6394 .. warning:: 

6395 This function is not implemented yet. 

6396 

6397 Raises 

6398 ------ 

6399 NotImplementedError 

6400 When `tofile` is called. 

6401 

6402 """ 

6403 raise NotImplementedError("MaskedArray.tofile() not implemented yet.") 

6404 

6405 def toflex(self): 

6406 """ 

6407 Transforms a masked array into a flexible-type array. 

6408 

6409 The flexible type array that is returned will have two fields: 

6410 

6411 * the ``_data`` field stores the ``_data`` part of the array. 

6412 * the ``_mask`` field stores the ``_mask`` part of the array. 

6413 

6414 Parameters 

6415 ---------- 

6416 None 

6417 

6418 Returns 

6419 ------- 

6420 record : ndarray 

6421 A new flexible-type `ndarray` with two fields: the first element 

6422 containing a value, the second element containing the corresponding 

6423 mask boolean. The returned record shape matches self.shape. 

6424 

6425 Notes 

6426 ----- 

6427 A side-effect of transforming a masked array into a flexible `ndarray` is 

6428 that meta information (``fill_value``, ...) will be lost. 

6429 

6430 Examples 

6431 -------- 

6432 >>> import numpy as np 

6433 >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4) 

6434 >>> x 

6435 masked_array( 

6436 data=[[1, --, 3], 

6437 [--, 5, --], 

6438 [7, --, 9]], 

6439 mask=[[False, True, False], 

6440 [ True, False, True], 

6441 [False, True, False]], 

6442 fill_value=999999) 

6443 >>> x.toflex() 

6444 array([[(1, False), (2, True), (3, False)], 

6445 [(4, True), (5, False), (6, True)], 

6446 [(7, False), (8, True), (9, False)]], 

6447 dtype=[('_data', '<i8'), ('_mask', '?')]) 

6448 

6449 """ 

6450 # Get the basic dtype. 

6451 ddtype = self.dtype 

6452 # Make sure we have a mask 

6453 _mask = self._mask 

6454 if _mask is None: 

6455 _mask = make_mask_none(self.shape, ddtype) 

6456 # And get its dtype 

6457 mdtype = self._mask.dtype 

6458 

6459 record = np.ndarray(shape=self.shape, 

6460 dtype=[('_data', ddtype), ('_mask', mdtype)]) 

6461 record['_data'] = self._data 

6462 record['_mask'] = self._mask 

6463 return record 

6464 torecords = toflex 

6465 

6466 # Pickling 

6467 def __getstate__(self): 

6468 """Return the internal state of the masked array, for pickling 

6469 purposes. 

6470 

6471 """ 

6472 cf = 'CF'[self.flags.fnc] 

6473 data_state = super().__reduce__()[2] 

6474 return data_state + (getmaskarray(self).tobytes(cf), self._fill_value) 

6475 

6476 def __setstate__(self, state): 

6477 """Restore the internal state of the masked array, for 

6478 pickling purposes. ``state`` is typically the output of the 

6479 ``__getstate__`` output, and is a 5-tuple: 

6480 

6481 - class name 

6482 - a tuple giving the shape of the data 

6483 - a typecode for the data 

6484 - a binary string for the data 

6485 - a binary string for the mask. 

6486 

6487 """ 

6488 (_, shp, typ, isf, raw, msk, flv) = state 

6489 super().__setstate__((shp, typ, isf, raw)) 

6490 self._mask.__setstate__((shp, make_mask_descr(typ), isf, msk)) 

6491 self.fill_value = flv 

6492 

6493 def __reduce__(self): 

6494 """Return a 3-tuple for pickling a MaskedArray. 

6495 

6496 """ 

6497 return (_mareconstruct, 

6498 (self.__class__, self._baseclass, (0,), 'b',), 

6499 self.__getstate__()) 

6500 

6501 def __deepcopy__(self, memo=None): 

6502 from copy import deepcopy 

6503 copied = MaskedArray.__new__(type(self), self, copy=True) 

6504 if memo is None: 

6505 memo = {} 

6506 memo[id(self)] = copied 

6507 for (k, v) in self.__dict__.items(): 

6508 copied.__dict__[k] = deepcopy(v, memo) 

6509 # as clearly documented for np.copy(), you need to use 

6510 # deepcopy() directly for arrays of object type that may 

6511 # contain compound types--you cannot depend on normal 

6512 # copy semantics to do the right thing here 

6513 if self.dtype.hasobject: 

6514 copied._data[...] = deepcopy(copied._data) 

6515 return copied 

6516 

6517 

6518def _mareconstruct(subtype, baseclass, baseshape, basetype,): 

6519 """Internal function that builds a new MaskedArray from the 

6520 information stored in a pickle. 

6521 

6522 """ 

6523 _data = ndarray.__new__(baseclass, baseshape, basetype) 

6524 _mask = ndarray.__new__(ndarray, baseshape, make_mask_descr(basetype)) 

6525 return subtype.__new__(subtype, _data, mask=_mask, dtype=basetype,) 

6526 

6527 

6528class mvoid(MaskedArray): 

6529 """ 

6530 Fake a 'void' object to use for masked array with structured dtypes. 

6531 """ 

6532 

6533 def __new__(self, data, mask=nomask, dtype=None, fill_value=None, 

6534 hardmask=False, copy=False, subok=True): 

6535 copy = None if not copy else True 

6536 _data = np.array(data, copy=copy, subok=subok, dtype=dtype) 

6537 _data = _data.view(self) 

6538 _data._hardmask = hardmask 

6539 if mask is not nomask: 

6540 if isinstance(mask, np.void): 

6541 _data._mask = mask 

6542 else: 

6543 try: 

6544 # Mask is already a 0D array 

6545 _data._mask = np.void(mask) 

6546 except TypeError: 

6547 # Transform the mask to a void 

6548 mdtype = make_mask_descr(dtype) 

6549 _data._mask = np.array(mask, dtype=mdtype)[()] 

6550 if fill_value is not None: 

6551 _data.fill_value = fill_value 

6552 return _data 

6553 

6554 @property 

6555 def _data(self): 

6556 # Make sure that the _data part is a np.void 

6557 return super()._data[()] 

6558 

6559 def __getitem__(self, indx): 

6560 """ 

6561 Get the index. 

6562 

6563 """ 

6564 m = self._mask 

6565 if isinstance(m[indx], ndarray): 

6566 # Can happen when indx is a multi-dimensional field: 

6567 # A = ma.masked_array(data=[([0,1],)], mask=[([True, 

6568 # False],)], dtype=[("A", ">i2", (2,))]) 

6569 # x = A[0]; y = x["A"]; then y.mask["A"].size==2 

6570 # and we can not say masked/unmasked. 

6571 # The result is no longer mvoid! 

6572 # See also issue #6724. 

6573 return masked_array( 

6574 data=self._data[indx], mask=m[indx], 

6575 fill_value=self._fill_value[indx], 

6576 hard_mask=self._hardmask) 

6577 if m is not nomask and m[indx]: 

6578 return masked 

6579 return self._data[indx] 

6580 

6581 def __setitem__(self, indx, value): 

6582 self._data[indx] = value 

6583 if self._hardmask: 

6584 self._mask[indx] |= getattr(value, "_mask", False) 

6585 else: 

6586 self._mask[indx] = getattr(value, "_mask", False) 

6587 

6588 def __str__(self): 

6589 m = self._mask 

6590 if m is nomask: 

6591 return str(self._data) 

6592 

6593 rdtype = _replace_dtype_fields(self._data.dtype, "O") 

6594 data_arr = super()._data 

6595 res = data_arr.astype(rdtype) 

6596 _recursive_printoption(res, self._mask, masked_print_option) 

6597 return str(res) 

6598 

6599 __repr__ = __str__ 

6600 

6601 def __iter__(self): 

6602 "Defines an iterator for mvoid" 

6603 (_data, _mask) = (self._data, self._mask) 

6604 if _mask is nomask: 

6605 yield from _data 

6606 else: 

6607 for (d, m) in zip(_data, _mask): 

6608 if m: 

6609 yield masked 

6610 else: 

6611 yield d 

6612 

6613 def __len__(self): 

6614 return self._data.__len__() 

6615 

6616 def filled(self, fill_value=None): 

6617 """ 

6618 Return a copy with masked fields filled with a given value. 

6619 

6620 Parameters 

6621 ---------- 

6622 fill_value : array_like, optional 

6623 The value to use for invalid entries. Can be scalar or 

6624 non-scalar. If latter is the case, the filled array should 

6625 be broadcastable over input array. Default is None, in 

6626 which case the `fill_value` attribute is used instead. 

6627 

6628 Returns 

6629 ------- 

6630 filled_void 

6631 A `np.void` object 

6632 

6633 See Also 

6634 -------- 

6635 MaskedArray.filled 

6636 

6637 """ 

6638 return asarray(self).filled(fill_value)[()] 

6639 

6640 def tolist(self): 

6641 """ 

6642 Transforms the mvoid object into a tuple. 

6643 

6644 Masked fields are replaced by None. 

6645 

6646 Returns 

6647 ------- 

6648 returned_tuple 

6649 Tuple of fields 

6650 """ 

6651 _mask = self._mask 

6652 if _mask is nomask: 

6653 return self._data.tolist() 

6654 result = [] 

6655 for (d, m) in zip(self._data, self._mask): 

6656 if m: 

6657 result.append(None) 

6658 else: 

6659 # .item() makes sure we return a standard Python object 

6660 result.append(d.item()) 

6661 return tuple(result) 

6662 

6663 

6664############################################################################## 

6665# Shortcuts # 

6666############################################################################## 

6667 

6668 

6669def isMaskedArray(x): 

6670 """ 

6671 Test whether input is an instance of MaskedArray. 

6672 

6673 This function returns True if `x` is an instance of MaskedArray 

6674 and returns False otherwise. Any object is accepted as input. 

6675 

6676 Parameters 

6677 ---------- 

6678 x : object 

6679 Object to test. 

6680 

6681 Returns 

6682 ------- 

6683 result : bool 

6684 True if `x` is a MaskedArray. 

6685 

6686 See Also 

6687 -------- 

6688 isMA : Alias to isMaskedArray. 

6689 isarray : Alias to isMaskedArray. 

6690 

6691 Examples 

6692 -------- 

6693 >>> import numpy as np 

6694 >>> import numpy.ma as ma 

6695 >>> a = np.eye(3, 3) 

6696 >>> a 

6697 array([[ 1., 0., 0.], 

6698 [ 0., 1., 0.], 

6699 [ 0., 0., 1.]]) 

6700 >>> m = ma.masked_values(a, 0) 

6701 >>> m 

6702 masked_array( 

6703 data=[[1.0, --, --], 

6704 [--, 1.0, --], 

6705 [--, --, 1.0]], 

6706 mask=[[False, True, True], 

6707 [ True, False, True], 

6708 [ True, True, False]], 

6709 fill_value=0.0) 

6710 >>> ma.isMaskedArray(a) 

6711 False 

6712 >>> ma.isMaskedArray(m) 

6713 True 

6714 >>> ma.isMaskedArray([0, 1, 2]) 

6715 False 

6716 

6717 """ 

6718 return isinstance(x, MaskedArray) 

6719 

6720 

6721isarray = isMaskedArray 

6722isMA = isMaskedArray # backward compatibility 

6723 

6724 

6725class MaskedConstant(MaskedArray): 

6726 # the lone np.ma.masked instance 

6727 __singleton = None 

6728 

6729 @classmethod 

6730 def __has_singleton(cls): 

6731 # second case ensures `cls.__singleton` is not just a view on the 

6732 # superclass singleton 

6733 return cls.__singleton is not None and type(cls.__singleton) is cls 

6734 

6735 def __new__(cls): 

6736 if not cls.__has_singleton(): 

6737 # We define the masked singleton as a float for higher precedence. 

6738 # Note that it can be tricky sometimes w/ type comparison 

6739 data = np.array(0.) 

6740 mask = np.array(True) 

6741 

6742 # prevent any modifications 

6743 data.flags.writeable = False 

6744 mask.flags.writeable = False 

6745 

6746 # don't fall back on MaskedArray.__new__(MaskedConstant), since 

6747 # that might confuse it - this way, the construction is entirely 

6748 # within our control 

6749 cls.__singleton = MaskedArray(data, mask=mask).view(cls) 

6750 

6751 return cls.__singleton 

6752 

6753 def __array_finalize__(self, obj): 

6754 if not self.__has_singleton(): 

6755 # this handles the `.view` in __new__, which we want to copy across 

6756 # properties normally 

6757 return super().__array_finalize__(obj) 

6758 elif self is self.__singleton: 

6759 # not clear how this can happen, play it safe 

6760 pass 

6761 else: 

6762 # everywhere else, we want to downcast to MaskedArray, to prevent a 

6763 # duplicate maskedconstant. 

6764 self.__class__ = MaskedArray 

6765 MaskedArray.__array_finalize__(self, obj) 

6766 

6767 def __array_wrap__(self, obj, context=None, return_scalar=False): 

6768 return self.view(MaskedArray).__array_wrap__(obj, context) 

6769 

6770 def __str__(self): 

6771 return str(masked_print_option._display) 

6772 

6773 def __repr__(self): 

6774 if self is MaskedConstant.__singleton: 

6775 return 'masked' 

6776 else: 

6777 # it's a subclass, or something is wrong, make it obvious 

6778 return object.__repr__(self) 

6779 

6780 def __format__(self, format_spec): 

6781 # Replace ndarray.__format__ with the default, which supports no 

6782 # format characters. 

6783 # Supporting format characters is unwise here, because we do not know 

6784 # what type the user was expecting - better to not guess. 

6785 try: 

6786 return object.__format__(self, format_spec) 

6787 except TypeError: 

6788 # 2020-03-23, NumPy 1.19.0 

6789 warnings.warn( 

6790 "Format strings passed to MaskedConstant are ignored," 

6791 " but in future may error or produce different behavior", 

6792 FutureWarning, stacklevel=2 

6793 ) 

6794 return object.__format__(self, "") 

6795 

6796 def __reduce__(self): 

6797 """Override of MaskedArray's __reduce__. 

6798 """ 

6799 return (self.__class__, ()) 

6800 

6801 # inplace operations have no effect. We have to override them to avoid 

6802 # trying to modify the readonly data and mask arrays 

6803 def __iop__(self, other): 

6804 return self 

6805 __iadd__ = \ 

6806 __isub__ = \ 

6807 __imul__ = \ 

6808 __ifloordiv__ = \ 

6809 __itruediv__ = \ 

6810 __ipow__ = \ 

6811 __iop__ 

6812 del __iop__ # don't leave this around 

6813 

6814 def copy(self, *args, **kwargs): 

6815 """ Copy is a no-op on the maskedconstant, as it is a scalar """ 

6816 # maskedconstant is a scalar, so copy doesn't need to copy. There's 

6817 # precedent for this with `np.bool` scalars. 

6818 return self 

6819 

6820 def __copy__(self): 

6821 return self 

6822 

6823 def __deepcopy__(self, memo): 

6824 return self 

6825 

6826 def __setattr__(self, attr, value): 

6827 if not self.__has_singleton(): 

6828 # allow the singleton to be initialized 

6829 return super().__setattr__(attr, value) 

6830 elif self is self.__singleton: 

6831 raise AttributeError( 

6832 f"attributes of {self!r} are not writeable") 

6833 else: 

6834 # duplicate instance - we can end up here from __array_finalize__, 

6835 # where we set the __class__ attribute 

6836 return super().__setattr__(attr, value) 

6837 

6838 

6839masked = masked_singleton = MaskedConstant() 

6840masked_array = MaskedArray 

6841 

6842 

6843def array(data, dtype=None, copy=False, order=None, 

6844 mask=nomask, fill_value=None, keep_mask=True, 

6845 hard_mask=False, shrink=True, subok=True, ndmin=0): 

6846 """ 

6847 Shortcut to MaskedArray. 

6848 

6849 The options are in a different order for convenience and backwards 

6850 compatibility. 

6851 

6852 """ 

6853 return MaskedArray(data, mask=mask, dtype=dtype, copy=copy, 

6854 subok=subok, keep_mask=keep_mask, 

6855 hard_mask=hard_mask, fill_value=fill_value, 

6856 ndmin=ndmin, shrink=shrink, order=order) 

6857 

6858 

6859array.__doc__ = masked_array.__doc__ 

6860 

6861 

6862def is_masked(x): 

6863 """ 

6864 Determine whether input has masked values. 

6865 

6866 Accepts any object as input, but always returns False unless the 

6867 input is a MaskedArray containing masked values. 

6868 

6869 Parameters 

6870 ---------- 

6871 x : array_like 

6872 Array to check for masked values. 

6873 

6874 Returns 

6875 ------- 

6876 result : bool 

6877 True if `x` is a MaskedArray with masked values, False otherwise. 

6878 

6879 Examples 

6880 -------- 

6881 >>> import numpy as np 

6882 >>> import numpy.ma as ma 

6883 >>> x = ma.masked_equal([0, 1, 0, 2, 3], 0) 

6884 >>> x 

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

6886 mask=[ True, False, True, False, False], 

6887 fill_value=0) 

6888 >>> ma.is_masked(x) 

6889 True 

6890 >>> x = ma.masked_equal([0, 1, 0, 2, 3], 42) 

6891 >>> x 

6892 masked_array(data=[0, 1, 0, 2, 3], 

6893 mask=False, 

6894 fill_value=42) 

6895 >>> ma.is_masked(x) 

6896 False 

6897 

6898 Always returns False if `x` isn't a MaskedArray. 

6899 

6900 >>> x = [False, True, False] 

6901 >>> ma.is_masked(x) 

6902 False 

6903 >>> x = 'a string' 

6904 >>> ma.is_masked(x) 

6905 False 

6906 

6907 """ 

6908 m = getmask(x) 

6909 if m is nomask: 

6910 return False 

6911 elif m.any(): 

6912 return True 

6913 return False 

6914 

6915 

6916############################################################################## 

6917# Extrema functions # 

6918############################################################################## 

6919 

6920 

6921class _extrema_operation(_MaskedUFunc): 

6922 """ 

6923 Generic class for maximum/minimum functions. 

6924 

6925 .. note:: 

6926 This is the base class for `_maximum_operation` and 

6927 `_minimum_operation`. 

6928 

6929 """ 

6930 def __init__(self, ufunc, compare, fill_value): 

6931 super().__init__(ufunc) 

6932 self.compare = compare 

6933 self.fill_value_func = fill_value 

6934 

6935 def __call__(self, a, b): 

6936 "Executes the call behavior." 

6937 

6938 return where(self.compare(a, b), a, b) 

6939 

6940 def reduce(self, target, axis=np._NoValue): 

6941 "Reduce target along the given axis." 

6942 target = narray(target, copy=None, subok=True) 

6943 m = getmask(target) 

6944 

6945 if axis is np._NoValue and target.ndim > 1: 

6946 name = self.__name__ 

6947 # 2017-05-06, Numpy 1.13.0: warn on axis default 

6948 warnings.warn( 

6949 f"In the future the default for ma.{name}.reduce will be axis=0, " 

6950 f"not the current None, to match np.{name}.reduce. " 

6951 "Explicitly pass 0 or None to silence this warning.", 

6952 MaskedArrayFutureWarning, stacklevel=2) 

6953 axis = None 

6954 

6955 if axis is not np._NoValue: 

6956 kwargs = {'axis': axis} 

6957 else: 

6958 kwargs = {} 

6959 

6960 if m is nomask: 

6961 t = self.f.reduce(target, **kwargs) 

6962 else: 

6963 target = target.filled( 

6964 self.fill_value_func(target)).view(type(target)) 

6965 t = self.f.reduce(target, **kwargs) 

6966 m = umath.logical_and.reduce(m, **kwargs) 

6967 if hasattr(t, '_mask'): 

6968 t._mask = m 

6969 elif m: 

6970 t = masked 

6971 return t 

6972 

6973 def outer(self, a, b): 

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

6975 ma = getmask(a) 

6976 mb = getmask(b) 

6977 if ma is nomask and mb is nomask: 

6978 m = nomask 

6979 else: 

6980 ma = getmaskarray(a) 

6981 mb = getmaskarray(b) 

6982 m = logical_or.outer(ma, mb) 

6983 result = self.f.outer(filled(a), filled(b)) 

6984 if not isinstance(result, MaskedArray): 

6985 result = result.view(MaskedArray) 

6986 result._mask = m 

6987 return result 

6988 

6989def min(obj, axis=None, out=None, fill_value=None, keepdims=np._NoValue): 

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

6991 

6992 try: 

6993 return obj.min(axis=axis, fill_value=fill_value, out=out, **kwargs) 

6994 except (AttributeError, TypeError): 

6995 # If obj doesn't have a min method, or if the method doesn't accept a 

6996 # fill_value argument 

6997 return asanyarray(obj).min(axis=axis, fill_value=fill_value, 

6998 out=out, **kwargs) 

6999 

7000 

7001min.__doc__ = MaskedArray.min.__doc__ 

7002 

7003def max(obj, axis=None, out=None, fill_value=None, keepdims=np._NoValue): 

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

7005 

7006 try: 

7007 return obj.max(axis=axis, fill_value=fill_value, out=out, **kwargs) 

7008 except (AttributeError, TypeError): 

7009 # If obj doesn't have a max method, or if the method doesn't accept a 

7010 # fill_value argument 

7011 return asanyarray(obj).max(axis=axis, fill_value=fill_value, 

7012 out=out, **kwargs) 

7013 

7014 

7015max.__doc__ = MaskedArray.max.__doc__ 

7016 

7017 

7018def ptp(obj, axis=None, out=None, fill_value=None, keepdims=np._NoValue): 

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

7020 try: 

7021 return obj.ptp(axis, out=out, fill_value=fill_value, **kwargs) 

7022 except (AttributeError, TypeError): 

7023 # If obj doesn't have a ptp method or if the method doesn't accept 

7024 # a fill_value argument 

7025 return asanyarray(obj).ptp(axis=axis, fill_value=fill_value, 

7026 out=out, **kwargs) 

7027 

7028 

7029ptp.__doc__ = MaskedArray.ptp.__doc__ 

7030 

7031 

7032############################################################################## 

7033# Definition of functions from the corresponding methods # 

7034############################################################################## 

7035 

7036 

7037def _frommethod(methodname: str, reversed: bool = False): 

7038 """ 

7039 Define functions from existing MaskedArray methods. 

7040 

7041 Parameters 

7042 ---------- 

7043 methodname : str 

7044 Name of the method to transform. 

7045 reversed : bool, optional 

7046 Whether to reverse the first two arguments of the method. Default is False. 

7047 """ 

7048 method = getattr(MaskedArray, methodname) 

7049 assert callable(method) 

7050 

7051 signature = inspect.signature(method) 

7052 params = list(signature.parameters.values()) 

7053 params[0] = params[0].replace(name="a") # rename 'self' to 'a' 

7054 

7055 if reversed: 

7056 assert len(params) >= 2 

7057 params[0], params[1] = params[1], params[0] 

7058 

7059 def wrapper(a, b, *args, **params): 

7060 return getattr(asanyarray(b), methodname)(a, *args, **params) 

7061 

7062 else: 

7063 def wrapper(a, *args, **params): 

7064 return getattr(asanyarray(a), methodname)(*args, **params) 

7065 

7066 wrapper.__signature__ = signature.replace(parameters=params) 

7067 wrapper.__name__ = wrapper.__qualname__ = methodname 

7068 

7069 # __doc__ is None when using `python -OO ...` 

7070 if method.__doc__ is not None: 

7071 str_signature = f"{methodname}{signature}" 

7072 # TODO: For methods with a docstring "Parameters" section, that do not already 

7073 # mention `a` (see e.g. `MaskedArray.var.__doc__`), it should be inserted there. 

7074 wrapper.__doc__ = f" {str_signature}\n{method.__doc__}" 

7075 

7076 return wrapper 

7077 

7078 

7079all = _frommethod('all') 

7080anomalies = anom = _frommethod('anom') 

7081any = _frommethod('any') 

7082argmax = _frommethod('argmax') 

7083argmin = _frommethod('argmin') 

7084compress = _frommethod('compress', reversed=True) 

7085count = _frommethod('count') 

7086cumprod = _frommethod('cumprod') 

7087cumsum = _frommethod('cumsum') 

7088copy = _frommethod('copy') 

7089diagonal = _frommethod('diagonal') 

7090harden_mask = _frommethod('harden_mask') 

7091ids = _frommethod('ids') 

7092maximum = _extrema_operation(umath.maximum, greater, maximum_fill_value) 

7093mean = _frommethod('mean') 

7094minimum = _extrema_operation(umath.minimum, less, minimum_fill_value) 

7095nonzero = _frommethod('nonzero') 

7096prod = _frommethod('prod') 

7097product = _frommethod('product') 

7098ravel = _frommethod('ravel') 

7099repeat = _frommethod('repeat') 

7100shrink_mask = _frommethod('shrink_mask') 

7101soften_mask = _frommethod('soften_mask') 

7102std = _frommethod('std') 

7103sum = _frommethod('sum') 

7104swapaxes = _frommethod('swapaxes') 

7105#take = _frommethod('take') 

7106trace = _frommethod('trace') 

7107var = _frommethod('var') 

7108 

7109 

7110def take(a, indices, axis=None, out=None, mode='raise'): 

7111 """ 

7112 

7113 """ 

7114 a = masked_array(a) 

7115 return a.take(indices, axis=axis, out=out, mode=mode) 

7116 

7117 

7118def power(a, b, third=None): 

7119 """ 

7120 Returns element-wise base array raised to power from second array. 

7121 

7122 This is the masked array version of `numpy.power`. For details see 

7123 `numpy.power`. 

7124 

7125 See Also 

7126 -------- 

7127 numpy.power 

7128 

7129 Notes 

7130 ----- 

7131 The *out* argument to `numpy.power` is not supported, `third` has to be 

7132 None. 

7133 

7134 Examples 

7135 -------- 

7136 >>> import numpy as np 

7137 >>> import numpy.ma as ma 

7138 >>> x = [11.2, -3.973, 0.801, -1.41] 

7139 >>> mask = [0, 0, 0, 1] 

7140 >>> masked_x = ma.masked_array(x, mask) 

7141 >>> masked_x 

7142 masked_array(data=[11.2, -3.973, 0.801, --], 

7143 mask=[False, False, False, True], 

7144 fill_value=1e+20) 

7145 >>> ma.power(masked_x, 2) 

7146 masked_array(data=[125.43999999999998, 15.784728999999999, 

7147 0.6416010000000001, --], 

7148 mask=[False, False, False, True], 

7149 fill_value=1e+20) 

7150 >>> y = [-0.5, 2, 0, 17] 

7151 >>> masked_y = ma.masked_array(y, mask) 

7152 >>> masked_y 

7153 masked_array(data=[-0.5, 2.0, 0.0, --], 

7154 mask=[False, False, False, True], 

7155 fill_value=1e+20) 

7156 >>> ma.power(masked_x, masked_y) 

7157 masked_array(data=[0.2988071523335984, 15.784728999999999, 1.0, --], 

7158 mask=[False, False, False, True], 

7159 fill_value=1e+20) 

7160 

7161 """ 

7162 if third is not None: 

7163 raise MaskError("3-argument power not supported.") 

7164 # Get the masks 

7165 ma = getmask(a) 

7166 mb = getmask(b) 

7167 m = mask_or(ma, mb) 

7168 # Get the rawdata 

7169 fa = getdata(a) 

7170 fb = getdata(b) 

7171 # Get the type of the result (so that we preserve subclasses) 

7172 if isinstance(a, MaskedArray): 

7173 basetype = type(a) 

7174 else: 

7175 basetype = MaskedArray 

7176 # Get the result and view it as a (subclass of) MaskedArray 

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

7178 result = np.where(m, fa, umath.power(fa, fb)).view(basetype) 

7179 result._update_from(a) 

7180 # Find where we're in trouble w/ NaNs and Infs 

7181 invalid = np.logical_not(np.isfinite(result.view(ndarray))) 

7182 # Add the initial mask 

7183 if m is not nomask: 

7184 if not result.ndim: 

7185 return masked 

7186 result._mask = np.logical_or(m, invalid) 

7187 # Fix the invalid parts 

7188 if invalid.any(): 

7189 if not result.ndim: 

7190 return masked 

7191 elif result._mask is nomask: 

7192 result._mask = invalid 

7193 result._data[invalid] = result.fill_value 

7194 return result 

7195 

7196 

7197def argsort(a, axis=np._NoValue, kind=None, order=None, endwith=True, 

7198 fill_value=None, *, stable=None): 

7199 "Function version of the eponymous method." 

7200 a = np.asanyarray(a) 

7201 

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

7203 if axis is np._NoValue: 

7204 axis = _deprecate_argsort_axis(a) 

7205 

7206 if isinstance(a, MaskedArray): 

7207 return a.argsort(axis=axis, kind=kind, order=order, endwith=endwith, 

7208 fill_value=fill_value, stable=None) 

7209 else: 

7210 return a.argsort(axis=axis, kind=kind, order=order, stable=None) 

7211 

7212 

7213argsort.__doc__ = MaskedArray.argsort.__doc__ 

7214 

7215def sort(a, axis=-1, kind=None, order=None, endwith=True, fill_value=None, *, 

7216 stable=None): 

7217 """ 

7218 Return a sorted copy of the masked array. 

7219 

7220 Equivalent to creating a copy of the array 

7221 and applying the MaskedArray ``sort()`` method. 

7222 

7223 Refer to ``MaskedArray.sort`` for the full documentation 

7224 

7225 See Also 

7226 -------- 

7227 MaskedArray.sort : equivalent method 

7228 

7229 Examples 

7230 -------- 

7231 >>> import numpy as np 

7232 >>> import numpy.ma as ma 

7233 >>> x = [11.2, -3.973, 0.801, -1.41] 

7234 >>> mask = [0, 0, 0, 1] 

7235 >>> masked_x = ma.masked_array(x, mask) 

7236 >>> masked_x 

7237 masked_array(data=[11.2, -3.973, 0.801, --], 

7238 mask=[False, False, False, True], 

7239 fill_value=1e+20) 

7240 >>> ma.sort(masked_x) 

7241 masked_array(data=[-3.973, 0.801, 11.2, --], 

7242 mask=[False, False, False, True], 

7243 fill_value=1e+20) 

7244 """ 

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

7246 if axis is None: 

7247 a = a.flatten() 

7248 axis = 0 

7249 

7250 if isinstance(a, MaskedArray): 

7251 a.sort(axis=axis, kind=kind, order=order, endwith=endwith, 

7252 fill_value=fill_value, stable=stable) 

7253 else: 

7254 a.sort(axis=axis, kind=kind, order=order, stable=stable) 

7255 return a 

7256 

7257 

7258def compressed(x): 

7259 """ 

7260 Return all the non-masked data as a 1-D array. 

7261 

7262 This function is equivalent to calling the "compressed" method of a 

7263 `ma.MaskedArray`, see `ma.MaskedArray.compressed` for details. 

7264 

7265 See Also 

7266 -------- 

7267 ma.MaskedArray.compressed : Equivalent method. 

7268 

7269 Examples 

7270 -------- 

7271 >>> import numpy as np 

7272 

7273 Create an array with negative values masked: 

7274 

7275 >>> import numpy as np 

7276 >>> x = np.array([[1, -1, 0], [2, -1, 3], [7, 4, -1]]) 

7277 >>> masked_x = np.ma.masked_array(x, mask=x < 0) 

7278 >>> masked_x 

7279 masked_array( 

7280 data=[[1, --, 0], 

7281 [2, --, 3], 

7282 [7, 4, --]], 

7283 mask=[[False, True, False], 

7284 [False, True, False], 

7285 [False, False, True]], 

7286 fill_value=999999) 

7287 

7288 Compress the masked array into a 1-D array of non-masked values: 

7289 

7290 >>> np.ma.compressed(masked_x) 

7291 array([1, 0, 2, 3, 7, 4]) 

7292 

7293 """ 

7294 return asanyarray(x).compressed() 

7295 

7296 

7297def concatenate(arrays, axis=0): 

7298 """ 

7299 Concatenate a sequence of arrays along the given axis. 

7300 

7301 Parameters 

7302 ---------- 

7303 arrays : sequence of array_like 

7304 The arrays must have the same shape, except in the dimension 

7305 corresponding to `axis` (the first, by default). 

7306 axis : int, optional 

7307 The axis along which the arrays will be joined. Default is 0. 

7308 

7309 Returns 

7310 ------- 

7311 result : MaskedArray 

7312 The concatenated array with any masked entries preserved. 

7313 

7314 See Also 

7315 -------- 

7316 numpy.concatenate : Equivalent function in the top-level NumPy module. 

7317 

7318 Examples 

7319 -------- 

7320 >>> import numpy as np 

7321 >>> import numpy.ma as ma 

7322 >>> a = ma.arange(3) 

7323 >>> a[1] = ma.masked 

7324 >>> b = ma.arange(2, 5) 

7325 >>> a 

7326 masked_array(data=[0, --, 2], 

7327 mask=[False, True, False], 

7328 fill_value=999999) 

7329 >>> b 

7330 masked_array(data=[2, 3, 4], 

7331 mask=False, 

7332 fill_value=999999) 

7333 >>> ma.concatenate([a, b]) 

7334 masked_array(data=[0, --, 2, 2, 3, 4], 

7335 mask=[False, True, False, False, False, False], 

7336 fill_value=999999) 

7337 

7338 """ 

7339 d = np.concatenate([getdata(a) for a in arrays], axis) 

7340 rcls = get_masked_subclass(*arrays) 

7341 data = d.view(rcls) 

7342 # Check whether one of the arrays has a non-empty mask. 

7343 for x in arrays: 

7344 if getmask(x) is not nomask: 

7345 break 

7346 else: 

7347 return data 

7348 # OK, so we have to concatenate the masks 

7349 dm = np.concatenate([getmaskarray(a) for a in arrays], axis) 

7350 dm = dm.reshape(d.shape) 

7351 

7352 # If we decide to keep a '_shrinkmask' option, we want to check that 

7353 # all of them are True, and then check for dm.any() 

7354 data._mask = _shrink_mask(dm) 

7355 return data 

7356 

7357 

7358def diag(v, k=0): 

7359 """ 

7360 Extract a diagonal or construct a diagonal array. 

7361 

7362 This function is the equivalent of `numpy.diag` that takes masked 

7363 values into account, see `numpy.diag` for details. 

7364 

7365 See Also 

7366 -------- 

7367 numpy.diag : Equivalent function for ndarrays. 

7368 

7369 Examples 

7370 -------- 

7371 >>> import numpy as np 

7372 

7373 Create an array with negative values masked: 

7374 

7375 >>> import numpy as np 

7376 >>> x = np.array([[11.2, -3.973, 18], [0.801, -1.41, 12], [7, 33, -12]]) 

7377 >>> masked_x = np.ma.masked_array(x, mask=x < 0) 

7378 >>> masked_x 

7379 masked_array( 

7380 data=[[11.2, --, 18.0], 

7381 [0.801, --, 12.0], 

7382 [7.0, 33.0, --]], 

7383 mask=[[False, True, False], 

7384 [False, True, False], 

7385 [False, False, True]], 

7386 fill_value=1e+20) 

7387 

7388 Isolate the main diagonal from the masked array: 

7389 

7390 >>> np.ma.diag(masked_x) 

7391 masked_array(data=[11.2, --, --], 

7392 mask=[False, True, True], 

7393 fill_value=1e+20) 

7394 

7395 Isolate the first diagonal below the main diagonal: 

7396 

7397 >>> np.ma.diag(masked_x, -1) 

7398 masked_array(data=[0.801, 33.0], 

7399 mask=[False, False], 

7400 fill_value=1e+20) 

7401 

7402 """ 

7403 output = np.diag(v, k).view(MaskedArray) 

7404 if getmask(v) is not nomask: 

7405 output._mask = np.diag(v._mask, k) 

7406 return output 

7407 

7408 

7409def left_shift(a, n): 

7410 """ 

7411 Shift the bits of an integer to the left. 

7412 

7413 This is the masked array version of `numpy.left_shift`, for details 

7414 see that function. 

7415 

7416 See Also 

7417 -------- 

7418 numpy.left_shift 

7419 

7420 Examples 

7421 -------- 

7422 Shift with a masked array: 

7423 

7424 >>> arr = np.ma.array([10, 20, 30], mask=[False, True, False]) 

7425 >>> np.ma.left_shift(arr, 1) 

7426 masked_array(data=[20, --, 60], 

7427 mask=[False, True, False], 

7428 fill_value=999999) 

7429 

7430 Large shift: 

7431 

7432 >>> np.ma.left_shift(10, 10) 

7433 masked_array(data=10240, 

7434 mask=False, 

7435 fill_value=999999) 

7436 

7437 Shift with a scalar and an array: 

7438 

7439 >>> scalar = 10 

7440 >>> arr = np.ma.array([1, 2, 3], mask=[False, True, False]) 

7441 >>> np.ma.left_shift(scalar, arr) 

7442 masked_array(data=[20, --, 80], 

7443 mask=[False, True, False], 

7444 fill_value=999999) 

7445 

7446 

7447 """ 

7448 m = getmask(a) 

7449 if m is nomask: 

7450 d = umath.left_shift(filled(a), n) 

7451 return masked_array(d) 

7452 else: 

7453 d = umath.left_shift(filled(a, 0), n) 

7454 return masked_array(d, mask=m) 

7455 

7456 

7457def right_shift(a, n): 

7458 """ 

7459 Shift the bits of an integer to the right. 

7460 

7461 This is the masked array version of `numpy.right_shift`, for details 

7462 see that function. 

7463 

7464 See Also 

7465 -------- 

7466 numpy.right_shift 

7467 

7468 Examples 

7469 -------- 

7470 >>> import numpy as np 

7471 >>> import numpy.ma as ma 

7472 >>> x = [11, 3, 8, 1] 

7473 >>> mask = [0, 0, 0, 1] 

7474 >>> masked_x = ma.masked_array(x, mask) 

7475 >>> masked_x 

7476 masked_array(data=[11, 3, 8, --], 

7477 mask=[False, False, False, True], 

7478 fill_value=999999) 

7479 >>> ma.right_shift(masked_x,1) 

7480 masked_array(data=[5, 1, 4, --], 

7481 mask=[False, False, False, True], 

7482 fill_value=999999) 

7483 

7484 """ 

7485 m = getmask(a) 

7486 if m is nomask: 

7487 d = umath.right_shift(filled(a), n) 

7488 return masked_array(d) 

7489 else: 

7490 d = umath.right_shift(filled(a, 0), n) 

7491 return masked_array(d, mask=m) 

7492 

7493 

7494def put(a, indices, values, mode='raise'): 

7495 """ 

7496 Set storage-indexed locations to corresponding values. 

7497 

7498 This function is equivalent to `MaskedArray.put`, see that method 

7499 for details. 

7500 

7501 See Also 

7502 -------- 

7503 MaskedArray.put 

7504 

7505 Examples 

7506 -------- 

7507 Putting values in a masked array: 

7508 

7509 >>> a = np.ma.array([1, 2, 3, 4], mask=[False, True, False, False]) 

7510 >>> np.ma.put(a, [1, 3], [10, 30]) 

7511 >>> a 

7512 masked_array(data=[ 1, 10, 3, 30], 

7513 mask=False, 

7514 fill_value=999999) 

7515 

7516 Using put with a 2D array: 

7517 

7518 >>> b = np.ma.array([[1, 2], [3, 4]], mask=[[False, True], [False, False]]) 

7519 >>> np.ma.put(b, [[0, 1], [1, 0]], [[10, 20], [30, 40]]) 

7520 >>> b 

7521 masked_array( 

7522 data=[[40, 30], 

7523 [ 3, 4]], 

7524 mask=False, 

7525 fill_value=999999) 

7526 

7527 """ 

7528 # We can't use 'frommethod', the order of arguments is different 

7529 try: 

7530 return a.put(indices, values, mode=mode) 

7531 except AttributeError: 

7532 return np.asarray(a).put(indices, values, mode=mode) 

7533 

7534 

7535def putmask(a, mask, values): # , mode='raise'): 

7536 """ 

7537 Changes elements of an array based on conditional and input values. 

7538 

7539 This is the masked array version of `numpy.putmask`, for details see 

7540 `numpy.putmask`. 

7541 

7542 See Also 

7543 -------- 

7544 numpy.putmask 

7545 

7546 Notes 

7547 ----- 

7548 Using a masked array as `values` will **not** transform a `ndarray` into 

7549 a `MaskedArray`. 

7550 

7551 Examples 

7552 -------- 

7553 >>> import numpy as np 

7554 >>> arr = [[1, 2], [3, 4]] 

7555 >>> mask = [[1, 0], [0, 0]] 

7556 >>> x = np.ma.array(arr, mask=mask) 

7557 >>> np.ma.putmask(x, x < 4, 10*x) 

7558 >>> x 

7559 masked_array( 

7560 data=[[--, 20], 

7561 [30, 4]], 

7562 mask=[[ True, False], 

7563 [False, False]], 

7564 fill_value=999999) 

7565 >>> x.data 

7566 array([[10, 20], 

7567 [30, 4]]) 

7568 

7569 """ 

7570 # We can't use 'frommethod', the order of arguments is different 

7571 if not isinstance(a, MaskedArray): 

7572 a = a.view(MaskedArray) 

7573 (valdata, valmask) = (getdata(values), getmask(values)) 

7574 if getmask(a) is nomask: 

7575 if valmask is not nomask: 

7576 a._sharedmask = True 

7577 a._mask = make_mask_none(a.shape, a.dtype) 

7578 np.copyto(a._mask, valmask, where=mask) 

7579 elif a._hardmask: 

7580 if valmask is not nomask: 

7581 m = a._mask.copy() 

7582 np.copyto(m, valmask, where=mask) 

7583 a.mask |= m 

7584 else: 

7585 if valmask is nomask: 

7586 valmask = getmaskarray(values) 

7587 np.copyto(a._mask, valmask, where=mask) 

7588 np.copyto(a._data, valdata, where=mask) 

7589 

7590 

7591def transpose(a, axes=None): 

7592 """ 

7593 Permute the dimensions of an array. 

7594 

7595 This function is exactly equivalent to `numpy.transpose`. 

7596 

7597 See Also 

7598 -------- 

7599 numpy.transpose : Equivalent function in top-level NumPy module. 

7600 

7601 Examples 

7602 -------- 

7603 >>> import numpy as np 

7604 >>> import numpy.ma as ma 

7605 >>> x = ma.arange(4).reshape((2,2)) 

7606 >>> x[1, 1] = ma.masked 

7607 >>> x 

7608 masked_array( 

7609 data=[[0, 1], 

7610 [2, --]], 

7611 mask=[[False, False], 

7612 [False, True]], 

7613 fill_value=999999) 

7614 

7615 >>> ma.transpose(x) 

7616 masked_array( 

7617 data=[[0, 2], 

7618 [1, --]], 

7619 mask=[[False, False], 

7620 [False, True]], 

7621 fill_value=999999) 

7622 """ 

7623 # We can't use 'frommethod', as 'transpose' doesn't take keywords 

7624 try: 

7625 return a.transpose(axes) 

7626 except AttributeError: 

7627 return np.asarray(a).transpose(axes).view(MaskedArray) 

7628 

7629 

7630def reshape(a, new_shape, order='C'): 

7631 """ 

7632 Returns an array containing the same data with a new shape. 

7633 

7634 Refer to `MaskedArray.reshape` for full documentation. 

7635 

7636 See Also 

7637 -------- 

7638 MaskedArray.reshape : equivalent function 

7639 

7640 Examples 

7641 -------- 

7642 Reshaping a 1-D array: 

7643 

7644 >>> a = np.ma.array([1, 2, 3, 4]) 

7645 >>> np.ma.reshape(a, (2, 2)) 

7646 masked_array( 

7647 data=[[1, 2], 

7648 [3, 4]], 

7649 mask=False, 

7650 fill_value=999999) 

7651 

7652 Reshaping a 2-D array: 

7653 

7654 >>> b = np.ma.array([[1, 2], [3, 4]]) 

7655 >>> np.ma.reshape(b, (1, 4)) 

7656 masked_array(data=[[1, 2, 3, 4]], 

7657 mask=False, 

7658 fill_value=999999) 

7659 

7660 Reshaping a 1-D array with a mask: 

7661 

7662 >>> c = np.ma.array([1, 2, 3, 4], mask=[False, True, False, False]) 

7663 >>> np.ma.reshape(c, (2, 2)) 

7664 masked_array( 

7665 data=[[1, --], 

7666 [3, 4]], 

7667 mask=[[False, True], 

7668 [False, False]], 

7669 fill_value=999999) 

7670 

7671 """ 

7672 # We can't use 'frommethod', it whine about some parameters. Dmmit. 

7673 try: 

7674 return a.reshape(new_shape, order=order) 

7675 except AttributeError: 

7676 _tmp = np.asarray(a).reshape(new_shape, order=order) 

7677 return _tmp.view(MaskedArray) 

7678 

7679 

7680def resize(x, new_shape): 

7681 """ 

7682 Return a new masked array with the specified size and shape. 

7683 

7684 This is the masked equivalent of the `numpy.resize` function. The new 

7685 array is filled with repeated copies of `x` (in the order that the 

7686 data are stored in memory). If `x` is masked, the new array will be 

7687 masked, and the new mask will be a repetition of the old one. 

7688 

7689 See Also 

7690 -------- 

7691 numpy.resize : Equivalent function in the top level NumPy module. 

7692 

7693 Examples 

7694 -------- 

7695 >>> import numpy as np 

7696 >>> import numpy.ma as ma 

7697 >>> a = ma.array([[1, 2] ,[3, 4]]) 

7698 >>> a[0, 1] = ma.masked 

7699 >>> a 

7700 masked_array( 

7701 data=[[1, --], 

7702 [3, 4]], 

7703 mask=[[False, True], 

7704 [False, False]], 

7705 fill_value=999999) 

7706 >>> np.resize(a, (3, 3)) 

7707 masked_array( 

7708 data=[[1, 2, 3], 

7709 [4, 1, 2], 

7710 [3, 4, 1]], 

7711 mask=False, 

7712 fill_value=999999) 

7713 >>> ma.resize(a, (3, 3)) 

7714 masked_array( 

7715 data=[[1, --, 3], 

7716 [4, 1, --], 

7717 [3, 4, 1]], 

7718 mask=[[False, True, False], 

7719 [False, False, True], 

7720 [False, False, False]], 

7721 fill_value=999999) 

7722 

7723 A MaskedArray is always returned, regardless of the input type. 

7724 

7725 >>> a = np.array([[1, 2] ,[3, 4]]) 

7726 >>> ma.resize(a, (3, 3)) 

7727 masked_array( 

7728 data=[[1, 2, 3], 

7729 [4, 1, 2], 

7730 [3, 4, 1]], 

7731 mask=False, 

7732 fill_value=999999) 

7733 

7734 """ 

7735 # We can't use _frommethods here, as N.resize is notoriously whiny. 

7736 m = getmask(x) 

7737 if m is not nomask: 

7738 m = np.resize(m, new_shape) 

7739 result = np.resize(x, new_shape).view(get_masked_subclass(x)) 

7740 if result.ndim: 

7741 result._mask = m 

7742 return result 

7743 

7744 

7745def ndim(obj): 

7746 """ 

7747 maskedarray version of the numpy function. 

7748 

7749 """ 

7750 return np.ndim(getdata(obj)) 

7751 

7752 

7753ndim.__doc__ = np.ndim.__doc__ 

7754 

7755 

7756def shape(obj): 

7757 "maskedarray version of the numpy function." 

7758 return np.shape(getdata(obj)) 

7759 

7760 

7761shape.__doc__ = np.shape.__doc__ 

7762 

7763 

7764def size(obj, axis=None): 

7765 "maskedarray version of the numpy function." 

7766 return np.size(getdata(obj), axis) 

7767 

7768 

7769size.__doc__ = np.size.__doc__ 

7770 

7771 

7772def diff(a, /, n=1, axis=-1, prepend=np._NoValue, append=np._NoValue): 

7773 """ 

7774 Calculate the n-th discrete difference along the given axis. 

7775 The first difference is given by ``out[i] = a[i+1] - a[i]`` along 

7776 the given axis, higher differences are calculated by using `diff` 

7777 recursively. 

7778 Preserves the input mask. 

7779 

7780 Parameters 

7781 ---------- 

7782 a : array_like 

7783 Input array 

7784 n : int, optional 

7785 The number of times values are differenced. If zero, the input 

7786 is returned as-is. 

7787 axis : int, optional 

7788 The axis along which the difference is taken, default is the 

7789 last axis. 

7790 prepend, append : array_like, optional 

7791 Values to prepend or append to `a` along axis prior to 

7792 performing the difference. Scalar values are expanded to 

7793 arrays with length 1 in the direction of axis and the shape 

7794 of the input array in along all other axes. Otherwise the 

7795 dimension and shape must match `a` except along axis. 

7796 

7797 Returns 

7798 ------- 

7799 diff : MaskedArray 

7800 The n-th differences. The shape of the output is the same as `a` 

7801 except along `axis` where the dimension is smaller by `n`. The 

7802 type of the output is the same as the type of the difference 

7803 between any two elements of `a`. This is the same as the type of 

7804 `a` in most cases. A notable exception is `datetime64`, which 

7805 results in a `timedelta64` output array. 

7806 

7807 See Also 

7808 -------- 

7809 numpy.diff : Equivalent function in the top-level NumPy module. 

7810 

7811 Notes 

7812 ----- 

7813 Type is preserved for boolean arrays, so the result will contain 

7814 `False` when consecutive elements are the same and `True` when they 

7815 differ. 

7816 

7817 For unsigned integer arrays, the results will also be unsigned. This 

7818 should not be surprising, as the result is consistent with 

7819 calculating the difference directly: 

7820 

7821 >>> u8_arr = np.array([1, 0], dtype=np.uint8) 

7822 >>> np.ma.diff(u8_arr) 

7823 masked_array(data=[255], 

7824 mask=False, 

7825 fill_value=np.uint64(999999), 

7826 dtype=uint8) 

7827 >>> u8_arr[1,...] - u8_arr[0,...] 

7828 np.uint8(255) 

7829 

7830 If this is not desirable, then the array should be cast to a larger 

7831 integer type first: 

7832 

7833 >>> i16_arr = u8_arr.astype(np.int16) 

7834 >>> np.ma.diff(i16_arr) 

7835 masked_array(data=[-1], 

7836 mask=False, 

7837 fill_value=np.int64(999999), 

7838 dtype=int16) 

7839 

7840 Examples 

7841 -------- 

7842 >>> import numpy as np 

7843 >>> a = np.array([1, 2, 3, 4, 7, 0, 2, 3]) 

7844 >>> x = np.ma.masked_where(a < 2, a) 

7845 >>> np.ma.diff(x) 

7846 masked_array(data=[--, 1, 1, 3, --, --, 1], 

7847 mask=[ True, False, False, False, True, True, False], 

7848 fill_value=999999) 

7849 

7850 >>> np.ma.diff(x, n=2) 

7851 masked_array(data=[--, 0, 2, --, --, --], 

7852 mask=[ True, False, False, True, True, True], 

7853 fill_value=999999) 

7854 

7855 >>> a = np.array([[1, 3, 1, 5, 10], [0, 1, 5, 6, 8]]) 

7856 >>> x = np.ma.masked_equal(a, value=1) 

7857 >>> np.ma.diff(x) 

7858 masked_array( 

7859 data=[[--, --, --, 5], 

7860 [--, --, 1, 2]], 

7861 mask=[[ True, True, True, False], 

7862 [ True, True, False, False]], 

7863 fill_value=1) 

7864 

7865 >>> np.ma.diff(x, axis=0) 

7866 masked_array(data=[[--, --, --, 1, -2]], 

7867 mask=[[ True, True, True, False, False]], 

7868 fill_value=1) 

7869 

7870 """ 

7871 if n == 0: 

7872 return a 

7873 if n < 0: 

7874 raise ValueError("order must be non-negative but got " + repr(n)) 

7875 

7876 a = np.ma.asanyarray(a) 

7877 if a.ndim == 0: 

7878 raise ValueError( 

7879 "diff requires input that is at least one dimensional" 

7880 ) 

7881 

7882 combined = [] 

7883 if prepend is not np._NoValue: 

7884 prepend = np.ma.asanyarray(prepend) 

7885 if prepend.ndim == 0: 

7886 shape = list(a.shape) 

7887 shape[axis] = 1 

7888 prepend = np.broadcast_to(prepend, tuple(shape)) 

7889 combined.append(prepend) 

7890 

7891 combined.append(a) 

7892 

7893 if append is not np._NoValue: 

7894 append = np.ma.asanyarray(append) 

7895 if append.ndim == 0: 

7896 shape = list(a.shape) 

7897 shape[axis] = 1 

7898 append = np.broadcast_to(append, tuple(shape)) 

7899 combined.append(append) 

7900 

7901 if len(combined) > 1: 

7902 a = np.ma.concatenate(combined, axis) 

7903 

7904 # GH 22465 np.diff without prepend/append preserves the mask 

7905 return np.diff(a, n, axis) 

7906 

7907 

7908############################################################################## 

7909# Extra functions # 

7910############################################################################## 

7911 

7912 

7913def where(condition, x=_NoValue, y=_NoValue): 

7914 """ 

7915 Return a masked array with elements from `x` or `y`, depending on condition. 

7916 

7917 .. note:: 

7918 When only `condition` is provided, this function is identical to 

7919 `nonzero`. The rest of this documentation covers only the case where 

7920 all three arguments are provided. 

7921 

7922 Parameters 

7923 ---------- 

7924 condition : array_like, bool 

7925 Where True, yield `x`, otherwise yield `y`. 

7926 x, y : array_like, optional 

7927 Values from which to choose. `x`, `y` and `condition` need to be 

7928 broadcastable to some shape. 

7929 

7930 Returns 

7931 ------- 

7932 out : MaskedArray 

7933 An masked array with `masked` elements where the condition is masked, 

7934 elements from `x` where `condition` is True, and elements from `y` 

7935 elsewhere. 

7936 

7937 See Also 

7938 -------- 

7939 numpy.where : Equivalent function in the top-level NumPy module. 

7940 nonzero : The function that is called when x and y are omitted 

7941 

7942 Examples 

7943 -------- 

7944 >>> import numpy as np 

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

7946 ... [1, 0, 1], 

7947 ... [0, 1, 0]]) 

7948 >>> x 

7949 masked_array( 

7950 data=[[0.0, --, 2.0], 

7951 [--, 4.0, --], 

7952 [6.0, --, 8.0]], 

7953 mask=[[False, True, False], 

7954 [ True, False, True], 

7955 [False, True, False]], 

7956 fill_value=1e+20) 

7957 >>> np.ma.where(x > 5, x, -3.1416) 

7958 masked_array( 

7959 data=[[-3.1416, --, -3.1416], 

7960 [--, -3.1416, --], 

7961 [6.0, --, 8.0]], 

7962 mask=[[False, True, False], 

7963 [ True, False, True], 

7964 [False, True, False]], 

7965 fill_value=1e+20) 

7966 

7967 """ 

7968 

7969 # handle the single-argument case 

7970 missing = (x is _NoValue, y is _NoValue).count(True) 

7971 if missing == 1: 

7972 raise ValueError("Must provide both 'x' and 'y' or neither.") 

7973 if missing == 2: 

7974 return nonzero(condition) 

7975 

7976 # we only care if the condition is true - false or masked pick y 

7977 cf = filled(condition, False) 

7978 xd = getdata(x) 

7979 yd = getdata(y) 

7980 

7981 # we need the full arrays here for correct final dimensions 

7982 cm = getmaskarray(condition) 

7983 xm = getmaskarray(x) 

7984 ym = getmaskarray(y) 

7985 

7986 # deal with the fact that masked.dtype == float64, but we don't actually 

7987 # want to treat it as that. 

7988 if x is masked and y is not masked: 

7989 xd = np.zeros((), dtype=yd.dtype) 

7990 xm = np.ones((), dtype=ym.dtype) 

7991 elif y is masked and x is not masked: 

7992 yd = np.zeros((), dtype=xd.dtype) 

7993 ym = np.ones((), dtype=xm.dtype) 

7994 

7995 data = np.where(cf, xd, yd) 

7996 mask = np.where(cf, xm, ym) 

7997 mask = np.where(cm, np.ones((), dtype=mask.dtype), mask) 

7998 

7999 # collapse the mask, for backwards compatibility 

8000 mask = _shrink_mask(mask) 

8001 

8002 return masked_array(data, mask=mask) 

8003 

8004 

8005def choose(indices, choices, out=None, mode='raise'): 

8006 """ 

8007 Use an index array to construct a new array from a list of choices. 

8008 

8009 Given an array of integers and a list of n choice arrays, this method 

8010 will create a new array that merges each of the choice arrays. Where a 

8011 value in `index` is i, the new array will have the value that choices[i] 

8012 contains in the same place. 

8013 

8014 Parameters 

8015 ---------- 

8016 indices : ndarray of ints 

8017 This array must contain integers in ``[0, n-1]``, where n is the 

8018 number of choices. 

8019 choices : sequence of arrays 

8020 Choice arrays. The index array and all of the choices should be 

8021 broadcastable to the same shape. 

8022 out : array, optional 

8023 If provided, the result will be inserted into this array. It should 

8024 be of the appropriate shape and `dtype`. 

8025 mode : {'raise', 'wrap', 'clip'}, optional 

8026 Specifies how out-of-bounds indices will behave. 

8027 

8028 * 'raise' : raise an error 

8029 * 'wrap' : wrap around 

8030 * 'clip' : clip to the range 

8031 

8032 Returns 

8033 ------- 

8034 merged_array : array 

8035 

8036 See Also 

8037 -------- 

8038 choose : equivalent function 

8039 

8040 Examples 

8041 -------- 

8042 >>> import numpy as np 

8043 >>> choice = np.array([[1,1,1], [2,2,2], [3,3,3]]) 

8044 >>> a = np.array([2, 1, 0]) 

8045 >>> np.ma.choose(a, choice) 

8046 masked_array(data=[3, 2, 1], 

8047 mask=False, 

8048 fill_value=999999) 

8049 

8050 """ 

8051 def fmask(x): 

8052 "Returns the filled array, or True if masked." 

8053 if x is masked: 

8054 return True 

8055 return filled(x) 

8056 

8057 def nmask(x): 

8058 "Returns the mask, True if ``masked``, False if ``nomask``." 

8059 if x is masked: 

8060 return True 

8061 return getmask(x) 

8062 # Get the indices. 

8063 c = filled(indices, 0) 

8064 # Get the masks. 

8065 masks = [nmask(x) for x in choices] 

8066 data = [fmask(x) for x in choices] 

8067 # Construct the mask 

8068 outputmask = np.choose(c, masks, mode=mode) 

8069 outputmask = make_mask(mask_or(outputmask, getmask(indices)), 

8070 copy=False, shrink=True) 

8071 # Get the choices. 

8072 d = np.choose(c, data, mode=mode, out=out).view(MaskedArray) 

8073 if out is not None: 

8074 if isinstance(out, MaskedArray): 

8075 out.__setmask__(outputmask) 

8076 return out 

8077 d.__setmask__(outputmask) 

8078 return d 

8079 

8080 

8081def round_(a, decimals=0, out=None): 

8082 """ 

8083 Return a copy of a, rounded to 'decimals' places. 

8084 

8085 When 'decimals' is negative, it specifies the number of positions 

8086 to the left of the decimal point. The real and imaginary parts of 

8087 complex numbers are rounded separately. Nothing is done if the 

8088 array is not of float type and 'decimals' is greater than or equal 

8089 to 0. 

8090 

8091 Parameters 

8092 ---------- 

8093 decimals : int 

8094 Number of decimals to round to. May be negative. 

8095 out : array_like 

8096 Existing array to use for output. 

8097 If not given, returns a default copy of a. 

8098 

8099 Notes 

8100 ----- 

8101 If out is given and does not have a mask attribute, the mask of a 

8102 is lost! 

8103 

8104 Examples 

8105 -------- 

8106 >>> import numpy as np 

8107 >>> import numpy.ma as ma 

8108 >>> x = [11.2, -3.973, 0.801, -1.41] 

8109 >>> mask = [0, 0, 0, 1] 

8110 >>> masked_x = ma.masked_array(x, mask) 

8111 >>> masked_x 

8112 masked_array(data=[11.2, -3.973, 0.801, --], 

8113 mask=[False, False, False, True], 

8114 fill_value=1e+20) 

8115 >>> ma.round_(masked_x) 

8116 masked_array(data=[11.0, -4.0, 1.0, --], 

8117 mask=[False, False, False, True], 

8118 fill_value=1e+20) 

8119 >>> ma.round(masked_x, decimals=1) 

8120 masked_array(data=[11.2, -4.0, 0.8, --], 

8121 mask=[False, False, False, True], 

8122 fill_value=1e+20) 

8123 >>> ma.round_(masked_x, decimals=-1) 

8124 masked_array(data=[10.0, -0.0, 0.0, --], 

8125 mask=[False, False, False, True], 

8126 fill_value=1e+20) 

8127 """ 

8128 if out is None: 

8129 return np.round(a, decimals, out) 

8130 else: 

8131 np.round(getdata(a), decimals, out) 

8132 if hasattr(out, '_mask'): 

8133 out._mask = getmask(a) 

8134 return out 

8135 

8136 

8137round = round_ 

8138 

8139 

8140def _mask_propagate(a, axis): 

8141 """ 

8142 Mask whole 1-d vectors of an array that contain masked values. 

8143 """ 

8144 a = array(a, subok=False) 

8145 m = getmask(a) 

8146 if m is nomask or not m.any() or axis is None: 

8147 return a 

8148 a._mask = a._mask.copy() 

8149 axes = normalize_axis_tuple(axis, a.ndim) 

8150 for ax in axes: 

8151 a._mask |= m.any(axis=ax, keepdims=True) 

8152 return a 

8153 

8154 

8155# Include masked dot here to avoid import problems in getting it from 

8156# extras.py. Note that it is not included in __all__, but rather exported 

8157# from extras in order to avoid backward compatibility problems. 

8158def dot(a, b, strict=False, out=None): 

8159 """ 

8160 Return the dot product of two arrays. 

8161 

8162 This function is the equivalent of `numpy.dot` that takes masked values 

8163 into account. Note that `strict` and `out` are in different position 

8164 than in the method version. In order to maintain compatibility with the 

8165 corresponding method, it is recommended that the optional arguments be 

8166 treated as keyword only. At some point that may be mandatory. 

8167 

8168 Parameters 

8169 ---------- 

8170 a, b : masked_array_like 

8171 Inputs arrays. 

8172 strict : bool, optional 

8173 Whether masked data are propagated (True) or set to 0 (False) for 

8174 the computation. Default is False. Propagating the mask means that 

8175 if a masked value appears in a row or column, the whole row or 

8176 column is considered masked. 

8177 out : masked_array, optional 

8178 Output argument. This must have the exact kind that would be returned 

8179 if it was not used. In particular, it must have the right type, must be 

8180 C-contiguous, and its dtype must be the dtype that would be returned 

8181 for `dot(a,b)`. This is a performance feature. Therefore, if these 

8182 conditions are not met, an exception is raised, instead of attempting 

8183 to be flexible. 

8184 

8185 See Also 

8186 -------- 

8187 numpy.dot : Equivalent function for ndarrays. 

8188 

8189 Examples 

8190 -------- 

8191 >>> import numpy as np 

8192 >>> a = np.ma.array([[1, 2, 3], [4, 5, 6]], mask=[[1, 0, 0], [0, 0, 0]]) 

8193 >>> b = np.ma.array([[1, 2], [3, 4], [5, 6]], mask=[[1, 0], [0, 0], [0, 0]]) 

8194 >>> np.ma.dot(a, b) 

8195 masked_array( 

8196 data=[[21, 26], 

8197 [45, 64]], 

8198 mask=[[False, False], 

8199 [False, False]], 

8200 fill_value=999999) 

8201 >>> np.ma.dot(a, b, strict=True) 

8202 masked_array( 

8203 data=[[--, --], 

8204 [--, 64]], 

8205 mask=[[ True, True], 

8206 [ True, False]], 

8207 fill_value=999999) 

8208 

8209 """ 

8210 if strict is True: 

8211 if np.ndim(a) == 0 or np.ndim(b) == 0: 

8212 pass 

8213 elif b.ndim == 1: 

8214 a = _mask_propagate(a, a.ndim - 1) 

8215 b = _mask_propagate(b, b.ndim - 1) 

8216 else: 

8217 a = _mask_propagate(a, a.ndim - 1) 

8218 b = _mask_propagate(b, b.ndim - 2) 

8219 am = ~getmaskarray(a) 

8220 bm = ~getmaskarray(b) 

8221 

8222 if out is None: 

8223 d = np.dot(filled(a, 0), filled(b, 0)) 

8224 m = ~np.dot(am, bm) 

8225 if np.ndim(d) == 0: 

8226 d = np.asarray(d) 

8227 r = d.view(get_masked_subclass(a, b)) 

8228 r.__setmask__(m) 

8229 return r 

8230 else: 

8231 d = np.dot(filled(a, 0), filled(b, 0), out._data) 

8232 if out.mask.shape != d.shape: 

8233 out._mask = np.empty(d.shape, MaskType) 

8234 np.dot(am, bm, out._mask) 

8235 np.logical_not(out._mask, out._mask) 

8236 return out 

8237 

8238 

8239def inner(a, b): 

8240 """ 

8241 Returns the inner product of a and b for arrays of floating point types. 

8242 

8243 Like the generic NumPy equivalent the product sum is over the last dimension 

8244 of a and b. The first argument is not conjugated. 

8245 

8246 """ 

8247 fa = filled(a, 0) 

8248 fb = filled(b, 0) 

8249 if fa.ndim == 0: 

8250 fa.shape = (1,) 

8251 if fb.ndim == 0: 

8252 fb.shape = (1,) 

8253 return np.inner(fa, fb).view(MaskedArray) 

8254 

8255 

8256inner.__doc__ = doc_note(np.inner.__doc__, 

8257 "Masked values are replaced by 0.") 

8258innerproduct = inner 

8259 

8260 

8261def outer(a, b): 

8262 "maskedarray version of the numpy function." 

8263 fa = filled(a, 0).ravel() 

8264 fb = filled(b, 0).ravel() 

8265 d = np.outer(fa, fb) 

8266 ma = getmask(a) 

8267 mb = getmask(b) 

8268 if ma is nomask and mb is nomask: 

8269 return masked_array(d) 

8270 ma = getmaskarray(a) 

8271 mb = getmaskarray(b) 

8272 m = make_mask(1 - np.outer(1 - ma, 1 - mb), copy=False) 

8273 return masked_array(d, mask=m) 

8274 

8275 

8276outer.__doc__ = doc_note(np.outer.__doc__, 

8277 "Masked values are replaced by 0.") 

8278outerproduct = outer 

8279 

8280 

8281def _convolve_or_correlate(f, a, v, mode, propagate_mask): 

8282 """ 

8283 Helper function for ma.correlate and ma.convolve 

8284 """ 

8285 if propagate_mask: 

8286 # results which are contributed to by either item in any pair being invalid 

8287 mask = ( 

8288 f(getmaskarray(a), np.ones(np.shape(v), dtype=bool), mode=mode) 

8289 | f(np.ones(np.shape(a), dtype=bool), getmaskarray(v), mode=mode) 

8290 ) 

8291 data = f(getdata(a), getdata(v), mode=mode) 

8292 else: 

8293 # results which are not contributed to by any pair of valid elements 

8294 mask = ~f(~getmaskarray(a), ~getmaskarray(v), mode=mode) 

8295 data = f(filled(a, 0), filled(v, 0), mode=mode) 

8296 

8297 return masked_array(data, mask=mask) 

8298 

8299 

8300def correlate(a, v, mode='valid', propagate_mask=True): 

8301 """ 

8302 Cross-correlation of two 1-dimensional sequences. 

8303 

8304 Parameters 

8305 ---------- 

8306 a, v : array_like 

8307 Input sequences. 

8308 mode : {'valid', 'same', 'full'}, optional 

8309 Refer to the `np.convolve` docstring. Note that the default 

8310 is 'valid', unlike `convolve`, which uses 'full'. 

8311 propagate_mask : bool 

8312 If True, then a result element is masked if any masked element contributes 

8313 towards it. If False, then a result element is only masked if no non-masked 

8314 element contribute towards it 

8315 

8316 Returns 

8317 ------- 

8318 out : MaskedArray 

8319 Discrete cross-correlation of `a` and `v`. 

8320 

8321 See Also 

8322 -------- 

8323 numpy.correlate : Equivalent function in the top-level NumPy module. 

8324 

8325 Examples 

8326 -------- 

8327 Basic correlation: 

8328 

8329 >>> a = np.ma.array([1, 2, 3]) 

8330 >>> v = np.ma.array([0, 1, 0]) 

8331 >>> np.ma.correlate(a, v, mode='valid') 

8332 masked_array(data=[2], 

8333 mask=[False], 

8334 fill_value=999999) 

8335 

8336 Correlation with masked elements: 

8337 

8338 >>> a = np.ma.array([1, 2, 3], mask=[False, True, False]) 

8339 >>> v = np.ma.array([0, 1, 0]) 

8340 >>> np.ma.correlate(a, v, mode='valid', propagate_mask=True) 

8341 masked_array(data=[--], 

8342 mask=[ True], 

8343 fill_value=999999, 

8344 dtype=int64) 

8345 

8346 Correlation with different modes and mixed array types: 

8347 

8348 >>> a = np.ma.array([1, 2, 3]) 

8349 >>> v = np.ma.array([0, 1, 0]) 

8350 >>> np.ma.correlate(a, v, mode='full') 

8351 masked_array(data=[0, 1, 2, 3, 0], 

8352 mask=[False, False, False, False, False], 

8353 fill_value=999999) 

8354 

8355 """ 

8356 return _convolve_or_correlate(np.correlate, a, v, mode, propagate_mask) 

8357 

8358 

8359def convolve(a, v, mode='full', propagate_mask=True): 

8360 """ 

8361 Returns the discrete, linear convolution of two one-dimensional sequences. 

8362 

8363 Parameters 

8364 ---------- 

8365 a, v : array_like 

8366 Input sequences. 

8367 mode : {'valid', 'same', 'full'}, optional 

8368 Refer to the `np.convolve` docstring. 

8369 propagate_mask : bool 

8370 If True, then if any masked element is included in the sum for a result 

8371 element, then the result is masked. 

8372 If False, then the result element is only masked if no non-masked cells 

8373 contribute towards it 

8374 

8375 Returns 

8376 ------- 

8377 out : MaskedArray 

8378 Discrete, linear convolution of `a` and `v`. 

8379 

8380 See Also 

8381 -------- 

8382 numpy.convolve : Equivalent function in the top-level NumPy module. 

8383 """ 

8384 return _convolve_or_correlate(np.convolve, a, v, mode, propagate_mask) 

8385 

8386 

8387def allequal(a, b, fill_value=True): 

8388 """ 

8389 Return True if all entries of a and b are equal, using 

8390 fill_value as a truth value where either or both are masked. 

8391 

8392 Parameters 

8393 ---------- 

8394 a, b : array_like 

8395 Input arrays to compare. 

8396 fill_value : bool, optional 

8397 Whether masked values in a or b are considered equal (True) or not 

8398 (False). 

8399 

8400 Returns 

8401 ------- 

8402 y : bool 

8403 Returns True if the two arrays are equal within the given 

8404 tolerance, False otherwise. If either array contains NaN, 

8405 then False is returned. 

8406 

8407 See Also 

8408 -------- 

8409 all, any 

8410 numpy.ma.allclose 

8411 

8412 Examples 

8413 -------- 

8414 >>> import numpy as np 

8415 >>> a = np.ma.array([1e10, 1e-7, 42.0], mask=[0, 0, 1]) 

8416 >>> a 

8417 masked_array(data=[10000000000.0, 1e-07, --], 

8418 mask=[False, False, True], 

8419 fill_value=1e+20) 

8420 

8421 >>> b = np.array([1e10, 1e-7, -42.0]) 

8422 >>> b 

8423 array([ 1.00000000e+10, 1.00000000e-07, -4.20000000e+01]) 

8424 >>> np.ma.allequal(a, b, fill_value=False) 

8425 False 

8426 >>> np.ma.allequal(a, b) 

8427 True 

8428 

8429 """ 

8430 m = mask_or(getmask(a), getmask(b)) 

8431 if m is nomask: 

8432 x = getdata(a) 

8433 y = getdata(b) 

8434 d = umath.equal(x, y) 

8435 return d.all() 

8436 elif fill_value: 

8437 x = getdata(a) 

8438 y = getdata(b) 

8439 d = umath.equal(x, y) 

8440 dm = array(d, mask=m, copy=False) 

8441 return dm.filled(True).all(None) 

8442 else: 

8443 return False 

8444 

8445 

8446def allclose(a, b, masked_equal=True, rtol=1e-5, atol=1e-8): 

8447 """ 

8448 Returns True if two arrays are element-wise equal within a tolerance. 

8449 

8450 This function is equivalent to `allclose` except that masked values 

8451 are treated as equal (default) or unequal, depending on the `masked_equal` 

8452 argument. 

8453 

8454 Parameters 

8455 ---------- 

8456 a, b : array_like 

8457 Input arrays to compare. 

8458 masked_equal : bool, optional 

8459 Whether masked values in `a` and `b` are considered equal (True) or not 

8460 (False). They are considered equal by default. 

8461 rtol : float, optional 

8462 Relative tolerance. The relative difference is equal to ``rtol * b``. 

8463 Default is 1e-5. 

8464 atol : float, optional 

8465 Absolute tolerance. The absolute difference is equal to `atol`. 

8466 Default is 1e-8. 

8467 

8468 Returns 

8469 ------- 

8470 y : bool 

8471 Returns True if the two arrays are equal within the given 

8472 tolerance, False otherwise. If either array contains NaN, then 

8473 False is returned. 

8474 

8475 See Also 

8476 -------- 

8477 all, any 

8478 numpy.allclose : the non-masked `allclose`. 

8479 

8480 Notes 

8481 ----- 

8482 If the following equation is element-wise True, then `allclose` returns 

8483 True:: 

8484 

8485 absolute(`a` - `b`) <= (`atol` + `rtol` * absolute(`b`)) 

8486 

8487 Return True if all elements of `a` and `b` are equal subject to 

8488 given tolerances. 

8489 

8490 Examples 

8491 -------- 

8492 >>> import numpy as np 

8493 >>> a = np.ma.array([1e10, 1e-7, 42.0], mask=[0, 0, 1]) 

8494 >>> a 

8495 masked_array(data=[10000000000.0, 1e-07, --], 

8496 mask=[False, False, True], 

8497 fill_value=1e+20) 

8498 >>> b = np.ma.array([1e10, 1e-8, -42.0], mask=[0, 0, 1]) 

8499 >>> np.ma.allclose(a, b) 

8500 False 

8501 

8502 >>> a = np.ma.array([1e10, 1e-8, 42.0], mask=[0, 0, 1]) 

8503 >>> b = np.ma.array([1.00001e10, 1e-9, -42.0], mask=[0, 0, 1]) 

8504 >>> np.ma.allclose(a, b) 

8505 True 

8506 >>> np.ma.allclose(a, b, masked_equal=False) 

8507 False 

8508 

8509 Masked values are not compared directly. 

8510 

8511 >>> a = np.ma.array([1e10, 1e-8, 42.0], mask=[0, 0, 1]) 

8512 >>> b = np.ma.array([1.00001e10, 1e-9, 42.0], mask=[0, 0, 1]) 

8513 >>> np.ma.allclose(a, b) 

8514 True 

8515 >>> np.ma.allclose(a, b, masked_equal=False) 

8516 False 

8517 

8518 """ 

8519 x = masked_array(a, copy=False) 

8520 y = masked_array(b, copy=False) 

8521 

8522 # make sure y is an inexact type to avoid abs(MIN_INT); will cause 

8523 # casting of x later. 

8524 # NOTE: We explicitly allow timedelta, which used to work. This could 

8525 # possibly be deprecated. See also gh-18286. 

8526 # timedelta works if `atol` is an integer or also a timedelta. 

8527 # Although, the default tolerances are unlikely to be useful 

8528 if y.dtype.kind != "m": 

8529 dtype = np.result_type(y, 1.) 

8530 if y.dtype != dtype: 

8531 y = masked_array(y, dtype=dtype, copy=False) 

8532 

8533 m = mask_or(getmask(x), getmask(y)) 

8534 xinf = np.isinf(masked_array(x, copy=False, mask=m)).filled(False) 

8535 # If we have some infs, they should fall at the same place. 

8536 if not np.all(xinf == filled(np.isinf(y), False)): 

8537 return False 

8538 # No infs at all 

8539 if not np.any(xinf): 

8540 d = filled(less_equal(absolute(x - y), atol + rtol * absolute(y)), 

8541 masked_equal) 

8542 return np.all(d) 

8543 

8544 if not np.all(filled(x[xinf] == y[xinf], masked_equal)): 

8545 return False 

8546 x = x[~xinf] 

8547 y = y[~xinf] 

8548 

8549 d = filled(less_equal(absolute(x - y), atol + rtol * absolute(y)), 

8550 masked_equal) 

8551 

8552 return np.all(d) 

8553 

8554 

8555def asarray(a, dtype=None, order=None): 

8556 """ 

8557 Convert the input to a masked array of the given data-type. 

8558 

8559 No copy is performed if the input is already an `ndarray`. If `a` is 

8560 a subclass of `MaskedArray`, a base class `MaskedArray` is returned. 

8561 

8562 Parameters 

8563 ---------- 

8564 a : array_like 

8565 Input data, in any form that can be converted to a masked array. This 

8566 includes lists, lists of tuples, tuples, tuples of tuples, tuples 

8567 of lists, ndarrays and masked arrays. 

8568 dtype : dtype, optional 

8569 By default, the data-type is inferred from the input data. 

8570 order : {'C', 'F'}, optional 

8571 Whether to use row-major ('C') or column-major ('FORTRAN') memory 

8572 representation. Default is 'C'. 

8573 

8574 Returns 

8575 ------- 

8576 out : MaskedArray 

8577 Masked array interpretation of `a`. 

8578 

8579 See Also 

8580 -------- 

8581 asanyarray : Similar to `asarray`, but conserves subclasses. 

8582 

8583 Examples 

8584 -------- 

8585 >>> import numpy as np 

8586 >>> x = np.arange(10.).reshape(2, 5) 

8587 >>> x 

8588 array([[0., 1., 2., 3., 4.], 

8589 [5., 6., 7., 8., 9.]]) 

8590 >>> np.ma.asarray(x) 

8591 masked_array( 

8592 data=[[0., 1., 2., 3., 4.], 

8593 [5., 6., 7., 8., 9.]], 

8594 mask=False, 

8595 fill_value=1e+20) 

8596 >>> type(np.ma.asarray(x)) 

8597 <class 'numpy.ma.MaskedArray'> 

8598 

8599 """ 

8600 order = order or 'C' 

8601 return masked_array(a, dtype=dtype, copy=False, keep_mask=True, 

8602 subok=False, order=order) 

8603 

8604 

8605def asanyarray(a, dtype=None, order=None): 

8606 """ 

8607 Convert the input to a masked array, conserving subclasses. 

8608 

8609 If `a` is a subclass of `MaskedArray`, its class is conserved. 

8610 No copy is performed if the input is already an `ndarray`. 

8611 

8612 Parameters 

8613 ---------- 

8614 a : array_like 

8615 Input data, in any form that can be converted to an array. 

8616 dtype : dtype, optional 

8617 By default, the data-type is inferred from the input data. 

8618 order : {'C', 'F', 'A', 'K'}, optional 

8619 Memory layout. 'A' and 'K' depend on the order of input array ``a``. 

8620 'C' row-major (C-style), 

8621 'F' column-major (Fortran-style) memory representation. 

8622 'A' (any) means 'F' if ``a`` is Fortran contiguous, 'C' otherwise 

8623 'K' (keep) preserve input order 

8624 Defaults to 'K'. 

8625 

8626 Returns 

8627 ------- 

8628 out : MaskedArray 

8629 MaskedArray interpretation of `a`. 

8630 

8631 See Also 

8632 -------- 

8633 asarray : Similar to `asanyarray`, but does not conserve subclass. 

8634 

8635 Examples 

8636 -------- 

8637 >>> import numpy as np 

8638 >>> x = np.arange(10.).reshape(2, 5) 

8639 >>> x 

8640 array([[0., 1., 2., 3., 4.], 

8641 [5., 6., 7., 8., 9.]]) 

8642 >>> np.ma.asanyarray(x) 

8643 masked_array( 

8644 data=[[0., 1., 2., 3., 4.], 

8645 [5., 6., 7., 8., 9.]], 

8646 mask=False, 

8647 fill_value=1e+20) 

8648 >>> type(np.ma.asanyarray(x)) 

8649 <class 'numpy.ma.MaskedArray'> 

8650 

8651 """ 

8652 # workaround for #8666, to preserve identity. Ideally the bottom line 

8653 # would handle this for us. 

8654 if ( 

8655 isinstance(a, MaskedArray) 

8656 and (dtype is None or dtype == a.dtype) 

8657 and ( 

8658 order in {None, 'A', 'K'} 

8659 or order == 'C' and a.flags.carray 

8660 or order == 'F' and a.flags.f_contiguous 

8661 ) 

8662 ): 

8663 return a 

8664 return masked_array(a, dtype=dtype, copy=False, keep_mask=True, subok=True, 

8665 order=order) 

8666 

8667 

8668############################################################################## 

8669# Pickling # 

8670############################################################################## 

8671 

8672 

8673def fromfile(file, dtype=float, count=-1, sep=''): 

8674 raise NotImplementedError( 

8675 "fromfile() not yet implemented for a MaskedArray.") 

8676 

8677 

8678def fromflex(fxarray): 

8679 """ 

8680 Build a masked array from a suitable flexible-type array. 

8681 

8682 The input array has to have a data-type with ``_data`` and ``_mask`` 

8683 fields. This type of array is output by `MaskedArray.toflex`. 

8684 

8685 Parameters 

8686 ---------- 

8687 fxarray : ndarray 

8688 The structured input array, containing ``_data`` and ``_mask`` 

8689 fields. If present, other fields are discarded. 

8690 

8691 Returns 

8692 ------- 

8693 result : MaskedArray 

8694 The constructed masked array. 

8695 

8696 See Also 

8697 -------- 

8698 MaskedArray.toflex : Build a flexible-type array from a masked array. 

8699 

8700 Examples 

8701 -------- 

8702 >>> import numpy as np 

8703 >>> x = np.ma.array(np.arange(9).reshape(3, 3), mask=[0] + [1, 0] * 4) 

8704 >>> rec = x.toflex() 

8705 >>> rec 

8706 array([[(0, False), (1, True), (2, False)], 

8707 [(3, True), (4, False), (5, True)], 

8708 [(6, False), (7, True), (8, False)]], 

8709 dtype=[('_data', '<i8'), ('_mask', '?')]) 

8710 >>> x2 = np.ma.fromflex(rec) 

8711 >>> x2 

8712 masked_array( 

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

8714 [--, 4, --], 

8715 [6, --, 8]], 

8716 mask=[[False, True, False], 

8717 [ True, False, True], 

8718 [False, True, False]], 

8719 fill_value=999999) 

8720 

8721 Extra fields can be present in the structured array but are discarded: 

8722 

8723 >>> dt = [('_data', '<i4'), ('_mask', '|b1'), ('field3', '<f4')] 

8724 >>> rec2 = np.zeros((2, 2), dtype=dt) 

8725 >>> rec2 

8726 array([[(0, False, 0.), (0, False, 0.)], 

8727 [(0, False, 0.), (0, False, 0.)]], 

8728 dtype=[('_data', '<i4'), ('_mask', '?'), ('field3', '<f4')]) 

8729 >>> y = np.ma.fromflex(rec2) 

8730 >>> y 

8731 masked_array( 

8732 data=[[0, 0], 

8733 [0, 0]], 

8734 mask=[[False, False], 

8735 [False, False]], 

8736 fill_value=np.int64(999999), 

8737 dtype=int32) 

8738 

8739 """ 

8740 return masked_array(fxarray['_data'], mask=fxarray['_mask']) 

8741 

8742 

8743def _convert2ma(funcname: str, np_ret: str, np_ma_ret: str, 

8744 params: dict[str, str] | None = None): 

8745 """Convert function from numpy to numpy.ma.""" 

8746 func = getattr(np, funcname) 

8747 params = params or {} 

8748 

8749 @functools.wraps(func, assigned=set(functools.WRAPPER_ASSIGNMENTS) - {"__module__"}) 

8750 def wrapper(*args, **kwargs): 

8751 common_params = kwargs.keys() & params.keys() 

8752 extras = params | {p: kwargs.pop(p) for p in common_params} 

8753 

8754 result = func.__call__(*args, **kwargs).view(MaskedArray) 

8755 

8756 if "fill_value" in common_params: 

8757 result.fill_value = extras["fill_value"] 

8758 if "hardmask" in common_params: 

8759 result._hardmask = bool(extras["hardmask"]) 

8760 

8761 return result 

8762 

8763 # workaround for a doctest bug in Python 3.11 that incorrectly assumes `__code__` 

8764 # exists on wrapped functions 

8765 del wrapper.__wrapped__ 

8766 

8767 # `arange`, `empty`, `empty_like`, `frombuffer`, and `zeros` have no signature 

8768 try: 

8769 signature = inspect.signature(func) 

8770 except ValueError: 

8771 signature = inspect.Signature([ 

8772 inspect.Parameter('args', inspect.Parameter.VAR_POSITIONAL), 

8773 inspect.Parameter('kwargs', inspect.Parameter.VAR_KEYWORD), 

8774 ]) 

8775 

8776 if params: 

8777 sig_params = list(signature.parameters.values()) 

8778 

8779 # pop `**kwargs` if present 

8780 sig_kwargs = None 

8781 if sig_params[-1].kind is inspect.Parameter.VAR_KEYWORD: 

8782 sig_kwargs = sig_params.pop() 

8783 

8784 # add new keyword-only parameters 

8785 for param_name, default in params.items(): 

8786 new_param = inspect.Parameter( 

8787 param_name, 

8788 inspect.Parameter.KEYWORD_ONLY, 

8789 default=default, 

8790 ) 

8791 sig_params.append(new_param) 

8792 

8793 # re-append `**kwargs` if it was present 

8794 if sig_kwargs: 

8795 sig_params.append(sig_kwargs) 

8796 

8797 signature = signature.replace(parameters=sig_params) 

8798 

8799 wrapper.__signature__ = signature 

8800 

8801 # __doc__ is None when using `python -OO ...` 

8802 if func.__doc__ is not None: 

8803 assert np_ret in func.__doc__, ( 

8804 f"Failed to replace `{np_ret}` with `{np_ma_ret}`. " 

8805 f"The documentation string for return type, {np_ret}, is not " 

8806 f"found in the docstring for `np.{func.__name__}`. " 

8807 f"Fix the docstring for `np.{func.__name__}` or " 

8808 "update the expected string for return type." 

8809 ) 

8810 wrapper.__doc__ = inspect.cleandoc(func.__doc__).replace(np_ret, np_ma_ret) 

8811 

8812 return wrapper 

8813 

8814 

8815arange = _convert2ma( 

8816 'arange', 

8817 params={'fill_value': None, 'hardmask': False}, 

8818 np_ret='arange : ndarray', 

8819 np_ma_ret='arange : MaskedArray', 

8820) 

8821clip = _convert2ma( 

8822 'clip', 

8823 params={'fill_value': None, 'hardmask': False}, 

8824 np_ret='clipped_array : ndarray', 

8825 np_ma_ret='clipped_array : MaskedArray', 

8826) 

8827empty = _convert2ma( 

8828 'empty', 

8829 params={'fill_value': None, 'hardmask': False}, 

8830 np_ret='out : ndarray', 

8831 np_ma_ret='out : MaskedArray', 

8832) 

8833empty_like = _convert2ma( 

8834 'empty_like', 

8835 np_ret='out : ndarray', 

8836 np_ma_ret='out : MaskedArray', 

8837) 

8838frombuffer = _convert2ma( 

8839 'frombuffer', 

8840 np_ret='out : ndarray', 

8841 np_ma_ret='out: MaskedArray', 

8842) 

8843fromfunction = _convert2ma( 

8844 'fromfunction', 

8845 np_ret='fromfunction : any', 

8846 np_ma_ret='fromfunction: MaskedArray', 

8847) 

8848identity = _convert2ma( 

8849 'identity', 

8850 params={'fill_value': None, 'hardmask': False}, 

8851 np_ret='out : ndarray', 

8852 np_ma_ret='out : MaskedArray', 

8853) 

8854indices = _convert2ma( 

8855 'indices', 

8856 params={'fill_value': None, 'hardmask': False}, 

8857 np_ret='grid : one ndarray or tuple of ndarrays', 

8858 np_ma_ret='grid : one MaskedArray or tuple of MaskedArrays', 

8859) 

8860ones = _convert2ma( 

8861 'ones', 

8862 params={'fill_value': None, 'hardmask': False}, 

8863 np_ret='out : ndarray', 

8864 np_ma_ret='out : MaskedArray', 

8865) 

8866ones_like = _convert2ma( 

8867 'ones_like', 

8868 np_ret='out : ndarray', 

8869 np_ma_ret='out : MaskedArray', 

8870) 

8871squeeze = _convert2ma( 

8872 'squeeze', 

8873 params={'fill_value': None, 'hardmask': False}, 

8874 np_ret='squeezed : ndarray', 

8875 np_ma_ret='squeezed : MaskedArray', 

8876) 

8877zeros = _convert2ma( 

8878 'zeros', 

8879 params={'fill_value': None, 'hardmask': False}, 

8880 np_ret='out : ndarray', 

8881 np_ma_ret='out : MaskedArray', 

8882) 

8883zeros_like = _convert2ma( 

8884 'zeros_like', 

8885 np_ret='out : ndarray', 

8886 np_ma_ret='out : MaskedArray', 

8887) 

8888 

8889 

8890def append(a, b, axis=None): 

8891 """Append values to the end of an array. 

8892 

8893 Parameters 

8894 ---------- 

8895 a : array_like 

8896 Values are appended to a copy of this array. 

8897 b : array_like 

8898 These values are appended to a copy of `a`. It must be of the 

8899 correct shape (the same shape as `a`, excluding `axis`). If `axis` 

8900 is not specified, `b` can be any shape and will be flattened 

8901 before use. 

8902 axis : int, optional 

8903 The axis along which `v` are appended. If `axis` is not given, 

8904 both `a` and `b` are flattened before use. 

8905 

8906 Returns 

8907 ------- 

8908 append : MaskedArray 

8909 A copy of `a` with `b` appended to `axis`. Note that `append` 

8910 does not occur in-place: a new array is allocated and filled. If 

8911 `axis` is None, the result is a flattened array. 

8912 

8913 See Also 

8914 -------- 

8915 numpy.append : Equivalent function in the top-level NumPy module. 

8916 

8917 Examples 

8918 -------- 

8919 >>> import numpy as np 

8920 >>> import numpy.ma as ma 

8921 >>> a = ma.masked_values([1, 2, 3], 2) 

8922 >>> b = ma.masked_values([[4, 5, 6], [7, 8, 9]], 7) 

8923 >>> ma.append(a, b) 

8924 masked_array(data=[1, --, 3, 4, 5, 6, --, 8, 9], 

8925 mask=[False, True, False, False, False, False, True, False, 

8926 False], 

8927 fill_value=999999) 

8928 """ 

8929 return concatenate([a, b], axis)