Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matplotlib animation; animate in push mode, not with a call back function

I want to create a matplotlib animation, but instead of having matplotlib call me I want to call matplotlib. For example I want to do this:

from random import random
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

def update(frame):
    plt.scatter(random(),random())

fig, ax = plt.subplots()
ani = FuncAnimation(fig, update, interval=340, repeat=True)
ani.save("my.mov", "avconv")

Like this:

def update():
    plt.scatter(random(),random())

fig, ax = plt.subplots()
ani = MadeUpSubClassPassiveAnimation(fig)

while True:
  update()
  ani.update()
  # do other stuff ...

ani.save("my.mov", "avconv") 

I realize I could drive a live plot like this:

def update():
  plt.scatter(x, y)
  plt.pause(0.01)

fig, ax = plt.subplots()
plt.ion()

while True:
  update()
  time.sleep(1)

But AFAIK I need to use Animation for the save() functionality. So, is it possible to drive Animation rather than have it drive me? If so how?

like image 355
spinkus Avatar asked Jun 21 '26 02:06

spinkus


1 Answers

An Animation is run when being saved. This means that the animation needs to reproducibly give the same result when being run twice (once for saving, once for showing). In other words, the animation needs to be defined in terms of successive frames. With this requirement, any animation can be constructed using a callback on either a function (FuncAnimation) or on a list of frames (ArtistAnimation).

The example from the question could be done with an ArtistAnimation (in order not to have different random numbers for the saved and the shown animation, respectively):

from random import random

import matplotlib.animation
import matplotlib.pyplot as plt

def update(frame: int) -> list[matplotlib.artist.Artist]:
    sc = ax.scatter(random(), random())
    return [sc]

fig, ax = plt.subplots()

artists = []

for i in range(10):
    sc = update(i)
    artists.append(sc)

# If you want previous plots to be present in all frames, add:
# artists = [[j[0] for j in artists[:i+1]] for i in range(len(artists))]
  
ani = matplotlib.animation.ArtistAnimation(fig, artists, interval=100)
ani.save(__file__ + ".gif", writer="imagemagick") 
plt.show()
like image 162
ImportanceOfBeingErnest Avatar answered Jun 22 '26 16:06

ImportanceOfBeingErnest



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!