Bottom horizontal legend

layer = let
n = 100
df = (;
        x=rand(n),
        y=rand(n),
        c=rand(["a", "b", "c"], n),
    )
d = data(df)
m = mapping(:x, :y, color=:c)
v = visual(Lines)
d * m * v
end

grid = draw(layer)
leg = only(x for x in contents(grid.figure.layout) if x isa Legend)
leg.orientation = :horizontal
grid.figure.layout[2,1] = leg
leg.tellwidth = false
grid

  • How can I fix the plot width?
  • Is there a way to build this horizontal bottom legend declaratively without all this stuff:
leg = only(x for x in contents(grid.figure.layout) if x isa Legend)
leg.orientation = :horizontal
grid.figure.layout[2,1] = leg

?

I guess for this simple case, AlgebraOfGraphics should just offer a horizontal legend switch. I like it a lot that you can pull out the legend, move it, and restyle it, but of course that adds some code that you don’t want to write everytime.

Regarding the spacing question, that exact case is talked about in the layout tutorial https://makie.juliaplots.org/stable/makielayout/tutorial.html#Fixing-spacing-issues

You can trim away the now empty space and make the legend adjust its own row height down.

1 Like

So at the moment draw does the plot call, adds facet styling, adds the legend and tries to “resize figure to fit”. I was planning to keep the draw interface reasonably simple, and if one wants more you would simply do these steps by hand and customize via Makie directly. (I hadn’t thought about moving it after having drawn it and did not know it was possible.)

That being said, horizontal legend may be of sufficiently general interest that one can just add a switch to draw directly.

I wonder if it would make sense to have a whole AoG algebraic function for configuring a legend. Legends are pretty flexible and underused for conveying semantics imo.

As a service for future readers:

Customizing the legend has been simplified a few releases ago. You can use the legend keyword in draw. (see also Legend tweaking · Algebra of Graphics)

begin
	fig = Figure()
	
	df = (
	    x=rand(500),
	    y=rand(500),
	    k=rand(["a", "b", "c"], 500),
	    l=rand(["d", "e", "f"], 500),
	)
	plt = data(df) * mapping(:x, :y, color=:k, marker=:l) * visual(Scatter)
	
	draw(plt, legend = (position = :bottom, titleposition = :left))
end