LoginSignup
5
3

More than 1 year has passed since last update.

2*2行列の計算を可視化したい(matplotlibとtkinter練習)

Posted at

この記事について

線形写像とか固有値とかが、何をしているのかよく分からなかったので、
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)に動くか(移動過程ではなく、それぞれの行き先)
を見たいというのが目的です。

移動過程も見たいのですが、どうしたらいいのかわかりませんでした。

コード

コードはこんなのです。パパっと作っちゃったので、なっげぇです。

すべて.py
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/
など、後はわからなかったらその都度つまみ食いしました。ありがとうございました。

コードの細かいとこ

すみません。書ききる気力が足りませんでした。
以下、処理のメモです。
image.png

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3