Reputation: 71
I am trying to plot a graph using cairo makie and want to have points on the x-axis labeled with letters.
But I still want to have evenly spaced tick marks with numbers on them as usual.
I would like to do it with Cairo-makie as that is what I primarily use for plotting.
Upvotes: 0
Views: 62
Reputation: 1683
Makie can generate a plot where certain values on the x-axis are annotated with labels and vertical lines in addition to the numeric tick labels. To produce two sets of axis tick labels, create Axis twice for the same figure. To add vertical lines, incorporate a VLines
plot.
# nonsense example x values
L = -0.1
K = +1.0/3
M = +1.0/2
R = +0.7
xtickstep1 = 0.1
xrange1 = L:xtickstep1:R
xLetterDict1 = Dict{Float64,String}(L => "Γ", K => "K", M => "M", R => "Γ")
# nonsense example function
f1 = x -> let x_ = 10*(x - K); return (x_ + sin(x_))*2/3; end
f1_hi = x -> max(f1(x), -f1(x))
f1_lo = x -> min(f1(x), -f1(x))
using CairoMakie: Figure, Axis, hidespines!, hideydecorations!, vlines!, :.., lines!
Create two Axis
for the same figure. Here they will be named axNumeric
for the Axis displaying numerical x and y values, and axLettered
for the Axis displaying lettered x values.
For axLettered
, use Axis
attribute xtickformat
to specify a function that produces tick labels, such as a function that uses a dictionary xLetterDict
to produce the corresponding symbol for each value.
Use Axis
option xticks
to specify that ticks should only appear at xLetterValues
, the key values from xLetterDict
.
Hide the redundant parts of axLettered
.
The vertical lines can be plotted using vlines!
with the same xLetterValues
.
One design puts the numerical axNumeric
x ticks at the top (Axis
option xaxisposition
= :top
), and the axLettered
x ticks at the bottom (default).
function makeBandStructureFigure_topBottom(xrange, xLetterDict, fs...)
xLetteredValues = collect(keys(xLetterDict))
xmin = min(minimum(xrange), minimum(xLetteredValues))
xmax = max(maximum(xrange), maximum(xLetteredValues))
xlimits = (xmin, xmax)
fig = Figure()
axNumeric = Axis(fig[1, 1],
title = "Band Structure [top & bottom axes]",
xaxisposition = :top, # <-- xaxisposition
xticks = xrange,
xtickformat = "{:.2f}",
xlabel = "x value",
ylabel = "Band Energy",
limits = (xlimits, nothing))
axLettered = Axis(fig[1, 1],
limits = (xlimits, nothing),
xaxisposition = :bottom,
xticks = xLetteredValues,
xtickformat = (xvalues -> [xLetterDict[x] for x in xvalues]),
xlabel = "Path in k-space")
hidespines!(axLettered)
hideydecorations!(axLettered)
vlines!(xLetteredValues, color = :black)
for f in fs
lines!(axNumeric, xmin..xmax, f)
end
fig
end
display(makeBandStructureFigure_topBottom(xrange1, xLetterDict1, f1_hi, f1_lo))
An alternative design puts both the numeric x-axis labels and the lettered x-axis labels at the bottom (default).
Offset labels of one Axis
using option xticklabelpad
so its x tick labels and axis label don't overlap with labels of the other Axis
.
function makeBandStructureFigure_bottomBottom(xrange, xLetterDict, fs...)
xLetteredValues = collect(keys(xLetterDict))
xmin = min(minimum(xrange), minimum(xLetteredValues))
xmax = max(maximum(xrange), maximum(xLetteredValues))
xlimits = (xmin, xmax)
fig = Figure()
axNumeric = Axis(fig[1, 1],
title = "Band Structure [bottom & bottom axes]",
xticks = xrange,
xtickformat = "{:.2f}",
xlabel = "x value",
ylabel = "Band Energy",
limits = (xlimits, nothing))
axLettered = Axis(fig[1, 1],
limits = (xlimits, nothing),
xticklabelpad = 50.0, # <-- xticklabelpad
xticks = xLetteredValues,
xtickformat = (xvalues -> [xLetterDict[x] for x in xvalues]),
xlabel = "Path in k-space")
hidespines!(axLettered)
hideydecorations!(axLettered)
vlines!(xLetteredValues, color = :black)
for f in fs
lines!(axNumeric, xmin..xmax, f)
end
fig
end
display(makeBandStructureFigure_bottomBottom(xrange1, xLetterDict1, f1_lo, f1_hi))
Upvotes: 1