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
garrek
February 2, 2023, 1:27am
3
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 Observable
s is that you can just use regular GLMakie functions and put Observable
s 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
garrek
February 2, 2023, 1:28am
4
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:
Interactive plot examples using GLMakie, the GPU-powered Julia plotting package - GitHub - garrekstemo/InteractivePlotExamples.jl: Interactive plot examples using GLMakie, the GPU-powered Julia plo...
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…
jules
February 2, 2023, 6:53am
6
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.
jules
February 2, 2023, 2:23pm
8
You could try this on the Axis:
This should work for clearing plots:
for c in contents(menugrid[end, :])
# clean up plots and some observables
empty!(c.blockscene)
delete!(c)
end
trim!(menugrid)
I’m not sure how complete the observable cleanup is with this. I wouldn’t be surprised if this leaves behind some ghost interactions, like an invisible button you can still press. If that is the case it would be good to open an issue for this.
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
I think I even tried that, but I don’t get it deleted
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)
jules
February 2, 2023, 5:17pm
13
Then you continue into the GridLayout and delete everything there as well.
I tried, but without being able to find the actual axis
jules
February 2, 2023, 5:40pm
15
AlgebraOfGraphics nests these things, but not so far that you shouldn’t be able to find them
garrek
February 2, 2023, 5:53pm
16
Ah I see. Sorry I misunderstood.