1- # AxisRanges .jl
1+ # AxisKeys .jl
22
3- [ ![ Build Status] ( https://travis-ci.org/mcabbott/AxisRanges .jl.svg?branch=master )] ( https://travis-ci.org/mcabbott/AxisRanges .jl )
3+ [ ![ Build Status] ( https://travis-ci.org/mcabbott/AxisKeys .jl.svg?branch=master )] ( https://travis-ci.org/mcabbott/AxisKeys .jl )
44
5- This package defines a thin wrapper which, alongside any array, stores an extra "range "
5+ This package defines a thin wrapper which, alongside any array, stores a vector of "keys "
66for each dimension. This may be useful to store perhaps actual times of measurements,
77or some strings labeling columns, etc. These will be propagated through many
88operations on arrays, including broadcasting, ` map ` , comprehensions, ` sum ` etc.
@@ -15,7 +15,7 @@ The function `wrapdims` constructs a nested pair of these wrappers,
1515for example:
1616
1717``` julia
18- using AxisRanges
18+ using AxisKeys
1919data = rand (Int8, 2 ,10 ,3 ) .| > abs;
2020A = wrapdims (data; channel= [:left , :right ], time= range (13 , step= 2.5 , length= 10 ), iter= 31 : 33 )
2121```
@@ -28,11 +28,10 @@ A = wrapdims(data; channel=[:left, :right], time=range(13, step=2.5, length=10),
2828
2929Indexing still works directly on the underlying array,
3030and keyword indexing works exactly as for a ` NamedDimsArray ` .
31- But in addition, it is possible to pick out elements based on the new ranges,
32- which for clarity we will call "lookup" based on a "key".
33- This is written with round brackets:
31+ But in addition, it is possible to pick out elements based on the keys,
32+ which for clarity we will call lookup. This is written with round brackets:
3433
35- | Dimension ` d ` | Indexing: ` i β axes(A,d) ` | Lookup: ` key β ranges (A,d) ` |
34+ | Dimension ` d ` | Indexing: ` i β axes(A,d) ` | Lookup: ` key β axiskeys (A,d) ` |
3635| --------------------| ---------------------| ---------------------|
3736| by position | ` A[1,2,:] ` | ` A(:left, 15.5, :) ` |
3837| by name | ` A[iter=1] ` | ` A(iter=31) ` |
@@ -73,33 +72,34 @@ and `setkey!` via `B[Key(13.0), Key('Ξ±')] = 0`. But they don't right now.)
7372### Construction
7473
7574``` julia
76- RangeArray (rand (Int8, 2 ,10 ), ([:a , :b ], 10 : 10 : 100 ))
75+ KeyedArray (rand (Int8, 2 ,10 ), ([:a , :b ], 10 : 10 : 100 ))
7776```
7877
7978A nested pair with names can be constructed with keywords,
8079and (apart from a few bugs) this should work the same in either order:
8180
8281``` julia
83- RangeArray (rand (Int8, 2 ,10 ), row= [:a , :b ], col= 10 : 10 : 100 ) # RangeArray (NamedDimsArray(...))
84- NamedDimsArray (rand (Int8, 2 ,10 ), row= [:a , :b ], col= 10 : 10 : 100 ) # NamedDimsArray(RangeArray (...))
82+ KeyedArray (rand (Int8, 2 ,10 ), row= [:a , :b ], col= 10 : 10 : 100 ) # KeyedArray (NamedDimsArray(...))
83+ NamedDimsArray (rand (Int8, 2 ,10 ), row= [:a , :b ], col= 10 : 10 : 100 ) # NamedDimsArray(KeyedArray (...))
8584```
8685
8786The function ` wrapdims ` does a bit more checking and fixing.
88- It will adjust the length of ranges if it can, and their indexing if needed to match the array:
87+ It will adjust the length of key vectors if it can, and their indexing if needed to match the array:
8988
9089``` julia
9190wrapdims (rand (Int8, 10 ), alpha= ' a' :' z' )
9291# Warning: range 'a':1:'z' replaced by 'a':1:'j', to match size(A, 1) == 10
9392
9493wrapdims (OffsetArray (rand (Int8, 10 ),- 1 ), iter= 10 : 10 : 100 )
95- ranges (ans,1 ) # 10:10:100 with indices 0:9
94+ axiskeys (ans,1 ) # 10:10:100 with indices 0:9
9695```
9796
9897### Functions
9998
100- As usual ` axes(A) ` returns (a tuple of vectors of) indices, and ` ranges(A) ` returns keys.
101- If the array has names, then ` dimnames(A) ` returns them, and functions like ` axes(A, name) `
102- give just one.
99+ As usual ` axes(A) ` returns (a tuple of vectors of) indices,
100+ and ` axiskeys(A) ` returns (a tuple of vectors of) keys.
101+ If the array has names, then ` dimnames(A) ` returns them,
102+ and functions like ` axes(A, name) ` give just one.
103103
104104Many functions should work, for example:
105105
@@ -116,49 +116,49 @@ Many functions should work, for example:
116116
117117* Some linear algebra functions like ` * ` and ` \ ` will work.
118118
119- * Getproperty returns the range , to allow things like
119+ * Getproperty returns the key vector , to allow things like
120120 ` for (i,t) in enumerate(A.time); fun(A[i], t); ... ` .
121121
122- * Vectors support ` push!(V, val) ` , which will try to extend the range .
123- There is also a method ` push!(V, key => val) ` which pushes the key into the range .
122+ * Vectors support ` push!(V, val) ` , which will try to extend the key vector .
123+ There is also a method ` push!(V, key => val) ` which pushes in a new key .
124124
125- To allow for this limited mutability, ` V.ranges isa Ref ` for vectors,
126- while ` A.ranges isa Tuple ` for matrices & higher. But ` ranges (A)` always returns a tuple.
125+ To allow for this limited mutability, ` V.keys isa Ref ` for vectors,
126+ while ` A.keys isa Tuple ` for matrices & higher. But ` axiskeys (A)` always returns a tuple.
127127
128128* [ LazyStack] ( https://github.com/mcabbott/LazyStack.jl ) ` .stack ` is now hooked up.
129129 Stacks of named tuples like ` stack((a=i, b=i^2) for i=1:3) ` create axis keys.
130130
131131### Absent
132132
133133* There is no automatic alignment of dimensions by name.
134- Thus ` A .+ A[iter=3] ` is fine as both names and ranges line up,
134+ Thus ` A .+ A[iter=3] ` is fine as both names and keys line up,
135135 but ` A .+ B ` is an error, as ` B ` 's first name is ` :time ` not ` :channel ` .
136136 (See [ NamedPlus] ( https://github.com/mcabbott/NamedPlus.jl ) ` .@named ` for something like this.)
137137
138138As for [ NamedDims.jl] ( https://github.com/invenia/NamedDims.jl ) , the guiding idea
139139is that every operation which could be done on ordinary arrays
140- should still produce the same data, but propagate the extra information (names/ranges ),
140+ should still produce the same data, but propagate the extra information (names/keys ),
141141and error if it conflicts.
142142
143143Both packages allow for wildcards, which never conflict.
144- In NamedDims.jl this is the name ` :_ ` , here it is a range ` Base.OneTo(n) ` ,
144+ In NamedDims.jl this is the name ` :_ ` , here it is a ` Base.OneTo(n) ` ,
145145like the ` axes ` of an ` Array ` . These can be constructed as
146146` M = wrapdims(rand(2,2); _=[:a, :b], cols=nothing) ` ,
147147and for instance ` M .+ M' ` is not an error.
148148
149- * There are no special types provided for ranges , they can be any ` AbstractVector ` s.
150- Lookup happens by calling ` i = findfirst(isequal(20.0), ranges (A,2)) ` ,
151- or ` is = findall(<(18), ranges (A,2)) ` .
149+ * There are no special types provided for key vectors , they can be any ` AbstractVector ` s.
150+ Lookup happens by calling ` i = findfirst(isequal(20.0), axiskeys (A,2)) ` ,
151+ or ` is = findall(<(18), axiskeys (A,2)) ` .
152152
153153If you need lookup to be very fast, then you will want to use a package like
154154[ UniqueVectors.jl] ( https://github.com/garrison/UniqueVectors.jl )
155155or [ AcceleratedArrays.jl] ( https://github.com/andyferris/AcceleratedArrays.jl )
156156or [ CategoricalArrays.jl] ( https://github.com/JuliaData/CategoricalArrays.jl ) .
157- To apply such a type to all ranges , you may write
157+ To apply such a type to all dimensions , you may write
158158` D = wrapdims(rand(1000), UniqueVector, rand(Int, 1000)) ` .
159159Then ` D(n) ` here will use the fast lookup from UniqueVectors.jl (about 60x faster).
160160
161- When a dimensionβs range is a Julia ` AbstractRange ` , then this package provides some faster
161+ When a key vector is a Julia ` AbstractRange ` , then this package provides some faster
162162overloads for things like ` findall(<=(42), 10:10:100) ` .
163163
164164* There is also no automatic alignment by keys, like time.
@@ -171,7 +171,7 @@ This is more or less an attempt to replace [AxisArrays](https://github.com/Julia
171171with several smaller packages. The complaints are:
172172(1) It's confusing to guess whether to perform indexing or lookup
173173 based on whether it is given an integer (index) or not (key).
174- (2) Each "range " was its own type ` Axis{:name} ` which allowed zero-overhead lookup
174+ (2) Each "axis " was its own type ` Axis{:name} ` which allowed zero-overhead lookup
175175 before Julia 1.0. But this is now possible with a simpler design.
176176 (They were called axes before ` Base.axes() ` was added, hence (3) the confusing terminology.)
177177(4) Broadcasting is not supported, as this changed dramatically in Julia 1.0.
@@ -180,10 +180,10 @@ with several smaller packages. The complaints are:
180180
181181Other older packages (pre-Julia-1.0):
182182
183- * [ NamedArrays] ( https://github.com/davidavdav/NamedArrays.jl ) also provides names & ranges ,
184- ranges are always OrderedDict. Named lookup looks like ` NA[:x => 13.0] `
183+ * [ NamedArrays] ( https://github.com/davidavdav/NamedArrays.jl ) also provides names & keys ,
184+ which are always ` OrderedDict ` s . Named lookup looks like ` NA[:x => 13.0] `
185185instead of ` A(x=13.0) ` here; this is not very fast.
186- Dimension names & ranges can be set after creation. Has nice pretty-printing routines.
186+ Dimension names & keys can be set after creation. Has nice pretty-printing routines.
187187
188188* [ LabelledArrays] ( https://github.com/JuliaDiffEq/LabelledArrays.jl ) adds names for individual elements, more like a NamedTuple.
189189Only for small sizes: the storage inside is a Tuple, not an Array.
@@ -193,24 +193,24 @@ Only for small sizes: the storage inside is a Tuple, not an Array.
193193* [ OffsetArrays] ( https://github.com/JuliaArrays/OffsetArrays.jl ) actually changes the indices
194194of an Array, allowing any continuous integer range, like ` 0:9 ` or ` -10:10 ` .
195195This package is happy to wrap such arrays,
196- and if needed will adjust indices of the given ranges :
196+ and if needed will adjust indices of the given key vectors :
197197` O = wrapdims(OffsetArray(["left", "mid", "right"], -1:1), 'A':'C') ` ,
198198then ` O[-1:0] ` works.
199199
200200Other new packages (post-1.0):
201201
202202* [ DimensionalData] ( https://github.com/rafaqz/DimensionalData.jl ) is another replacement
203- for AxisArrays. It again uses types like ` Dim{:name} ` to store both name & range ,
203+ for AxisArrays. It again uses types like ` Dim{:name} ` to store both name & keys ,
204204plus some special ones like ` X, Y ` of the same abstract type.
205205Named lookup then looks like ` DA[X <| At(13.0)] ` , roughly like ` A(x=13.0) ` here.
206206
207207* [ NamedPlus] ( https://github.com/mcabbott/NamedPlus.jl ) is some experiments using NamedDims.
208208Function ` align ` permutes dimensions automatically,
209209and macro ` @named ` can introduce this into broadcasting expressions.
210210
211- * [ IndexedDims] ( https://github.com/invenia/IndexedDims.jl ) like this package adds ranges
211+ * [ IndexedDims] ( https://github.com/invenia/IndexedDims.jl ) like this package adds keys
212212on top of the names from NamedDims.
213- These ranges must always be [ AcceleratedArrays] ( https://github.com/andyferris/AcceleratedArrays.jl ) .
213+ These key vectors must always be [ AcceleratedArrays] ( https://github.com/andyferris/AcceleratedArrays.jl ) .
214214Like AxisArrays, it tries to guess whether to do indexing or lookup based on type.
215215
216216* [ Dictionaries] ( https://github.com/andyferris/Dictionaries.jl ) does very fast lookup only
@@ -235,53 +235,3 @@ In π-land:
235235 Writes indexing "by position" as ` df.iat[1, 1] ` for scalars or ` df.iloc[1:3, :] ` allowing slices,
236236 and lookup "by label" as ` df.at[dates[0], 'A'] ` for scalars or ` df.loc['20130102':'20130104', ['A', 'B']] ` for slices, "both endpoints are * included* " in this.
237237
238- <!--
239- ### Words
240-
241- This package isn't registered yet, partly because what to call things is unclear.
242-
243- 1. Julia has adopted `index::Int β axes(A,1)`. So I think these other structures need other names.
244-
245- 2. From NamedDims.jl, each `name::Symbol` belongs to a dimension, `d β 1:ndims(A)`.
246-
247- 3. LabelledArrays.jl attaches a `label::Symbol` to every element of the array,
248- so that perhaps `A.label == A[2,2]`.
249-
250- 4. For now I use `key` for the thing you lookup, but it could also be `label`?
251- I think a `value` is what `A[1,2]` returns.
252-
253- 5. For now I use `ranges(A,1)` for the vector of possible keys.
254- But these do not have to be like `Base.range`'s `AbstractRange`s.
255- Perhaps `scales(A,1)`? A scale of keys? `domains(A,1)`?
256-
257- 6. The package could be `AxisScales` (hard to say) or `LabelledDims` (how many `l`s again?)
258- or `AxiKeys` (short!) or `ScaledDims` or what?
259-
260- 7. The constructor function is `wrapdims` because it doesn't only make `RangeArray`s,
261- but perhaps should match the package name better.
262-
263-
264- ### About
265-
266- Michael Abbott, 2019.
267- -->
268-
269- <!--
270- Terminology
271-
272-
273- Julia | axes | index | <i></i> | <i></i> | <i></i> | <i></i>
274- --------------|------|-------|-----------|-------|-------|------
275- this package | axes | index | names | range | key | meta
276- NamedDims | axes | index | dimnames | - | - | -
277- AxisArrays | | | axisnames | axis | value | -
278- LabelledArrays| axes | ? | ? | ? | name | -
279- --------------|------|-------|-----------|-------|-------|------
280- Python | _ | _ | _ | _ | _ |
281- --------------|------|---------------|---------|-------|-------------------|------
282- xarrays | ? | integer label | dims | coords | coordinate label | attrs
283- pytorch | ? | ? | names | - | - | -
284-
285-
286-
287- -->
0 commit comments