Mstislav Keldysh
Mstislav Keldysh

Reputation: 71

Labelling individual ticks on axes Julia with Cairo Makie

I am trying to plot a graph using cairo makie and want to have points on the x-axis labeled with letters.

So something like this: enter image description here

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

Answers (1)

user9712582
user9712582

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.

Example: data and functions to 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))

CairoMakie symbols used:

using CairoMakie: Figure, Axis, hidespines!, hideydecorations!, vlines!, :.., lines!

General Approach for both designs below

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.

Top and bottom

One design puts the numerical axNumeric x ticks at the top (Axis option xaxisposition = :top), and the axLettered x ticks at the bottom (default).

plot with numeric x-axis ticks on top and lettered x-axis ticks on bottom

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))

Bottom and bottom

An alternative design puts both the numeric x-axis labels and the lettered x-axis labels at the bottom (default).

plot with both x-axis tick labels on bottom, numeric above letters

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

Related Questions