3D surface plot in Python using plotly - python

I have a question about how the plotly surface code works.
I've got the data from dataframe to plot surface 3D graph , 1D array of x , y and z
example :
x (temperatures) = [26,25,24,29,21,20,21,21,26]
y (humidity) = [50,60,50,40,50,70,80,90,90]
z (power consumption) = [12,13,14,11,11,10,11,12,15]
I need to plot each point (ex: x1,y1,z1) to be a surface and I have used this code
import plotly.graph_objects as go
import numpy as np
#x,y,z from above
fig = go.Figure(data = go.Surface(z=z,
x=x,
y=y))
fig.update_traces(contours_z = dict(show = True , usecolormap = True ,
highlightcolor = 'limegreen' , project_z = True))
fig.update_layout(title = 'Linear')
fig.show()
but it doesn't show anything.
(I also known that z need to be 2D array but I don't know why it is)
How can I fix this problem?
Thank you

My answer consists of two parts:
How you can plot this data in 3d.
What's needed to create a 3d surface plot.
Plotting your data in 3D
With the data you have - three vectors of x, y, and z, you can easily create a 3D scatter plot:
fig = go.Figure(data=[go.Scatter3d(x=x, y=y, z=z,
mode='markers')])
fig.show()
Here's what it looks like, and you can rotate it and swivel it in all directions.
3D Surface Plot
To create a 3D surface plot, you need a z-value for each combination of a and y. Think of a surface plot as a map. For each point (x,y) on the map, you need to provide the altitude (z) at that point, so that plotly can create the surface you're looking for.

Related

How can I plot a square and colour map it using a 2d array of values

For example I have 2 arrays that are x, y co-ordinates and a square grid that corresponds to each point.
x = np.linspace(0,10,50)
y = np.linspace(-5,12,50)
square = np.empty((50,50))
I'm trying to plot out a square surface that is cmaped by the square values. I did get it to work with surface plotting but the issue is the surface has an irregular shape and I can't plot some scatter points over it, without visibility issues.
I'm wondering if there's a way to get it to work as a 2d plot rather than 3d as the Z cordinate can just be replaced by a cmap and make sense. Any suggestions?
So I did find a solution:
x_mesh, y_mesh = np.meshgrid(x,y)
fig = plt.figure(dpi = 200)
plt.scatter(x_mesh,y_mesh, c = square, cmap = 'viridis')
plt.show
With enough points it gets a good surface.

Plotly vertical 3D surface plot in z-x plane not showing up

I want to plot a plane in the z-x plane, but I am having problems.
I am able to successfully plot the plane into the z-y plane with the following code:
import plotly.graph_objects as go
import numpy as np
x1 = np.zeros(100)
y1 = np.linspace(-5, 5, 100)
z1 = np.linspace(-2.5, 2.5, 50)
rc = np.random.rand(100,50) # random surface colors
plane = go.Surface(x=x1, y=y1, z=np.array([z1] * len(x1)), surfacecolor=rc)
figure = go.Figure()
figure.add_traces([plane])
figure.show()
This gives the following figure:
To plot the same in the z-x plane, this should be achievable (from my understanding) by simply swapping the x and y parameters of the surface plot:
plane = go.Surface(x=y1, y=x1, z=np.array([z1] * len(x1)), surfacecolor=rc)
However, now the surface plot never shows up in the figure.
There is no error message or warning and looking at the data representation, all the data fields seem to be set the way they should.
So what am I missing?
Thanks for your feedback
I was having the exact same problem and google sent me here. Searching for a solution, I came across this answer: https://stackoverflow.com/a/62504443
According to the answer, you have to transpose the array of the z argument.
plane = go.Surface(x=y1, y=x1, z=np.array([z1] * len(x1)).T, surfacecolor=rc)
For the surface coloring you would have change to
rc = np.random.rand(100,100)

Plot a 3D surface plot based on points from ginput using Matplotlib

I am trying to plot peaks (3D topographical peaks) on ginput() points specified by a user. These peaks have to be in the form of a 3D surface plot as shown in the example image on this link 3D surface plot peaks .So far I have managed to acquire the points from the ginput() function and separated them into two different arrays one with x coordinates another with y coordinates. How do I go about plotting these peaks on these points using the cosine wave?
I am still new to python so I have written a few lines of pseudo code of what I am trying to achieve in order to try and add more clarity to my question.
import sys, numpy as np, matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
pts = []
fig = plt.figure()
ax = fig.gca(projection='3d')
Npeaks = input(' Enter your number of peaks here..')
pts = plt.ginput(Npeaks)
x=map(lambda x: x[0],pts) # creating an array with x coordinates
y=map(lambda x: x[1],pts) # creating an array with y coordinates
Pseudo code of the code I am trying to achieve
if number_of_peaks > 0 :
ax.plot_surface( plot a peak at those points )
else:
sys.exit()
ax.set_xlabel('X')
ax.set_xlim(value , value )
ax.set_ylabel('Y')
ax.set_ylim( value , value )
ax.set_zlabel('Z')
ax.set_zlim( value , value )
plt.show()

How do I use Matplotlib pyplot pcolor to provide distinct color to each grid in my plot

I have built some fairly simple logarithmic matplotlib scatter plots. I am happy with the results thus far, but I need to change the color of each grid area.
Current Plot:
I would like to understand how I could do the following:
I appreciate any help. Thanks.
Plot a small image underneath the scatter plot, with an integer indicating the tile color. You can then use pcolor to plot the image, with edgecolors to define the borders. The code below does this, with cell color defined as the maximum of cell index i, j, which happens to match your grid.
import numpy as np
import matplotlib.pyplot as plt
# define grid
nx, ny = 6, 5
x, y = np.arange(nx), np.arange(ny)
xx, yy = np.meshgrid(x, y)
z = np.maximum(xx, yy)
# create random points
npoints = 30
data_x = 10**(np.random.rand(npoints)*nx)
data_y = 10**(np.random.rand(npoints)*ny-1)
# plot grid then points
plt.pcolor(10.**x, 10.**(y-1), z, edgecolors='k')
plt.loglog(data_x, data_y, '.w')
plt.axis([1,10**5,0.1,10**3])
plt.show()
Note that you could also use zorder=n to force the scatter plot above the image.

Best way to plot a 3D matrix in python

I am trying to visualize 3D data. This is a full 3D matrix: each (x,y,z) coordinate has a value, unlike a surface or a collection of individual data vectors. The way I am trying to do this is to plot an opaque cube, where each edge of the cube shows the sum of the data over the orthogonal dimension.
Some example data -- basically, a blob centered at (3,5,7):
import numpy as np
(x,y,z) = np.mgrid[0:10,0:10, 0:10]
data = np.exp(-((x-3)**2 + (y-5)**2 + (z-7)**2)**(0.5))
edge_yz = np.sum(data,axis=0)
edge_xz = np.sum(data,axis=1)
edge_xy = np.sum(data,axis=2)
So the idea would be here to generate a 3D plot that showed a cube; each surface of the cube would show the appropriate 2D matrix edge_*. This would be like plotting 3 4-sided polygons at the appropriate 3D positions (or 6 if you did the back sides of the cube as well) except that each polygon is actually a matrix of values to be plotted in color.
My best approximation at the moment is to compute larger matrices that contained skewed versions of edge, and concatenate these into a single, larger 2D matrix, and imshow() that larger matrix. Seems pretty clumsy, and does a lot of work that some engine in matplotlib or m3plot or something I'm sure already does. It also only works to view a static image at a single view angle, but that's not something I need to overcome at the moment.
Is there a good way to plot these cube edges in a true 3D plot using an existing python tool? Is there a better way to plot a 3D matrix?
Falko's suggestion to use contourf works with a bit of finagling. It's a bit limited since at least my version of contourf has a few bugs where it sometimes renders one of the planes in front of other planes it should be behind, but for now only plotting either the three front or three back sides of the cube will do:
import numpy as np
import math
import matplotlib.pyplot as plot
import mpl_toolkits.mplot3d.axes3d as axes3d
def cube_marginals(cube, normalize=False):
c_fcn = np.mean if normalize else np.sum
xy = c_fcn(cube, axis=0)
xz = c_fcn(cube, axis=1)
yz = c_fcn(cube, axis=2)
return(xy,xz,yz)
def plotcube(cube,x=None,y=None,z=None,normalize=False,plot_front=False):
"""Use contourf to plot cube marginals"""
(Z,Y,X) = cube.shape
(xy,xz,yz) = cube_marginals(cube,normalize=normalize)
if x == None: x = np.arange(X)
if y == None: y = np.arange(Y)
if z == None: z = np.arange(Z)
fig = plot.figure()
ax = fig.gca(projection='3d')
# draw edge marginal surfaces
offsets = (Z-1,0,X-1) if plot_front else (0, Y-1, 0)
cset = ax.contourf(x[None,:].repeat(Y,axis=0), y[:,None].repeat(X,axis=1), xy, zdir='z', offset=offsets[0], cmap=plot.cm.coolwarm, alpha=0.75)
cset = ax.contourf(x[None,:].repeat(Z,axis=0), xz, z[:,None].repeat(X,axis=1), zdir='y', offset=offsets[1], cmap=plot.cm.coolwarm, alpha=0.75)
cset = ax.contourf(yz, y[None,:].repeat(Z,axis=0), z[:,None].repeat(Y,axis=1), zdir='x', offset=offsets[2], cmap=plot.cm.coolwarm, alpha=0.75)
# draw wire cube to aid visualization
ax.plot([0,X-1,X-1,0,0],[0,0,Y-1,Y-1,0],[0,0,0,0,0],'k-')
ax.plot([0,X-1,X-1,0,0],[0,0,Y-1,Y-1,0],[Z-1,Z-1,Z-1,Z-1,Z-1],'k-')
ax.plot([0,0],[0,0],[0,Z-1],'k-')
ax.plot([X-1,X-1],[0,0],[0,Z-1],'k-')
ax.plot([X-1,X-1],[Y-1,Y-1],[0,Z-1],'k-')
ax.plot([0,0],[Y-1,Y-1],[0,Z-1],'k-')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plot.show()
plot_front=True
plot_front=False
Other data (not shown)
Take a look at MayaVI. The contour3d() function may be what you want.
Here's an answer I gave to a similar question with an example of the code and resulting plot https://stackoverflow.com/a/24784471/3419537

Categories