DimensionalData.jl icon indicating copy to clipboard operation
DimensionalData.jl copied to clipboard

StackOverflowError with Makie Extension and Unitful Dimensions

Open joshkraan opened this issue 3 months ago • 5 comments

When I try to plot a DimArray with Unitful dimensions I am getting a StackOverflowError. There was previously a resolved issue about what seems to be the same error: https://github.com/rafaqz/DimensionalData.jl/issues/723. It seems that this issue was reintroduced with version 0.29.19.

Here is the same minimal example as provided by @david-macmahon in the original issue.

Version 0.29.18 works:

(jl_uAVeuD) pkg> st CairoMakie DimensionalData Unitful
Status `/tmp/jl_uAVeuD/Project.toml`
⌃ [13f3f980] CairoMakie v0.14.0
⌃ [0703355e] DimensionalData v0.29.18
  [1986cc42] Unitful v1.24.0
Info Packages marked with ⌃ have new versions available and may be upgradable.

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.866261  0.542912  0.556222  0.575055  0.423188
 1.5  0.716689  0.267359  0.25917   0.267714  0.199823
 2.0  0.619127  0.838477  0.821431  0.261603  0.0693282

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.205511  0.993605  0.966492  0.787188  0.685997
 1.5 Hz  0.905903  0.272701  0.617019  0.161883  0.0868278
 2.0 Hz  0.7243    0.735437  0.350271  0.906789  0.981961

julia> plot(ddu) # also works

Version 0.29.19 does not work:

(jl_Y1J9tn) pkg> st CairoMakie DimensionalData Unitful
Status `/tmp/jl_Y1J9tn/Project.toml`
  [13f3f980] CairoMakie v0.15.6
⌃ [0703355e] DimensionalData v0.29.19
  [1986cc42] Unitful v1.24.0
Info Packages marked with ⌃ have new versions available and may be upgradable.

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.863165   0.0334873  0.951236  0.905314   0.579467
 1.5  0.32396    0.988554   0.776589  0.912863   0.206955
 2.0  0.0461706  0.880968   0.32979   0.0800129  0.662683

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.290704    0.777649  0.169968   0.104919  0.900903
 1.5 Hz  0.00916393  0.763765  0.994425   0.47843   0.693603
 2.0 Hz  0.917727    0.525552  0.0422042  0.418307  0.787847

julia> plot(ddu)
ERROR: StackOverflowError:
Stacktrace:
 [1] Base.TwicePrecision{Float64}(nd::Tuple{Int128, Int128})
   @ Base ./twiceprecision.jl:222
 [2] steprangelen_hp(::Type{…}, ref::Tuple{…}, step::Tuple{…}, nb::Int64, len::Int64, offset::Int64)
   @ Base ./twiceprecision.jl:344
 [3] _linspace(::Type{Float64}, start_n::Int64, stop_n::Int64, len::Int64, den::Int64)
   @ Base ./twiceprecision.jl:730
 [4] range_start_stop_length(start::Float64, stop::Float64, len::Int64)
   @ Base ./twiceprecision.jl:660
 [5] _range
   @ ./range.jl:167 [inlined]
 [6] _range(start::Quantity{…}, ::Nothing, stop::Quantity{…}, len::Int64)
   @ Unitful ~/.julia/packages/Unitful/sxiHA/src/range.jl:26
 [7] range
   @ ./range.jl:148 [inlined]
 [8] to_linspace
   @ ~/.julia/packages/Makie/4JW9B/src/conversions.jl:737 [inlined]
 [9] convert_arguments(P::CellGrid, x::StepRangeLen{…}, y::StepRangeLen{…}, z::Matrix{…}) (repeats 79979 times)
   @ Makie ~/.julia/packages/Makie/4JW9B/src/conversions.jl:372
Some type information was truncated. Use `show(err)` to see complete types.

joshkraan avatar Aug 22 '25 22:08 joshkraan

Huh, I wonder if thats us or Makie

rafaqz avatar Aug 24 '25 12:08 rafaqz

For what it is worth, one dimensional data works as expected.

julia> ddu1 = DimArray(rand(3), (Dim{:freq}((1.0:0.5:2.0)u"Hz"),))

Also when I use heatmap, I get a bit more stacktrace:

julia> heatmap(ddu)
(xlookup, ylookup) = ((1.0:0.5:2.0) Hz, (0:4) s)
ERROR: StackOverflowError:
Stacktrace:
  [1] Base.TwicePrecision{Float64}(nd::Tuple{Int128, Int128})
    @ Base ./twiceprecision.jl:222
  [2] steprangelen_hp(::Type{…}, ref::Tuple{…}, step::Tuple{…}, nb::Int64, len::Int64, offset::Int64)
    @ Base ./twiceprecision.jl:344
  [3] _linspace(::Type{Float64}, start_n::Int64, stop_n::Int64, len::Int64, den::Int64)
    @ Base ./twiceprecision.jl:730
  [4] range_start_stop_length(start::Float64, stop::Float64, len::Int64)
    @ Base ./twiceprecision.jl:660
  [5] _range
    @ ./range.jl:167 [inlined]
  [6] _range(start::Quantity{…}, ::Nothing, stop::Quantity{…}, len::Int64)
    @ Unitful ~/.julia/packages/Unitful/sxiHA/src/range.jl:26
  [7] range
    @ ./range.jl:148 [inlined]
  [8] to_linspace
    @ ~/.julia/packages/Makie/4JW9B/src/conversions.jl:737 [inlined]
  [9] convert_arguments(P::CellGrid, x::StepRangeLen{…}, y::StepRangeLen{…}, z::Matrix{…}) (repeats 21637 times)
    @ Makie ~/.julia/packages/Makie/4JW9B/src/conversions.jl:372
 [10] convert_arguments(P::CellGrid, x::StepRangeLen{…}, y::StepRange{…}, z::Matrix{…})
    @ Makie ~/.julia/packages/Makie/4JW9B/src/conversions.jl:372
 [11] convert_arguments(::Type{…}, ::StepRangeLen{…}, ::Vararg{…}; kw::@Kwargs{})
    @ Makie ~/.julia/packages/Makie/4JW9B/src/conversions.jl:26
 [12] convert_arguments(::Type{…}, ::StepRangeLen{…}, ::StepRange{…}, ::Matrix{…})
    @ Makie ~/.julia/packages/Makie/4JW9B/src/conversions.jl:14
 [13] convert_arguments(P::Type{…}, A::DimMatrix{…}; xdim::Nothing, ydim::Nothing)
    @ DimensionalDataMakie ~/.julia/dev/DimensionalData/ext/DimensionalDataMakie.jl:487
 [14] convert_arguments
    @ ~/.julia/dev/DimensionalData/ext/DimensionalDataMakie.jl:481 [inlined]
 [15] #default_axis_type#78
    @ ~/.julia/dev/DimensionalData/ext/DimensionalDataMakie.jl:370 [inlined]
 [16] default_axis_type
    @ ~/.julia/dev/DimensionalData/ext/DimensionalDataMakie.jl:369 [inlined]
 [17] heatmap(fig::GridPosition, A::DimMatrix{…}; xdim::Nothing, ydim::Nothing, colorbar::@NamedTuple{}, axis::@NamedTuple{}, plot_attributes::@Kwargs{})
    @ DimensionalDataMakie ~/.julia/dev/DimensionalData/ext/DimensionalDataMakie.jl:278
 [18] heatmap
    @ ~/.julia/dev/DimensionalData/ext/DimensionalDataMakie.jl:273 [inlined]
 [19] #heatmap#11
    @ ~/.julia/dev/DimensionalData/ext/DimensionalDataMakie.jl:79 [inlined]
 [20] heatmap(A::DimMatrix{…})
    @ DimensionalDataMakie ~/.julia/dev/DimensionalData/ext/DimensionalDataMakie.jl:77
 [21] top-level scope
    @ REPL[32]:1
Some type information was truncated. Use `show(err)` to see complete types.

felixcremer avatar Aug 25 '25 09:08 felixcremer

It seems to be Makie, but I am still a bit confused, why this wasn't hit on 0.29.18.

julia> xlookup = (1.0:0.5:2.0)u"Hz"
(1.0:0.5:2.0) Hz
julia> Makie.convert_arguments(CellGrid(), xlookup, 0:4, rand(3,5))
ERROR: StackOverflowError:
Stacktrace:
  [1] Base.TwicePrecision{Float64}(nd::Tuple{Int128, Int128})
    @ Base ./twiceprecision.jl:222
  [2] steprangelen_hp(::Type{Float64}, ref::Tuple{Int128, Int128}, step::Tuple{Int128, Int128}, nb::Int64, len::Int64, offset::Int64)
    @ Base ./twiceprecision.jl:344
  [3] _linspace(::Type{Float64}, start_n::Int64, stop_n::Int64, len::Int64, den::Int64)
    @ Base ./twiceprecision.jl:730
  [4] range_start_stop_length(start::Float64, stop::Float64, len::Int64)
    @ Base ./twiceprecision.jl:660
  [5] _range
    @ ./range.jl:167 [inlined]
  [6] _range(start::Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{(Hz,), 𝐓^-1, nothing}}, ::Nothing, stop::Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{(Hz,), 𝐓^-1, nothing}}, len::Int64)
    @ Unitful ~/.julia/packages/Unitful/sxiHA/src/range.jl:26
  [7] range
    @ ./range.jl:148 [inlined]
  [8] to_linspace
    @ ~/.julia/packages/Makie/4JW9B/src/conversions.jl:737 [inlined]
  [9] convert_arguments(P::CellGrid, x::StepRangeLen{Quantity{…}, Base.TwicePrecision{…}, Base.TwicePrecision{…}, Int64}, y::StepRangeLen{Float64, Base.TwicePrecision{…}, Base.TwicePrecision{…}, Int64}, z::Matrix{Float64}) (repeats 47543 times)
    @ Makie ~/.julia/packages/Makie/4JW9B/src/conversions.jl:372
 [10] convert_arguments(P::CellGrid, x::StepRangeLen{Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{…}}, Base.TwicePrecision{Quantity{…}}, Base.TwicePrecision{Quantity{…}}, Int64}, y::UnitRange{Int64}, z::Matrix{Float64})
    @ Makie ~/.julia/packages/Makie/4JW9B/src/conversions.jl:372
 [11] top-level scope
    @ REPL[19]:1
Some type information was truncated. Use `show(err)` to see complete types.

Maybe @DylanMMarques you have some ideas, because you worked on the DimensionalData change that landed in 0.29.19.

felixcremer avatar Aug 25 '25 09:08 felixcremer

Yeah, looks like Makie to me. Ping @simondanisch in case you know what might be going on

rafaqz avatar Aug 25 '25 11:08 rafaqz

It seems it worked fine on 0.29.18 because the output of convert_arguments was defined as:

return xs, ys, last(Makie.convert_arguments(P, z))

while for 0.29.19, it is defined as:

return Makie.convert_arguments(P, xs, ys, z)

I tested this as:

 struct MyType1
 end
Makie.convert_arguments(P::Type{Heatmap}, x::MyType1)= Makie.convert_arguments(P, (1:6)u"s", (1:11), rand(5,10))

heatmap(MyType1()) # stack overflow error
 struct MyType2 
 end
Makie.convert_arguments(P::Type{Heatmap}, x::MyType2)= (1:6)u"s", (1:11), last(Makie.convert_arguments(P, rand(5,10)))

heatmap(MyType2()) # works fine

A work around could be to defined similarly as in 0.29.18. I don't think that it will create new problems, but I haven't tested it.

DylanMMarques avatar Aug 26 '25 10:08 DylanMMarques