Log scales would be nice. @SebastianM-C has put together an example of how it can be done, but I would like to integrate it more into the plotting pipeline - maybe as an Attribute of an Axis.
scale = (:identity, :identity) or (:identity, :identity, :identity) as default and then you could have :log, :log2, :exp10, :asinh, :sqrt, ... depending on the scaling function
For a logscale on the Oy axis, based on the discussion in JuliaPlots/Makie.jl#551, I used something like this:
using UnicodeFun
function log_ticks(lims, n)
a = round(lims[1], RoundNearest)
b = round(lims[2], RoundNearest)
r = range(a, b, length=n)
l = raw"10^{".*string.(r).*"}"
t = to_latex.(l)
return r, t
end
r, t = log_ticks(ey, 5)
ranges = Node((xrange, r))
labels = Node((xlabel, t))
plot(..., axis = (
names = (axisnames=("x", "log₁₀(y)"),),
ticks = (
ranges = ranges,
labels = labels
),
),
)
Perhaps a better API would be passing a Union{Function, Symbol} but we don't guarantee optimized ticks for functions
This might be better to lump in with the axis refactor that will be necessary for layouting.
has there been any progress on this?
I did a long example how to to make a matlab-like log10 plot using MakieLayout.
I don't know how to handle the internals of Makie, therefore for sure my code can be optimized and improved. But for sinple codes, is enough.
using AbstractPlotting
using CairoMakie
using FileIO
using MakieLayout
using UnicodeFun
using IterTools
function createLog10_AxisTicks(axes_interest, raw_data_interest; isX=false)
min_Log10Value = minimum(log10.(raw_data_interest))
max_Log10Value = maximum(log10.(raw_data_interest))
if isX
default_tick_values = MakieLayout.get_tickvalues(axes_interest.xticks.val, min_Log10Value,max_Log10Value)
else
default_tick_values = MakieLayout.get_tickvalues(axes_interest.yticks.val, min_Log10Value,max_Log10Value)
end
ticks_to_display = unique(round.(Int, default_tick_values)) # I want to avoid non-integer numbers, like "3.5"
full_tick_span = range(minimum(ticks_to_display)-1, maximum(ticks_to_display)+1, step=1)
tick_ranges, tick_labels = [], []
isFirstInterval = true
for interval_limits in partition(full_tick_span, 2, 1)
# create latex text for the interval
raw_text = raw"10^{".*string.(interval_limits).*"}"
latex_text = to_latex.(raw_text)
# compute numbers inside interval in log10 scale
values_inside_interval = collect(log10.(range(10.0^interval_limits[1], 10.0^interval_limits[2], length=10)))
labels_inside_interval = [" " for _=1:10] # do not show the values in the middle, but I need some marker
if interval_limits[1] ∈ ticks_to_display
labels_inside_interval[1] = latex_text[1]
end
if interval_limits[2] ∈ ticks_to_display
labels_inside_interval[end] = latex_text[end]
end
if isFirstInterval
[push!(tick_ranges, values_inside_interval[n]) for n = 1:10 ]
[push!(tick_labels, labels_inside_interval[n]) for n = 1:10 ]
isFirstInterval = false
else
# I want to avoid repetitions of values at the interval limits
# Therefore, I ignore the first element
[push!(tick_ranges, values_inside_interval[n]) for n = 2:10 ]
[push!(tick_labels, labels_inside_interval[n]) for n = 2:10 ]
end
end
return tick_ranges, tick_labels
end
xscale_log10(axes_interest, raw_data_interest) = createLog10_AxisTicks(axes_interest, raw_data_interest;isX=true)
yscale_log10(axes_interest, raw_data_interest) = createLog10_AxisTicks(axes_interest, raw_data_interest;isX=false)
x = range(4,10, step=0.001)
y1 = exp.(-x)
y2 = exp.(-x/2)
y3 = x.^(-1.5)
scene, layout = layoutscene(1, 1, 30, resolution = (500, 500))
ax1 = layout[1, 1] = LAxis(scene, title=" log10 example ")
scatter!(ax1, x, log10.(y1), color=:blue)
scatter!(ax1, x, log10.(y2), color=:green)
scatter!(ax1, x, log10.(y3), color=:purple)
scene
allYdata = vcat(y1, y2, y3) # I don't know how to access data inside ax1 structure, then, I passed it as argument
ax1.xlabel = "x"
ax1.ylabel = "y"
ax1.yticks = yscale_log10(ax1, allYdata)
scene
save("log10example.png", scene)
Most helpful comment
I did a long example how to to make a matlab-like log10 plot using MakieLayout.
I don't know how to handle the internals of Makie, therefore for sure my code can be optimized and improved. But for sinple codes, is enough.