# How to Call Function to Create Animation in GLMakie

**URL:** <https://discourse.julialang.org/t/how-to-call-function-to-create-animation-in-glmakie/99938>\
**Category:** General Usage\
**Tags:** question\
**Created:** [June 6, 2023, 1:13pm UTC](https://discourse.julialang.org/t/how-to-call-function-to-create-animation-in-glmakie/99938 "2023-06-06T13:13:43Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Freya\_the\_Goddess](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/freya_the_goddess/32/36835_2.png) [@Freya\_the\_Goddess](https://discourse.julialang.org/u/Freya_the_Goddess)\
**Post date:** [June 6, 2023, 1:13pm UTC](https://discourse.julialang.org/t/how-to-call-function-to-create-animation-in-glmakie/99938/1 "2023-06-06T13:13:43Z")

</div>

Hi all,

I have a question, I don’t know how to call function so it can create the animation, I get the code here:

> <https://stackoverflow.com/questions/75418252/how-to-create-3d-torus-from-circle-revolved-about-x-2r-r-is-the-radius-of-circl/76400951#76400951>

this is the code:

```julia
using GLMakie

Base.@kwdef mutable struct Torus
    R::Float64 = 2
    r::Float64 = 1
end

function generate_torus(torus::Torus, resolution=100; upto=1.0)
    u = range(0, stop=2π*upto, length=resolution) 
    v = range(0, stop=2π*upto, length=resolution) 
    x = [( torus.R + torus.r*cos(vᵢ) ) * cos(uᵢ) for vᵢ in v, uᵢ in u]
    y = [( torus.R + torus.r*cos(vᵢ) ) * sin(uᵢ) for vᵢ in v, uᵢ in u]
    z = [torus.r * sin(vᵢ) for vᵢ in v, _ in u]
    return x, y, z
end

function animate_torus(torus::Torus, filename="torus.gif")
    fig = Figure(resolution = (500, 500))
    ax = fig[1, 1] = LScene(fig)
    cam3d!(ax.scene)

    # Initialize surface plot with full torus
    x, y, z = generate_torus(torus)
    p = surface!(ax, x, y, z, colormap=:viridis, shading = false)
    # Set the limits
    xlims!(ax.scene, (-4, 4))
    ylims!(ax.scene, (-4, 4))
    zlims!(ax.scene, (-1, 1))

    record(fig, filename, range(0, stop=1, length=100)) do i
        # Update data of surface plot
        x, y, z = generate_torus(torus, upto=i)
        p[1] = x
        p[2] = y
        p[3] = z
    end
end

```

the problem is when I type: `animate_torus(torus)` it returns **UndefVarError: `torus` not defined** and I think the poster in SoF will not answer it as quick as in Discourse, that is why I ask it here.

---

<div class="post-metadata">

**Author:** ![LaurentPlagne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laurentplagne/32/10103_2.png) [@LaurentPlagne](https://discourse.julialang.org/u/LaurentPlagne)\
**Post date:** [June 6, 2023, 1:32pm UTC](https://discourse.julialang.org/t/how-to-call-function-to-create-animation-in-glmakie/99938/2 "2023-06-06T13:32:58Z")

</div>

If your plot command (surface!) is outside the loop then you have to “update” it via observable.  
See for example the paragraph [Animations using `Observables`] ([Animations · Makie](https://docs.makie.org/stable/documentation/animation/#animations_using_observables))

---

<div class="post-metadata">

**Author:** ![LaurentPlagne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laurentplagne/32/10103_2.png) [@LaurentPlagne](https://discourse.julialang.org/u/LaurentPlagne)\
**Post date:** [June 6, 2023, 9:10pm UTC](https://discourse.julialang.org/t/how-to-call-function-to-create-animation-in-glmakie/99938/3 "2023-06-06T21:10:10Z")

</div>

Here is the torus animation with observable. Note that you can have live plots and interactive plots in addition to the animation file production for free 😉

![torus](https://global.discourse-cdn.com/julialang/original/3X/5/4/5486b2e70fbe17f840be5559942ae6415d68aad4.gif)

```julia
using GLMakie

Base.@kwdef mutable struct Torus
    R::Float64 = 2
    r::Float64 = 1
end

function generate_torus(torus::Torus,upto,resolution=100)
    u = range(0, stop=2π*upto, length=resolution) 
    v = range(0, stop=2π*upto, length=resolution) 
    x = [( torus.R + torus.r*cos(vᵢ) ) * cos(uᵢ) for vᵢ in v, uᵢ in u]
    y = [( torus.R + torus.r*cos(vᵢ) ) * sin(uᵢ) for vᵢ in v, uᵢ in u]
    z = [torus.r * sin(vᵢ) for vᵢ in v, _ in u]
    return (x, y, z)
end

function setup_scene(fig,torus::Torus,upto)
    ax = Axis3(fig[1, 1], aspect = :data, perspectiveness = 0.5, elevation = π / 9,
        xzpanelcolor = (:black, 0.75), yzpanelcolor = (:black, 0.75),
        zgridcolor = :grey, ygridcolor = :grey, xgridcolor = :grey)
    xlims!(ax, -4, 4)
    ylims!(ax, -4, 4)
    zlims!(ax, -1, 1)
    lift(d->surface!( generate_torus(torus,d)...; colormap=:plasma, shading = false,transparency = false),upto)
    # lift(d->wireframe!(ax, generate_torus(torus,d)...; linewidth = 0.5, transparency = true),upto)
    display(fig)
    fig
end
    
function main_movie()
    GLMakie.activate!()
    fig = Figure(resolution = (800, 800), fontsize = 22)
    upto = Observable(0.)
    fig=setup_scene(fig,Torus(),upto)
    # record(fig, "torus.mp4", range(0, stop=1, length=100)) do i
    record(fig, "torus.gif", range(0, stop=1, length=100)) do i
            upto[] = i # Update data of surface plot
    end
end

function main_live()
    GLMakie.activate!()
    fig = Figure(resolution = (800, 800), fontsize = 22)
    upto = Observable(0.)
    fig=setup_scene(fig,Torus(),upto)
    for i ∈ range(0, stop=1, length=100)
        sleep(0.01)
        upto[] = i # Update data of surface plot
    end
end

function main_slider()
    GLMakie.activate!(float=true)
    fig = Figure(resolution = (2000, 2000), fontsize = 22)
    sl = Slider(fig[2,1],range=0:0.01:1,startvalue=0.01)
    fig = setup_scene(fig,Torus(),sl.value)
    fig
end

main_live()

```

---

<div class="post-metadata">

**Author:** ![Freya\_the\_Goddess](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/freya_the_goddess/32/36835_2.png) [@Freya\_the\_Goddess](https://discourse.julialang.org/u/Freya_the_Goddess)\
**Post date:** [June 7, 2023, 9:38am UTC](https://discourse.julialang.org/t/how-to-call-function-to-create-animation-in-glmakie/99938/4 "2023-06-07T09:38:45Z")

</div>

So if there is code like this:

```julia
p = surface!(ax, x, y, z, colormap=:viridis, shading = false)

```

I should add something like this then:

```julia
upto = Observable(0.)

```

?

GLMakie is quite hard to grasp for beginner, but thanks for this, it helps a lot! Not only me but other people in this Discourse too.

---

<div class="post-metadata">

**Author:** ![LaurentPlagne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laurentplagne/32/10103_2.png) [@LaurentPlagne](https://discourse.julialang.org/u/LaurentPlagne)\
**Post date:** [June 7, 2023, 10:19am UTC](https://discourse.julialang.org/t/how-to-call-function-to-create-animation-in-glmakie/99938/5 "2023-06-07T10:19:27Z")

</div>

Hi,

First I have to say that I am not the best specialist for Makie observable system, just a happy user, and it would be nice if a Makie specialist could review the proposed script (In particular, the main\_live).

FWIW, my understanding of the observable system is:

1 : You define one (or several) observable for a given (or several) quantity that will change during the animation. Here the quantity is your torus parameter `upto`:

```julia
 upto = Observable(0.) #0 is the default value of the observable upto (here of type Observable(Int)).

```

2 : If `o` is an observable, then `lift(x->f(x),o)` will execute the `f(new_value)` each time `o` is updated by the command `o[]=new_value`.

In the torus animation case this gives:

```julia
   record(fig, "torus.gif", range(0, stop=1, length=100)) do i
            upto[] = i # Update the value of the upto observable with value i
    end

```

which triggers a new execution of the `surface!` Makie command via:

```julia
    lift(x->surface!( generate_torus(torus,x)... ),upto)

```

where the function `f(x)` function is in this case the following closure(\*) :  
`surface!( generate_torus(torus,x)... )`

Hope it helps.

Not completely trivial to grasp but quite powerful (IMHO). You could for example add a title to the figure showing the current value of the parameter `upto`. To achieve this you need to add another `lift` construction like `title = lift(x->string(x),upto)`.

I tried to illustrate that a useful consequence of the Observable system is to allow for different applications of the same code. In the torus case you have 3 different applications:

1. The animation via the `record` function (`main_movie`)
2. The `live` plot via a loop (`main_live`).
3. An interactive plot using `slider` widgets (`main_interactive`).

(\*) closure : function that captures some context variables like `torus` in this case.
