Search code examples
juliamakie.jl

Custom Labels for Makie axis


I'm trying to shift some data in a Makie plot (I'm using a meshscatter, but have a simpler example).

If

fig = Figure()

Axis(fig[1,1],
xticks = 0:10:60,
xtickformat = x -> string.(x .+70),
yticks = 0:10:60,
ytickformat = x -> string.(x .+70),
limits = (0,60,0,60)
)
fig

I get the formats with a ".0" on the end of each label, but do not want them.

enter image description here

It appears that from the documentation, it runs through a command to automatically add the ".0".


Solution

  • By default, the tick values along a line axis in Makie are of type Float64. It's a bit convoluted to find in the code where this is happening, but you can see in the definition of the LineAxis function that tickvalues is created as an Observable{Vector{Float64}}, and it is this vector of Float64 values that ultimately gets passed to the function defined in xtickformat. This is true even though you define xticks as a StepRange{Int64, Int64}.

    The easiest way to force the display of the ticks to be integers is to cast the values passed to the xtickformat function as Int before turning them into strings:

    fig = Figure()
    Axis(fig[1,1];
        xticks = 0:10:60,
        xtickformat = (x -> @. string(Int(x) + 70)),
        limits = (0, 60, 0, 1),
    )
    

    An empty plot with integer x ticks from 70 to 130 incrementing by 10.

    This only works if all the xtick values can be converted into Int values, otherwise, this happens:

    Axis(fig[1,1];
        xticks = 0:1.5:6,
        xtickformat = (x -> @. string(Int(x) + 70)),
        limits = (0, 6, 0, 1),
    )
    # ERROR: InexactError: Int64(1.5)
    

    You can also pass a String to xtickformat, which will be interpreted as a format specifier for Format.jl, as described in the documentation. The format specifier for a floating point number with no decimal values is {:.0f}, which produces the following:

    Axis(fig[2,1];
        xticks = 0:10:60,
        xtickformat = "{:.0f}",
        xticklabelcolor = :purple,
        limits = (0, 60, 0, 1),
    )
    

    Two axes stacked vertically, the top one with black x tick marks labeled as integers from 70 to 130 by 10, and the bottom one with purple x tick marks labeled as integers from 0 to 60 by 10.

    Using this format specifier also works when the tick values are not integers, though the result will be rounded and might not be what you expect:

    Axis(fig[3,1];
        xticks = 0:1.5:6,
        xtickformat = "{:.0f}",
        xticklabelcolor = :orange,
        limits = (0, 6, 0, 1),
    )
    

    Three axes stacked vertically, the top one with black x tick marks labeled as integers from 70 to 130 by 10, the middle one with purple x tick marks labeled as integers from 0 to 60 by 10, and the bottom one with orange x tick marks labeled 0, 2, 3, 4, 6.