matplotlib はPythonのNumPyのグラフ描画ライブラリライブラリです。
python -m pip install matplotlibのモジュール追加が必要です。
またシステムによりますが、matplotlibのbackendsで'agg'や'WXAgg'などの指定が必要な場合があります。
import matplotlib
matplotlib.use('WXAgg')
import matplotlib.pyplot as plt
のような記述です。
import numpy as np
import matplotlib.pyplot as plt # pltを使うこと
x = np.arange(0, 6, 0.1)
y = np.sin(x)
y2=np.cos(x)
fig = plt.figure() # ◎ファイル保存の準備
plt.plot(x,y)
plt.plot(x,y2, linestyle="--", label="cos")
plt.xlabel("xx")
plt.ylabel("yy")
plt.title("sin & cos")
plt.legend() # グラフ内にも上記のlabel表示をつける
# plt.ylim(-1.5, 1.5) # y軸の表示範囲に-1.5〜1.5に限定 (xlimでX軸も可能)
# plt.grid() # グリッドの表示
fig.savefig("img.png")# ◎表示イメージのファイル保存
plt.show() #画面に表示して閉じるまで待つ(表示表示されると、plt内容はクリア)
import numpy as np import matplotlib.pyplot as plt # pltを使うこと x = np.arange(0, 6, 0.1) plt.subplot(2, 1, 1) # 2行に分割, 1列に分割, 1何番目のプロットを指定) y = np.sin(x) plt.plot(x,y) # プロット用データを設定 plt.subplot(2, 1, 2) # 2行に分割, 1列に分割, 2何番目のプロットを指定) y = np.cos(x) plt.plot(x,y, linestyle="--", label="cos") plt.plot(x,y) # プロット用データを設定 plt.show() #表示されると、plt内容はクリア
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3, 3, 1.0)
print("x=",x)
'''
x= [-3. -2. -1. 0. 1. 2.]
'''
y = np.arange(10, 20, 1.0)
print("y=",y)
'''
y= [ 10. 11. 12. 13. 14. 15. 16. 17. 18. 19.]
'''
# z=f(x,y)のnumpy算術がプロット順にするための配列生成
X, Y = np.meshgrid(x, y)
print("X=",X)
'''
X= [[-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.]
[-3. -2. -1. 0. 1. 2.]
[-3. -2. -1. 0. 1. 2.]
[-3. -2. -1. 0. 1. 2.]
[-3. -2. -1. 0. 1. 2.]]
'''
print("Y=",Y)
'''
Y= [[ 10. 10. 10. 10. 10. 10.]
[ 11. 11. 11. 11. 11. 11.]
[ 12. 12. 12. 12. 12. 12.]
[ 13. 13. 13. 13. 13. 13.]
[ 14. 14. 14. 14. 14. 14.]
[ 15. 15. 15. 15. 15. 15.]
[ 16. 16. 16. 16. 16. 16.]
[ 17. 17. 17. 17. 17. 17.]
[ 18. 18. 18. 18. 18. 18.]
[ 19. 19. 19. 19. 19. 19.]]
'''
Z = X + Y # 個々Z軸を一括演算
print("Z=",Z)
'''
Z= [[ 7. 8. 9. 10. 11. 12.]
[ 8. 9. 10. 11. 12. 13.]
[ 9. 10. 11. 12. 13. 14.]
[ 10. 11. 12. 13. 14. 15.]
[ 11. 12. 13. 14. 15. 16.]
[ 12. 13. 14. 15. 16. 17.]
[ 13. 14. 15. 16. 17. 18.]
[ 14. 15. 16. 17. 18. 19.]
[ 15. 16. 17. 18. 19. 20.]
[ 16. 17. 18. 19. 20. 21.]]
'''
fig = plt.figure() # 2次元の図を初期化「1つのshow()ごとで必要」
ax = Axes3D(fig) # 3次元版に変換「1つのshow()ごとで必要」
# プロットする。(主要なプロットを3つ紹介)
ax.plot_wireframe(X,Y,Z) #ワイヤーフレームのプロット
#ax.plot_surface(X, Y, Z, rstride=1, cstride=1)#サーフェスのプロット
#ax.scatter3D(np.ravel(X),np.ravel(Y),np.ravel(Z))#点のプロット
plt.show() #表示
def plot_xyz_to_xyz(x1,y1,z1, x2,y2,z3 , color="red"): X = np.array( [ [x1, x2] ]) Y = np.array( [ [y1, y2] ]) Z = np.array( [ [z1, z2] ]) ax.plot_wireframe(X,Y,Z, color=color) #ワイヤーフレームのプロット x1,y1,z1, x2,y2,z2 = (-3, 10 , 7, 2, 19, 21) plot_xyz_to_xyz( x1,y1,z1, x2,y2,z2 ) # 線をプロットする。 # 矢印をプロットする。 px, py, pz = ( np.array([[-3]]), np.array([[10]]), np.array([[ 7]]) ) u, v, w = ( np.array([[ 0 ]]), np.array([[ 0 ]]), np.array([[ 1 ]]) ) ax.quiver(px, py, pz, u, v, w, length=5, normalize=True, color="green") # 矢印プロット plt.show() #表示
上記グラフで、ピンクの矢印がZ内のデータが並ぶ順番です。
また、手書きで、X,Y,Zの軸のラベルを書きましたが、以下の表現をshow()の前に記述すれば
描いてくれます。
ax.set_xlabel("X", size = 16) # 軸ラベルを設定
ax.set_ylabel("Y", size = 16)
ax.set_zlabel("Z", size = 16)
numpyの便利さがよくわかる。以下にコードを示します。
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
X=[[v for v in range(-3,3)] for v in range(10)]
Y=[[v for n in range(6)] for v in range(10,20)] # x,y軸の格子を作る。
Z=[]
for y in range(len(Y)):
t=[]
for x in range(len(X[y])):
z=X[y][x]+Y[y][x] # 個々格子の点のzを計算
t.append(z)
print(t)
Z.append(t)
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")# 3DAxesを追加
ax.set_xlabel("X", size = 16) # 軸ラベルを設定
ax.set_ylabel("Y", size = 16)
ax.set_zlabel("Z", size = 16)
for i in range(len(X)):
ax.plot(X[i],Y[i],Z[i],color="blue")
for col in range( len(X[0]) ):
x2,y2,z2 = [],[],[]
for row in range( len(X) ):
x2.append( X[row][col] )
y2.append( Y[row][col] )
z2.append( Z[row][col] )
ax.plot(x2,y2,z2,color="green")
ax.plot([-3,2],[10,19],[7,21], color="red")
plt.show() #表示
import matplotlib.pyplot as plt
from matplotlib.image import imread
import os
path=os.path.expanduser('~') + "\\Pictures\\Face.png"
# path='file:///C:/Users/yuu.PC7/Pictures/Face.png' #上記で、例えば次のようなパスが得られます。
img = imread(path) # pathからImage生成
plt.imshow(img) # 画像を設定
# plt.ion() #plt.show()をした時点で、コンソールに入力できなくなる。それを可能したい場合のインターラクティブモード設定
# plt.draw() # plt.ion()を使う場合には、draw()する必要がある。
plt.show() # ここで表示
def function_1(x): return 0.01 * x**2 + 0.1*xこのよううな関数を引数にして、xの傾き(微分した値を求める)関数は次のように定義できます。(誤差を少なくする中心差分の実装)
def numerical_diff_0(f,x): # 関数f の xの微分値を求める h = 1e-4 return (f(x+h)- f(x-h))/(2*h)なお接線描画ように次の関数も用意した。
def ax_plus_b(x, a, b): # y = a * x + b の1次関数 return x * a + b次のようなコードで、プロットできます。
import numpy as np
import matplotlib.pylab as plt
x = np.arange(0.0,20.0,0.1) # 0から20まで、0.1ずつ計算させるnumpy配列生成
y= function_1(x) # 配列のまま計算(結果も配列)
plt.xlabel("x")
plt.ylabel("f(x)")
plt.plot(x,y) # x,yの配列が示す点をプロットする。
# x が5の接戦の描画
x1=5
y1=function_1(x1)
a1=numerical_diff_0(function_1,x1) # 微分値(傾き)を算出
b1=y1-a1*x1 # 線のパラメタbを算出
y2=ax_plus_b(x,a1,b1) # 接線のy計算
plt.plot(x,y2) # 接線プロット
# x が10の接戦の描画
x1=10
y1=function_1(x1)
a1=numerical_diff_0(function_1,x1) # 微分値(傾き)を算出
b1=y1-a1*x1 # 線のパラメタbを算出
y2=ax_plus_b(x,a1,b1) # 接線のy計算
plt.plot(x,y2) # 接線プロット
plt.show() #表示
def func_X2(x0,x1):
return x0**2 + x1**2
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
x_0 = np.arange(-4, 4, 0.5)
#print("x_0=",x_0)
x_1 = np.arange(-4, 4, 0.5)
#print("x_1=",x_1)
# y=f(x_0,y_1)のnumpy算術がプロット順にするための配列生成
X0, X1 = np.meshgrid(x_0, x_1)
#print("X0=",X0)
#print("X1=",X1)
Y =func_X2(X0,X1) # 個々Z軸を一括演算
print("Y=",Y)
fig = plt.figure() # 2次元の図を初期化「1つshow()の前に必要」
ax = Axes3D(fig) # 3次元版に変換「1つshow()の前に必要」
ax.plot_wireframe(X0,X1,Y) #ワイヤーフレームのプロット
plt.show() #表示

複数の変数からなる関数の微分を偏微分と言います。
上記 y = x0**2 + x1**2 であれば、
x0,x1の2つ(複数)の変数を使っていますが、このこような時に使います。
この例「x0,x1の2つの変数」の偏微分の式は、δf/δx0 、δf/δx1 のように書きます。(δ :デルタと呼んでます)
偏微分は、1つ変数の微分と同じで、ある所の傾きと言えます。
ただし、変数がたくさんあるので、1つの変数に絞って(他の変数を固定して)、算出する考え方です。
上記の微分で作ったnumerical_diff_sp関数を使って、算出した例です。
def numerical_diff_sp(f,x): # 関数f で xの微分値を求める h = 1e-4 return (f(x+h)- f(x-h))/(2*h) def func0(x0): # y=x0**2+x1**2 の式で、x1=を4.0に固定して、x0のδf/δx0 を求めるための関数を定義 return x0**2 + 4.0**2 y=numerical_diff_sp(func0,3.0) # x1=を4.0に固定して、x0が3.0 のδf/δx0 を求める。 print(y) # 結果:6.00000000000378 def func1(x1): # y=x0**2+x1**2 の式で、x0=を3.0に固定して、x0のδf/δx1 を求めるの関数を定義 return 3**2 + x1**2 y=numerical_diff_sp(func1,4.0) # x1=を3.0に固定して、x0が4.0 のδf/δx1 を求める。 print(y) # 結果:7.999999999999119上記では「y=x0**2+x1**2」の関数を「func0」と「func1」に分けて、 x0=3.0,x1=4.0の δf/δx0 、δf/δx1を求めました。
import numpy as np
def function_2(x):
return np.sum(x**2) # x[0]**2 + x[1]**2 と同じ
def numerical_gradient_d1(f, x): # 1次元の配列で変数を指定し、その時の勾配を求める。(偏微分の値を求める。)
h = 1e-4 # 0.0001
grad = np.zeros_like(x)
for idx in range(x.size):
tmp_val = x[idx]
x[idx] = float(tmp_val) + h
fxh1 = f(x) # f(x+h)
x[idx] = tmp_val - h
fxh2 = f(x) # f(x-h)
grad[idx] = (fxh1 - fxh2) / (2*h)
x[idx] = tmp_val # 値を元に戻す
return grad
x = np.array([ 3.0,4.0 ])
y = numerical_gradient_d1( function_2, x ) # numerical_diff_spで行った実行結果と同じ結果が得られる。
print(y[0], ",", y[1]) # 出力:6.0 , 8.0
x = np.array([ 3.0, 0.0 ])
y = numerical_gradient_d1( function_2, x )
print(y[0], ",", y[1]) # 出力:6.00000000001 , 0.0
x = np.array([ -3.0 , -2.0 ])
y = numerical_gradient_d1( function_2, x)
print(y[0], ",", y[1]) # 出力:-6.00000000001 , -4.0
上記に続けて、下記コードを、上記の3次元プロットののコードに追加すると赤の矢印が得られます。# 矢印をプロットする。 px, py, pz = ( np.array([[x[0]]]), np.array([[x[1]]]), np.array([[function_2(x)]]) ) import math u, v, w = ( np.array([[ 1 ]]), np.array([[ 1 ]]), np.array([[ -math.sqrt(y[0]**2 + y[1]**2) ]]) ) ax.quiver(px, py, pz, u, v, w, length=-5, normalize=True, color="red") # 矢印プロット plt.show() #表示
import numpy as np
def numerical_gradient_d2(f, X): # 1次元、2次元入力の兼用で配列で変数を指定し、その時の勾配を求める。
if X.ndim == 1:
return numerical_gradient_d1(f, X) # 1元の場合
else:
grad = np.zeros_like(X)
for idx, x in enumerate(X):
grad[idx] = numerical_gradient_d1(f, x)
return grad
def function_2_sp(x): # 1次元、2次元入力の兼用で配列で変数を指定し、# x[0]**2 + x[1]**2を求める関数。
if x.ndim == 1:
return np.sum(x**2) # 1次元
else:
return np.sum(x**2, axis=1) # 2次元
x=np.array([ 3.0, 4.0 ]) # 1次元入力の検証
numerical_gradient_d2(function_2_sp, x ) # 出力結果: array([ 6., 8.])
x0=np.array([ 3.0, 3.0, -3.0 ])
x1=np.array([ 4.0, 0.0, -2.0 ])
grad = numerical_gradient_d2(function_2_sp, np.array([x0, x1]) ) # 2次元入力の検証
grad # 次の出力結果となり、検証できた。
array([[ 6., 6., -6.],
[ 8., 0., -4.]])
上記のnumerical_gradient_d2を使ってもできますが、そうするために
以前に定義したfunction_2を、対応する専用のfunction_2_spに変更する必要がありました。
import numpy as np
def numerical_gradient(f, x):
h = 1e-4 # 0.0001
grad = np.zeros_like(x)
it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
while not it.finished:
idx = it.multi_index
tmp_val = x[idx]
x[idx] = float(tmp_val) + h
fxh1 = f(x) # f(x+h)
x[idx] = tmp_val - h
fxh2 = f(x) # f(x-h)
grad[idx] = (fxh1 - fxh2) / (2*h)
x[idx] = tmp_val # 値を元に戻す
it.iternext()
return grad
def function_2(x): # 以前の関数に戻す。
return np.sum(x**2) # x[0]**2 + x[1]**2 と同じ
x0 = np.arange(-4, 4.25, 0.5)
x1 = np.arange(-4, 4.25, 0.5)
X, Y = np.meshgrid(x0, x1) #numpy算術がプロット順にするための配列生成
X = X.flatten()
Y = Y.flatten()
grad = numerical_gradient(function_2, np.array([X, Y]) ) # 格子状の各点の勾配を求める。
import matplotlib.pylab as plt
plt.figure()
plt.xlim([-4, 4]) # グラフの表示範囲指定
plt.ylim([-4, 4])
plt.xlabel('x0') # 軸へのラベル
plt.ylabel('x1')
plt.legend() # グラフ内にも上記のlabel表示をつける
plt.grid() # グリッドの表示
plt.quiver(X, Y, -grad[0], -grad[1], angles="xy",color="blue") # 矢印を一括プロット
x=np.array([ -3.0, -2.0 ]) # x0=-3.0, x1=-2.0 の勾配の(上記の赤の矢印と同じ)を、以下で2次元にプロットする。
grad = numerical_gradient(function_2, x )
plt.quiver(np.array([ x[0] ]), np.array([ x[1] ]),np.array([ -grad[0]]), np.array([ -grad[1]]), angles="xy",color="red")
plt.show()

import numpy as np
def numerical_gradient(f, x): # 関数fの勾配を、x の勾配を求める
h = 1e-4 # 0.0001
grad = np.zeros_like(x)
it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
while not it.finished:
idx = it.multi_index
tmp_val = x[idx]
x[idx] = float(tmp_val) + h
fxh1 = f(x) # f(x+h)
x[idx] = tmp_val - h
fxh2 = f(x) # f(x-h)
grad[idx] = (fxh1 - fxh2) / (2*h)
x[idx] = tmp_val # 値を元に戻す
it.iternext()
return grad
def function_2(x): # 以前の関数
return np.sum(x**2) # x[0]**2 + x[1]**2 と同じ
def gradient_descent(f , init_x, lr=0.01, step_num=100): # 勾配降下法で、解く関数
x = init_x
x_history = []
for i in range(step_num): # x を更新する繰り返り返し(xを解に近づける繰り返し)
x_history.append( x.copy() )
# print(x)
grad = numerical_gradient(f, x) # 関数fの勾配を、x の勾配
x -= lr * grad # 勾配が少なる方向へ移動
return np.array(x_history), x
init_x = np.array([-3.0, -2.0]) # 初期値
x_history, x = gradient_descent(function_2 , init_x, 0.1, 100) # 解を求める
print("偏微分の解:", x) # 出力:偏微分の解: [ -6.11110793e-10 -4.07407195e-10]
# 計算過程のプロット
import matplotlib.pylab as plt
plt.figure()
plt.plot( [-5, 5], [0,0], '--b') # 水平軸のプロット y=0
plt.plot( [0,0], [-5, 5], '--b') # 垂直軸のプロット x=0
plt.plot(x_history[:,0], x_history[:,1], 'o') # [ [ 1,2 ], [3, 4], [5,6] ] を [ [ 1, 3, 5] ] と [ [ 2, 4, 6] ]に分けて、プロット
plt.xlim(-3.5, 3.5) # 描画範囲
plt.ylim(-4.5, 4.5)
plt.xlabel("X0") # 軸の表示用ラベル
plt.ylabel("X1")
plt.show()
この偏微分方程式の解は、(0,0)なので、それに近似していると分かる。
init_x = np.array([-3.0, -2.0]) # 初期値
x_history, x = gradient_descent(function_2 , init_x, 2.0, 100) # 解を求める
print("偏微分の解:", x) # 出力:偏微分の解: [ -1.37396262e+12 2.03412327e+12]
init_x = np.array([-3.0, -2.0]) # 初期値
x_history, x = gradient_descent(function_2 , init_x, 0.0001, 100) # 解を求める
print("偏微分の解:", x) # 出力:偏微分の解: [ -2.94059014 -1.96039343]
リアルタイムで出現する情報を、その都度に描画して表示させる。
アニメーション的な速度は期待できませんが、必要なタイミングで自動的に更新できます。
以下の例は、波形の始まりをxを0.1増やす繰り返しで、0.05秒ごとに100回の表示の繰り返しを行う例です。

import numpy as np
import matplotlib.pyplot as plt
# https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.html
fig, ax = plt.subplots(1, 1) # FigureとAxes object取得
lines, = ax.plot([0,1], [-1,1]) #Line2D (縦軸範囲はここで決まる)
def plotting( xlist, ylist):
lines.set_data(xlist, ylist) # 描画データを更新する
# set_data()を使うと軸とかは自動設定されないので,
# x軸の範囲は適宜修正してやる必要がある.
ax.set_xlim((xlist.min(), xlist.max()))
plt.pause(.00000000001) # 引数を小さくしているが、一定以下は速くならないようだ
# 上記で、ブロックするplt.show()の代わりにplt.pause(interval)で描画している。
# sinカーブを生成して描画するループ
xs = np.arange(0, np.pi*2, 0.1) # 初期のxの算出範囲のnumpy配列
for i in range(100):
xs += 0.1 # plotデータの更新
ys = np.sin(xs)
#print(xs)
plotting(xs, ys) # リアルタイムにグラフを描画
print("終了")
plt.show() # 最後のグラフを描画して閉じるまで停止
補足 fig, ax = plt.subplots(1, 1) これは、次のように分けて取得することもできます。 fig = plt.gcf() # figure の図の意味で表示範囲全体の図を管理するFigureオブジェクト ax = plt.gca() # axis の軸を複数管理りするAxesオブジェクト(AxesオブジェクトにはAxisオブジェクトが属している) fig = plt.figure(dpi=100, figsize=(4,3))のようなサイス指定が可能
次のような表示のサンプルです。

import numpy as np x2=np.arange(100) y2= x2 * np.random.rand(100) # 100個の乱数 import matplotlib.pyplot as plt plt.figure(dpi=70, figsize=(15,10))#描画サイズ plt.subplot(2,3,1) plt.scatter(x2,y2) #散布図(分布図)、点でプロットしたもの。 plt.subplot(2,3,2) plt.plot(x2,y2) #折れ線グラフでプロットしたもの。 plt.subplot(2,3,4) plt.bar(x2,y2) #棒グラフでプロットしたもの。 plt.subplot(2,3,5) plt.hist(y2, bins=5) #ヒストグラムでプロットしたもの。 plt.subplot(1,3,3) plt.boxplot(y2) #箱ひげ図表示 plt.show()
plt.hist(y2, bins=5) は、度数分布図とも呼びますが、binsの数に分割した階級の範囲を指定し、
その範囲(区間ごと)に存在する度数(個数)を集計して棒グラフにしたイメージです。
また箱ひげ図は、上記赤線が中央値を示しており、箱の上端と下端が四分位点(しぶんいすう:75%点と25%点)を表し、
上下の髭(ひげ)のラインがデータ範囲を表します。
pip install japanize-matplotlib以下のようにimportして使うだけです。import matplotlib.pyplot as plt import japanize_matplotlib