Figure title for a faceted plot in AlgebraOfGraphics

I can’t seem to get an overall figure title for a faceted plot in AlgebraOfGraphics:

using CairoMakie
using AlgebraOfGraphics
using DataFrames

df = DataFrame(
    x = randn(100),
    y = randn(100),
    g = rand(["a", "b", "c", "d"], 100)
)

plt = data(df) * mapping(:x, :y, layout = :g)

Both of the following make a figure with no overall title:

draw(plt; axis = (; title = "hello world"))
draw(plt; figure = (; title = "hello world"))

Does anyone know how to do this?

1 Like

Mmm, not an expert in AoG, but I would use this:
http://juliaplots.org/AlgebraOfGraphics.jl/dev/generated/gallery/#Embedding-facets

with something like

ax = Axis(fig[0, 1:end], title="Figure title")
1 Like

I’ve done this before

title = Label(aog_object.figure, titletext, textsize=42, tellwidth=false)
aog_object.figure[0, 1:end] = title
3 Likes

There’s currently nothing like a dedicated super title because it’s not clear how exactly that should work for all possible cases. The suggested solutions with manually placed labels are very flexible. Sometimes it can be a bit annoying to find out which indices to place the label at

2 Likes

Thanks! I think I’ll go with @jzr’s approach. For completeness, here’s the full MWE:

using CairoMakie
using AlgebraOfGraphics
using DataFrames

set_aog_theme!()

df = DataFrame(
    x = randn(100),
    y = randn(100),
    g = rand(["a", "b", "c", "d"], 100)
)

layer = data(df) * mapping(:x, :y, layout = :g)

plt = draw(layer)
plt.figure[0, :] = Label(plt.figure, "Hello World!", textsize=20)
2 Likes

You can just do Label(plot.figure[row, col],...)

Does that mutate the figure object? I’m a bit befuddled by the way Makie mutates some of the plot objects that are arguments to constructors, with no exclamation point to signal the mutation… But maybe I’m misunderstanding something—I haven’t studied Makie in depth yet.

1 Like

Every layoutable has to mutate the figure if it’s placed in it, there’s no ! version because there is no alternative non mutating version. The syntax I just used just combines adding the object to the figure and putting it in a specific layout position, which your syntax splits in two

1 Like

Ok. It just feels a bit odd to me. With this syntax, it’s clear that you are mutating the figure object:

plt.figure[0, :] = Label(plt.figure, "Hello World!", textsize=20)

But with your syntax,

Label(plot.figure[row, col],...)

it feels a bit like magical manipulation of global state, like the way that plotting works in Matlab.

In fact, I wonder why we can’t just do this:

# No figure first argument to Label:
plt.figure[0, :] = Label("Hello World!", textsize=20)

It seems like I ought to be able to make a Label object that is independent of any Figure, and then insert it into any figure that I care to use it in.

That’s not possible with the current architecture as the label’s underlying text object can’t exist without a scene to be plotted into.

Indexing into a figure creates a FigurePosition object, and giving that as the first argument for a layoutable just does both the adding to the figure and adding to the layout. It’s nice because it works with nested layouts as well so you can pass nested figure positions to functions creating custom sublayouts and it usually just works.

3 Likes