Interactive Menu with AlgebraOfGraphics / GLMakie

Hello,
I am trying to have an interactive AlgebraofGraphics plot, e.g. with a menu to select which variable is plotted.
A MWE is

x1=rand(50)
y1=10x1.^2
y2=x1 .+ randn(50)
df = DataFrame((;x1, y1, y2))

var=Observable("y1")

fig = @lift((data(df) * 
    mapping(:x1, Symbol($var), color=:x1) * 
    (visual(Scatter) +  smooth(;span=0.3, degree=1)) |> draw).figure)

menu = Menu(fig[], options = ["y1","y2"] , default = "y1")
fig[][1, 3] = vgrid!(
        Label(fig[], "Variable", width = nothing),
        menu,
        tellheight = false, width = 200)
    
 on(menu.selection) do s
         var[] = s
end

@lift(display($fig))

It is kind of clear that it cannot work, because with fig[] I destroy the observable, but the example shows what I want (it does display the initial figure and also updates, but the menu gets lost).

Is there is a GLMakie expert to help…?

This comes closer, but now I don’t know how to delete the previous plot (and if I am roughly doing the right thing):

var=Observable("y1")
fig=Figure()
axentry = draw!(fig[1,1:1], data(df) * 
    mapping(:x1, Symbol(var[]), color=:x1) * 
    (visual(Scatter) +  smooth(;span=0.3, degree=1)))
Colorbar(fig[:, 2])

menu = Menu(fig, options = ["y1","y2"] , default = "y1")
fig[2,1] = hgrid!(
        Label(fig, "Variable", width = nothing),
        menu,
        tellheight = true)
    
 on(menu.selection) do s
         var[] = s
         draw!(fig[1,1], data(df) * 
    mapping(:x1, Symbol(s), color=:x1) * 
    (visual(Scatter) +  smooth(;span=0.3, degree=1)))
end

You don’t have to @lift the figure or redraw it (not sure if this is an AlgebraOfGraphics thing. I only use GLMakie for interactivity so far). I would make the x data Observable and then @lift the y data (Note you need to use a $ in front of the x variable). The magic of Makie and Observables is that you can just use regular GLMakie functions and put Observables as x and y and Makie will automatically draw the new plot when any Observable changes (you can even change attributes like the xlabel and ylabel. Here’s how I would do it:

using GLMakie

x1 = Observable(rand(50))
y_current = @lift(10 .* $x1.^2)

y1 = @lift(10 .* $x1.^2)
y2 = @lift($x1 .+ randn(50))

ys = [y1, y2]

fig = Figure()
display(fig)
ax = Axis(fig[1, 1], xlabel = "x1", ylabel = "y1")
scatter!(ax, x1, y_current)

menu = Menu(fig, options = ["y1","y2"] , default = "y1")
fig[1, 2] = vgrid!(
        Label(fig, "Variable", width = nothing),
        menu,
        tellheight = false, width = 200)
    
 on(menu.selection) do _
    i = to_value(menu.i_selected)
    y_current[] = to_value(ys[i])
end

I’m working on a small set of interactive examples. I don’t have any menu examples right now, but maybe this will give you some ideas:

Thanks @garrek,
yes I know I can do it like that directly in GLMakie, but I wanted to take advantage of AlgebraOfGraphics, where it seems one cannot make “inner parameters” an Observable, cf. Update xlims in interactive GLMakie - #3 by mreichMPI-BGC

So, I am still wondering how it can be done in AoG…

I don’t think AlgebraOfGraphics sets up observables such that you can change the inputs and expect the whole Figure to change. For example, this would also entail Axes appearing and disappearing if you have facetting, which is not that easy to implement compared to changing a plot’s color or data.

Ok, yet with my post Interactive Menu with AlgebraOfGraphics / GLMakie - #2 by mreichMPI-BGC I was close. If I knew how to delete the previous plot just before the draw! statement in the on block, it would be ok. I believe it should be possible, but some intuitive things did not work.

You could try this on the Axis:

So, empty!(ax.blockscene) and delete!(ax)

This one works, if you are only using 1 Axis

using AlgebraOfGraphics, GLMakie
using DataFrames

x1=rand(50)
y1=10x1.^2
y2=x1 .+ randn(50)
df = DataFrame((;x1, y1, y2))

var=Observable("y1")
fig=Figure()

axentry = draw!(fig[1,1:1], data(df) * 
    mapping(:x1, Symbol(var[]), color=:x1) * 
    (visual(Scatter) +  smooth(;span=0.3, degree=1)))
Colorbar(fig[:, 2])

menu = Menu(fig, options = ["y1","y2"] , default = "y1")
fig[2,1] = hgrid!(
        Label(fig, "Variable", width = nothing),
        menu,
        tellheight = true)
    
 on(menu.selection) do s
         var[] = s
         Makie.delete!(fig.current_axis[])
         draw!(fig[1,1], data(df) * 
    mapping(:x1, Symbol(s), color=:x1) * 
    (visual(Scatter) +  smooth(;span=0.3, degree=1)))
end
fig

For more complicated layouts we will need a list of all Axis plotted. @jules how do we get the axis being plotted at fig[1,1]) ?

1 Like

https://docs.makie.org/stable/documentation/figure/#retrieving_objects_from_a_figure

I think I even tried that, but I don’t get it deleted :frowning:

Restarted, updated: It works now. Thanks!

Before, the plot was nominally deleted (nothing), but still dangled in the window (but did not resize)

yes, this works with a simpler workflow. But, what if is more nested, i.e., a GridLayout? which is the case here:

contents(fig[1,1])
1-element Vector{Any}:
 GridLayout[1, 1] (1 children)

Then you continue into the GridLayout and delete everything there as well.

:smile: I tried, but without being able to find the actual axis :laughing:

AlgebraOfGraphics nests these things, but not so far that you shouldn’t be able to find them :wink:

Ah I see. Sorry I misunderstood.