Python
numpy
matplotlib
python3

matplotlib 3次元プロットは難しくない!

3次元プロットの基本

2次元から拡張して考えると理解しやすいです。

まず2次元の場合

まず2次元の場合を考えてみましょう。

2次元グラフを描く場合まず次のよう1次元の配列を作ります。

import numpy as np

# -3から2.9まで0.1刻みで配列を作成
x = np.arange(-3, 3, 0.1)

そしてそれをもとに、グラフを描きます。
例えば、$y = \sin(x)$のグラフだと、

import matplotlib.pyplot as plt

# 描写
plt.plot(x, np.sin(x))
plt.show()

img_20181008234531.png

のようになります。

基本的にこれを3次元に拡張していきます。

3次元への拡張

2次元グラフのとき1次元配列を作成したのと同じように、まず2次元格子点の座標を作成します。

これはnumpy.meshgridを使うと簡単に作成できます。

そして、それぞれの格子点に対する高さを計算します。

numpy.meshgridについては以下の記事で詳しく説明しているので参考にしてみてください。

matplotlibでの描写 等高線プロットの基礎をわかりやすく説明してみた

重要なのは次です。

「mpl_toolkits.mplot3d.Axes3Dをインポート」

これをインポートすることによって3次元プロットが実現可能になります。

ためしに$z = \sin(x) + \cos(y)$のグラフを3次元プロットしてみましょう。

まず、関数を定義します。

def height(x, y):
    return np.sin(x) + np.cos(y)

次に、2次元メッシュと高さを作成します。

# 2次元メッシュ作成
x = np.arange(-3, 3, 0.1)
y = np.arange(-3, 3, 0.1)
xx, yy = np.meshgrid(x, y)

# 各メッシュにおける高さ
z = height(xx, yy)

そして、グラフを作成します。グラフの作成は2ステップで行います。

1.plt.figureで2次元の図を生成する
2.その後,Axes3D関数で3次元にする

from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure() # 2次元の図を作成
ax = Axes3D(fig) # 3次元化

最後にグラフを描写します。今回はplot_wireframeメソッドを用いてみましょう。

# 描写
ax.plot_wireframe(xx, yy, z)
plt.show()

img_20181009001630.png

様々なプロット

plot_wireframe

上の例を参照。

plot_surface

# 描写
fig = plt.figure()
ax = Axes3D(fig)
ax.plot_surface(xx, yy, z)

img_20181009134204.png

その他

一枚の画像に複数のグラフを描写する

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

fig = plt.figure()
ax1 = fig.add_subplot(121, projection='3d')
ax2 = fig.add_subplot(122, projection='3d')
ax1.plot_wireframe(xx, yy, z)
ax2.plot_surface(xx, yy, z)
plt.tight_layout()
plt.show()

img_20181009140609.png

この場合、明示的にはAxes3Dは使っていませんがインポートしておかないとエラーがでるので注意です。

また、グラフを2つ並べる必要のない場合はax = Axes3D(fig)の方法で十分です。

3次元散布図

# データ作成
x = np.arange(-3, 3, 0.5)
y = np.arange(-3, 3, 0.5)
xx, yy = np.meshgrid(x, y)
z = height(xx, yy)

# 描写
fig = plt.figure()
ax = Axes3D(fig)
ax.scatter3D(xx.ravel(), yy.ravel(), z.ravel())

img_20181010102512.png

  • 注意点としては1次元の配列として引数を渡すということです。