Julia: limited printing of large arrays
Asked Answered
S

4

14

I produce a number of large arrays in Julia using a script file. Printing out the whole array is cumbersome but I'd like to check the first few rows make sense.

I know in the REPL there's printing which is limited by the screen size e.g.

julia> zeros(1000,10)
1000×10 Array{Float64,2}:
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
⋮                        ⋮                      
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0

But I can't find any print/show function in base Julia which mimics this for scripts, say only printing out the first 10 rows of an array or something like R's head (I would have expected showcompact to do something like this).

Is there an analogous function to R's head in Julia or do I have to write my own.

Shepley answered 24/11, 2016 at 13:59 Comment(2)
You should use IOContext for this.Shyamal
Julia >=1.6: first(x, 1) is your head equivalent and last(x, 1) your tail equivalent. See: docs.julialang.org/en/v1/base/collections/#Base.firstDetoxicate
S
22

As I mentioned in a comment, the way to do this in v0.5 is to use an IOContext.

A very simple way to limit the data is to pass the :limit => true parameter to the IOContext;

julia> show(IOContext(stdout, :limit => true), v)
[0.147959 0.414018 … 0.595528 0.852563; 0.32679 0.824953 … 0.432143 0.036279; … ; 0.877398 0.661854 … 0.197207 0.15596; 0.0522946 0.508075 … 0.835359 0.705987]

But this still does not print out the way the REPL does; that's because show with two arguments uses a single-line display. To use a multiline display, pass text/plain as the second argument to show (a MIME type):

julia> show(IOContext(stdout, :limit => true), "text/plain", v)
100×100 Array{Float64,2}:
 0.147959   0.414018   0.0282934  …  0.816132   0.595528   0.852563 
 0.32679    0.824953   0.0582351     0.822526   0.432143   0.036279 
 0.754989   0.724317   0.533966      0.987273   0.931932   0.973622 
 0.547866   0.282694   0.0295411     0.75929    0.886218   0.0813057
 0.0626663  0.111795   0.625083      0.439983   0.562143   0.669046 
 0.712093   0.469622   0.377298   …  0.298224   0.31853    0.376066 
 0.774625   0.754328   0.756725      0.61113    0.76566    0.999292 
 0.917846   0.308363   0.489246      0.715311   0.175302   0.124059 
 0.310922   0.140575   0.20635       0.0280192  0.683004   0.168129 
 0.753361   0.755103   0.831806      0.118009   0.122374   0.281476 
 ⋮                                ⋱                                 
 0.420264   0.7614     0.748408      0.330983   0.0776789  0.309464 
 0.984379   0.851735   0.595121      0.534982   0.255317   0.743713 
 0.814505   0.765941   0.71852       0.730677   0.477631   0.0360992
 0.910384   0.0747604  0.490685      0.0904559  0.0756424  0.313898 
 0.628416   0.0790874  0.401488   …  0.523521   0.397249   0.58112  
 0.578361   0.336352   0.261118      0.838256   0.387374   0.451647 
 0.66724    0.586342   0.378968      0.602694   0.450686   0.901279 
 0.877398   0.661854   0.685156      0.658952   0.197207   0.15596  
 0.0522946  0.508075   0.244423      0.95935    0.835359   0.705987 

You can of course change how many rows are shown by passing in :displaysize to the IOContext:

julia> show(IOContext(stdout, :limit => true, :displaysize => (10, 10)), "text/plain", v)

100×100 Array{Float64,2}:
 0.147959   …  0.852563
 0.32679       0.036279
 0.754989      0.973622
 ⋮          ⋱          
 0.877398      0.15596 
 0.0522946     0.705987

Overall, IOContext is very flexible. See its documentation for more details.

Shyamal answered 24/11, 2016 at 21:43 Comment(2)
That's exactly what I wanted. Thanks!Shepley
This is the first understandable example of IOContext that I've seen. +100!Aekerly
A
4

You could easily define a head function yourself. For one and two dimensions, this is pretty straightforward:

torange(n::Integer, m) = 1:min(n, m)
torange(c::Colon, m) = (:)

function head(a::AbstractArray{TypeVar(:T), 1}, n = 10)
    view(a, torange(n,size(a,1)))
end


function head(a::AbstractArray{TypeVar(:T), 2}, n1 = 10, n2 = 10)
        view(a, torange(n1, size(a,1)), torange(n2, size(a,2)))
end

The torange method allows to use a : to return the full length in the corresponding dimension. For example

head(zeros(10, 10), 5, :)
5×10 SubArray{Float64,2,Array{Float64,2},Tuple{UnitRange{Int64},Colon},false}:
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0

For more than two dimensions, I have chosen to repeat the last argument beginning from the third:

function head{Na, Nn}(a::AbstractArray{TypeVar(:T), Na}, n1 = 10, n2 = 10, ns::Vararg{TypeVar(:T), Nn} = 2)
        nend = last(ns)
        view(a, torange(n1, size(a,1)), torange(n2, size(a,2)), (torange(ns[i], size(a,i+2)) for i = 1:Nn)..., (torange(nend, size(a, i)) for i in Nn+3:Na)...)
end

For example:

head(rand(10, 10, 5, 5), 3, 3, 2)  # the last two is the default value and can be omitted
3×3×2×2 SubArray{Float64,4,Array{Float64,4},Tuple{UnitRange{Int64},UnitRange{Int64},UnitRange{Int64},UnitRange{Int64}},false}:
[:, :, 1, 1] =
 0.384724  0.7328   0.585211
 0.738284  0.95145  0.362914
 0.43928   0.94307  0.758541

[:, :, 2, 1] =
 0.78603   0.588877  0.677201
 0.559547  0.800559  0.488433
 0.993593  0.691884  0.236595

[:, :, 1, 2] =
 0.25732   0.90491   0.323905
 0.300924  0.703919  0.813316
 0.040522  0.776142  0.624097

[:, :, 2, 2] =
 0.746677   0.153574   0.155539 
 0.991624   0.90167    0.0880094
 0.0423263  0.0153597  0.0608328

Note that the n-dimensional version is not type-stable, but that shouldn't matter for printing.

Abeyant answered 24/11, 2016 at 16:58 Comment(3)
Aah that is a good way of doing it. Do you know if there is a base method that does limited printing in Julia?Shepley
I don't know. It would be nice if the default maximum printing length of the head and tail could be set for each dimension at the beginning of a script or session.Abeyant
In Julia 1.6+ you can use first(x, 10) and last(x, 10).Detoxicate
T
4

We can get the same output as REPL by using display() (is this what you are looking for...?) Also, the "head" and "tail" parts can be printed by using array sections, e.g.,

disp( x ) = ( display(x) ; println() ; println() )

A = diagm( [ i for i=1:100 ] )

disp( A )
disp( A[ 1:5, : ] )         # head
disp( A[ end-4:end, : ] )   # tail

B = [ i for i=1:100 ]

disp( B )
disp( B[ 1:5 ] )         # head
disp( B[ end-4:end ] )   # tail

$ julia test.jl

100x100 Array{Int64,2}:
 1  0  0  0  0  0  0  0  0   0  0  0  …  0   0   0   0   0   0   0   0    0
 0  2  0  0  0  0  0  0  0   0  0  0      0   0   0   0   0   0   0   0    0
 0  0  3  0  0  0  0  0  0   0  0  0      0   0   0   0   0   0   0   0    0
 0  0  0  4  0  0  0  0  0   0  0  0      0   0   0   0   0   0   0   0    0
 0  0  0  0  5  0  0  0  0   0  0  0      0   0   0   0   0   0   0   0    0
 0  0  0  0  0  6  0  0  0   0  0  0  …  0   0   0   0   0   0   0   0    0
 0  0  0  0  0  0  7  0  0   0  0  0      0   0   0   0   0   0   0   0    0
 0  0  0  0  0  0  0  8  0   0  0  0      0   0   0   0   0   0   0   0    0
 0  0  0  0  0  0  0  0  9   0  0  0      0   0   0   0   0   0   0   0    0
 0  0  0  0  0  0  0  0  0  10  0  0      0   0   0   0   0   0   0   0    0
 ⋮              ⋮               ⋮     ⋱                   ⋮                 
 0  0  0  0  0  0  0  0  0   0  0  0     92   0   0   0   0   0   0   0    0
 0  0  0  0  0  0  0  0  0   0  0  0      0  93   0   0   0   0   0   0    0
 0  0  0  0  0  0  0  0  0   0  0  0      0   0  94   0   0   0   0   0    0
 0  0  0  0  0  0  0  0  0   0  0  0      0   0   0  95   0   0   0   0    0
 0  0  0  0  0  0  0  0  0   0  0  0  …  0   0   0   0  96   0   0   0    0
 0  0  0  0  0  0  0  0  0   0  0  0      0   0   0   0   0  97   0   0    0
 0  0  0  0  0  0  0  0  0   0  0  0      0   0   0   0   0   0  98   0    0
 0  0  0  0  0  0  0  0  0   0  0  0      0   0   0   0   0   0   0  99    0
 0  0  0  0  0  0  0  0  0   0  0  0      0   0   0   0   0   0   0   0  100

5x100 Array{Int64,2}:
 1  0  0  0  0  0  0  0  0  0  0  0  0  … 0  0  0  0  0  0  0  0  0  0  0  0
 0  2  0  0  0  0  0  0  0  0  0  0  0     0  0  0  0  0  0  0  0  0  0  0  0
 0  0  3  0  0  0  0  0  0  0  0  0  0     0  0  0  0  0  0  0  0  0  0  0  0
 0  0  0  4  0  0  0  0  0  0  0  0  0     0  0  0  0  0  0  0  0  0  0  0  0
 0  0  0  0  5  0  0  0  0  0  0  0  0     0  0  0  0  0  0  0  0  0  0  0  0

5x100 Array{Int64,2}:
 0  0  0  0  0  0  0  0  0  0  0  0  0  … 0  0  0  0  0  96   0   0   0    0
 0  0  0  0  0  0  0  0  0  0  0  0  0     0  0  0  0  0   0  97   0   0    0
 0  0  0  0  0  0  0  0  0  0  0  0  0     0  0  0  0  0   0   0  98   0    0
 0  0  0  0  0  0  0  0  0  0  0  0  0     0  0  0  0  0   0   0   0  99    0
 0  0  0  0  0  0  0  0  0  0  0  0  0     0  0  0  0  0   0   0   0   0  100

100-element Array{Int64,1}:
   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
   ⋮
  92
  93
  94
  95
  96
  97
  98
  99
 100

5-element Array{Int64,1}:
 1
 2
 3
 4
 5

5-element Array{Int64,1}:
  96
  97
  98
  99
 100
Type answered 24/11, 2016 at 17:18 Comment(5)
Thanks, I guess this is the best option, though as tim said would be nice to set a default on the maximum printing lengthShepley
Yeah I agree, and I also write a custom pretty-print routine that has more control. But for simple cases display() is OK for me.Type
Though I don't seem to get the 'auto limits' with the ... notation as you do. I'm using Julia 0.5. So I'll have to just try and define my own function.Shepley
Ohhh, right, if I use v0.5, I did not get such "..." thing but a full list of numbers.... (I used v0.4.7 in the above test). Hmm..Type
Aah right so maybe it's an issue with v0.5! It might be worth raising the issue on github...Shepley
S
2

I believe this thread is out of date. For me on julia v1.4.1 , the display function does not print a limited array, and

a = zeros(1000,6)
show(IOContext(STDOUT, limit=true), "text/plain", a)

yields an error. Instead I found this works

a = zeros(1000,6)
show(IOContext(stdout, :limit => true), "text/plain", a)
Scrophulariaceous answered 24/5, 2021 at 17:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.