web-dev-qa-db-ja.com

matplotlib mplot3Dまたは同様の3D配列等値面の3Dプロットを表示する方法は?

3次元のnumpy配列があります。この配列の等値面のニース3Dプロットを(matplotlibで)表示したい(より厳密には、サンプルポイント間の補間によって定義された3Dスカラーフィールドの等値面を表示したい)。

matplotlibのmplot3Dパーツは素敵な3Dプロットサポートを提供しますが、(私の知る限り)そのAPIにはスカラー値の3D配列を取り、等値面を表示するものは何もありません。ただし、ポリゴンのコレクションの表示はサポートされているため、おそらく、マーチングキューブアルゴリズムを実装してこのようなポリゴンを生成できます。

Scipyに優しいマーチングキューブが既にどこかで実装されており、それを見つけていないか、またはこれを行う簡単な方法が欠けている可能性が高いようです。あるいは、Python/numpy/scipyの世界から簡単に使用できる3D配列データを視覚化する他のツールへのポインターを歓迎します。

42
timday

上記の私のコメントを詳しく述べると、matplotlibの3Dプロットは、等値面のような複雑なものを意図したものではありません。これは、非常にシンプルな3Dプロット用の、出版物品質の素晴らしいベクター出力を生成することを目的としています。複雑な3Dポリゴンを処理できないので、等値面を作成するために自分でマーチングキューブを実装しても、適切にレンダリングされません。

ただし、代わりに mayavi を使用できます( mlab API はmayaviを直接使用するよりも少し便利です) [〜#〜]を使用しますvtk [〜#〜] 多次元データを処理および視覚化するため。

簡単な例として(mayaviギャラリーの例の1つから変更):

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

enter image description here

39
Joe Kington

@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)
verts, faces = measure.marching_cubes(vol, 0, 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()

enter image description here

更新: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)
verts, faces, _, _ = measure.marching_cubes(vol, 0, 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()
20
nicoguaro

プロットをmatplotlibに保持したい場合(私の意見ではmayaviよりも出版品質の画像を作成する方がはるかに簡単です)、 skimageで実装されたmarching_cubes関数 を使用し、次にmatplotlibに結果をプロットできます

mpl_toolkits.mplot3d.art3d.Poly3DCollection

上記のリンクに示すように。 Matplotlibは、等値面をレンダリングする上でかなり良い仕事をします。以下は、実際のトモグラフィーデータで作成した例です。

enter image description here

12
DanHickstein