GLMakie: figure does not change

Hi,

I do not manage to make my fig interactive, below a simplified version of my initial script.

Any idea what is missing?

using GLMakie

x_ = 0:0.01:8π
obs_ = [Observable(0.0) for s in 1:3]
function example_func(_x, _a, _b, _c)
   return _a.val .+ _b.val .* _x.^_c.val 
end

y_ = example_func(x_, obs_...)

fig = Figure()

sg = SliderGrid(fig[1, 2],
    (label = "a", range = 0.1:0.01:3, format = "{:.1f}", startvalue = 1),
    (label = "b", range = 0:0.01:10, format = "{:.1f}", startvalue = 1),
    (label = "c", range = 0:0.01:2, format = "{:0.1f}", startvalue = 1),
    tellheight = false,
)

sliderobservables = [s.value for s in sg.sliders]

for (_i, _oh) in enumerate(obs_)
    connect!(_oh, sliderobservables[_i])
end

ax1 = Axis(fig[1, 1], title = "Test", xlabel = "x", ylabel = "y", )

lines!(ax1, x_, y_, color = :indigo)

display(fig)

P.S.:
A nice collection of interactive plots can be found here:
Examples by garrekstemo
P.P.S.:
Under Linux below Julia v1.8.3 you might face difficulties to use GLMakie:

I saw this function lift() the concept is strange to me and I wonder if there is something around like a tutorial to understand this concept better.
I do not know if this is proper coding, but it works a least:

[...]
for (_i, _oh) in enumerate(obs_)
    connect!(_oh, sliderobservables[_i])
end
# --- new:
y_ = lift(sliderobservables...) do slvalues...
    example_func(x_, obs_...)
end

[...]

A good page to look at for the basics would be https://docs.makie.org/stable/documentation/nodes/index.html

This is how I would do it (I took the liberty of removing a lot of underscores because they were noisy to me).

using GLMakie

x = 0:0.01:8π
obs = Observable(zeros(3)) #Make the whole vector observable

#write your function as if it would not receive observables but a regular vector
function func(x, values) 
   return values[1] .+ values[2] .* x .^ values[3] 
end

#this is where the lift will listen to changes in the observable and apply the function
y = @lift func(x, $obs) 

fig = Figure()
ax1 = Axis(fig[1, 1])
lines!(ax1, x, y)

sg = SliderGrid(fig[1, 2],
    (label = "a", range = 0.1:0.01:3, startvalue = 1),
    (label = "b", range = 0:0.01:10, startvalue = 1),
    (label = "c", range = 0:0.01:2, startvalue = 1),
    tellheight = false,
)

sliderobservables = [s.value for s in sg.sliders]

#Here I connect each slider to the value inside obs and I use notify to trigger "lift" you can simplify it using map or a comprehension but I do it explicitly for clarity
on(sliderobservables[1]) do sl
        obs[][1] = sl[]
        notify(obs)
end

on(sliderobservables[2]) do sl
       obs[][2] = sl[]
       notify(obs)
end

on(sliderobservables[3]) do sl
       obs[][3] = sl[]
       notify(obs)
end

display(fig) #running in the REPL this line is not needed, but let's leave it for completeness
1 Like

Thanks a lot!!! :slight_smile:
Step by step I become more familiar with the concept of Observable structures.