How to animate a rotation of a 3D plot?

Iโ€™m trying to recreate what this guy did here:

https://codepen.io/etpinard/pen/mBVVyE?editors=0010

but in python.

Is it possible? So far I only found one resource that even mentioned rotation animation (this one), but the issue I have with it is that the anymation is either not smooth or too slow, when fiddling around with the parameters.

@wtfzambo Another option is to define an animated rotation via frames (see the offline animations here: https://plot.ly/python/animations/.

Rotation function:

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

Frame definition:

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))))))

and updatemenus for Play button:

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

@empet thanks! Iโ€™ll try to see if I can work something out.

On a side note, how do you post code that keeps its format?

@wtfzambo For code formatting follow this link https://help.github.com/en/articles/creating-and-highlighting-code-blocks.

2 Likes

Hi empet. Sorry to revive this thread but Iโ€™m in serious need of help.

Iโ€™ve been trying to adapt your sample code to mine but am having absolutely zero luck. Iโ€™m working with Scattergeo and have no idea where to put the frames you defined about. I tried putting them into go.Figure(frames=frames) but that didnโ€™t work. The button shows up fine and dandy but I for the life of me I canโ€™t get my globe to rotate at all. Can you help??

Current code is below:

# generate visualization
        colorsIdx = {'Permanent': 'rgb(224,189,0)', 'Itinerant': 'rgb(40,96,237)'}
        shapesIdx = {'Permanent': 'star', 'Itinerant': 'circle'}

        cols_colors = merge_v2['Type'].map(colorsIdx)
        cols_shapes = merge_v2['Type'].map(shapesIdx)

        x_eye, y_eye, z_eye = 1.25, 1.25, 0.8
        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(frames=frames)

        fig.add_trace(go.Scattergeo(
            lon=merge_v2['Longitude'],
            lat=merge_v2['Latitude'],
            hoverinfo='text',
            text=merge_v2['Installation'],  # TODO: add staff required
            mode='markers',
            marker=dict(
                size=6,
                color=cols_colors,
                symbol=cols_shapes,
                line=dict(
                    width=1,
                    color=cols_colors
                )
            )))

        for i in range(len(merge_v2)):
            fig.add_trace(
                go.Scattergeo(
                    lon=[merge_v2['Hub Longitude'][i], merge_v2['Longitude'][i]],
                    lat=[merge_v2['Hub Latitude'][i], merge_v2['Latitude'][i]],
                    mode='lines',
                    text=merge_v2['Installation'][i],
                    line=dict(width=1, color='red'),
                    opacity=1
                    #             opacity = float(merge_v2['Staff Required'][i]+1) / float(merge_v2['Staff Required'].max()+1),
                )
            )

        # list of projection types can be found http://etpinard.xyz/plotly-dashboards/map-projections/
        fig.update_layout(
            title_text='Staffing Model Test Network',
            showlegend=False,
            autosize=True,
            width=1500, height=800,
            margin=dict(l=100, r=100, b=40, t=50, pad=1, autoexpand=True),
            geo=go.layout.Geo(
                projection_type='orthographic',
                showland=True,
                showcountries=True,
                landcolor='rgb(243, 243, 243)',
                countrycolor='rgb(204, 204, 204)',
            ),
            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=False),
                                                             transition=dict(duration=0),
                                                             fromcurrent=True,
                                                             mode='immediate'
                                                             )]
                                            )
                                       ]
                              )
                         ]
        )
        fig.show(renderer="browser")
        print(fig)

Hello @empet,

I was able to use your code. Worked very well. However, its still slow and not smooth.

Is there a way to speed up the frames any further?

I think this was also a query by @wtfzambo. Did you manage to get a smoother, faster rotation?

Hi @ShreyasP,

The smoothness is controled by plotly.js. Read please this discussion: https://github.com/plotly/plotly.py/issues/1904
and follow the link at the end.

1 Like

Hi @empet,

so if I understand correctly I cannot use Plotly in Python to achieve this. I will have to try out one of the other libraries.

I am building a model plane with Gyroscopic sensors. I would like visualize the pitch, yaw and roll motion of the plane in Jupyter notebook based on the sensor input. Therefore i wanted to roll a 3D model of a plane along the X, Y & Z axes. I got the plane 3D model imported into Jupyter notebook. However, I am not sure how to proceed. Any ideas?

Hi @ShreyasP,

Good news: defining the 3D rotation by rotating the points of a Plotly trace, representing a 3D object, is much smoother than rotating the camera eye around that object.

In this notebook I detailed how you can define and animate the roll, pitch or yaw motion of an airplane:
https://chart-studio.plotly.com/~empet/15666.

3 Likes

Hi @empet,

This looks great. Just what I needed. Thank you soo much.

Regards,
Shreyas

@ShreyasP

I edited the above notebook because what I called roll motion is in fact the pitch one :slight_smile: