Extending DimensionalData
Nearly everything in DimensionalData.jl is designed to be extensible.
AbstractDimArray
is easily extended to custom array types.Raster
orYAXArray
are examples from other packages.AbstractDimStack
is easily extended to custom mixed array datasets.RasterStack
orArViZ.Dataset
are examples.Lookup
can have new types added, e.g. toAbstractSampled
orAbstractCategorical
.Rasters.Projected
is a lookup that knows its coordinate reference system, but otherwise behaves as a regularSampled
lookup.
dims
, rebuild
and format
are the key interface methods in most of these cases.
dims
Objects extending DimensionalData.jl that have dimensions must return a Tuple
of constructed Dimension
s from dims(obj)
.
Dimension
axes
Dimensions returned from dims
should hold a Lookup
or in some cases just an AbstractArray
(like with DimIndices
). When attached to multi-dimensional objects, lookups must be the same length as the axis of the array it represents, and eachindex(A, i)
and eachindex(dim)
must return the same values.
This means that if the array has OffsetArrays.jl axes, the array the dimension wraps must also have OffsetArrays.jl axes.
dims
keywords
To any dims
keyword argument that usually requires the dimension I, objects should accept any Dimension
, Type{<:Dimension}
, Symbol
, Val{:Symbol}
, Val{<:Type{<:Dimension}}
or also regular Integer
.
This is easier than it sounds, calling DD.dims(objs, dims)
will return the matching dimension and DD.dimnum(obj, dims)
will return the matching Int
for any of these inputs as long as dims(obj)
is implemented.
rebuild
Rebuild methods are used to rebuild immutable objects with new field values, in a way that is more flexible and extensible than just using ConstructionBase.jl reconstruction. Developers can choose to ignore some of the fields passed by rebuild
.
The function signature is always one of:
rebuild(obj, args...)
rebuild(obj; kw...)
rebuild
has keyword versions automatically generated for all objects using ConstructionBase.jl.
These will work without further work as long as your object has the fields used by DimensionalData.jl objects. For example, AbstractDimArray
will receive these keywords in rebuild
: data
, dims
, refdims
, name
, metadata
.
If your AbstractDimArray
does not have all these fields, you must implement rebuild(x::YourDimArray; kw...)
manually.
An argument method is also defined with the same arguments as the keyword version. For AbstractDimArray
it should only be used for updating data
and dims
, any more that that is confusing.
For Dimension
and Selector
the single argument versions are easiest to use, as there is only one argument.
format
When constructing an AbstractDimArray
or AbstractDimStack
DimensionalData.format
must be called on the dims
tuple and the parent array:
format(dims, array)
This lets DimensionalData detect the lookup properties, fill in missing fields of a Lookup
, pass keywords from Dimension
to detected Lookup
constructors, and accept a wider range of dimension inputs like tuples of Symbol
and Type
.
Not calling format
in the outer constructors of an AbstractDimArray
has undefined behaviour.
Interfaces.jl interface testing
DimensionalData defines explicit, testable Interfaces.jl interfaces: DimArrayInterface
and DimStackInterface
.
This is the implementation definition for DimArray
:
julia> using DimensionalData, Interfaces
julia> @implements DimensionalData.DimArrayInterface{(:refdims,:name,:metadata)} DimArray [rand(X(10), Y(10)), zeros(Z(10))]
See the DimensionalData.DimArrayInterface
docs for options. We can test it with:
julia> Interfaces.test(DimensionalData.DimArrayInterface)
Testing DimArrayInterface is implemented for DimArray
Mandatory components
dims: (defines a `dims` method [true, true],
dims are updated on getindex [true, true])
refdims_base: `refdims` returns a tuple of Dimension or empty [true, true]
ndims: number of dims matches dimensions of array [true, true]
size: length of dims matches dimensions of array [true, true]
rebuild_parent: rebuild parent from args [true, true]
rebuild_dims: rebuild paaarnet and dims from args [true, true]
rebuild_parent_kw: rebuild parent from args [true, true]
rebuild_dims_kw: rebuild dims from args [true, true]
rebuild: all rebuild arguments and keywords are accepted [true, true]
Optional components
refdims: (refdims are updated in args rebuild [true, true],
refdims are updated in kw rebuild [true, true],
dropped dimensions are added to refdims [true, true])
name: (rebuild updates name in arg rebuild [true, true],
rebuild updates name in kw rebuild [true, true])
metadata: (rebuild updates metadata in arg rebuild [true, true],
rebuild updates metadata in kw rebuild [true, true])
Implementation summary:
DimArray correctly implements DimensionalData.DimArrayInterface: true
true