Python(PySide + PyQtGraph)による「おれおれグラフ生成アプリケーション」その1

#はじめに
プログラミングを専門としない人でも、データがあるとグラフを作りたくなります。
そのためにまず思いつくのはExcelでしょう。グラフのプロトタイピングとしても広く用いられていますが、マクロである程度の楽が出来るとはいえ、手間だったり、遅かったり、重かったり、細かいところで融通が効かなかったりと、イラっとすることは多いのではないでしょうか。
特に試行数の多い実験屋さんだと、数百試行分のデータファイルを逐一Excelに取り込んで―などやっていては気が遠くなってしまいます。ましてや、変数やグラフの凡例にちょっとしたミスを発見した時など……。

もちろんgnuplotなど比較的気軽に使えるグラフ描写ソフトウェアもあります。
が、どうせなら自分用にフルカスタマイズされたグラフ生成アプリケーションを使いたいじゃないですか……！いや……作りたいじゃないですか！と、まぁそんな人の指針になればと思い、諸々まとめて公開します。

今回の内容は「導入とプログラム全体像」です。

#目標
基本的には実験屋のための「おれおれグラフ生成アプリケーション」の開発を目標とします。具体的には「計測データが格納されたファイルを読み込み、GUI上のエディット部で変数を変えつつ、グラフ描写する」アプリケーションです。
これから作っていく「おれおれGUI」じゃ気に食わなかったり、手持ちのデータが取り扱うファイル形式と違っていたり、変数は変える必要がなかったりすると思いますが、そこは必要に応じて適宜改変して「おれおれ」してください。
一応、PySide部(GUI生成部)、PyQtGraph部(グラフ描写部)、細かい処理部の説明は出来るだけ分けていますので、必要に応じた部分のみでも読めるようにはしているつもりです。

![おれおれグラフ生成アプリケーション](https://qiita-image-store.s3.amazonaws.com/0/55744/2d1f4bab-7988-76e6-a0c9-25aaea486cbc.png)

前提知識は「Python3の基礎知識(～条件分岐・ループまで)」を想定しています。
「おれおれ」を念頭に、手元で動けばいいことを最優先にしているのでオブジェクト指向の考え方はスルーします。PySideとPyQtGraphのところは少し詳しく説明していきます。

正直に言うと趣味プログラマーなのでわかっていない部分も多いです。間違いなどあればご指摘ください。

#PySideについて
[Category:LanguageBindings::PySide - Qt Wiki](https://wiki.qt.io/Category:LanguageBindings::PySide)
PySideはC++のクロスプラットフォームGUIフレームワーク「Qt」をPythonから利用できるようにしたライブラリー群です。PyQtというものもありますがライセンスが異なります(GPLとLGPL)。Qtはデスクトップ向けのクロスプラットフォームGUIフレームワークとしては最も新しい(？)とかで、モダンでクールで使いやすいです(適当)。
元は、かつての「Qt」の持ち主だったNokiaが、Qt4をPythonでも使えるようにと開発を始めました。その後いろいろとごたごたあったのですが、最近、CADソフトウェア大手のAutodeskが最新版であるQt5にも対応させようと動き出した、みたいな話がメーリングリストに流れていました。
「PySide」を検索ワードにTwitterを追っていると、Autodesk製3D CGソフト「Maya」を拡張するために結構利用されているみたいです。Autodesk製品はQtを利用しているものが多いので、その繋がりもあってなのかと思います。ちなみに日本語ツイートが非常に多いですよ。

#PyQtGraphについて
[PyQtGraph - Scientific Graphics and GUI Library for Python](http://www.pyqtgraph.org/)
Pythonのグラフ描写ライブラリーとしておそらく最も有名なのはMatplotlibかと思います。
多くの比較ポイントは[公式サイト](http://www.pyqtgraph.org/)に記載されていますが、Matplotlibの弱点である描画の即応性を重視して開発されているのがこのPyQtGraphです。「Matplotlibの方が成熟してるし、使ってる人多いし、基本あっち使ったほうがいいよ」なんてPyQtGraph側が言っている通りPyQtGraphには足らない点も多少あるようです。が、コミュニティーの議論も活発なので時間の問題でしょう。
個人的にはMatplotlibで調整しないままグラフを2つ並べて表示すると、下のように描写域が被ったり、軸ラベルが欠けたりしてしまう問題が、PyQtGraphでは起こらないところが最高だと思います。
その名の通り、Qt(正確にはPyQt / PySIde)を派生させた、グラフ描写に特化したGUIライブラリーです。

![Matploylib vs PyQtGraph](https://qiita-image-store.s3.amazonaws.com/0/55744/654f3ce8-6d81-f2e7-7c79-a3213bf3b2d6.png)
※両者ともにできるだけデフォルト表示

#インストール
最新のPythonが導入済みなら、どちらもインストールはコマンドプロンプト(ターミナル/端末)にpipコマンドで一発です。もしかしたらPyQtGraph入れるときにnampyが必要になるかもしれません。そのときはAnacondaとか使ってください。

```
pip install PySide
pip install PyQtGraph
```

#プログラムの全体像
今後の説明の流れをわかりやすくするためにも、今回はとりあえずプログラムの全体像を説明します。適当に「graphApp.py」等のファイル名で、下記の内容のPythonのソースファイルを作成してください。

```py3:graphApp.py
# [1]
import sys
import os
from PySide.QtCore import *
from PySide.QtGui import *
import pyqtgraph as pg

# [3]
class MainWindow(QWidget):
# [4]
    # MainWindowクラスの初期化(GUIの生成、シグナルスロット接続)
    def __init__(self, parent = None):
        super(MainWindow, self).__init__(parent)
    
# [5]
    # fileNameListWidgetを更新する
    def updateFileNameListWidget(self, fileNameListWidget, folderPath):
        print('updateFileNameListWidget')
    
# [6]
    # グラフ生成関数
    def createGraph(self, folderPath, fileName):
        print('createGraph')
    
# [6.1]
    # データリストの集合を生成する
    def createDataListSet(self, folderPath, fileName):
        print('createDataListSet')
    
# [6.2]
    # データリストの集合を読み込む
    def loadDataListSet(self, folderPath, fileName):
        print('loadDataListSet')
    
# [6.3]
    # テスト用グラフを生成する
    def createTestGraph(self, dataListSet):
        print('createTestGraph')

# [2]
if __name__ == '__main__':
    # Qt Applicationを作ります
    app = QApplication(sys.argv)
    # ウィンドウを作成して表示します
    mainWin = MainWindow()
    mainWin.show()
    # Qtのメインループを開始します
    sys.exit(app.exec_())
```

釈迦に説法な部分も含めてになりますが説明していきます。各関数にはダミーとしてprint()文を記述しています。

まず、**[1]**において必要なモジュール、ライブラリーのインポートを行います。osモジュールは計測データの格納されたファイルの読み込む際に使用します。PySideとPyQtGraphのインポートについて、

```py3
from PySide.QtCore import *
from PySide.QtGui import *
import pyqtgraph as pg
```

となっているのは打鍵量を減らすためですね。Matplotlibを使うとなると余分にライブラリーをインポートする必要がありますが、この辺りPyQtGraphを使うとシンプルにまとまります。

続いてメイン関数として**[2]**部分が実行されます。コメント通りではありますが、以下の箇所において、

```py3
    # ウィンドウを作成して表示します
    mainWin = MainWindow()
    mainWin.show()
```

mainWinというウィンドウを生成し、表示します。

mainWinであるMainWindow()クラスは**[3]**および**[4]**からわかるようにQWwidgetを継承しQWwidgetで初期化します。次回、**[4]**の中にファイル一覧を表示のためのリストウィジェットや、表示する一覧のディレクトリを記述するテキストボックス、グラフ描写領域などのGUI要素を記述していくことになります。

**[5] updateFileNameListWidget()**は、先に述べたリストウィジェットにファイル一覧を表示するための関数です。

**[6] createGraph()**は、データリストを生成し、それを元にグラフ描写するためのクッション関数です。データリストは**[6.1] createDataListSet()**および**[6.2] loadDataListSet()**で生成します。具体的には、一度**[6.2]**を呼び出してファイルに格納された計測データを読み込み、**[6.1]**において得られたデータリストに対し係数をかけるなど整形し、returnすることになります。この整形後のデータリストを**[6.3] createTestGraph()**に投げることでグラフを描写します。



以上がこれから作成していくプログラムの全体像です。

……ちなみに実は、このままでもGUIを持ったプログラムとして実行することができます。以下の通り、「graphApp.py」が置かれてるディレクトリを開き実行してみてください。まっさらなウィンドウが開かれるかと思います。

```
cd 「graphApp.py」が置かれてるディレクトリ
python graphApp.py
```

![その1成果](https://qiita-image-store.s3.amazonaws.com/0/55744/2112538b-1639-dd26-3f1a-bfebe9ee9acf.png)


#次回予告
次回以降、先ほどのプログラムを最終的に300行ちょっとのコードへとむくむくと成長させていく予定です。
次回は[4] \_\_init\_\_()内にPySideによるGUIプログラミングを行います。

*その1 - 導入とプログラム全体像* … 今回
**その2 - PySideによるGUIプログラミング** … 次回
その3 - ファイル一覧の生成
その4 - PyQtGraphによるグラフ生成1（基本編）
その5 - PyQtGraphによるグラフ生成2（多軸グラフ編）
その6 - PyQtGraphによるグラフ生成3（体裁を整える編）
以降未定……