Array of Plot objects

I want to make an array containing plots, but the two approaches I’ve tried both fail.

My first approach was to allocate an empty array and push! new plot objects:

p_arr1 = Array{Plots.Plot{Plots.GRBackend},1}[]
push!(p_arr1, plot(1:10,rand(10))) 
# MethodError: Cannot `convert` an object of type
# Plots.Plot{Plots.GRBackend} to an object of type 
# Array{Plots.Plot{Plots.GRBackend},1}

My second approach was to resize an existing array and assign by index:

p_arr2 = [plot(1:10,rand(10))]
p_arr2[1] = plot(1:10,rand(10))
p_arr2[2] = plot(1:10,rand(10))
# UndefRefError: access to undefined reference

Any ideas?

That’s just not the right syntax. You want Array{...}() not Array{...}[]. Your code was creating a new array of arrays of plots.

Alternatively you can do

p_arr1 = Plots.Plot{Plots.GRBackend}[]

That did it! Thanks. I’m new to Julia and am still trying to figure out the syntax in places.

This works too! And it’s more concise if you won’t be pre-allocating at a certain size (as e.g., Array{...}(undef, 10)). I’m sorry I’m not able to mark both answers as a solution!

In case you’re curious, the syntax T[] means "a 1D array of T". You’ll usually see it used as Int[] meaning “a 1D array of Ints”, but that T can be any type at all. Thus, Array{Plot, 1}[] means "an array of Array{Plot, 1}. Even though that’s not what you want here, it’s a perfectly valid thing to construct, so the language will let you do it.

1 Like

Yes, I’m definitely curious – I want to get a proper handle on all this, so thanks.

Supposing you used the A = Int[] syntax, is it possible to later change it to a 3x2 array? Using reshape(A, 3, 2) naturally yields an error: DimensionMismatch("new dimensions (3, 2) must be consistent with array size 0"). Does Julia have a way to resize arrays (prior to reshaping), or do you have to allocate a new array? I suppose you could push! yourself to the correct length prior to re-shaping…

Yup, you want resize!:

julia> A = Int[]
0-element Array{Int64,1}

julia> resize!(A, 3 * 2)
6-element Array{Int64,1}:

julia> reshape(A, 3, 2)
3×2 Array{Int64,2}:
 140500550566576  140500550566768
 140500550566672  140500550566816
 140500550566720  140500550566864

You can also skip resizing by doing:

A = Array{Int, 1}(undef, 6)

or, exactly equivalently:

A = Vector{Int}(undef, 6)

because Vector{T} is an alias for Array{T, 1}.

Or you can directly construct a 3x2 array and skip all the steps:

Array{Int, 2}(undef, 3, 2)

and again, equivalently:

Matrix{Int}(undef, 3, 2)

because Matrix{T} === Array{T, 2}.

1 Like

Great – thanks. It will be particularly good to know that Vector{T} == Array{T, 1} and Matrix{T} == Array{T, 2}.

If I can bug you about one more question… consider:

julia> A = Array{Int}(6, 3, undef)

6×3 Array{Int64,2}:
 300060112  134827984  131543120
 131543120  131543120  131543120
 300074896  300238224  131543120
 300084816  300239152  131543120
 131543120  151583056  131543120
 151583056  926541680          0

julia> A = Array{Int}(6, 3, undef)
3×6 LinearAlgebra.Transpose{Int64,Array{Int64,2}}:
 300060112  131543120  300074896  300084816  131543120  151583056
 134827984  131543120  300238224  300239152  151583056  926541680
 131543120  131543120  131543120  131543120  131543120          0

After transposing, it has a new LinearAlgebra.Transpose type. That’s fine… but it also changes the shape to 3x6 from 6x3. I would think it would either retain its type and change its shape, or else it would change its type but retain its shape. Do you have any insights into this?

(As to the array values – these just whatever values were in memory at the array’s address when declared with undef, right?)

I see, you want it to be printed as a “transpose of a 6x3 matrix” not a “6x3 transposed matrix”. That’s not unreasonable, but FWIW I don’t agree. The transposed result definitely has 3 rows and 6 columns, so printing it as such seems reasonable to me.

(As to the array values – these just whatever values were in memory at the array’s address when declared with undef , right?)

Yup, exactly.

1 Like

Okay, that makes sense… the user wants to see what the actual dimensions are. And Julia defines it as a new Transpose type because maybe it makes the math easier later (rather than having to actually shuffle anything around in memory)? By specifying it to be of Transpose type, Julia is making itself a note as to how to index the array?

Yeah, that’s exactly right. The Transpose is just a pointer to the original data and a clue about how to index it. That means that doing A' * B doesn’t have to copy all the data in A just to create A'. And even cooler is the fact that A' * B can be implemented using a special method for multiplication of a Transpose and an Array, for which there are dedicated BLAS algorithms we can call.