Python で GUI アプリを作成するときに Qt の Python 用バインディングである PySide (Qt for Python) を使用することが多くなりました。散布図などのチャート作成には、もっぱら matplotlib を使っていますが、他の選択肢も検討しようと、QtCharts というチャート作成用ライブラリの使い方をまとめました。
当初、PySide 用の QtCharts のサンプルが見つからず、C++ 用のサンプル [1] を PySide 用に書き直していましたが、よく探してみると PySide 用サンプルもありました [2]。ここでは、勉強がてら C++ 用のサンプルを書き直したものを紹介していきます。
本記事では、下記の OS 環境を使用しています。
![]() |
Fedora 34 Workstation | x86_64 |
- Python 3.9.6 | ||
- PySide6 6.1.2 (venv) | ||
- IDE: PyCharm 2021.1.3 (Community Edition) |
LineChart(折れ線グラフ)と時間軸
LineChart(折れ線グラフ)は、時系列などの連続的変化をとらえるときに使用するグラフです。前回の記事 [3] では、肝心の時間軸のサンプルを示しませんでしたので、今回は時間軸を扱った折れ線グラフのサンプルを紹介します。
#!/usr/bin/env python | |
# coding: utf-8 | |
# Reference | |
# https://doc.qt.io/qt-6/qtcharts-datetimeaxis-example.html | |
import sys | |
from PySide6.QtCharts import ( | |
QChart, | |
QChartView, | |
QDateTimeAxis, | |
QLineSeries, | |
QValueAxis, | |
) | |
from PySide6.QtCore import ( | |
QDate, | |
QDateTime, | |
QLocale, | |
Qt, | |
) | |
from PySide6.QtGui import QPainter | |
from PySide6.QtWidgets import ( | |
QApplication, | |
QMainWindow, | |
) | |
import numpy as np | |
def datetime_data_reader(name_file): | |
series = QLineSeries() | |
with open(name_file) as f: | |
for line in f: | |
values = line.strip().split() | |
if len(values) == 0: | |
continue | |
if values[0].startswith('#'): | |
continue | |
if values[0].startswith(':'): | |
continue | |
moment_in_time = QDateTime() | |
moment_in_time.setDate(QDate(int(values[0]), int(values[1]), 15)) | |
series.append(np.int64(moment_in_time.toMSecsSinceEpoch()), float(values[2])) | |
return series | |
class LineChart(QChartView): | |
def __init__(self): | |
super().__init__() | |
QLocale.setDefault(QLocale.c()) | |
chart = self.init_ui() | |
self.setChart(chart) | |
self.setRenderHint(QPainter.Antialiasing) | |
def init_ui(self): | |
series = datetime_data_reader('sun_spots.txt') | |
chart = QChart() | |
chart.legend().hide() | |
chart.addSeries(series) | |
chart.setTitle('Sunspots count (by Space Weather Prediction Center)') | |
axisX = QDateTimeAxis() | |
axisX.setTickCount(10) | |
axisX.setFormat('MMM yyyy') | |
axisX.setTitleText('Date') | |
chart.addAxis(axisX, Qt.AlignBottom) | |
series.attachAxis(axisX) | |
axisY = QValueAxis() | |
axisY.setTickCount(10) | |
axisY.setLabelFormat('%i') | |
axisY.setTitleText('Sunspots count') | |
chart.addAxis(axisY, Qt.AlignLeft) | |
series.attachAxis(axisY) | |
return chart | |
class Example(QMainWindow): | |
def __init__(self): | |
super().__init__() | |
linechart = LineChart() | |
self.setCentralWidget(linechart) | |
self.resize(1000, 600) | |
self.setWindowTitle('LineChart (DateTime)') | |
def main(): | |
app = QApplication(sys.argv) | |
ex = Example() | |
ex.show() | |
sys.exit(app.exec()) | |
if __name__ == '__main__': | |
main() |
本サンプルでは、下記のテキストファイルをプロットするデータとして読み込んでいます。
実行例を下記に示しました。
ファイルを読み込んで、データ列 series への追加は、下記のスタティックメソッドで処理しています。
def datetime_data_reader(name_file): series = QLineSeries() with open(name_file) as f: for line in f: values = line.strip().split() if len(values) == 0: continue if values[0].startswith('#'): continue if values[0].startswith(':'): continue moment_in_time = QDateTime() moment_in_time.setDate(QDate(int(values[0]), int(values[1]), 15)) series.append(moment_in_time.toMSecsSinceEpoch(), float(values[2])) return series
横軸(時間軸)axisX と縦軸 axisY はデフォルトの設定を使わずに、個別に設定しています。
axisX = QDateTimeAxis() axisX.setTickCount(10) axisX.setFormat('MMM yyyy') axisX.setTitleText('Date') chart.addAxis(axisX, Qt.AlignBottom) series.attachAxis(axisX)
axisY = QValueAxis() axisY.setTickCount(10) axisY.setLabelFormat('%i') axisY.setTitleText('Sunspots count') chart.addAxis(axisY, Qt.AlignLeft) series.attachAxis(axisY)
なお、日本語環境 ja_JP.UTF-8 下では、チャート横軸 (QDateTimeAxis) の目盛ラベルの表示について axisX.setFormat('MMM yyyy') と書式指定をしても、月の表示が '8月' などと表示されてしまいます。そこで、今回は LineChart クラスのコンストラクタ部でロケールを C に指定して、強制的に ’Aug' というように英語3文字の月名で表示するようにしています。
QLocale.setDefault(QLocale.c())
参考サイト
- Qt Charts Examples | Qt Charts 6.1.2
- Qt for Python Examples — Qt for Python
- bitWalk's: Qt for Python によるチャート (1) [2021-07-19]

にほんブログ村
0 件のコメント:
コメントを投稿