Makie interaction: Slider with animation

(Edited for clarity in the light of feedback (thanks, yakir12) about how to post on this forum)

I’m struggling to figure out how to use a slider to interact with an animation in Makie.

I’m using v1.1.1 in Atom under Win10. The code below is MWE using animation. The hexagons move across the plot while dot changes color from blue to yellow with random probability proportional to the height of the second hexagon.

I want to control the x-position of the hexagons using the slider, and have the dot continue to change color randomly even if the slider is not sliding. I’ve looked at the slider examples in the Makie gallery but can’t figure out how to generalize to my problem. Also can’t find documentation about e.g. RecordEvents (what is the string in the second argument? It seems to be essential but what is it for?).

using Makie
using AbstractPlotting
using Colors


x₀ =-5.
gateState = false
xRange =  10

#  deflection
p₀(x) = x/2

# plot
nPts = 100.
x = (x₀ .+ collect((-nPts/2.):(nPts/2.))/nPts*xRange)
scene = lines(x,  p₀(x),
             linewidth =4,
             color = :darkcyan,
             leg = false
        )
axis = scene[Axis]
 axis[:names][:axisnames] =
 ( "x","y")


HC_handle = scatter!([-4], [2], marker=:circle,
          markersize = .5, color = :red)[end]

s1 = slider(LinRange(-5.0, 5.0, 101),
      raw = true, camera = campixel!, start = -5.0)

kx = s1[end][:value]

scatter!(scene, [kx[]; kx[]],[0.5; p₀(kx[])], marker = :hexagon,
    color = RGBA(.5,0.,.5,.5),
    markersize = .35, strokewidth = 1, strokecolor = :black)
Kc_handle = scene[end]

record(hbox(scene, s1, parent = Scene(resolution = (800, 600))),
   "gate.mp4", 1:200) do i
    Δx = x₀ + 0.05*i
    p = p₀(Δx)
    gateState = rand(1)[]<(p + 2.5)/5
    HC_handle[:color] = gateState ? :gold1 : :dodgerblue1
    Kc_handle[1] = [Δx, Δx]
    Kc_handle[2] = [0, p]
end

start with this:

1 Like

You use the signal from the slider without lifting it. A fix would be:

using Makie
using AbstractPlotting
using Colors

x₀=-5.
gateState = false
xRange = 10

p₀(x) = x/2

nPts = 100.
x = (x₀ .+ collect((-nPts/2.):(nPts/2.))/nPts*xRange)
scene = lines(x, p₀(x),
    linewidth =4,
    color = :darkcyan,
    leg = false
)
axis = scene[Axis]
axis[:names][:axisnames] = ("x","y")

HC_handle = scatter!([-4], [2], marker=:circle, markersize = .5, color = :red)[end]

s1 = slider(LinRange(-5.0, 5.0, 101), raw = true, camera = campixel!, start = -5.0)

kx = s1[end][:value]

scatter!(
    scene, [kx; kx], lift(x-> [0.5; p₀(x)], kx), marker = :hexagon,
    color = RGBA(.5,0.,.5,.5),
    markersize = .35, strokewidth = 1, strokecolor = :black
)
Kc_handle = scene[end]
hbox(scene, s1, parent = Scene(resolution = (800, 600)))

Please make sure that your example runs (e.g. xScale was undefined, and I had to edit out Plot / deflection, correct x00 to x₀). To get help, it really helps if I can simply copy and paste your code and don’t need to waste any time to get it to run!

2 Likes

Thanks. I appreciate the advice.

2 Likes

Thanks, sdanish, I appreciate you taking the time to help.

I edited my code as you suggested, using lift() to specify the x- and y- coordinates of the hexagons,

scatter!(scene, lift(x->[x; x],kx), lift(x-> [0.5; p₀(x)], kx), marker = :hexagon,
    color = RGBA(.5,0.,.5,.5),
    markersize = .35, strokewidth = 1, strokecolor = :black)
Kc_handle = scene[end]

hbox(scene, s1, parent = Scene(resolution = (800, 600)))

Now the hexagons are correctly controlled by the slider.

My problem is how to do this while running an animation? I don’t want to generate a movie file (although in future I might), but I want other things changing in the scene even when the slider is not sliding. In the MWE I have the dot randomly changing colour in a way that depends on the slider value. (How) can this be done?

Thanks.

That should just work like this:

while isopen(scene)
 #animate any parameter
 ...
 yield() # yield to render loop
end

If you want to keep interacting with the REPL/Atom, you can just prefix the while loop with @async

Btw, kx is a signal, and the value can be extracted like this in the loop:

kx[]

Thank you!
I just filled in the Julia user survey. For me the best thing about Julia (apart from Julia) is the community of smart people who are super-helpful. The worst thing is the difficultly in finding documentation, and examples that work in v1.1.1. Do you have any advice about learning Makie without bothering the experts every time I get stuck?

Well, besides http://juliaplots.org/MakieGallery.jl/stable/ and the examples in the gallery, there isn’t that much right now you can consult besides Discourse and the Julia slack!

Working demo of animation with slider control, to help the next newbie who gets stuck in this place:

using Makie
using AbstractPlotting
using Colors

x₀ =-5.
#gateState = false
xRange =  10

#  deflection
p₀(x) = x/2

# plot
nPts = 100.
x = (x₀ .+ collect((-nPts/2.):(nPts/2.))/nPts*xRange)
scene = lines(x,  p₀(x),
             linewidth =4,
             color = :darkcyan,
             leg = false
        )
axis = scene[Axis]
axis[:names][:axisnames] =  ( "x","y")

D = Node(x₀)
HC_handle = scatter!(lift(x->[x],  D), [2], marker=:circle,
          markersize = 1., color = :red)[end]

s1 = slider(LinRange(-10.0, 0.0, 101),
      raw = true, camera = campixel!, start = -10.0)
kx = s1[end][:value]

scatter!(scene, lift(x->[x; x],kx), lift(x-> [0.5; p₀(x)], kx),
    marker = :hexagon,  color = RGBA(.5,0.,.5,.5),
    markersize = .35, strokewidth = 1, strokecolor = :black)

S = hbox(scene, s1, parent = Scene(resolution = (800, 600)))
display(S) 

@async while isopen(S)
  p = p₀((10.0+kx[])/10.)
  gateState = rand(1)[]<p
  HC_handle[:color] = gateState ? :gold1 : :dodgerblue1
  push!(D, -3. + rand(1)[]/5.)
  yield()
end

RecordEvents(S, "output");
3 Likes

I’m getting an InexactError: trunc(Int64, Inf) when I try to run this. Will need some time to debug, and possibly try to get a better error message for this…

Edit: It looks like src/layouting.jl#L215 is the problem.