Display of arrays with row and column names

I’m aware of some previous threads discussing this topic, but I do not find any way to conveniently reproduce what I can do with Octave, e.g.,

octave:1> cnames=["this"; "that"];
octave:2> a = rand(3,2);
octave:3> prettyprint_c(a, cnames);
      this      that  
     0.486     0.294
     0.166     0.328
     0.826     0.974
octave:4> rnames = ["aaa";"bbb";"ccc"];
octave:5> prettyprint(a, rnames, cnames);
             this          that  
aaa         0.486         0.294
bbb         0.166         0.328
ccc         0.826         0.974
octave:6> 

Is something like this part of some package?

2 Likes

Maybe NamedArrays.jl? Depending on your task, DataFrames.jl might also be interesting.

2 Likes

Definitely NamedArrays or AxisArrays. DataFrames are more intended for data base like structures (and they do not support row names).

1 Like

It seems to me like there’s potentially two distinct issues here: maintaining a data structure with names and wanting to print out an existing matrix/table data structure with names. I’ve often thought we would benefit from writing a package that provides an API for printing matrices and tables with ad hoc formatting – which would include printing names.

I’ve seen people using DataFrames just because they prefer the way DataFrames are printed to the way matrices are printed.

4 Likes

Thanks for the suggestions. I hacked together a quick solution, which is just a proof of concept. It still takes me time to think of using loops, as I’m so used to avoiding them.

Contents of test.jl:

function prettyprint_c(a, cnames)
    for i = 1:size(a,2)
        @printf("%s  ", lpad(cnames[i],8," "))
    end
    @printf("\n")
    for i = 1:size(a,1)
        for j = 1:size(a,2)
            @printf("%f  ", a[i,j])
        end
        @printf("\n")
    end    
end
julia> include("test.jl")
prettyprint_c (generic function with 1 method)

julia> prettyprint_c(rand(2,2), cnames)
     red     green  
0.538184  0.921006  
0.771004  0.036080  

julia>

Here’s another version, a little more elaborate. I haven’t figured out how to allow for user specified printing format of the numbers.

function prettyprint(a, cnames, rnames="",digits=8, decimals=4)
    # TBD: try to use this to allow using specified digits and decimals
    #fmt = @sprintf("%d",digits)"."@sprintf("%d",decimals)"%f"
    #@eval dofmt(x) = @sprintf($fmt, x)
    
    # print column names
    for i = 1:size(a,2)
        pad = digits
        if rnames != "" && i==1
            pad = 2*digits
        end    
        @printf("%s", lpad(cnames[i],pad," "))
    end
    @printf("\n")
    # print the rows
    for i = 1:size(a,1)
        if rnames != ""
            @printf("%s", lpad(rnames[i],digits," "))
        end
        for j = 1:size(a,2)
            # TBD: use fmt defined above to print array contents
            @printf("%8.4f",(a[i,j]))
        end
        @printf("\n")
    end    
end  

This is what it gives you:

julia> prettyprint(rand(3,2), ["r","b"], ["1","2","3"])
               r       b
       1  0.1127  0.0660
       2  0.4678  0.1982
       3  0.3126  0.1833

julia> prettyprint(rand(3,2), ["r","b"])
       r       b
  0.9553  0.9253
  0.8519  0.8340
  0.1447  0.1828

julia>
1 Like

You could just put strings at the top of the array:

julia> cnames = ["this" "that"];

julia> a = rand(3,2);

julia> [cnames; a]
4×2 Array{Any,2}:
  "this"    "that" 
 0.919038  0.959908
 0.54821   0.954816
 0.448264  0.135813

This prints out the strings in quotation marks, which is a little annoying, but you can eliminate the quotes in display by wrapping them in a Text object:

julia> [Text.(cnames); a]
4×2 Array{Any,2}:
  this      that   
 0.919038  0.959908
 0.54821   0.954816
 0.448264  0.135813

If you want to avoid the header, you have to call the internal showarray function:

julia> Base.showarray(STDOUT, [Text.(cnames); a], false, header=false)
  this      that   
 0.919038  0.959908
 0.54821   0.954816
 0.448264  0.135813
1 Like

The show method in NamedArrays is very good IMHO
https://github.com/davidavdav/NamedArrays.jl/blob/b6a3b1d03214ba8b977b85944ea1bb47c7796495/src/show.jl#L96

This seems like a nice solution. On top of this, I’m using Base.print_matrix, which is giving me the format I’d like:

julia> cnames = ["this" "that"]
1×2 Array{String,2}:
 "this"  "that"

julia> a = rand(3,2)
3×2 Array{Float64,2}:
 0.527699  0.416864
 0.154895  0.953161
 0.642032  0.309332

julia> Base.print_matrix(stdout, [Text.(cnames); a])
  this                 that
 0.5276986161946835   0.41686414033643016
 0.15489479331644973  0.9531611170842169
 0.6420319865177682   0.3093316412409517

I saw this requirement more than once including in SO. I think that a native prettyprint function for matrices would be very convenient.