Scientific Notation in REPL

Is there a way to temporally change show() not to use scientific notation in REPL? or at least print with specific power of n, ex. e3 or e12 ?

I’m not used to using scientific notation and seeing two values in different notation isn’t obvious at glance which value is larger.

julia> [1000000.0, 10000.0]
2-element Vector{Float64}:
     1.0e6
 10000.0

The documentation says that show() is the function to print in REPL. But not sure how to customize it.

Is it possible to show the values in either way?

julia> [1000000.0, 10000.0]
2-element Vector{Float64}:
1000000.0
  10000.0

or

julia> [1000000.0, 10000.0]
2-element Vector{Float64}:
1000.0e3
  10.0e3
1 Like

Maybe via IOContext I/O and Network · The Julia Language ?

Otherwise you need to override a Base.show method.

What would you like it to print?

See one example of customization in this post.

2 Likes

This doesn’t help with the solution you’re looking for, but for the issue of which one is larger- it’s always the one in scientific notation, because the printing only switches to it for large values.

Edit: at least I think so- I always assumed this is how it works but I’m not sure that’s written anywhere…

1 Like
1 Like

Thanks @rafael.guerra, this seems to be the easiest one:

julia> [1000000.0, 10000.0]
2-element Vector{Float64}:
     1.0e6
 10000.0

julia> using Printf

julia> Base.show(io::IO, f::Float64) = @printf(io, "%.1f", f)

julia> [1000000.0, 10000.0]
2-element Vector{Float64}:
 1000000.0
   10000.0

julia> 

it seems to me that NumericIO.jl is a bit behind?

  • It’s still using ~/.juliarc.jl, as it’s been replaced by ~/.julia/config/startup.jl in Julia 1.0 (.juliarc.jl in Julia1.0)
  • REPL setup in the README doesn’t work with Julia 1.7.
julia> using NumericIO
julia> Base.display(r::Base.REPL.REPLDisplay, v::Union{Float32,Float64}) = print(formatted(Base.REPL.outstream(r.repl), :SI, ndigits=4), v)
ERROR: UndefVarError: REPL not defined
Stacktrace:
 [1] getproperty(x::Module, f::Symbol)
   @ Base ./Base.jl:35
 [2] top-level scope
   @ REPL[7]:1
1 Like

@MA_Laforge might have more to say

Thanks for pinging me. @jar1

I haven’t touched this module in quite a while.
I’ll try to revisit that example sometime this week. I should definitively at least update to the readme to point to juliarc.jlstartup.jl.

2 Likes

Correct: REPL moved out of base and into its own module.

You now have to write:

import REPL
using NumericIO
Base.display(r::REPL.REPLDisplay, v::Union{Float32,Float64}) = print(formatted(REPL.outstream(r.repl), :SI, ndigits=4), v)

Dangers of overwriting show()

I recommend against overwriting show() as it is somewhat of a base function, and changing it might have unexpected repercussions in other modules elsewhere.

It is much safer to overwrite the Base.display() function, as it applies only to results displayed to the REPL (aka Julia “console”). REPL output is meant for human consumption, and is not typically read back by machine.

For more details on the display/print/show/… call stack, you might want to take a look here:

(Note that display calls either print() or show()… but I did not draw it on that diagram).

Changing Vectors/Arrays are displayed

Unfortunately, Julia will not change how it displays vectors if you overwrite the Base.display(r::REPL.REPLDisplay, v::Union{Float32,Float64}) method.

That’s because the call tree used to display vectors does not call display() on individual elements of the array/vector.

Here is an example of what you could define to customize the display() of numeric Vectors.

import REPL
using NumericIO

function Base.display(r::REPL.REPLDisplay, v::Vector)
	N = length(v)
	println(REPL.outstream(r.repl), N, "-element ", typeof(v), ":")
	for v_i in v
		println(formatted(REPL.outstream(r.repl), :SI, ndigits=4), v_i)
	end
end

And what about Arrays?

"Array"s seem to use a more elaborate algorithm to display its multi-dimensional contents while maintaining good readability. You would have to experiment a bit to get your display(::Array, ...) function to produce pleasant results.

Comments

I honestly think we should consider re-evaluating how the Julia call tree display()s vectors & arrays so we can more easily switch out how numbers are displayed on the REPL.

What you are requesting sounds fairly reasonable to me - but I’m not convinced the solution is that trivial.

3 Likes

Would you mind elaborating me a bit more? In what case does a module read the string from show()? Does it solve if I specify io to be stdout?

I assume you meant that some functions are relying on show() to convert values to string. ex) repr()?

help?> repr()

repr(x; context=nothing)

Create a string from any value using the show function. You
should not add methods to repr; define a show method
instead.

Indeed: repr() is an example of unintended consequences - but let me paint a clearer picture…

More generally:

Overwriting the show(::IO, ::Float64) method means you are modifying how pretty much ALL code EVERYWHERE where Julia functions print() Float64 values. This doesn’t just affect the REPL output.

Let’s assume you overwrite show as:

Base.show(io::IO, f::Float64) = @printf(io, "%.1f", f)

That means that if some code somewhere was trying to print out 4.2e-6 to file… then it would end up writing “0.0” instead of “4.2e-6” (The normal behaviour).

Just like that, your one line of code broke pretty much any other function that needed to accurately write out fractional values that are significantly smaller than one to an ::IO device (like a file).

Maybe that’s ok if you write a tiny little custom program that doesn’t really rely on other functions… Maybe.

That being said: I strongly recommend you don’t do this unless you really just want a quick and dirty solution for your (throw-away) Julia-as-a-line-calculator session.

2 Likes

I wrote this function for this purpose. I keep it in my startup.jl . If I knew Julia better, I would make this into another dispatch of the @printf macro or, more to the point in this case, the show() function

""" 
    printfa = print format array
"""
function printfa(A, fmt="%7.3f")
    print("[")
    if ndims(A) == 1
        for i in range(1, stop=length(A))
            @eval @printf($fmt, $A[$i])
            if i != length(A)
                print(", ")
            end
        end
    else
        m, n = size(A)
        for i in range(1, stop=m), j in range(1, stop=n)
            @eval @printf($fmt, $A[$i, $j])
            if j < n
                print(" ")
            elseif j == n && i < m
                print("; \n")
            end
        end
    end
    println("]")

end