diff options
author | Charles Harris <charlesr.harris@gmail.com> | 2011-08-27 21:46:08 -0600 |
---|---|---|
committer | Charles Harris <charlesr.harris@gmail.com> | 2011-08-27 21:46:08 -0600 |
commit | 9ecd91b7bf8c77d696ec9856ba10896d8f60309a (patch) | |
tree | 9884131ece5eada06212538c591965bf5928afa2 /numpy/core/arrayprint.py | |
parent | aa55ba7437fbe6b8772a360a641b5aa7d3e669e0 (diff) | |
parent | 10fac981763e87f949bed15c66127fc380fa9b27 (diff) | |
download | numpy-9ecd91b7bf8c77d696ec9856ba10896d8f60309a.tar.gz |
Merge branch 'pull-141'
* pull-141: (167 commits)
ENH: missingdata: Make PyArray_Converter and PyArray_OutputConverter safer for legacy code
DOC: missingdata: Add a mention of the design NEP, and masks vs bitpatterns
DOC: missingdata: Updates from pull request feedback
DOC: missingdata: Updates based on pull request feedback
ENH: nditer: Change the Python nditer exposure to automatically add NPY_ITER_USE_MASKNA
ENH: missingdata: Make comparisons with NA return NA(dtype='bool')
BLD: core: onefile build fix and Python3 compatibility change
DOC: Mention the update to np.all and np.any in the release notes
TST: dtype: Adjust void dtype test to pass without raising a zero-size exception
STY: Remove trailing whitespace
TST: missingdata: Write some tests for the np.any and np.all NA behavior
ENH: missingdata: Make numpy.all follow the NA && False == False rule
ENH: missingdata: Make numpy.all follow the NA || True == True rule
DOC: missingdata: Also show what assigning a non-NA value does in each case
DOC: missingdata: Add introductory documentation for NA-masked arrays
ENH: core: Rename PyArrayObject_fieldaccess to PyArrayObject_fields
DOC: missingdata: Some tweaks to the NA mask documentation
DOC: missingdata: Add example of a C-API function supporting NA masks
DOC: missingdata: Documenting C API for NA-masked arrays
ENH: missingdata: Finish adding C-API access to the NpyNA object
...
Diffstat (limited to 'numpy/core/arrayprint.py')
-rw-r--r-- | numpy/core/arrayprint.py | 123 |
1 files changed, 85 insertions, 38 deletions
diff --git a/numpy/core/arrayprint.py b/numpy/core/arrayprint.py index 508056a26..aad83500e 100644 --- a/numpy/core/arrayprint.py +++ b/numpy/core/arrayprint.py @@ -15,7 +15,7 @@ __docformat__ = 'restructuredtext' import sys import numerictypes as _nt from umath import maximum, minimum, absolute, not_equal, isnan, isinf -from multiarray import format_longfloat, datetime_as_string, datetime_data +from multiarray import format_longfloat, datetime_as_string, datetime_data, isna from fromnumeric import ravel @@ -29,6 +29,7 @@ _float_output_suppress_small = False _line_width = 75 _nan_str = 'nan' _inf_str = 'inf' +_na_str = 'NA' _formatter = None # formatting function for array elements if sys.version_info[0] >= 3: @@ -36,7 +37,8 @@ if sys.version_info[0] >= 3: def set_printoptions(precision=None, threshold=None, edgeitems=None, linewidth=None, suppress=None, - nanstr=None, infstr=None, formatter=None): + nanstr=None, infstr=None, nastr=None, + formatter=None): """ Set printing options. @@ -63,6 +65,8 @@ def set_printoptions(precision=None, threshold=None, edgeitems=None, String representation of floating point not-a-number (default nan). infstr : str, optional String representation of floating point infinity (default inf). + nastr : str, optional + String representation of NA missing value (default NA). formatter : dict of callables, optional If not None, the keys should indicate the type(s) that the respective formatting function applies to. Callables should return a string. @@ -140,7 +144,7 @@ def set_printoptions(precision=None, threshold=None, edgeitems=None, global _summaryThreshold, _summaryEdgeItems, _float_output_precision, \ _line_width, _float_output_suppress_small, _nan_str, _inf_str, \ - _formatter + _na_str, _formatter if linewidth is not None: _line_width = linewidth if threshold is not None: @@ -155,6 +159,8 @@ def set_printoptions(precision=None, threshold=None, edgeitems=None, _nan_str = nanstr if infstr is not None: _inf_str = infstr + if nastr is not None: + _na_str = nastr _formatter = formatter def get_printoptions(): @@ -189,6 +195,7 @@ def get_printoptions(): suppress=_float_output_suppress_small, nanstr=_nan_str, infstr=_inf_str, + nastr=_na_str, formatter=_formatter) return d @@ -212,9 +219,19 @@ def _leading_trailing(a): return b def _boolFormatter(x): - if x: return ' True' - else: return 'False' + if isna(x): + return str(x).replace('NA', _na_str, 1) + elif x: + return ' True' + else: + return 'False' + +def repr_format(x): + if isna(x): + return str(x).replace('NA', _na_str, 1) + else: + return repr(x) def _array2string(a, max_line_width, precision, suppress_small, separator=' ', prefix="", formatter=None): @@ -247,8 +264,9 @@ def _array2string(a, max_line_width, precision, suppress_small, separator=' ', 'longcomplexfloat' : LongComplexFormat(precision), 'datetime' : DatetimeFormat(data), 'timedelta' : TimedeltaFormat(data), - 'numpystr' : repr, + 'numpystr' : repr_format, 'str' : str} + if formatter is not None: fkeys = [k for k in formatter.keys() if formatter[k] is not None] if 'all' in fkeys: @@ -419,16 +437,20 @@ def array2string(a, max_line_width=None, precision=None, if a.shape == (): x = a.item() - try: - lst = a._format(x) - msg = "The `_format` attribute is deprecated in Numpy 2.0 and " \ - "will be removed in 2.1. Use the `formatter` kw instead." - import warnings - warnings.warn(msg, DeprecationWarning) - except AttributeError: - if isinstance(x, tuple): - x = _convert_arrays(x) - lst = style(x) + if isna(x): + lst = str(x).replace('NA', _na_str, 1) + else: + try: + lst = a._format(x) + msg = "The `_format` attribute is deprecated in Numpy " \ + "2.0 and will be removed in 2.1. Use the " \ + "`formatter` kw instead." + import warnings + warnings.warn(msg, DeprecationWarning) + except AttributeError: + if isinstance(x, tuple): + x = _convert_arrays(x) + lst = style(x) elif reduce(product, a.shape) == 0: # treat as a null array if any of shape elements == 0 lst = "[]" @@ -531,14 +553,17 @@ class FloatFormat(object): import numeric as _nc errstate = _nc.seterr(all='ignore') try: - special = isnan(data) | isinf(data) - non_zero = absolute(data.compress(not_equal(data, 0) & ~special)) + special = isnan(data) | isinf(data) | isna(data) + special[isna(data)] = False + valid = not_equal(data, 0) & ~special + valid[isna(data)] = False + non_zero = absolute(data.compress(valid)) if len(non_zero) == 0: max_val = 0. min_val = 0. else: - max_val = maximum.reduce(non_zero) - min_val = minimum.reduce(non_zero) + max_val = maximum.reduce(non_zero, skipna=True) + min_val = minimum.reduce(non_zero, skipna=True) if max_val >= 1.e8: self.exp_format = True if not self.suppress_small and (min_val < 0.0001 @@ -569,7 +594,8 @@ class FloatFormat(object): if _nc.any(special): self.max_str_len = max(self.max_str_len, len(_nan_str), - len(_inf_str)+1) + len(_inf_str)+1, + len(_na_str)) if self.sign: format = '%#+' else: @@ -583,7 +609,9 @@ class FloatFormat(object): import numeric as _nc err = _nc.seterr(invalid='ignore') try: - if isnan(x): + if isna(x): + return self.special_fmt % (str(x).replace('NA', _na_str, 1),) + elif isnan(x): if self.sign: return self.special_fmt % ('+' + _nan_str,) else: @@ -626,16 +654,21 @@ _MININT = -sys.maxint-1 class IntegerFormat(object): def __init__(self, data): try: - max_str_len = max(len(str(maximum.reduce(data))), - len(str(minimum.reduce(data)))) + max_str_len = max(len(str(maximum.reduce(data, skipna=True))), + len(str(minimum.reduce(data, skipna=True)))) self.format = '%' + str(max_str_len) + 'd' except TypeError, NotImplementedError: # if reduce(data) fails, this instance will not be called, just # instantiated in formatdict. pass + except ValueError: + # this occurs when everything is NA + pass def __call__(self, x): - if _MININT < x < _MAXINT: + if isna(x): + return str(x).replace('NA', _na_str, 1) + elif _MININT < x < _MAXINT: return self.format % x else: return "%s" % x @@ -648,7 +681,9 @@ class LongFloatFormat(object): self.sign = sign def __call__(self, x): - if isnan(x): + if isna(x): + return str(x).replace('NA', _na_str, 1) + elif isnan(x): if self.sign: return '+' + _nan_str else: @@ -676,9 +711,12 @@ class LongComplexFormat(object): self.imag_format = LongFloatFormat(precision, sign=True) def __call__(self, x): - r = self.real_format(x.real) - i = self.imag_format(x.imag) - return r + i + 'j' + if isna(x): + return str(x).replace('NA', _na_str, 1) + else: + r = self.real_format(x.real) + i = self.imag_format(x.imag) + return r + i + 'j' class ComplexFormat(object): @@ -688,14 +726,17 @@ class ComplexFormat(object): sign=True) def __call__(self, x): - r = self.real_format(x.real, strip_zeros=False) - i = self.imag_format(x.imag, strip_zeros=False) - if not self.imag_format.exp_format: - z = i.rstrip('0') - i = z + 'j' + ' '*(len(i)-len(z)) + if isna(x): + return str(x).replace('NA', _na_str, 1) else: - i = i + 'j' - return r + i + r = self.real_format(x.real, strip_zeros=False) + i = self.imag_format(x.imag, strip_zeros=False) + if not self.imag_format.exp_format: + z = i.rstrip('0') + i = z + 'j' + ' '*(len(i)-len(z)) + else: + i = i + 'j' + return r + i class DatetimeFormat(object): def __init__(self, x, unit=None, @@ -720,7 +761,10 @@ class DatetimeFormat(object): self.casting = casting def __call__(self, x): - return "'%s'" % datetime_as_string(x, + if isna(x): + return str(x).replace('NA', _na_str, 1) + else: + return "'%s'" % datetime_as_string(x, unit=self.unit, timezone=self.timezone, casting=self.casting) @@ -734,5 +778,8 @@ class TimedeltaFormat(object): self.format = '%' + str(max_str_len) + 'd' def __call__(self, x): - return self.format % x.astype('i8') + if isna(x): + return str(x).replace('NA', _na_str, 1) + else: + return self.format % x.astype('i8') |