Makie.jl
Makie.jl copied to clipboard
Non-numeric axes
I want to plot non-numeric data and get non-numeric labels. It is possible to do this if I convert the values to float before passing them into makie and then pass a custom float-to-label function, but I find that somewhat awkward. I would prefer if Makie could handle my non-numeric values natively.
The basic idea of this implementation is to have a pair of functions: values2points
that converts rich types into floats, and points2values
that converts floats into rich types. This almost works. There are two problems here, labeled XXX
in the code.
- I have to convert the values into floats myself.
- Once the ticks are floats, I need to dispatch to a function that produces the label, but the floats alone aren't enough to tell which label function they need. Therefore I just dispatch on the value. This isn't a real solution.
I would like if Makie had another layer of hooks that could switch between rich data types and plot position floats. In particular, the tick-label functions could take rich types as arguments, rather than floats.
I'm interested in your thoughts.
using Dates
using Unitful
using CairoMakie
using AbstractPlotting
struct CustomLinearTicks
n_ideal::Int
end
function MakieLayout.get_tickvalues(ticks::CustomLinearTicks, vmin, vmax)
MakieLayout.get_tickvalues(LinearTicks(ticks.n_ideal), vmin, vmax)
end
function MakieLayout.get_ticklabels(formatter::AbstractString, tickvalues::AbstractArray)
string.(points2values(round.((@show(tickvalues)))))
end
# XXX HACK.
points2values(points) = points[1] > 1000 ? Dates.epochdays2date.(points) : points .* u"°C"
values2points(x::AbstractArray{T}) where T <: Quantity = getproperty.(x, :val)
values2points(x::AbstractArray{Date}) = Dates.date2epochdays.(x)
values2points(values::AbstractArray{Float64}) = @show(values)
fig = Figure(resolution=(500, 500), )
xs = collect(Date(2010,01,01):Dates.Month(3):Date(2012,01,01))
ys = rand(length(xs)) .* 100 .* u"°C"
# XXX I don't want to call these functions myself.
ax, sc = scatter(fig[1, 1], values2points(xs), values2points(ys), markersize=2)
ax.xticks = CustomLinearTicks(10)
ax.xtickformat = "{:}"
ax.xticklabelrotation = 45.
ax.xticklabelalign = (:right, :top)
ax.yticks = CustomLinearTicks(20)
ax.ytickformat = "{:}"
fig