Can I align all vertical axes in a multi-row faceted plot done with Plots.jl?

This is a really interesting discussion, and it made me start looking for out-of-the box solutions that might be floating around already. I see that @rafael.guerra also has a similar post using StatsPlots.jl, but I guess the problem there is that some extra work would still need to be done to hide shared axis decorations and switch from an auto generated legend to a title? Trying it out on the above still gets us pretty far I think:

using Plots, DataFrames, Dates

dfd = DataFrame(
    Date = (today() + Day(1)) : Day(1) : (today() + Day(60)),
    Return = randn(60) / 100.0,
    A = repeat(1:5; inner=12),
    B = repeat(1:12; inner=5),
)

@df dfd Plots.plot(:Date, :Return;
    group = {B = :B},
    layout = 12,
    size = (1_000, 700),
    rotation = 45,
    xtickfontsize = 6,
    ytickfontsize = 6,
    plot_title = "Hello",
    ylims = extrema(:Return),
)

This made me curious if AlgebraOfGraphics could get us the rest of the way there, but it looks like there are a couple of trade-offs, IIUC:

using CairoMakie, AlgebraOfGraphics

plt = data(dfd) * mapping(:Date, :Return;
    layout = :B => nonnumeric,
) *
visual(Lines)

fg = draw(plt;
    figure = (; resolution = (1_000, 700)),
    axis = (;
        xticklabelrotation = π/4,
        yticklabelrotation = π/4,
        xticks = datetimeticks(identity, dfd.Date),   
        xticklabelsize = 10,
        yticklabelsize = 10,
    ),
    facet = (; linkxaxes=:none),
)

Label(fg.figure[0, :], "Hello";
    textsize = 28,
    font = AlgebraOfGraphics.firasans("Medium"),
)

fg

A few of the benefits include computing the number of subplots we need automatically, hiding shared axis decorations, handling the global data limits, and applying common axis labels. The remaining downsides I am seeing are that we need to manually specify the xticks with a helper function for now, and stick to numerical facet labels to get the ordering right (i.e., doing something like layout = :B => (x -> "B = $x") would change the ordering according to sort(string.(1:12)), instead of following the natural sorting via something like NaturalSort.jl). I could be misunderstanding some of the more technical points here, so maybe @piever might have a better solution?

Anyway, I’m realizing that this thread was originally about Plots.jl, so I’d be happy to split this discussion off if that would be better

1 Like