Making mesh skin transparent? - python

I wonder if mplot3d provides a way to alter the opacity of mesh face colors.
Below is a simple example for creating a 3Dplot using mplot3D and marching_squares method.
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
from mpl_toolkits.mplot3d import Axes3D
# create 3D numpy array, called mask
mask = np.zeros((3,3,3))
for i in np.arange(0,1):
for j in np.arange(0,1):
for k in np.arange(0,1):
mask[i,j,k] = 1
# use module (in this case, marching cubes) to find the vertices and faces of this 3D object
verts, faces, normals, values = marching_cubes_lewiner(mask)
fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(111, projection="3d")
ax.set_xlim(np.min(verts[:,0]), np.max(verts[:,0]))
ax.set_ylim(np.min(verts[:,1]), np.max(verts[:,1]))
ax.set_zlim(np.min(verts[:,2]), np.max(verts[:,2]))
mesh = Poly3DCollection(verts[faces])
mesh.set_edgecolor('k')
# set face color
mesh.set_facecolor('r')
ax.add_collection3d(mesh)
plt.tight_layout()
plt.show()
Is there a function to set the face color as transparent (i.e. can you alter face opacity?) I searched around and have not found the right function, as yet.

Related

3d contour with 3 variables and 1 variable as colour

I have three variables for my plot and I colour by the fourth variable. I have made a scatter plot via the following code, but I want a contour plot. My code:
import numpy as np
import matplotlib.pyplot as plt
a=np.linspace(4.0,14.0,3)
b=np.linspace(0.5,2.5,3)
c=np.linspace(0.0,1.0,3)
d=np.random.rand(len(a),len(b),len(c)) #colour by this variable
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
z,y,x=np.meshgrid(c,a,b)
img = ax.scatter(x, y, z, c=d, cmap='RdGy')
fig.colorbar(img, pad=0.2).set_label('colour')
ax.set_xlabel('c')
ax.set_ylabel('a')
ax.set_zlabel('b')
I want a filled contour instead of scatter plot. I know mayavi.mlab has this feature, but I cannot import mlab for some reason. Is there an alternative, or is there a better way of presenting this data?
Here is how I would present this 3-dimensional data. Each plot is a cross-section through the cube. This makes sense intuitively.
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(4.0, 14.0, 3)
y = np.linspace(0.5, 2.5, 3)
z = np.linspace(0.0, 1.0, 3)
data = np.random.rand(len(x), len(y), len(z))
fig, axes = plt.subplots(len(z), 1, figsize=(3.5, 9),
sharex=True,sharey=True)
for i, (ax, d) in enumerate(zip(axes, data.swapaxes(0, 2))):
ax.contour(x, y, d)
ax.set_ylabel('y')
ax.grid()
ax.set_title(f"z = {z[i]}")
axes[-1].set_xlabel('x')
plt.tight_layout()
plt.show()
My advice: 3D plots are rarely used for serious data visualization. While they look cool, it is virtually impossible to read any data points with any accuracy.
Same thing goes for colours. I recommend labelling the contours rather than using a colour map.
You can always use a filled contour plot to add colours as well.

How to color individual elements in matplotlib plot_trisurf

I have a triangular surface mesh, generated via marching cubes. I want to color the surface elements based on an arbitrary variable in my plot. I am currently using plot_trisurf, but as I read the documentation, it looks like the color is always based on the Z component, or else a constant? Can I not specify a color per element? Or is there a better plot routine to use? For example, something along the lines of the code below is what I am after, where the color is based on the 'value' output from the marching cubes. Thanks!
import numpy as np
import matplotlib.pyplot as plt
from skimage import measure
from skimage.draw import ellipsoid
from matplotlib import cm
# Generate a level set about zero of two identical ellipsoids in 3D
ellip_base = ellipsoid(6, 10, 16, levelset=True)
# Use marching cubes to obtain the surface mesh of these ellipsoids
verts, faces, normals, values = measure.marching_cubes_lewiner(ellip_double, 0)
fig = plt.figure(figsize=(20, 10))
ax = fig.add_subplot(111, projection='3d')
ax.plot_trisurf(verts[:, 0], verts[:,1], verts[:, 2], triangles=faces, cmap=cm.rainbow, color=values)
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("z")
ax.set_xlim(0, 24)
ax.set_ylim(0, 20)
ax.set_zlim(0, 32)
plt.tight_layout()
plt.show()
As noted by JohanC, in this question they reset the face colors after the fact. This works for me, as I already have an array of colors defined.
# set the face colors of the Poly3DCollection
p3dc.set_fc(colors)

Compute area of isosurface

I'm analyzing several files containing volumetric data reported as Gaussian Cube File Format (click here for the description).
I created this script in Python to compute and represent the isosurfaces using numpy and skimage:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
from skimage import measure
from skimage.draw import ellipsoid
import load_cube
# create an object and read in data from file
cube=load_cube.CUBE(gaussian_cube_file.cube)
# Obtain the surface mesh setting a specific isovalue (0.2)
verts, faces = measure.marching_cubes(cube.data, 0.2)
# Display resulting triangular mesh using Matplotlib.
fig = plt.figure(figsize=(10, 12))
ax = fig.add_subplot(111, projection='3d')
# Generate triangles
mesh = Poly3DCollection(verts[faces])
ax.add_collection3d(mesh)
ax.set_xlabel("x-axis: a = 6")
ax.set_ylabel("y-axis: b = 10")
ax.set_zlabel("z-axis: c = 16")
ax.set_xlim(0, 100)
ax.set_ylim(0, 100)
ax.set_zlim(0, 100)
plt.show()
Results from the previous script
The questions are: how I can compute the total area of all isosurfaces showed in the resulting plot? How I can color each triangle on the basis of its value?

matplotlib contours labels in 3D

Is there any way to put contours labels in 3D plots? Clabel is apparently not implemented in 3D
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
x,y = np.meshgrid(np.linspace(-1,1,10),np.linspace(-1,1,10))
z=-(x**2+y**2)
fig,ax = plt.subplots()
C=ax.contour(x,y,z)
ax.clabel(C)
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
C=ax.contour(x,y,z,zdir='z',offset=-2)
ax.clabel(C)
As clabel is not implemented and the return value is None, there is indeed no point in calling clabel() for the time being. You can use the C.levels attribute to manually add labels to the graph.
It won't have the nice inline feature that hides the contour under the labels though.

How to create surface plot from greyscale image with Matplotlib?

Let's say I have a greyscale image (size: 550x150 px). I load the image with matplolib
import matplotlib.pyplot as plt
import matplotlib.image as mp_img
image = mp_img.imread("my-cat.png")
plt.imshow(image)
plt.show()
Now, plt.imshow displays the image on the screen. But what I want is a surface plot of the greyscale values, something like this:
.Colour is not really a necessity, but it would be helpful for the height lines. I know, that I need a function of the form f(x,y) -> z to create the surface plot. So, I want to use the greyscale value at (x_pixel,y_pixel) in my image to get the value of f. This leads to my problem:
I'd like to do some interpolation (e.g. smoothing) of my image values during plotting. This depends also on the size of my meshgrid, so how do I control this? And,
how do I make a surface plot of the greyscale values from my image?
So this is pretty straightforward. Load the data, build the plot:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# generate some sample data
import scipy.misc
lena = scipy.misc.lena()
# downscaling has a "smoothing" effect
lena = scipy.misc.imresize(lena, 0.15, interp='cubic')
# create the x and y coordinate arrays (here we just use pixel indices)
xx, yy = np.mgrid[0:lena.shape[0], 0:lena.shape[1]]
# create the figure
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(xx, yy, lena ,rstride=1, cstride=1, cmap=plt.cm.gray,
linewidth=0)
# show it
plt.show()
Result:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import cv2
# generate some sample data
import scipy.misc
lena = cv2.imread("./data/lena.png", 0)
# downscaling has a "smoothing" effect
lena = cv2.resize(lena, (100,100))
# create the x and y coordinate arrays (here we just use pixel indices)
xx, yy = np.mgrid[0:lena.shape[0], 0:lena.shape[1]]
# create the figure
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(xx, yy, lena ,rstride=1, cstride=1, cmap=plt.cm.jet,
linewidth=0)
# show it
plt.show()
If you want to get color plot, change the code to: "cmap=plt.cm.jet".
So you can get something like this:
color plot

Categories

Resources