AxisKeys.jl icon indicating copy to clipboard operation
AxisKeys.jl copied to clipboard

Unable to use Tuples to label a KeyedArray

Open ParadaCarleton opened this issue 4 years ago • 2 comments

Trying to construct an array where the labels are stored in a tuple throws an error:

  MethodError: no method matching axes(::Tuple{Symbol, Symbol, Symbol}, ::Int64)
  Closest candidates are:
    axes(::Tuple) at tuple.jl:28
    axes(::TArray, ::Any...) at /home/lime/.julia/packages/Libtask/RQkfZ/src/tarray.jl:198
    axes(::DataFrames.GroupKey, ::Integer) at /home/lime/.julia/packages/DataFrames/vuMM8/src/groupeddataframe/groupeddataframe.jl:517

The code that generated this error --

table = KeyedArray(data; model=model_names, statistic=(:cv_diff, :se_cv_diff, :weight))

I'm guessing this is unintended, and the method is accidentally overtyped. If it's intentional, KeyedArray should probably be typed in such a way as to to avoid passing a tuple in the first place

ParadaCarleton avatar Aug 11 '21 02:08 ParadaCarleton

It does assume they are AbstractVectors; I see that the name-less constructor has an explicit check:

julia> table = KeyedArray(rand(3,3), ([1,2,3], (:cv_diff, :se_cv_diff, :weight)))
ERROR: ArgumentError: key vectors must all be AbstractVectors
Stacktrace:
 [1] construction_check(data::Matrix{Float64}, keys::Tuple{Vector{Int64}, Tuple{Symbol, Symbol, Symbol}})
   @ AxisKeys ~/.julia/dev/AxisKeys/src/struct.jl:28
 [2] KeyedArray(data::Matrix{Float64}, keys::Tuple{Vector{Int64}, Tuple{Symbol, Symbol, Symbol}})
   @ AxisKeys ~/.julia/dev/AxisKeys/src/struct.jl:13

The reason for this is that it wants to allow OffsetArrays, for which it needs always to think about axes not size, and Tuples have only the latter. It's possible that this could be worked around, but I'm not sure how much work it would be.

The named constructor accepts any number of keywords, and I didn't think you could also impose a type constraint:

julia> @less KeyedArray(rand(3,3); model=[1,2,3], statistic=(:cv_diff, :se_cv_diff, :weight))

julia> f1(; kw...) = kw;

julia> f1(; a=1, b=2)
pairs(::NamedTuple) with 2 entries:
  :a => 1
  :b => 2

julia> f2(; kw::Int...) = kw;
ERROR: syntax: "kw::Int" is not a valid function argument name around REPL[163]:1

It could perhaps be arranged that this hit the construction_check error first, though.

mcabbott avatar Aug 11 '21 03:08 mcabbott

@mcabbott I would think you could replace the types in the constructor that say AbstractVector with AbstractVecOrTuple, then just insert this at the top of the constructor:

for kwarg in kwargs
    if kwarg isa Tuple
        kwarg = [kwarg[i] for i in length(kwarg)]
    end
end

Which will convert the tuples to vectors.

ParadaCarleton avatar Aug 29 '21 17:08 ParadaCarleton