62

I have a python animation script (using matplotlib's funcAnimation), which runs in Spyder but not in Jupyter. I have tried following various suggestions such as adding "%matplotlib inline" and changing the matplotlib backend to "Qt4agg", all without success. I have also tried running several example animations (from Jupyter tutorials), none of which have worked. Sometimes I get an error message and sometimes the plot appears, but does not animate. Incidentally, I have gotten pyplot.plot() to work using "%matplotlib inline".

Does anyone know of a working Jupyter notebook with a simple inline animation example that uses funcAnimation.

[Note: I am on Windows 7]

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
Ari Herman
  • 805
  • 1
  • 7
  • 11

6 Answers6

93

notebook backend

'Inline' means that the plots are shown as png graphics. Those png images cannot be animated. While in principle one could build an animation by successively replacing the png images, this is probably undesired.

A solution is to use the notebook backend, which is fully compatible with FuncAnimation as it renders the matplotlib figure itself:

%matplotlib notebook

jsanimation

From matplotlib 2.1 on, we can create an animation using JavaScript. This is similar to the ani.to_html5() solution, except that it does not require any video codecs.

from IPython.display import HTML
HTML(ani.to_jshtml())

Some complete example:

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

t = np.linspace(0,2*np.pi)
x = np.sin(t)

fig, ax = plt.subplots()
ax.axis([0,2*np.pi,-1,1])
l, = ax.plot([],[])

def animate(i):
    l.set_data(t[:i], x[:i])

ani = matplotlib.animation.FuncAnimation(fig, animate, frames=len(t))

from IPython.display import HTML
HTML(ani.to_jshtml())

Alternatively, make the jsanimation the default for showing animations,

plt.rcParams["animation.html"] = "jshtml"

Then at the end simply state ani to obtain the animation.

Also see this answer for a complete overview.

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • 7
    AttributeError: 'FuncAnimation' object has no attribute 'to_jshtml' – ctrl-alt-delor Nov 23 '17 at 18:05
  • 1
    The to_jshtml was added in matplotlib version 2.1.0 : https://matplotlib.org/users/prev_whats_new/whats_new_2.1.0.html `!pip install matplotlib --upgrade` – Salain Sep 14 '18 at 13:11
  • 1
    When I copy the example into a network, it runs fine the first that I execute it. The second time it returns the animation AND an empty figure that I can't seem to get rid of. Where does it come from? – Alice Schwarze Jan 22 '20 at 00:20
  • 5
    @AliceSchwarze place `plt.close()` right after the `ani = ... ` declaration to get rid of the initial plot. The second `ani` then initiates the animation. – hahnec Jul 02 '20 at 17:22
  • How can I make a successful html file that shows the animation? I tried `jupyter nbconvert --html `, but it doesn't show any output. – Gabe Morris Jun 15 '22 at 12:53
  • @Gabe Morris - For presenting the animation in an HTML - using the JavaScript option described above and `nbconvert` as you suggest, worked out of the box for me. Matplotlib 3.7.1, nbconvert 7.4.0, Windows 11 – Ran Feldesh Jun 08 '23 at 12:34
17

There is a simple example within this tutorial here: http://louistiao.me/posts/notebooks/embedding-matplotlib-animations-in-jupyter-notebooks/

To summarise the tutorial above, you basically need something like this:

from matplotlib import animation
from IPython.display import HTML

# <insert animation setup code here>

anim = animation.FuncAnimation()  # With arguments of course!
HTML(anim.to_html5_video())

However...

I had a lot of trouble getting that to work. Essentially, the problem was that the above uses (by default) ffmpeg and the x264 codec in the background but these were not configured correctly on my machine. The solution was to uninstall them and rebuild them from source with the correct configuration. For more details, see the question I asked about it with a working answer from Andrew Heusser: Animations in ipython (jupyter) notebook - ValueError: I/O operation on closed file

So, try the to_html5_video solution above first, and if it doesn't work then also try the uninstall / rebuild of ffmpeg and x264.

Biggsy
  • 1,306
  • 1
  • 12
  • 28
13

Another option:

import matplotlib.animation
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams["animation.html"] = "jshtml"
plt.rcParams['figure.dpi'] = 150  
plt.ioff()
fig, ax = plt.subplots()

x= np.linspace(0,10,100)
def animate(t):
    plt.cla()
    plt.plot(x-t,x)
    plt.xlim(0,10)

matplotlib.animation.FuncAnimation(fig, animate, frames=10)

enter image description here

Kolibril
  • 1,096
  • 15
  • 19
7

Here is the answer that I put together from multiple sources including the official examples. I tested with the latest versions of Jupyter and Python.

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from IPython.display import HTML

#=========================================
# Create Fake Images using Numpy 
# You don't need this in your code as you have your own imageList.
# This is used as an example.

imageList = []
x = np.linspace(0, 2 * np.pi, 120)
y = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)
for i in range(60):
    x += np.pi / 15.
    y += np.pi / 20.
    imageList.append(np.sin(x) + np.cos(y))

#=========================================
# Animate Fake Images (in Jupyter)

def getImageFromList(x):
    return imageList[x]

fig = plt.figure(figsize=(10, 10))
ims = []
for i in range(len(imageList)):
    im = plt.imshow(getImageFromList(i), animated=True)
    ims.append([im])

ani = animation.ArtistAnimation(fig, ims, interval=50, blit=True, repeat_delay=1000)
plt.close()

# Show the animation
HTML(ani.to_html5_video())

#=========================================
# Save animation as video (if required)
# ani.save('dynamic_images.mp4')
Georgy
  • 12,464
  • 7
  • 65
  • 73
MosGeo
  • 1,012
  • 9
  • 9
3

If you have a list of images and want to animate through them, you can use something like this:

from keras.preprocessing.image import load_img, img_to_array
from matplotlib import animation
from IPython.display import HTML
import glob

%matplotlib inline

def plot_images(img_list):
  def init():
    img.set_data(img_list[0])
    return (img,)

  def animate(i):
    img.set_data(img_list[i])
    return (img,)

  fig = figure()
  ax = fig.gca()
  img = ax.imshow(img_list[0])
  anim = animation.FuncAnimation(fig, animate, init_func=init,
                                 frames=len(img_list), interval=20, blit=True)
  return anim

imgs = [img_to_array(load_img(i)) for i in glob.glob('*.jpg')]

HTML(plot_images(imgs).to_html5_video())
duhaime
  • 25,611
  • 17
  • 169
  • 224
  • 1
    In order for this to work, you have to download ffmpeg to your OS and then `plt.rcParams['animation.ffmpeg_path'] = '/usr/bin/ffmpeg'`. Replace `/usr/bin/ffmpeg'` with the path in your OS to the binary of ffmpeg. – Ruthvik Vaila Feb 03 '20 at 18:37
0

Thank to Kolibril. I finally can run animation on Jupyter and Google Colab. I modify some code which will generate animation of drawing random line instead.

import matplotlib.animation
import matplotlib.pyplot as plt
from itertools import count
import random

plt.rcParams["animation.html"] = "jshtml"
plt.rcParams['figure.dpi'] = 150  

fig, ax = plt.subplots()
x_value = []
y_value = []
index = count();
def animate(t):
    x_value.append(next(index))
    y_value.append(random.randint(0,10))
    ax.cla()
    ax.plot(x_value,y_value)
    ax.set_xlim(0,10)

matplotlib.animation.FuncAnimation(fig, animate, frames=10, interval = 500)

enter image description here