Logscale on negative real axis

Hi all

I have a function, foo(x), which is defined only on the negative real axis. The range is quite wide and I want to plot it in log-scale, say from x=-1.0e7 to x=-1.0e-7. How can I “transform” the axis in Makie to allow this “negative” logscale? I can transform y=-x by myself, of course, but then the plot is from +1.0e-7 to +1.0e+7, i.e. mirrored left-right… I cannot re-mirror it by setting the xlims (no output); I guess that the transform is flipping because of negative values in log scale.

You can re-mirror by setting ax.xreversed = true? The tick labels will be positive of course, one could change that via formatting but it’s a little annoying I guess. Another option would be to add negative_log as an axis scale function. Here’s how you’d do that, it’s not really documented because it’s not something people often do. I’m hijacking the functionality for normal log ticks by running the tick finding on the positive mirror values and converting back.

neglog10(x) = log10(-x)
Makie.defaultlimits(::typeof(neglog10)) = (-100, -1)
Makie.defined_interval(::typeof(neglog10)) = Makie.OpenInterval(-Inf, 0.0)
Makie.inverse_transform(::typeof(neglog10)) = x -> -exp10(x)
function Makie.get_ticks(::Makie.Automatic, scale::typeof(neglog10),
    any_formatter, vmin, vmax)
    vals, labels = get_ticks(LogTicks(WilkinsonTicks(5, k_min = 3)), log10, any_formatter, -vmax, -vmin)
    -vals, rich.("-", labels)
end

data = sort(-exp.(rand(-7..7, 1000)))
scatter(data, axis = (; yscale = neglog10))

2 Likes

In my setup, I need to change

vals, labels = get_ticks(LogTicks(WilkinsonTicks(5, k_min = 3)), log10, any_formatter, -vmax, -vmin)
    -vals, rich.("-", labels

to

vals, labels = Makie.get_ticks(LogTicks(WilkinsonTicks(5, k_min = 3)), log10, any_formatter, -vmax, -vmin)
    -vals, rich.("-", labels

And sorry to nag, but the code doesn’t work for me when applied on the x-axis (using pure negative values, of course). Which is kind of weird…

I don’t know, this works for me scatter(data, data, axis = (; xscale = neglog10))

Yes. That works for me as well. Weird. My bad. Thanks for the nifty solution!

It seemed that my range is too wide (-1e7 to -1e-7)…

This works:

pmin = -3
pmax = 3
x = sort(-(10.) .^ range(pmin,pmax, 1000))
lines(x, x, axis = (; xscale = neglog10, yscale = neglog10))

but changing pmin to -4 or pmax to +4, gives no output (no warnings/errors either, just no output).

Do I need to manually set limits for the axis?

Hm yeah that is weird, I get

ERROR: Found invalid x-limits (-10000.0f0, 0.0f0) for scale neglog10 which is defined on the interval -Inf..0.0 (open)

seems like the float32 conversion lets the max value round up to 0, which is not allowed for log scale. There’s an open PR to fix such issues by switching to Float64, at least for CairoMakie.