简体   繁体   English

如何在 matplotlib mplot3D 或类似工具中显示 3D 阵列等值面的 3D 图?

[英]How to display a 3D plot of a 3D array isosurface in matplotlib mplot3D or similar?

I have a 3-dimensional numpy array.我有一个 3 维 numpy 数组。 I'd like to display (in matplotlib) a nice 3D plot of an isosurface of this array (or more strictly, display an isosurface of the 3D scalar field defined by interpolating between the sample points).我想显示(在 matplotlib 中)这个数组的等值面的一个很好的 3D 图(或者更严格地说,显示通过在样本点之间插值定义的 3D 标量场的等值面)。

matplotlib's mplot3D part provides nice 3D plot support, but (so far as I can see) its API doesn't have anything which will simply take a 3D array of scalar values and display an isosurface. matplotlib 的 mplot3D 部分提供了很好的 3D 绘图支持,但是(据我所知)它的 API 没有任何可以简单地采用标量值的 3D 数组并显示等值面的东西。 However, it does support displaying a collection of polygons, so presumably I could implement the marching cubes algorithm to generate such polygons.然而,它确实支持显示多边形的集合,所以大概我可以实现行进立方体算法来生成这样的多边形。

It does seem quite likely that a scipy-friendly marching cubes has already been implemented somewhere and that I haven't found it, or that I'm missing some easy way of doing this.似乎很可能已经在某处实现了对 scipy 友好的行进立方体,而我还没有找到它,或者我错过了一些简单的方法来做到这一点。 Alternatively I'd welcome any pointers to other tools for visualising 3D array data easily usable from the Python/numpy/scipy world.或者,我欢迎任何指向其他工具的指针,用于可视化可从 Python/numpy/scipy 世界轻松使用的 3D 数组数据。

Just to elaborate on my comment above, matplotlib's 3D plotting really isn't intended for something as complex as isosurfaces.只是为了详细说明我上面的评论,matplotlib 的 3D 绘图实际上并不适用于像等值面这样复杂的东西。 It's meant to produce nice, publication-quality vector output for really simple 3D plots.它旨在为非常简单的 3D 绘图生成漂亮的、出版质量的矢量输出。 It can't handle complex 3D polygons, so even if implemented marching cubes yourself to create the isosurface, it wouldn't render it properly.它无法处理复杂的 3D 多边形,因此即使自己实现了行进立方体来创建等值面,它也无法正确渲染。

However, what you can do instead is use mayavi (it's mlab API is a bit more convenient than directly using mayavi), which uses VTK to process and visualize multi-dimensional data.但是,您可以做的是使用mayavi (它的mlab API比直接使用mayavi 方便一点),它使用VTK来处理和可视化多维数据。

As a quick example (modified from one of the mayavi gallery examples):作为一个快速示例(从 mayavi 库示例之一修改):

import numpy as np
from enthought.mayavi import mlab

x, y, z = np.ogrid[-10:10:20j, -10:10:20j, -10:10:20j]
s = np.sin(x*y*z)/(x*y*z)

src = mlab.pipeline.scalar_field(s)
mlab.pipeline.iso_surface(src, contours=[s.min()+0.1*s.ptp(), ], opacity=0.3)
mlab.pipeline.iso_surface(src, contours=[s.max()-0.1*s.ptp(), ],)

mlab.show()

在此处输入图片说明

Complementing the answer of @DanHickstein, you can also use trisurf to visualize the polygons obtained in the marching cubes phase.补充@DanHickstein 的答案,您还可以使用trisurf来可视化在行进立方体阶段获得的多边形。

import numpy as np
from numpy import sin, cos, pi
from skimage import measure
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
   
   
def fun(x, y, z):
    return cos(x) + cos(y) + cos(z)
    
x, y, z = pi*np.mgrid[-1:1:31j, -1:1:31j, -1:1:31j]
vol = fun(x, y, z)
iso_val=0.0
verts, faces = measure.marching_cubes(vol, iso_val, spacing=(0.1, 0.1, 0.1))

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_trisurf(verts[:, 0], verts[:,1], faces, verts[:, 2],
                cmap='Spectral', lw=1)
plt.show()

在此处输入图片说明

Update: May 11, 2018更新:2018 年 5 月 11 日

As mentioned by @DrBwts, now marching_cubes return 4 values.正如@DrBwts 所提到的,现在 Marching_cubes 返回 4 个值。 The following code works.以下代码有效。

import numpy as np
from numpy import sin, cos, pi
from skimage import measure
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D


def fun(x, y, z):
    return cos(x) + cos(y) + cos(z)

x, y, z = pi*np.mgrid[-1:1:31j, -1:1:31j, -1:1:31j]
vol = fun(x, y, z)
iso_val=0.0
verts, faces, _, _ = measure.marching_cubes(vol, iso_val, spacing=(0.1, 0.1, 0.1))

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_trisurf(verts[:, 0], verts[:,1], faces, verts[:, 2],
                cmap='Spectral', lw=1)
plt.show()

Update: February 2, 2020更新:2020 年 2 月 2 日

Adding to my previous answer, I should mention that since then PyVista has been released, and it makes this kind of tasks somewhat effortless.除了我之前的回答之外,我应该提到PyVista 从那时起已经发布,它使此类任务变得有些轻松。

Following the same example as before.遵循与之前相同的示例。

from numpy import cos, pi, mgrid
import pyvista as pv

#%% Data
x, y, z = pi*mgrid[-1:1:31j, -1:1:31j, -1:1:31j]
vol = cos(x) + cos(y) + cos(z)
grid = pv.StructuredGrid(x, y, z)
grid["vol"] = vol.flatten()
contours = grid.contour([0])

#%% Visualization
pv.set_plot_theme('document')
p = pv.Plotter()
p.add_mesh(contours, scalars=contours.points[:, 2], show_scalar_bar=False)
p.show()

With the following result结果如下

在此处输入图片说明

Update: February 24, 2020更新:2020 年 2 月 24 日

As mentioned by @HenriMenke, marching_cubes has been renamed to marching_cubes_lewiner .正如@HenriMenke 所提到的, marching_cubes已重命名为marching_cubes_lewiner The "new" snippet is the following. “新”片段如下。

import numpy as np
from numpy import cos, pi
from skimage.measure import marching_cubes_lewiner
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

x, y, z = pi*np.mgrid[-1:1:31j, -1:1:31j, -1:1:31j]
vol = cos(x) + cos(y) + cos(z)
iso_val=0.0
verts, faces, _, _ = marching_cubes_lewiner(vol, iso_val, spacing=(0.1, 0.1, 0.1))

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_trisurf(verts[:, 0], verts[:,1], faces, verts[:, 2], cmap='Spectral',
                lw=1)
plt.show()

If you want to keep your plots in matplotlib (much easier to produce publication-quality images than mayavi in my opinion), then you can use the marching_cubes function implemented in skimage and then plot the results in matplotlib using如果你想把你的图保存在 matplotlib 中(在我看来比 Mayavi 更容易生成出版质量的图像),那么你可以使用skimage 中实现Marching_cubes 函数,然后使用在 matplotlib 中绘制结果

mpl_toolkits.mplot3d.art3d.Poly3DCollection

as shown in the link above.如上面的链接所示。 Matplotlib does a pretty good job of rendering the isosurface. Matplotlib 在渲染等值面方面做得非常好。 Here is an example that I made of some real tomography data:这是我用一些真实的断层扫描数据制作的示例:

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM