# Rotating 3D plots with plotly

**URL:** <https://community.plotly.com/t/rotating-3d-plots-with-plotly/34776>\
**Category:** 📊 Plotly Python\
**Created:** [February 10, 2020, 8:49pm UTC](https://community.plotly.com/t/rotating-3d-plots-with-plotly/34776 "2020-02-10T20:49:29Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![ChocolatePlotter](https://avatars.discourse-cdn.com/v4/letter/c/3d9bf3/32.png) [@ChocolatePlotter](https://community.plotly.com/u/ChocolatePlotter)\
**Post date:** [February 10, 2020, 8:49pm UTC](https://community.plotly.com/t/rotating-3d-plots-with-plotly/34776/1 "2020-02-10T20:49:29Z")

</div>

Hi,  
I’m working on making a rotating 3D plot in plotly. I found the following topic in this forum:  
[https://community.plotly.com/t/how-to-animate-a-rotation-of-a-3d-plot/20974](https://community.plotly.com/t/how-to-animate-a-rotation-of-a-3d-plot/20974)

The help looked really promising, but like the last person commenting I have some trouble determining exactly where the different parts are supposed to go! Please help me find out what I am doing incorrectly.

Here is my minimal working example:

```auto
import plotly.graph_objects as go
import numpy as np

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

data=[go.Scatter3d(x=x, y=y, z=z, mode='markers')]

x_eye = -1.25
y_eye = 2
z_eye = 0.5

layout = go.Layout(
         title='Animation Test',
         width=600,
         height=600,
         scene=dict(camera=dict(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=2, redraw=False), 
                                                             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 t in np.arange(0, 6.26, 0.1):
    xe, ye, ze = rotate_z(x_eye, y_eye, z_eye, -t)
    frames.append(dict(layout=dict(scene=dict(camera=dict(eye=dict(x=xe, y=ye, z=ze))))))

fig = go.Figure(data=data, layout=layout, frames=frames)

fig.show()

```

---

<div class="post-metadata">

**Author:** ![empet](https://avatars.discourse-cdn.com/v4/letter/e/977dab/32.png) [@empet](https://community.plotly.com/u/empet)\
**Post date:** [February 10, 2020, 9:21pm UTC](https://community.plotly.com/t/rotating-3d-plots-with-plotly/34776/2 "2020-02-10T21:21:27Z")

</div>

Hi @ChocolatePlotter,

I updated your code to work with Plotly 4.5 (the last version). Your code follows the animation code for Plotly \<=4.0.

```auto
import plotly.graph_objects as go
import numpy as np

# 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 t in np.arange(0, 6.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))))
fig.frames=frames

fig.show()

```

The rotation is implemented as a rotation of the observer (camera) around the plot. Since the trace definition (i.e. the Scatter3d for helix curve) is unchanged from frame to frame, we are only updating the observer(camera) position in go.Frame.

---

<div class="post-metadata">

**Author:** ![ChocolatePlotter](https://avatars.discourse-cdn.com/v4/letter/c/3d9bf3/32.png) [@ChocolatePlotter](https://community.plotly.com/u/ChocolatePlotter)\
**Post date:** [February 10, 2020, 9:34pm UTC](https://community.plotly.com/t/rotating-3d-plots-with-plotly/34776/3 "2020-02-10T21:34:20Z")

</div>

It worked like a charm! Thank you!

I eventually saw that I hadn’t defined the frames as go.Frame objects, but was very confused when that didn’t work either. Probably some version issues.

But no matter. Now it works! 🙂

---

<div class="post-metadata">

**Author:** ![empet](https://avatars.discourse-cdn.com/v4/letter/e/977dab/32.png) [@empet](https://community.plotly.com/u/empet)\
**Post date:** [February 11, 2020, 7:10am UTC](https://community.plotly.com/t/rotating-3d-plots-with-plotly/34776/4 "2020-02-11T07:10:35Z")

</div>

@ChocolatePlotter,

The first version didn’t work because in `go.Layout.updatemenus` the key `redraw` of the dict `frame` was set on `False`. Before some Plotly version it worked with this setting, but later it changed to `True` (notice that in the new working code it is `True`). Only scatter (2d) works without redrawing from frame to frame see: [https://plot.ly/~empet/14896](https://plot.ly/~empet/14896).

Your initial frame definition, using dicts, still works, but I changed it to `go.Frame` because it is more clear.

Update: Meanwhile I realized that an explanation of why the 3D rotation is expressed in complex numbers could be useful for code understanding. Here is an image I cropped from a LaTeX file I edited:

 ![Rotation-explanation](https://us1.discourse-cdn.com/flex024/uploads/plot/original/2X/d/de706c350706bd48a055e282d3bba9ab9b16c617.png)
