rafaqz / DimensionalData.jl

Named dimensions and indexing for julia arrays and other data
https://rafaqz.github.io/DimensionalData.jl/stable/
MIT License
262 stars 38 forks source link

Makie extension throws StackOverflowError when dimensions have Unitful units #723

Open david-macmahon opened 3 weeks ago

david-macmahon commented 3 weeks ago

Using plot to plot a DimArray whose axes have Unitful units leads to a StackOverflowError. If the axes do not have units then all is fine (except for no units).

Version Info:

(demo) pkg> st CairoMakie DimensionalData Unitful
Status `~/demo/Project.toml`
  [13f3f980] CairoMakie v0.12.2
  [0703355e] DimensionalData v0.27.3
  [1986cc42] Unitful v1.20.0

Minimum (non-)Working Example

Here is a simple test case showing this problem:

julia> using DimensionalData, CairoMakie, Unitful

julia> dd = DimArray(rand(3,5), (Dim{:freq}(1.0:0.5:2.0), Dim{:time}(0:4)))
╭─────────────────────────╮
│ 3×5 DimArray{Float64,2} │
├─────────────────────────┴──────────────────────────────────── dims ┐
  ↓ freq Sampled{Float64} 1.0:0.5:2.0 ForwardOrdered Regular Points,
  → time Sampled{Int64} 0:4 ForwardOrdered Regular Points
└────────────────────────────────────────────────────────────────────┘
 ↓ →  0         1         2         3         4
 1.0  0.526717  0.362188  0.578533  0.575689  0.965008
 1.5  0.822882  0.281632  0.258725  0.1635    0.828233
 2.0  0.109821  0.454065  0.279114  0.42193   0.0889199

Julia> plot(dd) # works!

julia> ddu = DimArray(rand(3,5), (Dim{:freq}((1.0:0.5:2.0)u"Hz"), Dim{:time}((0:4)u"s")))
╭─────────────────────────╮
│ 3×5 DimArray{Float64,2} │
├─────────────────────────┴────────────────────────────────────────────────────────────────────────────────────────────────── dims ┐
  ↓ freq Sampled{Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{(Hz,), 𝐓^-1, nothing}}} (1.0:0.5:2.0) Hz ForwardOrdered Regular Points,
  → time Sampled{Quantity{Int64, 𝐓, Unitful.FreeUnits{(s,), 𝐓, nothing}}} (0:4) s ForwardOrdered Regular Points
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
      ↓ →  0 s         1 s         2 s         3 s         4 s
 1.0 Hz      0.310773    0.192892    0.9813      0.54426     0.406931
 1.5 Hz      0.194972    0.956161    0.455914    0.133517    0.280051
 2.0 Hz      0.246418    0.425358    0.550912    0.326435    0.591601

julia> plot(ddu)
ERROR: StackOverflowError:
Stacktrace:
  [1] splitprec(::Type{Float64}, i::Int128)
    @ Base ./twiceprecision.jl:22
  [2] TwicePrecision
    @ Base ./twiceprecision.jl:211 [inlined]
  [3] TwicePrecision
    @ Base ./twiceprecision.jl:224 [inlined]
  [4] Base.TwicePrecision{Float64}(nd::Tuple{Int128, Int128}, nb::Int64)
    @ Base ./twiceprecision.jl:236
  [5] steprangelen_hp(::Type{…}, ref::Tuple{…}, step::Tuple{…}, nb::Int64, len::Int64, offset::Int64)
    @ Base ./twiceprecision.jl:344
  [6] _linspace(::Type{Float64}, start_n::Int64, stop_n::Int64, len::Int64, den::Int64)
    @ Base ./twiceprecision.jl:732
  [7] range_start_stop_length(start::Float64, stop::Float64, len::Int64)
    @ Base ./twiceprecision.jl:662
  [8] _range
    @ ./range.jl:166 [inlined]
  [9] _range(start::Quantity{…}, ::Nothing, stop::Quantity{…}, len::Int64)
    @ Unitful ~/.julia/packages/Unitful/6r8Hq/src/range.jl:26
 [10] range
    @ ./range.jl:147 [inlined]
 [11] to_linspace(interval::StepRangeLen{Quantity{…}, Base.TwicePrecision{…}, Base.TwicePrecision{…}, Int64}, N::Int64)
    @ Makie ~/.julia/packages/Makie/We6MY/src/conversions.jl:650
 [12] convert_arguments(P::CellGrid, x::StepRangeLen{…}, y::StepRangeLen{…}, z::Matrix{…}) (repeats 28817 times)
    @ Makie ~/.julia/packages/Makie/We6MY/src/conversions.jl:351
 [13] convert_arguments(P::CellGrid, x::IntervalSets.ClosedInterval{…}, y::IntervalSets.ClosedInterval{…}, z::Matrix{…})
    @ Makie ~/.julia/packages/Makie/We6MY/src/conversions.jl:351
 [14] convert_arguments(::Type{Heatmap}, ::IntervalSets.ClosedInterval{Quantity{…}}, ::Vararg{Any}; kw::@Kwargs{})
    @ Makie ~/.julia/packages/Makie/We6MY/src/conversions.jl:26
 [15] convert_arguments(::Type{…}, ::IntervalSets.ClosedInterval{…}, ::IntervalSets.ClosedInterval{…}, ::Matrix{…})
    @ Makie ~/.julia/packages/Makie/We6MY/src/conversions.jl:14
 [16] conversion_pipeline(P::Type{…}, used_attrs::Tuple{}, args::Tuple{…}, args_obs::Tuple{…}, user_attributes::Dict{…}, deregister::Vector{…}, recursion::Int64)
    @ Makie ~/.julia/packages/Makie/We6MY/src/interfaces.jl:222
 [17] conversion_pipeline(P::Type{…}, used_attrs::Tuple{}, args::Tuple{…}, args_obs::Tuple{…}, user_attributes::Dict{…}, deregister::Vector{…})
    @ Makie ~/.julia/packages/Makie/We6MY/src/interfaces.jl:213
 [18] (Heatmap)(user_args::Tuple{…}, user_attributes::Dict{…})
    @ Makie ~/.julia/packages/Makie/We6MY/src/interfaces.jl:271
 [19] _create_plot(::Function, ::Dict{Symbol, Any}, ::IntervalSets.ClosedInterval{Quantity{…}}, ::Vararg{Any})
    @ Makie ~/.julia/packages/Makie/We6MY/src/figureplotting.jl:316
 [20] heatmap(::IntervalSets.ClosedInterval{Quantity{…}}, ::Vararg{Any}; kw::@Kwargs{axis::Attributes})
    @ MakieCore ~/.julia/packages/MakieCore/8S3xT/src/recipes.jl:436
 [21] #plot#20
    @ DimensionalDataMakie ~/.julia/packages/DimensionalData/BoJag/ext/DimensionalDataMakie.jl:146 [inlined]
 [22] plot(A::DimMatrix{…})
    @ DimensionalDataMakie ~/.julia/packages/DimensionalData/BoJag/ext/DimensionalDataMakie.jl:134
 [23] top-level scope
    @ REPL[33]:1
Some type information was truncated. Use `show(err)` to see complete types.
felixcremer commented 3 weeks ago

Thanks for the issue. I can reproduce this. With one dimensional DimArrays it is not running into a stack overflow error, but it ignores the units and the values of the Dimension but it correctly uses the Dimension label for the axis label.

julia> ddu = DimArray(rand(3), (Dim{:freq}((1.0:0.5:2.0)u"Hz")))
╭───────────────────────────────╮
│ 3-element DimArray{Float64,1} │
├───────────────────────────────┴─────────────────────────────────────────────────────────────────────────────────────────── dims ┐
  ↓ freq Sampled{Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{(Hz,), 𝐓^-1, nothing}}} (1.0:0.5:2.0) Hz ForwardOrdered Regular Points
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
 1.0 Hz  0.406088
 1.5 Hz  0.834368
 2.0 Hz  0.0332971

julia> plot(ddu)

I expect that this related to by #720.

asinghvi17 commented 3 weeks ago

[14] convert_arguments(::Type{Heatmap}, ::IntervalSets.ClosedInterval{Quantity{…}}, ::Vararg{Any}; kw::@Kwargs{})

This stuff is meant to be handled by expand_dimensions, so implementing #720 may help here.

rafaqz commented 3 weeks ago

Ah right, really need #720!

I am super busy currently I'm unlikely to have time for it soon. So if anyone wants to try to for it

felixcremer commented 3 weeks ago

It only worked on 1-dim arrays because it ignored the lookup values of the axis with #714 I get the following error.

julia> plot(ddu)
ERROR: MethodError: no method matching convert_arguments(::PointBased, ::StepRange{Quantity{…}, Quantity{…}}, ::Vector{Float64})

Closest candidates are:
  convert_arguments(::PointBased, ::AbstractVector{T} where T<:Number, ::AbstractVector{T} where T<:Number, ::AbstractVector{T} where T<:Number)
   @ Makie ~/.julia/packages/Makie/iRM0c/src/conversions.jl:131
  convert_arguments(::PointBased, ::AbstractArray, ::AbstractVector, ::AbstractArray)
   @ Makie ~/.julia/packages/Makie/iRM0c/src/conversions.jl:112
  convert_arguments(::PointBased, ::IntervalSets.ClosedInterval, ::AbstractVector{T} where T<:Number)
   @ Makie ~/.julia/packages/Makie/iRM0c/src/conversions.jl:166
  ...

Stacktrace:
 [1] convert_arguments(t::PointBased, A::DimVector{…})
   @ DimensionalDataMakie ~/.julia/dev/DimensionalData/ext/DimensionalDataMakie.jl:353
 [2] _pointbased1(A::DimVector{…}, attributes::@Kwargs{}; set_axis_attributes::Bool)
   @ DimensionalDataMakie ~/.julia/dev/DimensionalData/ext/DimensionalDataMakie.jl:94
 [3] _pointbased1
   @ ~/.julia/dev/DimensionalData/ext/DimensionalDataMakie.jl:89 [inlined]
 [4] plot(A::DimVector{…}; axislegendkw::@NamedTuple{}, attributes::@Kwargs{})
   @ DimensionalDataMakie ~/.julia/dev/DimensionalData/ext/DimensionalDataMakie.jl:77
 [5] plot(A::DimVector{…})
   @ DimensionalDataMakie ~/.julia/dev/DimensionalData/ext/DimensionalDataMakie.jl:76
 [6] top-level scope
   @ REPL[43]:1
Some type information was truncated. Use `show(err)` to see complete types.