簡體   English   中英

如何在 matplotlib mplot3D 或類似工具中顯示 3D 陣列等值面的 3D 圖?

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

我有一個 3 維 numpy 數組。 我想顯示(在 matplotlib 中)這個數組的等值面的一個很好的 3D 圖(或者更嚴格地說,顯示通過在樣本點之間插值定義的 3D 標量場的等值面)。

matplotlib 的 mplot3D 部分提供了很好的 3D 繪圖支持,但是(據我所知)它的 API 沒有任何可以簡單地采用標量值的 3D 數組並顯示等值面的東西。 然而,它確實支持顯示多邊形的集合,所以大概我可以實現行進立方體算法來生成這樣的多邊形。

似乎很可能已經在某處實現了對 scipy 友好的行進立方體,而我還沒有找到它,或者我錯過了一些簡單的方法來做到這一點。 或者,我歡迎任何指向其他工具的指針,用於可視化可從 Python/numpy/scipy 世界輕松使用的 3D 數組數據。

只是為了詳細說明我上面的評論,matplotlib 的 3D 繪圖實際上並不適用於像等值面這樣復雜的東西。 它旨在為非常簡單的 3D 繪圖生成漂亮的、出版質量的矢量輸出。 它無法處理復雜的 3D 多邊形,因此即使自己實現了行進立方體來創建等值面,它也無法正確渲染。

但是,您可以做的是使用mayavi (它的mlab API比直接使用mayavi 方便一點),它使用VTK來處理和可視化多維數據。

作為一個快速示例(從 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()

在此處輸入圖片說明

補充@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()

在此處輸入圖片說明

更新:2018 年 5 月 11 日

正如@DrBwts 所提到的,現在 Marching_cubes 返回 4 個值。 以下代碼有效。

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()

更新:2020 年 2 月 2 日

除了我之前的回答之外,我應該提到PyVista 從那時起已經發布,它使此類任務變得有些輕松。

遵循與之前相同的示例。

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()

結果如下

在此處輸入圖片說明

更新:2020 年 2 月 24 日

正如@HenriMenke 所提到的, marching_cubes已重命名為marching_cubes_lewiner “新”片段如下。

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()

如果你想把你的圖保存在 matplotlib 中(在我看來比 Mayavi 更容易生成出版質量的圖像),那么你可以使用skimage 中實現Marching_cubes 函數,然后使用在 matplotlib 中繪制結果

mpl_toolkits.mplot3d.art3d.Poly3DCollection

如上面的鏈接所示。 Matplotlib 在渲染等值面方面做得非常好。 這是我用一些真實的斷層掃描數據制作的示例:

在此處輸入圖片說明

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM