Skip to content

Commit

Permalink
fix makie recipes for units in lookups (#769)
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaqz authored Aug 17, 2024
1 parent 6aa28e4 commit 4c611bc
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 25 deletions.
53 changes: 41 additions & 12 deletions ext/DimensionalDataMakie.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
module DimensionalDataMakie

using DimensionalData, Makie
using DimensionalData
using Makie
using IntervalSets
using DimensionalData.Dimensions, DimensionalData.LookupArrays

const DD = DimensionalData
Expand Down Expand Up @@ -345,18 +347,18 @@ function _boxplotlike(A, attributes, labeldim)
end

# Plot type definitions. Not sure they will ever get called?
Makie.plottype(A::AbstractDimVector) = Makie.Scatter
Makie.plottype(A::AbstractDimMatrix) = Makie.Heatmap
Makie.plottype(A::AbstractDimArray{<:Any,3}) = Makie.Volume
Makie.plottype(::AbstractDimVector) = Makie.Scatter
Makie.plottype(::AbstractDimMatrix) = Makie.Heatmap
Makie.plottype(::AbstractDimArray{<:Any,3}) = Makie.Volume

# Conversions
function Makie.convert_arguments(t::Type{<:Makie.AbstractPlot}, A::AbstractDimMatrix)
A1 = _prepare_for_makie(A)
xs, ys = map(parent, lookup(A1))
xs, ys = map(_lookup_to_vector, lookup(A1))
return xs, ys, last(Makie.convert_arguments(t, parent(A1)))
end
function Makie.convert_arguments(t::Makie.PointBased, A::AbstractDimVector)
A = _prepare_for_makie(A)
A1 = _prepare_for_makie(A)
xs = parent(lookup(A, 1))
return Makie.convert_arguments(t, xs, _floatornan(parent(A)))
end
Expand All @@ -365,24 +367,30 @@ function Makie.convert_arguments(t::Makie.PointBased, A::AbstractDimMatrix)
end
function Makie.convert_arguments(t::SurfaceLikeCompat, A::AbstractDimMatrix)
A1 = _prepare_for_makie(A)
xs, ys = map(parent, lookup(A1))
xs, ys = map(_lookup_to_vector, lookup(A1))
# the following will not work for irregular spacings, we'll need to add a check for this.
return first(xs)..last(xs), first(ys)..last(ys), last(Makie.convert_arguments(t, parent(A1)))
return xs, ys, last(Makie.convert_arguments(t, parent(A1)))
end
function Makie.convert_arguments(t::Makie.ImageLike, A::AbstractDimMatrix)
A1 = _prepare_for_makie(A)
xs, ys = map(_lookup_to_intervals, lookup(A))
# the following will not work for irregular spacings, we'll need to add a check for this.
return xs, ys, last(Makie.convert_arguments(t, parent(A1)))
end
function Makie.convert_arguments(
t::Makie.CellGrid, A::AbstractDimMatrix
)
A1 = _prepare_for_makie(A)
xs, ys = map(parent, lookup(A1))
xs, ys = map(_lookup_to_axis, lookup(A1))
return xs, ys, last(Makie.convert_arguments(t, parent(A1)))
end
function Makie.convert_arguments(t::Makie.VolumeLike, A::AbstractDimArray{<:Any,3})
A1 = _prepare_for_makie(A)
xs, ys, zs = map(parent, lookup(A1))
xs, ys, zs = map(_lookup_to_vector, lookup(A1))
# the following will not work for irregular spacings
return first(xs)..last(xs), first(ys)..last(ys), first(zs)..last(zs), last(Makie.convert_arguments(t, parent(A1)))
return xs, ys, zs, last(Makie.convert_arguments(t, parent(A1)))
end
# fallbacks with descriptive error messages
# # fallbacks with descriptive error messages
function Makie.convert_arguments(t::Makie.ConversionTrait, A::AbstractDimArray{<:Any,N}) where {N}
@warn "$t not implemented for `AbstractDimArray` with $N dims, falling back to parent array type"
return Makie.convert_arguments(t, parent(A))
Expand Down Expand Up @@ -512,6 +520,27 @@ function _keywords2dimpairs(x, y)
end
end

function _lookup_to_vector(l)
if isintervals(l)
bs = intervalbounds(l)
x = first.(bs)
push!(x, last(last(bs)))
else
collect(parent(l))
end
end

function _lookup_to_interval(l)
l1 = if isnolookup(l)
Sampled(parent(l); order=ForwardOrdered(), sampling=Intervals(Center()), span=Regular(1))
elseif ispoints(l)
set(l, Intervals())
else
l
end
return IntervalSets.Interval(bounds(l1)...)
end

_floatornan(A::AbstractArray{<:Union{Missing,<:Real}}) = _floatornan64.(A)
_floatornan(A::AbstractArray{<:Union{Missing,Float64}}) = _floatornan64.(A)
_floatornan(A) = A
Expand Down
78 changes: 65 additions & 13 deletions test/plotrecipes.jl
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
using DimensionalData, Test, Dates
using Plots, StatsPlots, Unitful
using Unitful
import Distributions

using DimensionalData: Metadata, NoMetadata, ForwardOrdered, ReverseOrdered, Unordered,
Sampled, Categorical, NoLookup, Transformed,
Regular, Irregular, Explicit, Points, Intervals, Start, Center, End


@testset "Plots.jl" begin

using Plots
using StatsPlots

A1 = rand(Distributions.Normal(), 20)
ref = (Ti(Sampled(1:1; order=ForwardOrdered(), span=Regular(Day(1)), sampling=Points())),)
da1_regular = DimArray(A1, X(1:50:1000); name=:Normal, refdims=ref)
Expand Down Expand Up @@ -131,8 +137,6 @@ for da in (da3_regular, da3_noindex, da3_ni_r_ni, da3_c_c_c, da3_XYZ, da3_XTiZ,
end
end

nothing

# Not sure how recipes work for this
# andrewsplot(da2)

Expand All @@ -159,13 +163,19 @@ nothing
# da_im2 = DimArray(im2, (X(10:10:100), Y(10:10:100)), "Image")
# da_im2 |> plot

using CairoMakie: CairoMakie as M
using ColorTypes
end


@testset "Makie" begin

using CairoMakie: CairoMakie as M
using ColorTypes

# 1d
A1 = rand(X('a':'e'); name=:test)
A1m = rand([missing, (1:3.)...], X('a':'e'); name=:test)
A1u = rand([missing, (1:3.)...], X(1u"s":1u"s":3u"s"); name=:test)
A1ui = rand([missing, (1:3.)...], X(1u"s":1u"s":3u"s"; sampling=Intervals(Start())); name=:test)
A1num = rand(X(-10:10))
A1m .= A1
A1m[3] = missing
Expand All @@ -174,6 +184,10 @@ using ColorTypes
fig, ax, _ = M.plot(A1m)
fig, ax, _ = M.plot(parent(A1m))
M.plot!(ax, A1m)
fig, ax, _ = M.plot(A1u)
M.plot!(ax, A1u)
fig, ax, _ = M.plot(A1ui)
M.plot!(ax, A1ui)
fig, ax, _ = M.plot(A1num)
M.reset_limits!(ax)
org = first(ax.finallimits.val.origin)
Expand All @@ -187,39 +201,57 @@ using ColorTypes
M.scatter!(ax, A1m)
fig, ax, _ = M.lines(A1)
M.lines!(ax, A1)
fig, ax, _ = M.lines(A1u)
M.lines!(ax, A1u)
fig, ax, _ = M.lines(A1m)
M.lines!(ax, A1m)
fig, ax, _ = M.scatterlines(A1)
M.scatterlines!(ax, A1)
fig, ax, _ = M.scatterlines(A1u)
M.scatterlines!(ax, A1u)
fig, ax, _ = M.scatterlines(A1m)
M.scatterlines!(ax, A1m)
fig, ax, _ = M.stairs(A1)
M.stairs!(ax, A1)
fig, ax, _ = M.stairs(A1u)
M.stairs!(ax, A1u)
fig, ax, _ = M.stairs(A1m)
M.stairs!(ax, A1m)
fig, ax, _ = M.stem(A1)
M.stem!(ax, A1)
fig, ax, _ = M.stem(A1u)
M.stem!(ax, A1u)
fig, ax, _ = M.stem(A1m)
M.stem!(ax, A1m)
fig, ax, _ = M.barplot(A1)
M.barplot!(ax, A1)
fig, ax, _ = M.barplot(A1u)
M.barplot!(ax, A1u)
fig, ax, _ = M.barplot(A1m)
M.barplot!(ax, A1m)
fig, ax, _ = M.waterfall(A1)
M.waterfall!(ax, A1)
fig, ax, _ = M.waterfall(A1u)
M.waterfall!(ax, A1u)
fig, ax, _ = M.waterfall(A1m)
M.waterfall!(ax, A1m)
# 2d
A2 = rand(X(10:10:100), Y(['a', 'b', 'c']))
A2r = rand(Y(10:10:100), X(['a', 'b', 'c']))
A2m = rand([missing, (1:5)...], Y(10:10:100), X(['a', 'b', 'c']))
A2u = rand(Y(10u"km":10u"km":100u"km"), X(['a', 'b', 'c']))
A2ui = rand(Y(10u"km":10u"km":100u"km"; sampling=Intervals(Start())), X(['a', 'b', 'c']))
A2m[3] = missing
A2rgb = rand(RGB, X(10:10:100), Y(['a', 'b', 'c']))

fig, ax, _ = M.plot(A2)
M.plot!(ax, A2)
fig, ax, _ = M.plot(A2m)
M.plot!(ax, A2m)
fig, ax, _ = M.plot(A2u)
M.plot!(ax, A2u)
fig, ax, _ = M.plot(A2ui)
M.plot!(ax, A2ui)
fig, ax, _ = M.plot(A2rgb)
M.plot!(ax, A2rgb)
fig, ax, _ = M.heatmap(A2)
Expand All @@ -241,17 +273,26 @@ using ColorTypes

fig, ax, _ = M.rainclouds(A2)
M.rainclouds!(ax, A2)
# @test_throws ErrorException M.rainclouds(A2m) # MethodError ? missing values in data not supported
# @test_throws ErrorException M.rainclouds!(ax, A2m)
fig, ax, _ = M.rainclouds(A2u)
M.rainclouds!(ax, A2u)
@test_throws ErrorException M.rainclouds(A2m) # MethodError ? missing values in data not supported

fig, ax, _ = M.surface(A2)
M.surface!(ax, A2)
fig, ax, _ = M.surface(A2u)
M.surface!(ax, A2u)
fig, ax, _ = M.surface(A2ui)
M.surface!(ax, A2ui)
fig, ax, _ = M.surface(A2m)
M.surface!(ax, A2m)
# Series also puts Categories in the legend no matter where they are
# TODO: method series! is incomplete, we need to include the colors logic, as in series. There should not be any issue if the correct amount of colours is provided.
fig, ax, _ = M.series(A2)
# M.series!(ax, A2)
fig, ax, _ = M.series(A2u)
# M.series!(ax, A2u)
fig, ax, _ = M.series(A2ui)
# M.series!(ax, A2u)
fig, ax, _ = M.series(A2r)
# M.series!(ax, A2r)
fig, ax, _ = M.series(A2r; labeldim=Y)
Expand Down Expand Up @@ -289,21 +330,32 @@ using ColorTypes

# 3d, all these work with GLMakie
A3 = rand(X(7), Z(10), Y(5))
A3u = rand(X((1:7)u"m"), Z((1.0:1:10.0)u"m"), Y((1:5)u"g"))
A3m = rand([missing, (1:7)...], X(7), Z(10), Y(5))
A3m[3] = missing
A3rgb = rand(RGB, X(7), Z(10), Y(5))
fig, ax, _ = M.volume(A3)
M.volume!(ax, A3)
fig, ax, _ = M.volume(A3m)
M.volume!(ax, A3m)
# Broken in Makie ?

# Units are broken in Makie ?
# fig, ax, _ = M.volume(A3u)
# M.volume!(ax, A3u)

fig, ax, _ = M.volumeslices(A3)
M.volumeslices!(ax, A3)
# Need to manually specify colorrange
fig, ax, _ = M.volumeslices(A3m; colorrange=(1, 7))
M.volumeslices!(ax, A3m; colorrange=(1, 7))

# Unitful volumeslices broken in Makie ?
# fig, ax, _ = M.volumeslices(A3u)
# M.volumeslices!(ax, A3u)

# RGB volumeslices broken in Makie ?
# fig, ax, _ = M.volumeslices(A3rgb)
# M.volumeslices!(ax, A3rgb)
# fig, ax, _ = M.volumeslices(A3)
# M.volumeslices!(ax, A3)
# colorrange isn't detected here
# fig, ax, _ = M.volumeslices(A3m; colorrange=(1, 7))
# M.volumeslices!(ax, A3m; colorrange=(1, 7))
# fig, ax, _ = M.volumeslices(A3rgb)
# M.volumeslices!(ax, A3rgb)
# x/y/z can be specified
Expand Down

0 comments on commit 4c611bc

Please sign in to comment.