DimensionalData.jl
DimensionalData.jl copied to clipboard
Support `replace!` for `DimStack`s
This should be easy to do. Currently you can
julia> A = rand(0.:1., (x,y))
╭─────────────────────────╮
│ 3×4 DimArray{Float64,2} │
├─────────────────────────┴──────────────────────── dims ┐
↓ X Sampled{Int64} 1:3 ForwardOrdered Regular Points,
→ Y Sampled{Int64} 10:13 ForwardOrdered Regular Points
└────────────────────────────────────────────────────────┘
↓ → 10 11 12 13
1 0.0 0.0 1.0 1.0
2 0.0 1.0 0.0 1.0
3 0.0 0.0 0.0 1.0
julia> replace!(A, 0 => NaN)
╭─────────────────────────╮
│ 3×4 DimArray{Float64,2} │
├─────────────────────────┴──────────────────────── dims ┐
↓ X Sampled{Int64} 1:3 ForwardOrdered Regular Points,
→ Y Sampled{Int64} 10:13 ForwardOrdered Regular Points
└────────────────────────────────────────────────────────┘
↓ → 10 11 12 13
1 NaN NaN 1.0 1.0
2 NaN 1.0 NaN 1.0
3 NaN NaN NaN 1.0
However, this doesn't work over DimStacks unless you know what you're doing
julia> stack = DimStack(rand(0.:1., (x,y)), rand(0.:1., (x,y)) )
╭──────────────╮
│ 3×4 DimStack │
├──────────────┴─────────────────────────────────── dims ┐
↓ X Sampled{Int64} 1:3 ForwardOrdered Regular Points,
→ Y Sampled{Int64} 10:13 ForwardOrdered Regular Points
├──────────────────────────────────────────────── layers ┤
:layer1 eltype: Float64 dims: X, Y size: 3×4
:layer2 eltype: Float64 dims: X, Y size: 3×4
└────────────────────────────────────────────────────────┘
julia> replace!(stack, 0 => NaN)
ERROR: MethodError: no method matching _replace!(::Base.var"#new#395"{…}, ::DimStack{…}, ::DimStack{…}, ::Int64)
# broadcasting gives incorrect hint
julia> replace!.(stack, 0 => NaN)
ERROR: Use iterate(layers(s)) rather than `iterate(s)`
julia> replace!.(iterate(layers(stack)), 0 => NaN)
ERROR: MethodError: no method matching _replace!(::Base.var"#new#395"{Tuple{Pair{Int64, Float64}}}, ::Int64, ::Int64, ::Int64)
# this works
julia> replace!.(values(layers(stack)), 0 => NaN)
maybe I'm just again stumbling over julian-vs-non-julian ways of doing this with respect to broadcasting, and what's more sensible is to extend the error hint to be:
ERROR: Use iterate(layers(s)) rather than `iterate(s)`. If broadcasting over layers, values(layers(s)), may also be useful.
ref array-of-arrays.
julia> arrs = [rand(0.:1., (2,3)), rand(0.:1., (2,3)) ]
2-element Vector{Matrix{Float64}}:
[0.0 0.0 1.0; 1.0 0.0 0.0]
[1.0 0.0 0.0; 0.0 1.0 0.0]
julia> replace!(arrs, 0 => NaN)
2-element Vector{Matrix{Float64}}:
[0.0 0.0 1.0; 1.0 0.0 0.0]
[1.0 0.0 0.0; 0.0 1.0 0.0]
julia> replace!.(arrs, 0 => NaN)
2-element Vector{Matrix{Float64}}:
[NaN NaN 1.0; 1.0 NaN NaN]
[1.0 NaN NaN; NaN 1.0 NaN]
DimStack is a totally custom creation (it's like a NamedTuple/Array Franken thing) so we can do what we want. It makes sense to add a replace! method.
You may also want to pass a NamedTuple of values for each layer? That should also be allowed.
But probably best just to do :
foreach(layers(stack)) do A
replace!(A, 0 => NaN)
end
Wich generalises to :
foreach(layers(stack), replacementvals) do A, val
replace!(A, zero(val) => val)
end
Rethinking this it doesn't really make sense as DimStack can have mixed type layers. Doing it manually on layers is better.