summaryrefslogtreecommitdiff
path: root/numpy/core/arrayprint.py
diff options
context:
space:
mode:
authorCharles Harris <charlesr.harris@gmail.com>2011-08-27 21:46:08 -0600
committerCharles Harris <charlesr.harris@gmail.com>2011-08-27 21:46:08 -0600
commit9ecd91b7bf8c77d696ec9856ba10896d8f60309a (patch)
tree9884131ece5eada06212538c591965bf5928afa2 /numpy/core/arrayprint.py
parentaa55ba7437fbe6b8772a360a641b5aa7d3e669e0 (diff)
parent10fac981763e87f949bed15c66127fc380fa9b27 (diff)
downloadnumpy-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.py123
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')