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

Jupyter Notebook中无法在循环中更新Matplotlib绘图(保留历史轨迹),也无法用animation子函数实现动画的问题

Jupyter Notebook中无法在循环中更新Matplotlib绘图(保留历史轨迹),也无法用animation子函数实现动画的问题

嘿,我看你在做粒子轨道模拟的时候卡在绘图更新这一步了——循环里得等跑完才能看到结果,用animation模块也没搞定是吧?先把你给出的代码整理好(看起来有点截断,我先补全关键逻辑),然后咱们一步步解决问题~

首先先看你现有的代码框架(补全了截断的受力计算部分):

# Import necessary Python libraries
import matplotlib.pyplot as plt
import numpy as np
%matplotlib notebook
from matplotlib import animation

# Define constants and initialize variables:
# All quantities are directly in SI units
# (To begin, I will take the Earth-Moon system as a reference)

G = 6.67e-11
R_12 = 384399 * 1000 + 3474 / 2 * 1000 + 6371 * 1000

# Attracting particle 1 (P1), kept fixed.
m1 = 5.97e24
x1 = 0; y1 = 0

# Attracted particle 2 (P2), moving around the fixed particle.
m2 = 7.35e22
x2_0 = x1 + R_12; y2_0 = y1 + 0
Vx2_0 = 0; Vy2_0 = 1000

# Simulation parameters
dt = 3600  # Time step
N = 24 * 30  # Number of iterations

# 补全你截断的受力计算逻辑
# 这里直接把计算逻辑写在循环里更直观

问题原因分析

  1. 循环里不更新绘图:Jupyter的Matplotlib默认是静态渲染,直接在循环里画完不触发刷新,就只能等整个循环结束才会一次性显示。而且如果每次循环都重新调用plt.plot(),会叠加很多图层,既卡又乱。
  2. animation模块用不对:可能是没正确定义初始化函数和帧更新函数,或者没设置blit=True优化渲染,再或者notebook的渲染模式没匹配上。

解决方案1:循环实时更新并保留轨迹

这种方法适合你想边跑模拟边看轨迹变化的场景,核心是复用同一个绘图对象,每次更新数据后手动刷新画布:

# 导入库(保持你的配置)
import matplotlib.pyplot as plt
import numpy as np
%matplotlib notebook
from matplotlib import animation

# 常量和初始化参数(和你的一致)
G = 6.67e-11
R_12 = 384399 * 1000 + 3474 / 2 * 1000 + 6371 * 1000
m1 = 5.97e24
x1 = 0; y1 = 0
m2 = 7.35e22
x2_0 = x1 + R_12; y2_0 = y1 + 0
Vx2_0 = 0; Vy2_0 = 1000
dt = 3600
N = 24 * 30

# 初始化绘图窗口,设置等比例坐标轴(不然轨道会变形)
fig, ax = plt.subplots()
ax.set_aspect('equal')
ax.set_xlim(-R_12*1.2, R_12*1.2)  # 留一点边距
ax.set_ylim(-R_12*1.2, R_12*1.2)

# 初始化绘图对象:轨迹线、当前粒子点、固定粒子
trajectory, = ax.plot([], [], 'b-', alpha=0.5)  # 半透明蓝色轨迹
current_particle, = ax.plot([], [], 'ro', markersize=5)  # 红色当前点
ax.plot(x1, y1, 'go', markersize=10, label='P1 (Earth)')  # 绿色固定粒子
ax.legend()

# 存储轨迹的数组,初始值是粒子初始位置
x2_history = [x2_0]
y2_history = [y2_0]
vx2, vy2 = Vx2_0, Vy2_0

# 开始循环模拟
for i in range(N):
    # 计算粒子P2的加速度(万有引力公式)
    r = np.sqrt((x2_history[-1] - x1)**2 + (y2_history[-1] - y1)**2)
    ax_x = -G * m1 * (x2_history[-1] - x1) / r**3
    ax_y = -G * m1 * (y2_history[-1] - y1) / r**3
    
    # 更新速度和位置
    vx2 += ax_x * dt
    vy2 += ax_y * dt
    new_x = x2_history[-1] + vx2 * dt
    new_y = y2_history[-1] + vy2 * dt
    
    # 追加到轨迹数组
    x2_history.append(new_x)
    y2_history.append(new_y)
    
    # 更新绘图对象的数据
    trajectory.set_data(x2_history, y2_history)
    current_particle.set_data(new_x, new_y)
    
    # 刷新画布并暂停一小段时间(让渲染跟上)
    fig.canvas.draw()
    plt.pause(0.01)  # 数值越小,动画越快,根据需要调整

解决方案2:用Matplotlib Animation模块实现更稳定的动画

如果需要更流畅的动画或者想保存动画文件,用FuncAnimation是更好的选择。建议先预计算所有轨迹数据,再逐帧渲染:

# 导入库
import matplotlib.pyplot as plt
import numpy as np
%matplotlib notebook
from matplotlib import animation

# 常量和初始化参数(和你的一致)
G = 6.67e-11
R_12 = 384399 * 1000 + 3474 / 2 * 1000 + 6371 * 1000
m1 = 5.97e24
x1 = 0; y1 = 0
m2 = 7.35e22
x2_0 = x1 + R_12; y2_0 = y1 + 0
Vx2_0 = 0; Vy2_0 = 1000
dt = 3600
N = 24 * 30

# 先预计算所有轨迹数据
x2_history = [x2_0]
y2_history = [y2_0]
vx2, vy2 = Vx2_0, Vy2_0

for i in range(N):
    r = np.sqrt((x2_history[-1] - x1)**2 + (y2_history[-1] - y1)**2)
    ax_x = -G * m1 * (x2_history[-1] - x1) / r**3
    ax_y = -G * m1 * (y2_history[-1] - y1) / r**3
    vx2 += ax_x * dt
    vy2 += ax_y * dt
    new_x = x2_history[-1] + vx2 * dt
    new_y = y2_history[-1] + vy2 * dt
    x2_history.append(new_x)
    y2_history.append(new_y)

# 初始化绘图窗口
fig, ax = plt.subplots()
ax.set_aspect('equal')
ax.set_xlim(-R_12*1.2, R_12*1.2)
ax.set_ylim(-R_12*1.2, R_12*1.2)
trajectory, = ax.plot([], [], 'b-', alpha=0.5)
current_particle, = ax.plot([], [], 'ro', markersize=5)
ax.plot(x1, y1, 'go', markersize=10, label='P1 (Earth)')
ax.legend()

# 初始化函数:设置初始空数据
def init():
    trajectory.set_data([], [])
    current_particle.set_data([], [])
    return trajectory, current_particle

# 帧更新函数:每帧渲染到当前帧的轨迹和粒子位置
def update(frame):
    trajectory.set_data(x2_history[:frame+1], y2_history[:frame+1])
    current_particle.set_data(x2_history[frame], y2_history[frame])
    return trajectory, current_particle

# 创建动画:frames是总帧数,interval是每帧间隔毫秒,blit=True优化渲染
anim = animation.FuncAnimation(
    fig, update, init_func=init,
    frames=N+1, interval=50, blit=True
)

# 如果需要保存动画,取消下面的注释(需要安装ffmpeg或pillow)
# anim.save('moon_orbit.mp4', writer='ffmpeg', fps=20)

几个关键注意事项

  • 确保%matplotlib notebook(或新版的%matplotlib widget)是在导入Matplotlib之前运行的,不然渲染模式不会生效。
  • 循环更新时,plt.pause()是必须的——它会触发画布刷新,没有这一步的话,绘图窗口会一直卡住。
  • 用FuncAnimation时,blit=True会只重绘变化的部分,动画会更流畅;如果显示有问题,可以试试把blit改成False。
  • 如果你用的是新版JupyterLab,推荐用%matplotlib widget替代%matplotlib notebook,交互体验更好。

备注:内容来源于stack exchange,提问作者MyDePain

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.17 10:18:03