Jupyter Notebook函数内HTML(anim.to_jshtml())无法显示动画的问题
Jupyter Notebook中Matplotlib动画封装到函数后不显示的解决办法
这绝对是Jupyter玩Matplotlib动画时的经典坑!我来给你唠明白为啥会这样,还有两种直接在函数里显示动画的办法~
先明确问题现象
- 直接在单元格里写代码运行,
HTML(anim.to_jshtml())能正常弹出交互动画控件 - 把代码塞进函数里调用,就只显示一张静态图,动画完全出不来
- 但如果从函数返回
anim对象,再手动调用HTML(anim.to_jshtml()),又能正常显示
不工作的函数封装代码示例
from matplotlib import animation, rc from IPython.display import HTML import numpy as np import matplotlib.pyplot as plt def plot_anim_funct(): fig, ax = plt.subplots() ax.set_xlim((0, 2)) ax.set_ylim((-2, 2)) line, = ax.plot([], [], lw=2) def init(): line.set_data([], []) return (line,) def animate(i): x = np.linspace(0, 2, 1000) y = np.sin(2 * np.pi * (x - 0.01 * i)) line.set_data(x, y) return (line,) anim = animation.FuncAnimation(fig, animate, init_func=init, frames=100, interval=20, blit=True) HTML(anim.to_jshtml()) # 这里创建了HTML对象,但没让Jupyter渲染它 plot_anim_funct()
为啥会这样?
核心原因就是Jupyter的单元格输出逻辑:
- 当你在单元格里直接写
HTML(xxx),它是单元格的最后一个表达式,Jupyter会自动把这个对象的渲染结果输出 - 但在函数内部调用
HTML(xxx)时,这个对象只是在函数内部生成了,没有被返回或者主动输出,Jupyter根本不知道要渲染它 - 你看到的静态图,是
animation.FuncAnimation创建时Matplotlib自动生成的默认静态绘图,和动画控件没关系
解决办法:两种方式在函数内显示动画
办法1:主动返回HTML对象,让Jupyter渲染
这是你已经发现的方式,把HTML(anim.to_jshtml())作为函数返回值,调用函数时Jupyter就会自动渲染它:
from matplotlib import animation, rc from IPython.display import HTML import numpy as np import matplotlib.pyplot as plt def plot_anim_funct(): fig, ax = plt.subplots() ax.set_xlim((0, 2)) ax.set_ylim((-2, 2)) line, = ax.plot([], [], lw=2) def init(): line.set_data([], []) return (line,) def animate(i): x = np.linspace(0, 2, 1000) y = np.sin(2 * np.pi * (x - 0.01 * i)) line.set_data(x, y) return (line,) anim = animation.FuncAnimation(fig, animate, init_func=init, frames=100, interval=20, blit=True) # 返回HTML对象,让Jupyter渲染 return HTML(anim.to_jshtml()) # 调用函数,自动显示动画 plot_anim_funct()
办法2:在函数内部主动输出HTML对象
用IPython.display里的display()函数,直接在函数里把HTML动画控件输出,不用返回也能显示:
from matplotlib import animation, rc from IPython.display import HTML, display import numpy as np import matplotlib.pyplot as plt def plot_anim_funct(): fig, ax = plt.subplots() ax.set_xlim((0, 2)) ax.set_ylim((-2, 2)) line, = ax.plot([], [], lw=2) def init(): line.set_data([], []) return (line,) def animate(i): x = np.linspace(0, 2, 1000) y = np.sin(2 * np.pi * (x - 0.01 * i)) line.set_data(x, y) return (line,) anim = animation.FuncAnimation(fig, animate, init_func=init, frames=100, interval=20, blit=True) # 主动调用display输出动画控件 display(HTML(anim.to_jshtml())) # 直接调用函数就会弹出动画 plot_anim_funct()
额外小技巧:去掉多余的静态图
如果不想看到那个碍眼的静态图,可以在函数里加上plt.close(fig),把FuncAnimation生成的默认静态图关掉:
def plot_anim_funct(): fig, ax = plt.subplots() ax.set_xlim((0, 2)) ax.set_ylim((-2, 2)) line, = ax.plot([], [], lw=2) def init(): line.set_data([], []) return (line,) def animate(i): x = np.linspace(0, 2, 1000) y = np.sin(2 * np.pi * (x - 0.01 * i)) line.set_data(x, y) return (line,) anim = animation.FuncAnimation(fig, animate, init_func=init, frames=100, interval=20, blit=True) # 关闭当前figure,避免静态图输出 plt.close(fig) display(HTML(anim.to_jshtml()))
内容的提问来源于stack exchange,提问作者Marses
相关产品推荐
相关产品推荐

