「PyQtの基礎 - グラフ」の版間の差分

提供:MochiuWiki - SUSE, Electronic Circuit, PCB
ナビゲーションに移動 検索に移動
編集の要約なし
100行目: 100行目:
<br>
<br>
次のセクションでは、上記の警告も出力されないように修正を加えながら、動的な画面とグラフを作成する。<br>
次のセクションでは、上記の警告も出力されないように修正を加えながら、動的な画面とグラフを作成する。<br>
<br><br>
== Matplotlibで作成するグラフ ==
上記のセクションにおいて、警告が出力される原因は、<code>add_subplot()</code>関数が2箇所に存在しているからである。<br>
<br>
上記のサンプルコードでは、<code>PlotCanvas</code>クラスのコンストラクタと<code>plot</code>関数の中で、それぞれ<code>add_subplot()</code>関数を使用している。<br>
つまり、axesに関わる変数を2回定義(重複)しているから警告が出力される。<br>
<br>
したがって、まず、<code>plot</code>関数内にある以下の行を削除する。<br>
<source lang="python">
ax = self.figure.add_subplot(111)
</source>
<br>
次に、上記で削除した変数axが使用されている箇所を修正する。<br>
コンストラクタで定義している変数<code>self.axes</code>にすればよい。<br>
<br>
以上で、警告は出力されなくなる。<br>
<br>
このセクションでは、以下の機能を実装する。<br>
* メニューバー:終了メニュー
* ステータスバー:時計
* グラフの再描画・削除機能
<br>
メニューバーとステータスバーについては、[[PyQtの基礎 - 画面]]に記載したサンプルコードを使用する。<br>
グラフの再描画・削除機能についても、それぞれのボタンを配置して、それらのボタンを描画と削除の関数に<code>clicked.connect</code>する。<br>
<br>
以下のサンプルコードでは、警告が出力されないように修正を加え、上記の3つの機能を実装している。<br>
なお、クラス名や変数名等は変更している箇所がある。<br>
<source lang="python">
# - * - coding: utf8 - *
import sys
import random  # 乱数を使用
import datetime
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QTimer
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
# 画面用クラス
class plotGraph(QMainWindow):
    def __init__(self):
        super().__init__()
        self.title  = "グラフを表示するウインドウ"
        self.width  = 700
        self.height = 400
        self.setWindowTitle(self.title)
        self.setGeometry(0, 0, self.width, self.height)
        self.setWindowLayout()
        self.statusBar()
    def setWindowLayout(self):
        # メニューバーアクションの定義
        exitAction = QAction("&終了", self)
        exitAction.setShortcut("Ctrl+Q")
        exitAction.setStatusTip("ウィンドウを閉じる")
        exitAction.triggered.connect(qApp.quit)
        menubar = self.menuBar()
        fileMenu = menubar.addMenu("ファイル")
        fileMenu.addAction(exitAction)
        self.w = QWidget()
        # グラフを打つPlotCanvasクラスのインスタンスを生成
        self.m = PlotCanvas(self, width=5, height=4)
        # ボタンの作成
        self.plt_button = QPushButton("グラフを打つ", self)
        self.plt_button.clicked.connect(self.m.plot)
        self.del_button = QPushButton("グラフを消す", self)
        self.del_button.clicked.connect(self.m.clear)
        # GridLayoutの使用
        main_layout = QGridLayout()
        # GridLayoutの配置を指定
        main_layout.addWidget(self.m, 0, 0, 5, 4)
        main_layout.addWidget(self.plt_button, 0, 11, 1, 1)
        main_layout.addWidget(self.del_button, 0, 11, 2, 1)
        # タイマイベントの指定
        timer = QTimer(self)
        timer.timeout.connect(self.getDateTime)
        timer.start(1000)
        self.w.setLayout(main_layout)
        self.setCentralWidget(self.w)
        self.show()
    def getDateTime(self):
        dt = datetime.datetime.today()
        dt_str = dt.strftime("%Y年%m月%d日 %H時%M分%S秒")
        self.statusBar().showMessage("日時" + " " + dt_str)
# グラフを描画するクラス
class PlotCanvas(FigureCanvas):
    def __init__(self, parent=None, width=5, height=4, dpi=100):
        self.fig = Figure(figsize=(width, height), dpi=dpi)
        self.axes = self.fig.add_subplot(111)
        super(PlotCanvas, self).__init__(self.fig)
        self.setParent(parent)
        FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Expanding)
        FigureCanvas.updateGeometry(self)
        self.plot()
    def plot(self):
        self.axes.cla()
        self.data = [random.random() for i in range(25)]
        self.axes.plot(self.data, 'r-')
        self.axes.set_title("PyQt5 & Matplotlib Graph")
        self.draw()
    def clear(self):
        self.axes.cla()
        self.draw()
def main():
    app = QApplication(sys.argv)
    window = plotGraph()
    sys.exit(app.exec_())
if __name__ == '__main__':
    main()
</source>
<br>
上記のサンプルコードを実行すると、下図のような画面が表示される。<br>
<br>
右側にあるボタンを押すと、それぞれグラフを再描画・削除する。<br>
さらに、メニューバーからウィンドウを終了することができ、ステータスバーには時計が表示される。<br>
<br>
このページでは記載は無いが、例えば、メニューから再描画・削除できるようにする、複数のグラフを表示する等も行うことができる。<br>
また、上記のサンプルコードでは、グラフで使用するデータを乱数で生成しているが、CSVファイル等を読み込み、グラフを描画することもできる。<br>
<br><br>
<br><br>


__FORCETOC__
__FORCETOC__
[[カテゴリ:Python]]
[[カテゴリ:Python]]

2020年9月30日 (水) 17:43時点における版

概要

ここでは、PyQtとMatplotlibを使用して、グラフを表示する方法を記載する。


Matplotlibとは

Matplotlibとは、PythonやNumPyで使用するためのグラフ描画用ライブラリである。
Matplotlibは、豊富な種類のグラフを生成することができる。

MatplotlibはPythonの標準ライブラリではないので、別途インストールする必要がある。
以下のコマンドを実行して、Matplotlibをインストールする。

pip3 install matplotlib


実務上において、NumPyやSciPyと合わせて使用することが多い。
その時は、必要に応じてNumPy等もpipコマンドを使用してインストールすること。
(このページでは、NumPyやSciPyは使用しない)

また、Matplotlibをさらに詳しく知りたい場合は、公式Webサイトにアクセスして確認すること。


Matplotlibで作成するグラフ (1)

このセクションでは、PyQtとMatplotlibを使用してグラフを表示する。
こちらのWebサイトのチュートリアルにあるPyQt5 Matplotlibという箇所とサンプルコードを参考にする。

下図のグラフは、Matplotlibによって描画されたグラフである。
この画面とグラフを表示するためのサンプルコードを以下に示す。(このサンプルコードは、上記のチュートリアルから引用している)


 # - * - coding: utf8 - *
 
 import sys
 import random
 
 from PyQt5.QtWidgets import QApplication, QMainWindow, QMenu, QVBoxLayout, QSizePolicy, QMessageBox, QWidget, QPushButton
 from PyQt5.QtGui import QIcon
 
 from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
 from matplotlib.figure import Figure
 import matplotlib.pyplot as plt
 
 
 class App(QMainWindow):
 
    def __init__(self):
        super().__init__()
        self.left   = 10
        self.top    = 10
        self.title  = "PyQt5 matplotlib example - pythonspot.com"
        self.width  = 640
        self.height = 400
 
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)
 
        m = PlotCanvas(self, width=5, height=4)
        m.move(0,0)
 
        button = QPushButton('PyQt5 button', self)
        button.setToolTip('This s an example button')
        button.move(500,0)
        button.resize(140,100)
 
        self.show()
 
 
 class PlotCanvas(FigureCanvas):
 
    def __init__(self, parent=None, width=5, height=4, dpi=100):
        fig       = Figure(figsize=(width, height), dpi=dpi)
        self.axes = fig.add_subplot(111)
 
        FigureCanvas.__init__(self, fig)
        self.setParent(parent)
 
        FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Expanding)
        FigureCanvas.updateGeometry(self)
        self.plot()
 
 
    def plot(self):
        data = [random.random() for i in range(25)]
        ax   = self.figure.add_subplot(111)
        ax.plot(data, 'r-')
        ax.set_title('PyQt Matplotlib Example')
        self.draw()
 
 
 if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = App()
    sys.exit(app.exec_())


上記のサンプルコードを実行すると、コンソール上に次のような警告が出力される。(挙動自体に影響はないと思われる)

MatplotlibDeprecationWarning: Adding an axes using the same arguments   
as a previous axes currently reuses the earlier instance. In a future version,   
a new instance will always be created and returned. Meanwhile, this warning can   
be suppressed, and the future behavior ensured, by passing a unique label to each axes instance.
warnings.warn(message, mplDeprecation, stacklevel=1)


次のセクションでは、上記の警告も出力されないように修正を加えながら、動的な画面とグラフを作成する。


Matplotlibで作成するグラフ

上記のセクションにおいて、警告が出力される原因は、add_subplot()関数が2箇所に存在しているからである。

上記のサンプルコードでは、PlotCanvasクラスのコンストラクタとplot関数の中で、それぞれadd_subplot()関数を使用している。
つまり、axesに関わる変数を2回定義(重複)しているから警告が出力される。

したがって、まず、plot関数内にある以下の行を削除する。

 ax = self.figure.add_subplot(111)


次に、上記で削除した変数axが使用されている箇所を修正する。
コンストラクタで定義している変数self.axesにすればよい。

以上で、警告は出力されなくなる。

このセクションでは、以下の機能を実装する。

  • メニューバー:終了メニュー
  • ステータスバー:時計
  • グラフの再描画・削除機能


メニューバーとステータスバーについては、PyQtの基礎 - 画面に記載したサンプルコードを使用する。
グラフの再描画・削除機能についても、それぞれのボタンを配置して、それらのボタンを描画と削除の関数にclicked.connectする。

以下のサンプルコードでは、警告が出力されないように修正を加え、上記の3つの機能を実装している。
なお、クラス名や変数名等は変更している箇所がある。

 # - * - coding: utf8 - *
 
 import sys
 import random   # 乱数を使用
 import datetime
 
 from PyQt5.QtWidgets import *
 from PyQt5.QtCore import QTimer
 
 from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
 from matplotlib.figure import Figure
 import matplotlib.pyplot as plt
 
 
 # 画面用クラス
 class plotGraph(QMainWindow):
 
     def __init__(self):
         super().__init__()
         self.title  = "グラフを表示するウインドウ"
         self.width  = 700
         self.height = 400
 
         self.setWindowTitle(self.title)
         self.setGeometry(0, 0, self.width, self.height)
 
         self.setWindowLayout()
         self.statusBar()
 
 
     def setWindowLayout(self):
        # メニューバーアクションの定義
        exitAction = QAction("&終了", self)
        exitAction.setShortcut("Ctrl+Q")
        exitAction.setStatusTip("ウィンドウを閉じる")
        exitAction.triggered.connect(qApp.quit)
 
        menubar = self.menuBar()
        fileMenu = menubar.addMenu("ファイル")
        fileMenu.addAction(exitAction)
 
        self.w = QWidget()
 
        # グラフを打つPlotCanvasクラスのインスタンスを生成
        self.m = PlotCanvas(self, width=5, height=4)
 
        # ボタンの作成
        self.plt_button = QPushButton("グラフを打つ", self)
        self.plt_button.clicked.connect(self.m.plot)
        self.del_button = QPushButton("グラフを消す", self)
        self.del_button.clicked.connect(self.m.clear)
 
        # GridLayoutの使用
        main_layout = QGridLayout()
 
        # GridLayoutの配置を指定
        main_layout.addWidget(self.m, 0, 0, 5, 4)
        main_layout.addWidget(self.plt_button, 0, 11, 1, 1)
        main_layout.addWidget(self.del_button, 0, 11, 2, 1)
 
        # タイマイベントの指定
        timer = QTimer(self)
        timer.timeout.connect(self.getDateTime)
        timer.start(1000)
 
        self.w.setLayout(main_layout)
        self.setCentralWidget(self.w)
        self.show()
 
 
    def getDateTime(self):
        dt = datetime.datetime.today()
        dt_str = dt.strftime("%Y年%m月%d日 %H時%M分%S秒")
        self.statusBar().showMessage("日時" + " " + dt_str)
 
 
 # グラフを描画するクラス
 class PlotCanvas(FigureCanvas):
 
     def __init__(self, parent=None, width=5, height=4, dpi=100):
         self.fig = Figure(figsize=(width, height), dpi=dpi)
         self.axes = self.fig.add_subplot(111)
 
         super(PlotCanvas, self).__init__(self.fig)
         self.setParent(parent)
 
         FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Expanding)
         FigureCanvas.updateGeometry(self)
         self.plot()
 
 
     def plot(self):
         self.axes.cla()
         self.data = [random.random() for i in range(25)]
         self.axes.plot(self.data, 'r-')
         self.axes.set_title("PyQt5 & Matplotlib Graph")
         self.draw()
 
 
     def clear(self):
         self.axes.cla()
         self.draw()
 
 
 def main():
     app = QApplication(sys.argv)
     window = plotGraph()
     sys.exit(app.exec_())
 
 
 if __name__ == '__main__':
     main()


上記のサンプルコードを実行すると、下図のような画面が表示される。

右側にあるボタンを押すと、それぞれグラフを再描画・削除する。
さらに、メニューバーからウィンドウを終了することができ、ステータスバーには時計が表示される。

このページでは記載は無いが、例えば、メニューから再描画・削除できるようにする、複数のグラフを表示する等も行うことができる。
また、上記のサンプルコードでは、グラフで使用するデータを乱数で生成しているが、CSVファイル等を読み込み、グラフを描画することもできる。