[PYTHON MATRIX-SIG] Final (!?) pretty printer
Konrad HINSEN
hinsenk@ere.umontreal.ca
Thu, 8 Feb 1996 18:49:21 -0500
Here it is: the fully functional pretty printer for Python arrays.
Unless there are bugs to be fixed or complaints or requests for
reasonable new features, I'd like to leave it at this stage. Line
wrapping is now implemented and respects the maximum line width
whenever possible, but it still puts at least one element on each
line.
Note that continuation lines are indented by at least 6 characters
in such a way as to make sure that their items do *not* align with
the main lines. This makes visual parsing easier.
And now, as you expected, the code:
def arrayToString(a, max_line_width = None, precision = None):
if not max_line_width:
try:
max_line_width = sys.output_line_width
except AttributeError:
max_line_width = 77
if not precision:
try:
precision = sys.float_output_precision
except AttributeError:
precision = 8
if a.contiguous():
data = a.reshape(None)
else:
data = a.copy().reshape(None)
type = a.typecode()
items_per_line = a.shape[-1]
if type == 'b' or type == '1' or type == 's' or type == 'i' \
or type == 'l':
max_str_len = max(len(str(maximum.reduce(data))),
len(str(minimum.reduce(data))))
format = '%' + str(max_str_len) + 'd'
item_length = max_str_len+1
format_function = lambda x, f = format: _formatInteger(x, f)
elif type == 'f' or type == 'd':
format, item_length = _floatFormat(data, precision)
format_function = lambda x, f = format: _formatFloat(x, f)
elif type == 'F' or type == 'D':
real_format, real_item_length = _floatFormat(data.real, precision,
sign=0)
imag_format, imag_item_length = _floatFormat(data.imaginary, precision,
sign=1)
item_length = real_item_length + imag_item_length + 2
format_function = lambda x, f1 = real_format, f2 = imag_format: \
_formatComplex(x, f1, f2)
elif type == 'c':
format = '%s'
item_length = 1
format_function = lambda x, f = format: _formatCharacter(x, f)
else: # give up on 'O'
return str(a)
final_spaces = (type != 'c')
line_width = item_length*items_per_line - final_spaces
if line_width > max_line_width:
indent = 6
if indent == item_length:
indent = 8
items_first = (max_line_width+final_spaces)/item_length
if items_first < 1: items_first = 1
items_continuation = (max_line_width+final_spaces-indent)/item_length
if items_continuation < 1: items_continuation = 1
line_width = max(item_length*items_first,
item_length*items_continuation+indent) - final_spaces
number_of_lines = 1 + (items_per_line-items_first +
items_continuation-1)/items_continuation
line_format = (number_of_lines, items_first, items_continuation,
indent, line_width)
else:
line_format = (1, items_per_line, 0, 0, line_width)
return _arrayToString(a, format_function, len(a.shape), line_format)[:-1]
def _floatFormat(data, precision, sign = 0):
exp_format = 0
non_zero = abs(compress(data.notEqual(0), data))
if len(non_zero) == 0:
max_val = 0.
min_val = 0.
else:
max_val = maximum.reduce(non_zero)
min_val = minimum.reduce(non_zero)
if max_val >= 1.e12 or min_val < 0.0001 or max_val/min_val > 1000.:
exp_format = 1
if exp_format:
large_exponent = 0 < min_val < 1e-99 or max_val >= 1e100
max_str_len = 8 + precision + large_exponent
if sign: format = '%+'
else: format = '%'
format = format + str(max_str_len) + '.' + str(precision) + 'e'
if large_exponent: format = format + '3'
item_length = max_str_len + 1
else:
format = '%.' + str(precision) + 'f'
precision = min(precision, apply(max, tuple(map(lambda x, p=precision,
f=format: _digits(x,p,f),
data))))
max_str_len = len(str(int(max_val))) + precision + 2
if sign: format = '%#+'
else: format = '%#'
format = format + str(max_str_len) + '.' + str(precision) + 'f'
item_length = max_str_len + 1
return (format, item_length)
def _digits(x, precision, format):
s = format % x
zeros = len(s)
while s[zeros-1] == '0': zeros = zeros-1
return precision-len(s)+zeros
def _arrayToString(a, format_function, rank, line_format):
if rank == 0:
return str(a[0])
elif rank == 1:
s = ''
items = line_format[1]
indent = 0
index = 0
for j in range(line_format[0]):
s = s + indent * ' '
for i in range(items):
s = s + format_function(a[index])
index = index + 1
if index == a.shape[0]: break
if s[-1] == ' ': s = s[:-1]
s = s + '\n'
items = line_format[2]
indent = line_format[3]
else:
s = ''
for i in range(a.shape[0]-1):
s = s + _arrayToString(a[i], format_function, rank-1, line_format)
if rank == 3:
s = s + '\n'
elif rank > 3:
s = s + (rank-3)*(line_format[4]*'-'+'\n')
s = s + _arrayToString(a[a.shape[0]-1], format_function,
rank-1, line_format)
return s
def _formatInteger(x, format):
return format % x + ' '
def _formatFloat(x, format, strip_zeros = 1):
if format[-1] == '3':
format = format[:-1]
s = format % x
third = s[-3]
if third == '+' or third == '-':
s = s[1:-2] + '0' + s[-2:]
elif format[-1] == 'f':
s = format % x
if strip_zeros:
zeros = len(s)
while s[zeros-1] == '0': zeros = zeros-1
s = s[:zeros] + (len(s)-zeros)*' '
else:
s = format % x
return s + ' '
def _formatComplex(x, real_format, imag_format):
r = _formatFloat(x.real, real_format)[:-1]
i = _formatFloat(x.imag, imag_format, 0)[:-1]
spaces = 0
while r[spaces] == ' ': spaces = spaces + 1
r = spaces*' ' + '(' + r[spaces:]
if imag_format[-1] == 'f':
zeros = len(i)
while i[zeros-1] == '0': zeros = zeros-1
i = i[:zeros] + 'j)' + (len(i)-zeros)*' '
else:
i = i + 'j)'
return r + i + ' '
def _formatCharacter(x, format):
return format % x
-------------------------------------------------------------------------------
Konrad Hinsen | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal | Fax: +1-514-343-7586
C.P. 6128, succ. Centre-Ville | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7 | Francais (phase experimentale)
-------------------------------------------------------------------------------
=================
MATRIX-SIG - SIG on Matrix Math for Python
send messages to: matrix-sig@python.org
administrivia to: matrix-sig-request@python.org
=================