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

Non-numeric axes

Open adkabo opened this issue 3 years ago • 0 comments

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.

  1. I have to convert the values into floats myself.
  2. 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

image

adkabo avatar Mar 06 '21 02:03 adkabo