You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多次调用Matplotlib.FuncAnimation制作多场景动画出现闪烁问题

解决Matplotlib动画闪烁问题,实现迭代法可视化

问题情况

我正在做一个教学演示工具,要展示迭代法一步步逼近方程根的过程。想用Matplotlib做动画,具体要实现三个步骤:

  • 在x=1.5处画垂直线,和曲线交于(1.5,9)
  • 过这个点画一条斜率为m的直线,同时删掉之前的垂直线
  • 暂停一会儿后删掉这条斜率直线

现在测试的代码里同时调用了两个FuncAnimation,结果动画闪得特别厉害,明显能看到两个动画在来回切换。

为啥会闪烁?

同时创建多个FuncAnimation实例,Matplotlib的动画渲染线程会互相冲突,两个动画各自抢着更新画布,画面就会频繁切换导致闪烁。

解决办法:用单个动画管所有步骤

不要搞多个动画实例,把所有阶段的逻辑都放到一个FuncAnimation里,通过帧的范围来区分不同的动画阶段。下面是修改后的代码:

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

fig, ax = plt.subplots()
# 先把基础曲线画好,不用在动画里重复画
x_curve = np.linspace(-3, 3, 200)
y_curve = x_curve ** 3 + 4 * x_curve ** 2 + x_curve - 6
ax.plot(x_curve, y_curve, label='$y=x^3+4x^2+x-6$', color='blue')
ax.legend()

# 初始化要用到的两条线:垂直线、斜率直线
vline, = ax.plot([], [], color='red', linestyle='--')
slope_line, = ax.plot([], [], color='green', linestyle='-')

# 设置坐标轴范围
ax.set_xlim(-3, 3)
ax.set_ylim(-10, 10)
ax.set_xlabel('x')
ax.set_ylabel('y')

# 划分各阶段的帧数,可根据需要调整速度
total_frames = 300
stage1_frames = 100  # 画垂直线的帧
stage2_frames = 100  # 删垂直线、画斜率直线的帧
stage3_frames = 50   # 暂停展示斜率直线的帧
stage4_frames = 50   # 删斜率直线的帧

def init():
    # 初始化时把两条线清空
    vline.set_data([], [])
    slope_line.set_data([], [])
    return [vline, slope_line]

def update(frame):
    x0 = 1.5
    y0 = x0 ** 3 + 4 * x0 ** 2 + x0 - 6  # 算出(1.5,9)这个点
    m = 19.75  # 这里用的是曲线在x=1.5处的切线斜率,你可以改成自己需要的斜率
    
    if frame < stage1_frames:
        # 阶段1:慢慢画出垂直线,从y=-10升到y0
        current_y = np.linspace(-10, y0, stage1_frames)[frame]
        vline.set_data([x0, x0], [-10, current_y])
        slope_line.set_data([], [])
    elif frame < stage1_frames + stage2_frames:
        # 阶段2:清空垂直线,画出斜率直线
        vline.set_data([], [])
        # 让斜率直线覆盖整个x轴范围,看得清楚
        x_slope = np.array([-3, 3])
        y_slope = m * (x_slope - x0) + y0
        slope_line.set_data(x_slope, y_slope)
    elif frame < stage1_frames + stage2_frames + stage3_frames:
        # 阶段3:暂停,保持当前画面不动
        pass
    else:
        # 阶段4:清空斜率直线
        slope_line.set_data([], [])
    
    return [vline, slope_line]

# 只创建一个动画实例,统一管理所有阶段
ani = FuncAnimation(fig, update, frames=total_frames,
                    init_func=init, blit=True, interval=30)

plt.show()

代码说明

  • 先画好基础曲线,避免动画过程中重复绘制导致闪烁
  • 用单个动画实例,通过帧的区间判断当前处于哪个阶段,执行对应的操作
  • 每个阶段只更新需要变化的元素,其他元素保持状态不变
  • blit=True可以优化渲染,减少不必要的重绘,进一步降低闪烁

内容的提问来源于stack exchange,提问作者Soham

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 17:18:18