Search code examples
juliainteractivemakie.jl

how to create interactive slider in Julia in Makie


I want to create a topoplot with slider regulating time of topoplot.

In minimum scenario - just print the value on slider, in maximum - plot the topoplot at that time.

I find this tutorial for sliders in Makie. https://www.youtube.com/watch?v=odpoatozNz8&ab_channel=doggodotjl Code in video works perfectly. But it doesn't work with my plot. enter image description here Here is my code:

let 
    t = 100 # @lift($time)
eeg_topoplot(mean(dat_e[1:30, t, :], dims=2)[:,1], # averaging all trial of 30 participants on 100th msec
raw.ch_names[1:30]; 
positions=pos, # produced  automatically from ch_names
label_text=true,
axis=(aspect=DataAspect(),)) # aspect ratio, correlation of height and width

fig = current_figure()
xs = range(-30, 120, length = size(dat_e, 2))

lsgrid = labelslidergrid!(fig,
["time"],
Ref(LinRange(xs));
formats = [x -> "$(round(x, digits =0))"],
labelkw = Dict([(:textsize, 20)]),
sliderkw = Dict([(:linewidth, 20)]),
valuekw = Dict([(:textsize, 20)])
)

# set starting position for slope
set_close_to!(lsgrid.sliders[1], 120)

# layout sliders, put slider under the field

sl_sublayout = GridLayout(height = 80)
fig[2, 1] = sl_sublayout
fig[2, 1] = lsgrid.layout

# create listener
time = lsgrid.sliders[1].value
y = @lift($time .* 0 .+ $time)

#t = time
# add text
text!(0.5, -0.2,  text = "[" .* string.(y).* " ms]", align = (:center, :center))

hidedecorations!(current_axis())
hidespines!(current_axis()) 
fig

end

Code is awful by now, for instance you can ask why you have y = @lift($time .* 0 .+ $time)? That's because of this problem, which is currently not my goal.

LoadError: You can't @lift an expression that only consists of a single 
observable.

My current pain is this problem:

MethodError: no method matching length(::Observable{Float64})
Closest candidates are:
length(!Matched::Union{Base.KeySet, Base.ValueIterator}) at abstractdict.jl:58
robin_dict.jl:86

This code works with array, I understand that. But what should I do if I want to get just one single value that is currently on slider and put it as text or in function?


Solution

  • Does this example help?

    T = 10
    
    pts = range(-1, 1, length=100)
    ts = reshape(1:T, 1, 1, :)
    topo = cos.(pts) .+ cos.(ts .* pts')
    
    fig = Figure()
    ax = Axis(fig[1, 1])
    
    sg = SliderGrid(fig[2,1],
        (label="time", range=1:T))
    
    time = sg.sliders[1].value
    
    str = lift(t -> "[$t ms]", time)
    text!(ax, str)
    
    topo_slice = lift((t, data) -> data[:, :, t], time, topo)
    contour!(ax, topo_slice)
    
    hidedecorations!(ax)
    hidespines!(ax) 
    fig