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 """
1201 precision = _none_or_positive_arg(precision, 'precision')
1202 pad_left = _none_or_positive_arg(pad_left, 'pad_left')
1203 exp_digits = _none_or_positive_arg(exp_digits, 'exp_digits')
1204 min_digits = _none_or_positive_arg(min_digits, 'min_digits')
1205 if min_digits > 0 and precision > 0 and min_digits > precision:
1206 raise ValueError("min_digits must be less than or equal to precision")
1207 return dragon4_scientific(x, precision=precision, unique=unique,
1208 trim=trim, sign=sign, pad_left=pad_left,
1209 exp_digits=exp_digits, min_digits=min_digits)
1210
1211
1212@set_module('numpy')
1213def format_float_positional(x, precision=None, unique=True,
1214 fractional=True, trim='k', sign=False,
1215 pad_left=None, pad_right=None, min_digits=None):
1216 """
1217 Format a floating-point scalar as a decimal string in positional notation.
1218
1219 Provides control over rounding, trimming and padding. Uses and assumes
1220 IEEE unbiased rounding. Uses the "Dragon4" algorithm.
1221
1222 Parameters
1223 ----------
1224 x : python float or numpy floating scalar
1225 Value to format.
1226 precision : non-negative integer or None, optional
1227 Maximum number of digits to print. May be None if `unique` is
1228 `True`, but must be an integer if unique is `False`.
1229 unique : boolean, optional
1230 If `True`, use a digit-generation strategy which gives the shortest
1231 representation which uniquely identifies the floating-point number from
1232 other values of the same type, by judicious rounding. If `precision`
1233 is given fewer digits than necessary can be printed, or if `min_digits`
1234 is given more can be printed, in which cases the last digit is rounded
1235 with unbiased rounding.
1236 If `False`, digits are generated as if printing an infinite-precision
1237 value and stopping after `precision` digits, rounding the remaining
1238 value with unbiased rounding
1239 fractional : boolean, optional
1240 If `True`, the cutoffs of `precision` and `min_digits` refer to the
1241 total number of digits after the decimal point, including leading
1242 zeros.
1243 If `False`, `precision` and `min_digits` refer to the total number of
1244 significant digits, before or after the decimal point, ignoring leading
1245 zeros.
1246 trim : one of 'k', '.', '0', '-', optional
1247 Controls post-processing trimming of trailing digits, as follows:
1248
1249 * 'k' : keep trailing zeros, keep decimal point (no trimming)
1250 * '.' : trim all trailing zeros, leave decimal point
1251 * '0' : trim all but the zero before the decimal point. Insert the
1252 zero if it is missing.
1253 * '-' : trim trailing zeros and any trailing decimal point
1254 sign : boolean, optional
1255 Whether to show the sign for positive values.
1256 pad_left : non-negative integer, optional
1257 Pad the left side of the string with whitespace until at least that
1258 many characters are to the left of the decimal point.
1259 pad_right : non-negative integer, optional
1260 Pad the right side of the string with whitespace until at least that
1261 many characters are to the right of the decimal point.
1262 min_digits : non-negative integer or None, optional
1263 Minimum number of digits to print. Only has an effect if `unique=True`
1264 in which case additional digits past those necessary to uniquely
1265 identify the value may be printed, rounding the last additional digit.
1266
1267 .. versionadded:: 1.21.0
1268
1269 Returns
1270 -------
1271 rep : string
1272 The string representation of the floating point value
1273
1274 See Also
1275 --------
1276 format_float_scientific
1277
1278 Examples
1279 --------
1280 >>> import numpy as np
1281 >>> np.format_float_positional(np.float32(np.pi))
1282 '3.1415927'
1283 >>> np.format_float_positional(np.float16(np.pi))
1284 '3.14'
1285 >>> np.format_float_positional(np.float16(0.3))
1286 '0.3'
1287 >>> np.format_float_positional(np.float16(0.3), unique=False, precision=10)
1288 '0.3000488281'
1289 """
1290 precision = _none_or_positive_arg(precision, 'precision')
1291 pad_left = _none_or_positive_arg(pad_left, 'pad_left')
1292 pad_right = _none_or_positive_arg(pad_right, 'pad_right')
1293 min_digits = _none_or_positive_arg(min_digits, 'min_digits')
1294 if not fractional and precision == 0:
1295 raise ValueError("precision must be greater than 0 if "
1296 "fractional=False")
1297 if min_digits > 0 and precision > 0 and min_digits > precision:
1298 raise ValueError("min_digits must be less than or equal to precision")
1299 return dragon4_positional(x, precision=precision, unique=unique,
1300 fractional=fractional, trim=trim,
1301 sign=sign, pad_left=pad_left,
1302 pad_right=pad_right, min_digits=min_digits)
1303
1304class IntegerFormat:
1305 def __init__(self, data, sign='-'):
1306 if data.size > 0:
1307 data_max = np.max(data)
1308 data_min = np.min(data)
1309 data_max_str_len = len(str(data_max))
1310 if sign == ' ' and data_min < 0:
1311 sign = '-'
1312 if data_max >= 0 and sign in "+ ":
1313 data_max_str_len += 1
1314 max_str_len = max(data_max_str_len,
1315 len(str(data_min)))
1316 else:
1317 max_str_len = 0
1318 self.format = f'{{:{sign}{max_str_len}d}}'
1319
1320 def __call__(self, x):
1321 return self.format.format(x)
1322
1323class BoolFormat:
1324 def __init__(self, data, **kwargs):
1325 # add an extra space so " True" and "False" have the same length and
1326 # array elements align nicely when printed, except in 0d arrays
1327 self.truestr = ' True' if data.shape != () else 'True'
1328
1329 def __call__(self, x):
1330 return self.truestr if x else "False"
1331
1332
1333class ComplexFloatingFormat:
1334 """ Formatter for subtypes of np.complexfloating """
1335 def __init__(self, x, precision, floatmode, suppress_small,
1336 sign=False, *, legacy=None):
1337 # for backcompatibility, accept bools
1338 if isinstance(sign, bool):
1339 sign = '+' if sign else '-'
1340
1341 floatmode_real = floatmode_imag = floatmode
1342 if legacy <= 113:
1343 floatmode_real = 'maxprec_equal'
1344 floatmode_imag = 'maxprec'
1345
1346 self.real_format = FloatingFormat(
1347 x.real, precision, floatmode_real, suppress_small,
1348 sign=sign, legacy=legacy
1349 )
1350 self.imag_format = FloatingFormat(
1351 x.imag, precision, floatmode_imag, suppress_small,
1352 sign='+', legacy=legacy
1353 )
1354
1355 def __call__(self, x):
1356 r = self.real_format(x.real)
1357 i = self.imag_format(x.imag)
1358
1359 # add the 'j' before the terminal whitespace in i
1360 sp = len(i.rstrip())
1361 i = i[:sp] + 'j' + i[sp:]
1362
1363 return r + i
1364
1365
1366class _TimelikeFormat:
1367 def __init__(self, data):
1368 non_nat = data[~isnat(data)]
1369 if len(non_nat) > 0:
1370 # Max str length of non-NaT elements
1371 max_str_len = max(len(self._format_non_nat(np.max(non_nat))),
1372 len(self._format_non_nat(np.min(non_nat))))
1373 else:
1374 max_str_len = 0
1375 if len(non_nat) < data.size:
1376 # data contains a NaT
1377 max_str_len = max(max_str_len, 5)
1378 self._format = f'%{max_str_len}s'
1379 self._nat = "'NaT'".rjust(max_str_len)
1380
1381 def _format_non_nat(self, x):
1382 # override in subclass
1383 raise NotImplementedError
1384
1385 def __call__(self, x):
1386 if isnat(x):
1387 return self._nat
1388 else:
1389 return self._format % self._format_non_nat(x)
1390
1391
1392class DatetimeFormat(_TimelikeFormat):
1393 def __init__(self, x, unit=None, timezone=None, casting='same_kind',
1394 legacy=False):
1395 # Get the unit from the dtype
1396 if unit is None:
1397 if x.dtype.kind == 'M':
1398 unit = datetime_data(x.dtype)[0]
1399 else:
1400 unit = 's'
1401
1402 if timezone is None:
1403 timezone = 'naive'
1404 self.timezone = timezone
1405 self.unit = unit
1406 self.casting = casting
1407 self.legacy = legacy
1408
1409 # must be called after the above are configured
1410 super().__init__(x)
1411
1412 def __call__(self, x):
1413 if self.legacy <= 113:
1414 return self._format_non_nat(x)
1415 return super().__call__(x)
1416
1417 def _format_non_nat(self, x):
1418 return "'%s'" % datetime_as_string(x,
1419 unit=self.unit,
1420 timezone=self.timezone,
1421 casting=self.casting)
1422
1423
1424class TimedeltaFormat(_TimelikeFormat):
1425 def _format_non_nat(self, x):
1426 return str(x.astype('i8'))
1427
1428
1429class SubArrayFormat:
1430 def __init__(self, format_function, **options):
1431 self.format_function = format_function
1432 self.threshold = options['threshold']
1433 self.edge_items = options['edgeitems']
1434
1435 def __call__(self, a):
1436 self.summary_insert = "..." if a.size > self.threshold else ""
1437 return self.format_array(a)
1438
1439 def format_array(self, a):
1440 if np.ndim(a) == 0:
1441 return self.format_function(a)
1442
1443 if self.summary_insert and a.shape[0] > 2 * self.edge_items:
1444 formatted = (
1445 [self.format_array(a_) for a_ in a[:self.edge_items]]
1446 + [self.summary_insert]
1447 + [self.format_array(a_) for a_ in a[-self.edge_items:]]
1448 )
1449 else:
1450 formatted = [self.format_array(a_) for a_ in a]
1451
1452 return "[" + ", ".join(formatted) + "]"
1453
1454
1455class StructuredVoidFormat:
1456 """
1457 Formatter for structured np.void objects.
1458
1459 This does not work on structured alias types like
1460 np.dtype(('i4', 'i2,i2')), as alias scalars lose their field information,
1461 and the implementation relies upon np.void.__getitem__.
1462 """
1463 def __init__(self, format_functions):
1464 self.format_functions = format_functions
1465
1466 @classmethod
1467 def from_data(cls, data, **options):
1468 """
1469 This is a second way to initialize StructuredVoidFormat,
1470 using the raw data as input. Added to avoid changing
1471 the signature of __init__.
1472 """
1473 format_functions = []
1474 for field_name in data.dtype.names:
1475 format_function = _get_format_function(data[field_name], **options)
1476 if data.dtype[field_name].shape != ():
1477 format_function = SubArrayFormat(format_function, **options)
1478 format_functions.append(format_function)
1479 return cls(format_functions)
1480
1481 def __call__(self, x):
1482 str_fields = [
1483 format_function(field)
1484 for field, format_function in zip(x, self.format_functions)
1485 ]
1486 if len(str_fields) == 1:
1487 return f"({str_fields[0]},)"
1488 else:
1489 return f"({', '.join(str_fields)})"
1490
1491
1492def _void_scalar_to_string(x, is_repr=True):
1493 """
1494 Implements the repr for structured-void scalars. It is called from the
1495 scalartypes.c.src code, and is placed here because it uses the elementwise
1496 formatters defined above.
1497 """
1498 options = format_options.get().copy()
1499
1500 if options["legacy"] <= 125:
1501 return StructuredVoidFormat.from_data(array(x), **options)(x)
1502
1503 if options.get('formatter') is None:
1504 options['formatter'] = {}
1505 options['formatter'].setdefault('float_kind', str)
1506 val_repr = StructuredVoidFormat.from_data(array(x), **options)(x)
1507 if not is_repr:
1508 return val_repr
1509 cls = type(x)
1510 cls_fqn = cls.__module__.replace("numpy", "np") + "." + cls.__name__
1511 void_dtype = np.dtype((np.void, x.dtype))
1512 return f"{cls_fqn}({val_repr}, dtype={void_dtype!s})"
1513
1514
1515_typelessdata = [int_, float64, complex128, _nt.bool]
1516
1517
1518def dtype_is_implied(dtype):
1519 """
1520 Determine if the given dtype is implied by the representation
1521 of its values.
1522
1523 Parameters
1524 ----------
1525 dtype : dtype
1526 Data type
1527
1528 Returns
1529 -------
1530 implied : bool
1531 True if the dtype is implied by the representation of its values.
1532
1533 Examples
1534 --------
1535 >>> import numpy as np
1536 >>> np._core.arrayprint.dtype_is_implied(int)
1537 True
1538 >>> np.array([1, 2, 3], int)
1539 array([1, 2, 3])
1540 >>> np._core.arrayprint.dtype_is_implied(np.int8)
1541 False
1542 >>> np.array([1, 2, 3], np.int8)
1543 array([1, 2, 3], dtype=int8)
1544 """
1545 dtype = np.dtype(dtype)
1546 if format_options.get()['legacy'] <= 113 and dtype.type == np.bool:
1547 return False
1548
1549 # not just void types can be structured, and names are not part of the repr
1550 if dtype.names is not None:
1551 return False
1552
1553 # should care about endianness *unless size is 1* (e.g., int8, bool)
1554 if not dtype.isnative:
1555 return False
1556
1557 return dtype.type in _typelessdata
1558
1559
1560def dtype_short_repr(dtype):
1561 """
1562 Convert a dtype to a short form which evaluates to the same dtype.
1563
1564 The intent is roughly that the following holds
1565
1566 >>> from numpy import *
1567 >>> dt = np.int64([1, 2]).dtype
1568 >>> assert eval(dtype_short_repr(dt)) == dt
1569 """
1570 if type(dtype).__repr__ != np.dtype.__repr__:
1571 # TODO: Custom repr for user DTypes, logic should likely move.
1572 return repr(dtype)
1573 if dtype.names is not None:
1574 # structured dtypes give a list or tuple repr
1575 return str(dtype)
1576 elif issubclass(dtype.type, flexible):
1577 # handle these separately so they don't give garbage like str256
1578 return f"'{str(dtype)}'"
1579
1580 typename = dtype.name
1581 if not dtype.isnative:
1582 # deal with cases like dtype('<u2') that are identical to an
1583 # established dtype (in this case uint16)
1584 # except that they have a different endianness.
1585 return f"'{str(dtype)}'"
1586 # quote typenames which can't be represented as python variable names
1587 if typename and not (typename[0].isalpha() and typename.isalnum()):
1588 typename = repr(typename)
1589 return typename
1590
1591
1592def _array_repr_implementation(
1593 arr, max_line_width=None, precision=None, suppress_small=None,
1594 array2string=array2string):
1595 """Internal version of array_repr() that allows overriding array2string."""
1596 current_options = format_options.get()
1597 override_repr = current_options["override_repr"]
1598 if override_repr is not None:
1599 return override_repr(arr)
1600
1601 if max_line_width is None:
1602 max_line_width = current_options['linewidth']
1603
1604 if type(arr) is not ndarray:
1605 class_name = type(arr).__name__
1606 else:
1607 class_name = "array"
1608
1609 prefix = class_name + "("
1610 if (current_options['legacy'] <= 113 and
1611 arr.shape == () and not arr.dtype.names):
1612 lst = repr(arr.item())
1613 else:
1614 lst = array2string(arr, max_line_width, precision, suppress_small,
1615 ', ', prefix, suffix=")")
1616
1617 # Add dtype and shape information if these cannot be inferred from
1618 # the array string.
1619 extras = []
1620 if ((arr.size == 0 and arr.shape != (0,))
1621 or (current_options['legacy'] > 210
1622 and arr.size > current_options['threshold'])):
1623 extras.append(f"shape={arr.shape}")
1624 if not dtype_is_implied(arr.dtype) or arr.size == 0:
1625 extras.append(f"dtype={dtype_short_repr(arr.dtype)}")
1626
1627 if not extras:
1628 return prefix + lst + ")"
1629
1630 arr_str = prefix + lst + ","
1631 extra_str = ", ".join(extras) + ")"
1632 # compute whether we should put extras on a new line: Do so if adding the
1633 # extras would extend the last line past max_line_width.
1634 # Note: This line gives the correct result even when rfind returns -1.
1635 last_line_len = len(arr_str) - (arr_str.rfind('\n') + 1)
1636 spacer = " "
1637 if current_options['legacy'] <= 113:
1638 if issubclass(arr.dtype.type, flexible):
1639 spacer = '\n' + ' ' * len(prefix)
1640 elif last_line_len + len(extra_str) + 1 > max_line_width:
1641 spacer = '\n' + ' ' * len(prefix)
1642
1643 return arr_str + spacer + extra_str
1644
1645
1646def _array_repr_dispatcher(
1647 arr, max_line_width=None, precision=None, suppress_small=None):
1648 return (arr,)
1649
1650
1651@array_function_dispatch(_array_repr_dispatcher, module='numpy')
1652def array_repr(arr, max_line_width=None, precision=None, suppress_small=None):
1653 """
1654 Return the string representation of an array.
1655
1656 Parameters
1657 ----------
1658 arr : ndarray
1659 Input array.
1660 max_line_width : int, optional
1661 Inserts newlines if text is longer than `max_line_width`.
1662 Defaults to ``numpy.get_printoptions()['linewidth']``.
1663 precision : int, optional
1664 Floating point precision.
1665 Defaults to ``numpy.get_printoptions()['precision']``.
1666 suppress_small : bool, optional
1667 Represent numbers "very close" to zero as zero; default is False.
1668 Very close is defined by precision: if the precision is 8, e.g.,
1669 numbers smaller (in absolute value) than 5e-9 are represented as
1670 zero.
1671 Defaults to ``numpy.get_printoptions()['suppress']``.
1672
1673 Returns
1674 -------
1675 string : str
1676 The string representation of an array.
1677
1678 See Also
1679 --------
1680 array_str, array2string, set_printoptions
1681
1682 Examples
1683 --------
1684 >>> import numpy as np
1685 >>> np.array_repr(np.array([1,2]))
1686 'array([1, 2])'
1687 >>> np.array_repr(np.ma.array([0.]))
1688 'MaskedArray([0.])'
1689 >>> np.array_repr(np.array([], np.int32))
1690 'array([], dtype=int32)'
1691
1692 >>> x = np.array([1e-6, 4e-7, 2, 3])
1693 >>> np.array_repr(x, precision=6, suppress_small=True)
1694 'array([0.000001, 0. , 2. , 3. ])'
1695
1696 """
1697 return _array_repr_implementation(
1698 arr, max_line_width, precision, suppress_small)
1699
1700
1701@_recursive_guard()
1702def _guarded_repr_or_str(v):
1703 if isinstance(v, bytes):
1704 return repr(v)
1705 return str(v)
1706
1707
1708def _array_str_implementation(
1709 a, max_line_width=None, precision=None, suppress_small=None,
1710 array2string=array2string):
1711 """Internal version of array_str() that allows overriding array2string."""
1712 if (format_options.get()['legacy'] <= 113 and
1713 a.shape == () and not a.dtype.names):
1714 return str(a.item())
1715
1716 # the str of 0d arrays is a special case: It should appear like a scalar,
1717 # so floats are not truncated by `precision`, and strings are not wrapped
1718 # in quotes. So we return the str of the scalar value.
1719 if a.shape == ():
1720 # obtain a scalar and call str on it, avoiding problems for subclasses
1721 # for which indexing with () returns a 0d instead of a scalar by using
1722 # ndarray's getindex. Also guard against recursive 0d object arrays.
1723 return _guarded_repr_or_str(np.ndarray.__getitem__(a, ()))
1724
1725 return array2string(a, max_line_width, precision, suppress_small, ' ', "")
1726
1727
1728def _array_str_dispatcher(
1729 a, max_line_width=None, precision=None, suppress_small=None):
1730 return (a,)
1731
1732
1733@array_function_dispatch(_array_str_dispatcher, module='numpy')
1734def array_str(a, max_line_width=None, precision=None, suppress_small=None):
1735 """
1736 Return a string representation of the data in an array.
1737
1738 The data in the array is returned as a single string. This function is
1739 similar to `array_repr`, the difference being that `array_repr` also
1740 returns information on the kind of array and its data type.
1741
1742 Parameters
1743 ----------
1744 a : ndarray
1745 Input array.
1746 max_line_width : int, optional
1747 Inserts newlines if text is longer than `max_line_width`.
1748 Defaults to ``numpy.get_printoptions()['linewidth']``.
1749 precision : int, optional
1750 Floating point precision.
1751 Defaults to ``numpy.get_printoptions()['precision']``.
1752 suppress_small : bool, optional
1753 Represent numbers "very close" to zero as zero; default is False.
1754 Very close is defined by precision: if the precision is 8, e.g.,
1755 numbers smaller (in absolute value) than 5e-9 are represented as
1756 zero.
1757 Defaults to ``numpy.get_printoptions()['suppress']``.
1758
1759 See Also
1760 --------
1761 array2string, array_repr, set_printoptions
1762
1763 Examples
1764 --------
1765 >>> import numpy as np
1766 >>> np.array_str(np.arange(3))
1767 '[0 1 2]'
1768
1769 """
1770 return _array_str_implementation(
1771 a, max_line_width, precision, suppress_small)
1772
1773
1774# needed if __array_function__ is disabled
1775_array2string_impl = getattr(array2string, '__wrapped__', array2string)
1776_default_array_str = functools.partial(_array_str_implementation,
1777 array2string=_array2string_impl)
1778_default_array_repr = functools.partial(_array_repr_implementation,
1779 array2string=_array2string_impl)