この記事について
線形写像とか固有値とかが、何をしているのかよく分からなかったので、
pythonの練習ついでに作ってみました。
matplotlibとnumpy行列演算とtkinterが融合してます。
ただの勉強の副産物です。需要?信憑性?…あっ…ないです…
結論
\boldsymbol{r} = A\boldsymbol{v} \\
\\
\begin{pmatrix}
x_1 \\
y_1
\end{pmatrix}
=
\begin{pmatrix}
1 & 2 \\
3 & 4
\end{pmatrix}
\begin{pmatrix}
x_0 \\
y_0
\end{pmatrix}
こんな感じで作用してる真ん中の2*2の行列をAとしています。
x1とかの"r"eturnベクトルが変換後で、
x0とかの"v"ectorが変換前としたときに、
これが、
こう。
ベクトルつけると、こう。
\boldsymbol{r} = (t*A)\boldsymbol{v}
のようにt倍したものという式にして、tを下のバーで動かすと、
こう。
とまあこのように、
変換前の(x0,y0)を格子状の点として用意して、
その子らがどんな感じで(x1,y1)に動くか(移動過程ではなく、それぞれの行き先)
を見たいというのが目的です。
移動過程も見たいのですが、どうしたらいいのかわかりませんでした。
コード
コードはこんなのです。パパっと作っちゃったので、なっげぇです。
import tkinter
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from matplotlib.figure import Figure
import numpy as np
# ベクトルも書きます?
vec_flag = True
### 関数 ###
# スライダーを移動したとき
def slider_scroll(
value,
x_min, x_max, x_n,
y_min, y_max, y_n,
A):
t = float(value) # valueはstr()っぽいから治す
x_data, y_data = create_point(x_min, x_max, x_n, y_min, y_max, y_n, t, A)
if vec_flag == True:
ax.cla()
ax.quiver(o_x_data, o_y_data, x_data-o_x_data, y_data-o_y_data, color = "orange",
angles = 'xy', scale_units = 'xy', scale = 1) # 始点x,始点y, 成分x, 成分y
ax.plot(x_data, y_data, marker='o', linestyle="None") # https://beiznotes.org/matplotlib-plot-without-line/
ax.grid()
else:
line.set_xdata(x_data)
line.set_ydata(y_data)
canvas.draw()
# 点を用意する関数(分かりやすい書き方なので最適化はお願いします)
def create_point(
x_min, x_max, x_n,
y_min, y_max, y_n,
t, A):
# arange用の分割幅を先に計算
dx_width = (x_max - x_min)/(x_n)
dy_width = (y_max - y_min)/(y_n)
x_line = np.arange(x_min, x_max, dx_width) # 一列用意して
x_data = np.tile(x_line, (y_n, 1)) # 並べる
y_line = np.arange(y_min, y_max, dy_width) # 一列用意して
y_line = y_line.reshape(y_n,1) # 行にして
y_data = np.tile(y_line, (1, x_n)) # 並べる
result_x = x_data.copy()
result_y = y_data.copy()
for x in range(x_n):
for y in range(y_n):
vector = np.array(
[[x],
[y]]
) # ベクトル用意
result = np.dot(t*A, vector) # 行列の積(pythonでは内積で書く)
result_x[x,y] = result[0]
result_y[x,y] = result[1]
# 次元を1に矯正
result_x = result_x.reshape(1, x_n*y_n)
result_y = result_y.reshape(1, x_n*y_n)
result_x = np.squeeze(result_x)
result_y = np.squeeze(result_y)
return result_x, result_y
if __name__ == "__main__":
### 変数 ###
x_min = 0 # x_minから
x_max = 5 # x_maxまで
x_n = 5 # x_n個プロット
y_min = 0 # y_minから
y_max = 5 # y_maxまで
y_n = 5 # y_n個プロット
t = 1 # t倍して変化を見るための係数
theta = 0 # 回転行列とか用の媒介変数
A = np.array( # 表現行列
[
[1, 0],
[0, 1]
]
)
# 単位行列
E = np.array( # 表現行列
[
[1, 0],
[0, 1]
]
)
#グラフデータ
o_x_data, o_y_data = create_point(x_min, x_max, x_n, y_min, y_max, y_n, t, E)
### 表示本体 ###
root = tkinter.Tk()
root.title("matplotlib 埋め込み")
#グラフ用オブジェクト生成
fig = Figure(figsize=(5, 5)) #Figure
ax = fig.add_subplot(1, 1, 1) #Axes
ax.set_xlim([x_min-1, x_max])
ax.set_ylim([y_min-1, y_max])
line, = ax.plot(o_x_data, o_y_data, marker='o', linestyle="None") # https://beiznotes.org/matplotlib-plot-without-line/
ax.grid() # グリッド追加
#Figureを埋め込み
canvas = FigureCanvasTkAgg(fig, master=root) # A tk.DrawingArea.
canvas.get_tk_widget().pack()
#ツールバーを表示
toolbar=NavigationToolbar2Tk(canvas, root)
### スケールなどを用意 https://imagingsolution.net/program/python/tkinter/scale_trackbar/ ###
# tを操作する用
scaleH = tkinter.Scale( root,
command = lambda value:slider_scroll(value, x_min, x_max, x_n, y_min, y_max, y_n, A),
orient=tkinter.HORIZONTAL, # 配置の向き、水平(HORIZONTAL)、垂直(VERTICAL)
length = 300, # 全体の長さ
width = 20, # 全体の太さ
sliderlength = 20, # スライダー(つまみ)の幅
from_ = -10, # 最小値(開始の値)
to = 10, # 最大値(終了の値)
resolution=0.1, # 変化の分解能(初期値:1)
tickinterval=10 # 目盛りの分解能(初期値0で表示なし)
)
scaleH.set(t)
scaleH.pack()
#---------------------------------------------------------------
tkinter.mainloop()
参考
・tkinterとmatplotlibの合体!について:https://www.python-beginners.com/entry/20210720/1626710254
・グリッド追加 https://www.delftstack.com/ja/howto/matplotlib/how-to-show-pyplot-grid-in-matplotlib/
・スライドボタン追加 https://imagingsolution.net/program/python/tkinter/scale_trackbar/
など、後はわからなかったらその都度つまみ食いしました。ありがとうございました。