matplotlib - plot_surface で 3D グラフを描画する方法
基本的な使い方
Axes3D.plot_surface(X, Y, Z, *args, **kwargs)
まず numpy.mgrid で格子状の点を作成し、この各点における関数の値を計算する。
import matplotlib.pyplot as plt import numpy as np from mpl_toolkits.mplot3d import Axes3D def f(x, y): return x ** 2 + y ** 2 + x * y X, Y = np.mgrid[-3:3, -3:3] print("X:\n", X) print("Y:\n", Y) Z = f(X, Y) print("Z:\n", Z)
X: [[-3 -3 -3 -3 -3 -3] [-2 -2 -2 -2 -2 -2] [-1 -1 -1 -1 -1 -1] [ 0 0 0 0 0 0] [ 1 1 1 1 1 1] [ 2 2 2 2 2 2]] Y: [[-3 -2 -1 0 1 2] [-3 -2 -1 0 1 2] [-3 -2 -1 0 1 2] [-3 -2 -1 0 1 2] [-3 -2 -1 0 1 2] [-3 -2 -1 0 1 2]] Z: [[27 19 13 9 7 7] [19 12 7 4 3 4] [13 7 3 1 1 3] [ 9 4 1 0 1 4] [ 7 3 1 1 3 7] [ 7 4 3 4 7 12]]
Axes 上に 3D グラフを追加するには、用意した X, Y, Z を plot_surface(X, Y, Z) と渡す。
3D グラフは四角形のポリゴン (patch) の集合 (Poly3DCollection) で構成される。
plot_surface() は返り値として Axes に追加したこのオブジェクトを返す。
fig = plt.figure(figsize=(9, 9), facecolor="w") ax = fig.add_subplot(111, projection="3d") surf = ax.plot_surface(X, Y, Z) print(type(surf)) # <class 'mpl_toolkits.mplot3d.art3d.Poly3DCollection'> plt.show()
影を無効にする。
shade 引数で影を付けるかどうかを設定できる。
デフォルトは有効になっている。
import matplotlib.pyplot as plt import numpy as np from mpl_toolkits.mplot3d import Axes3D def f(x, y): return x ** 2 + y ** 2 + x * y X, Y = np.mgrid[-10:10, -10:10] Z = f(X, Y) fig = plt.figure(figsize=(10, 5)) ax1 = fig.add_subplot(121, projection="3d", facecolor="w") ax1.set_title("shade=True") ax1.plot_surface(X, Y, Z, shade=True) # 影を有効 ax2 = fig.add_subplot(122, projection="3d", facecolor="w") ax2.set_title("shade=False") ax2.plot_surface(X, Y, Z, shade=False) # 影を無効 plt.show()
パッチの間隔を変更する。
パッチは rstride, cstride 引数で指定した大きさで作成される。
デフォルトでは rstirde=1, cstride=1 のため、パッチは (1, 1) の大きさである。
import matplotlib.pyplot as plt import numpy as np from mpl_toolkits.mplot3d import Axes3D def f(x, y): return x ** 2 + y ** 2 + x * y X, Y = np.mgrid[-10:10, -10:10] Z = f(X, Y) fig = plt.figure(figsize=(7, 7)) ax = fig.add_subplot(111, projection="3d", facecolor="w") # (3, 3) の大きさでパッチを作成する。 ax.plot_surface(X, Y, Z, cmap="plasma", rstride=3, cstride=3) plt.show()
パッチの境界線をなくす。
antialiased=False とすることで、パッチの境界線を無効にできる。
import matplotlib.pyplot as plt import numpy as np from mpl_toolkits.mplot3d import Axes3D def f(x, y): return x ** 2 + y ** 2 + x * y X, Y = np.mgrid[-10:10, -10:10] Z = f(X, Y) fig = plt.figure(figsize=(7, 7)) ax = fig.add_subplot(111, projection="3d", facecolor="w") # パッチの境界線を無効化 ax.plot_surface(X, Y, Z, antialiased=False) plt.show()
パッチの境界線の色を変更する。
edgecolor 引数でパッチの境界線の色を設定できる。
import matplotlib.pyplot as plt import numpy as np from mpl_toolkits.mplot3d import Axes3D def f(x, y): return x ** 2 + y ** 2 + x * y X, Y = np.mgrid[-10:10, -10:10] Z = f(X, Y) fig = plt.figure(figsize=(9, 9)) ax = fig.add_subplot(111, projection="3d", facecolor="w") ax.plot_surface(X, Y, Z, cmap="plasma", edgecolor="w") plt.show()
色を指定する。
color 引数で色を指定できる。
import matplotlib.pyplot as plt import numpy as np from mpl_toolkits.mplot3d import Axes3D def f(x, y): return x ** 2 + y ** 2 + x * y X, Y = np.mgrid[-10:10, -10:10] Z = f(X, Y) fig = plt.figure(figsize=(9, 9)) ax = fig.add_subplot(111, projection="3d", facecolor="w") ax.plot_surface(X, Y, Z, color="green") plt.show()
カラーマップを指定する。
cmap 引数で値に応じて色を変化させるカラーマップを設定できる。
連続的な値の変化に対応した Sequential カテゴリのカラーマップがおすすめ。
http://pynote.hatenablog.com/entry/matplotlib-colorpynote.hatenablog.com
import matplotlib.pyplot as plt import numpy as np from mpl_toolkits.mplot3d import Axes3D def f(x, y): return x ** 2 + y ** 2 + x * y X, Y = np.mgrid[-10:10, -10:10] Z = f(X, Y) fig = plt.figure(figsize=(7, 7)) ax = fig.add_subplot(111, projection="3d", facecolor="w") ax.plot_surface(X, Y, Z, cmap="plasma") plt.show()
カラーバーを追加する。
plot_surface() の返り値 Poly3DCollection を Figure.colorbar() に渡すことで、カラーバーを Axes に追加できる。
import matplotlib.pyplot as plt import numpy as np from mpl_toolkits.mplot3d import Axes3D def f(x, y): return x ** 2 + y ** 2 + x * y X, Y = np.mgrid[-10:10, -10:10] Z = f(X, Y) # 点でグラフを作成する。 fig = plt.figure(figsize=(9, 7)) ax = fig.add_subplot(111, projection="3d") surf = ax.plot_surface(X, Y, Z, cmap="plasma", facecolor="w") # カラーバーを追加する。 fig.colorbar(surf) plt.show()
色を透過する。
alpha 引数に [0, 1] の範囲の float を指定することで透過度を設定できる。
デフォルトは 1.0 なので、透過なし。
import matplotlib.pyplot as plt import numpy as np from mpl_toolkits.mplot3d import Axes3D def f(x, y): return x ** 2 + y ** 2 + x * y X, Y = np.mgrid[-10:10, -10:10] Z = f(X, Y) fig = plt.figure(figsize=(7, 7)) ax = fig.add_subplot(111, projection="3d", facecolor="w") ax.plot_surface(X, Y, Z, edgecolor="black", alpha=0.3) plt.show()
パッチごとに色を設定する。
以下の例では、格子が (20, 20) で rstride, cstride はデフォルトの (1, 1) であるから、パッチは (20, 20) 作られる。
facecolors に各パッチごとの色を指定した (20, 20, 3) の配列を渡すことで、パッチが指定した色で作成される。
色の値は [0, 255] ではなく、[0, 1] の範囲の浮動小数点数で指定することに注意する。
import matplotlib.pyplot as plt import numpy as np from mpl_toolkits.mplot3d import Axes3D def f(x, y): return x ** 2 + y ** 2 + x * y X, Y = np.mgrid[-10:10, -10:10] Z = f(X, Y) # 各パッチの色を作成する。 colors = np.random.random(X.shape + (3,)) print(colors.shape) # (20, 20, 3) fig = plt.figure(figsize=(7, 7)) ax = fig.add_subplot(111, projection="3d", facecolor="w") ax.plot_surface(X, Y, Z, facecolors=colors) plt.show()