Avoid repeating tick labels with subplots in Plots.jl

I’m making grids of subplots in Plots.jl by composing several plots together:

using Plots
default(legend=false, tickfont=font(12))
x = -6:0.1:6
plots = map(f -> plot(x, f(x), title=string(f), tickfont=font(12)), [sin, cos, sinh, cosh])
plotgrid = plot(plots..., layout=grid(2,2), link=:both)

Now I’d like to remove unnecessary tick labels: because both axes are linked, there’s some unnecessary duplication.

let none = Int[]
  xticks!(plots[1], none)
  xticks!(plots[2], none)
  yticks!(plots[2], none)
  yticks!(plots[4], none)
  plotgrid
end

But this has the side effect of 1) misaligning the subplots and 2) removing the grid lines.

Has anyone had success doing this sort of thing?

2 Likes

On master this will work:

julia> using Plots; funcs=[sin,cos,sinh,cosh];

julia> p = plot(funcs,-6,6,link=:both,layout=4,title=reshape(map(string,funcs),1,4),leg=false)

julia> for i=1:2; plot!(p[i],xformatter=_->""); plot!(p[2i],yformatter=_->""); end; p

I set the formatter to always return an empty string, so that the ticks will still be there (so the grid lines will be drawn). If you don’t care about the grid, you can also set xticks=nothing.

6 Likes

That’s perfect - I was using dev at the time, which had an issue that I see you have already fixed. Didn’t know about xformatter and yformatter but they will be very useful. Amazing work as usual. Thanks!

1 Like

I’ve noticed that the misalignment persists if you build a plot from pre-existing ones rather than doing it all at once.

Your method:

julia> using Plots; funcs=[sin, cos, sinh, cosh];

julia> p = plot(funcs, -6, 6, layout=4, link=:both)

julia> for i=1:2; plot!(p[i],xformatter=_->""); plot!(p[2i],yformatter=_->""); end; p

Making the plots individually first:

julia> using Plots; funcs=[sin, cos, sinh, cosh];

julia> plots = map(f -> plot(f, -6, 6), funcs); p = plot(plots..., layout=4, link=:both)

julia> for i=1:2; plot!(p[i],xformatter=_->""); plot!(p[2i],yformatter=_->""); end; p

The reason for this is subtle, and hard to fix generically. When you build a plot from existing subplots, there is an extra layer of layout. Specifically, there’s a 2x2 grid layout where each cell contains a 1x1 grid layout. I guess the alignment logic isn’t passing through multiple recursive layers in the way you would hope.

Ideally the fix would come from within Plots, but since my time is limited, you’ll have to fix it yourself. There’s another way to do this if you want to define each plot individually:

p = plot(layout=4, link=:both, leg=false)
for (i,f) in enumerate(funcs)
    plot!(p[i], f, -6, 6, title=string(f))
end
p

This builds the layout but doesn’t add any series initially. Then you can add to a specific subplot by indexing into the Plot object. Note: you could also do p[row,column] in this case to get a specific subplot.

1 Like