Chipmuenk
Chipmuenk

Reputation: 697

Matplotlib animation in Jupyter notebook creates additional empty plot

I've started to create a series of interactive notebooks for a DSP lecture. So far, I've managed to copy & implement the MWE pasted below. However, in addition to the matplotlib figure containing the animation, I'm always getting an empty Matplotlib window. Any ideas how to suppress this behaviour?

python: 3.6.3 matplotlib: 2.0 and 2.1 IPython: 5.3.0 OS: Win 7 64 bit

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt

from matplotlib import animation
from IPython.display import HTML

plt.rcParams['figure.figsize'] = (5,3)
plt.rcParams['figure.dpi'] = 100
plt.rcParams['savefig.dpi'] = 100
plt.rcParams["animation.html"] = "jshtml"  # for matplotlib 2.1 and above, uses JavaScript
#plt.rcParams["animation.html"] = "html5" # for matplotlib 2.0 and below, converts to x264 using ffmpeg video codec
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 = animation.FuncAnimation(fig, animate, frames=len(t))
ani

The notebook can also be viewed under:

https://github.com/chipmuenk/dsp_fpga/blob/master/notebooks/01_LTI/MWE_animation.ipynb

In the static rendering at github, only the empty plot window shows, not the JavaScript animation.

Upvotes: 17

Views: 14303

Answers (3)

ftracefull
ftracefull

Reputation: 151

You can add plt.close() before the last line.

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt

from matplotlib import animation
from IPython.display import HTML

plt.rcParams['figure.figsize'] = (5,3)
plt.rcParams['figure.dpi'] = 100
plt.rcParams['savefig.dpi'] = 100
plt.rcParams["animation.html"] = "jshtml"  # for matplotlib 2.1 and above, uses JavaScript
#plt.rcParams["animation.html"] = "html5" # for matplotlib 2.0 and below, converts to x264 using ffmpeg video codec
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 = animation.FuncAnimation(fig, animate, frames=len(t))
plt.close()
ani

Upvotes: 15

benjimin
benjimin

Reputation: 4890

Here is an alternative example:

%matplotlib inline
from matplotlib import animation, pyplot as plt
import numpy as np
plt.rc('animation', html='html5')

data = np.random.random(20)
fig = plt.figure()

ax = fig.add_subplot(111)   
ax.plot(data) # draw background

anim = animation.ArtistAnimation(fig, [[ax.scatter(x, y)] for x, y in enumerate(data)])
anim

The result (anim) is shown animated, but the potential side-effect is an additional display of the static frame. This side-effect vanishes if the plt.figure call occurs in a separate cell before the add_subplot method.

This works because (like ImportanceOfBeingErnest said) the creation of a new figure causes the side effect of displaying a static image (depicting how the figure was left at the conclusion of the current cell evaluation in the notebook). But if nothing has been populated onto the figure yet (not even the axes), you prevent any image from being displayed (without needing jupyter magic to suppress it).

Upvotes: 3

ImportanceOfBeingErnest
ImportanceOfBeingErnest

Reputation: 339112

This has nothing to do with an animation.

The lines

%matplotlib inline
import matplotlib.pyplot as plt
fig, ax = plt.subplots()

will create an output with an empty figure.

You may prevent the output of a cell in jupyter notebook using %%capture.

Cell1:

%%capture
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.animation
plt.rcParams["animation.html"] = "jshtml"
import numpy as np

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

fig, ax = plt.subplots()
h = 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))

Cell2:

ani

enter image description here

Upvotes: 18

Related Questions