how to plot 3D mesh to depth map - python

I have a 3d triangle mesh
from torch_geometric.data import Data
want to plot it as depth map from top view, so the pixel value of (x,y) equals depth value.
there is a piece of code to plot, but I don't know how to calculate z value for each pair of (x,y)
plt.subplot()
x = data.x[:,1]
y = data.x[:,0]
X, Y = np.meshgrid(x, y)
plt.pcolor(data.x[:,1], data.x[:,0], data.x[:,2] * 255, cmap='RdBu', vmin=0, vmax=255)

You probably want to use tripcolor.
Simply cut off the z-component from your data and use z as the value in your plot:
tpc = ax1.tripcolor(triang, z, shading='flat')

Related

How does the Matplotlib trisurf plot work?

I am unable to understand from the matplotlib documentation(https://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html), the working of a trisurf plot. Can someone please explain how the X,Y and Z arguments result in a 3-D plot?
Let me talk you through this example taken from the docs
'''
======================
Triangular 3D surfaces
======================
Plot a 3D surface with a triangular mesh.
'''
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
n_radii = 8
n_angles = 36
# Make radii and angles spaces (radius r=0 omitted to eliminate duplication).
radii = np.linspace(0.125, 1.0, n_radii)
angles = np.linspace(0, 2*np.pi, n_angles, endpoint=False)
# Repeat all angles for each radius.
angles = np.repeat(angles[..., np.newaxis], n_radii, axis=1)
# Convert polar (radii, angles) coords to cartesian (x, y) coords.
# (0, 0) is manually added at this stage, so there will be no duplicate
# points in the (x, y) plane.
x = np.append(0, (radii*np.cos(angles)).flatten())
y = np.append(0, (radii*np.sin(angles)).flatten())
# Compute z to make the pringle surface.
z = np.sin(-x*y)
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_trisurf(x, y, z, linewidth=0.2, antialiased=True)
plt.show()
The x, y values are a range of values over which we calculate the surface. For each (x, y) pair of coordinates, we have a single value of z, which represents the height of the surface at that point.

Python: mapping colors across surface plots

Is there a way to map the color-scheme from one surface plot onto another?
For example, let's say I have:
surf_1 = ax.plot_surface(X, Y, Z, cmap='summer')
and
surf_2 = ax.plot_surface(X, Y, Z-Q, cmap='summer')
Is there a way to map the colorscheme for the surface defined by Z-Q onto the surface defined by Z? In other words, I want to visualize surf_1, but I want its surface to take on the colors defined by surf_2.
For context, I am trying to visualize the colors of the fluctuations of a parameter (Z) around a variable height (Q), where Q is not necessarily equal to 0.
EDIT: Is there a way I could extract the colors in surf_2 as an array, and use those colors as input colors for surf_1? Any suggestions would be much appreciated!
You can use ScalarMappable() function to create all colors to use as facecolors in the two surface plots. Here is the runnable code that demonstrates the steps to achieve what you want.
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
fig, ax = plt.subplots(subplot_kw={'projection': '3d'})
fig.set_size_inches([10, 8])
# Make up data for 2 surfaces
X = np.logspace(0, np.log10(16), 50)
Y = np.linspace(3, 6, 50)
Z = np.linspace(-1, 1, 50)
# Convert to 2d arrays
Z = np.outer(Z.T, Z) # 50x50
X, Y = np.meshgrid(X, Y) # 50x50
# Make use of `ScalarMappable()` for custom color
# This use Z to get a colormap for plotting the surface
C = np.linspace(-1, 1, Z.size).reshape(Z.shape)
colormap = "summer" # 'inferno' 'plasma' 'viridis'
scmap = plt.cm.ScalarMappable(cmap=colormap)
# for clarity, 2 surfaces are separated by some z shift
zshift = 80
# Upper-surface
# Note: ax.plot_surface(X, Y, Z*X+zshift, cmap=colormap)
# is almost equivalent with this
ax.plot_surface(X, Y, Z*X+zshift, facecolors=scmap.to_rgba(Z*X+zshift), shade=False)
# `shade=False` is used to suppress 3D shading
# Lower-surface
# Also use `facecolors=scmap.to_rgba(Z*X+zshift)`
# thus, equivalent with taking color from previous surface
ax.plot_surface(X, Y, Z, facecolors=scmap.to_rgba(Z*X+zshift), shade=False)
plt.show()
The output plot:

How to plot 3 arrays as a surface plot in Python

So, I've got three arrays of data, X, Y, and Z, each 225 numbers long. What I would like to do is to plot all three values at the same time on a surface plot. When I try to use
ax.plot_surface(X,Y,Z)
it tells me that Z needs to be a 2D array. I've looked it up and I've seen that it's possible to plot Z if it was a function of X and Y, but I need the first Z point to be associated with the first X and Y point etc. Is this possible in Python?
If your arrays are all 1-D, then I think what you want is
ax.plot_trisurf(X,Y,Z, triangles=tri.triangles, cmap=plt.cm.Spectral)
See more info at https://matplotlib.org/examples/mplot3d/trisurf3d_demo2.html
So, I've got three arrays of data, X, Y, and Z, each 225 numbers long. What I would like to do is to plot all three values at the same time on a surface plot.
So, from what i understood you want to plot a 3d surface plot.
But it seems you are only providing 3 1xn arrays. (in this case n == 255)
When plotting a surface plot, what you are doing in practice is getting each and every possible combination of a base (XY plane) and telling how high is a point Z on that given XY coordinates, hence Z is depicted as a function Z(i,j)
but I need the first Z point to be associated with the first X and Y point etc. Is this possible in Python?
Yes, but if you associate each Z point to the first X,Y and so on, you would only have the Z values for X==Y, which would be incomplete information for your surfaceplot!
A good (great) example of surface plot comes from matplotlib official docs
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
# Make data.
X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
# Plot the surface.
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
which results in:
What the code is actually doing:
Defining the input vectors X and Y (both range and interval)
Making a meshgrid out of those vectors (if unclear as to what a meshgrid is, print the output!)
Defining a function over the X,Y domain
Applying it to get Z
If you check, X,Y and Z are 2 dimensional arrays!
Hope it helps!

Plot of 3D matrix with colour scale - Python

I would like to plot a 3D matrix - essentially a box of numbers, each labelled by an x, y, z triad of coordinates- by assigning a different colour to each of the x, y, z point, according to its magnitude (for example, bigger numbers in red and smaller numbers in blue).
I cannot plot sections of the matrix, I rather need to plot the whole matrix together.
If we call matrix3D my matrix, its elements are built this way:
matrix3D[x][y][z] = np.exp(-(x**2+y**2+z**2))
How can I obtain the desired plot?
EDIT: Using Mayavi2 Contour3D(), I have tried to write the following:
from mayavi import mlab
X = np.arange(0, n_x, 1)
Y = np.arange(0, n_z, 1)
Z = np.arange(0, n_z, 1)
X, Y, Z = np.meshgrid(X, Y, Z)
obj = mlab.contour3d(X, Y, Z, matrix3D, contours=4, transparent=True)
where n_x, n_y, n_z are the dimension of the 3 axes. How can I actually see and/or save the image now?
If you need to plot the whole thing I think you're best taking a look at mayavi. This will let you plot a volume and you should be able to get the results you need.
I know you said you need to plot the whole thing at once, but this might still be of some use. You can use countourf to plot like this:
import numpy as np
import matplotlib.pyplot as plt
matrix3D = np.empty((10, 10, 10))
x = np.arange(10)
y = np.arange(10)
z = np.arange(10)
matrix3D[x][y][z] = np.exp(-(x**2+y**2+z**2))
fig = plt.figure()
ax = fig.add_subplot(plt.subplot(1, 1, 1))
ax.contourf(x, y, matrix3D[:, :, 3])
plt.show()
This gives you a slice of the 3D matrix (in this example the 4th slice).

How to plot a smooth 2D color plot for z = f(x, y)

I am trying to plot 2D field data using matplotlib. So basically I want something similar to this:
In my actual case I have data stored in a file on my harddrive. However for simplicity consider the function z = f(x, y). I want a smooth 2D plot where z is visualised using color. I managed the plotting with the following lines of code:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-1, 1, 21)
y = np.linspace(-1, 1, 21)
z = np.array([i*i+j*j for j in y for i in x])
X, Y = np.meshgrid(x, y)
Z = z.reshape(21, 21)
plt.pcolor(X, Y, Z)
plt.show()
However, the plot I obtain is very coarse. Is there a very simple way to smooth the plot? I know something similar is possible with surface plots, however, those are 3D. I could change the camera angle to obtain a 2D representation, but I am convinced there is an easier way. I also tried imshow but then I have to think in graphic coordinates where the origin is in the upper left corner.
Problem solved
I managed to solve my problem using:
plt.imshow(Z,origin='lower',interpolation='bilinear')
If you can't change your mesh granularity, then try to go with imshow, which will essentially plot any 2D matrix as an image, where the values of each matrix cell represent the color to make that pixel. Using your example values:
In [3]: x = y = np.linspace(-1, 1, 21)
In [4]: z = np.array([i*i+j*j for j in y for i in x])
In [5]: Z = z.reshape(21, 21)
In [7]: plt.imshow(Z, interpolation='bilinear')
Out[7]: <matplotlib.image.AxesImage at 0x7f4864277650>
In [8]: plt.show()
you can use contourf
plt.contourf(X, Y, Z)
EDIT:
For more levels (smoother colour transitions), you can use more levels (contours)
For example:
plt.contourf(X, Y, Z, 100)

Categories