Skip to content

Commit

Permalink
ENH: remove unneeded spaces in float/bool reprs
Browse files Browse the repository at this point in the history
  • Loading branch information
ahaldane committed Sep 26, 2017
1 parent ceef499 commit 8943851
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 32 deletions.
7 changes: 7 additions & 0 deletions doc/release/1.14.0-notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -304,3 +304,10 @@ source to the destination.
Using field "titles" in multiple-field indexing is now disallowed, as is
repeating a field name in a multiple-field index.

Removed unneeded whitespace in float and bool array printing
------------------------------------------------------------
The ``repr`` of float arrays now omits the whitespace character previsouly used
to display the sign if possible, for example if the array has all-positive
values. Similarly, the ``repr`` of bool arrays with only one element now omits
the whitespace before a ``True`` value, so that ``repr(array([True]))`` now
returns ``'array([True])'`` instead of ``'array([ True])'``.
69 changes: 37 additions & 32 deletions numpy/core/arrayprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,12 +251,6 @@ def _leading_trailing(a):
b = concatenate(tuple(l))
return b

def _boolFormatter(x):
if x:
return ' True'
else:
return 'False'

def _object_format(o):
""" Object arrays containing lists should be printed unambiguously """
if type(o) is list:
Expand All @@ -270,7 +264,7 @@ def repr_format(x):

def _get_formatdict(data, precision, suppress_small, formatter):
# wrapped in lambdas to avoid taking a code path with the wrong type of data
formatdict = {'bool': lambda: _boolFormatter,
formatdict = {'bool': lambda: BoolFormat(data),
'int': lambda: IntegerFormat(data),
'float': lambda: FloatFormat(data, precision, suppress_small),
'longfloat': lambda: LongFloatFormat(precision),
Expand Down Expand Up @@ -627,44 +621,54 @@ def __init__(self, data, precision, suppress_small, sign=False):

def fillFormat(self, data):
with errstate(all='ignore'):
special = isnan(data) | isinf(data)
hasinf = isinf(data)
special = isnan(data) | hasinf
valid = not_equal(data, 0) & ~special
non_zero = absolute(data.compress(valid))
non_zero = data.compress(valid)
abs_non_zero = absolute(non_zero)
if len(non_zero) == 0:
max_val = 0.
min_val = 0.
min_val_sgn = 0.
else:
max_val = maximum.reduce(non_zero)
min_val = minimum.reduce(non_zero)
max_val = maximum.reduce(abs_non_zero)
min_val = minimum.reduce(abs_non_zero)
min_val_sgn = minimum.reduce(non_zero)
if max_val >= 1.e8:
self.exp_format = True
if not self.suppress_small and (min_val < 0.0001
or max_val/min_val > 1000.):
self.exp_format = True

if self.exp_format:
self.large_exponent = 0 < min_val < 1e-99 or max_val >= 1e100
self.max_str_len = 8 + self.precision
if self.large_exponent:
self.max_str_len += 1
large_exponent = 0 < min_val < 1e-99 or max_val >= 1e100
self.large_exponent = large_exponent
pad_sign = self.sign or any(non_zero < 0)
self.max_str_len = pad_sign + 6 + self.precision + large_exponent

if self.sign:
format = '%+'
else:
format = '%'
format = format + '%d.%de' % (self.max_str_len, self.precision)
else:
format = '%%.%df' % (self.precision,)
if len(non_zero):
precision = max([_digits(x, self.precision, format)
for x in non_zero])
if len(non_zero) and self.precision > 0:
precision = self.precision
trim_zero = lambda s: precision - (len(s) - len(s.rstrip('0')))
fmt = '%%.%df' % (precision,)
precision = max(trim_zero(fmt % x) for x in abs_non_zero)
else:
precision = 0
precision = min(self.precision, precision)
self.max_str_len = len(str(int(max_val))) + precision + 2

int_len = len(str(int(max_val)))
pad_sign = self.sign or (len(str(int(min_val_sgn))) > int_len)
self.max_str_len = pad_sign + int_len + 1 + precision

if any(special):
neginf = any(data[hasinf] < 0)
self.max_str_len = max(self.max_str_len,
len(_nan_str),
len(_inf_str)+1)
len(_inf_str) + neginf)
if self.sign:
format = '%#+'
else:
Expand Down Expand Up @@ -705,16 +709,6 @@ def __call__(self, x, strip_zeros=True):
s = z + ' '*(len(s)-len(z))
return s


def _digits(x, precision, format):
if precision > 0:
s = format % x
z = s.rstrip('0')
return precision - len(s) + len(z)
else:
return 0


class IntegerFormat(object):
def __init__(self, data):
try:
Expand All @@ -735,6 +729,17 @@ def __call__(self, x):
else:
return "%s" % x

class BoolFormat(object):
def __init__(self, data):
# add an extra space so " True" and "False" have the same length and
# array elements align nicely when printed, but only for arrays with
# more than one element.
self.truestr = ' True' if data.size > 1 else 'True'

def __call__(self, x):
return self.truestr if x else "False"


class LongFloatFormat(object):
# XXX Have to add something to determine the width to use a la FloatFormat
# Right now, things won't line up properly
Expand Down
27 changes: 27 additions & 0 deletions numpy/core/tests/test_arrayprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,33 @@ def test_0d_arrays(self):
np.set_printoptions(formatter={'all':lambda x: "test"})
assert_equal(repr(x), "array(test)")

def test_float_spacing(self):
x = np.array([1., 2., 3.])
y = np.array([1., 2., -10.])
z = np.array([100., 2., -1.])

assert_equal(repr(x), 'array([1., 2., 3.])')
assert_equal(repr(y), 'array([ 1., 2., -10.])')
assert_equal(repr(np.array(y[0])), 'array(1.)')
assert_equal(repr(np.array(y[-1])), 'array(-10.)')
assert_equal(repr(z), 'array([ 100., 2., -1.])')

assert_equal(repr(np.array([np.nan, np.inf])), 'array([nan, inf])')
assert_equal(repr(np.array([np.nan, -np.inf])), 'array([ nan, -inf])')

def test_bool_spacing(self):
assert_equal(repr(np.array([True, True])),
'array([ True, True], dtype=bool)')
assert_equal(repr(np.array([True, False])),
'array([ True, False], dtype=bool)')
assert_equal(repr(np.array([True])),
'array([True], dtype=bool)')
assert_equal(repr(np.array(True)),
'array(True, dtype=bool)')
assert_equal(repr(np.array(False)),
'array(False, dtype=bool)')


def test_unicode_object_array():
import sys
if sys.version_info[0] >= 3:
Expand Down

0 comments on commit 8943851

Please sign in to comment.