Skip to content

Commit 22eae14

Browse files
committed
Some generalizations for non-1 indices
1 parent d572dc3 commit 22eae14

File tree

5 files changed

+51
-14
lines changed

5 files changed

+51
-14
lines changed

src/core.jl

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,12 @@ Base.getindex(A::Axis, i...) = A.val[i...]
6161
Base.unsafe_getindex(A::Axis, i...) = Base.unsafe_getindex(A, i...)
6262
Base.eltype{_,T}(::Type{Axis{_,T}}) = eltype(T)
6363
Base.size(A::Axis) = size(A.val)
64+
Base.indices(A::Axis) = indices(A.val)
65+
Base.indices(A::Axis, d) = indices(A.val, d)
6466
Base.length(A::Axis) = length(A.val)
6567
@compat (A::Axis{name}){name}(i) = Axis{name}(i)
68+
Base.convert{name,T}(::Type{Axis{name,T}}, ax::Axis{name,T}) = ax
69+
Base.convert{name,T}(::Type{Axis{name,T}}, ax::Axis{name}) = Axis{name}(convert(T, ax.val))
6670

6771
@doc """
6872
An AxisArray is an AbstractArray that wraps another AbstractArray and
@@ -95,11 +99,12 @@ AxisArray(A::AbstractArray, vectors::AbstractVector...)
9599
* `A::AbstractArray` : the wrapped array data
96100
* `axes` or `names` or `vectors` : dimensional information for the wrapped array
97101
98-
The dimensional information may be passed in one of three ways and is entirely
99-
optional. When the axis name or value is missing for a dimension, a default is
100-
substituted. The default axis names for dimensions `(1, 2, 3, 4, 5, ...)` are
101-
`(:row, :col, :page, :dim_4, :dim_5, ...)`. The default axis values are the
102-
integer unit ranges: `1:size(A, d)` for each missing dimension `d`.
102+
The dimensional information may be passed in one of three ways and is
103+
entirely optional. When the axis name or value is missing for a
104+
dimension, a default is substituted. The default axis names for
105+
dimensions `(1, 2, 3, 4, 5, ...)` are `(:row, :col, :page, :dim_4,
106+
:dim_5, ...)`. The default axis values are `indices(A, d)` for each
107+
missing dimension `d`.
103108
104109
### Indexing
105110
@@ -166,12 +171,12 @@ AxisArray(A::AbstractArray, axs::Axis...) = AxisArray(A, axs)
166171
push!(ax.args, :(axs[$i]))
167172
end
168173
for i=L+1:N
169-
push!(ax.args, :(Axis{_defaultdimname($i)}(1:size(A, $i))))
174+
push!(ax.args, :(Axis{_defaultdimname($i)}(indices(A, $i))))
170175
end
171176
quote
172177
for i = 1:length(axs)
173178
checkaxis(axs[i].val)
174-
if length(axs[i].val) != size(A, i)
179+
if _length(axs[i].val) != _size(A, i)
175180
throw(ArgumentError("the length of each axis must match the corresponding size of data"))
176181
end
177182
end
@@ -183,7 +188,7 @@ AxisArray(A::AbstractArray, axs::Axis...) = AxisArray(A, axs)
183188
end
184189
# Simple non-type-stable constructors to specify just the name or axis values
185190
AxisArray(A::AbstractArray) = AxisArray(A, ()) # Disambiguation
186-
AxisArray(A::AbstractArray, names::Symbol...) = AxisArray(A, ntuple(i->Axis{names[i]}(1:size(A, i)), length(names)))
191+
AxisArray(A::AbstractArray, names::Symbol...) = AxisArray(A, map((name,ind)->Axis{name}(ind), names, indices(A)))
187192
AxisArray(A::AbstractArray, vects::AbstractVector...) = AxisArray(A, ntuple(i->Axis{_defaultdimname(i)}(vects[i]), length(vects)))
188193

189194
# Axis definitions
@@ -214,6 +219,9 @@ end
214219
Base.size(A::AxisArray) = size(A.data)
215220
Base.size(A::AxisArray, Ax::Axis) = size(A.data, axisdim(A, Ax))
216221
Base.size{Ax<:Axis}(A::AxisArray, ::Type{Ax}) = size(A.data, axisdim(A, Ax))
222+
Base.indices(A::AxisArray) = indices(A.data)
223+
Base.indices(A::AxisArray, Ax::Axis) = indices(A.data, axisdim(A, Ax))
224+
Base.indices{Ax<:Axis}(A::AxisArray, ::Type{Ax}) = indices(A.data, axisdim(A, Ax))
217225
Base.linearindexing(A::AxisArray) = Base.linearindexing(A.data)
218226
Base.convert{T,N}(::Type{Array{T,N}}, A::AxisArray{T,N}) = convert(Array{T,N}, A.data)
219227
# Similar is tricky. If we're just changing the element type, it can stay as an
@@ -233,25 +241,25 @@ Base.similar{T}(A::AxisArray{T}, S::Type, dims::Tuple{Vararg{Int}}) = similar(A.
233241
Base.similar{T}(A::AxisArray{T}, axs::Axis...) = similar(A, T, axs)
234242
Base.similar{T}(A::AxisArray{T}, S::Type, axs::Axis...) = similar(A, S, axs)
235243
@generated function Base.similar{T,N}(A::AxisArray{T,N}, S::Type, axs::Tuple{Vararg{Axis}})
236-
sz = Expr(:tuple)
244+
inds = Expr(:tuple)
237245
ax = Expr(:tuple)
238246
for d=1:N
239-
push!(sz.args, :(size(A, Axis{$d})))
247+
push!(inds.args, :(indices(A, Axis{$d})))
240248
push!(ax.args, :(axes(A, Axis{$d})))
241249
end
242250
to_delete = Int[]
243251
for i=1:length(axs.parameters)
244252
a = axs.parameters[i]
245253
d = axisdim(A, a)
246254
axistype(a) <: Tuple{} && push!(to_delete, d)
247-
sz.args[d] = :(length(axs[$i].val))
255+
inds.args[d] = :(indices(axs[$i].val, 1))
248256
ax.args[d] = :(axs[$i])
249257
end
250258
sort!(to_delete)
251-
deleteat!(sz.args, to_delete)
259+
deleteat!(inds.args, to_delete)
252260
deleteat!(ax.args, to_delete)
253261
quote
254-
d = similar(A.data, S, $sz)
262+
d = similar(A.data, S, $inds)
255263
AxisArray(d, $ax)
256264
end
257265
end
@@ -356,3 +364,10 @@ function checkaxis(::Type{Categorical}, ax)
356364
push!(seen, elt)
357365
end
358366
end
367+
368+
_length(A::AbstractArray) = length(linearindices(A))
369+
_length(A) = length(A)
370+
_size(A::AbstractArray) = map(length, indices(A))
371+
_size(A) = size(A)
372+
_size(A::AbstractArray, d) = length(indices(A, d))
373+
_size(A, d) = size(A, d)

src/indexing.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ end
7878
push!(newaxes, :($(Axis{names[d]})(A.axes[$d].val[J[$d]])))
7979
elseif I[d] <: AbstractArray
8080
for i=1:ndims(I[d])
81-
push!(newaxes, :($(Axis{Symbol(names[d], "_", i)})(1:size(I[$d], $i))))
81+
push!(newaxes, :($(Axis{Symbol(names[d], "_", i)})(indices(I[$d], $i))))
8282
end
8383
end
8484
end

src/sortedvector.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ Base.getindex(v::SortedVector, idx::AbstractVector) =
6363
Base.length(v::SortedVector) = length(v.data)
6464
Base.size(v::SortedVector) = size(v.data)
6565
Base.size(v::SortedVector, i) = size(v.data, i)
66+
Base.indices(v::SortedVector) = indices(v.data)
6667

6768
axistrait(::SortedVector) = Dimensional
6869
checkaxis(::SortedVector) = nothing

test/REQUIRE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
OffsetArrays

test/core.jl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,14 @@ A = AxisArray(reshape(1:24, 2,3,4),
115115
@test hash(Axis{:row}()) != hash(Axis{:col}())
116116
@test hash(Axis{:x}(1:3)) == hash(Axis{:x}(Base.OneTo(3)))
117117
@test AxisArrays.axistype(Axis{1}(1:2)) == typeof(1:2)
118+
@test AxisArrays.axistype(Axis{1,UInt32}) == UInt32
118119
@test axisnames(Axis{1}, Axis{2}, Axis{3}) == (1,2,3)
120+
@test Axis{:row}(2:7)[4] == 5
121+
@test eltype(Axis{:row}(1.0:1.0:3.0)) == Float64
122+
@test size(Axis{:row}(2:7)) === (6,)
123+
@test indices(Axis{:row}(2:7)) === (Base.OneTo(6),)
124+
@test indices(Axis{:row}(-1:1), 1) === Base.OneTo(3)
125+
@test length(Axis{:col}(-1:2)) === 4
119126

120127
# Test Timetype axis construction
121128
dt, vals = DateTime(2010, 1, 2, 3, 40), randn(5,2)
@@ -125,3 +132,16 @@ A = AxisArray(vals, Axis{:Timestamp}(dt-Dates.Hour(2):Dates.Hour(1):dt+Dates.Hou
125132

126133
# Simply run the display method to ensure no stupid errors
127134
@compat show(IOBuffer(),MIME("text/plain"),A)
135+
136+
# With unconventional indices
137+
import OffsetArrays # import rather than using because OffsetArrays has a deprecation for ..
138+
A = AxisArray(OffsetArrays.OffsetArray([5,3,4], -1:1), :x)
139+
@test axes(A) == (Axis{:x}(-1:1),)
140+
@test A[-1] == 5
141+
A[0] = 12
142+
@test A.data[0] == 12
143+
@test indices(A) == (-1:1,)
144+
@test linearindices(A) == -1:1
145+
A = AxisArray(OffsetArrays.OffsetArray(rand(4,5), -1:2, 5:9), :x, :y)
146+
@test indices(A) == (-1:2, 5:9)
147+
@test linearindices(A) == 1:20

0 commit comments

Comments
 (0)