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

如何用Plotly制作Scatter3D旋转动画并保存为GIF?解决存图异常

问题分析与解决

问题原因

  1. 空图问题:你保存的newframe仅包含相机视角的布局配置,没有关联原图表的3D数据与基础布局,因此渲染出的是空的2D坐标系。
  2. 图片生成时机:Jupyter单元格执行时会直接运行循环内的pio.write_image代码,这是后端执行逻辑,和前端Play按钮的交互无关,所以图片会在单元格运行时直接生成。

修正后的完整代码

以下是可正确生成旋转动画并导出rotate.gif的代码:

import plotly.graph_objects as go
import numpy as np
import plotly.io as pio
from PIL import Image
import os

# 确保图片保存目录存在
if not os.path.exists("images"):
    os.makedirs("images")

# 生成螺旋线数据
t = np.linspace(0, 10, 50)
x, y, z = np.cos(t), np.sin(t), t

# 创建基础3D散点图
fig = go.Figure(go.Scatter3d(x=x, y=y, z=z, mode='markers'))

# 初始相机视角
x_eye = -1.25
y_eye = 2
z_eye = 0.5

# 更新布局并添加播放按钮
fig.update_layout(
    title='Animation Test',
    width=600,
    height=600,
    scene_camera_eye=dict(x=x_eye, y=y_eye, z=z_eye),
    updatemenus=[dict(
        type='buttons',
        showactive=False,
        y=1,
        x=0.8,
        xanchor='left',
        yanchor='bottom',
        pad=dict(t=45, r=10),
        buttons=[dict(
            label='Play',
            method='animate',
            args=[None, dict(
                frame=dict(duration=50, redraw=True),  # 调整时长让动画更流畅
                transition=dict(duration=1),
                fromcurrent=True,
                mode='immediate'
            )]
        )]
    )]
)

# 定义绕Z轴旋转相机视角的函数
def rotate_z(x, y, z, theta):
    w = x + 1j * y
    return np.real(np.exp(1j * theta) * w), np.imag(np.exp(1j * theta) * w), z

# 生成动画帧并保存对应图片
frames = []
image_paths = []
for k, theta in enumerate(np.arange(0, 6.28, 0.1)):  # 0到2π,完成一周旋转
    xe, ye, ze = rotate_z(x_eye, y_eye, z_eye, -theta)
    # 更新当前图表的相机视角
    fig.update_layout(scene_camera_eye=dict(x=xe, y=ye, z=ze))
    # 添加帧到动画列表
    frames.append(go.Frame(layout=fig.layout))
    # 保存当前完整图表为图片
    img_path = f"images/images_{k+1:03d}.png"
    pio.write_image(fig, img_path, width=400, height=400, scale=1)
    image_paths.append(img_path)

# 给图表绑定动画帧
fig.frames = frames

# 显示交互式图表
fig.show()

# 将所有图片合成GIF
with Image.open(image_paths[0]) as img:
    img.save(
        'rotate.gif',
        save_all=True,
        append_images=[Image.open(p) for p in image_paths[1:]],
        duration=50,  # 每帧间隔时长(毫秒)
        loop=0  # 设置为0表示无限循环
    )

# 可选:清理临时图片文件
# for p in image_paths:
#     os.remove(p)

关键修正点

  • 保存完整图表:不再单独保存孤立的布局帧,而是每次更新相机视角后直接保存整个fig,确保图片包含3D散点数据。
  • 合成GIF文件:使用PIL库将生成的所有静态图片合并为GIF,指定每帧时长与循环模式。
  • 优化动画流畅度:将帧播放时长从5调整为50,避免动画过快导致视觉卡顿。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 16:42:28