💸 Reduce costs by consolidating proprietary analytics & reporting software to open-source & Dash.
Challenge us to replace your analytics with Dash and reduce costs.

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'
                                                            )]
                                            )
                                      ]
                              )
                        ]
1 Like

@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.

2 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: