# How to animate Sierpinski triangle construction

**URL:** <https://discourse.julialang.org/t/how-to-animate-sierpinski-triangle-construction/91315>\
**Category:** Visualization\
**Tags:** plots\
**Created:** [December 6, 2022, 4:52pm UTC](https://discourse.julialang.org/t/how-to-animate-sierpinski-triangle-construction/91315 "2022-12-06T16:52:58Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [December 6, 2022, 4:52pm UTC](https://discourse.julialang.org/t/how-to-animate-sierpinski-triangle-construction/91315/1 "2022-12-06T16:52:58Z")

</div>

How do I get an animated gif from the following construction?  
Possibly also changing the functions used, if a different function is more suitable for the case.

```julia
using Plots
gr()
tr=[(0,0),(1,0),0.5.*(1,sqrt(3))]
p=plot(tr, st=:scatter, markersize=3, legend=false)
m=0.5 .* ((0,0).+ (1,0))
sierpinski=[m]
for i in 1:10000
    m=0.5 .*(m .+ tr[rand(1:3)])
    push!(sierpinski,m)
end

plot!(p,sierpinski,st=:scatter, markersize=1, legend=false)

savefig(p,"sierpinski.png")
![sierpinski|600x400](upload://zD6zATpX1cxDoNJtUgU0e2LRxr3.png)

```

I tried this way, but it doesn’t work.

```julia
julia> using Plots

julia> gr()
Plots.GRBackend()

julia> tr=[(0,0),(1,0),0.5.*(1,sqrt(3))]
3-element Vector{Tuple{Real, Real}}:
 (0, 0)
 (1, 0)
 (0.5, 0.8660254037844386)

julia> p = scatter(1,xlim = (0, 1),ylim = (0, sqrt(3)/2), legend = false, marker = 1)

julia> m=0.5 .* ((0,0).+ (1,0))
(0.5, 0.0)

julia> @gif for i=1:10000
           m=0.5 .*(m .+ tr[rand(1:3)])
           push!(p, m)
       end every 10
ERROR: UndefVarError: m not defined
Stacktrace:
 [1] macro expansion
   @ c:\Users\sprmn\.julia\v1.8\plot3.jl:86 [inlined]
 [2] top-level scope
   @ C:\Users\sprmn\.julia\packages\Plots\yJrrq\src\animation.jl:235

```

I tried to use the same scheme used for the [lorenz attractor](https://docs.juliaplots.org/latest/user_gallery/misc/gr_lorenz_attractor/#Lorenz-Attractor) and in this way I get the animated gif. But I don’t understand why it doesn’t work in the first case and I’m pretty sure there are easier ways to achieve the same result.

```julia
#-------------
using Plots
# define the Lorenz attractor
Base.@kwdef mutable struct Sier
    a = (0,0)
    b=(1,0)
    c=0.5.*(1,sqrt(3))
    tr=[a,b,c]
    x=0.5 * (a[1]+ b[1])
    y=0.5 * (a[2]+ b[2])
end

function step!(m::Sier)
    v=m.tr[rand(1:3)]
    m.x = 0.5*(m.x+v[1])
    m.y = 0.5*(m.y+v[2])
end

midpoint = Sier()

plt = scatter(
    1,
    xlim = (0, 1),
    ylim = (0, sqrt(3)/2),
    legend = false,
    marker = 1,
)

@gif for i=1:10000
    step!(midpoint)
    push!(plt, midpoint.x, midpoint.y)
end every 10

```

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [December 8, 2022, 7:36am UTC](https://discourse.julialang.org/t/how-to-animate-sierpinski-triangle-construction/91315/3 "2022-12-08T07:36:24Z")

</div>

I get this error (I ran update Plots command)

```julia
julia> gif(p, [sierpinski[1:i] for i in 1:length(sierpinski)], st=:scatter, markersize=1, legend=false, filename="sierpinski 1.gif")
ERROR: MethodError: no method matching gif(::Plots.Plot{Plots.GRBackend}, ::Vector{Vector{Any}}; st=:scatter, markersize=1, legend=false, filename="sierpinski 1.gif")
Closest candidates are:
  gif(::Animation, ::Any; kw...) at C:\Users\sprmn\.julia\packages\Plots\yJrrq\src\animation.jl:65
Stacktrace:
 [1] top-level scope
   @ c:\Users\sprmn\.julia\v1.8\plot3.jl:113

(v1.8) pkg> status Plots
Status `C:\Users\sprmn\.julia\v1.8\Project.toml`
⌃ [91a5bcdd] Plots v1.32.0
Info Packages marked with ⌃ have new versions available

```

PS  
Could you upload the gif you get?

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [December 8, 2022, 8:25am UTC](https://discourse.julialang.org/t/how-to-animate-sierpinski-triangle-construction/91315/4 "2022-12-08T08:25:22Z")

</div>

Excuse me, @devvinish, but are getting your answers from chatGPT? Both the language of your explanations (which is very good), the clarity of the code, as well as the incongruent oddness of the errors in the code remind me a lot of the bot-generated code.

I suggest that you actually test that your code runs before sharing it here. And _if_ the code and answers are written by chatGPT, please indicate so in your posts.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [December 8, 2022, 9:06am UTC](https://discourse.julialang.org/t/how-to-animate-sierpinski-triangle-construction/91315/5 "2022-12-08T09:06:17Z")

</div>

Try this (edited to get rid of `global` as per @DNF advice):

```julia
using Plots; gr(dpi=100)

function sierpinski_gif(n)
    p = scatter(1, xlim=(0,1), ylim=(0,√3/2), legend=false, ms=1.5, msw=0, marker=:utriangle, c=:black)
    m = 0.5 .* ((0,0) .+ (1,0))
    anim = @animate for i=1:n
        m = 0.5 .* (m .+ rand([(0,0), (1,0), 0.5 .* (1, √3)]))
        push!(p, m)
    end every 10
    gif(anim, "sierpinski.gif")
    return p
end

sierpinski_gif(5000) # 21 s (40 M allocs: 889 MiB, 0.4% gc time)

```

---

<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:** [December 8, 2022, 9:36am UTC](https://discourse.julialang.org/t/how-to-animate-sierpinski-triangle-construction/91315/6 "2022-12-08T09:36:30Z")

</div>

The GIF generation takes too long about 7 seconds to produce one png.

Maybe the Graphics card or RAM is not powerful enough for my laptop. Thanks for the code anyway…

7000 seconds to create one gif or 116 minutes

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [December 8, 2022, 9:44am UTC](https://discourse.julialang.org/t/how-to-animate-sierpinski-triangle-construction/91315/7 "2022-12-08T09:44:46Z")

</div>

Your proposal has been around for a long time and I didn’t wait for it to conclude.  
I did however exploit making the variable m global in my first attempt and this seems to achieve what I was looking for…  
 ![sierpinski10fr](https://global.discourse-cdn.com/julialang/original/3X/d/8/d8cb31e021696619aa58113b4994c977f0677140.gif)

```julia
using Plots

gr()

tr=[(0,0),(1,0),0.5.*(1,sqrt(3))]

p = scatter(1,xlim = (0, 1),ylim = (0, sqrt(3)/2), legend = false, marker = 1)

m=0.5 .* ((0,0).+ (1,0))

 @gif for i=1:10000
          **global** m=0.5 .*(m .+ tr[rand(1:3)])
           push!(p, m)
       end every 10

```

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [December 8, 2022, 9:57am UTC](https://discourse.julialang.org/t/how-to-animate-sierpinski-triangle-construction/91315/8 "2022-12-08T09:57:15Z")

</div>

> [@rafael.guerra](#):
>
> `global m = 0.5 .* (m .+ tr[rand(1:3)])`

Come on! Don’t give this advice 😉 You know this should be wrapped in a function, and that `global` is poison.

---

<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 8, 2022, 10:02am UTC](https://discourse.julialang.org/t/how-to-animate-sierpinski-triangle-construction/91315/9 "2022-12-08T10:02:49Z")

</div>

Makie version:

```julia
using CairoMakie

function sierpinski()
    # create observable holding scatter points
    tr = Observable(Point2f[(0, 0), (1, 0), 0.5.*(1, sqrt(3))])

    # create a scatter plot of that observable
    f, ax, sc = scatter(tr, markersize = 3)

    # create the starting point for the iterative algorithm
    m = Point2f(0.5 .* ((0,0).+ (1,0)))
    
    # make a recording of figure `f` with 300 frames
    record(f, "sierpinski.mp4", 1:300) do frame
        # add 10 new points per frame
        for i in 1:10
            # calculate a new m
            m = 0.5f0 * (m + tr[][rand(1:3)])
            # and push it to the vector contained in the observable tr
            # without updating the observable, yet
            push!(tr[], m)
        end
        # after all new points are added, update the observable tr once
        # so the scatter plot is updated as well for the new frame
        # that is being created each time that this closure returns
        notify(tr)
    end
end

```

---

<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:** [December 8, 2022, 10:06am UTC](https://discourse.julialang.org/t/how-to-animate-sierpinski-triangle-construction/91315/10 "2022-12-08T10:06:00Z")

</div>

why 'global` is poison?

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [December 8, 2022, 10:36am UTC](https://discourse.julialang.org/t/how-to-animate-sierpinski-triangle-construction/91315/11 "2022-12-08T10:36:14Z")

</div>

I asked chatGPT, which answered the following:

> Global variables are variables that are declared outside of any function or class and can be accessed from anywhere in the program. Using global variables can lead to several problems.
> 
> First, global variables can make it difficult to understand the flow of a program. Because global variables can be accessed and modified from anywhere, it’s hard to keep track of how and when they are being used. This can make it difficult to debug the program and understand how it works.
> 
> Second, global variables can cause conflicts if multiple parts of the program try to access or modify the same global variable. This can lead to unpredictable behavior and errors.
> 
> Third, global variables can make it difficult to reuse code. If a function or class relies on a global variable, it can only be used in a specific context where that global variable is defined. This can limit the reusability of the code and make it difficult to write modular and flexible programs.
> 
> In general, it’s best to avoid using global variables whenever possible. Instead, it’s usually better to use local variables and pass them as arguments to functions or methods. This can make the code easier to understand, debug, and reuse.

My own remark: they are _particularly_ bad in Julia because they hurt performance, unless they are `const`, which it isn’t here and cannot be.

(chatGPT will enable some some extremely lazy answers, but I’m still a bit fascinated with trying it out. This question seemed like a reasonable usecase).

---

<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:** [December 8, 2022, 11:00am UTC](https://discourse.julialang.org/t/how-to-animate-sierpinski-triangle-construction/91315/12 "2022-12-08T11:00:06Z")

</div>

Yes I understand now about global variables concept, then I look for chatGPT, and I think it is amazing to have answer like that from chatGPT.

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [December 8, 2022, 12:23pm UTC](https://discourse.julialang.org/t/how-to-animate-sierpinski-triangle-construction/91315/13 "2022-12-08T12:23:55Z")

</div>

> [@jules](#):
>
> ```julia
> using CairoMakie
> 
> function sierpinski()
> 
> ```

Very interesting.  
But not easy to follow for those unfamiliar with the functions used.  
Could you explain the logic of the different lines of code?

---

<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 8, 2022, 12:28pm UTC](https://discourse.julialang.org/t/how-to-animate-sierpinski-triangle-construction/91315/14 "2022-12-08T12:28:31Z")

</div>

I’ve added some comments

---

<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 8, 2022, 12:43pm UTC](https://discourse.julialang.org/t/how-to-animate-sierpinski-triangle-construction/91315/15 "2022-12-08T12:43:09Z")

</div>

to be included in BMakie?

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [December 8, 2022, 3:52pm UTC](https://discourse.julialang.org/t/how-to-animate-sierpinski-triangle-construction/91315/16 "2022-12-08T15:52:10Z")

</div>

> [@rocco\_sprmnt21](#):
>
> Your proposal has been around for a long time and I didn’t wait for it to conclude.

I think you meant “… has been running for a long time …” 🙂

In any case, the Plots.jl animations performance seems to depend heavilly on the dpi selected, in addition to the step size to not capture all the plot frames.

I have edited my post above using macro `@animate` and putting everything inside a function.

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [December 8, 2022, 5:18pm UTC](https://discourse.julialang.org/t/how-to-animate-sierpinski-triangle-construction/91315/17 "2022-12-08T17:18:28Z")

</div>

Colpa di Google translator 🙂

---

<div class="post-metadata">

**Author:** ![cormullion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cormullion/32/49131_2.png) [@cormullion](https://discourse.julialang.org/u/cormullion)\
**Post date:** [December 8, 2022, 6:27pm UTC](https://discourse.julialang.org/t/how-to-animate-sierpinski-triangle-construction/91315/18 "2022-12-08T18:27:05Z")

</div>

I think there’s potential for some interesting variations on this theme. Here’s one that looked promising:

![sierpinski](https://global.discourse-cdn.com/julialang/original/3X/f/5/f5252ed386692642a5b7ac923e7a1ab5126d9050.gif)

No code for this - let those AI bots do the work for themselves … 🙂

---

<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:** [December 8, 2022, 7:16pm UTC](https://discourse.julialang.org/t/how-to-animate-sierpinski-triangle-construction/91315/19 "2022-12-08T19:16:00Z")

</div>

> [@rocco\_sprmnt21](#):
>
> ```julia
> using Plots
> 
> gr()
> 
> tr=[(0,0),(1,0),0.5.*(1,sqrt(3))]
> 
> p = scatter(1,xlim = (0, 1),ylim = (0, sqrt(3)/2), legend = false, marker = 1)
> 
> m=0.5 .* ((0,0).+ (1,0))
> 
> @gif for i=1:10000
> **global** m=0.5 .*(m .+ tr[rand(1:3)])
> push!(p, m)
> end every 10
> 
> ```

I got error for this code:

**LoadError: syntax: use “x^y” instead of "x** y" for exponentiation, and “x…” instead of " **x" for splatting.**

---

<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:** [December 8, 2022, 7:26pm UTC](https://discourse.julialang.org/t/how-to-animate-sierpinski-triangle-construction/91315/20 "2022-12-08T19:26:36Z")

</div>

I try this code from JULIA REPL and get this in return:

```julia
**sierpinski (generic function with 1 method)**

```

what should I do to generate the .mp4 or the animation then?

---

<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 8, 2022, 8:01pm UTC](https://discourse.julialang.org/t/how-to-animate-sierpinski-triangle-construction/91315/21 "2022-12-08T20:01:22Z")

</div>

Call the function 🙂

[Next page](https://discourse.julialang.org/t/how-to-animate-sierpinski-triangle-construction/91315.md?page=2)
