Makie: Calculation on Observables?

I have a relatively complicated function to produce values and a relatively complicated function to plot the values. The combination already works to produce a still image.

Now, I want to produce an animation changing a parameter, say time t. Both functions depend on t. Both functions include some arithmetics on t.

When I turn this program into one using Observables as below, the complier complains that some functions I use aren’t defined on Observable{Float64}, which the new t is.

The following is a much simplified toy program that (I hope correctly) duplicates my problem. Below, the function single() succeeds in producing the still image but anime() fails for the reason stated above.

How should I proceed? I’m stuck because I don’t understand Observables after all.

"Returns a vector"
function func(t, xs)
  sin.(t/100.0 .+ xs)
end

function plot_func(xs, fs; t)
  lab = "$(t/(24*60*60)) days"
  fig = Figure()
  ax = Axis(fig[1,1]; title = lab)
  lines!(ax, xs, fs)
  return fig
end

function single() # -> Works
  xs = -5.0:(5/32):5.0
  t = 0.0
  fs = func.(t, xs)
  fig = plot_func(xs, fs; t = t)
  display(fig)
end

# Fails because Observable{Float64} cannot be used in calculations
function anime()
  xs = -5.0:(5/32):5.0
  t = Observable(0.0) # -> t/100.0 fails?
  fs = Observable(func.(t, xs))
  fig = plot_func(xs, fs; t = t)
  nrange = 0:20
  record(fig, "tmp.mp4", nrange; framerate=2) do n
    t.val  = 40.0*n
    fs[] = func.(t, xs)
  end
end

single()
anime() # -> fails

To operate on the value of an Observable, you need to use map or @lift to unwrap it, use the value, and create a new observable. There is no need to explicitly evaluate fs inside the animation, setting t pushes the update through.

using GLMakie

"Returns a vector"
function func(t, xs)
  sin.(t/100.0 .+ xs)
end

function plot_func(xs, fs; t)
   lab = map(t) do t
       "$(t/(24*60*60)) days"
   end
  fig = Figure()
  ax = Axis(fig[1,1]; title = lab)
  lines!(ax, xs, fs)
  return fig
end

function single() # -> Works
  xs = -5.0:(5/32):5.0
  t = 0.0
  fs = func.(t, xs)
  fig = plot_func(xs, fs; t )
  display(fig)
end

function anime()
  xs = -5.0:(5/32):5.0
  t = Observable(0.0)
  fs = @lift( func.($t, xs) )
  fig = plot_func(xs, fs; t)
  nrange = 0:20
  record(fig, "tmp.mp4", nrange; framerate=2) do n
      t[]  = 40.0*n
  end
end

single()
anime()