-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
set_display_precision!(n) in REPL to control floating-point display #52543
base: master
Are you sure you want to change the base?
Conversation
@StefanKarpinski, should I continue to pursue this? |
|
||
PrecisionIO(io::IO, precision::AbstractDict, compact_precision::AbstractDict) = | ||
new{typeof(io)}(io, precision, compact_precision) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The alternative to defining a new PrecisionIO <: IO
subtype to propagate this information is to simply use IOContext
with a :precision => <digits>
option. Using a plain IOContext
has both advantages and disadvantages:
Advantages of using IOContext
:
- Simpler, more user-accessible implementation. (Documented with the other
IOContext
flags.) - Easier for other packages (e.g. DecFP.jl) to support for their own floating-point types (don't have to depend on
InteractiveUtils.PrecisionIO
internals). - More consistent with our other
IO
metadata (:compact
etc) - Easier to use in non-
display
contexts, e.g. if the user wants to write to a CSV file with fewer digits.
Disadvantages of using IOContext
:
- Can only support
%.*g
format, not arbitrary user-defined format strings. (Since otherwisebase/ryu/Ryu.jl
would have to depend on Printf.) - Less fine-grained control (probably we would just want
precision
to be an integer, apply to all supporting floating-point types, and override:compact
unconditionally). IOContext
flags are a global namespace, hence precious and poorly composable — it's not clear if any package is already using:precision
for something else?- Requires some refactoring of Printf stdlib, to move
%.*g
formatting toRyu.jl
.
Overall, I'm starting to be inclined more towards the IOContext
route. It's not clear to me that fine-grained control here (different precisions for different types, or compact
vs non-compact
mode) is particularly important — people mainly just want a way to show more (or fewer) digits in the REPL.
What do people think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IOContext
does seem like a more natural way to implement this.
This seems good! I had not seen it, but I will look now. |
Closes #6493: gives a way to control the REPL display precision (the number of significant digits displayed for floating-point values, and more generally the
printf
-style format string).This is a very common request from users. e.g. on discourse see here and here and here and here and here. A lot of the suggested solutions involve redefining
show(::IO, ::Float64)
, which is type piracy and non-composable.I wanted a solution which:
display
output (what the REPL uses to show results) and not output to any other stream (files, etcetera).display
I/O.startup.jl
and a running REPL (or IJulia etc) session. But if you somehow have multiple REPLs running in parallel from the same Julia process, they can still change their display formats independently.This PR adds two new functions exported by the
InteractiveUtils
stdlib (which is loaded in REPL and IJulia sessions):to set the displayed precision to
precision
, which can either be an integer number of significant digits (corresponding to a format string"%.*g"
) or an arbitraryprintf
format string, for the typeT
and its subtypes (defaulting toAbstractFloat
, i.e. all supported floating-point types). If you don't pass adisplay
argument, it affects all currently loadedAbstractDisplay
s (that support this settting) as well as a dictionary of defaults that is used for subsequently created REPL sessions (or IJulia sessions, in the future). By default, it affects the digits shown for all displays, but you can separately control the precision shown in:compact=>true
IOContext
s by passing thecompact=true
argument.Internally, a supporting display (currently just
REPLDisplay
, but IJulia can opt-in to this later) implements this by wrapping itsIO
stream in anInteractiveUtils.digitsio(io)
stream, which overloadsshow
for the built-inAbstractFloat
types (and external packages can opt-in for their ownAbstractFloat
types in the future). This way it has zero effect on any otherIO
stream. (IOContext
wrappers around aDigitsIO
stream inherit its floating-point display too.)For example:
As mentioned above, you can also use an arbitrary
printf
format string:Remaining issues
Before I do any more work on this, however, I want to get some feedback on the overall design. Do the core devs want something along these lines?
To do:
There is also the question of whether we only want to control digits (always format asUpdate: now optionally supports arbitrary format strings instead of a numeric precision, though I expect that most users will opt for the latter.%.*g
) or if we want a configurable format string (con: more complex; pro: more options, but is it actually useful in practice?). Configurable format strings could be added later on if desired — you'd still want a simple API where you just specify the precision, as well as a more advanced API where you pass a format string — but it would be easier for downstream packages (e.g. IJulia) if we build it in now. IPython's%precision
allows either an integer or a format string, so that may be a reasonable precedent for allowing a similar flexibility in Julia. (Maybe rename toset_display_precision!
)