3D Surface. plotly = hardest library for python from user pov? Spent 3 hours on trying to understand 3D surface, no progress

Hey. I wonder why they make such a complex software so beginners must spend so much time trying to figure out some basic functionality such as 3D surface.

I tried matplotlib to create a 3D surface based on 3 pandas dataframe columns - let’s say x, y and z. It took me about 10 minutes to find documentation, take an example from documentation and adapt it for my needs. The only drawback is that i can’t rotate it live, otherwise i would stop there already.

So i decided to try plotly. Their website is almost a joke. “New to plotly?” taking half of the page on every single page, which is annoying. Plust tons of links stacked on top of each other also on every page. It clutters the page. I’m not mentioning that after spending an hour i couldn’t find a well written documentation for 3D Surface plots.

Ended up looking on google. Not a single well written tutorial. The only website i found barely mentions that i need to pass data like this:

x = [1,2,3]
y = [1,2,3,4]
z = [ [ 1, 1, 1, 1 ], [ 4, 4, 4, 4 ], [ 4, 4, 9, 9 ] ]

and then goes

surface = go.Surface(x=x,y=y,z=z)
data = [surface]

etc.

My simple question is - is there a way to use surface plot like this:

x = [1,2,3]
y = [1,2,3]
z = [1,2,3]

like in matplotlib. Otherwise it is a horrible experience to figure out how to use that complexity such as i demonstrated above.

P.S. hope they will hire some nice content manager or something to make solid documentation and clear explanations because currently it is a mess.

Thank you!

1 Like

Plotly surface seems to be difficult when you don’t know the geometry of a surface.
The simplest equation of a surface is of the form z=f(x,y). For example,
z=x**2+y**2, x in [-2,2], y in [-2,2], is a paraboloid.

To define an instance of the Plotly surface, you have to define the lists (or numpy arrays) x, y, z:

x=np.linspace(-2,2, 100),
y=np.linspace(-2,2, 100)
X,Y=np.meshgrid(x,y)
Z=X**2+Y**2# z has the shape (100,100)
surf=dict(type='surface',
           x=x, 
           y=y,
           z=Z,
           colorscale='Viridis'
         )

or with the same effect:

surf=dict(type='surface',
          x=X,y=Y, z=Z,
          colorscale='Viridis',
          )

As long as the equation of a surface depends on (x,y), how could you expect to give its values z=f(x,y)
as a simple list?

What dou you mean in your example with:

 x = [1,2,3]
 y = [1,2,3]
 z = [1,2,3]???!!!!!!!!!!!!!!!!!!!!

1=f(1,1), 2=f(2,2), 3=f(3,3)??? (f can be whatever function of two variables you want)
From mathematical point of view this means that f is evaluated at the points on the line
x=y. It is so clear that a function of two variables restricted to a line is NOT a surface.

Even if the pairs (x,y) were not on a line, giving z of the same shape as x, y, you do not get a surface.
Take a look at this surface to understand better what I’m saying: https://plot.ly/~empet/13872/mount-st-helens/

By the way, matplotlib plot_surface works following the same rule: : https://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html#surface-plots

I answered your question although it should not have been, because you were impolite choosing such an user name. Please read here the forum guidelines: https://community.plotly.com/guidelines

Yes. Thank you. Regarding username, i fully agree. Couldn’t come up with something better at that moment, sorry for that!

The problem is that matplotlib did the job exactly as i thought in less than 10 minutes of playing with it. Now you say i need to know surface geometry etc. Ok, accepted.

What i meant by this:

x = [1,2,3]
y = [1,2,3]
z = [1,2,3]

z = function’s output in this case (for example x = 2; y = 2 so z = f(x=2,y=2) = also 2 in this case)

So i thought it should be easy to plot it this way (like in matplotlib). At least they could provide such option for
high-level users like me.

That’s why i wonder how to adapt my (pandas dataframe) columns of xyz to the structure required. Let’s say i have 100 x examples so 100 y correspondingly and 100 z. If you say i need that meshgrid transformation, i guess i also need Z^2 values which is 1000, while i have only 100.

But anyway thank you for clarifications! I’ll try to extract as much information from your answer as possible.

Edit: After looking at numpy’s meshgird and figuring out what it is it becomes clearer what is expected by plotly. But i wonder why can’t i just specify a lot of points like i mentiond using columns xyz and let the plotly figure out the rest (like matplotlib does it). This is the main question now (as well as is it possible to somehow still use my xyz columns to feed the surface plot).

. At least they could provide such option for
high-level users like me.

One reason that triplet data may may not be supported “out-of-the-box” yet is that x-y-z triplet data (like you have) is not necessarily evenly spaced. You’re right though that it would be nice for the Python library to handle this case, seems like a recipe like this one would work:

http://scipy-cookbook.readthedocs.io/items/Matplotlib_Gridding_irregularly_spaced_data.html

Plotly could perhaps provide a new FigureFactory like FF.TripletContour(X,Y,Z) or FF.TripletSurface(X,Y,Z). Triplets work with contour plots (a 2d version of surface plots), but they are quite slow for large numbers of triplets, so a Python approach might be better.

Yeah. It would be very nice! For now I ended up creating separate calculations to plot 3D surface using meshgrid and then calculating z value for each point in the grid.

Thank you all for assistance!

To everyone that has a point dataframe with x,y and z coordinates i figure this out:

from scipy.interpolate import griddata
import numpy as np
import plotly.graph_objs as go

Read in your data

x_vals = finger_dataframe[‘X’].values
y_vals = finger_dataframe[‘Y’].values
z_vals = finger_dataframe[‘Z’].values

Create a meshgrid of x, y values

x_range = np.linspace(x_vals.min(), x_vals.max(), 100)
y_range = np.linspace(y_vals.min(), y_vals.max(), 100)
x_mesh, y_mesh = np.meshgrid(x_range, y_range)

Interpolate the z values onto the meshgrid

z_mesh = griddata((x_vals, y_vals), z_vals, (x_mesh, y_mesh), method=‘cubic’)

Create a surface plot

fig = go.Figure(data=[go.Surface(x=x_mesh, y=y_mesh, z=z_mesh)])
fig.show()

this worked for me :slight_smile: