From 25a66e33039d915265904f3b6c2580066ae8a58a Mon Sep 17 00:00:00 2001 From: Chris Foster Date: Wed, 5 Dec 2018 15:45:19 +1000 Subject: [PATCH] Access to the values of an axis by name using getproperty This is particularly useful and succinct when you're working on domain specific data with known axis names. --- docs/src/index.md | 17 +++++++++++++++-- src/core.jl | 14 ++++++++++++++ test/core.jl | 12 ++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/docs/src/index.md b/docs/src/index.md index 0fe85e9..3e74d39 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -79,8 +79,21 @@ And data, a 2400001×2 Array{Float64,2}: ``` -AxisArrays behave like regular arrays, but they additionally use the axis -information to enable all sorts of fancy behaviors. For example, we can specify +AxisArrays behave like regular arrays, but they carry extra information about +their axes along with them: + +```jldoctest +julia> A.time +0.0 s:2.5e-5 s:60.0 s + +julia> A.chan +2-element Array{Symbol,1}: + :c1 + :c2 + +``` + +This enables all sorts of fancy indexing behaviors. For example, we can specify indices in *any* order, just so long as we annotate them with the axis name: ```jldoctest diff --git a/src/core.jl b/src/core.jl index 9f3a8d9..8fb06e7 100644 --- a/src/core.jl +++ b/src/core.jl @@ -285,6 +285,20 @@ function axisdim(::Type{AxisArray{T,N,D,Ax}}, ::Type{<:Axis{name,S} where S}) wh idx end +# Access to the values of axes by name +function Base.getproperty(A::AxisArray, name::Symbol) + if name === :data || name === :axes + getfield(A, name) + else + # Other things are axis names + getfield(A, :axes)[axisdim(A, Axis{name})].val + end +end +function Base.propertynames(A::AxisArray, private=false) + ns = axisnames(A) + private ? (ns..., :data, :axes) : ns +end + # Base definitions that aren't provided by AbstractArray @inline Base.size(A::AxisArray) = size(A.data) @inline Base.size(A::AxisArray, Ax::Axis) = size(A.data, axisdim(A, Ax)) diff --git a/test/core.jl b/test/core.jl index 01d1b05..874ea5a 100644 --- a/test/core.jl +++ b/test/core.jl @@ -167,6 +167,18 @@ A = @inferred(AxisArray(reshape(1:24, 2,3,4), @test axisdim(A, Axis{:x}) == axisdim(A, Axis{:x}()) == 1 @test axisdim(A, Axis{:y}) == axisdim(A, Axis{:y}()) == 2 @test axisdim(A, Axis{:z}) == axisdim(A, Axis{:z}()) == 3 +# Test that getproperty is fully inferred when a const name is supplied +let getx(A) = A.x, + getz(A) = A.z, + getdata(A) = A.data + @test @inferred(getx(A)) == A.axes[1].val + @test @inferred(getz(A)) == A.axes[3].val + @test @inferred(AxisArrays.axes(A)) === A.axes + @test @inferred(getdata(A)) === A.data +end +@test propertynames(A) == (:x, :y, :z) +@test propertynames(A, true) == (:x, :y, :z, :data, :axes) + # Test axes @test @inferred(AxisArrays.axes(A)) == (Axis{:x}(.1:.1:.2), Axis{:y}(1//10:1//10:3//10), Axis{:z}(["a", "b", "c", "d"])) @test @inferred(AxisArrays.axes(A, Axis{:x})) == @inferred(AxisArrays.axes(A, Axis{:x}())) == Axis{:x}(.1:.1:.2)