「PyQtの基礎 - グラフ」の版間の差分
編集の要約なし |
|||
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ファイル等を読み込み、グラフを描画することもできる。