Skip to content

plot! fails for time-based DimArrays #1160

@thirtysixbananas

Description

@thirtysixbananas

Works:

y1 = DimArray(rand(Float64, 11), (times=1:11,),)
y2 = DimArray(rand(Float64, 11), (times=1:11,),)
f = Figure()
ax = Axis(f[1,1])
plot!(ax, y1)  # Scatter{Tuple{Vector{Point{2, Float64}}}}
plot!(ax, y2)  # Scatter{Tuple{Vector{Point{2, Float64}}}}

Doesn't work:

y1 = DimArray(
    rand(Float64, 11),
    (times=DateTime("2026-01-01"):Minute(1):DateTime("2026-01-01T00:10:00"),),
)
y2 = DimArray(
    rand(Float64, 11),
    (times=DateTime("2026-01-01"):Minute(1):DateTime("2026-01-01T00:10:00"),),
)
f = Figure()
ax = Axis(f[1,1])
plot!(ax, y1)  # Scatter{Tuple{Vector{Point{2, Float64}}}}
plot!(ax, y2)  # ERROR: ArgumentError:
    Conversion failed for Scatter (With conversion trait PointBased()) with args:
        Tuple{DimVector{Float64, Tuple{Dim{:times, DimensionalData.Dimensions.Lookups.Sampled{DateTime, StepRange{DateTime, Minute}, DimensionalData.Dimensions.Lookups.ForwardOrdered, DimensionalData.Dimensions.Lookups.Regular{Minute}, DimensionalData.Dimensions.Lookups.Points, DimensionalData.Dimensions.Lookups.NoMetadata}}}, Tuple{}, Vector{Float64}, DimensionalData.NoName, DimensionalData.Dimensions.Lookups.NoMetadata}} 
    Got converted to: Tuple{StepRange{DateTime, Minute}, Vector{Float64}}
    Scatter requires to convert to argument types Tuple{AbstractVector{<:Union{Point2, Point3}}}, which convert_arguments didn't succeed in.
    To fix this overload convert_arguments(P, args...) for Scatter or PointBased() and return an object of type Tuple{AbstractVector{<:Union{Point2, Point3}}}.`

Stacktrace:
 [1] argument_error(PTrait::PointBased, P::Type, args::Tuple{…}, user_kw::Dict{…}, converted::Tuple{…})
   @ Makie ~/.julia/packages/Makie/Vn16E/src/compute-plots.jl:725
 [2] (Scatter)(user_args::Tuple{DimVector{…}}, user_attributes::Dict{Symbol, Any})
   @ Makie ~/.julia/packages/Makie/Vn16E/src/compute-plots.jl:773
 [3] _create_plot!(::Function, ::Dict{…}, ::Axis, ::DimVector{…})
   @ Makie ~/.julia/packages/Makie/Vn16E/src/figureplotting.jl:403
 [4] #scatter!#62
   @ ~/.julia/packages/Makie/Vn16E/src/recipes.jl:534 [inlined]
 [5] scatter!
   @ ~/.julia/packages/Makie/Vn16E/src/recipes.jl:532 [inlined]
 [6] plot!(ax::Axis, dd::DimVector{…})
   @ DimensionalDataMakieExt ~/.julia/packages/DimensionalData/FWnw9/ext/DimensionalDataMakieExt.jl:395

As a sanity check I tried plotting with DateTime on the x-axis and it works, so the above problem is specific to DD, not Makie:

ts = DateTime("2026-01-01"):Minute(1):DateTime("2026-01-01T00:10:00")
y1 = rand(Float64, 11)
y2 = rand(Float64, 11)
f = Figure()
ax = Axis(f[1,1])
plot!(ax, ts, y1)  # Scatter{Tuple{Vector{Point{2, Float64}}}}
plot!(ax, ts, y2)  # Scatter{Tuple{Vector{Point{2, Float64}}}}

EDIT:

Calls here so this is a simpler path to reproduce:

Makie.scatter!(ax, y1)

Does this check before throwing: https://github.com/MakieOrg/Makie.jl/blob/4a6728146ca4d5b3d20ee9244300788243697c79/Makie/src/compute-plots.jl#L780

In both cases, PTrait = PointBased(), P=Scatter.
However, in the first plot!

converted=(Point{2, Float64}[[6.39029088e13, 0.5836928495029402], [6.390290886e13, 0.384911441829076], [6.390290892e13, 0.1530611230665475], [6.390290898e13, 0.416598093899766], [6.390290904e13, 0.1913697055696404], [6.39029091e13, 0.07931893959562897], [6.390290916e13, 0.5810192663574537], [6.390290922e13, 0.4698605070411458], [6.390290928e13, 0.2241905689270648], [6.390290934e13, 0.25124129374053417], [6.39029094e13, 0.9313477533438733]],)
got_converted(P, PTrait, converted)  # true and succeeds

but in the second

converted=(DateTime("2026-01-01T00:00:00"):Minute(1):DateTime("2026-01-01T00:10:00"), [0.646820062789859, 0.5319466876655881, 0.36043739283964304, 0.8572681488599282, 0.4556710116927154, 0.6731147331017542, 0.08469344244360877, 0.4920890801070882, 0.9769361150754856, 0.9531765290732815, 0.3459698165949199])
got_converted(P, PTrait, converted)  # false and throws
PTrait = Makie.PointBased()
P = Makie.Scatter
converted1=(Point{2, Float64}[[6.39029088e13, 0.5836928495029402], [6.390290886e13, 0.384911441829076], [6.390290892e13, 0.1530611230665475], [6.390290898e13, 0.416598093899766], [6.390290904e13, 0.1913697055696404], [6.39029091e13, 0.07931893959562897], [6.390290916e13, 0.5810192663574537], [6.390290922e13, 0.4698605070411458], [6.390290928e13, 0.2241905689270648], [6.390290934e13, 0.25124129374053417], [6.39029094e13, 0.9313477533438733]],)
converted2=(DateTime("2026-01-01T00:00:00"):Minute(1):DateTime("2026-01-01T00:10:00"), [0.646820062789859, 0.5319466876655881, 0.36043739283964304, 0.8572681488599282, 0.4556710116927154, 0.6731147331017542, 0.08469344244360877, 0.4920890801070882, 0.9769361150754856, 0.9531765290732815, 0.3459698165949199])
Makie.got_converted(P, PTrait, converted1)  # true
Makie.got_converted(P, PTrait, converted2)  # false

EDIT2:

On entering this function https://github.com/MakieOrg/Makie.jl/blob/4a6728146ca4d5b3d20ee9244300788243697c79/Makie/src/compute-plots.jl#L746
in boths cases, user_args: ([0.646820062789859, 0.5319466876655881, 0.36043739283964304, 0.8572681488599282, 0.4556710116927154, 0.6731147331017542, 0.08469344244360877, 0.4920890801070882, 0.9769361150754856, 0.9531765290732815, 0.3459698165949199],)
However user_attributes in the first case is

Dict{Symbol, Any}(
    :dim_conversions => Makie.DimConversions(
        (
            Observable{Union{Nothing, Makie.AbstractDimConversion}}(nothing),
            Observable{Union{Nothing, Makie.AbstractDimConversion}}(nothing),
            Observable{Union{Nothing, Makie.AbstractDimConversion}}(nothing),
        ),
    ),
)

whereas in the second case its

Dict{Symbol, Any}(
    :dim_conversions => Makie.DimConversions(
        (
            Observable{Union{Nothing, Makie.AbstractDimConversion}}(Makie.DateTimeConversion(Observable(DateTime))),
            Observable{Union{Nothing, Makie.AbstractDimConversion}}(Makie.NoDimConversion()),
            Observable{Union{Nothing, Makie.AbstractDimConversion}}(nothing),
        ),
    ),
)

EDIT3:

So the function above is called with different arguments each time. That comes from here: https://github.com/MakieOrg/Makie.jl/blob/4a6728146ca4d5b3d20ee9244300788243697c79/Makie/src/figureplotting.jl#L401-L403

On line 403 you see the call to the function above, and on line 401 you can see how the arguments are generated. They are different the first and the second time, because ax is a stateful Axis object and get_conversions(ax) returns different things each time. We can see that by doing:

f = Figure()
ax = Axis(f[1,1])
Makie.get_conversions(ax)  # Makie.DimConversions((Observable{Union{Nothing, Makie.AbstractDimConversion}}(nothing), Observable{Union{Nothing, Makie.AbstractDimConversion}}(nothing), Observable{Union{Nothing, Makie.AbstractDimConversion}}(nothing)))
plot!(ax, y1)
Makie.get_conversions(ax)  # Makie.DimConversions((Observable{Union{Nothing, Makie.AbstractDimConversion}}(Makie.DateTimeConversion(Observable(DateTime))), Observable{Union{Nothing, Makie.AbstractDimConversion}}(Makie.NoDimConversion()), Observable{Union{Nothing, Makie.AbstractDimConversion}}(nothing)))
plot!(ax, y2)

EDIT4:

Ok dim conversions being different in first and second calling of plot! isn't the reason for this problem, because the simple case:

ts = DateTime("2026-01-01"):Minute(1):DateTime("2026-01-01T00:10:00")
y1 = rand(Float64, 11)
y2 = rand(Float64, 11)
f = Figure()
ax = Axis(f[1,1])
plot!(ax, ts, y1)  # Scatter{Tuple{Vector{Point{2, Float64}}}}
plot!(ax, ts, y2)  # Scatter{Tuple{Vector{Point{2, Float64}}}}

Has the same behavior.

Help? I have no idea what I'm doing here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions