Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Python PySideで作ったGUIにMatplotlibを埋め込んでみた(以前の記事のMatplotlib版)

More than 3 years have passed since last update.

前回の記事

前回は、PySideで作ったGUIに、pyqtgraphでプロットしてみました。

今回の目的

前回のような書き方で、pyqtgraphではなく、matplotlibを動かしてみます。

とりあえずこれをim2.pyとして保存し、実行する。

im2.py
from PySide import QtCore, QtGui

import matplotlib.pyplot as plt

import matplotlib
matplotlib.rcParams['backend.qt4'] = 'PySide'

from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        MainWindow.setCentralWidget(self.centralwidget)

        self.verticalLayout = QtGui.QVBoxLayout(self.centralwidget)
        self.verticalLayout.setObjectName("verticalLayout")

        self.fig = plt.Figure()
        self.graph01 = FigureCanvas(self.fig)
        self.ax1 = self.fig.add_subplot(211)
        self.ax2 = self.fig.add_subplot(212)

        self.graph01.setObjectName("graph01")
        self.verticalLayout.addWidget(self.graph01)

        self.psbtn = QtGui.QPushButton(self.centralwidget)
        self.psbtn.setObjectName("psbtn")
        self.psbtn.setText("Plot")
        self.verticalLayout.addWidget(self.psbtn)
        QtCore.QObject.connect(self.psbtn, QtCore.SIGNAL("clicked()"), self.plot)

    def plot(self):
        frq1 = 10.0
        frq2 = 30.0
        frq3 = 50.0
        duration = 1.0
        samples = 1001

        x1 = np.linspace(0, duration, samples)
        rad1 = np.linspace(0, 2 * np.pi * frq1, samples)
        rad2 = np.linspace(0, 2 * np.pi * frq2, samples)
        rad3 = np.linspace(0, 2 * np.pi * frq3, samples)
        y1 = np.sin(rad1) + np.sin(rad2) + np.sin(rad3) 

        x2 = np.linspace(0,1001,1001)[0:np.floor(len(y1)/2)]
        y2 = abs(np.fft.fft(y1))[0:np.floor(len(y1)/2)]

        self.ax1.plot(x1, y1)
        self.ax2.plot(x2, y2)
        self.graph01.draw()#zettai iru

import sys
import numpy as np

class ControlMainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(ControlMainWindow, self).__init__(parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    mySW = ControlMainWindow()
    mySW.show()
    sys.exit(app.exec_())

こうなる。

20160831 screenshot 41.png
20160831 screenshot 4.png

注意

このままだと、plotボタンを押すたびに、プロットが上書きされて、たまっていく一方なので、プロットする前に、クリアするべきだった。
押すたびに色違いのグラフが描かれていく。
使用メモリがたまっていく様子は、Windowsのタスクマネージャーや、linuxなら「top」コマンド等から見れる。

変更点は...

  • import

import pyqtgraph as pg

1 import matplotlib.pyplot as plt
2 import matplotlib
3 from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas

1個目は、定番。figure, subplot, plot, draw() などで使用した。
2個目は、PySideで使うためのおまじない。 rcParamsの['backend.qt4']を、'PySide'としないとだめらしい。
3個目は、PySideに入れるための部品のimport。plt.figure.Figureは、PySideに直接入れられない。このFigureCanvasQTAggの中にfigureを入れて、それを、addWidgetする。pyqtgraphでいうところの、plotWidget。

  • PlotWidget ⇒ FigureCanvasQTAgg

self.graph = pg.PlotWidget(self.centralwidget)

self.fig = plt.Figure()
self.graph = FigureCanvas(self.fig)
self.ax = self.fig.add_subplot(***)

  • plot

self.graph.plot(x,y)

self.ax.plot(x,y)
(場合によっては、↓も要る)
plt.draw()

全体的に、matplotlibでは行数が増えた。

タイトルとは関係ないけど、前回から変更した点。

前回の10 Hzの信号から、複数の周波数の信号を足し合わせた信号に変えた。
その信号yを使って、abs(fft(y))して、サブプロットし下段に描いた。

MatplotlibとPyQtGraphの比較

メリット

  • matplotlibのメリット
    - LaTeXが使える!
    - matplotlibの扱いに既に慣れていて、(subplotで作ったax1,ax2に次々プロットしては更新し...とか)分かっているのであれば便利。

  • pyqtgraphのメリット

    • 多点プロット時に速い
    • コードが、matplotlibよりも簡潔にできる。
    • (重要)プログラムしなくても、既にインタラクティブなグラフになっている。
      • グラフのズーム、シフトが、プログラムしなくてもできる。グラフを左クリックでドラッグ⇒上下左右に移動。右クリックでドラッグ⇒ズーム
      • 右クリックで、出てくるメニューがすごい。データ点をtxtで排出したり、画像として保存したりできる。 log⇔linearの表示切り替えも、後からできる。 (試してはいないが、)この機能をオフにもできると思う。 20160831 screenshot 1.png

ディメリット

  • matplotlibのディメリット

    • (PySideの場合)いろいろ付け足す必要ある。参考:PythonでmatplotlibとPySideを連携させる
    • ax.plot(x,y)等を書く場所によっては、draw()しないと、グラフ描いてくれない。自分の場合、axを作った関数内なら、plotするだけでプロットしてくれるが、それ以外の関数内でax.plotなどをやっても、何も書いてくれない⇒次の行とかにdraw()があると書いてくれる。
    • デザインが変わる。
      • 自動的に、アプリの縦横サイズでかくなる。
      • グラフ領域の背景が、灰色になる。
    • 多点プロットで遅い。
  • pyqtgraphのディメリット

    • LaTeXが使えない!!!!!!!!!!!!!
    • グラフの枠が見切れる。 20160831 screenshot 2.png 20160831 screenshot 3.png
    • 自動で、グラフの大きさを調節してくれない。前回のim.pyのように、アプリの大きさを指定しないと、ものすごい小さいプロットを作ってくる。
    • ディフォルトの背景黒く、怪しい。直すには、2行くらい必要。
      • pg.setConfigOption('foreground', 'k')
      • pg.setConfigOption('background', 'w')

pyqtgraphは

(重要)ユーザーの少なさから、情報量が圧倒的にmatplotlibに負けているけど、pysideや、pyqt上での使い方は、案外あっさり分かる仕組みがある↓

import pyqtgraph.examples
pyqtgraph.examples.run()

20160831 screenshot 42.png
圧倒的(それでもmatplotlibには負けるが)に充実したサンプルが、コード付きで見られる。
20160831 screenshot 43.png

ここに、ちゃんと載っているんだけれども、英語は自動的にシャットアウトしてしまうので見逃しがちだった。
http://www.pyqtgraph.org/documentation/introduction.html#examples

PyQtGraphは、広範囲な使用例のセットが含まれています。 下記を実行すれば、その使用例にアクセスできます。

import pyqtgraph.examples
pyqtgraph.examples.run()

これで、使用可能な例のリストを持つランチャーが、開始されます。項目を選んで、そのソースコードを見たり、項目をダブルクリックして、使用例を実行したりして下さい。

要するに

私は、pyqtgraph推し。

個人的な感想

 この記事だけ見ると、matplotlibは、行数多く必要だったり、遅かったりと、ディメリットだらけの様だが、subplotなど、細かい設定をすればするほど、matplotlibの方が、使い勝手が良くなっていくのではないかと思う。

「たかだか、作図のために、何種類もAPIの使い方覚えるとか馬鹿らしい」というのも正論。
ただ、pythonだけでも、何種類も作図のライブラリはあって、それぞれ一長一短があるのも事実。

  • 論文や報告書に載せるようなグラフを、きれいに仕上げたい場合は、matplotlib
  • GUIに入れるなら、pyqtgraph

とか使い分けてもいい気がする。

個人のブログには、誰もコメントを書いてくれないので、コメントを頂いてすごい嬉しかったので、再度投稿してみました。QiitaのSEOは素晴らしいですね。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away