Pythonの標準GUIプログラミングライブラリであるTkinterはmatplotlibとも連携可能です。ここでは簡単な波形を使い、Tkinterでmatplotlibを使う1つの事例を紹介します。
こんにちは。wat(@watlablog)です。ここではTkinter+matplotlibでGUIグラフプロットを学びます!
Tkinterとmatplotlibの概要
Tkinterのおさらい
当WATLABブログでは、
Python初心者がGUI作成にTkinterを選ぶ3つの理由
Python Tkinterのボタンでイベント処理
TkinterのFrame/pack/gridを理解してみる
…の3つの記事でTkinterによるGUIプログラミングの初歩的な部分を説明してきました。本記事を読む前に、これらの記事を読んで頂くとmatplotlibとの連携について理解が深まると思います。
matplotlibのおさらい
matplotlibはいわずもがなですが、超有名なグラフプロットライブラリです。MATLABライクなプロットでPythonユーザに大変人気です。
当WATLABブログでは、
Pythonのmatplotlibで論文に使えるグラフを描く!
Pythonのmatplotlibをオブジェクト指向で使う!
Pythonのmatplotlibアニメーションで楕円の軌跡!
Python/matplotlib3Dプロット!面と散布図を作成
…とmatplotlib関連の記事を書いています。2Dや3Dグラフ、アニメーションプロットと様々な表現が可能なライブラリですので、まだ使った事が無い方は是非上記記事を参照下さい。
Tkinterとmatplotlibを組み合わせる理由
これまで当ブログではmatplotlibをGUIではなくIDE上で使っていました。信号処理、画像処理、機械学習、シミュレーション、Webスクレイピング…と数あるジャンルのプログラムを触っていましたが、どれも特にGUIを必要とはしていませんでした。
これまで当ブログではmatplotlibをGUIではなくIDE上で使っていました。信号処理、画像処理、機械学習、シミュレーション、Webスクレイピング…と数あるジャンルのプログラムを触っていましたが、どれも特にGUIを必要とはしていませんでした。
しかし、IDE上でプログラムを実行していると、条件を変更した時にいちいち実行ボタンを押さないといけません。また、実行ファイルにして第三者に配布したい時はイベントストラクチャを表現できるGUIがあると何かと便利です。
特にmatplotlibはユーザが最終的に得たいグラフというアウトプットを出すので、GUIの需要は高いと感じます。
いつもは必要ないけど、ちょっとした時にあると便利…というのがGUIだと思います。そのため特に特別なライブラリを使用しなくて済むTkinterとmatplotlibを連携させようと思います。
Tkinterにmatplotlibのグラフを埋め込むコード
目標
本日のコードの目標は以下のGIF動画に示すもので、Updateボタンをクリックしたらランダムな波形がTkinterで構築したGUI上で更新される…というものです。
それでは早速コードを説明していきましょう!
import文
まずはimport文を以下に示します。
tkinterは「import *」の形でimportし、本文中に「tk.〜」と書かないようにしています。
matplotlibはtkinterと連携させるために、「FigureCanvasTkAgg」をimportしておきます。numpyはサンプル波形を生成するのに使います。
1 2 3 4 |
from tkinter import * from matplotlib import pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg import numpy as np |
プロットの関数を用意する
matplotlibでグラフをプロットする部分は予めdef関数で用意しておきます。こうすることで、グラフを更新する時も関数を呼び出すだけで済みます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# プロットをする関数 def plot_wave(x, y): # Figureインスタンスを生成する。 fig = plt.Figure() # 目盛を内側にする。 plt.rcParams['xtick.direction'] = 'in' plt.rcParams['ytick.direction'] = 'in' # Axesを作り、グラフの上下左右に目盛線を付ける。 ax1 = fig.add_subplot(111) ax1.yaxis.set_ticks_position('both') ax1.xaxis.set_ticks_position('both') # 軸のラベルを設定する。 ax1.set_xlabel('x') ax1.set_ylabel('y') # データをプロットする。 ax1.plot(x, y) return fig |
ボタンイベントの関数を用意する
「Python Tkinterのボタンでイベント処理」で紹介したように、ボタンにはイベントが発生した時のdef関数が必要です。ボタンがクリックされたらnumpyで生成したランダム波形を作り、matplotlibのfigureオブジェクトを得るために先ほどの関数を実行します。
取得したfigを使ってcanvasに関する一連の動作をさせますが、canvasについては後述します。
1 2 3 4 5 6 7 |
def button1(): x = np.arange(0, 10, 0.1) y = np.random.rand(len(x)) fig = plot_wave(x, y) canvas = FigureCanvasTkAgg(fig, frame_2) canvas.draw() canvas.get_tk_widget().grid(row=0, column=0) |
Tkinterのウィンドウを用意する
Tkinterではお決まりのウィンドウを以下のコードで定義します。
1 2 3 4 |
# Windowの設定 root = Tk() root.title("Plot window") root.geometry() |
widgetのレイアウトをする
以下のコードはwidgetをレイアウトするものです。
ここで、widgetはボタンとグラフですが、グラフはcanvasという変数で、FigureCanvasTkAgg()にfigオブジェクトを引数として渡すことでwidgetとして実現しています。
そしてcanvas.get_tk_widget()でwidgetとして配置させます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# Frameの設定 frame_1 = Frame(root, bd=4, relief=GROOVE) frame_2 = Frame(root, bd=4, relief=GROOVE) # widgetの設定 btn1 = Button(frame_1, text='Update', command=button1) fig = plot_wave(0, 0) canvas = FigureCanvasTkAgg(fig, frame_2) # widgetの配置 frame_1.grid(row=0, column=0, sticky=W + E) frame_2.grid(row=1, column=0) btn1.pack(fill=X) canvas.get_tk_widget().grid(row=0, column=0) root.mainloop() |
レイアウトに関する一連の説明は「TkinterのFrame/pack/gridを理解してみる」に載せていますので、詳細はそちらをご覧下さい。
全コード(コピペ用)
以下にコピペ用の全コードを示します。是非お手持ちの環境で実行してみて下さい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
from tkinter import * from matplotlib import pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg import numpy as np # プロットをする関数 def plot_wave(x, y): # Figureインスタンスを生成する。 fig = plt.Figure() # 目盛を内側にする。 plt.rcParams['xtick.direction'] = 'in' plt.rcParams['ytick.direction'] = 'in' # Axesを作り、グラフの上下左右に目盛線を付ける。 ax1 = fig.add_subplot(111) ax1.yaxis.set_ticks_position('both') ax1.xaxis.set_ticks_position('both') # 軸のラベルを設定する。 ax1.set_xlabel('x') ax1.set_ylabel('y') # データをプロットする。 ax1.plot(x, y) return fig def button1(): x = np.arange(0, 10, 0.1) y = np.random.rand(len(x)) fig = plot_wave(x, y) canvas = FigureCanvasTkAgg(fig, frame_2) canvas.draw() canvas.get_tk_widget().grid(row=0, column=0) # Windowの設定 root = Tk() root.title("Plot window") root.geometry() # Frameの設定 frame_1 = Frame(root, bd=4, relief=GROOVE) frame_2 = Frame(root, bd=4, relief=GROOVE) # widgetの設定 btn1 = Button(frame_1, text='Update', command=button1) fig = plot_wave(0, 0) canvas = FigureCanvasTkAgg(fig, frame_2) # widgetの配置 frame_1.grid(row=0, column=0, sticky=W + E) frame_2.grid(row=1, column=0) btn1.pack(fill=X) canvas.get_tk_widget().grid(row=0, column=0) root.mainloop() |
まとめ
本記事ではPython標準のGUIプログラミングであるTkinterと、Pythonの強力なグラフプロットライブラリであるmatplotlibを連携させてみました。
とりあえずボタン操作でグラフを更新…という程度のことは本ソフトでできるようになりました。
Tkinterに少しずつ慣れてきました!必要であればいつでも使えるようにしておこうと思います!
Twitterでも関連情報をつぶやいているので、wat(@watlablog)のフォローお待ちしています!