# Nice printing of some values of an array

**URL:** <https://discourse.julialang.org/t/nice-printing-of-some-values-of-an-array/109512>\
**Category:** General Usage\
**Tags:** macros, pretty-printing\
**Created:** [January 31, 2024, 1:37pm UTC](https://discourse.julialang.org/t/nice-printing-of-some-values-of-an-array/109512 "2024-01-31T13:37:03Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Gravlax](https://avatars.discourse-cdn.com/v4/letter/g/dbc845/32.png) [@Gravlax](https://discourse.julialang.org/u/Gravlax)\
**Post date:** [January 31, 2024, 1:37pm UTC](https://discourse.julialang.org/t/nice-printing-of-some-values-of-an-array/109512/1 "2024-01-31T13:37:03Z")

</div>

During a simulation, it can be useful to monitor some representative values of an array (mean, max, min, median).  
With a colleague, we’ve tried to write a function or macro that prints the minimum and maximum value of an array.  
The idea was to pass only one argument, the array of interest. Then, the function or macro would internally retrieve the variable name, the values of interest (e.g. `minimum(x)') and print a string. The current MWE looks like this:

```julia
macro minmax(x)
    quote
        name = $(string(x))
        var = $(esc(x))
        info = @sprintf("min(%05s) = %2.4e --- max(%05s) = %2.4e\n", name, minimum(var), name, maximum(var))
        print(info)
    end
end

```

So one can call the macro like this `@minmax(x)` and get, e.g.:  
`min( x) = 1.0000e+00 --- max( x) = 1.0000e+00`

1. _Question 0_: Is there already a package that provides such type of functions/macros?

2. _Question 1_: That’s handy but as it’s a macro, I don’t think it’s possible to use multiple dispatch to change the formatting of number based on the type of `x`. Or is it possible?  
For example, it would be great to print using `%d` if `x` is an integer array.

3. _Question 2_: Regarding formatting. Now lets assume I have arrays with different values, some have only positive values, some have both positive and negative values, some only negative:

```julia
# Arrays
x = ones(10)
y = -1*ones(10)
z = ones(10)
z[1] = -1

# Print info
@minmax(x)
@minmax(y)
@minmax(z)

```

This returns an output which is all shifted because of the occurrence of minus signs:

```julia-repl
min( x) = 1.0000e+00 --- max( x) = 1.0000e+00
min( y) = -1.0000e+00 --- max( y) = -1.0000e+00
min( z) = -1.0000e+00 --- max( z) = 1.0000e+00

```

Would there be a way to avoid this shift and get everything nicely aligned?

Any thoughts would be welcome!

A potential extension could be to also print the physical dimension, that would be cool…

---

<div class="post-metadata">

**Author:** ![barucden](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/barucden/32/26154_2.png) [@barucden](https://discourse.julialang.org/u/barucden)\
**Post date:** [January 31, 2024, 2:11pm UTC](https://discourse.julialang.org/t/nice-printing-of-some-values-of-an-array/109512/2 "2024-01-31T14:11:24Z")

</div>

If you printed a summary for all the arrays at once, the best solution would probably be to use PrettyTables.jl. But as I understand it, you have a running simulation and wish to summarize an array in each iteration. In that case, it is difficult (impossible) to align the lines when you don’t know what to the future arrays will contain (current array might contain only single-digit numbers, but the following array might contain triple-digit numbers). Nevertheless, you might have some intuition about what the value ranges are. I would avoid macros and tried something like this:

```julia
using Printf

# fmt_val is supposed to provide a string representation of `x` 
# in the desired format
fmt_val(x) = string(x)
fmt_val(x::Integer) = x < 0 ? string(x) : " " * string(x)

# This might be useful when, e.g., minimum returns single-digit integers, 
# but maximum returns triple-digit integers. In that case, you want to 
# differentiate between integers returned from minimum and maximum.
struct CustomResult{T}
    x::T
end
fmt_val(x::CustomResult{<:Integer}) = @sprintf "%05d" x.x
fmt_val(x::CustomResult{<:Real}) = @sprintf "%05.4f" x.x

custom_maximum(vals) = CustomResult(maximum(vals))

function minmax(name, vals)
    # list of values to compute together with their labels
    summaries = ["min" => minimum,
                 "max" => maximum,
                 "mymax" => custom_maximum]
    print(name, ": ")
    for (i, (label, func)) in enumerate(summaries)
        print(label, "=", fmt_val(func(vals)))
        i < length(summaries) && print(", ")
    end
    println()
end

```

Since it is a function, you would have to pass the variable name:

```julia
julia> minmax("x", [1, 2, 3, 54])
x: min= 1, max= 54, mymax=00054

julia> minmax("x", [1, 2.2, 3, 54])
x: min=-54.0, max=3.0, mymax=3.0000

```

---

<div class="post-metadata">

**Author:** ![Gravlax](https://avatars.discourse-cdn.com/v4/letter/g/dbc845/32.png) [@Gravlax](https://discourse.julialang.org/u/Gravlax)\
**Post date:** [January 31, 2024, 2:27pm UTC](https://discourse.julialang.org/t/nice-printing-of-some-values-of-an-array/109512/3 "2024-01-31T14:27:45Z")

</div>

Thanks a lot for the input. It’s a nice one that switches printing style based on the type, cool!  
Yes, I would like to call these functions at each iteration.

I guess there will be no way to get these points at the same time:

- pass the variable only, not also a string representing its name (because one needs a macro for this)
- use multiple dispatch (because one needs a function for this)
- make sure that the text is aligned (because it’s not possible)

Right?

---

<div class="post-metadata">

**Author:** ![barucden](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/barucden/32/26154_2.png) [@barucden](https://discourse.julialang.org/u/barucden)\
**Post date:** [January 31, 2024, 2:46pm UTC](https://discourse.julialang.org/t/nice-printing-of-some-values-of-an-array/109512/4 "2024-01-31T14:46:40Z")

</div>

> [@Gravlax](#):
>
> - pass the variable only, not also a string representing its name (because one needs a macro for this)
> - use multiple dispatch (because one needs a function for this)

These are not mutually exclusive. You can implement `minmax` as a macro and `fmt_val` as a function with many methods. I just prefer to avoid macros.

> [@Gravlax](#):
>
> - make sure that the text is aligned (because it’s not possible)

I don’t think you can guarantee alignment without knowing what values to expect.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [January 31, 2024, 3:15pm UTC](https://discourse.julialang.org/t/nice-printing-of-some-values-of-an-array/109512/5 "2024-01-31T15:15:21Z")

</div>

> [@Gravlax](#):
>
> Would there be a way to avoid this shift and get everything nicely aligned?

You can provide a large enough width field:

```julia
using Printf
@printf("min(x) = %11.3e .... max(x) = %11.3e", extrema(rand(Int)*(rand(5) .-0.5))...)

min(x) = -1.281e+16 .... max(x) = 4.409e+16
min(x) = -6.228e+17 .... max(x) = 5.941e+17
min(x) = 4.455e+17 .... max(x) = 4.238e+18
min(x) = -1.418e+18 .... max(x) = 2.560e+18

```

---

<div class="post-metadata">

**Author:** ![Gravlax](https://avatars.discourse-cdn.com/v4/letter/g/dbc845/32.png) [@Gravlax](https://discourse.julialang.org/u/Gravlax)\
**Post date:** [January 31, 2024, 5:38pm UTC](https://discourse.julialang.org/t/nice-printing-of-some-values-of-an-array/109512/6 "2024-01-31T17:38:25Z")

</div>

Thanks a lot to all of you!  
By combining your advices, I could reach want I wanted.

- the macro call takes a single argument.
- it generates the name from the variable internally
- it changes printing style based on the type of array
- the printed lines are nicely aligned

```julia
_minmax(name, var::Array{Int64}) = @sprintf("min(%06s) = %+011d --- max(%06s) = %+011d\n", name, minimum(var), name, maximum(var))
_minmax(name, var::Array{Float64}) = @sprintf("min(%06s) = %11.3e --- max(%06s) = %11.3e\n", name, minimum(var), name, maximum(var))

macro minmax(x)
    quote
        name = $(string(x))
        var = $(esc(x))
        info = _minmax(name, var)
        print(info)
    end
end

```
