How to define a custom Makie xscale function which needs an extra argument?

Hi

To apply a custom scaling function in Makie as per the docs we need to overload some functions. The example below is taken from here

import Makie

function my_log(x)
    return log10(x)
end

function my_inverse_log(x)
    return  10.0^x
end

Makie.defaultlimits(::typeof(my_log)) = (1.0, 1000.0)
Makie.defined_interval(::typeof(my_log)) = Makie.OpenInterval(0.0, Inf)
Makie.inverse_transform(::typeof(my_log)) = my_inverse_log

using CairoMakie

x = collect(1.0:10.0)
y = rand(10)

fig, ax = lines(x,y)
ax.yscale = my_log

fig

My question is how can I create yscale or xscale functions that take an extra argument? For example suppose my scaling function requires an extra argument b which is fixed per plot. But I want to apply the same scaling with different b values to other plots and I don’t know b until runtime.

function my_log(x, b)
    return log(b,x)
end

function my_inverse_log(x, b)
    return b^x
end

To apply the scaling function we could simply write

b = 3.0
fig, ax = lines(x,y)

ax.yscale = x -> my_log(x, b)

but it’s not clear how to handle the inverse function since the extra argument b is defined in local scope but Makie.inverse_transform is defined in global space. It doesn’t have access to b

Makie.inverse_transform(::typeof(my_log)) = my_inverse_log

Is there a way around this? Can I pass the inverse function to the Axis constructor maybe?

Someone refactored Symlog10 to use ReversibleScale with internal closures.
I don’t remember what it looked like before but I thought I had used functor structs.
Makie.jl/src/layouting/transformation.jl at master · MakieOrg/Makie.jl · GitHub

1 Like

Clever! Works great, thank you.

Do

ax.yscale = Base.Fix2(my_log, b)

and

Makie.inverse_transform(f::Base.Fix2(typeof(my_log))) = Base.Fix2(my_inverse_log, f.x)

instead.