# Commit to a common syntax for accessing additional index mapping information on axes

**URL:** <https://discourse.julialang.org/t/commit-to-a-common-syntax-for-accessing-additional-index-mapping-information-on-axes/84988>\
**Category:** Data\
**Created:** [July 29, 2022, 4:38pm UTC](https://discourse.julialang.org/t/commit-to-a-common-syntax-for-accessing-additional-index-mapping-information-on-axes/84988 "2022-07-29T16:38:47Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Zach\_Christensen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zach_christensen/32/7220_2.png) [@Zach\_Christensen](https://discourse.julialang.org/u/Zach_Christensen)\
**Post date:** [July 29, 2022, 4:38pm UTC](https://discourse.julialang.org/t/commit-to-a-common-syntax-for-accessing-additional-index-mapping-information-on-axes/84988/1 "2022-07-29T16:38:47Z")

</div>

If you use AxisArrays.jl it’s `axisvalues(data, dim)`, if you use AxisKeys.jl it’s called `axiskeys(data, dim)`, if you use DimensionalData.jl it’s `dims(data, dim).val`, if you use NamedArrays.jl it’s `names(data, dim). Whatever you call it, it would be great if we had a consistent way of extracting it for end users because we’ve been talking about it and implanting it in different ways for years now ([WIP: The Plan · Issue #1 · JuliaCollections/AxisArraysFuture · GitHub](https://github.com/JuliaCollections/AxisArraysFuture/issues/1)). For quite a while I’ve wanted to implement this syntax in ArrayInterface.jl and have recently made active efforts to do so ([`index_labels` method and `IndexLabel` type indexing by Tokazama · Pull Request #328 · JuliaArrays/ArrayInterface.jl · GitHub](https://github.com/JuliaArrays/ArrayInterface.jl/pull/328), [`axis_keys` · Issue #250 · JuliaArrays/ArrayInterface.jl · GitHub](https://github.com/JuliaArrays/ArrayInterface.jl/issues/250)). However, we need to agree on a name for this.

The ambiguity in naming may mislead some new comers to this conversation, so I want to be very clear what we want to access with this new syntax. (for the sake of unbiased examples here I’ll just call it `newsyntax`)

- The return of `newsyntax(data)` is a direct mapping to `axes(data)`. Therefore, the following properties should hold:
  - `length(newsyntax(data)) == ndims(data)`
  - `length(newsyntax(data, dim)) == length(axes(data, dim))`
  - `axes(data, dim)[index] == findfirst(==(newsyntax(data, dim)[index]), newsyntax(data, dim))`
  - `allunique(newsyntax(data, dim))`

- This is _NOT_ intended for general information that may be mapped to axes (even if the above properties are valid). Something like the description of each each column in a data set is not the intended use case.

en lieu of fully reviewing previous conversations, here’s a quick overview of what has been discussed previously concerning this:

- Something with “keys” has a very close meaning to what we’re trying to access with this new syntax. However, `keys(::AbstractArray)` already exists, and there’s fairly compelling reasons for the current behavior ([https://github.com/JuliaLang/julia/pull/36073](https://github.com/JuliaLang/julia/pull/36073)). So if we use “keys” in the name it needs to be clearly differentiated from `keys(data)` somehow.
- “names”: already used for something with a completely different meaning in Base and a bit awkward when the return isn’t clearly a naming something (e.g., time-points).
- “labels” is also close in meaning to what we are interested in here. It’s a bit less clear that it is intended to support an extra mapping that has a `key => index` relationship and LaballedArrays.jl already has a bit of a claim on “labels” (so we should get the go ahead from @ChrisRackauckas that this would gel with the SciML ecosystem first).
- We’ve yet to explore a lot of other options (tags, tokens, markers, etc.). But the exact thing we want shouldn’t conflict with more appropriate use of the term ([GitHub - andyferris/Dictionaries.jl: An alternative interface for dictionaries in Julia, for improved productivity and performance](https://github.com/andyferris/Dictionaries.jl#tokens)).

It would be extremely helpful to get some feedback on what works best overall, so please vote below. If you choose to vote for one of the following options but would prefer some variant of what’s provided, please comment.

_Poll ([view on site](https://discourse.julialang.org/t/commit-to-a-common-syntax-for-accessing-additional-index-mapping-information-on-axes/84988/1))_

Thank you!

---

<div class="post-metadata">

**Author:** ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)\
**Post date:** [July 29, 2022, 8:38pm UTC](https://discourse.julialang.org/t/commit-to-a-common-syntax-for-accessing-additional-index-mapping-information-on-axes/84988/2 "2022-07-29T20:38:12Z")

</div>

I’ve used these packages before but they’re not on the top of my head. It would be easier to respond to this given some examples using the function as well as some of the related functions.

---

<div class="post-metadata">

**Author:** ![Zach\_Christensen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zach_christensen/32/7220_2.png) [@Zach\_Christensen](https://discourse.julialang.org/u/Zach_Christensen)\
**Post date:** [July 29, 2022, 9:38pm UTC](https://discourse.julialang.org/t/commit-to-a-common-syntax-for-accessing-additional-index-mapping-information-on-axes/84988/3 "2022-07-29T21:38:40Z")

</div>

The [Images docs](https://juliaimages.org/stable/pkgs/axes/#Usage) have some examples where this would return time points for the time axis and spatial positions for the spatial axes. I believe @Raf uses this feature in DimensionalData.jl primarily for referring to geographical data (which could do something like `newsyntax(data) = (latitude, longitude)`). A number of spatiotemporal features can be derived from this such as spatial spatial intervals (also see [References · JuliaImages](https://juliaimages.org/stable/function_reference/#Traits)). I think AxisKeys.jl is used by some statistical packages to label model parameters along an axis and iterations along another. In the simplest case this would provide some mapping between feature names and data just as DataFrames does.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [July 29, 2022, 10:17pm UTC](https://discourse.julialang.org/t/commit-to-a-common-syntax-for-accessing-additional-index-mapping-information-on-axes/84988/4 "2022-07-29T22:17:25Z")

</div>

I’ll try making a simple example of using keyed arrays and these functions.  
Suppose you have measured counts at different times (time=10, 20, 30) and with different polarizations (L and R). This data is naturally represented as a keyed array:

```julia
julia> A = KeyedArray([1 2 3; 4 5 6], pol=[:L, :R], time=10:10:30)
2-dimensional KeyedArray(NamedDimsArray(...)) with keys:
↓ pol ∈ 2-element Vector{Symbol}
→ time ∈ 3-element StepRange{Int64,...}
And data, 2×3 Matrix{Int64}:
        (10) (20) (30)
  (:L) 1 2 3
  (:R) 4 5 6

```

The function `AxisKeys.axiskeys` accesses the “key” values for each axis:

```julia
julia> axiskeys(A, :pol)
2-element Vector{Symbol}:
 :L
 :R

julia> axiskeys(A, :time)
10:10:30

julia> axiskeys(A)
([:L, :R], 10:10:30)

```

Also, there is a convenient `named_axiskeys` function, not sure if it’s in scope here:

```julia
julia> named_axiskeys(A)
(pol = [:L, :R], time = 10:10:30)

```

These examples use `AxisKeys.jl`, and @Zach_Christensen discusses generalizing the function to alternative implementations of keyed arrays.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [July 29, 2022, 10:20pm UTC](https://discourse.julialang.org/t/commit-to-a-common-syntax-for-accessing-additional-index-mapping-information-on-axes/84988/5 "2022-07-29T22:20:22Z")

</div>

Among the poll variants, I think both `labels` and `names` are too specific. As you say, it would be weird to call fundamentally continuous values – times, distances, or latitudes – “labels” or “names”. Keys/axiskeys/axisvalues sound more abstract and general.

---

<div class="post-metadata">

**Author:** ![Zach\_Christensen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zach_christensen/32/7220_2.png) [@Zach\_Christensen](https://discourse.julialang.org/u/Zach_Christensen)\
**Post date:** [July 29, 2022, 10:22pm UTC](https://discourse.julialang.org/t/commit-to-a-common-syntax-for-accessing-additional-index-mapping-information-on-axes/84988/6 "2022-07-29T22:22:08Z")

</div>

Interestingly, @mcabbott (the author of AxisKeys.jl) doesn’t love `axiskeys` and suggested “labels”.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [July 29, 2022, 10:27pm UTC](https://discourse.julialang.org/t/commit-to-a-common-syntax-for-accessing-additional-index-mapping-information-on-axes/84988/7 "2022-07-29T22:27:36Z")

</div>

Anyway, standardization itself is more important than name differences between several reasonable variants. For example, one could argue that `Base.keys` should really be `indices` instead, and this `axiskeys` should just be `keys`. But it takes little time to get used to either.

---

<div class="post-metadata">

**Author:** ![Zach\_Christensen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zach_christensen/32/7220_2.png) [@Zach\_Christensen](https://discourse.julialang.org/u/Zach_Christensen)\
**Post date:** [July 30, 2022, 12:21pm UTC](https://discourse.julialang.org/t/commit-to-a-common-syntax-for-accessing-additional-index-mapping-information-on-axes/84988/8 "2022-07-30T12:21:43Z")

</div>

I completely agree. There are some names that sound a bit better to me but I’m mostly interested in getting something standardized that we can build on.

---

<div class="post-metadata">

**Author:** ![nalimilan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nalimilan/32/147_2.png) [@nalimilan](https://discourse.julialang.org/u/nalimilan)\
**Post date:** [July 31, 2022, 3:08pm UTC](https://discourse.julialang.org/t/commit-to-a-common-syntax-for-accessing-additional-index-mapping-information-on-axes/84988/9 "2022-07-31T15:08:35Z")

</div>

Thanks for taking the intiative. It would indeed be good to standardize this. BTW, it would also be useful to have a standard API to build such arrays and to convert from one type to another. That would allow e.g. using FreqTables.jl to create a frequency table stored in an `AxisArray` instead of a `NamedArray` (which is the only supported type currently).

Regarding the function name, `axiskeys` isn’t distinct enough from `keys` (as you note). `keys` already returns keys for each axis, so adding “axis” to the name doesn’t add anything IMO. Maybe something like `axisnames`/`axislabels` or `dimnames`/`dimlabels`? `dimnames` is used by R FWIW.

Also note that several packages support giving names to dimensions themselves (i.e. a single name attached to dimension N, as opposed to one name for each slice on that dimension) so it would be good to ensure we can find a name for that too (like `dimnames` in NamedArrays). One solution is simply to have `newsyntax(data)` return a named tuple whose names are dimension names.

---

<div class="post-metadata">

**Author:** ![yha](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yha/32/3502_2.png) [@yha](https://discourse.julialang.org/u/yha)\
**Post date:** [July 31, 2022, 8:34pm UTC](https://discourse.julialang.org/t/commit-to-a-common-syntax-for-accessing-additional-index-mapping-information-on-axes/84988/10 "2022-07-31T20:34:28Z")

</div>

> [@Zach\_Christensen](#):
>
> This is _NOT_ intended for general information that may be mapped to axes (even if the above properties are valid). Something like the description of each each column in a data set is not the intended use case.

Can you explain this distinction? I though I understood what this is about until this paragraph. Is this paragraph trying to make a distinction between indexing the data through the keys/labels/values vs. other uses?

Of the mentioned packages, I’ve only ever used `NamedArrays` to label row and columns (as well as block-rows and block-columns when also using `BlockArrays`, by labeling the row and columns of `blocks(matrix::BlockMatrix)`), those labels being later used when viewing the data (but not as keys for accessing it). If I understand correctly, this seems to be a use case that you dismiss here (“description of each column in data set”). In the example by @aplavin below, `:L` and `:R` can also be seen as description of each row in a data set. Are these uses not what this thread is about?

---

<div class="post-metadata">

**Author:** ![Zach\_Christensen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zach_christensen/32/7220_2.png) [@Zach\_Christensen](https://discourse.julialang.org/u/Zach_Christensen)\
**Post date:** [July 31, 2022, 11:40pm UTC](https://discourse.julialang.org/t/commit-to-a-common-syntax-for-accessing-additional-index-mapping-information-on-axes/84988/11 "2022-07-31T23:40:49Z")

</div>

> [@nalimilan](#):
>
> BTW, it would also be useful to have a standard API to build such arrays and to convert from one type to another. That would allow e.g. using FreqTables.jl to create a frequency table stored in an `AxisArray` instead of a `NamedArray` (which is the only supported type currently).

I agree, but I’m trying to take solve this in small agreeable steps so we don’t continue generating new packages for the same thing here.

> [@nalimilan](#):
>
> Regarding the function name, `axiskeys` isn’t distinct enough from `keys` (as you note). `keys` already returns keys for each axis, so adding “axis” to the name doesn’t add anything IMO. Maybe something like `axisnames`/`axislabels` or `dimnames`/`dimlabels`? `dimnames` is used by R FWIW.

`axislabels` makes sense to me since it implies a relationship with axes.

---

<div class="post-metadata">

**Author:** ![Zach\_Christensen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zach_christensen/32/7220_2.png) [@Zach\_Christensen](https://discourse.julialang.org/u/Zach_Christensen)\
**Post date:** [July 31, 2022, 11:52pm UTC](https://discourse.julialang.org/t/commit-to-a-common-syntax-for-accessing-additional-index-mapping-information-on-axes/84988/12 "2022-07-31T23:52:30Z")

</div>

I’m not saying this “key” can’t be descriptive but each should be unique from all other values in the collection and typically used as a a mapping into the space. So a data dictionary wouldn’t really be the intended use case here because no one is going to look up a value with a long sentence. It also wouldn’t make sense to have non unique values just as you wouldn’t have multiple columns with the same name in a table.

> [@yha](#):
>
> If I understand correctly, this seems to be a use case that you dismiss here (“description of each column in data set”).

I said this application was “not intended” for general information. I chose that wording very carefully because:

1. I don’t want to get too distracted by every possible application loosely related to this. We have been trying to get an AxisArrays type system standardized for years and this is only one small step toward solving this.
2. “not intended” is more permissive than “forbidden” or “disallowed”. If you want to attach a stanza to each element of your `axislabels`/`axiskekeys`/etc that’s fine. Just don’t expect any special effort to be put into optimizing and debugging problems when used for `newsyntax(data)` that returns that.

If you have a related but diverging application you think will benefit the entire community and needs to be discussed more thoroughly, I’d love to discuss it in a new topic or github issue. It might be a good application for the metadata API in development.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [August 1, 2022, 3:39am UTC](https://discourse.julialang.org/t/commit-to-a-common-syntax-for-accessing-additional-index-mapping-information-on-axes/84988/13 "2022-08-01T03:39:29Z")

</div>

DimensionalData.jl actually has a method `lookup(A, 2)` for this, and the objects are called `LookupArray`s. This came from trying to avoid `key` and `index`, and `label` for being too generic.

---

<div class="post-metadata">

**Author:** ![Zach\_Christensen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zach_christensen/32/7220_2.png) [@Zach\_Christensen](https://discourse.julialang.org/u/Zach_Christensen)\
**Post date:** [August 1, 2022, 4:06am UTC](https://discourse.julialang.org/t/commit-to-a-common-syntax-for-accessing-additional-index-mapping-information-on-axes/84988/14 "2022-08-01T04:06:56Z")

</div>

If you think there’s a better name there I’m open to it. Like `axislookups`

---

<div class="post-metadata">

**Author:** ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)\
**Post date:** [August 1, 2022, 6:04am UTC](https://discourse.julialang.org/t/commit-to-a-common-syntax-for-accessing-additional-index-mapping-information-on-axes/84988/15 "2022-08-01T06:04:09Z")

</div>

Pandas [uses](https://pandas.pydata.org/pandas-docs/stable/user_guide/advanced.html) `labels` and `levels`.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [August 1, 2022, 6:33am UTC](https://discourse.julialang.org/t/commit-to-a-common-syntax-for-accessing-additional-index-mapping-information-on-axes/84988/16 "2022-08-01T06:33:58Z")

</div>

@Zach_Christensen in addition to naming, there is also a decision regarding the discussed function behavior. Should it return `NamedTuple`s when the dimensions themselves are named, or the result should always be a `Tuple`?  
I personally like the first variant more: getting “axis keys” together with dimension names is definitely a useful piece of functionality, and having two separate function (`Tuple` and `NamedTuple` ones) seems like an unnecessary increase of API surface.

---

<div class="post-metadata">

**Author:** ![Zach\_Christensen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zach_christensen/32/7220_2.png) [@Zach\_Christensen](https://discourse.julialang.org/u/Zach_Christensen)\
**Post date:** [August 1, 2022, 7:43am UTC](https://discourse.julialang.org/t/commit-to-a-common-syntax-for-accessing-additional-index-mapping-information-on-axes/84988/17 "2022-08-01T07:43:57Z")

</div>

We have a `dimnames` method already and the convention is to have `:_` be an unnamed dimension. Multiple unnamed dims wouldn’t work with a NamedTuple.

Maybe we could figure out a work around for this. I might be able to put together a small package for this if it’s really necessary.

---

<div class="post-metadata">

**Author:** ![Zach\_Christensen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zach_christensen/32/7220_2.png) [@Zach\_Christensen](https://discourse.julialang.org/u/Zach_Christensen)\
**Post date:** [August 1, 2022, 7:50am UTC](https://discourse.julialang.org/t/commit-to-a-common-syntax-for-accessing-additional-index-mapping-information-on-axes/84988/18 "2022-08-01T07:50:58Z")

</div>

We could probably figure out how to support multiple levels at some point but I think that implementation has issues. Not enforcing unique keys makes it ambiguous wether one is accessing an element or collection, not to mention performance issues. But I am interested in that sort of thing once we have these syntax in place.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [August 1, 2022, 2:11pm UTC](https://discourse.julialang.org/t/commit-to-a-common-syntax-for-accessing-additional-index-mapping-information-on-axes/84988/19 "2022-08-01T14:11:41Z")

</div>

Im in favour of returning `NamedTuple` to get both the dim names and lookup values from one method.

But yes unnamed dimensions is a problem for that, unless we adopt a numbering convention.

Extents.jl uses a `NamedTuple`-like wrapper object for a similar purpose, combing dimension names and extent bounds in one object. Returning `NamedTuple` was avoided to make dispatch easier.

---

<div class="post-metadata">

**Author:** ![Zach\_Christensen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zach_christensen/32/7220_2.png) [@Zach\_Christensen](https://discourse.julialang.org/u/Zach_Christensen)\
**Post date:** [August 1, 2022, 2:20pm UTC](https://discourse.julialang.org/t/commit-to-a-common-syntax-for-accessing-additional-index-mapping-information-on-axes/84988/20 "2022-08-01T14:20:58Z")

</div>

We would likely have two methods if we support that. One for a names version and one that returns a plain tuple.

[Next page](https://discourse.julialang.org/t/commit-to-a-common-syntax-for-accessing-additional-index-mapping-information-on-axes/84988.md?page=2)
