2023-07-16

PySide6 と Matplotlib

PySide (Qt for Python) は、Qt(キュート)の Python バインディングで、GUI などを構築するためのクロスプラットフォームなライブラリです。配布ライセンスは LGPL で公開されています(商用ライセンスも有り)。最新のバージョンは Qt6 に対応した PySide6(記事執筆時点で 6.5.1.1)です。

PySide6 の GUI アプリで Matplotlib のプロットを扱うとき、確実に削除できるようにすることを意識しすぎてしまいます。

なぜか?それはプロットする度に新しいインスタンスを作成していたからです。インスタンスを再利用してプロットし直す、という考えが無かったのでした。ということで、今さらですが、プロットを更新するサンプルを作成しました。

下記の OS 環境で動作確認をしました。

Fedora Linux 38 (Server Edition) x86_64
python3.11 python3-3.11.4-1.fc38.x86_64
PySide6 6.5.1.1

以下のサンプルでは、matplotlib のプロットで日本語フォントを表示するために fonts フォルダーに RictyDiminished-Regular.ttf [2] を保存して利用しています。

また、Matplotlib のプロットの更新については、参考サイト [3] の内容を参考にさせていただきました。

qt_matplotlib_update.py
import random
import sys
import matplotlib.font_manager as fm
import matplotlib.pyplot as plt
from PySide6.QtCore import Qt
from PySide6.QtGui import QFontDatabase, QFont
from PySide6.QtWidgets import (
QApplication,
QMainWindow,
QToolBar,
QToolButton,
)
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
FONT_PATH = 'fonts/RictyDiminished-Regular.ttf'
class MyCanvas(FigureCanvas):
def __init__(self):
fm.fontManager.addfont(FONT_PATH)
font_prop = fm.FontProperties(fname=FONT_PATH)
plt.rcParams['font.family'] = font_prop.get_name()
plt.rcParams['font.size'] = 16
self.fig = Figure()
self.axes = self.fig.add_subplot(111)
super().__init__(self.fig)
def clearAxes(self):
self.axes.cla()
def refreshDraw(self):
self.fig.canvas.draw()
class Example(QMainWindow):
count = 1
def __init__(self):
super().__init__()
self.init_ui()
self.setWindowTitle('Ploy Example')
def init_ui(self):
id = QFontDatabase.addApplicationFont(FONT_PATH)
if id < 0:
print("Error")
sys.exit()
families = QFontDatabase.applicationFontFamilies(id)
print(families)
toolbar = QToolBar()
self.addToolBar(Qt.TopToolBarArea, toolbar)
toolbutton = QToolButton()
toolbutton.setText('更新')
toolbutton.setFont(QFont(families[0], 12))
toolbutton.clicked.connect(self.toolButtonClicked)
toolbar.addWidget(toolbutton)
self.plot = MyCanvas()
self.draw_plot()
self.setCentralWidget(self.plot)
def toolButtonClicked(self):
self.plot.clearAxes()
self.draw_plot()
self.plot.refreshDraw()
def draw_plot(self):
# TEST PLOTS
n_data = 100
list_x = [x for x in range(n_data)]
list_y = [(random.random() - 0.5) * 100 for i in range(n_data)]
self.plot.axes.plot(list_x, list_y)
#
self.plot.axes.set_title('テスト %d' % self.count)
self.plot.axes.set_xlabel('X軸')
self.plot.axes.set_ylabel('Y軸')
self.plot.axes.grid()
self.count += 1
def main():
app = QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec())
if __name__ == '__main__':
main()

ツールバーの更新ボタンをクリックすると、プロットが更新されます。

実行例

参考サイト

  1. How to clear the memory completely of all Matplotlib plots
  2. edihbrandon/RictyDiminished: Ricty Diminished --- fonts for programming
  3. Matplotlib plots in PySide6, embedding charts in your GUI applications

 

ブログランキング・にほんブログ村へ bitWalk's - にほんブログ村 にほんブログ村 IT技術ブログ オープンソースへ
にほんブログ村

オープンソース - ブログ村ハッシュタグ
#オープンソース



0 件のコメント: