4

I am currently experimenting with the matplotbib FuncAnimation and try some exmaples. Everthing runs fine, however, I produce videos via ffmpeg with anim.save(...) and I don't get my animation to play faster/slower. Neither changing

FuncAnimation(...,interval=x,...)

nor

anim.save(...,fps=x.)

had any effect on the video output. What is the difference between the two ('frames'/'fps' should be 'interval', no?)? Here my reduced code:

import numpy as np
import matplotlib.animation as animation
import matplotlib.pyplot as plt

class Ball:

    def __init__(self,initpos,initvel,radius,M):
        self.pos=initpos
        self.vel=initvel
        self.radius=radius
        self.M=M


    def step(self,dt):

        self.pos += self.vel*dt
        self.vel[2] += -9.81*dt*self.M

initpos=np.array([5.0,5.0,10.0])
initvel=np.array([0.0,0.0,0.0])
radius=0.25
M=1


test_ball = Ball(initpos,initvel,radius,M)  
dt=1./10

fig = plt.figure()
ax = fig.add_axes([0, 0, 1, 1], projection='3d')

pts = []
pts += ax.plot([], [], [], 'bo', c="blue")

def init():
    for pt in pts:
    pt.set_data([], [])
    pt.set_3d_properties([])
    return pts

def animate(i):
test_ball.step(dt) 
for pt in pts:
    pt.set_data(test_ball.pos[0],test_ball.pos[1])
    pt.set_3d_properties(test_ball.pos[2])
    pt.set_markersize(10)
    return pts 

anim = animation.FuncAnimation(fig, animate,init_func=init,frames=50,interval=1)


mywriter = animation.FFMpegWriter()
anim.save('mymovie.mp4',writer=mywriter,fps=10)

Hope, someone can help me. Thanks a lot.

PS: By the way, I was wondering as well

  1. what the init funcion does because the code also runs perfectly without it but it is in most of the inet-examples.
  2. what markersize is for an ax.plot(...,'o',...) point. Radius in which unit?
tshepang
  • 12,111
  • 21
  • 91
  • 136
intasys
  • 75
  • 1
  • 7

3 Answers3

1

Here is a working example.

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.animation as animation
import matplotlib.pyplot as plt
import numpy as np


class Ball:

    def __init__(self, initpos, initvel, radius, M):
        self.pos = initpos
        self.vel = initvel
        self.radius = radius
        self.M = M

    def step(self, dt):

        self.pos += self.vel * dt
        self.vel[2] += -9.81 * dt * self.M

initpos = np.array([5., 5., 10.])
initvel = np.array([0., 0., 0.])
radius = .25
M, dt = 1, .1


test_ball = Ball(initpos, initvel, radius, M)

fig, ax = plt.subplots(subplot_kw=dict(projection='3d'))

pts = ax.plot([], [], [], 'bo', c='blue')


def init():
    for pt in pts:
        pt.set_data([], [])
        pt.set_3d_properties([])
    ax.set_xlim3d(0, 1.5 * initpos[0])
    ax.set_ylim3d(0, 1.5 * initpos[1])
    ax.set_zlim3d(0, 1.5 * initpos[2])
    return pts


def animate(i):
    test_ball.step(dt)
    for pt in pts:
        pt.set_data(test_ball.pos[0], test_ball.pos[1])
        pt.set_3d_properties(test_ball.pos[2])
        pt.set_markersize(10)

    return pts

anim = animation.FuncAnimation(fig, animate, init_func=init, frames=50)
mywriter = animation.FFMpegWriter(fps=10)
anim.save('mymovie.mp4', writer=mywriter)

When using a custom writer you need to specify the number of frame per second when creating the writer.

You can check for the correct fps with the following command line

$ ffprobe mymovie.mp4
t-bltg
  • 854
  • 9
  • 17
  • I tried setting my fps to 2 to show two of the animation steps per second, but the video doesn't play properly (skips frames, hangs). Had to resort to encoding at 25fps with an interval of 50, then converting using ffmpeg. – womblerone Jul 03 '18 at 13:07
  • @wellspokenman, it does work properly for me on linux at 2fps, but using another player than vlc ... – t-bltg Jul 03 '18 at 14:13
0

From reading the source code it seems that the interval argument of FuncAnimation is often ignored in the Animation parent class (although there is a lot of inheritance so maybe used elsewhere?), and instead the fps argument to FFMpegWriter is used in most cases.

Anyhow for me not using interval, and instead using the fps argument of FFMPegWriter to control the animation speed works best.

Since the animation function is only called a certain number of times (as can be proved with print statements), there can only really be one parameter that determines the time interval between each frame, so this either comes from interval or it comes from fps. As I say it seems to come from fps.

Joe Iddon
  • 20,101
  • 7
  • 33
  • 54
-1

If you want to slow down the animation you can use time.sleep() inside the animate function. I am having some trouble with the interval argument too. The speed of the animation should depend on interval argument, not fps.

anim.save(...,fps=x.)

This will determine the quality of video being saved, ie the rate at which frames are being rendered in the video.

DarthSpeedious
  • 965
  • 1
  • 13
  • 25