Extending DimensionalData
Nearly everything in DimensionalData.jl is designed to be extensible.
AbstractDimArrayare easily extended to custom array types.RasterorYAXArrayare examples from other packages.AbstractDimStackare easily extended to custom mixed array dataset.RasterStackorArViZ.Datasetare examples.Lookupcan have new types added, e.g. toAbstractSampledorAbstractCategorical.Rasters.Projectedis a lookup that knows its coordinate reference system, but otherwise behaves as a regularSampledlookup.
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 Dimensions from dims(obj).
Dimension axes
Dimensions return from dims should hold a Lookup or in some cases just an AbstractArray (like wiht DimIndices). When attached to mullti-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 interterface 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])
true