matplotlibの表面プロット


104

3D空間のポイントのセットを表す3タプルのリストがあります。これらのすべての点をカバーする表面をプロットしたいと思います。

パッケージplot_surface内の関数は、mplot3d引数としてX、Y、Zが2d配列である必要があります。あるplot_surfaceプロット表面への権利の機能とどのように私は必要な形式に自分のデータを変換するのですか?

data = [(x1,y1,z1),(x2,y2,z2),.....,(xn,yn,zn)]


これらすべての重複サーフェスにタグを付け、重複を互いに閉じてください。また、メッシュグリッドの生成に関するものには、numpymeshのタグを付けます。
smci

回答:


120

サーフェスの場合、3タプルのリストとは少し異なります。2d配列のドメインのグリッドを渡す必要があります。

いくつかの関数ではなく、3Dポイントのリストがある場合f(x, y) -> z、その3Dポイントクラウドをサーフェスに三角形分割する方法が複数あるため、問題が発生します。

これは滑らかな表面の例です:

import numpy as np
from mpl_toolkits.mplot3d import Axes3D  
# Axes3D import has side effects, it enables using projection='3d' in add_subplot
import matplotlib.pyplot as plt
import random

def fun(x, y):
    return x**2 + y

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = y = np.arange(-3.0, 3.0, 0.05)
X, Y = np.meshgrid(x, y)
zs = np.array(fun(np.ravel(X), np.ravel(Y)))
Z = zs.reshape(X.shape)

ax.plot_surface(X, Y, Z)

ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')

plt.show()

3D


1
こんにちは、ありがとうございます。f(x,y) -> zOPが最初に持っていたようなリストアプローチを使用するだけではなく、関数を使用するとどのように多くの情報が得られるかについて詳しく説明していただけますか。
グレゴリークーン

16
しかし、zがxとyの関数ではなく独立変数である場合はどうしますか?
Labibah、2015

4
この場合、おそらくplot_trisurf代わりに見るべきです。しかし、すでに述べたように、表面を三角測量する必要があり、複数のソリューションがあるため、それは簡単なことではありません。基本的な例として、(0、0、0.2)、(0、1、0)、(1、1、0.2)、(1、0、0)で与えられる4つの点だけを考えます。上から見ると、少し折り目が入った正方形のように見えます。 しかし、「折り目」はどの対角線に沿って発生しますか? 0.2の「高い」対角線か、0の「低い」対角線ですか。どちらも有効なサーフェスです!したがって、明確に定義されたソリューションを得る前に、三角測量アルゴリズムを選択する必要があります。
2015

mpl_toolkits.mplot3dからAxes3Dをインポートするのに、Axes3Dが上記のコードのどこでも使用されていないのはなぜですか?
絢瀬絵里

5
このインポートには副作用があります。このインポートがないとprojection='3d'、呼び出しでkwarg をfig.add_subplot使用できません。
2015年

33

いくつかのファイルから直接データを読み取ってプロットできます

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
from sys import argv

x,y,z = np.loadtxt('your_file', unpack=True)

fig = plt.figure()
ax = Axes3D(fig)
surf = ax.plot_trisurf(x, y, z, cmap=cm.jet, linewidth=0.1)
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.savefig('teste.pdf')
plt.show()

必要に応じて、vminとvmaxを渡して、カラーバーの範囲を定義できます。例:

surf = ax.plot_trisurf(x, y, z, cmap=cm.jet, linewidth=0.1, vmin=0, vmax=2000)

表面

ボーナスセクション

インタラクティブなプロットを行う方法を考えていました

from __future__ import print_function
from ipywidgets import interact, interactive, fixed, interact_manual
import ipywidgets as widgets
from IPython.display import Image

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits import mplot3d

def f(x, y):
    return np.sin(np.sqrt(x ** 2 + y ** 2))

def plot(i):

    fig = plt.figure()
    ax = plt.axes(projection='3d')

    theta = 2 * np.pi * np.random.random(1000)
    r = i * np.random.random(1000)
    x = np.ravel(r * np.sin(theta))
    y = np.ravel(r * np.cos(theta))
    z = f(x, y)

    ax.plot_trisurf(x, y, z, cmap='viridis', edgecolor='none')
    fig.tight_layout()

interactive_plot = interactive(plot, i=(2, 10))
interactive_plot

5
厳密に言えば、ここではパンダは不要です。
下落

私はこのプロットを再現するのに苦労しています。これを達成するためのいくつかの(小さい)サンプル値は何でしょうか?
JRsz

21

私はこの同じ問題に出くわしました。私は均等に代えて2-D配列の3 1-Dアレイにあるデータに離間しているmatplotlibplot_surface欲求を。私のデータはたまたまpandas.DataFrameそこにあるので、ここに3つの1次元配列をプロットするための変更を加えたmatplotlib.plot_surface示します。

from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import matplotlib.pyplot as plt
import numpy as np

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)

fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm,
    linewidth=0, antialiased=False)
ax.set_zlim(-1.01, 1.01)

ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))

fig.colorbar(surf, shrink=0.5, aspect=5)
plt.title('Original Code')

それが元の例です。この次のビットを追加すると、3つの1次元配列から同じプロットが作成されます。

# ~~~~ MODIFICATION TO EXAMPLE BEGINS HERE ~~~~ #
import pandas as pd
from scipy.interpolate import griddata
# create 1D-arrays from the 2D-arrays
x = X.reshape(1600)
y = Y.reshape(1600)
z = Z.reshape(1600)
xyz = {'x': x, 'y': y, 'z': z}

# put the data into a pandas DataFrame (this is what my data looks like)
df = pd.DataFrame(xyz, index=range(len(xyz['x']))) 

# re-create the 2D-arrays
x1 = np.linspace(df['x'].min(), df['x'].max(), len(df['x'].unique()))
y1 = np.linspace(df['y'].min(), df['y'].max(), len(df['y'].unique()))
x2, y2 = np.meshgrid(x1, y1)
z2 = griddata((df['x'], df['y']), df['z'], (x2, y2), method='cubic')

fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(x2, y2, z2, rstride=1, cstride=1, cmap=cm.coolwarm,
    linewidth=0, antialiased=False)
ax.set_zlim(-1.01, 1.01)

ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))

fig.colorbar(surf, shrink=0.5, aspect=5)
plt.title('Meshgrid Created from 3 1D Arrays')
# ~~~~ MODIFICATION TO EXAMPLE ENDS HERE ~~~~ #

plt.show()

結果の数値は次のとおりです。

ここに画像の説明を入力してください ここに画像の説明を入力してください


表面にある線を削除することは可能ですか?ありがとうございました。@ stvn66
diffracteD

@diffracteD、より小さいグリッドサイズを使用してみてください。それが輪郭間の幅を設定するものであることはほぼ確実です。より細かいグリッドで評価することにより、「ピクセルサイズ」を減らし、解像度を上げて、より滑らかなグラデーションに近づける必要があります。
Steven C. Howell

特定のカテゴリに従って上記の表面に色を付ける方法はありますか?例のために。 カテゴリx、y、zはデータ形式であり、特定のカテゴリに従って、x、y、zを通過するサーフェスに色を付けます。
Rudresh Ajgaonkar

@ RudreshAjgaonkar、3つのそれぞれに必要な色を使用して、カテゴリごとに1つずつ、3つの個別のプロットコマンドを使用できるはずです。
Steven C. Howell

サンプルコードを提供できますか?私はmatplotlibとpythonにかなり慣れています。
Rudresh Ajgaonkar

4

エマニュエルは、私が(そしておそらく他の多くの人も)探しているという答えを得ました。3つの分散したデータを3つの別々の配列で持っている場合、パンダは非常に役立ち、他のオプションよりもはるかにうまく機能します。詳しく説明すると、x、y、zが任意の変数であるとします。私の場合、サポートベクターマシンをテストしていたため、これらはc、gamma、およびエラーでした。データをプロットするには、多くの潜在的な選択肢があります。

  • scatter3D(cParams、gammas、avg_errors_array)-これは機能しますが、非常に単純化しています
  • plot_wireframe(cParams、gammas、avg_errors_array)-これは機能しますが、実際の科学データの大量のチャンクの場合と同様に、データが適切にソートされていない場合は見苦しくなります
  • ax.plot3D(cParams、gammas、avg_errors_array)-ワイヤーフレームに似ています

データのワイヤーフレームプロット

データのワイヤーフレームプロット

データの3D散布図

データの3D散布図

コードは次のようになります。

    fig = plt.figure()
    ax = fig.gca(projection='3d')
    ax.set_xlabel('c parameter')
    ax.set_ylabel('gamma parameter')
    ax.set_zlabel('Error rate')
    #ax.plot_wireframe(cParams, gammas, avg_errors_array)
    #ax.plot3D(cParams, gammas, avg_errors_array)
    #ax.scatter3D(cParams, gammas, avg_errors_array, zdir='z',cmap='viridis')

    df = pd.DataFrame({'x': cParams, 'y': gammas, 'z': avg_errors_array})
    surf = ax.plot_trisurf(df.x, df.y, df.z, cmap=cm.jet, linewidth=0.1)
    fig.colorbar(surf, shrink=0.5, aspect=5)    
    plt.savefig('./plots/avgErrs_vs_C_andgamma_type_%s.png'%(k))
    plt.show()

これが最終的な出力です。

xyzデータのplot_trisurf


3

公式の例を確認してください。X、Y、Zは2d配列です。numpy.meshgrid()は、1d xとyの値から2d x、yメッシュを取得する簡単な方法です。

http://matplotlib.sourceforge.net/mpl_examples/mplot3d/surface3d_demo.py

これは、3タプルを3つの1d配列に変換するpythonicの方法です。

data = [(1,2,3), (10,20,30), (11, 22, 33), (110, 220, 330)]
X,Y,Z = zip(*data)
In [7]: X
Out[7]: (1, 10, 11, 110)
In [8]: Y
Out[8]: (2, 20, 22, 220)
In [9]: Z
Out[9]: (3, 30, 33, 330)

これがmtaplotlib delaunay三角形分割(内挿)です。1dx、y、zを準拠したものに変換します(?):

http://matplotlib.sourceforge.net/api/mlab_api.html#matplotlib.mlab.griddata


いいえ...その例では、XYZは2次元です。
2012

私は修正された立場です。リンクされた例のように、データが等間隔である場合は、meshgrid()を使用してください。データが等間隔でない場合は、たとえばgriddata()で補間します。
Dima Tisnek、2012

1

Matlab では、、座標のみ(ではなく)のdelaunay関数を使用して同様のことを行い、高さとしてまたはを使用してプロットしました。xyztrimeshtrisurfz

SciPyにはDelaunayクラスがあります。これは、Matlabのdelaunay関数と同じ基本的なQHullライブラリに基づいているため、同じ結果が得られます。

そこから、python-matplotlibの例にあるこの3DポリゴンのプロットをDelaunay、各三角形ポリゴンの仕様がわかるように、希望するものに変換するための数行のコードが必要です。


に基づいてこの回答を参照してくださいax.plot_trisurf(..)
Evgeni Sergeev 2014年

1

不規則なドメインタイプの問題で他の人を助けるかもしれないいくつかのさらなる考えを追加するだけです。ユーザーが3Dのベクトル/リストを持っている場合、x、y、zは2Dソリューションを表し、zはサーフェスとして長方形グリッドにプロットされます。ArtifixRによる 'plot_trisurf()'コメントが適用されます。同様の例ですが、長方形以外のドメインがあります。

import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D 

# problem parameters
nu = 50; nv = 50
u = np.linspace(0, 2*np.pi, nu,) 
v = np.linspace(0, np.pi, nv,)

xx = np.zeros((nu,nv),dtype='d')
yy = np.zeros((nu,nv),dtype='d')
zz = np.zeros((nu,nv),dtype='d')

# populate x,y,z arrays
for i in range(nu):
  for j in range(nv):
    xx[i,j] = np.sin(v[j])*np.cos(u[i])
    yy[i,j] = np.sin(v[j])*np.sin(u[i])
    zz[i,j] = np.exp(-4*(xx[i,j]**2 + yy[i,j]**2)) # bell curve

# convert arrays to vectors
x = xx.flatten()
y = yy.flatten()
z = zz.flatten()

# Plot solution surface
fig = plt.figure(figsize=(6,6))
ax = Axes3D(fig)
ax.plot_trisurf(x, y, z, cmap=cm.jet, linewidth=0,
                antialiased=False)
ax.set_title(r'trisurf example',fontsize=16, color='k')
ax.view_init(60, 35)
fig.tight_layout()
plt.show()

上記のコードは以下を生成します:

非長方形グリッド問題の表面プロット

ただし、これはすべての問題を解決できるわけではありません。特に、問題が不規則なドメインで定義されている場合はそうです。また、ドメインに1つ以上の凹面領域がある場合、ドロネー三角形分割により、ドメインの外部に偽の三角形が生成されることがあります。このような場合、正しいサーフェス表現を実現するために、これらの不正な三角形を三角形分割から削除する必要があります。これらの状況では、これらの三角形をプログラムで削除できるように、ユーザーはdelaunay三角形分割計算を明示的に含める必要がある場合があります。このような状況では、次のコードが以前のプロットコードを置き換える可能性があります。


import matplotlib.tri as mtri 
import scipy.spatial
# plot final solution
pts = np.vstack([x, y]).T
tess = scipy.spatial.Delaunay(pts) # tessilation

# Create the matplotlib Triangulation object
xx = tess.points[:, 0]
yy = tess.points[:, 1]
tri = tess.vertices # or tess.simplices depending on scipy version

#############################################################
# NOTE: If 2D domain has concave properties one has to
#       remove delaunay triangles that are exterior to the domain.
#       This operation is problem specific!
#       For simple situations create a polygon of the
#       domain from boundary nodes and identify triangles
#       in 'tri' outside the polygon. Then delete them from
#       'tri'.
#       <ADD THE CODE HERE>
#############################################################

triDat = mtri.Triangulation(x=pts[:, 0], y=pts[:, 1], triangles=tri)

# Plot solution surface
fig = plt.figure(figsize=(6,6))
ax = fig.gca(projection='3d')
ax.plot_trisurf(triDat, z, linewidth=0, edgecolor='none',
                antialiased=False, cmap=cm.jet)
ax.set_title(r'trisurf with delaunay triangulation', 
          fontsize=16, color='k')
plt.show()

プロットの例を以下に示し、1)疑似三角形を使用し、2)それらを削除した場合のソリューションを示します。

ここに画像の説明を入力してください

削除された三角形

上記が解決策データに凹状の状況がある人々に役立つことを願っています。


0

データを使用して3Dサーフェスを直接作成することはできません。pykridgeなどのツールを使用して補間モデルを構築することをお勧めします。プロセスには3つのステップが含まれます。

  1. を使用して補間モデルをトレーニングする pykridge
  2. グリッドを作成しXY使用するmeshgrid
  3. の値を補間 Z

グリッドと対応するZ値を作成したら、次の作業に進みますplot_surface。データのサイズによっては、meshgrid関数がしばらく実行できることに注意してください。回避策は、np.linspacefor XYaxes を使用して等間隔のサンプルを作成し、補間を適用して必要なZ値を推測することです。その場合、補間された値は、変更されたZために元の値と異なる場合がXありYます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.