123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701 |
- """Array printing function
- $Id: arrayprint.py,v 1.9 2005/09/13 13:58:44 teoliphant Exp $
- """
- __all__ = ["array2string", "array_str", "array_repr", "set_string_function",
- "set_printoptions", "get_printoptions", "printoptions",
- "format_float_positional", "format_float_scientific"]
- __docformat__ = 'restructuredtext'
- #
- # Written by Konrad Hinsen <hinsenk@ere.umontreal.ca>
- # last revision: 1996-3-13
- # modified by Jim Hugunin 1997-3-3 for repr's and str's (and other details)
- # and by Perry Greenfield 2000-4-1 for numarray
- # and by Travis Oliphant 2005-8-22 for numpy
- # Note: Both scalartypes.c.src and arrayprint.py implement strs for numpy
- # scalars but for different purposes. scalartypes.c.src has str/reprs for when
- # the scalar is printed on its own, while arrayprint.py has strs for when
- # scalars are printed inside an ndarray. Only the latter strs are currently
- # user-customizable.
- import functools
- import numbers
- import sys
- try:
- from _thread import get_ident
- except ImportError:
- from _dummy_thread import get_ident
- import numpy as np
- from . import numerictypes as _nt
- from .umath import absolute, isinf, isfinite, isnat
- from . import multiarray
- from .multiarray import (array, dragon4_positional, dragon4_scientific,
- datetime_as_string, datetime_data, ndarray,
- set_legacy_print_mode)
- from .fromnumeric import any
- from .numeric import concatenate, asarray, errstate
- from .numerictypes import (longlong, intc, int_, float_, complex_, bool_,
- flexible)
- from .overrides import array_function_dispatch, set_module
- import operator
- import warnings
- import contextlib
- _format_options = {
- 'edgeitems': 3, # repr N leading and trailing items of each dimension
- 'threshold': 1000, # total items > triggers array summarization
- 'floatmode': 'maxprec',
- 'precision': 8, # precision of floating point representations
- 'suppress': False, # suppress printing small floating values in exp format
- 'linewidth': 75,
- 'nanstr': 'nan',
- 'infstr': 'inf',
- 'sign': '-',
- 'formatter': None,
- # Internally stored as an int to simplify comparisons; converted from/to
- # str/False on the way in/out.
- 'legacy': sys.maxsize}
- def _make_options_dict(precision=None, threshold=None, edgeitems=None,
- linewidth=None, suppress=None, nanstr=None, infstr=None,
- sign=None, formatter=None, floatmode=None, legacy=None):
- """
- Make a dictionary out of the non-None arguments, plus conversion of
- *legacy* and sanity checks.
- """
- options = {k: v for k, v in locals().items() if v is not None}
- if suppress is not None:
- options['suppress'] = bool(suppress)
- modes = ['fixed', 'unique', 'maxprec', 'maxprec_equal']
- if floatmode not in modes + [None]:
- raise ValueError("floatmode option must be one of " +
- ", ".join('"{}"'.format(m) for m in modes))
- if sign not in [None, '-', '+', ' ']:
- raise ValueError("sign option must be one of ' ', '+', or '-'")
- if legacy == False:
- options['legacy'] = sys.maxsize
- elif legacy == '1.13':
- options['legacy'] = 113
- elif legacy == '1.21':
- options['legacy'] = 121
- elif legacy is None:
- pass # OK, do nothing.
- else:
- warnings.warn(
- "legacy printing option can currently only be '1.13', '1.21', or "
- "`False`", stacklevel=3)
- if threshold is not None:
- # forbid the bad threshold arg suggested by stack overflow, gh-12351
- if not isinstance(threshold, numbers.Number):
- raise TypeError("threshold must be numeric")
- if np.isnan(threshold):
- raise ValueError("threshold must be non-NAN, try "
- "sys.maxsize for untruncated representation")
- if precision is not None:
- # forbid the bad precision arg as suggested by issue #18254
- try:
- options['precision'] = operator.index(precision)
- except TypeError as e:
- raise TypeError('precision must be an integer') from e
- return options
- @set_module('numpy')
- def set_printoptions(precision=None, threshold=None, edgeitems=None,
- linewidth=None, suppress=None, nanstr=None, infstr=None,
- formatter=None, sign=None, floatmode=None, *, legacy=None):
- """
- Set printing options.
- These options determine the way floating point numbers, arrays and
- other NumPy objects are displayed.
- Parameters
- ----------
- precision : int or None, optional
- Number of digits of precision for floating point output (default 8).
- May be None if `floatmode` is not `fixed`, to print as many digits as
- necessary to uniquely specify the value.
- threshold : int, optional
- Total number of array elements which trigger summarization
- rather than full repr (default 1000).
- To always use the full repr without summarization, pass `sys.maxsize`.
- edgeitems : int, optional
- Number of array items in summary at beginning and end of
- each dimension (default 3).
- linewidth : int, optional
- The number of characters per line for the purpose of inserting
- line breaks (default 75).
- suppress : bool, optional
- If True, always print floating point numbers using fixed point
- notation, in which case numbers equal to zero in the current precision
- will print as zero. If False, then scientific notation is used when
- absolute value of the smallest number is < 1e-4 or the ratio of the
- maximum absolute value to the minimum is > 1e3. The default is False.
- nanstr : str, optional
- String representation of floating point not-a-number (default nan).
- infstr : str, optional
- String representation of floating point infinity (default inf).
- sign : string, either '-', '+', or ' ', optional
- Controls printing of the sign of floating-point types. If '+', always
- print the sign of positive values. If ' ', always prints a space
- (whitespace character) in the sign position of positive values. If
- '-', omit the sign character of positive values. (default '-')
- formatter : dict of callables, optional
- If not None, the keys should indicate the type(s) that the respective
- formatting function applies to. Callables should return a string.
- Types that are not specified (by their corresponding keys) are handled
- by the default formatters. Individual types for which a formatter
- can be set are:
- - 'bool'
- - 'int'
- - 'timedelta' : a `numpy.timedelta64`
- - 'datetime' : a `numpy.datetime64`
- - 'float'
- - 'longfloat' : 128-bit floats
- - 'complexfloat'
- - 'longcomplexfloat' : composed of two 128-bit floats
- - 'numpystr' : types `numpy.string_` and `numpy.unicode_`
- - 'object' : `np.object_` arrays
- Other keys that can be used to set a group of types at once are:
- - 'all' : sets all types
- - 'int_kind' : sets 'int'
- - 'float_kind' : sets 'float' and 'longfloat'
- - 'complex_kind' : sets 'complexfloat' and 'longcomplexfloat'
- - 'str_kind' : sets 'numpystr'
- floatmode : str, optional
- Controls the interpretation of the `precision` option for
- floating-point types. Can take the following values
- (default maxprec_equal):
- * 'fixed': Always print exactly `precision` fractional digits,
- even if this would print more or fewer digits than
- necessary to specify the value uniquely.
- * 'unique': Print the minimum number of fractional digits necessary
- to represent each value uniquely. Different elements may
- have a different number of digits. The value of the
- `precision` option is ignored.
- * 'maxprec': Print at most `precision` fractional digits, but if
- an element can be uniquely represented with fewer digits
- only print it with that many.
- * 'maxprec_equal': Print at most `precision` fractional digits,
- but if every element in the array can be uniquely
- represented with an equal number of fewer digits, use that
- many digits for all elements.
- legacy : string or `False`, optional
- If set to the string `'1.13'` enables 1.13 legacy printing mode. This
- approximates numpy 1.13 print output by including a space in the sign
- position of floats and different behavior for 0d arrays. This also
- enables 1.21 legacy printing mode (described below).
- If set to the string `'1.21'` enables 1.21 legacy printing mode. This
- approximates numpy 1.21 print output of complex structured dtypes
- by not inserting spaces after commas that separate fields and after
- colons.
- If set to `False`, disables legacy mode.
- Unrecognized strings will be ignored with a warning for forward
- compatibility.
- .. versionadded:: 1.14.0
- .. versionchanged:: 1.22.0
- See Also
- --------
- get_printoptions, printoptions, set_string_function, array2string
- Notes
- -----
- `formatter` is always reset with a call to `set_printoptions`.
- Use `printoptions` as a context manager to set the values temporarily.
- Examples
- --------
- Floating point precision can be set:
- >>> np.set_printoptions(precision=4)
- >>> np.array([1.123456789])
- [1.1235]
- Long arrays can be summarised:
- >>> np.set_printoptions(threshold=5)
- >>> np.arange(10)
- array([0, 1, 2, ..., 7, 8, 9])
- Small results can be suppressed:
- >>> eps = np.finfo(float).eps
- >>> x = np.arange(4.)
- >>> x**2 - (x + eps)**2
- array([-4.9304e-32, -4.4409e-16, 0.0000e+00, 0.0000e+00])
- >>> np.set_printoptions(suppress=True)
- >>> x**2 - (x + eps)**2
- array([-0., -0., 0., 0.])
- A custom formatter can be used to display array elements as desired:
- >>> np.set_printoptions(formatter={'all':lambda x: 'int: '+str(-x)})
- >>> x = np.arange(3)
- >>> x
- array([int: 0, int: -1, int: -2])
- >>> np.set_printoptions() # formatter gets reset
- >>> x
- array([0, 1, 2])
- To put back the default options, you can use:
- >>> np.set_printoptions(edgeitems=3, infstr='inf',
- ... linewidth=75, nanstr='nan', precision=8,
- ... suppress=False, threshold=1000, formatter=None)
- Also to temporarily override options, use `printoptions` as a context manager:
- >>> with np.printoptions(precision=2, suppress=True, threshold=5):
- ... np.linspace(0, 10, 10)
- array([ 0. , 1.11, 2.22, ..., 7.78, 8.89, 10. ])
- """
- opt = _make_options_dict(precision, threshold, edgeitems, linewidth,
- suppress, nanstr, infstr, sign, formatter,
- floatmode, legacy)
- # formatter is always reset
- opt['formatter'] = formatter
- _format_options.update(opt)
- # set the C variable for legacy mode
- if _format_options['legacy'] == 113:
- set_legacy_print_mode(113)
- # reset the sign option in legacy mode to avoid confusion
- _format_options['sign'] = '-'
- elif _format_options['legacy'] == 121:
- set_legacy_print_mode(121)
- elif _format_options['legacy'] == sys.maxsize:
- set_legacy_print_mode(0)
- @set_module('numpy')
- def get_printoptions():
- """
- Return the current print options.
- Returns
- -------
- print_opts : dict
- Dictionary of current print options with keys
- - precision : int
- - threshold : int
- - edgeitems : int
- - linewidth : int
- - suppress : bool
- - nanstr : str
- - infstr : str
- - formatter : dict of callables
- - sign : str
- For a full description of these options, see `set_printoptions`.
- See Also
- --------
- set_printoptions, printoptions, set_string_function
- """
- opts = _format_options.copy()
- opts['legacy'] = {
- 113: '1.13', 121: '1.21', sys.maxsize: False,
- }[opts['legacy']]
- return opts
- def _get_legacy_print_mode():
- """Return the legacy print mode as an int."""
- return _format_options['legacy']
- @set_module('numpy')
- @contextlib.contextmanager
- def printoptions(*args, **kwargs):
- """Context manager for setting print options.
- Set print options for the scope of the `with` block, and restore the old
- options at the end. See `set_printoptions` for the full description of
- available options.
- Examples
- --------
- >>> from numpy.testing import assert_equal
- >>> with np.printoptions(precision=2):
- ... np.array([2.0]) / 3
- array([0.67])
- The `as`-clause of the `with`-statement gives the current print options:
- >>> with np.printoptions(precision=2) as opts:
- ... assert_equal(opts, np.get_printoptions())
- See Also
- --------
- set_printoptions, get_printoptions
- """
- opts = np.get_printoptions()
- try:
- np.set_printoptions(*args, **kwargs)
- yield np.get_printoptions()
- finally:
- np.set_printoptions(**opts)
- def _leading_trailing(a, edgeitems, index=()):
- """
- Keep only the N-D corners (leading and trailing edges) of an array.
- Should be passed a base-class ndarray, since it makes no guarantees about
- preserving subclasses.
- """
- axis = len(index)
- if axis == a.ndim:
- return a[index]
- if a.shape[axis] > 2*edgeitems:
- return concatenate((
- _leading_trailing(a, edgeitems, index + np.index_exp[ :edgeitems]),
- _leading_trailing(a, edgeitems, index + np.index_exp[-edgeitems:])
- ), axis=axis)
- else:
- return _leading_trailing(a, edgeitems, index + np.index_exp[:])
- def _object_format(o):
- """ Object arrays containing lists should be printed unambiguously """
- if type(o) is list:
- fmt = 'list({!r})'
- else:
- fmt = '{!r}'
- return fmt.format(o)
- def repr_format(x):
- return repr(x)
- def str_format(x):
- return str(x)
- def _get_formatdict(data, *, precision, floatmode, suppress, sign, legacy,
- formatter, **kwargs):
- # note: extra arguments in kwargs are ignored
- # wrapped in lambdas to avoid taking a code path with the wrong type of data
- formatdict = {
- 'bool': lambda: BoolFormat(data),
- 'int': lambda: IntegerFormat(data),
- 'float': lambda: FloatingFormat(
- data, precision, floatmode, suppress, sign, legacy=legacy),
- 'longfloat': lambda: FloatingFormat(
- data, precision, floatmode, suppress, sign, legacy=legacy),
- 'complexfloat': lambda: ComplexFloatingFormat(
- data, precision, floatmode, suppress, sign, legacy=legacy),
- 'longcomplexfloat': lambda: ComplexFloatingFormat(
- data, precision, floatmode, suppress, sign, legacy=legacy),
- 'datetime': lambda: DatetimeFormat(data, legacy=legacy),
- 'timedelta': lambda: TimedeltaFormat(data),
- 'object': lambda: _object_format,
- 'void': lambda: str_format,
- 'numpystr': lambda: repr_format}
- # we need to wrap values in `formatter` in a lambda, so that the interface
- # is the same as the above values.
- def indirect(x):
- return lambda: x
- if formatter is not None:
- fkeys = [k for k in formatter.keys() if formatter[k] is not None]
- if 'all' in fkeys:
- for key in formatdict.keys():
- formatdict[key] = indirect(formatter['all'])
- if 'int_kind' in fkeys:
- for key in ['int']:
- formatdict[key] = indirect(formatter['int_kind'])
- if 'float_kind' in fkeys:
- for key in ['float', 'longfloat']:
- formatdict[key] = indirect(formatter['float_kind'])
- if 'complex_kind' in fkeys:
- for key in ['complexfloat', 'longcomplexfloat']:
- formatdict[key] = indirect(formatter['complex_kind'])
- if 'str_kind' in fkeys:
- formatdict['numpystr'] = indirect(formatter['str_kind'])
- for key in formatdict.keys():
- if key in fkeys:
- formatdict[key] = indirect(formatter[key])
- return formatdict
- def _get_format_function(data, **options):
- """
- find the right formatting function for the dtype_
- """
- dtype_ = data.dtype
- dtypeobj = dtype_.type
- formatdict = _get_formatdict(data, **options)
- if dtypeobj is None:
- return formatdict["numpystr"]()
- elif issubclass(dtypeobj, _nt.bool_):
- return formatdict['bool']()
- elif issubclass(dtypeobj, _nt.integer):
- if issubclass(dtypeobj, _nt.timedelta64):
- return formatdict['timedelta']()
- else:
- return formatdict['int']()
- elif issubclass(dtypeobj, _nt.floating):
- if issubclass(dtypeobj, _nt.longfloat):
- return formatdict['longfloat']()
- else:
- return formatdict['float']()
- elif issubclass(dtypeobj, _nt.complexfloating):
- if issubclass(dtypeobj, _nt.clongfloat):
- return formatdict['longcomplexfloat']()
- else:
- return formatdict['complexfloat']()
- elif issubclass(dtypeobj, (_nt.unicode_, _nt.string_)):
- return formatdict['numpystr']()
- elif issubclass(dtypeobj, _nt.datetime64):
- return formatdict['datetime']()
- elif issubclass(dtypeobj, _nt.object_):
- return formatdict['object']()
- elif issubclass(dtypeobj, _nt.void):
- if dtype_.names is not None:
- return StructuredVoidFormat.from_data(data, **options)
- else:
- return formatdict['void']()
- else:
- return formatdict['numpystr']()
- def _recursive_guard(fillvalue='...'):
- """
- Like the python 3.2 reprlib.recursive_repr, but forwards *args and **kwargs
- Decorates a function such that if it calls itself with the same first
- argument, it returns `fillvalue` instead of recursing.
- Largely copied from reprlib.recursive_repr
- """
- def decorating_function(f):
- repr_running = set()
- @functools.wraps(f)
- def wrapper(self, *args, **kwargs):
- key = id(self), get_ident()
- if key in repr_running:
- return fillvalue
- repr_running.add(key)
- try:
- return f(self, *args, **kwargs)
- finally:
- repr_running.discard(key)
- return wrapper
- return decorating_function
- # gracefully handle recursive calls, when object arrays contain themselves
- @_recursive_guard()
- def _array2string(a, options, separator=' ', prefix=""):
- # The formatter __init__s in _get_format_function cannot deal with
- # subclasses yet, and we also need to avoid recursion issues in
- # _formatArray with subclasses which return 0d arrays in place of scalars
- data = asarray(a)
- if a.shape == ():
- a = data
- if a.size > options['threshold']:
- summary_insert = "..."
- data = _leading_trailing(data, options['edgeitems'])
- else:
- summary_insert = ""
- # find the right formatting function for the array
- format_function = _get_format_function(data, **options)
- # skip over "["
- next_line_prefix = " "
- # skip over array(
- next_line_prefix += " "*len(prefix)
- lst = _formatArray(a, format_function, options['linewidth'],
- next_line_prefix, separator, options['edgeitems'],
- summary_insert, options['legacy'])
- return lst
- def _array2string_dispatcher(
- a, max_line_width=None, precision=None,
- suppress_small=None, separator=None, prefix=None,
- style=None, formatter=None, threshold=None,
- edgeitems=None, sign=None, floatmode=None, suffix=None,
- *, legacy=None):
- return (a,)
- @array_function_dispatch(_array2string_dispatcher, module='numpy')
- def array2string(a, max_line_width=None, precision=None,
- suppress_small=None, separator=' ', prefix="",
- style=np._NoValue, formatter=None, threshold=None,
- edgeitems=None, sign=None, floatmode=None, suffix="",
- *, legacy=None):
- """
- Return a string representation of an array.
- Parameters
- ----------
- a : ndarray
- Input array.
- max_line_width : int, optional
- Inserts newlines if text is longer than `max_line_width`.
- Defaults to ``numpy.get_printoptions()['linewidth']``.
- precision : int or None, optional
- Floating point precision.
- Defaults to ``numpy.get_printoptions()['precision']``.
- suppress_small : bool, optional
- Represent numbers "very close" to zero as zero; default is False.
- Very close is defined by precision: if the precision is 8, e.g.,
- numbers smaller (in absolute value) than 5e-9 are represented as
- zero.
- Defaults to ``numpy.get_printoptions()['suppress']``.
- separator : str, optional
- Inserted between elements.
- prefix : str, optional
- suffix : str, optional
- The length of the prefix and suffix strings are used to respectively
- align and wrap the output. An array is typically printed as::
- prefix + array2string(a) + suffix
- The output is left-padded by the length of the prefix string, and
- wrapping is forced at the column ``max_line_width - len(suffix)``.
- It should be noted that the content of prefix and suffix strings are
- not included in the output.
- style : _NoValue, optional
- Has no effect, do not use.
- .. deprecated:: 1.14.0
- formatter : dict of callables, optional
- If not None, the keys should indicate the type(s) that the respective
- formatting function applies to. Callables should return a string.
- Types that are not specified (by their corresponding keys) are handled
- by the default formatters. Individual types for which a formatter
- can be set are:
- - 'bool'
- - 'int'
- - 'timedelta' : a `numpy.timedelta64`
- - 'datetime' : a `numpy.datetime64`
- - 'float'
- - 'longfloat' : 128-bit floats
- - 'complexfloat'
- - 'longcomplexfloat' : composed of two 128-bit floats
- - 'void' : type `numpy.void`
- - 'numpystr' : types `numpy.string_` and `numpy.unicode_`
- Other keys that can be used to set a group of types at once are:
- - 'all' : sets all types
- - 'int_kind' : sets 'int'
- - 'float_kind' : sets 'float' and 'longfloat'
- - 'complex_kind' : sets 'complexfloat' and 'longcomplexfloat'
- - 'str_kind' : sets 'numpystr'
- threshold : int, optional
- Total number of array elements which trigger summarization
- rather than full repr.
- Defaults to ``numpy.get_printoptions()['threshold']``.
- edgeitems : int, optional
- Number of array items in summary at beginning and end of
- each dimension.
- Defaults to ``numpy.get_printoptions()['edgeitems']``.
- sign : string, either '-', '+', or ' ', optional
- Controls printing of the sign of floating-point types. If '+', always
- print the sign of positive values. If ' ', always prints a space
- (whitespace character) in the sign position of positive values. If
- '-', omit the sign character of positive values.
- Defaults to ``numpy.get_printoptions()['sign']``.
- floatmode : str, optional
- Controls the interpretation of the `precision` option for
- floating-point types.
- Defaults to ``numpy.get_printoptions()['floatmode']``.
- Can take the following values:
- - 'fixed': Always print exactly `precision` fractional digits,
- even if this would print more or fewer digits than
- necessary to specify the value uniquely.
- - 'unique': Print the minimum number of fractional digits necessary
- to represent each value uniquely. Different elements may
- have a different number of digits. The value of the
- `precision` option is ignored.
- - 'maxprec': Print at most `precision` fractional digits, but if
- an element can be uniquely represented with fewer digits
- only print it with that many.
- - 'maxprec_equal': Print at most `precision` fractional digits,
- but if every element in the array can be uniquely
- represented with an equal number of fewer digits, use that
- many digits for all elements.
- legacy : string or `False`, optional
- If set to the string `'1.13'` enables 1.13 legacy printing mode. This
- approximates numpy 1.13 print output by including a space in the sign
- position of floats and different behavior for 0d arrays. If set to
- `False`, disables legacy mode. Unrecognized strings will be ignored
- with a warning for forward compatibility.
- .. versionadded:: 1.14.0
- Returns
- -------
- array_str : str
- String representation of the array.
- Raises
- ------
- TypeError
- if a callable in `formatter` does not return a string.
- See Also
- --------
- array_str, array_repr, set_printoptions, get_printoptions
- Notes
- -----
- If a formatter is specified for a certain type, the `precision` keyword is
- ignored for that type.
- This is a very flexible function; `array_repr` and `array_str` are using
- `array2string` internally so keywords with the same name should work
- identically in all three functions.
- Examples
- --------
- >>> x = np.array([1e-16,1,2,3])
- >>> np.array2string(x, precision=2, separator=',',
- ... suppress_small=True)
- '[0.,1.,2.,3.]'
- >>> x = np.arange(3.)
- >>> np.array2string(x, formatter={'float_kind':lambda x: "%.2f" % x})
- '[0.00 1.00 2.00]'
- >>> x = np.arange(3)
- >>> np.array2string(x, formatter={'int':lambda x: hex(x)})
- '[0x0 0x1 0x2]'
- """
- overrides = _make_options_dict(precision, threshold, edgeitems,
- max_line_width, suppress_small, None, None,
- sign, formatter, floatmode, legacy)
- options = _format_options.copy()
- options.update(overrides)
- if options['legacy'] <= 113:
- if style is np._NoValue:
- style = repr
- if a.shape == () and a.dtype.names is None:
- return style(a.item())
- elif style is not np._NoValue:
- # Deprecation 11-9-2017 v1.14
- warnings.warn("'style' argument is deprecated and no longer functional"
- " except in 1.13 'legacy' mode",
- DeprecationWarning, stacklevel=3)
- if options['legacy'] > 113:
- options['linewidth'] -= len(suffix)
- # treat as a null array if any of shape elements == 0
- if a.size == 0:
- return "[]"
- return _array2string(a, options, separator, prefix)
- def _extendLine(s, line, word, line_width, next_line_prefix, legacy):
- needs_wrap = len(line) + len(word) > line_width
- if legacy > 113:
- # don't wrap lines if it won't help
- if len(line) <= len(next_line_prefix):
- needs_wrap = False
- if needs_wrap:
- s += line.rstrip() + "\n"
- line = next_line_prefix
- line += word
- return s, line
- def _extendLine_pretty(s, line, word, line_width, next_line_prefix, legacy):
- """
- Extends line with nicely formatted (possibly multi-line) string ``word``.
- """
- words = word.splitlines()
- if len(words) == 1 or legacy <= 113:
- return _extendLine(s, line, word, line_width, next_line_prefix, legacy)
- max_word_length = max(len(word) for word in words)
- if (len(line) + max_word_length > line_width and
- len(line) > len(next_line_prefix)):
- s += line.rstrip() + '\n'
- line = next_line_prefix + words[0]
- indent = next_line_prefix
- else:
- indent = len(line)*' '
- line += words[0]
- for word in words[1::]:
- s += line.rstrip() + '\n'
- line = indent + word
- suffix_length = max_word_length - len(words[-1])
- line += suffix_length*' '
- return s, line
- def _formatArray(a, format_function, line_width, next_line_prefix,
- separator, edge_items, summary_insert, legacy):
- """formatArray is designed for two modes of operation:
- 1. Full output
- 2. Summarized output
- """
- def recurser(index, hanging_indent, curr_width):
- """
- By using this local function, we don't need to recurse with all the
- arguments. Since this function is not created recursively, the cost is
- not significant
- """
- axis = len(index)
- axes_left = a.ndim - axis
- if axes_left == 0:
- return format_function(a[index])
- # when recursing, add a space to align with the [ added, and reduce the
- # length of the line by 1
- next_hanging_indent = hanging_indent + ' '
- if legacy <= 113:
- next_width = curr_width
- else:
- next_width = curr_width - len(']')
- a_len = a.shape[axis]
- show_summary = summary_insert and 2*edge_items < a_len
- if show_summary:
- leading_items = edge_items
- trailing_items = edge_items
- else:
- leading_items = 0
- trailing_items = a_len
- # stringify the array with the hanging indent on the first line too
- s = ''
- # last axis (rows) - wrap elements if they would not fit on one line
- if axes_left == 1:
- # the length up until the beginning of the separator / bracket
- if legacy <= 113:
- elem_width = curr_width - len(separator.rstrip())
- else:
- elem_width = curr_width - max(len(separator.rstrip()), len(']'))
- line = hanging_indent
- for i in range(leading_items):
- word = recurser(index + (i,), next_hanging_indent, next_width)
- s, line = _extendLine_pretty(
- s, line, word, elem_width, hanging_indent, legacy)
- line += separator
- if show_summary:
- s, line = _extendLine(
- s, line, summary_insert, elem_width, hanging_indent, legacy)
- if legacy <= 113:
- line += ", "
- else:
- line += separator
- for i in range(trailing_items, 1, -1):
- word = recurser(index + (-i,), next_hanging_indent, next_width)
- s, line = _extendLine_pretty(
- s, line, word, elem_width, hanging_indent, legacy)
- line += separator
- if legacy <= 113:
- # width of the separator is not considered on 1.13
- elem_width = curr_width
- word = recurser(index + (-1,), next_hanging_indent, next_width)
- s, line = _extendLine_pretty(
- s, line, word, elem_width, hanging_indent, legacy)
- s += line
- # other axes - insert newlines between rows
- else:
- s = ''
- line_sep = separator.rstrip() + '\n'*(axes_left - 1)
- for i in range(leading_items):
- nested = recurser(index + (i,), next_hanging_indent, next_width)
- s += hanging_indent + nested + line_sep
- if show_summary:
- if legacy <= 113:
- # trailing space, fixed nbr of newlines, and fixed separator
- s += hanging_indent + summary_insert + ", \n"
- else:
- s += hanging_indent + summary_insert + line_sep
- for i in range(trailing_items, 1, -1):
- nested = recurser(index + (-i,), next_hanging_indent,
- next_width)
- s += hanging_indent + nested + line_sep
- nested = recurser(index + (-1,), next_hanging_indent, next_width)
- s += hanging_indent + nested
- # remove the hanging indent, and wrap in []
- s = '[' + s[len(hanging_indent):] + ']'
- return s
- try:
- # invoke the recursive part with an initial index and prefix
- return recurser(index=(),
- hanging_indent=next_line_prefix,
- curr_width=line_width)
- finally:
- # recursive closures have a cyclic reference to themselves, which
- # requires gc to collect (gh-10620). To avoid this problem, for
- # performance and PyPy friendliness, we break the cycle:
- recurser = None
- def _none_or_positive_arg(x, name):
- if x is None:
- return -1
- if x < 0:
- raise ValueError("{} must be >= 0".format(name))
- return x
- class FloatingFormat:
- """ Formatter for subtypes of np.floating """
- def __init__(self, data, precision, floatmode, suppress_small, sign=False,
- *, legacy=None):
- # for backcompatibility, accept bools
- if isinstance(sign, bool):
- sign = '+' if sign else '-'
- self._legacy = legacy
- if self._legacy <= 113:
- # when not 0d, legacy does not support '-'
- if data.shape != () and sign == '-':
- sign = ' '
- self.floatmode = floatmode
- if floatmode == 'unique':
- self.precision = None
- else:
- self.precision = precision
- self.precision = _none_or_positive_arg(self.precision, 'precision')
- self.suppress_small = suppress_small
- self.sign = sign
- self.exp_format = False
- self.large_exponent = False
- self.fillFormat(data)
- def fillFormat(self, data):
- # only the finite values are used to compute the number of digits
- finite_vals = data[isfinite(data)]
- # choose exponential mode based on the non-zero finite values:
- abs_non_zero = absolute(finite_vals[finite_vals != 0])
- if len(abs_non_zero) != 0:
- max_val = np.max(abs_non_zero)
- min_val = np.min(abs_non_zero)
- with errstate(over='ignore'): # division can overflow
- if max_val >= 1.e8 or (not self.suppress_small and
- (min_val < 0.0001 or max_val/min_val > 1000.)):
- self.exp_format = True
- # do a first pass of printing all the numbers, to determine sizes
- if len(finite_vals) == 0:
- self.pad_left = 0
- self.pad_right = 0
- self.trim = '.'
- self.exp_size = -1
- self.unique = True
- self.min_digits = None
- elif self.exp_format:
- trim, unique = '.', True
- if self.floatmode == 'fixed' or self._legacy <= 113:
- trim, unique = 'k', False
- strs = (dragon4_scientific(x, precision=self.precision,
- unique=unique, trim=trim, sign=self.sign == '+')
- for x in finite_vals)
- frac_strs, _, exp_strs = zip(*(s.partition('e') for s in strs))
- int_part, frac_part = zip(*(s.split('.') for s in frac_strs))
- self.exp_size = max(len(s) for s in exp_strs) - 1
- self.trim = 'k'
- self.precision = max(len(s) for s in frac_part)
- self.min_digits = self.precision
- self.unique = unique
- # for back-compat with np 1.13, use 2 spaces & sign and full prec
- if self._legacy <= 113:
- self.pad_left = 3
- else:
- # this should be only 1 or 2. Can be calculated from sign.
- self.pad_left = max(len(s) for s in int_part)
- # pad_right is only needed for nan length calculation
- self.pad_right = self.exp_size + 2 + self.precision
- else:
- trim, unique = '.', True
- if self.floatmode == 'fixed':
- trim, unique = 'k', False
- strs = (dragon4_positional(x, precision=self.precision,
- fractional=True,
- unique=unique, trim=trim,
- sign=self.sign == '+')
- for x in finite_vals)
- int_part, frac_part = zip(*(s.split('.') for s in strs))
- if self._legacy <= 113:
- self.pad_left = 1 + max(len(s.lstrip('-+')) for s in int_part)
- else:
- self.pad_left = max(len(s) for s in int_part)
- self.pad_right = max(len(s) for s in frac_part)
- self.exp_size = -1
- self.unique = unique
- if self.floatmode in ['fixed', 'maxprec_equal']:
- self.precision = self.min_digits = self.pad_right
- self.trim = 'k'
- else:
- self.trim = '.'
- self.min_digits = 0
- if self._legacy > 113:
- # account for sign = ' ' by adding one to pad_left
- if self.sign == ' ' and not any(np.signbit(finite_vals)):
- self.pad_left += 1
- # if there are non-finite values, may need to increase pad_left
- if data.size != finite_vals.size:
- neginf = self.sign != '-' or any(data[isinf(data)] < 0)
- nanlen = len(_format_options['nanstr'])
- inflen = len(_format_options['infstr']) + neginf
- offset = self.pad_right + 1 # +1 for decimal pt
- self.pad_left = max(self.pad_left, nanlen - offset, inflen - offset)
- def __call__(self, x):
- if not np.isfinite(x):
- with errstate(invalid='ignore'):
- if np.isnan(x):
- sign = '+' if self.sign == '+' else ''
- ret = sign + _format_options['nanstr']
- else: # isinf
- sign = '-' if x < 0 else '+' if self.sign == '+' else ''
- ret = sign + _format_options['infstr']
- return ' '*(self.pad_left + self.pad_right + 1 - len(ret)) + ret
- if self.exp_format:
- return dragon4_scientific(x,
- precision=self.precision,
- min_digits=self.min_digits,
- unique=self.unique,
- trim=self.trim,
- sign=self.sign == '+',
- pad_left=self.pad_left,
- exp_digits=self.exp_size)
- else:
- return dragon4_positional(x,
- precision=self.precision,
- min_digits=self.min_digits,
- unique=self.unique,
- fractional=True,
- trim=self.trim,
- sign=self.sign == '+',
- pad_left=self.pad_left,
- pad_right=self.pad_right)
- @set_module('numpy')
- def format_float_scientific(x, precision=None, unique=True, trim='k',
- sign=False, pad_left=None, exp_digits=None,
- min_digits=None):
- """
- Format a floating-point scalar as a decimal string in scientific notation.
- Provides control over rounding, trimming and padding. Uses and assumes
- IEEE unbiased rounding. Uses the "Dragon4" algorithm.
- Parameters
- ----------
- x : python float or numpy floating scalar
- Value to format.
- precision : non-negative integer or None, optional
- Maximum number of digits to print. May be None if `unique` is
- `True`, but must be an integer if unique is `False`.
- unique : boolean, optional
- If `True`, use a digit-generation strategy which gives the shortest
- representation which uniquely identifies the floating-point number from
- other values of the same type, by judicious rounding. If `precision`
- is given fewer digits than necessary can be printed. If `min_digits`
- is given more can be printed, in which cases the last digit is rounded
- with unbiased rounding.
- If `False`, digits are generated as if printing an infinite-precision
- value and stopping after `precision` digits, rounding the remaining
- value with unbiased rounding
- trim : one of 'k', '.', '0', '-', optional
- Controls post-processing trimming of trailing digits, as follows:
- * 'k' : keep trailing zeros, keep decimal point (no trimming)
- * '.' : trim all trailing zeros, leave decimal point
- * '0' : trim all but the zero before the decimal point. Insert the
- zero if it is missing.
- * '-' : trim trailing zeros and any trailing decimal point
- sign : boolean, optional
- Whether to show the sign for positive values.
- pad_left : non-negative integer, optional
- Pad the left side of the string with whitespace until at least that
- many characters are to the left of the decimal point.
- exp_digits : non-negative integer, optional
- Pad the exponent with zeros until it contains at least this many digits.
- If omitted, the exponent will be at least 2 digits.
- min_digits : non-negative integer or None, optional
- Minimum number of digits to print. This only has an effect for
- `unique=True`. In that case more digits than necessary to uniquely
- identify the value may be printed and rounded unbiased.
- -- versionadded:: 1.21.0
-
- Returns
- -------
- rep : string
- The string representation of the floating point value
- See Also
- --------
- format_float_positional
- Examples
- --------
- >>> np.format_float_scientific(np.float32(np.pi))
- '3.1415927e+00'
- >>> s = np.float32(1.23e24)
- >>> np.format_float_scientific(s, unique=False, precision=15)
- '1.230000071797338e+24'
- >>> np.format_float_scientific(s, exp_digits=4)
- '1.23e+0024'
- """
- precision = _none_or_positive_arg(precision, 'precision')
- pad_left = _none_or_positive_arg(pad_left, 'pad_left')
- exp_digits = _none_or_positive_arg(exp_digits, 'exp_digits')
- min_digits = _none_or_positive_arg(min_digits, 'min_digits')
- if min_digits > 0 and precision > 0 and min_digits > precision:
- raise ValueError("min_digits must be less than or equal to precision")
- return dragon4_scientific(x, precision=precision, unique=unique,
- trim=trim, sign=sign, pad_left=pad_left,
- exp_digits=exp_digits, min_digits=min_digits)
- @set_module('numpy')
- def format_float_positional(x, precision=None, unique=True,
- fractional=True, trim='k', sign=False,
- pad_left=None, pad_right=None, min_digits=None):
- """
- Format a floating-point scalar as a decimal string in positional notation.
- Provides control over rounding, trimming and padding. Uses and assumes
- IEEE unbiased rounding. Uses the "Dragon4" algorithm.
- Parameters
- ----------
- x : python float or numpy floating scalar
- Value to format.
- precision : non-negative integer or None, optional
- Maximum number of digits to print. May be None if `unique` is
- `True`, but must be an integer if unique is `False`.
- unique : boolean, optional
- If `True`, use a digit-generation strategy which gives the shortest
- representation which uniquely identifies the floating-point number from
- other values of the same type, by judicious rounding. If `precision`
- is given fewer digits than necessary can be printed, or if `min_digits`
- is given more can be printed, in which cases the last digit is rounded
- with unbiased rounding.
- If `False`, digits are generated as if printing an infinite-precision
- value and stopping after `precision` digits, rounding the remaining
- value with unbiased rounding
- fractional : boolean, optional
- If `True`, the cutoffs of `precision` and `min_digits` refer to the
- total number of digits after the decimal point, including leading
- zeros.
- If `False`, `precision` and `min_digits` refer to the total number of
- significant digits, before or after the decimal point, ignoring leading
- zeros.
- trim : one of 'k', '.', '0', '-', optional
- Controls post-processing trimming of trailing digits, as follows:
- * 'k' : keep trailing zeros, keep decimal point (no trimming)
- * '.' : trim all trailing zeros, leave decimal point
- * '0' : trim all but the zero before the decimal point. Insert the
- zero if it is missing.
- * '-' : trim trailing zeros and any trailing decimal point
- sign : boolean, optional
- Whether to show the sign for positive values.
- pad_left : non-negative integer, optional
- Pad the left side of the string with whitespace until at least that
- many characters are to the left of the decimal point.
- pad_right : non-negative integer, optional
- Pad the right side of the string with whitespace until at least that
- many characters are to the right of the decimal point.
- min_digits : non-negative integer or None, optional
- Minimum number of digits to print. Only has an effect if `unique=True`
- in which case additional digits past those necessary to uniquely
- identify the value may be printed, rounding the last additional digit.
-
- -- versionadded:: 1.21.0
- Returns
- -------
- rep : string
- The string representation of the floating point value
- See Also
- --------
- format_float_scientific
- Examples
- --------
- >>> np.format_float_positional(np.float32(np.pi))
- '3.1415927'
- >>> np.format_float_positional(np.float16(np.pi))
- '3.14'
- >>> np.format_float_positional(np.float16(0.3))
- '0.3'
- >>> np.format_float_positional(np.float16(0.3), unique=False, precision=10)
- '0.3000488281'
- """
- precision = _none_or_positive_arg(precision, 'precision')
- pad_left = _none_or_positive_arg(pad_left, 'pad_left')
- pad_right = _none_or_positive_arg(pad_right, 'pad_right')
- min_digits = _none_or_positive_arg(min_digits, 'min_digits')
- if not fractional and precision == 0:
- raise ValueError("precision must be greater than 0 if "
- "fractional=False")
- if min_digits > 0 and precision > 0 and min_digits > precision:
- raise ValueError("min_digits must be less than or equal to precision")
- return dragon4_positional(x, precision=precision, unique=unique,
- fractional=fractional, trim=trim,
- sign=sign, pad_left=pad_left,
- pad_right=pad_right, min_digits=min_digits)
- class IntegerFormat:
- def __init__(self, data):
- if data.size > 0:
- max_str_len = max(len(str(np.max(data))),
- len(str(np.min(data))))
- else:
- max_str_len = 0
- self.format = '%{}d'.format(max_str_len)
- def __call__(self, x):
- return self.format % x
- class BoolFormat:
- def __init__(self, data, **kwargs):
- # add an extra space so " True" and "False" have the same length and
- # array elements align nicely when printed, except in 0d arrays
- self.truestr = ' True' if data.shape != () else 'True'
- def __call__(self, x):
- return self.truestr if x else "False"
- class ComplexFloatingFormat:
- """ Formatter for subtypes of np.complexfloating """
- def __init__(self, x, precision, floatmode, suppress_small,
- sign=False, *, legacy=None):
- # for backcompatibility, accept bools
- if isinstance(sign, bool):
- sign = '+' if sign else '-'
- floatmode_real = floatmode_imag = floatmode
- if legacy <= 113:
- floatmode_real = 'maxprec_equal'
- floatmode_imag = 'maxprec'
- self.real_format = FloatingFormat(
- x.real, precision, floatmode_real, suppress_small,
- sign=sign, legacy=legacy
- )
- self.imag_format = FloatingFormat(
- x.imag, precision, floatmode_imag, suppress_small,
- sign='+', legacy=legacy
- )
- def __call__(self, x):
- r = self.real_format(x.real)
- i = self.imag_format(x.imag)
- # add the 'j' before the terminal whitespace in i
- sp = len(i.rstrip())
- i = i[:sp] + 'j' + i[sp:]
- return r + i
- class _TimelikeFormat:
- def __init__(self, data):
- non_nat = data[~isnat(data)]
- if len(non_nat) > 0:
- # Max str length of non-NaT elements
- max_str_len = max(len(self._format_non_nat(np.max(non_nat))),
- len(self._format_non_nat(np.min(non_nat))))
- else:
- max_str_len = 0
- if len(non_nat) < data.size:
- # data contains a NaT
- max_str_len = max(max_str_len, 5)
- self._format = '%{}s'.format(max_str_len)
- self._nat = "'NaT'".rjust(max_str_len)
- def _format_non_nat(self, x):
- # override in subclass
- raise NotImplementedError
- def __call__(self, x):
- if isnat(x):
- return self._nat
- else:
- return self._format % self._format_non_nat(x)
- class DatetimeFormat(_TimelikeFormat):
- def __init__(self, x, unit=None, timezone=None, casting='same_kind',
- legacy=False):
- # Get the unit from the dtype
- if unit is None:
- if x.dtype.kind == 'M':
- unit = datetime_data(x.dtype)[0]
- else:
- unit = 's'
- if timezone is None:
- timezone = 'naive'
- self.timezone = timezone
- self.unit = unit
- self.casting = casting
- self.legacy = legacy
- # must be called after the above are configured
- super().__init__(x)
- def __call__(self, x):
- if self.legacy <= 113:
- return self._format_non_nat(x)
- return super().__call__(x)
- def _format_non_nat(self, x):
- return "'%s'" % datetime_as_string(x,
- unit=self.unit,
- timezone=self.timezone,
- casting=self.casting)
- class TimedeltaFormat(_TimelikeFormat):
- def _format_non_nat(self, x):
- return str(x.astype('i8'))
- class SubArrayFormat:
- def __init__(self, format_function):
- self.format_function = format_function
- def __call__(self, arr):
- if arr.ndim <= 1:
- return "[" + ", ".join(self.format_function(a) for a in arr) + "]"
- return "[" + ", ".join(self.__call__(a) for a in arr) + "]"
- class StructuredVoidFormat:
- """
- Formatter for structured np.void objects.
- This does not work on structured alias types like np.dtype(('i4', 'i2,i2')),
- as alias scalars lose their field information, and the implementation
- relies upon np.void.__getitem__.
- """
- def __init__(self, format_functions):
- self.format_functions = format_functions
- @classmethod
- def from_data(cls, data, **options):
- """
- This is a second way to initialize StructuredVoidFormat, using the raw data
- as input. Added to avoid changing the signature of __init__.
- """
- format_functions = []
- for field_name in data.dtype.names:
- format_function = _get_format_function(data[field_name], **options)
- if data.dtype[field_name].shape != ():
- format_function = SubArrayFormat(format_function)
- format_functions.append(format_function)
- return cls(format_functions)
- def __call__(self, x):
- str_fields = [
- format_function(field)
- for field, format_function in zip(x, self.format_functions)
- ]
- if len(str_fields) == 1:
- return "({},)".format(str_fields[0])
- else:
- return "({})".format(", ".join(str_fields))
- def _void_scalar_repr(x):
- """
- Implements the repr for structured-void scalars. It is called from the
- scalartypes.c.src code, and is placed here because it uses the elementwise
- formatters defined above.
- """
- return StructuredVoidFormat.from_data(array(x), **_format_options)(x)
- _typelessdata = [int_, float_, complex_, bool_]
- def dtype_is_implied(dtype):
- """
- Determine if the given dtype is implied by the representation of its values.
- Parameters
- ----------
- dtype : dtype
- Data type
- Returns
- -------
- implied : bool
- True if the dtype is implied by the representation of its values.
- Examples
- --------
- >>> np.core.arrayprint.dtype_is_implied(int)
- True
- >>> np.array([1, 2, 3], int)
- array([1, 2, 3])
- >>> np.core.arrayprint.dtype_is_implied(np.int8)
- False
- >>> np.array([1, 2, 3], np.int8)
- array([1, 2, 3], dtype=int8)
- """
- dtype = np.dtype(dtype)
- if _format_options['legacy'] <= 113 and dtype.type == bool_:
- return False
- # not just void types can be structured, and names are not part of the repr
- if dtype.names is not None:
- return False
- return dtype.type in _typelessdata
- def dtype_short_repr(dtype):
- """
- Convert a dtype to a short form which evaluates to the same dtype.
- The intent is roughly that the following holds
- >>> from numpy import *
- >>> dt = np.int64([1, 2]).dtype
- >>> assert eval(dtype_short_repr(dt)) == dt
- """
- if type(dtype).__repr__ != np.dtype.__repr__:
- # TODO: Custom repr for user DTypes, logic should likely move.
- return repr(dtype)
- if dtype.names is not None:
- # structured dtypes give a list or tuple repr
- return str(dtype)
- elif issubclass(dtype.type, flexible):
- # handle these separately so they don't give garbage like str256
- return "'%s'" % str(dtype)
- typename = dtype.name
- # quote typenames which can't be represented as python variable names
- if typename and not (typename[0].isalpha() and typename.isalnum()):
- typename = repr(typename)
- return typename
- def _array_repr_implementation(
- arr, max_line_width=None, precision=None, suppress_small=None,
- array2string=array2string):
- """Internal version of array_repr() that allows overriding array2string."""
- if max_line_width is None:
- max_line_width = _format_options['linewidth']
- if type(arr) is not ndarray:
- class_name = type(arr).__name__
- else:
- class_name = "array"
- skipdtype = dtype_is_implied(arr.dtype) and arr.size > 0
- prefix = class_name + "("
- suffix = ")" if skipdtype else ","
- if (_format_options['legacy'] <= 113 and
- arr.shape == () and not arr.dtype.names):
- lst = repr(arr.item())
- elif arr.size > 0 or arr.shape == (0,):
- lst = array2string(arr, max_line_width, precision, suppress_small,
- ', ', prefix, suffix=suffix)
- else: # show zero-length shape unless it is (0,)
- lst = "[], shape=%s" % (repr(arr.shape),)
- arr_str = prefix + lst + suffix
- if skipdtype:
- return arr_str
- dtype_str = "dtype={})".format(dtype_short_repr(arr.dtype))
- # compute whether we should put dtype on a new line: Do so if adding the
- # dtype would extend the last line past max_line_width.
- # Note: This line gives the correct result even when rfind returns -1.
- last_line_len = len(arr_str) - (arr_str.rfind('\n') + 1)
- spacer = " "
- if _format_options['legacy'] <= 113:
- if issubclass(arr.dtype.type, flexible):
- spacer = '\n' + ' '*len(class_name + "(")
- elif last_line_len + len(dtype_str) + 1 > max_line_width:
- spacer = '\n' + ' '*len(class_name + "(")
- return arr_str + spacer + dtype_str
- def _array_repr_dispatcher(
- arr, max_line_width=None, precision=None, suppress_small=None):
- return (arr,)
- @array_function_dispatch(_array_repr_dispatcher, module='numpy')
- def array_repr(arr, max_line_width=None, precision=None, suppress_small=None):
- """
- Return the string representation of an array.
- Parameters
- ----------
- arr : ndarray
- Input array.
- max_line_width : int, optional
- Inserts newlines if text is longer than `max_line_width`.
- Defaults to ``numpy.get_printoptions()['linewidth']``.
- precision : int, optional
- Floating point precision.
- Defaults to ``numpy.get_printoptions()['precision']``.
- suppress_small : bool, optional
- Represent numbers "very close" to zero as zero; default is False.
- Very close is defined by precision: if the precision is 8, e.g.,
- numbers smaller (in absolute value) than 5e-9 are represented as
- zero.
- Defaults to ``numpy.get_printoptions()['suppress']``.
- Returns
- -------
- string : str
- The string representation of an array.
- See Also
- --------
- array_str, array2string, set_printoptions
- Examples
- --------
- >>> np.array_repr(np.array([1,2]))
- 'array([1, 2])'
- >>> np.array_repr(np.ma.array([0.]))
- 'MaskedArray([0.])'
- >>> np.array_repr(np.array([], np.int32))
- 'array([], dtype=int32)'
- >>> x = np.array([1e-6, 4e-7, 2, 3])
- >>> np.array_repr(x, precision=6, suppress_small=True)
- 'array([0.000001, 0. , 2. , 3. ])'
- """
- return _array_repr_implementation(
- arr, max_line_width, precision, suppress_small)
- @_recursive_guard()
- def _guarded_repr_or_str(v):
- if isinstance(v, bytes):
- return repr(v)
- return str(v)
- def _array_str_implementation(
- a, max_line_width=None, precision=None, suppress_small=None,
- array2string=array2string):
- """Internal version of array_str() that allows overriding array2string."""
- if (_format_options['legacy'] <= 113 and
- a.shape == () and not a.dtype.names):
- return str(a.item())
- # the str of 0d arrays is a special case: It should appear like a scalar,
- # so floats are not truncated by `precision`, and strings are not wrapped
- # in quotes. So we return the str of the scalar value.
- if a.shape == ():
- # obtain a scalar and call str on it, avoiding problems for subclasses
- # for which indexing with () returns a 0d instead of a scalar by using
- # ndarray's getindex. Also guard against recursive 0d object arrays.
- return _guarded_repr_or_str(np.ndarray.__getitem__(a, ()))
- return array2string(a, max_line_width, precision, suppress_small, ' ', "")
- def _array_str_dispatcher(
- a, max_line_width=None, precision=None, suppress_small=None):
- return (a,)
- @array_function_dispatch(_array_str_dispatcher, module='numpy')
- def array_str(a, max_line_width=None, precision=None, suppress_small=None):
- """
- Return a string representation of the data in an array.
- The data in the array is returned as a single string. This function is
- similar to `array_repr`, the difference being that `array_repr` also
- returns information on the kind of array and its data type.
- Parameters
- ----------
- a : ndarray
- Input array.
- max_line_width : int, optional
- Inserts newlines if text is longer than `max_line_width`.
- Defaults to ``numpy.get_printoptions()['linewidth']``.
- precision : int, optional
- Floating point precision.
- Defaults to ``numpy.get_printoptions()['precision']``.
- suppress_small : bool, optional
- Represent numbers "very close" to zero as zero; default is False.
- Very close is defined by precision: if the precision is 8, e.g.,
- numbers smaller (in absolute value) than 5e-9 are represented as
- zero.
- Defaults to ``numpy.get_printoptions()['suppress']``.
- See Also
- --------
- array2string, array_repr, set_printoptions
- Examples
- --------
- >>> np.array_str(np.arange(3))
- '[0 1 2]'
- """
- return _array_str_implementation(
- a, max_line_width, precision, suppress_small)
- # needed if __array_function__ is disabled
- _array2string_impl = getattr(array2string, '__wrapped__', array2string)
- _default_array_str = functools.partial(_array_str_implementation,
- array2string=_array2string_impl)
- _default_array_repr = functools.partial(_array_repr_implementation,
- array2string=_array2string_impl)
- def set_string_function(f, repr=True):
- """
- Set a Python function to be used when pretty printing arrays.
- Parameters
- ----------
- f : function or None
- Function to be used to pretty print arrays. The function should expect
- a single array argument and return a string of the representation of
- the array. If None, the function is reset to the default NumPy function
- to print arrays.
- repr : bool, optional
- If True (default), the function for pretty printing (``__repr__``)
- is set, if False the function that returns the default string
- representation (``__str__``) is set.
- See Also
- --------
- set_printoptions, get_printoptions
- Examples
- --------
- >>> def pprint(arr):
- ... return 'HA! - What are you going to do now?'
- ...
- >>> np.set_string_function(pprint)
- >>> a = np.arange(10)
- >>> a
- HA! - What are you going to do now?
- >>> _ = a
- >>> # [0 1 2 3 4 5 6 7 8 9]
- We can reset the function to the default:
- >>> np.set_string_function(None)
- >>> a
- array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
- `repr` affects either pretty printing or normal string representation.
- Note that ``__repr__`` is still affected by setting ``__str__``
- because the width of each array element in the returned string becomes
- equal to the length of the result of ``__str__()``.
- >>> x = np.arange(4)
- >>> np.set_string_function(lambda x:'random', repr=False)
- >>> x.__str__()
- 'random'
- >>> x.__repr__()
- 'array([0, 1, 2, 3])'
- """
- if f is None:
- if repr:
- return multiarray.set_string_function(_default_array_repr, 1)
- else:
- return multiarray.set_string_function(_default_array_str, 0)
- else:
- return multiarray.set_string_function(f, repr)
|