Daunter
Daunter

Reputation: 61

Animated 3D Surface Plots with Plotly

For research data visualisation I'd like to make an animated 3D surface plot in Plotly. The goal is to see the evolution of temperature in a box in function of time. But I don't know how to animate it.

At this moment I only have my plot at a give time. This is my code:

import plotly
import plotly.graph_objects as go
#import plotly.express as px
import pandas as pd
#import numpy as np

#read CSV
z_data = pd.read_csv('data1.csv')# Read data from a csv

fig = go.Figure(data=[go.Surface(z=z_data.values)])

#projection 2D
fig.update_traces(contours_z=dict(show=True, usecolormap=True,
                                  highlightcolor="tomato", project_z=True),
                                  colorscale='portland')

#fig
fig.update_layout(title='data HEATPILES', autosize=False, width=650, height=500, margin=dict(l=0, r=0, b=0, t=0))

#show
plotly.offline.plot(fig)

data1.csv is only this: data1.csv

But I have more data of the point's position in function of time and I would want to make an animated plot, so we could clearly see the evolution on time.

Here is the result at a given time Plot at a given time

I've seen on the plotly documentation that it's possible to make animation with px.scatter and px.line from here, and from there that we can do it with image, so I guess it would be possible with surface plot.

If you could help me do you I would much appreciate ! Thank you for your help,

Theophile

Upvotes: 6

Views: 4103

Answers (2)

ASAD ASHRAF KAREL
ASAD ASHRAF KAREL

Reputation: 71

After a good research I built this code to plot a proper smooth 3D surface plot. Simply put the data_frame into this function. You'll get a proper smoothen surface plot. Incase you face any error, just choose only those features from data_frame which are numerical.

'data_frame = data_frame.select_dtypes(include='number')'

from scipy import interpolate
from mpl_toolkits.mplot3d import axes3d, Axes3D

def surface(data_frame, title=None, title_x=0.5, title_y=0.9):

    X, Y = np.mgrid[-10:10:complex(0,data_frame.shape[0]), 
-10:10:complex(0,data_frame.shape[1])]
    Z = data_frame.values

    xnew, ynew = np.mgrid[-1:1:80j, -1:1:80j]
    tck = interpolate.bisplrep(X, Y, Z, s=0)
    znew = interpolate.bisplev(xnew[:,0], ynew[0,:], tck)

    fig = go.Figure(data=[go.Surface(z=znew)])
    fig.update_layout(template='plotly_dark', 
                      width=800, 
                      height=800,
                      title = title,
                      title_x = title_x, 
                      title_y = title_y
                     )
    return fig

Upvotes: 0

bitbang
bitbang

Reputation: 2182

Here is the full code for you:

import pandas as pd
import plotly.graph_objects as go

z_data = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/api_docs/mt_bruno_elevation.csv').values
print(z_data)
z_data2 = z_data * 1.1
z_data3 = z_data * 1.2
z_data4 = z_data * 0.5

z_data_list = []
z_data_list.append(z_data)
z_data_list.append(z_data2)
z_data_list.append(z_data3)
z_data_list.append(z_data4)
z_data_list.append(z_data)
z_data_list.append(z_data2)
z_data_list.append(z_data3)
z_data_list.append(z_data4)

fig = go.Figure(
    data=[go.Surface(z=z_data_list[0])],
    layout=go.Layout(updatemenus=[dict(type="buttons", buttons=[dict(label="Play", method="animate", args=[None])])]),
    frames=[go.Frame(data=[go.Surface(z=k)], name=str(i)) for i, k in enumerate(z_data_list)]
)

fig.update_traces(contours_z=dict(show=True, usecolormap=True, highlightcolor="tomato", project_z=True), colorscale='portland')

fig.update_layout(title='data HEATPILES', autosize=False, width=650, height=500, margin=dict(l=0, r=0, b=0, t=0))

def frame_args(duration):
    return {
            "frame": {"duration": duration},
            "mode": "immediate",
            "fromcurrent": True,
            "transition": {"duration": duration, "easing": "linear"},
        }

sliders = [
            {
                "pad": {"b": 10, "t": 60},
                "len": 0.9,
                "x": 0.1,
                "y": 0,
                "steps": [
                    {
                        "args": [[f.name], frame_args(0)],
                        "label": str(k),
                        "method": "animate",
                    }
                    for k, f in enumerate(fig.frames)
                ],
            }
        ]
    
fig.update_layout(sliders=sliders)
   
import plotly.io as pio

ii = 1
pio.write_html(fig, file="Live3D_"+str(ii)+".html", auto_open=True)
# plotly.offline.plot(fig)

Upvotes: 2

Related Questions