Modifying Objects
DimensionalData.jl objects are all struct rather than mutable struct. The only things you can modify in-place are the values of the contained arrays or metadata Dicts if they exist.
Everything else must be rebuilt and assigned to a variable.
modify
Modify the inner arrays of a AbstractDimArray or AbstractDimStack, with modify. This can be useful to e.g. replace all arrays with CuArray moving the data to the GPU, collect all inner arrays to Array without losing the outer DimArray wrappers, and similar things.
julia> using DimensionalData
julia> A = falses(X(3), Y(5))┌ 3×5 DimArray{Bool, 2} ┐
├───────────────── dims ┤
↓ X, → Y
└───────────────────────┘
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0julia> parent(A)3×5 BitMatrix:
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0julia> A_mod = modify(Array, A)┌ 3×5 DimArray{Bool, 2} ┐
├───────────────── dims ┤
↓ X, → Y
└───────────────────────┘
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0julia> parent(A_mod)3×5 Matrix{Bool}:
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0reorder
reorder is like reverse but declarative, rather than imperative: we tell it how we want the object to be, not what to do.
Reorder a specific dimension
julia> using DimensionalData.Lookups;
julia> A = rand(X(1.0:3.0), Y('a':'n'));
julia> reorder(A, X => ReverseOrdered())┌ 3×14 DimArray{Float64, 2} ┐
├───────────────────────────┴───────────────────────────────── dims ┐
↓ X Sampled{Float64} 3.0:-1.0:1.0 ReverseOrdered Regular Points,
→ Y Categorical{Char} 'a':1:'n' ForwardOrdered
└───────────────────────────────────────────────────────────────────┘
↓ → 'a' 'b' 'c' … 'l' 'm' 'n'
3.0 0.664038 0.602315 0.589564 0.85775 0.0684288 0.925042
2.0 0.654537 0.639212 0.153219 0.711697 0.761295 0.202744
1.0 0.380662 0.00832284 0.375166 0.969435 0.484251 0.475818mergedims
mergedims is like reshape, but simultaneously merges multiple dimensions into a single combined dimension with a lookup holding Tuples of the values of both dimensions.
rebuild
rebuild is one of the core functions of DimensionalData.jl. Basically everything uses it somewhere. And you can too, with a few caveats.
Warning
rebuild assumes you know what you are doing. You can quite easily set values to things that don't make sense. The constructor may check a few things, like the number of dimensions matches the axes of the array. But not much else.
julia> A1 = rebuild(A; name=:my_array)┌ 3×14 DimArray{Float64, 2} my_array ┐
├────────────────────────────────────┴─────────────────────── dims ┐
↓ X Sampled{Float64} 1.0:1.0:3.0 ForwardOrdered Regular Points,
→ Y Categorical{Char} 'a':1:'n' ForwardOrdered
└──────────────────────────────────────────────────────────────────┘
↓ → 'a' 'b' 'c' … 'l' 'm' 'n'
1.0 0.380662 0.00832284 0.375166 0.969435 0.484251 0.475818
2.0 0.654537 0.639212 0.153219 0.711697 0.761295 0.202744
3.0 0.664038 0.602315 0.589564 0.85775 0.0684288 0.925042julia> name(A1):my_arrayThe most common use internally is the arg version on Dimension. This is very useful in dimension-based algorithms as a way to transform a dimension wrapper from one object to another:
julia> d = X(1)X 1julia> rebuild(d, 1:10)X 1:10rebuild applications are listed here. AbstractDimArray and AbstractDimStack always accept these keywords or arguments, but those in [ ] brackets may be thrown away if not needed. Keywords in ( ) will error if used where they are not accepted.
| Type | Keywords | Arguments |
|---|---|---|
AbstractDimArray | data, dims, [refdims, name, metadata] | as with kw, in order |
AbstractDimStack | data, dims, [refdims], layerdims, [metadata, layermetadata] | as with kw, in order |
Dimension | val | val |
Selector | val, (atol) | val |
Lookup | data, (order, span, sampling, metadata) | keywords only |
rebuild magic
rebuild with keywords will even work on objects DD doesn't know about!
julia> nt = (a = 1, b = 2)(a = 1, b = 2)julia> rebuild(nt, a = 99)(a = 99, b = 2)Really, the keyword version is just ConstructionBase.setproperties underneath, but wrapped so objects can customise the DD interface without changing the more generic ConstructionBase.jl behaviours and breaking e.g. Accessors.jl in the process.
set
set gives us a way to set the values of the immutable objects in DD, like Dimension and LookupArray. Unlike rebuild it tries its best to do the right thing. You don't have to specify what field you want to set. Just pass in the object you want to be part of the lookup. Usually, there is no possible ambiguity.
set is still improving. Sometimes it may not do the right thing. If you think this is the case, create a GitHub issue.
julia> set(A, Y => Z)┌ 3×14 DimArray{Float64, 2} ┐
├───────────────────────────┴──────────────────────────────── dims ┐
↓ X Sampled{Float64} 1.0:1.0:3.0 ForwardOrdered Regular Points,
→ Z Categorical{Char} 'a':1:'n' ForwardOrdered
└──────────────────────────────────────────────────────────────────┘
↓ → 'a' 'b' 'c' … 'l' 'm' 'n'
1.0 0.380662 0.00832284 0.375166 0.969435 0.484251 0.475818
2.0 0.654537 0.639212 0.153219 0.711697 0.761295 0.202744
3.0 0.664038 0.602315 0.589564 0.85775 0.0684288 0.925042