How to pretty-print a numpy.array without scientific notation and with given precision?

PythonNumpyPython 2.xPretty Print

Python Problem Overview


I'm curious, whether there is any way to print formatted numpy.arrays, e.g., in a way similar to this:

x = 1.23456
print '%.3f' % x

If I want to print the numpy.array of floats, it prints several decimals, often in 'scientific' format, which is rather hard to read even for low-dimensional arrays. However, numpy.array apparently has to be printed as a string, i.e., with %s. Is there a solution for this?

Python Solutions


Solution 1 - Python

You can use set_printoptions to set the precision of the output:

import numpy as np
x=np.random.random(10)
print(x)
# [ 0.07837821  0.48002108  0.41274116  0.82993414  0.77610352  0.1023732#   0.51303098  0.4617183   0.33487207  0.71162095]

np.set_printoptions(precision=3)
print(x)
# [ 0.078  0.48   0.413  0.83   0.776  0.102  0.513  0.462  0.335  0.712]

And suppress suppresses the use of scientific notation for small numbers:

y=np.array([1.5e-10,1.5,1500])
print(y)
# [  1.500e-10   1.500e+00   1.500e+03]
np.set_printoptions(suppress=True)
print(y)
# [    0.      1.5  1500. ]

See the docs for set_printoptions for other options.


To apply print options locally, using NumPy 1.15.0 or later, you could use the numpy.printoptions context manager. For example, inside the with-suite precision=3 and suppress=True are set:

x = np.random.random(10)
with np.printoptions(precision=3, suppress=True):
    print(x)
    # [ 0.073  0.461  0.689  0.754  0.624  0.901  0.049  0.582  0.557  0.348]

But outside the with-suite the print options are back to default settings:

print(x)    
# [ 0.07334334  0.46132615  0.68935231  0.75379645  0.62424021  0.90115836
#   0.04879837  0.58207504  0.55694118  0.34768638]

If you are using an earlier version of NumPy, you can create the context manager yourself. For example,

import numpy as np
import contextlib

@contextlib.contextmanager
def printoptions(*args, **kwargs):
    original = np.get_printoptions()
    np.set_printoptions(*args, **kwargs)
    try:
        yield
    finally: 
        np.set_printoptions(**original)

x = np.random.random(10)
with printoptions(precision=3, suppress=True):
    print(x)
    # [ 0.073  0.461  0.689  0.754  0.624  0.901  0.049  0.582  0.557  0.348]

To prevent zeros from being stripped from the end of floats:

np.set_printoptions now has a formatter parameter which allows you to specify a format function for each type.

np.set_printoptions(formatter={'float': '{: 0.3f}'.format})
print(x)

which prints

[ 0.078  0.480  0.413  0.830  0.776  0.102  0.513  0.462  0.335  0.712]

instead of

[ 0.078  0.48   0.413  0.83   0.776  0.102  0.513  0.462  0.335  0.712]

Solution 2 - Python

You can get a subset of the np.set_printoptions functionality from the np.array_str command, which applies only to a single print statement.

http://docs.scipy.org/doc/numpy/reference/generated/numpy.array_str.html

For example:

In [27]: x = np.array([[1.1, 0.9, 1e-6]]*3)

In [28]: print x
[[  1.10000000e+00   9.00000000e-01   1.00000000e-06]
 [  1.10000000e+00   9.00000000e-01   1.00000000e-06]
 [  1.10000000e+00   9.00000000e-01   1.00000000e-06]]

In [29]: print np.array_str(x, precision=2)
[[  1.10e+00   9.00e-01   1.00e-06]
 [  1.10e+00   9.00e-01   1.00e-06]
 [  1.10e+00   9.00e-01   1.00e-06]]

In [30]: print np.array_str(x, precision=2, suppress_small=True)
[[ 1.1  0.9  0. ]
 [ 1.1  0.9  0. ]
 [ 1.1  0.9  0. ]]

Solution 3 - Python

Unutbu gave a really complete answer (they got a +1 from me too), but here is a lo-tech alternative:

>>> x=np.random.randn(5)
>>> x
array([ 0.25276524,  2.28334499, -1.88221637,  0.69949927,  1.0285625 ])
>>> ['{:.2f}'.format(i) for i in x]
['0.25', '2.28', '-1.88', '0.70', '1.03']

As a function (using the format() syntax for formatting):

def ndprint(a, format_string ='{0:.2f}'):
    print [format_string.format(v,i) for i,v in enumerate(a)]

Usage:

>>> ndprint(x)
['0.25', '2.28', '-1.88', '0.70', '1.03']

>>> ndprint(x, '{:10.4e}')
['2.5277e-01', '2.2833e+00', '-1.8822e+00', '6.9950e-01', '1.0286e+00']

>>> ndprint(x, '{:.8g}')
['0.25276524', '2.283345', '-1.8822164', '0.69949927', '1.0285625']

The index of the array is accessible in the format string:

>>> ndprint(x, 'Element[{1:d}]={0:.2f}')
['Element[0]=0.25', 'Element[1]=2.28', 'Element[2]=-1.88', 'Element[3]=0.70', 'Element[4]=1.03']

Solution 4 - Python

FYI Numpy 1.15 (release date pending) will include a context manager for setting print options locally. This means that the following will work the same as the corresponding example in the accepted answer (by unutbu and Neil G) without having to write your own context manager. E.g., using their example:

x = np.random.random(10)
with np.printoptions(precision=3, suppress=True):
    print(x)
    # [ 0.073  0.461  0.689  0.754  0.624  0.901  0.049  0.582  0.557  0.348]

Solution 5 - Python

The gem that makes it all too easy to obtain the result as a string (in today's numpy versions) is hidden in denis answer: np.array2string

>>> import numpy as np
>>> x=np.random.random(10)
>>> np.array2string(x, formatter={'float_kind':'{0:.3f}'.format})
'[0.599 0.847 0.513 0.155 0.844 0.753 0.920 0.797 0.427 0.420]'

Solution 6 - Python

Years later, another one is below. But for everyday use I just

np.set_printoptions( threshold=20, edgeitems=10, linewidth=140,
    formatter = dict( float = lambda x: "%.3g" % x ))  # float arrays %.3g


''' printf( "... %.3g ... %.1f  ...", arg, arg ... ) for numpy arrays too

Example:
	printf( """ x: %.3g   A: %.1f   s: %s   B: %s """,
				   x,        A,        "str",  B )

If `x` and `A` are numbers, this is like `"format" % (x, A, "str", B)` in python.
If they're numpy arrays, each element is printed in its own format:
	`x`: e.g. [ 1.23 1.23e-6 ... ]  3 digits
	`A`: [ [ 1 digit after the decimal point ... ] ... ]
with the current `np.set_printoptions()`. For example, with
	np.set_printoptions( threshold=100, edgeitems=3, suppress=True )
only the edges of big `x` and `A` are printed.
`B` is printed as `str(B)`, for any `B` -- a number, a list, a numpy object ...

`printf()` tries to handle too few or too many arguments sensibly,
but this is iffy and subject to change.

How it works:
numpy has a function `np.array2string( A, "%.3g" )` (simplifying a bit).
`printf()` splits the format string, and for format / arg pairs
	format: % d e f g
	arg: try `np.asanyarray()`
-->  %s  np.array2string( arg, format )
Other formats and non-ndarray args are left alone, formatted as usual.

Notes:

`printf( ... end= file= )` are passed on to the python `print()` function.

Only formats `% [optional width . precision] d e f g` are implemented,
not `%(varname)format` .

%d truncates floats, e.g. 0.9 and -0.9 to 0; %.0f rounds, 0.9 to 1 .
%g is the same as %.6g, 6 digits.
%% is a single "%" character.

The function `sprintf()` returns a long string. For example,
	title = sprintf( "%s  m %g  n %g  X %.3g",
					__file__, m, n, X )
	print( title )
	...
	pl.title( title )

Module globals:
_fmt = "%.3g"  # default for extra args
_squeeze = np.squeeze  # (n,1) (1,n) -> (n,) print in 1 line not n

See also:
http://docs.scipy.org/doc/numpy/reference/generated/numpy.set_printoptions.html
http://docs.python.org/2.7/library/stdtypes.html#string-formatting

'''
# http://stackoverflow.com/questions/2891790/pretty-printing-of-numpy-array


#...............................................................................
from __future__ import division, print_function
import re
import numpy as np

__version__ = "2014-02-03 feb denis"

_splitformat = re.compile( r'''(
	%
	(?<! %% )  # not %%
	-? [ \d . ]*  # optional width.precision
	\w
	)''', re.X )
	# ... %3.0f  ... %g  ... %-10s ...
	# -> ['...' '%3.0f' '...' '%g' '...' '%-10s' '...']
	# odd len, first or last may be ""

_fmt = "%.3g"  # default for extra args
_squeeze = np.squeeze  # (n,1) (1,n) -> (n,) print in 1 line not n

#...............................................................................
def printf( format, *args, **kwargs ):
	print( sprintf( format, *args ), **kwargs )  # end= file=

printf.__doc__ = __doc__


def sprintf( format, *args ):
	""" sprintf( "text %.3g text %4.1f ... %s ... ", numpy arrays or ... )
		%[defg] array -> np.array2string( formatter= )
	"""
	args = list(args)
	if not isinstance( format, basestring ):
		args = [format] + args
		format = ""

	tf = _splitformat.split( format )  # [ text %e text %f ... ]
	nfmt = len(tf) // 2
	nargs = len(args)
	if nargs < nfmt:
		args += (nfmt - nargs) * ["?arg?"]
	elif nargs > nfmt:
		tf += (nargs - nfmt) * [_fmt, " "]  # default _fmt

	for j, arg in enumerate( args ):
		fmt = tf[ 2*j + 1 ]
		if arg is None \
		or isinstance( arg, basestring ) \
		or (hasattr( arg, "__iter__" ) and len(arg) == 0):
			tf[ 2*j + 1 ] = "%s"  # %f -> %s, not error
			continue
		args[j], isarray = _tonumpyarray(arg)
		if isarray  and fmt[-1] in "defgEFG":
			tf[ 2*j + 1 ] = "%s"
			fmtfunc = (lambda x: fmt % x)
			formatter = dict( float_kind=fmtfunc, int=fmtfunc )
			args[j] = np.array2string( args[j], formatter=formatter )
	try:
		return "".join(tf) % tuple(args)
	except TypeError:  # shouldn't happen
		print( "error: tf %s  types %s" % (tf, map( type, args )))
		raise


def _tonumpyarray( a ):
	""" a, isarray = _tonumpyarray( a )
		->  scalar, False
			np.asanyarray(a), float or int
			a, False
	"""
	a = getattr( a, "value", a )  # cvxpy
	if np.isscalar(a):
		return a, False
	if hasattr( a, "__iter__" )  and len(a) == 0:
		return a, False
	try:
		# map .value ?
		a = np.asanyarray( a )
	except ValueError:
		return a, False
	if hasattr( a, "dtype" )  and a.dtype.kind in "fi":  # complex ?
		if callable( _squeeze ):
			a = _squeeze( a )  # np.squeeze
		return a, True
	else:
		return a, False


#...............................................................................
if __name__ == "__main__":
	import sys

	n = 5
	seed = 0
		# run this.py n= ...  in sh or ipython
	for arg in sys.argv[1:]:
		exec( arg )
	np.set_printoptions( 1, threshold=4, edgeitems=2, linewidth=80, suppress=True )
	np.random.seed(seed)

	A = np.random.exponential( size=(n,n) ) ** 10
	x = A[0]

	printf( "x: %.3g  \nA: %.1f  \ns: %s  \nB: %s ",
				x,         A,         "str",   A )
	printf( "x %%d: %d", x )
	printf( "x %%.0f: %.0f", x )
	printf( "x %%.1e: %.1e", x )
	printf( "x %%g: %g", x )
	printf( "x %%s uses np printoptions: %s", x )

	printf( "x with default _fmt: ", x )
	printf( "no args" )
	printf( "too few args: %g %g", x )
	printf( x )
	printf( x, x )
	printf( None )
	printf( "[]:", [] )
	printf( "[3]:", [3] )
	printf( np.array( [] ))
	printf( [[]] )  # squeeze

Solution 7 - Python

And here is what I use, and it's pretty uncomplicated:

print(np.vectorize("%.2f".__mod__)(sparse))

Solution 8 - Python

The numpy arrays have the method round(precision) which returns a new numpy array with elements rounded accordingly.

import numpy as np

x = np.random.random([5,5])
print(x.round(3))

Solution 9 - Python

Was surprised to not see around method mentioned - means no messing with print options.

import numpy as np

x = np.random.random([5,5])
print(np.around(x,decimals=3))

Output:
[[0.475 0.239 0.183 0.991 0.171]
 [0.231 0.188 0.235 0.335 0.049]
 [0.87  0.212 0.219 0.9   0.3  ]
 [0.628 0.791 0.409 0.5   0.319]
 [0.614 0.84  0.812 0.4   0.307]]

Solution 10 - Python

I often want different columns to have different formats. Here is how I print a simple 2D array using some variety in the formatting by converting (slices of) my NumPy array to a tuple:

import numpy as np
dat = np.random.random((10,11))*100  # Array of random values between 0 and 100
print(dat)                           # Lines get truncated and are hard to read
for i in range(10):
    print((4*"%6.2f"+7*"%9.4f") % tuple(dat[i,:]))

Solution 11 - Python

I find that the usual float format {:9.5f} works properly -- suppressing small-value e-notations -- when displaying a list or an array using a loop. But that format sometimes fails to suppress its e-notation when a formatter has several items in a single print statement. For example:

import numpy as np
np.set_printoptions(suppress=True)
a3 = 4E-3
a4 = 4E-4
a5 = 4E-5
a6 = 4E-6
a7 = 4E-7
a8 = 4E-8
#--first, display separate numbers-----------
print('Case 3:  a3, a4, a5:             {:9.5f}{:9.5f}{:9.5f}'.format(a3,a4,a5))
print('Case 4:  a3, a4, a5, a6:         {:9.5f}{:9.5f}{:9.5f}{:9.5}'.format(a3,a4,a5,a6))
print('Case 5:  a3, a4, a5, a6, a7:     {:9.5f}{:9.5f}{:9.5f}{:9.5}{:9.5f}'.format(a3,a4,a5,a6,a7))
print('Case 6:  a3, a4, a5, a6, a7, a8: {:9.5f}{:9.5f}{:9.5f}{:9.5f}{:9.5}{:9.5f}'.format(a3,a4,a5,a6,a7,a8))
#---second, display a list using a loop----------
myList = [a3,a4,a5,a6,a7,a8]
print('List 6:  a3, a4, a5, a6, a7, a8: ', end='')
for x in myList: 
    print('{:9.5f}'.format(x), end='')
print()
#---third, display a numpy array using a loop------------
myArray = np.array(myList)
print('Array 6: a3, a4, a5, a6, a7, a8: ', end='')
for x in myArray:
    print('{:9.5f}'.format(x), end='')
print()

My results show the bug in cases 4, 5, and 6:

Case 3:  a3, a4, a5:               0.00400  0.00040  0.00004
Case 4:  a3, a4, a5, a6:           0.00400  0.00040  0.00004    4e-06
Case 5:  a3, a4, a5, a6, a7:       0.00400  0.00040  0.00004    4e-06  0.00000
Case 6:  a3, a4, a5, a6, a7, a8:   0.00400  0.00040  0.00004  0.00000    4e-07  0.00000
List 6:  a3, a4, a5, a6, a7, a8:   0.00400  0.00040  0.00004  0.00000  0.00000  0.00000
Array 6: a3, a4, a5, a6, a7, a8:   0.00400  0.00040  0.00004  0.00000  0.00000  0.00000

I have no explanation for this, and therefore I always use a loop for floating output of multiple values.

Solution 12 - Python

I use

def np_print(array,fmt="10.5f"):
    print (array.size*("{:"+fmt+"}")).format(*array)

It's not difficult to modify it for multi-dimensional arrays.

Solution 13 - Python

numpy.char.mod may also be useful, depending on the details of your application e.g.:numpy.char.mod('Value=%4.2f', numpy.arange(5, 10, 0.1)) will return a string array with elements "Value=5.00", "Value=5.10" etc. (as a somewhat contrived example).

Solution 14 - Python

Yet another option is to use the decimal module:

import numpy as np
from decimal import *

arr = np.array([  56.83,  385.3 ,    6.65,  126.63,   85.76,  192.72,  112.81, 10.55])
arr2 = [str(Decimal(i).quantize(Decimal('.01'))) for i in arr]

# ['56.83', '385.30', '6.65', '126.63', '85.76', '192.72', '112.81', '10.55']

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestioncamillioView Question on Stackoverflow
Solution 1 - PythonunutbuView Answer on Stackoverflow
Solution 2 - PythonDaniel GoldenView Answer on Stackoverflow
Solution 3 - PythonCaleb HattinghView Answer on Stackoverflow
Solution 4 - PythonJustin LanfranchiView Answer on Stackoverflow
Solution 5 - PythonhamoguView Answer on Stackoverflow
Solution 6 - PythondenisView Answer on Stackoverflow
Solution 7 - PythonutdemirView Answer on Stackoverflow
Solution 8 - PythonȘtefanView Answer on Stackoverflow
Solution 9 - Pythontea_peaView Answer on Stackoverflow
Solution 10 - PythonAstroFloydView Answer on Stackoverflow
Solution 11 - PythonMike LamptonView Answer on Stackoverflow
Solution 12 - PythonalbapaView Answer on Stackoverflow
Solution 13 - PythonjtniehofView Answer on Stackoverflow
Solution 14 - PythonjppView Answer on Stackoverflow