codekingpro/portable-devtools
115k
1"""Array printing function
2
3$Id: arrayprint.py,v 1.9 2005/09/13 13:58:44 teoliphant Exp $
4
5"""
6__all__ = ["array2string", "array_str", "array_repr",
7 "set_printoptions", "get_printoptions", "printoptions",
8 "format_float_positional", "format_float_scientific"]
9__docformat__ = 'restructuredtext'
10
11#
12# Written by Konrad Hinsen <hinsenk@ere.umontreal.ca>
13# last revision: 1996-3-13
14# modified by Jim Hugunin 1997-3-3 for repr's and str's (and other details)
15# and by Perry Greenfield 2000-4-1 for numarray
16# and by Travis Oliphant 2005-8-22 for numpy
17
18
19# Note: Both scalartypes.c.src and arrayprint.py implement strs for numpy
20# scalars but for different purposes. scalartypes.c.src has str/reprs for when
21# the scalar is printed on its own, while arrayprint.py has strs for when
22# scalars are printed inside an ndarray. Only the latter strs are currently
23# user-customizable.
24
25import functools
26import numbers
27import sys
28
29try:
30 from _thread import get_ident
31except ImportError:
32 from _dummy_thread import get_ident
33
34import contextlib
35import operator
36import warnings
37
38import numpy as np
39
40from . import numerictypes as _nt
41from .fromnumeric import any
42from .multiarray import (
43 array,
44 datetime_as_string,
45 datetime_data,
46 dragon4_positional,
47 dragon4_scientific,
48 ndarray,
49)
50from .numeric import asarray, concatenate, errstate
51from .numerictypes import complex128, flexible, float64, int_
52from .overrides import array_function_dispatch, set_module
53from .printoptions import format_options
54from .umath import absolute, isfinite, isinf, isnat
55
56
57def _make_options_dict(precision=None, threshold=None, edgeitems=None,
58 linewidth=None, suppress=None, nanstr=None, infstr=None,
59 sign=None, formatter=None, floatmode=None, legacy=None,
60 override_repr=None):
61 """
62 Make a dictionary out of the non-None arguments, plus conversion of
63 *legacy* and sanity checks.
64 """
65
66 options = {k: v for k, v in list(locals().items()) if v is not None}
67
68 if suppress is not None:
69 options['suppress'] = bool(suppress)
70
71 modes = ['fixed', 'unique', 'maxprec', 'maxprec_equal']
72 if floatmode not in modes + [None]:
73 raise ValueError("floatmode option must be one of " +
74 ", ".join(f'"{m}"' for m in modes))
75
76 if sign not in [None, '-', '+', ' ']:
77 raise ValueError("sign option must be one of ' ', '+', or '-'")
78
79 if legacy is False:
80 options['legacy'] = sys.maxsize
81 elif legacy == False: # noqa: E712
82 warnings.warn(
83 f"Passing `legacy={legacy!r}` is deprecated.",
84 FutureWarning, stacklevel=3
85 )
86 options['legacy'] = sys.maxsize
87 elif legacy == '1.13':
88 options['legacy'] = 113
89 elif legacy == '1.21':
90 options['legacy'] = 121
91 elif legacy == '1.25':
92 options['legacy'] = 125
93 elif legacy == '2.1':
94 options['legacy'] = 201
95 elif legacy == '2.2':
96 options['legacy'] = 202
97 elif legacy is None:
98 pass # OK, do nothing.
99 else:
100 warnings.warn(
101 "legacy printing option can currently only be '1.13', '1.21', "
102 "'1.25', '2.1', '2.2' or `False`", stacklevel=3)
103
104 if threshold is not None:
105 # forbid the bad threshold arg suggested by stack overflow, gh-12351
106 if not isinstance(threshold, numbers.Number):
107 raise TypeError("threshold must be numeric")
108 if np.isnan(threshold):
109 raise ValueError("threshold must be non-NAN, try "
110 "sys.maxsize for untruncated representation")
111
112 if precision is not None:
113 # forbid the bad precision arg as suggested by issue #18254
114 try:
115 options['precision'] = operator.index(precision)
116 except TypeError as e:
117 raise TypeError('precision must be an integer') from e
118
119 return options
120
121
122@set_module('numpy')
123def set_printoptions(precision=None, threshold=None, edgeitems=None,
124 linewidth=None, suppress=None, nanstr=None,
125 infstr=None, formatter=None, sign=None, floatmode=None,
126 *, legacy=None, override_repr=None):
127 """
128 Set printing options.
129
130 These options determine the way floating point numbers, arrays and
131 other NumPy objects are displayed.
132
133 Parameters
134 ----------
135 precision : int or None, optional
136 Number of digits of precision for floating point output (default 8).
137 May be None if `floatmode` is not `fixed`, to print as many digits as
138 necessary to uniquely specify the value.
139 threshold : int, optional
140 Total number of array elements which trigger summarization
141 rather than full repr (default 1000).
142 To always use the full repr without summarization, pass `sys.maxsize`.
143 edgeitems : int, optional
144 Number of array items in summary at beginning and end of
145 each dimension (default 3).
146 linewidth : int, optional
147 The number of characters per line for the purpose of inserting
148 line breaks (default 75).
149 suppress : bool, optional
150 If True, always print floating point numbers using fixed point
151 notation, in which case numbers equal to zero in the current precision
152 will print as zero. If False, then scientific notation is used when
153 absolute value of the smallest number is < 1e-4 or the ratio of the
154 maximum absolute value to the minimum is > 1e3. The default is False.
155 nanstr : str, optional
156 String representation of floating point not-a-number (default nan).
157 infstr : str, optional
158 String representation of floating point infinity (default inf).
159 sign : string, either '-', '+', or ' ', optional
160 Controls printing of the sign of floating-point types. If '+', always
161 print the sign of positive values. If ' ', always prints a space
162 (whitespace character) in the sign position of positive values. If
163 '-', omit the sign character of positive values. (default '-')
164
165 .. versionchanged:: 2.0
166 The sign parameter can now be an integer type, previously
167 types were floating-point types.
168
169 formatter : dict of callables, optional
170 If not None, the keys should indicate the type(s) that the respective
171 formatting function applies to. Callables should return a string.
172 Types that are not specified (by their corresponding keys) are handled
173 by the default formatters. Individual types for which a formatter
174 can be set are:
175
176 - 'bool'
177 - 'int'
178 - 'timedelta' : a `numpy.timedelta64`
179 - 'datetime' : a `numpy.datetime64`
180 - 'float'
181 - 'longfloat' : 128-bit floats
182 - 'complexfloat'
183 - 'longcomplexfloat' : composed of two 128-bit floats
184 - 'numpystr' : types `numpy.bytes_` and `numpy.str_`
185 - 'object' : `np.object_` arrays
186
187 Other keys that can be used to set a group of types at once are:
188
189 - 'all' : sets all types
190 - 'int_kind' : sets 'int'
191 - 'float_kind' : sets 'float' and 'longfloat'
192 - 'complex_kind' : sets 'complexfloat' and 'longcomplexfloat'
193 - 'str_kind' : sets 'numpystr'
194 floatmode : str, optional
195 Controls the interpretation of the `precision` option for
196 floating-point types. Can take the following values
197 (default maxprec_equal):
198
199 * 'fixed': Always print exactly `precision` fractional digits,
200 even if this would print more or fewer digits than
201 necessary to specify the value uniquely.
202 * 'unique': Print the minimum number of fractional digits necessary
203 to represent each value uniquely. Different elements may
204 have a different number of digits. The value of the
205 `precision` option is ignored.
206 * 'maxprec': Print at most `precision` fractional digits, but if
207 an element can be uniquely represented with fewer digits
208 only print it with that many.
209 * 'maxprec_equal': Print at most `precision` fractional digits,
210 but if every element in the array can be uniquely
211 represented with an equal number of fewer digits, use that
212 many digits for all elements.
213 legacy : string or `False`, optional
214 If set to the string ``'1.13'`` enables 1.13 legacy printing mode. This
215 approximates numpy 1.13 print output by including a space in the sign
216 position of floats and different behavior for 0d arrays. This also
217 enables 1.21 legacy printing mode (described below).
218
219 If set to the string ``'1.21'`` enables 1.21 legacy printing mode. This
220 approximates numpy 1.21 print output of complex structured dtypes
221 by not inserting spaces after commas that separate fields and after
222 colons.
223
224 If set to ``'1.25'`` approximates printing of 1.25 which mainly means
225 that numeric scalars are printed without their type information, e.g.
226 as ``3.0`` rather than ``np.float64(3.0)``.
227
228 If set to ``'2.1'``, shape information is not given when arrays are
229 summarized (i.e., multiple elements replaced with ``...``).
230
231 If set to ``'2.2'``, the transition to use scientific notation for
232 printing ``np.float16`` and ``np.float32`` types may happen later or
233 not at all for larger values.
234
235 If set to `False`, disables legacy mode.
236
237 Unrecognized strings will be ignored with a warning for forward
238 compatibility.
239
240 .. versionchanged:: 1.22.0
241 .. versionchanged:: 2.2
242
243 override_repr: callable, optional
244 If set a passed function will be used for generating arrays' repr.
245 Other options will be ignored.
246
247 See Also
248 --------
249 get_printoptions, printoptions, array2string
250
251
252 Notes
253 -----
254
255 * ``formatter`` is always reset with a call to `set_printoptions`.
256 * Use `printoptions` as a context manager to set the values temporarily.
257 * These print options apply only to NumPy ndarrays, not to scalars.
258
259 **Concurrency note:** see :ref:`text_formatting_options`
260
261 Examples
262 --------
263 Floating point precision can be set:
264
265 >>> import numpy as np
266 >>> np.set_printoptions(precision=4)
267 >>> np.array([1.123456789])
268 [1.1235]
269
270 Long arrays can be summarised:
271
272 >>> np.set_printoptions(threshold=5)
273 >>> np.arange(10)
274 array([0, 1, 2, ..., 7, 8, 9], shape=(10,))
275
276 Small results can be suppressed:
277
278 >>> eps = np.finfo(float).eps
279 >>> x = np.arange(4.)
280 >>> x**2 - (x + eps)**2
281 array([-4.9304e-32, -4.4409e-16, 0.0000e+00, 0.0000e+00])
282 >>> np.set_printoptions(suppress=True)
283 >>> x**2 - (x + eps)**2
284 array([-0., -0., 0., 0.])
285
286 A custom formatter can be used to display array elements as desired:
287
288 >>> np.set_printoptions(formatter={'all':lambda x: 'int: '+str(-x)})
289 >>> x = np.arange(3)
290 >>> x
291 array([int: 0, int: -1, int: -2])
292 >>> np.set_printoptions() # formatter gets reset
293 >>> x
294 array([0, 1, 2])
295
296 To put back the default options, you can use:
297
298 >>> np.set_printoptions(edgeitems=3, infstr='inf',
299 ... linewidth=75, nanstr='nan', precision=8,
300 ... suppress=False, threshold=1000, formatter=None)
301
302 Also to temporarily override options, use `printoptions`
303 as a context manager:
304
305 >>> with np.printoptions(precision=2, suppress=True, threshold=5):
306 ... np.linspace(0, 10, 10)
307 array([ 0. , 1.11, 2.22, ..., 7.78, 8.89, 10. ], shape=(10,))
308
309 """
310 _set_printoptions(precision, threshold, edgeitems, linewidth, suppress,
311 nanstr, infstr, formatter, sign, floatmode,
312 legacy=legacy, override_repr=override_repr)
313
314
315def _set_printoptions(precision=None, threshold=None, edgeitems=None,
316 linewidth=None, suppress=None, nanstr=None,
317 infstr=None, formatter=None, sign=None, floatmode=None,
318 *, legacy=None, override_repr=None):
319 new_opt = _make_options_dict(precision, threshold, edgeitems, linewidth,
320 suppress, nanstr, infstr, sign, formatter,
321 floatmode, legacy)
322 # formatter and override_repr are always reset
323 new_opt['formatter'] = formatter
324 new_opt['override_repr'] = override_repr
325
326 updated_opt = format_options.get() | new_opt
327 updated_opt.update(new_opt)
328
329 if updated_opt['legacy'] == 113:
330 updated_opt['sign'] = '-'
331
332 return format_options.set(updated_opt)
333
334
335@set_module('numpy')
336def get_printoptions():
337 """
338 Return the current print options.
339
340 Returns
341 -------
342 print_opts : dict
343 Dictionary of current print options with keys
344
345 - precision : int
346 - threshold : int
347 - edgeitems : int
348 - linewidth : int
349 - suppress : bool
350 - nanstr : str
351 - infstr : str
352 - sign : str
353 - formatter : dict of callables
354 - floatmode : str
355 - legacy : str or False
356
357 For a full description of these options, see `set_printoptions`.
358
359 Notes
360 -----
361 These print options apply only to NumPy ndarrays, not to scalars.
362
363 **Concurrency note:** see :ref:`text_formatting_options`
364
365 See Also
366 --------
367 set_printoptions, printoptions
368
369 Examples
370 --------
371 >>> import numpy as np
372
373 >>> np.get_printoptions()
374 {'edgeitems': 3, 'threshold': 1000, ..., 'override_repr': None}
375
376 >>> np.get_printoptions()['linewidth']
377 75
378 >>> np.set_printoptions(linewidth=100)
379 >>> np.get_printoptions()['linewidth']
380 100
381
382 """
383 opts = format_options.get().copy()
384 opts['legacy'] = {
385 113: '1.13', 121: '1.21', 125: '1.25', 201: '2.1',
386 202: '2.2', sys.maxsize: False,
387 }[opts['legacy']]
388 return opts
389
390
391def _get_legacy_print_mode():
392 """Return the legacy print mode as an int."""
393 return format_options.get()['legacy']
394
395
396@set_module('numpy')
397@contextlib.contextmanager
398def printoptions(*args, **kwargs):
399 """Context manager for setting print options.
400
401 Set print options for the scope of the `with` block, and restore the old
402 options at the end. See `set_printoptions` for the full description of
403 available options.
404
405 Examples
406 --------
407 >>> import numpy as np
408
409 >>> from numpy.testing import assert_equal
410 >>> with np.printoptions(precision=2):
411 ... np.array([2.0]) / 3
412 array([0.67])
413
414 The `as`-clause of the `with`-statement gives the current print options:
415
416 >>> with np.printoptions(precision=2) as opts:
417 ... assert_equal(opts, np.get_printoptions())
418
419 See Also
420 --------
421 set_printoptions, get_printoptions
422
423 Notes
424 -----
425 These print options apply only to NumPy ndarrays, not to scalars.
426
427 **Concurrency note:** see :ref:`text_formatting_options`
428
429 """
430 token = _set_printoptions(*args, **kwargs)
431
432 try:
433 yield get_printoptions()
434 finally:
435 format_options.reset(token)
436
437
438def _leading_trailing(a, edgeitems, index=()):
439 """
440 Keep only the N-D corners (leading and trailing edges) of an array.
441
442 Should be passed a base-class ndarray, since it makes no guarantees about
443 preserving subclasses.
444 """
445 axis = len(index)
446 if axis == a.ndim:
447 return a[index]
448
449 if a.shape[axis] > 2 * edgeitems:
450 return concatenate((
451 _leading_trailing(a, edgeitems, index + np.index_exp[:edgeitems]),
452 _leading_trailing(a, edgeitems, index + np.index_exp[-edgeitems:])
453 ), axis=axis)
454 else:
455 return _leading_trailing(a, edgeitems, index + np.index_exp[:])
456
457
458def _object_format(o):
459 """ Object arrays containing lists should be printed unambiguously """
460 if type(o) is list:
461 fmt = 'list({!r})'
462 else:
463 fmt = '{!r}'
464 return fmt.format(o)
465
466def repr_format(x):
467 if isinstance(x, (np.str_, np.bytes_)):
468 return repr(x.item())
469 return repr(x)
470
471def str_format(x):
472 if isinstance(x, (np.str_, np.bytes_)):
473 return str(x.item())
474 return str(x)
475
476def _get_formatdict(data, *, precision, floatmode, suppress, sign, legacy,
477 formatter, **kwargs):
478 # note: extra arguments in kwargs are ignored
479
480 # wrapped in lambdas to avoid taking a code path
481 # with the wrong type of data
482 formatdict = {
483 'bool': lambda: BoolFormat(data),
484 'int': lambda: IntegerFormat(data, sign),
485 'float': lambda: FloatingFormat(
486 data, precision, floatmode, suppress, sign, legacy=legacy),
487 'longfloat': lambda: FloatingFormat(
488 data, precision, floatmode, suppress, sign, legacy=legacy),
489 'complexfloat': lambda: ComplexFloatingFormat(
490 data, precision, floatmode, suppress, sign, legacy=legacy),
491 'longcomplexfloat': lambda: ComplexFloatingFormat(
492 data, precision, floatmode, suppress, sign, legacy=legacy),
493 'datetime': lambda: DatetimeFormat(data, legacy=legacy),
494 'timedelta': lambda: TimedeltaFormat(data),
495 'object': lambda: _object_format,
496 'void': lambda: str_format,
497 'numpystr': lambda: repr_format}
498
499 # we need to wrap values in `formatter` in a lambda, so that the interface
500 # is the same as the above values.
501 def indirect(x):
502 return lambda: x
503
504 if formatter is not None:
505 fkeys = [k for k in formatter.keys() if formatter[k] is not None]
506 if 'all' in fkeys:
507 for key in formatdict.keys():
508 formatdict[key] = indirect(formatter['all'])
509 if 'int_kind' in fkeys:
510 for key in ['int']:
511 formatdict[key] = indirect(formatter['int_kind'])
512 if 'float_kind' in fkeys:
513 for key in ['float', 'longfloat']:
514 formatdict[key] = indirect(formatter['float_kind'])
515 if 'complex_kind' in fkeys:
516 for key in ['complexfloat', 'longcomplexfloat']:
517 formatdict[key] = indirect(formatter['complex_kind'])
518 if 'str_kind' in fkeys:
519 formatdict['numpystr'] = indirect(formatter['str_kind'])
520 for key in formatdict.keys():
521 if key in fkeys:
522 formatdict[key] = indirect(formatter[key])
523
524 return formatdict
525
526def _get_format_function(data, **options):
527 """
528 find the right formatting function for the dtype_
529 """
530 dtype_ = data.dtype
531 dtypeobj = dtype_.type
532 formatdict = _get_formatdict(data, **options)
533 if dtypeobj is None:
534 return formatdict["numpystr"]()
535 elif issubclass(dtypeobj, _nt.bool):
536 return formatdict['bool']()
537 elif issubclass(dtypeobj, _nt.integer):
538 if issubclass(dtypeobj, _nt.timedelta64):
539 return formatdict['timedelta']()
540 else:
541 return formatdict['int']()
542 elif issubclass(dtypeobj, _nt.floating):
543 if issubclass(dtypeobj, _nt.longdouble):
544 return formatdict['longfloat']()
545 else:
546 return formatdict['float']()
547 elif issubclass(dtypeobj, _nt.complexfloating):
548 if issubclass(dtypeobj, _nt.clongdouble):
549 return formatdict['longcomplexfloat']()
550 else:
551 return formatdict['complexfloat']()
552 elif issubclass(dtypeobj, (_nt.str_, _nt.bytes_)):
553 return formatdict['numpystr']()
554 elif issubclass(dtypeobj, _nt.datetime64):
555 return formatdict['datetime']()
556 elif issubclass(dtypeobj, _nt.object_):
557 return formatdict['object']()
558 elif issubclass(dtypeobj, _nt.void):
559 if dtype_.names is not None:
560 return StructuredVoidFormat.from_data(data, **options)
561 else:
562 return formatdict['void']()
563 else:
564 return formatdict['numpystr']()
565
566
567def _recursive_guard(fillvalue='...'):
568 """
569 Like the python 3.2 reprlib.recursive_repr, but forwards *args and **kwargs
570
571 Decorates a function such that if it calls itself with the same first
572 argument, it returns `fillvalue` instead of recursing.
573
574 Largely copied from reprlib.recursive_repr
575 """
576
577 def decorating_function(f):
578 repr_running = set()
579
580 @functools.wraps(f)
581 def wrapper(self, *args, **kwargs):
582 key = id(self), get_ident()
583 if key in repr_running:
584 return fillvalue
585 repr_running.add(key)
586 try:
587 return f(self, *args, **kwargs)
588 finally:
589 repr_running.discard(key)
590
591 return wrapper
592
593 return decorating_function
594
595
596# gracefully handle recursive calls, when object arrays contain themselves
597@_recursive_guard()
598def _array2string(a, options, separator=' ', prefix=""):
599 # The formatter __init__s in _get_format_function cannot deal with
600 # subclasses yet, and we also need to avoid recursion issues in
601 # _formatArray with subclasses which return 0d arrays in place of scalars
602 data = asarray(a)
603 if a.shape == ():
604 a = data
605
606 if a.size > options['threshold']:
607 summary_insert = "..."
608 data = _leading_trailing(data, options['edgeitems'])
609 else:
610 summary_insert = ""
611
612 # find the right formatting function for the array
613 format_function = _get_format_function(data, **options)
614
615 # skip over "["
616 next_line_prefix = " "
617 # skip over array(
618 next_line_prefix += " " * len(prefix)
619
620 lst = _formatArray(a, format_function, options['linewidth'],
621 next_line_prefix, separator, options['edgeitems'],
622 summary_insert, options['legacy'])
623 return lst
624
625
626def _array2string_dispatcher(
627 a, max_line_width=None, precision=None,
628 suppress_small=None, separator=None, prefix=None,
629 *, formatter=None, threshold=None,
630 edgeitems=None, sign=None, floatmode=None, suffix=None,
631 legacy=None):
632 return (a,)
633
634
635@array_function_dispatch(_array2string_dispatcher, module='numpy')
636def array2string(a, max_line_width=None, precision=None,
637 suppress_small=None, separator=' ', prefix="",
638 *, formatter=None, threshold=None,
639 edgeitems=None, sign=None, floatmode=None, suffix="",
640 legacy=None):
641 """
642 Return a string representation of an array.
643
644 Parameters
645 ----------
646 a : ndarray
647 Input array.
648 max_line_width : int, optional
649 Inserts newlines if text is longer than `max_line_width`.
650 Defaults to ``numpy.get_printoptions()['linewidth']``.
651 precision : int or None, optional
652 Floating point precision.
653 Defaults to ``numpy.get_printoptions()['precision']``.
654 suppress_small : bool, optional
655 Represent numbers "very close" to zero as zero; default is False.
656 Very close is defined by precision: if the precision is 8, e.g.,
657 numbers smaller (in absolute value) than 5e-9 are represented as
658 zero.
659 Defaults to ``numpy.get_printoptions()['suppress']``.
660 separator : str, optional
661 Inserted between elements.
662 prefix : str, optional
663 suffix : str, optional
664 The length of the prefix and suffix strings are used to respectively
665 align and wrap the output. An array is typically printed as::
666
667 prefix + array2string(a) + suffix
668
669 The output is left-padded by the length of the prefix string, and
670 wrapping is forced at the column ``max_line_width - len(suffix)``.
671 It should be noted that the content of prefix and suffix strings are
672 not included in the output.
673 formatter : dict of callables, optional
674 If not None, the keys should indicate the type(s) that the respective
675 formatting function applies to. Callables should return a string.
676 Types that are not specified (by their corresponding keys) are handled
677 by the default formatters. Individual types for which a formatter
678 can be set are:
679
680 - 'bool'
681 - 'int'
682 - 'timedelta' : a `numpy.timedelta64`
683 - 'datetime' : a `numpy.datetime64`
684 - 'float'
685 - 'longfloat' : 128-bit floats
686 - 'complexfloat'
687 - 'longcomplexfloat' : composed of two 128-bit floats
688 - 'void' : type `numpy.void`
689 - 'numpystr' : types `numpy.bytes_` and `numpy.str_`
690
691 Other keys that can be used to set a group of types at once are:
692
693 - 'all' : sets all types
694 - 'int_kind' : sets 'int'
695 - 'float_kind' : sets 'float' and 'longfloat'
696 - 'complex_kind' : sets 'complexfloat' and 'longcomplexfloat'
697 - 'str_kind' : sets 'numpystr'
698 threshold : int, optional
699 Total number of array elements which trigger summarization
700 rather than full repr.
701 Defaults to ``numpy.get_printoptions()['threshold']``.
702 edgeitems : int, optional
703 Number of array items in summary at beginning and end of
704 each dimension.
705 Defaults to ``numpy.get_printoptions()['edgeitems']``.
706 sign : string, either '-', '+', or ' ', optional
707 Controls printing of the sign of floating-point types. If '+', always
708 print the sign of positive values. If ' ', always prints a space
709 (whitespace character) in the sign position of positive values. If
710 '-', omit the sign character of positive values.
711 Defaults to ``numpy.get_printoptions()['sign']``.
712
713 .. versionchanged:: 2.0
714 The sign parameter can now be an integer type, previously
715 types were floating-point types.
716
717 floatmode : str, optional
718 Controls the interpretation of the `precision` option for
719 floating-point types.
720 Defaults to ``numpy.get_printoptions()['floatmode']``.
721 Can take the following values:
722
723 - 'fixed': Always print exactly `precision` fractional digits,
724 even if this would print more or fewer digits than
725 necessary to specify the value uniquely.
726 - 'unique': Print the minimum number of fractional digits necessary
727 to represent each value uniquely. Different elements may
728 have a different number of digits. The value of the
729 `precision` option is ignored.
730 - 'maxprec': Print at most `precision` fractional digits, but if
731 an element can be uniquely represented with fewer digits
732 only print it with that many.
733 - 'maxprec_equal': Print at most `precision` fractional digits,
734 but if every element in the array can be uniquely
735 represented with an equal number of fewer digits, use that
736 many digits for all elements.
737 legacy : string or `False`, optional
738 If set to the string ``'1.13'`` enables 1.13 legacy printing mode. This
739 approximates numpy 1.13 print output by including a space in the sign
740 position of floats and different behavior for 0d arrays. If set to
741 `False`, disables legacy mode. Unrecognized strings will be ignored
742 with a warning for forward compatibility.
743
744 Returns
745 -------
746 array_str : str
747 String representation of the array.
748
749 Raises
750 ------
751 TypeError
752 if a callable in `formatter` does not return a string.
753
754 See Also
755 --------
756 array_str, array_repr, set_printoptions, get_printoptions
757
758 Notes
759 -----
760 If a formatter is specified for a certain type, the `precision` keyword is
761 ignored for that type.
762
763 This is a very flexible function; `array_repr` and `array_str` are using
764 `array2string` internally so keywords with the same name should work
765 identically in all three functions.
766
767 Examples
768 --------
769 >>> import numpy as np
770 >>> x = np.array([1e-16,1,2,3])
771 >>> np.array2string(x, precision=2, separator=',',
772 ... suppress_small=True)
773 '[0.,1.,2.,3.]'
774
775 >>> x = np.arange(3.)
776 >>> np.array2string(x, formatter={'float_kind':lambda x: "%.2f" % x})
777 '[0.00 1.00 2.00]'
778
779 >>> x = np.arange(3)
780 >>> np.array2string(x, formatter={'int':lambda x: hex(x)})
781 '[0x0 0x1 0x2]'
782
783 """
784
785 overrides = _make_options_dict(precision, threshold, edgeitems,
786 max_line_width, suppress_small, None, None,
787 sign, formatter, floatmode, legacy)
788 options = format_options.get().copy()
789 options.update(overrides)
790
791 if options['legacy'] <= 113:
792 if a.shape == () and a.dtype.names is None:
793 return repr(a.item())
794
795 if options['legacy'] > 113:
796 options['linewidth'] -= len(suffix)
797
798 # treat as a null array if any of shape elements == 0
799 if a.size == 0:
800 return "[]"
801
802 return _array2string(a, options, separator, prefix)
803
804
805def _extendLine(s, line, word, line_width, next_line_prefix, legacy):
806 needs_wrap = len(line) + len(word) > line_width
807 if legacy > 113:
808 # don't wrap lines if it won't help
809 if len(line) <= len(next_line_prefix):
810 needs_wrap = False
811
812 if needs_wrap:
813 s += line.rstrip() + "\n"
814 line = next_line_prefix
815 line += word
816 return s, line
817
818
819def _extendLine_pretty(s, line, word, line_width, next_line_prefix, legacy):
820 """
821 Extends line with nicely formatted (possibly multi-line) string ``word``.
822 """
823 words = word.splitlines()
824 if len(words) == 1 or legacy <= 113:
825 return _extendLine(s, line, word, line_width, next_line_prefix, legacy)
826
827 max_word_length = max(len(word) for word in words)
828 if (len(line) + max_word_length > line_width and
829 len(line) > len(next_line_prefix)):
830 s += line.rstrip() + '\n'
831 line = next_line_prefix + words[0]
832 indent = next_line_prefix
833 else:
834 indent = len(line) * ' '
835 line += words[0]
836
837 for word in words[1::]:
838 s += line.rstrip() + '\n'
839 line = indent + word
840
841 suffix_length = max_word_length - len(words[-1])
842 line += suffix_length * ' '
843
844 return s, line
845
846def _formatArray(a, format_function, line_width, next_line_prefix,
847 separator, edge_items, summary_insert, legacy):
848 """formatArray is designed for two modes of operation:
849
850 1. Full output
851
852 2. Summarized output
853
854 """
855 def recurser(index, hanging_indent, curr_width):
856 """
857 By using this local function, we don't need to recurse with all the
858 arguments. Since this function is not created recursively, the cost is
859 not significant
860 """
861 axis = len(index)
862 axes_left = a.ndim - axis
863
864 if axes_left == 0:
865 return format_function(a[index])
866
867 # when recursing, add a space to align with the [ added, and reduce the
868 # length of the line by 1
869 next_hanging_indent = hanging_indent + ' '
870 if legacy <= 113:
871 next_width = curr_width
872 else:
873 next_width = curr_width - len(']')
874
875 a_len = a.shape[axis]
876 show_summary = summary_insert and 2 * edge_items < a_len
877 if show_summary:
878 leading_items = edge_items
879 trailing_items = edge_items
880 else:
881 leading_items = 0
882 trailing_items = a_len
883
884 # stringify the array with the hanging indent on the first line too
885 s = ''
886
887 # last axis (rows) - wrap elements if they would not fit on one line
888 if axes_left == 1:
889 # the length up until the beginning of the separator / bracket
890 if legacy <= 113:
891 elem_width = curr_width - len(separator.rstrip())
892 else:
893 elem_width = curr_width - max(
894 len(separator.rstrip()), len(']')
895 )
896
897 line = hanging_indent
898 for i in range(leading_items):
899 word = recurser(index + (i,), next_hanging_indent, next_width)
900 s, line = _extendLine_pretty(
901 s, line, word, elem_width, hanging_indent, legacy)
902 line += separator
903
904 if show_summary:
905 s, line = _extendLine(
906 s, line, summary_insert, elem_width, hanging_indent, legacy
907 )
908 if legacy <= 113:
909 line += ", "
910 else:
911 line += separator
912
913 for i in range(trailing_items, 1, -1):
914 word = recurser(index + (-i,), next_hanging_indent, next_width)
915 s, line = _extendLine_pretty(
916 s, line, word, elem_width, hanging_indent, legacy)
917 line += separator
918
919 if legacy <= 113:
920 # width of the separator is not considered on 1.13
921 elem_width = curr_width
922 word = recurser(index + (-1,), next_hanging_indent, next_width)
923 s, line = _extendLine_pretty(
924 s, line, word, elem_width, hanging_indent, legacy)
925
926 s += line
927
928 # other axes - insert newlines between rows
929 else:
930 s = ''
931 line_sep = separator.rstrip() + '\n' * (axes_left - 1)
932
933 for i in range(leading_items):
934 nested = recurser(
935 index + (i,), next_hanging_indent, next_width
936 )
937 s += hanging_indent + nested + line_sep
938
939 if show_summary:
940 if legacy <= 113:
941 # trailing space, fixed nbr of newlines,
942 # and fixed separator
943 s += hanging_indent + summary_insert + ", \n"
944 else:
945 s += hanging_indent + summary_insert + line_sep
946
947 for i in range(trailing_items, 1, -1):
948 nested = recurser(index + (-i,), next_hanging_indent,
949 next_width)
950 s += hanging_indent + nested + line_sep
951
952 nested = recurser(index + (-1,), next_hanging_indent, next_width)
953 s += hanging_indent + nested
954
955 # remove the hanging indent, and wrap in []
956 s = '[' + s[len(hanging_indent):] + ']'
957 return s
958
959 try:
960 # invoke the recursive part with an initial index and prefix
961 return recurser(index=(),
962 hanging_indent=next_line_prefix,
963 curr_width=line_width)
964 finally:
965 # recursive closures have a cyclic reference to themselves, which
966 # requires gc to collect (gh-10620). To avoid this problem, for
967 # performance and PyPy friendliness, we break the cycle:
968 recurser = None
969
970def _none_or_positive_arg(x, name):
971 if x is None:
972 return -1
973 if x < 0:
974 raise ValueError(f"{name} must be >= 0")
975 return x
976
977class FloatingFormat:
978 """ Formatter for subtypes of np.floating """
979 def __init__(self, data, precision, floatmode, suppress_small, sign=False,
980 *, legacy=None):
981 # for backcompatibility, accept bools
982 if isinstance(sign, bool):
983 sign = '+' if sign else '-'
984
985 self._legacy = legacy
986 if self._legacy <= 113:
987 # when not 0d, legacy does not support '-'
988 if data.shape != () and sign == '-':
989 sign = ' '
990
991 self.floatmode = floatmode
992 if floatmode == 'unique':
993 self.precision = None
994 else:
995 self.precision = precision
996
997 self.precision = _none_or_positive_arg(self.precision, 'precision')
998
999 self.suppress_small = suppress_small
1000 self.sign = sign
1001 self.exp_format = False
1002 self.large_exponent = False
1003 self.fillFormat(data)
1004
1005 def fillFormat(self, data):
1006 # only the finite values are used to compute the number of digits
1007 finite_vals = data[isfinite(data)]
1008
1009 # choose exponential mode based on the non-zero finite values:
1010 abs_non_zero = absolute(finite_vals[finite_vals != 0])
1011 if len(abs_non_zero) != 0:
1012 max_val = np.max(abs_non_zero)
1013 min_val = np.min(abs_non_zero)
1014 if self._legacy <= 202:
1015 exp_cutoff_max = 1.e8
1016 else:
1017 # consider data type while deciding the max cutoff for exp format
1018 exp_cutoff_max = 10.**min(8, np.finfo(data.dtype).precision)
1019 with errstate(over='ignore'): # division can overflow
1020 if max_val >= exp_cutoff_max or (not self.suppress_small and
1021 (min_val < 0.0001 or max_val / min_val > 1000.)):
1022 self.exp_format = True
1023
1024 # do a first pass of printing all the numbers, to determine sizes
1025 if len(finite_vals) == 0:
1026 self.pad_left = 0
1027 self.pad_right = 0
1028 self.trim = '.'
1029 self.exp_size = -1
1030 self.unique = True
1031 self.min_digits = None
1032 elif self.exp_format:
1033 trim, unique = '.', True
1034 if self.floatmode == 'fixed' or self._legacy <= 113:
1035 trim, unique = 'k', False
1036 strs = (dragon4_scientific(x, precision=self.precision,
1037 unique=unique, trim=trim, sign=self.sign == '+')
1038 for x in finite_vals)
1039 frac_strs, _, exp_strs = zip(*(s.partition('e') for s in strs))
1040 int_part, frac_part = zip(*(s.split('.') for s in frac_strs))
1041 self.exp_size = max(len(s) for s in exp_strs) - 1
1042
1043 self.trim = 'k'
1044 self.precision = max(len(s) for s in frac_part)
1045 self.min_digits = self.precision
1046 self.unique = unique
1047
1048 # for back-compat with np 1.13, use 2 spaces & sign and full prec
1049 if self._legacy <= 113:
1050 self.pad_left = 3
1051 else:
1052 # this should be only 1 or 2. Can be calculated from sign.
1053 self.pad_left = max(len(s) for s in int_part)
1054 # pad_right is only needed for nan length calculation
1055 self.pad_right = self.exp_size + 2 + self.precision
1056 else:
1057 trim, unique = '.', True
1058 if self.floatmode == 'fixed':
1059 trim, unique = 'k', False
1060 strs = (dragon4_positional(x, precision=self.precision,
1061 fractional=True,
1062 unique=unique, trim=trim,
1063 sign=self.sign == '+')
1064 for x in finite_vals)
1065 int_part, frac_part = zip(*(s.split('.') for s in strs))
1066 if self._legacy <= 113:
1067 self.pad_left = 1 + max(len(s.lstrip('-+')) for s in int_part)
1068 else:
1069 self.pad_left = max(len(s) for s in int_part)
1070 self.pad_right = max(len(s) for s in frac_part)
1071 self.exp_size = -1
1072 self.unique = unique
1073
1074 if self.floatmode in ['fixed', 'maxprec_equal']:
1075 self.precision = self.min_digits = self.pad_right
1076 self.trim = 'k'
1077 else:
1078 self.trim = '.'
1079 self.min_digits = 0
1080
1081 if self._legacy > 113:
1082 # account for sign = ' ' by adding one to pad_left
1083 if self.sign == ' ' and not any(np.signbit(finite_vals)):
1084 self.pad_left += 1
1085
1086 # if there are non-finite values, may need to increase pad_left
1087 if data.size != finite_vals.size:
1088 neginf = self.sign != '-' or any(data[isinf(data)] < 0)
1089 offset = self.pad_right + 1 # +1 for decimal pt
1090 current_options = format_options.get()
1091 self.pad_left = max(
1092 self.pad_left, len(current_options['nanstr']) - offset,
1093 len(current_options['infstr']) + neginf - offset
1094 )
1095
1096 def __call__(self, x):
1097 if not np.isfinite(x):
1098 with errstate(invalid='ignore'):
1099 current_options = format_options.get()
1100 if np.isnan(x):
1101 sign = '+' if self.sign == '+' else ''
1102 ret = sign + current_options['nanstr']
1103 else: # isinf
1104 sign = '-' if x < 0 else '+' if self.sign == '+' else ''
1105 ret = sign + current_options['infstr']
1106 return ' ' * (
1107 self.pad_left + self.pad_right + 1 - len(ret)
1108 ) + ret
1109
1110 if self.exp_format:
1111 return dragon4_scientific(x,
1112 precision=self.precision,
1113 min_digits=self.min_digits,
1114 unique=self.unique,
1115 trim=self.trim,
1116 sign=self.sign == '+',
1117 pad_left=self.pad_left,
1118 exp_digits=self.exp_size)
1119 else:
1120 return dragon4_positional(x,
1121 precision=self.precision,
1122 min_digits=self.min_digits,
1123 unique=self.unique,
1124 fractional=True,
1125 trim=self.trim,
1126 sign=self.sign == '+',
1127 pad_left=self.pad_left,
1128 pad_right=self.pad_right)
1129
1130
1131@set_module('numpy')
1132def format_float_scientific(x, precision=None, unique=True, trim='k',
1133 sign=False, pad_left=None, exp_digits=None,
1134 min_digits=None):
1135 """
1136 Format a floating-point scalar as a decimal string in scientific notation.
1137
1138 Provides control over rounding, trimming and padding. Uses and assumes
1139 IEEE unbiased rounding. Uses the "Dragon4" algorithm.
1140
1141 Parameters
1142 ----------
1143 x : python float or numpy floating scalar
1144 Value to format.
1145 precision : non-negative integer or None, optional
1146 Maximum number of digits to print. May be None if `unique` is
1147 `True`, but must be an integer if unique is `False`.
1148 unique : boolean, optional
1149 If `True`, use a digit-generation strategy which gives the shortest
1150 representation which uniquely identifies the floating-point number from
1151 other values of the same type, by judicious rounding. If `precision`
1152 is given fewer digits than necessary can be printed. If `min_digits`
1153 is given more can be printed, in which cases the last digit is rounded
1154 with unbiased rounding.
1155 If `False`, digits are generated as if printing an infinite-precision
1156 value and stopping after `precision` digits, rounding the remaining
1157 value with unbiased rounding
1158 trim : one of 'k', '.', '0', '-', optional
1159 Controls post-processing trimming of trailing digits, as follows:
1160
1161 * 'k' : keep trailing zeros, keep decimal point (no trimming)
1162 * '.' : trim all trailing zeros, leave decimal point
1163 * '0' : trim all but the zero before the decimal point. Insert the
1164 zero if it is missing.
1165 * '-' : trim trailing zeros and any trailing decimal point
1166 sign : boolean, optional
1167 Whether to show the sign for positive values.
1168 pad_left : non-negative integer, optional
1169 Pad the left side of the string with whitespace until at least that
1170 many characters are to the left of the decimal point.
1171 exp_digits : non-negative integer, optional
1172 Pad the exponent with zeros until it contains at least this
1173 many digits. If omitted, the exponent will be at least 2 digits.
1174 min_digits : non-negative integer or None, optional
1175 Minimum number of digits to print. This only has an effect for
1176 `unique=True`. In that case more digits than necessary to uniquely
1177 identify the value may be printed and rounded unbiased.
1178
1179 .. versionadded:: 1.21.0
1180
1181 Returns
1182 -------
1183 rep : string
1184 The string representation of the floating point value
1185
1186 See Also
1187 --------
1188 format_float_positional
1189
1190 Examples
1191 --------
1192 >>> import numpy as np
1193 >>> np.format_float_scientific(np.float32(np.pi))
1194 '3.1415927e+00'
1195 >>> s = np.float32(1.23e24)
1196 >>> np.format_float_scientific(s, unique=False, precision=15)
1197 '1.230000071797338e+24'
1198 >>> np.format_float_scientific(s, exp_digits=4)
1199 '1.23e+0024'
1200 """
