SEワンタンの独学備忘録

IT関連の独学した内容や資格試験に対する取り組みの備忘録

【Python】入門⑦ Pythonでグラフを扱う その3(三次元グラフを扱う)

ちょっと時間が空いてしまいましたが、今回はPythonで三次元グラフを扱います。

三次元グラフ

三次元の数式

これまで、Python学習においてはもちろん、学生時代の数学でも三次元のグラフというのはあまり扱ってきませんでした。

二次元というのはx軸とy軸を持つグラフでしたので、三次元ではx軸、y軸、z軸の三方向性を持つグラフとなります。
数式で表してみると例えば以下のようなものになります。

z = x + 2y

Pythonで表現してみます。

・例

# ライブラリのインポート
import numpy as npy

# 関数の定義
def f(x,y):
    return x + 2*y

linelen = 3
# X軸とY軸に-5から5までの配列
xline = npy.linspace(0,2,linelen)
yline = npy.linspace(0,2,linelen)
# Z軸に0、0の要素を必要な数だけ用意する
zline = npy.zeros((len(xline),len(yline)))

# X軸のループ
for i0 in range(linelen):
    # Y軸のループ
    for i1 in range(linelen):
        zline[i1,i0] = f( xline[i0], yline[i1]) 

print(zline)

・出力結果

[[0. 1. 2.]
 [2. 3. 4.]
 [4. 5. 6.]]

表現として正しいのか分かりませんが(x, y)としたとき以下に対応していることになるので出力結果が正しいのはわかるでしょう。

[[(0,0) (1,0) (2,0)]
[(0,1) (1,1) (2,1)]
[(0,2) (1,2) (2,2)]]

数値を色で表現する

三次元グラフの出力結果を色で表現してみます。
グラフ表現を行うので「matplotlib.pyplot」(plt)を使用します。

・例

# ライブラリのインポート
import numpy as npy
import matplotlib.pyplot as plt
# Jupiter Notebookで結果を表示するためのおまじない
%matplotlib inline
# 関数の定義
def f(x,y):
    return x + 2*y

linelen = 3
# X軸とY軸に0から2までの配列
xline = npy.linspace(0,2,linelen)
yline = npy.linspace(0,2,linelen)
# Z軸に0、0の要素を必要な数だけ用意する
zline = npy.zeros((len(xline),len(yline)))

# X軸のループ
for i0 in range(linelen):
    # Y軸のループ
    for i1 in range(linelen):
        zline[i1,i0] = f( xline[i0], yline[i1]) 
        
# 数値を灰色階調で表現する
plt.gray()
# pltに要素を設定する
plt.pcolor(zline)
# 右側にカラーバーを表示する
plt.colorbar() 
plt.show()

・出力結果

f:id:wantanBlog:20191130001351p:plain


出力結果をみると一瞬???となりました。
行列表現と異なるように見えますが、左下から値を出力し始めるようなので以下のように結果が出力されており正しいことがわかります。

f:id:wantanBlog:20191130001951p:plain


グレースケールのみでなく他の色での表現も可能なようです。すごいなぁ純粋に感心。

これで三次元関数を可視化することができました。
現時点ではだから何?って感じはしますがまぁ進めていきましょう。

数値を表面で表現する

色の表現で少しはそれっぽくなりましたが、表現方法としては二次元です。
実際に三次元で表現するのがここからの方法。

三次元の表現を行うためには以下のAxes3Dをインポートを行う必要があるようです。

from mpl_toolkits.mplot3d import Axes3D


正直いきなりやると何がなんだか分からなくなりますが、一つ一つ理解していくかまずは固定表現として覚えてしまうでよいのではないかと思います。


・例

# ライブラリのインポート
import numpy as npy
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# Jupiter Notebookで結果を表示するためのおまじない
%matplotlib inline
# 関数の定義
def f(x,y):
    return x + 2*y

linelen = 3
# X軸とY軸に0から2までの配列
xline = npy.linspace(0,2,linelen)
yline = npy.linspace(0,2,linelen)
# Z軸に0、0の要素を必要な数だけ用意する
zline = npy.zeros((len(xline),len(yline)))

# X軸のループ
for i0 in range(linelen):
    # Y軸のループ
    for i1 in range(linelen):
        zline[i1,i0] = f( xline[i0], yline[i1]) 
        
# x軸とy軸を行列表現にする
xline, yline = npy.meshgrid(xline, yline)
# 座標系の指定
ax = plt.subplot( 1, 1, 1, projection ='3d')
# 表面の表示
ax.plot_surface( xline, yline, zline, rstride = 1, cstride = 1, alpha = 0.3, color ='blue', edgecolor ='black')
# Z軸の表示をずらす
ax.set_zticks(( 0, 0.2))
# グラフの向きを調整する
ax.view_init( 75, -95)
plt.show()

・出力結果

f:id:wantanBlog:20191130004704p:plain


これだけ見てもいまいち正しいのかわからない気がします。自身が理解できる形にグラフを調整してみましょう。

・例

# ライブラリのインポート
import numpy as npy
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# Jupiter Notebookで結果を表示するためのおまじない
%matplotlib inline
# 関数の定義
def f(x,y):
    return 2*x*x - 2*y

linelen = 10
# X軸とY軸に0から5までの配列
xline = npy.linspace(0,5,linelen)
yline = npy.linspace(0,5,linelen)
# Z軸に0、0の要素を必要な数だけ用意する
zline = npy.zeros((len(xline),len(yline)))

# X軸のループ
for i0 in range(linelen):
    # Y軸のループ
    for i1 in range(linelen):
        zline[i1,i0] = f( xline[i0], yline[i1]) 
        
# x軸とy軸を行列表現にする
xline, yline = npy.meshgrid(xline, yline)
# 座標系の指定
ax = plt.subplot( 1, 1, 1, projection ='3d')
# 表面の表示
ax.plot_surface( xline, yline, zline, rstride = 1, cstride = 1, alpha = 0.3, color ='blue', edgecolor ='black')
# Z軸の表示をずらす
ax.set_zticks((-10, 0, 40))
# グラフの向きを調整する
ax.view_init( 20, -100)
# X軸に名前を付ける
plt.xlabel('$x$')
# Y軸に名前を付ける
plt.ylabel('$y$')
plt.show()

・出力結果

f:id:wantanBlog:20191130015021p:plain

とりあえずで、ちゃかちゃかといじってみると何となく関数の使い方もわかってくるものです。

関数は少し変化を大きくするために以下のようにしてみました。

z = 2x^2 -2y

X軸とY軸の範囲を0から5までにする。スポットは10個。

linelen = 10
# X軸とY軸に0から5までの配列
xline = npy.linspace(0,5,linelen)
yline = npy.linspace(0,5,linelen)

グラフの取りうる最大値や最小値から表示値を決めます。

# Z軸の表示をする
ax.set_zticks((-10, 0, 40))

見やすいように調整したが、まだいまいちわからない。

# グラフの向きを調整する
ax.view_init( 20, -100)

X軸とY軸を明示する。

# X軸に名前を付ける
plt.xlabel('$x$')
# Y軸に名前を付ける
plt.ylabel('$y$')

単純な関数なのであまり面白くはないですが
x=5,y=0のとき最大値をとり
x=0,y=5のとき最小値をとるので思い通りのグラフになっていることがわかりました。


グラフの描写はこんなところまで、段々道具がそろってきた感じがしますね。
次回はちょっと数学に触れます。

サンプルソース
https://github.com/wantanblog/python_dev/blob/master/python_Graph3.ipynb