This is actually more tricky than you might think at first. The reason why your top-right axis is smaller is that the other two both need to include the width of the y-axis decorations of the lower axes. The Box doesn’t have that. The space in the layout is distributed equally between the elements only based on the inner size of the objects. The thing is that you conflate inner area of the top-row elements with outer area of the bottom-row elements. Actually all columns have the same size:
fig = Figure(resolution = (300, 200), fontsize = 12, figure_padding = 2)
Axis(fig[1,1:2])
Axis(fig[1,3:4])
Axis(fig[1,5:6])
Axis(fig[2,2:3])
Axis(fig[2,4:5])
Box( fig[2,6])
colgap!(fig.layout, Relative(0.02))
for i in 1:6
Box(fig[:, i], color = (:red, 0.2), strokewidth = 0)
end
fig
So the intuition to put the lower row into a nested GridLayout is good, but then the two layouts don’t know anything about each other and therefore the automatic distribution of column widths is uneven.
This kind of “shifted” layout where you as a human know about some relationship between widths is not easy to represent for an automatic grid-based algorithm. But you can help out with your knowledge. If you’re sure that the legend will be less wide than one of the three subplots in the upper row, you can be sure that if you manually set the lower two axes to the width of the upper ones, the lower row will still fit. You can get the current inner size of an axis by looking at the px_area
Observable of its Scene
(the inner plot area). That is of course a bit of internal knowledge and might break later, but for custom plotting it’s always good to know your way around the internals a bit.
So here I derive the width setting for the lower two axes by the px_area of the top-left axis (all three are the same anyway). I give the legend box a fixed width as that simulates the legend better. The lower row can be put into a separate GridLayout so the columns are free relative to row 1. The lower GridLayout will be fixed in width if the two axes and the legend have known width, so it will center itself in the available space by default. You can set halign
on it to :left
or :right
if you like that better.
fig = Figure(resolution = (300, 200), fontsize = 12, figure_padding = 6)
ax1 = Axis(fig[1,1])
Axis(fig[1,2])
Axis(fig[1,3])
# create a width observable from the first axis' inner area
w = @lift widths($(ax1.scene.px_area))[1]
subgl = GridLayout(fig[2, :])
Axis(subgl[1, 1], width = w)
Axis(subgl[1, 2], width = w)
Box(subgl[1, 3], width = 30)
colgap!(fig.layout, 5)
rowgap!(fig.layout, 10)
colgap!(subgl, 5)
fig