はじめに
numpyのmeshgridの使い方があまり理解できなくて、なんとなくコピペで動かしていたので、どのようなものなのかまとめておくことにしました。
目次
とりあえずmeshgridを作ってみる
meshgrid自体はこのように何の変哲もないものです。
>>> import numpy as np >>> a = np.arange(0,3,0.5) >>> b = np.arange(0,10,2) >>> a array([0. , 0.5, 1. , 1.5, 2. , 2.5]) >>> b array([0, 2, 4, 6, 8]) >>> X, Y = np.meshgrid(a, b) >>> X array([[0. , 0.5, 1. , 1.5, 2. , 2.5], [0. , 0.5, 1. , 1.5, 2. , 2.5], [0. , 0.5, 1. , 1.5, 2. , 2.5], [0. , 0.5, 1. , 1.5, 2. , 2.5], [0. , 0.5, 1. , 1.5, 2. , 2.5]]) >>> Y array([[0, 0, 0, 0, 0, 0], [2, 2, 2, 2, 2, 2], [4, 4, 4, 4, 4, 4], [6, 6, 6, 6, 6, 6], [8, 8, 8, 8, 8, 8]])
つまり(0,0)の値を(X[0,0],Y[0,0])として表現できる。ここまでは常識的な話。
計算する
numpy配列なので、配列全体でそのまま計算することができます。numpyでいうところの[1, 2, 3] + [4, 5, 6]が[5, 7, 9]になるのと同じです(この表記はリストのリテラルなのでできませんが)。
>>> Z = np.sin(X+Y) >>> Z array([[ 0. , 0.47942554, 0.84147098, 0.99749499, 0.90929743, 0.59847214], [ 0.90929743, 0.59847214, 0.14112001, -0.35078323, -0.7568025 , -0.97753012], [-0.7568025 , -0.97753012, -0.95892427, -0.70554033, -0.2794155 , 0.21511999], [-0.2794155 , 0.21511999, 0.6569866 , 0.93799998, 0.98935825, 0.79848711], [ 0.98935825, 0.79848711, 0.41211849, -0.07515112, -0.54402111, -0.87969576]])
ま、これはmeshgridの機能というより、numpyの機能。
plotしてみる
ぶっちゃけ3Dのplot以外でmeshgrid使うことってあるんですか・・・?
>>> import matplotlib.pyplot as plt >>> from mpl_toolkits.mplot3d import Axes3D >>> fig = plt.figure() >>> ax = Axes3D(fig) >>> ax.plot_wireframe(X, Y, Z) <mpl_toolkits.mplot3d.art3d.Line3DCollection object at 0x7f04d0367860> >>> plt.show()
XとYを足してsinに通すという謎の関数にしてしまったので見た目は気持ち悪いですが、それはさておきうまくプロットすることができています。matplotlibには同じような3次元データのプロット用の関数がたくさんあり、だいたいmeshgridを受け付けるので、いろいろな方法でプロットすることができます。
xyz座標の配列に変換する
meshgridからx,y,zの座標列に変換したい、ということもあるでしょう。あまり難しく考える必要はなくて、Xをflattenすればx座標列が、Yをflattenすれば……というように座標を得ることができ、あとは適当に結合すれば任意の形にできます。
>>> x = X.ravel() >>> y = Y.ravel() >>> z = Z.ravel() >>> x.shape (30,) >>> y.shape (30,) >>> z.shape (30,) >>> x array([0. , 0.5, 1. , 1.5, 2. , 2.5, 0. , 0.5, 1. , 1.5, 2. , 2.5, 0. , 0.5, 1. , 1.5, 2. , 2.5, 0. , 0.5, 1. , 1.5, 2. , 2.5, 0. , 0.5, 1. , 1.5, 2. , 2.5]) >>> y array([0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 8, 8, 8, 8, 8, 8]) >>> z array([ 0. , 0.47942554, 0.84147098, 0.99749499, 0.90929743, 0.59847214, 0.90929743, 0.59847214, 0.14112001, -0.35078323, -0.7568025 , -0.97753012, -0.7568025 , -0.97753012, -0.95892427, -0.70554033, -0.2794155 , 0.21511999, -0.2794155 , 0.21511999, 0.6569866 , 0.93799998, 0.98935825, 0.79848711, 0.98935825, 0.79848711, 0.41211849, -0.07515112, -0.54402111, -0.87969576])
こうすると色々な関数に渡せそうで便利。結合については、こちらの記事を参照してください。
たとえばxyzで(n_samples, 3)にしたければnp.stack([x, y, z], axis=1)などでよさそうです。
逆にxyz座標からmeshgridを生成する
x, y, zの座標データが与えられていて、プロットするためにmeshgridに変換したいというシチュエーションもあります。
この場合は元のデータが都合よくグリッド状になっていないことが多いので、補完という処理をした上で変換することが可能です。
詳細はこちらの記事を御覧ください。
まとめ
いろいろ動かしてみると、それなりにやっていることが単純なのがわかって、親近感が湧いてきました。とにかく三次元プロットでは必需品なので、meshgridは使いこなそうということです。