如何使用plotly创建Scatter3D绘图的旋转动画并将其另存为gif?

问题描述 投票:0回答:1

使用 jupyter 中的plotly,我正在创建一个 Scatter3D 图,如下所示:

# Configure the trace.
trace = go.Scatter3d(
    x=x,
    y=y,
    z=z,
    mode='markers',
    marker=dict(color=colors, size=1)
)

# Configure the layout.
layout = go.Layout(
    margin={'l': 0, 'r': 0, 'b': 0, 't': 0},
    height = 1000,
    width = 1000
)

data = [trace]

plot_figure = go.Figure(data=data, layout=layout)

# Render the plot.
plotly.offline.iplot(plot_figure)

如何旋转这样生成的绘图,以便从中创建 gif 视频,即存储为 gif 文件,如

rotate.gif
,它显示旋转绘图的动画?

根据给出的评论,我创建了这段代码(完整的工作示例):

import plotly.graph_objects as go
import numpy as np
import plotly.io as pio


# Helix equation
t = np.linspace(0, 10, 50)
x, y, z = np.cos(t), np.sin(t), t

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=5, redraw=True), 
                                                             transition=dict(duration=1),
                                                             fromcurrent=True,
                                                             mode='immediate'
                                                            )]
                                            )
                                      ]
                              )
                        ]
)


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=[]
for k, t in enumerate(np.arange(0, 6.26, 0.1)):
    xe, ye, ze = rotate_z(x_eye, y_eye, z_eye, -t)
    newframe = go.Frame(layout=dict(scene_camera_eye=dict(x=xe, y=ye, z=ze)))
    frames.append(newframe)
    pio.write_image(newframe, f"images/images_{k+1:03d}.png", width=400, height=400, scale=1)
fig.frames=frames

fig.show()

运行时没有错误,并且当我按下“播放”时会旋转场景,但是保存的图像仅显示一个空的 2D 坐标系:

但不是我实际看到的旋转。这些图像似乎是在我执行 jupyter 笔记本中的单元格时创建的,而不是在我按“播放”后创建的。似乎有两个图形,一个我可以看到旋转,另一个是保存到文件中的空 2D 坐标系的图像......

python animation 3d plotly jupyter
1个回答
0
投票

下面这个更接近。不过,我怀疑我们需要解决尺寸和缩放问题。

import plotly.graph_objects as go
import numpy as np
import plotly.io as pio

# Helix equation
t = np.linspace(0, 10, 50)
x, y, z = np.cos(t), np.sin(t), t

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=5, redraw=True), 
                                                             transition=dict(duration=0),
                                                             fromcurrent=True,
                                                             mode='immediate'
                                                            )]
                                            )
                                      ]
                              )
                        ]
)


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=[]
for k,t in enumerate(np.arange(0, 1.26, 0.1)):
    xe, ye, ze = rotate_z(x_eye, y_eye, z_eye, -t)
    frames.append(go.Frame(layout=dict(scene_camera_eye=dict(x=xe, y=ye, z=ze))))
    current_fig = go.Figure(fig.data, layout=dict(scene_camera_eye=dict(x=xe, y=ye, z=ze)))
    pio.write_image(current_fig, f"images/images_{k+1:03d}.png", width=400, height=400, scale=1)
fig.frames=frames

fig.show()

说明:

在您更新的代码中,看起来您正在使用此代码并尝试根据我在

此处
指出的pio.write_image()的使用添加图形的保存。 (我真的不明白
Play
按钮对于您的情况的用途,除了它可以让您像这样检查开发中的工作情况。虽然它可能是您最终想要分享的混乱动画。)
但是,您并没有完全收集到发送到
.png
文件的帧所需的内容。

具有以下内容:

newframe = go.Frame(layout=dict(scene_camera_eye=dict(x=xe, y=ye, z=ze)))
frames.append(newframe)
pio.write_image(newframe, f"images/images_{k+1:03d}.png", width=400, height=400, scale=1)

您正在向

pio.write_image
发送一个框架对象。我认为您想要带有原始数据的图形,因此您需要使用类似于 此 Plotly 问题“获取动画帧”的回复中所涵盖的内容来重建该图形。

所以现在我更改了代码以使用您用于框架的布局,但使用该布局和原始数据制作一个图形。

© www.soinside.com 2019 - 2024. All rights reserved.