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).

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.