# Makie does not update the plot during an animation

**URL:** <https://discourse.julialang.org/t/makie-does-not-update-the-plot-during-an-animation/91109>\
**Category:** General Usage\
**Tags:** makie, glmakie, animations\
**Created:** [December 1, 2022, 5:31pm UTC](https://discourse.julialang.org/t/makie-does-not-update-the-plot-during-an-animation/91109 "2022-12-01T17:31:59Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![BambOoxX](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bambooxx/32/22179_2.png) [@BambOoxX](https://discourse.julialang.org/u/BambOoxX)\
**Post date:** [December 1, 2022, 5:32pm UTC](https://discourse.julialang.org/t/makie-does-not-update-the-plot-during-an-animation/91109/1 "2022-12-01T17:32:00Z")

</div>

Working with lots of geometry objects, I wrote some recipes to plot such objects using low-level commands like `lines!` and `scatter!`  
I have a _master_-recipe that combines all of those so that my call sequence remains simple. Now I am trying to animate such complex plots using `lift`s and `Observables`

My call sequence looks like

```julia
time = Observable(0.0)
constantargument = 1
varargument = @lift(fun($time))
f,ax,p = mymasterrecipeplot!(constantargument,varargument)
for t in 0:100
    time[] = t
    sleep(0.5)
end

```

At the beginning, no variables defined in the recipes was updated when upon the `time[]` call.  
So I wrapped all my underlying recipes such that any of them was declared `lift`ing the arguments. For instance

```julia
Makie.@recipe(MyMasterRecipePlot,arg1,arg2) do scene
    # Recipe declarations
end

function Makie.plot!(plt::MyMasterRecipePlot{<:Tuple{<arg1 type>,<arg2 type>})
    (;arg1,arg2) = plt
    lift(arg1,arg2) do arg1, arg2
        # computation and other calls here
        return plt
    end
end

```

At that point I can see that the values passed upon `time` update are modified. However, these new values are not reflected in the plotted figure. I tried to `display(f)` in the loop but that does not change it.  
However, if I close manually the figure during the update loop, it reopens at the next iteration, showing all consecutive plots that should have been plotted during the previous loop iterations on top of each other in the same figure.

Could someone tell me what I am doing wrong ?

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [December 1, 2022, 6:37pm UTC](https://discourse.julialang.org/t/makie-does-not-update-the-plot-during-an-animation/91109/2 "2022-12-01T18:37:02Z")

</div>

The plotting calls in your recipe should only be done once, not on every observable update. But the input observables to these inner plotting calls should be lifted from the recipe input observables. Whenever these are updated, the inner plots receive updated inputs and visually update. I would recommend to have a look in the recipes folder of Makie’s source, to see how we do it there. Probably easier to learn by example.

---

<div class="post-metadata">

**Author:** ![BambOoxX](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bambooxx/32/22179_2.png) [@BambOoxX](https://discourse.julialang.org/u/BambOoxX)\
**Post date:** [December 1, 2022, 8:40pm UTC](https://discourse.julialang.org/t/makie-does-not-update-the-plot-during-an-animation/91109/3 "2022-12-01T20:40:37Z")

</div>

> [@jules](#):
>
> The plotting calls in your recipe should only be done once, not on every observable update  
> But the input observables to these inner plotting calls should be lifted from the recipe input observables.

As far as I understand what you mean, It seems to me it is what I do in the call sequence in the first codeblock, isn"t it ?

- Call de main recipe once, then update the observable
- Have all arguments in the underlying recipes be lifted before being used in each recipe ?

I had a look at the Makie source, as you advised, what I found is the following

- In [`hvlines`](https://github.com/MakieOrg/Makie.jl/blob/39cc40fc86ced14c1ee68bc2ea54047919272489/src/basic_recipes/hvlines.jl#L59-L82), observables seem to be called via `onany`
- In [`scatterlines`](https://github.com/MakieOrg/Makie.jl/blob/39cc40fc86ced14c1ee68bc2ea54047919272489/src/basic_recipes/scatterlines.jl#L31-L61), the arguments of the calling recipe are passed to the underlying recipes directly, without `lift`, and some `map!` is used too…
- In [`series`](https://github.com/MakieOrg/Makie.jl/blob/39cc40fc86ced14c1ee68bc2ea54047919272489/src/basic_recipes/series.jl#L66-L93), attributes of the plot are extracted with `@extract` but I’m guessing this is for backwards,compatibility (I may have overlooked that). Some `lift` calls are used, and `@lift` calls as well.

All in all, this shows that there are multiple related ways to achieve an animation which I (somehow, with a broken outcome) managed to do, but what I can’t figure is what prevents the figure from updating, since the underlying data is correctly updated. It’s like some kind of flush operation does not happen and trigger the replot in the `GLMakie` window.

---

<div class="post-metadata">

**Author:** ![lazarusA](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lazarusa/32/6571_2.png) [@lazarusA](https://discourse.julialang.org/u/lazarusA)\
**Post date:** [December 1, 2022, 9:33pm UTC](https://discourse.julialang.org/t/makie-does-not-update-the-plot-during-an-animation/91109/4 "2022-12-01T21:33:22Z")

</div>

Indeed, I also have the same issue. Saving the animation and doing the animation is fine, but the live update in the window is not longer there.

---

<div class="post-metadata">

**Author:** ![BambOoxX](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bambooxx/32/22179_2.png) [@BambOoxX](https://discourse.julialang.org/u/BambOoxX)\
**Post date:** [December 1, 2022, 9:37pm UTC](https://discourse.julialang.org/t/makie-does-not-update-the-plot-during-an-animation/91109/5 "2022-12-01T21:37:37Z")

</div>

I have to say that reproducing a simple example from the Makie website works in my case (even the live updating) but not something inside a custom recipe.

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [December 1, 2022, 11:52pm UTC](https://discourse.julialang.org/t/makie-does-not-update-the-plot-during-an-animation/91109/6 "2022-12-01T23:52:49Z")

</div>

That sounds like a bug then…

---

<div class="post-metadata">

**Author:** ![fatteneder](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fatteneder/32/33991_2.png) [@fatteneder](https://discourse.julialang.org/u/fatteneder)\
**Post date:** [December 1, 2022, 11:54pm UTC](https://discourse.julialang.org/t/makie-does-not-update-the-plot-during-an-animation/91109/7 "2022-12-01T23:54:09Z")

</div>

> [@BambOoxX](#):
>
> In [`scatterlines`](https://github.com/MakieOrg/Makie.jl/blob/39cc40fc86ced14c1ee68bc2ea54047919272489/src/basic_recipes/scatterlines.jl#L31-L61), the arguments of the calling recipe are passed to the underlying recipes directly, without `lift`, and some `map!` is used too…

This works because the arguments we pass on are already `Observables`.  
The use of `map!` is just an inplace version of `lift`. I think you could have also written

```julia
real_markercolor = Observable{Union{Vector{RGBAf}, RGBAf}}()
onany(p.color, p.markercolor) do col, mcol
    if mcol === automatic
        real_marker[] = to_color(col)
    else
        real_marker[] = to_color(mcol)
    end
end

```

I guess the reason for not using `lift` here is that otherwise you would have to convert your result to `Union{Vector{RGBAf}, RGBAf}` before `return`ing, which looks akward…

---

<div class="post-metadata">

**Author:** ![fatteneder](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fatteneder/32/33991_2.png) [@fatteneder](https://discourse.julialang.org/u/fatteneder)\
**Post date:** [December 2, 2022, 12:02am UTC](https://discourse.julialang.org/t/makie-does-not-update-the-plot-during-an-animation/91109/8 "2022-12-02T00:02:57Z")

</div>

> [@BambOoxX](#):
>
> In [`series`](https://github.com/MakieOrg/Makie.jl/blob/39cc40fc86ced14c1ee68bc2ea54047919272489/src/basic_recipes/series.jl#L66-L93), attributes of the plot are extracted with `@extract` but I’m guessing this is for backwards,compatibility (I may have overlooked that). Some `lift` calls are used, and `@lift` calls as well.

```julia
@extract plot (curves, labels, linewidth, color, solid_color)

```

is just short for

```julia
curves = plot.curves
linewidth = plot.linewidth
color = plot.color
solid_color = plot.solid_color

```

so nothing special. Again, the key is that `curves, linewidth, color, solid_color` are `Observables` and passed on as such.

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [December 2, 2022, 8:05am UTC](https://discourse.julialang.org/t/makie-does-not-update-the-plot-during-an-animation/91109/9 "2022-12-02T08:05:09Z")

</div>

`lift` is usually used when there’s a simple many to one relationship of observables where the output type is always the same. If it’s not, the second or later invocation of the function can error as the observable will get the type of the first result with `lift`.

So one can avoid this by defining the observable with the desired type beforehand, to then call `map!` on it.

And `onany` is usually used when multiple observables need to be updated and the order of updates has to be carefully orchestrated to avoid desynchronization or double updates.

---

<div class="post-metadata">

**Author:** ![BambOoxX](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bambooxx/32/22179_2.png) [@BambOoxX](https://discourse.julialang.org/u/BambOoxX)\
**Post date:** [December 2, 2022, 10:47am UTC](https://discourse.julialang.org/t/makie-does-not-update-the-plot-during-an-animation/91109/10 "2022-12-02T10:47:46Z")

</div>

Ok, I think I managed to make a reproducible example based on my code.

### First, a slightly modified example in 3D based on an example in the Makie website

This was tested on windows 10, GLMakie v0.7.3

```julia-auto
using GLMakie, GeometryBasics

time = Observable(0.0)
# 3D version of Makie animation example (works fine, even live update)
xs = range(0, 7, length=40)
ys_1 = @lift(sin.(xs .- $time))
ys_2 = @lift(cos.(xs .- $time) .+ 3)
z_s = @lift(sin.(xs .+ 2 * $time))

fig = lines(xs, ys_1, z_s, color=:blue, linewidth=4)
scatter!(xs, ys_2, z_s, color=:red, markersize=15)
fig
framerate = 30
timestamps = range(0, 2, step=1 / framerate)

```

@lazarusA maybe try this one to see if you manage to get a live update

### Now an example with recipes

```julia-auto
# Setup a data container of geometry objects
struct MyGeometry
    points::Vector{Point3f}
end

# Declare a sub-recipe
Makie.@recipe(NodePlot, points) do scene
    Attributes(
        color=:black
    )
end
function Makie.plot!(plt::NodePlot{<:Tuple{AbstractVector{<:AbstractPoint}}})
    # Unpack all relevant arguments
    (; points) = plt
    lift(points) do points
        # Just to see if points are updated from the outside
        @info first(points)
        meshscatter!(plt, points)
        return plt
    end
end

# Declare the master recipe
Makie.@recipe(MyGeometryPlot, geometry) do scene
    Attributes(
        color=:black
    )
end
function Makie.plot!(plt::MyGeometryPlot{MyGeometry})
    # Unpack all relevant arguments
    (; geometry) = plt
    lift(geometry) do geometry
        points = geometry.points
        !isempty(points) && nodeplot!(plt, points)
        return plt
    end
end

# Declare the actual geometry
mypoints = rand(Point3f,10)
geometry = @lift(MyGeometry(mypoints .+ Point3f($time)))
# Plot the geometry
mygeometryplot(geometry)

# Try and update the geometry
for t in timestamps
    time[] = t
    sleep(0.1)
end

```

On my machine, the `@info` call shows that the points are modified by the observable update, but that change is not reflected on the screen. Can anyone reproduce this ? And / or is it a misuse of the `lift` calls ?

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [December 2, 2022, 11:12am UTC](https://discourse.julialang.org/t/makie-does-not-update-the-plot-during-an-animation/91109/11 "2022-12-02T11:12:44Z")

</div>

As I tried to explain before, you’re not supposed to modify plot objects in `lift` closures like this

```julia
lift(geometry) do geometry
        points = geometry.points
        !isempty(points) && nodeplot!(plt, points)
        return plt
    end

```

`nodeplot!` should be called just once with `points = lift(g -> g.points, geometry)` as input

---

<div class="post-metadata">

**Author:** ![BambOoxX](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bambooxx/32/22179_2.png) [@BambOoxX](https://discourse.julialang.org/u/BambOoxX)\
**Post date:** [December 2, 2022, 12:02pm UTC](https://discourse.julialang.org/t/makie-does-not-update-the-plot-during-an-animation/91109/12 "2022-12-02T12:02:10Z")

</div>

> [@jules](#):
>
> points = lift(g → g.points, geometry)

That dit it thanks !

Here is the corrected example

```julia
using GLMakie, GeometryBasics

time = Observable(0.0)
framerate = 30
timestamps = range(0, 2, step=1 / framerate)

# Setup a data container of geometry objects
struct MyGeometry
    points::Vector{Point3f}
end

# Declare a sub-recipe
Makie.@recipe(NodePlot, points) do scene
    Attributes(
        color=:black
    )
end
function Makie.plot!(plt::NodePlot{<:Tuple{AbstractVector{<:AbstractPoint}}})
    # Unpack all relevant arguments
    (; points) = plt
        meshscatter!(plt, points)
        return plt
    end
end

# Declare the master recipe
Makie.@recipe(MyGeometryPlot, geometry) do scene
    Attributes(
        color=:black
    )
end
function Makie.plot!(plt::MyGeometryPlot{<:Tuple{MyGeometry}})
    # Unpack all relevant arguments
    (; geometry) = plt
    points = lift(g -> g.points, geometry)
    nodeplot!(plt, points)
    return plt
end

# Declare the actual geometry
mypoints = rand(Point3f, 10)
geometry = @lift(MyGeometry(mypoints .+ Point3f($time)))
# Plot the geometry
f, ax, p = mygeometryplot(geometry)

# Try and update the geometry
for t in timestamps
    time[] = t
    sleep(0.05)
end

```

---

<div class="post-metadata">

**Author:** ![BambOoxX](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bambooxx/32/22179_2.png) [@BambOoxX](https://discourse.julialang.org/u/BambOoxX)\
**Post date:** [December 2, 2022, 5:24pm UTC](https://discourse.julialang.org/t/makie-does-not-update-the-plot-during-an-animation/91109/13 "2022-12-02T17:24:08Z")

</div>

Jules, a side question, if I may. When dealing with large `lift` blocks I am returning multiple values, however, the lift returns an `Observable{Tuple{...}}` and not a `Tuple{Observable{...},...}` how do you unpack this kind of structure ?

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [December 2, 2022, 6:49pm UTC](https://discourse.julialang.org/t/makie-does-not-update-the-plot-during-an-animation/91109/14 "2022-12-02T18:49:59Z")

</div>

Multiple values are the achilles heel of the observable workflow. The problem is this:

Here, A triggers B and C, and both trigger D. In order to avoid a double update of D, A should first do `B.val = new_value`, then `C[] = new_value`.

```julia
     ┌─────┐
   ┌─┤ A ├─┐
   │ └─────┘ │
   │ │
   │ │
┌──▼──┐ ┌──▼──┐
│ B │ │ C │
└──┬──┘ └──┬──┘
   │ │
   │ │
   │ ┌─────┐ │
   └►│ D ◄─┘
     └─────┘

```

Now B has another listener, E. We can’t do `B.val = ...` anymore because `E` won’t be updated. But we can still do `C.val = ...` and `B[] = ...`.

```julia
          ┌─────┐
        ┌─┤ A ├─┐
        │ └─────┘ │
        │ │
        │ │
     ┌──▼──┐ ┌──▼──┐
   ┌─┤ B │ │ C │
   │ └──┬──┘ └──┬──┘
   │ │ │
   │ │ │
┌──▼──┐ │ ┌─────┐ │
│ E │ └►│ D ◄─┘
└─────┘ └─────┘

```

But if `C` also has a second listener, `F` this is impossible:

```julia
          ┌─────┐
        ┌─┤ A ├─┐
        │ └─────┘ │
        │ │
        │ │
     ┌──▼──┐ ┌──▼──┐
   ┌─┤ B │ │ C ├─┐
   │ └──┬──┘ └──┬──┘ │
   │ │ │ │
   │ │ │ │
┌──▼──┐ │ ┌─────┐ │ ┌──▼──┐
│ E │ └►│ D ◄─┘ │ F │
└─────┘ └─────┘ └─────┘

```

You cannot avoid updating both `B` and `C` if you want to trigger their listeners `E` and `F`, which means `D` is updated twice. But if `B` and `C` store arrays whose lengths change with the update of `A`, it can be that the first update of `D`, after `B` is triggered, errors because `B` and `C` have different lengths in that moment. In that case it’s _impossible_ to update all observables correctly. We’re still trying to figure out ways in which we can make the updating process simpler, but it’s a thorny issue and observables are deeply ingrained in the whole codebase, so we must be careful not to break anything with a “fix”.

I say this because you asked what to do with a tuple resulting from `lift`. But this usually happens because one calculates multiple input arguments for an inner plot object from input observables. In that case, one has to define all the observables beforehand, and carefully update them inside an `on` or `onany` function with `obs.val = ...` and only once (if possible) with `obs[] = ...` so that one doesn’t trigger duplicate updates downstream. But as I showed, this is sometimes impossible. Here’s one example of such a thing: [Makie.jl/contourf.jl at master · MakieOrg/Makie.jl · GitHub](https://github.com/MakieOrg/Makie.jl/blob/master/src/basic_recipes/contourf.jl#L125)  
The `colors` observable is not triggered, its content array is just mutated. This way the downstream `poly` will have access to the new colors when its input observable `polys` is triggered. This way `polys` and `colors` can always have the same length from the perspective of the `poly` plot. But this wouldn’t work if something internal to `poly` relied on the `color` observable actually triggering…

---

<div class="post-metadata">

**Author:** ![BambOoxX](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bambooxx/32/22179_2.png) [@BambOoxX](https://discourse.julialang.org/u/BambOoxX)\
**Post date:** [December 5, 2022, 9:05am UTC](https://discourse.julialang.org/t/makie-does-not-update-the-plot-during-an-animation/91109/15 "2022-12-05T09:05:57Z")

</div>

Thanks for this detailed answer ! Indeed, finding a good compromise between automatic handling of updates and unwanted multiple updates is tricky !  
To simplify this answer to its core, what I understand from it at least, one should use observables in a parsimonious manner right ? So as not to trigger too much updates ?

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [December 5, 2022, 9:17am UTC](https://discourse.julialang.org/t/makie-does-not-update-the-plot-during-an-animation/91109/16 "2022-12-05T09:17:07Z")

</div>

Yes, parsimonious is good. My heuristic is that it usually works to `obs.val = ..` update all the style attributes of a plot and only then trigger one of the positional arguments last, which usually makes everything redraw correctly. But if the internal logic is too complex, this doesn’t always work. I have some ideas about multi-observables that could alleviate some of these paint points, but those haven’t been fleshed out enough, yet.
