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

Matplotlib散点图动画异常:所有帧重复第一帧数据求助

解决Matplotlib 3D动画始终显示第一帧数据的问题

问题背景

使用Python结合Matplotlib读取一系列.xyz文件制作3D动画时,所有帧均显示第一帧的数据,但单独绘制单帧数据显示正常。.xyz文件格式如下(X/Y/Z三列):

0.0199995 0.02 0.0199999
0.0397943 0.02 0.0199997
0.059875 0.02 0.0199997
0.0799158 0.0199993 0.02
0.0999472 0.02 0.0199997
0.119963 0.0199992 0.02
0.139975 0.02 0.0199996
0.159982 0.02 0.0199996
0.179987 0.02 0.0199996
0.19999 0.0199992 0.02
0.219993 0.0199992 0.02
0.239994 0.0199992 0.02

用户原始代码:

for i in range(num_of_frames):
    # Reading the data from ./sph_sim_output/frame_%d.xyz, where %d is the frame number
    data_x, data_y, data_z = get_pt_data("./sph_sim_output/frame_000000.xyz", i)
    data.append((data_x, data_y, data_z)) #data_x, data_y, data_z are numpy vectors

fig = plt.figure()
ax = fig.add_subplot(projection="3d")
x, y, z = get_pt_data("./sph_sim_output/frame_000000.xyz", 0)
scatters = ax.plot(x,z,y) # I also tried this with ax.scatter

def update_pts(frame, data,scatters):
    x = data[frame][0]
    y = data[frame][1]
    z = data[frame][2]
    scatters._offset3d = (x, z, y)
    return scatters 

anim = animation.FuncAnimation(fig, update_pts, num_of_frames, fargs=(data,scatters), interval=60, blit=False)
output_filename = "waterdrop.mp4"
anim.save(output_filename, fps=60, bitrate=5000, writer=video_writer, extra_args=video_extra_args)
plt.close(fig)

问题排查与解决方案

1. 核心错误:数据读取阶段硬编码文件名

循环读取文件时,始终使用固定路径"./sph_sim_output/frame_000000.xyz",未替换为当前帧编号i,导致所有帧读取的都是第一帧数据。

修正方式:动态生成对应帧的文件名,匹配6位数字的命名格式:

data = []
for i in range(num_of_frames):
    # 生成带6位编号的文件名,比如frame_000001.xyz、frame_000002.xyz等
    filename = f"./sph_sim_output/frame_{i:06d}.xyz"
    data_x, data_y, data_z = get_pt_data(filename, i)
    data.append((data_x, data_y, data_z))

2. 动画更新函数的对象操作错误

原始代码中对绘图对象的更新方式不符合Matplotlib的规范,且未正确处理ax.plot返回的列表对象:

  • ax.plot返回的是Line3D对象的列表,直接操作scatters._offset3d无效,需取出列表中的单个元素
  • 直接修改内部属性_offset3d无法触发绘图重绘,应使用官方提供的更新方法

情况A:使用ax.scatter制作散点动画(推荐)

ax.scatter返回Path3DCollection对象,需用set_offsets和set_3d_properties更新数据:

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

fig = plt.figure()
ax = fig.add_subplot(projection="3d")
# 初始化第一帧数据
x0, y0, z0 = data[0]
scatter = ax.scatter(x0, z0, y0)  # 直接获取单个散点对象,而非列表

def update_pts(frame, data, scatter):
    x, y, z = data[frame]
    # 更新2D偏移量
    scatter.set_offsets(np.column_stack((x, z)))
    # 更新Y轴属性(对应代码中的y数据)
    scatter.set_3d_properties(y, 'y')
    return scatter,  # 返回元组,支持blit=True加速重绘

# 初始化动画
anim = animation.FuncAnimation(
    fig, 
    update_pts, 
    frames=num_of_frames, 
    fargs=(data, scatter), 
    interval=60, 
    blit=True
)

情况B:使用ax.plot制作折线动画

ax.plot返回Line3D对象列表,需取出单个对象后用set_data和set_3d_properties更新:

import matplotlib.pyplot as plt
from matplotlib import animation

fig = plt.figure()
ax = fig.add_subplot(projection="3d")
x0, y0, z0 = data[0]
line, = ax.plot(x0, z0, y0)  # 加逗号取出列表中的Line3D对象

def update_pts(frame, data, line):
    x, y, z = data[frame]
    line.set_data(x, z)
    line.set_3d_properties(y)
    return line,

anim = animation.FuncAnimation(
    fig, 
    update_pts, 
    frames=num_of_frames, 
    fargs=(data, line), 
    interval=60, 
    blit=True
)

3. 其他注意事项

  • 确保get_pt_data函数能正确读取对应帧的X/Y/Z数据
  • 启用blit=True可提升动画绘制效率
  • 保存动画时需确保video_writer(如FFMpegWriter)已正确配置

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 12:57:17