How to automatically choose legend location in Makie?

When I plot a series with Makie and label it, how do I get axislegend to automatically pick the empty part of the axis to place the legend in to? Example: (don’t worry about the data source lol)

Best explored in a Julia REPL or an interactive session

using CairoMakie

x = [
    0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3,
    3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, 6.1, 6.2, 6.3,
    6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9.0, 9.1,
]

y = [
    NaN, 0.0429089737491369, 0.10264903115083439, 0.0947777814294252, 0.0338277977476063, 0.03174121198969, 0.03635105144486207, 0.03978537080576214, 0.04046699021588537, 0.0412114876081603, 0.04319992729537861, 0.047075466839262954, 0.05131356002183631, 0.054075421907765195, 0.05494064442696345, 0.05522113901611183,
    0.0545425783674207, 0.053337326355401504, 0.053955238010355705, 0.05361125520368727, 0.053835496133942236, 0.05355467706356569, 0.05420182434727196, 0.054824149894319114, 0.05561180236049295, 0.05604520368951108, 0.05696506714638169, 0.05777955130155306, 0.058152676029887364, 0.05830765126032878, 0.05807693543178287,
    0.057956142242877214, 0.058417102692983953, 0.05941577009935072, 0.06213862703222151, 0.06394819091335811, 0.06430757550020112, 0.06396330812044938, 0.06364797247277251, 0.06444432433951856, 0.06612602361444533, 0.06674719965040146, 0.06663497415958049, 0.06651114762672354, 0.0677709835257091, 0.06910617890411844,
    0.06916322518500292, 0.06858061917815957, 0.06887476660829213, 0.07034755694303292, 0.07160496055559556, 0.0719943878296249, 0.07251013980137015, 0.07316880248230188, 0.07535219914259361, 0.07895575424150675, 0.08190481515216726, 0.0841501909525944, 0.087111284064865, 0.09262652606093782, 0.10198570164602906,
    0.11407621031241988, 0.12787899039271325, 0.1395963748046922, 0.15027238139221732, 0.16861242635799975, 0.19141131550878965, 0.22991581881877568, 0.26987775088184257, 0.3989823619456098, 0.5173832829870192, 0.7014131365240662, 0.730236402997345, 0.7637231954332452, 0.9406621308584271, 1.0269919264161609,
    1.205219232605864, 2.132652139555734, 2.231610024175371, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN,
]

fig, ax, _ = lines(x, y, label = "data")
axislegend(framevisible = false) # problem better shown with framevisible = false
fig


fig, ax, _ = lines(x, y, label = "data", axis = (; yscale = log10))
axislegend(framevisible = false) # problem better shown with framevisible = false
fig

For the two figures, Makie places the legend box in the top-right, where if I hadn’t specified framevisible, it would have obscured the last few points. I know I can pass in position = :ct or something to that effect, but how do I get Makie to figure out where to place the legend (still inside the axis)? This is especially necessary when different plots take up different corners of the axis.

I’m attaching the two plots I got from the above example where we can clearly see the plot and the legend overlapping


Hmm, I don’t think we have auto legend placement yet but it sounds like something we should add. The main effort is probably in determining which areas of the plot are “filled” since it’s pointless to take the bounding box of each plot.

My first inclination is that one could perform some form of “rasterization” for each plot onto a coarse grid, then find an area on that grid that is relatively empty. Not sure how other libraries do it though so there might be something to learn from there.

3 Likes

Ask Claude to do it for you. I did that for GMT and it told me that mapplotlib has that for the option loc='best'. It works fine. Made a couple of cleanings and and it now only adds 100 kB to the cache (before it added 0.5 MB)

1 Like

Here is how Plots does it:

Basically it sums a penalty for data in each quadrant where the legend might be placed.

It works relatively well:

1 Like

Claude’s creation does this

plot(mat2ds([[0. 0; 1 1], [1.0 0; 0 1]]), legend=(label="colnames", pos=:auto), show=true)

There is now an associated issue on the Makie.jl repository at #5554: Automatic legend placement by `axislegend()` · Issue #5554 · MakieOrg/Makie.jl · GitHub

1 Like