2022-03-05

Matplotlib と QThread

Matplotlib は、Python および NumPy のためのグラフ描画ライブラリです。Qt for Python (PySide) などと組み合わせて GUI アプリを作成するのに重宝しています。調子に乗ってプロットに時間がかかるような、ちょっと重い処理にも応用を広げているのですが、当然、プロットされるまでの間、GUI が固まってしまいます。

自分だけで使うときは、判っているので、ちょっと待つという我慢で済みます。しかし、他の人も使うような場合は、このままにはできません。時間のかかる処理は QThread を使って GUI が固まらないように別スレッドで処理させるように配慮する必要があります。

なんかうまくいかない

当初の方針は、Matplotlib で作成するプロットを別スレッドで処理して、その出力である canvas をメインのスレッドに渡して GUI に表示する、というものでした。しかし、テスト用のプログラムは、もっともらしい動作をするものの、肝心のプロットの内容を表示できませんでした。

ふと、下記の警告に気が付きました。

Starting the Matplotlib GUI outside the main thread may fail.

なんと、別スレッドで Matplotlib の描画処理をするのはうまくいかないようです。

プロットのためのデータセット準備の部分をスレッドに

考えてみると、プロットを描画する時間がボトルネックになっているわけではなく、プロットするためのデータセットの準備に時間がかかっています。

上記 Matplotlib の処理を別スレッドでできるやり方を探すよりも、時間がかかるであろうデータセット準備の処理部分を別スレッドにするようにした方が確実そうです。

そうすると、今まで作っていたアプリの構成が悪く、スレッド化のために作り直しが多く発生しそうで青くなっています。スレッド化を後回しにしたツケが回ってきました。

とにもかくにも、簡単なサンプルを作って、これをもとに基本構成を作り直すことにしました。

サンプル

長い前置きでしたが、本記事では、その簡単なサンプルを紹介します。なお、下記の OS 環境で動作確認をしました。

Fedora 35 Silverblue x86_64
Python 3.10.2
PySide6 6.2.3
matplotlib 3.5.1

以下にサンプルの実行例を示します。上部ツールバーの plot をクリックすると散布図を描画するという単純なサンプルです。

qt_matplotlib_scatter_thread.py の実行例

サンプルコードを下記に示しました。時間がかかる処理の雰囲気を出すために、ダミーで 2 秒のスリープを入れました。

qt_matplotlib_scatter_thread.py

※ コードを更新しました。[2022-04-10]

参考サイト

  1. Use PyQt's QThread to Prevent Freezing GUIs – Real Python
  2. QThread

 

 

ブログランキング・にほんブログ村へ bitWalk's - にほんブログ村 にほんブログ村 IT技術ブログ Linuxへ
にほんブログ村
このエントリーをはてなブックマークに追加

0 件のコメント: