2021-07-31

Qt for Python によるチャート (13)

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.2 (Community Edition)

PieChart(円グラフ)

円グラフは、円全体を 100% として、その中に占める項目の構成比を扇形で表したグラフです。

qtcharts_piechart.py
#!/usr/bin/env python
# coding: utf-8
# Reference
# https://doc.qt.io/qt-6/qtcharts-piechart-example.html
import sys
from PySide6.QtCharts import (
QChart,
QChartView,
QPieSeries,
)
from PySide6.QtCore import Qt
from PySide6.QtGui import (
QPainter,
QPen
)
from PySide6.QtWidgets import (
QApplication,
QMainWindow,
)
class PieChart(QChartView):
def __init__(self):
super().__init__()
chart = self.init_ui()
self.setChart(chart)
self.setRenderHint(QPainter.Antialiasing)
def init_ui(self):
series = QPieSeries()
series.append('Jane', 25)
series.append('Joe', 16)
series.append('Andy', 9)
series.append('Barbara', 4)
series.append('Axel', 1)
slice1 = series.slices()[1]
slice1.setExploded()
slice1.setLabelVisible()
slice1.setPen(QPen(Qt.darkGreen, 2))
slice1.setBrush(Qt.green)
chart = QChart()
chart.addSeries(series)
chart.setTitle('Simple piechart example')
chart.setAnimationOptions(QChart.SeriesAnimations)
chart.legend().setVisible(True)
chart.legend().setAlignment(Qt.AlignBottom)
return chart
class Example(QMainWindow):
def __init__(self):
super().__init__()
piechart = PieChart()
self.setCentralWidget(piechart)
self.resize(500, 300)
self.setWindowTitle('PieChart')
def main():
app = QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec())
if __name__ == '__main__':
main()

実行例を下記に示しました。

qtcharts_piechart.py の実行例

QPieSeries クラスのインスタンスに、データラベルとデーター量を対にして追加します。

        series = QPieSeries()
        series.append('Jane', 25)
        series.append('Joe', 16)
        series.append('Andy', 9)
        series.append('Barbara', 4)
        series.append('Axel', 1)

特定のデータを際立たしたい場合には、定義したデータを格納した slices のリストから(0 からの)順番を指定して QPieSlice クラスのインスタンスを取り出し、装飾します。

        slice1 = series.slices()[1]
        slice1.setExploded()
        slice1.setLabelVisible()
        slice1.setPen(QPen(Qt.darkGreen, 2))
        slice1.setBrush(Qt.green)

参考サイト

  1. Qt Charts Examples | Qt Charts 6.1.2
  2. Qt for Python Examples — Qt for Python

 

ブログランキング・にほんブログ村へ bitWalk's - にほんブログ村 にほんブログ村 IT技術ブログ Linuxへ
にほんブログ村

2021-07-30

Qt for Python によるチャート (12)

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.2 (Community Edition)

BoxWhiskerChart(箱ひげ図)

箱ひげ図(はこひげず、英:box-and-whisker plot)は、データのばらつきをわかりやすく表現するための統計図です。主に多くの水準からなる分布を視覚的に要約し、比較するために用います。箱(box)と、その両側に出たひげ(whisker)で表現されることからこの名があります。

Wikipedia より引用、編集
qtcharts_boxwhiskerchart.py
#!/usr/bin/env python
# coding: utf-8
# Reference
# https://doc.qt.io/qt-6/qtcharts-boxplotchart-example.html
import sys
from PySide6.QtCharts import (
QChart,
QChartView,
QBoxPlotSeries,
QBoxSet,
)
from PySide6.QtCore import Qt
from PySide6.QtGui import QPainter
from PySide6.QtWidgets import (
QApplication,
QMainWindow,
)
def box_data_reader(name_file: str, name_series: str) -> QBoxPlotSeries:
series = QBoxPlotSeries()
series.setName(name_series)
with open(name_file) as f:
for line in f:
values = line.strip().split()
if len(values) == 0:
continue
if values[0] == '#':
continue
boxset = QBoxSet(values[0])
for i in range(1, len(values)):
boxset.append(float(values[i]))
series.append(boxset)
return series
class BoxWhiskerChart(QChartView):
def __init__(self):
super().__init__()
chart = self.init_ui()
self.setChart(chart)
self.setRenderHint(QPainter.Antialiasing)
def init_ui(self):
series_acme: QBoxPlotSeries = box_data_reader('acme_data.txt', 'Acme Ltd')
series_boxwhisk: QBoxPlotSeries = box_data_reader('boxwhisk_data.txt', 'BoxWhisk Inc')
chart = QChart()
chart.addSeries(series_acme)
chart.addSeries(series_boxwhisk)
chart.setTitle('Acme Ltd and BoxWhisk Inc share deviation in 2012')
chart.setAnimationOptions(QChart.SeriesAnimations)
chart.createDefaultAxes()
chart.axes(Qt.Vertical)[0].setMin(15.0)
chart.axes(Qt.Horizontal)[0].setMax(34.0)
chart.legend().setVisible(True)
chart.legend().setAlignment(Qt.AlignBottom)
return chart
class Example(QMainWindow):
def __init__(self):
super().__init__()
boxplot = BoxWhiskerChart()
self.setCentralWidget(boxplot)
self.resize(700, 400)
self.setWindowTitle('Box & Whisker Chart')
def main():
app = QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec())
if __name__ == '__main__':
main()

本サンプルでは、下記の二つのテキストファイルをプロットするデータとして読み込んでいます。

実行例を下記に示しました。

qtcharts_boxwhiskerchart.py の実行例

ファイルを読み込んで、データ列 series への追加は、下記のスタティックメソッドで処理しています。

def box_data_reader(name_file: str, name_series: str) -> QBoxPlotSeries:
    series = QBoxPlotSeries()
    series.setName(name_series)

    with open(name_file) as f:
        for line in f:
            values = line.strip().split()
            if len(values) == 0:
                continue
            if values[0] == '#':
                continue

            boxset = QBoxSet(values[0])
            for i in range(1, len(values)):
                boxset.append(float(values[i]))

            series.append(boxset)

    return series

データ列には QBoxPlotSeries クラス、ボックスプロット用のデータセット作成には QBoxSet クラスのインスタンスを使います。

参考サイト

  1. Qt Charts Examples | Qt Charts 6.1.2
  2. Qt for Python Examples — Qt for Python

 

ブログランキング・にほんブログ村へ bitWalk's - にほんブログ村 にほんブログ村 IT技術ブログ Linuxへ
にほんブログ村

2021-07-29

Qt for Python によるチャート (11)

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)

PercentBarChart(パーセント棒グラフ)

BarChart(棒グラフ)は、縦軸(あるいは横軸)にデータ量をとり、棒の高さ(長さ)でデータの大小を表現したグラフです。以前紹介した棒グラフのサンプル [3] では、横軸のカテゴリに対して、異なるデータ列 (series) を並べて異なる色の棒であらわし、前回 [4] は、それをひとつの棒に積み上げました。

今回は積み上げてカテゴリ毎に一本の棒であらわし、かつ全体を 100% として全体に対するデータの比率をあらわしたパーセント棒グラフのサンプル (PercentBarChart) を紹介します。

qtcharts_percentbarchart.py
#!/usr/bin/env python
# coding: utf-8
# Reference
# https://doc.qt.io/qt-6/qtcharts-percentbarchart-example.html
import sys
from PySide6.QtCharts import (
QBarCategoryAxis,
QBarSet,
QChart,
QChartView,
QPercentBarSeries,
QValueAxis,
)
from PySide6.QtCore import Qt
from PySide6.QtGui import QPainter
from PySide6.QtWidgets import (
QApplication,
QMainWindow,
)
class PercentBarChart(QChartView):
def __init__(self):
super().__init__()
chart = self.init_ui()
self.setChart(chart)
self.setRenderHint(QPainter.Antialiasing)
def init_ui(self):
set0 = QBarSet('Jane')
set1 = QBarSet('John')
set2 = QBarSet('Axel')
set3 = QBarSet('Mary')
set4 = QBarSet('Samantha')
set0 << 1 << 2 << 3 << 4 << 5 << 6
set1 << 5 << 0 << 0 << 4 << 0 << 7
set2 << 3 << 5 << 8 << 13 << 8 << 5
set3 << 5 << 6 << 7 << 3 << 4 << 5
set4 << 9 << 7 << 5 << 3 << 1 << 2
series = QPercentBarSeries()
series.append(set0)
series.append(set1)
series.append(set2)
series.append(set3)
series.append(set4)
chart = QChart()
chart.addSeries(series)
chart.setTitle('Simple percentbarchart example')
chart.setAnimationOptions(QChart.SeriesAnimations)
categories = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']
axisX = QBarCategoryAxis()
axisX.append(categories)
chart.addAxis(axisX, Qt.AlignBottom)
series.attachAxis(axisX)
axisY = QValueAxis()
chart.addAxis(axisY, Qt.AlignLeft)
series.attachAxis(axisY)
chart.legend().setVisible(True)
chart.legend().setAlignment(Qt.AlignBottom)
return chart
class Example(QMainWindow):
def __init__(self):
super().__init__()
barchart = PercentBarChart()
self.setCentralWidget(barchart)
self.resize(500, 300)
self.setWindowTitle('PercentBarChart')
def main():
app = QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec())
if __name__ == '__main__':
main()

実行例を下記に示しました。

qtcharts_percentbarchart.py の実行例

パーセント棒グラフを作成する場合は、QBarSeries クラスの代わりに QPercentBarSeries クラスのインスタンスをデータ列の定義に使用します。

        series = QPercentBarSeries()
        series.append(set0)
        series.append(set1)
        ...
        ...

参考サイト

  1. Qt Charts Examples | Qt Charts 6.1.2
  2. Qt for Python Examples — Qt for Python
  3. bitWalk's: Qt for Python によるチャート (3) [2021-07-21]
  4. bitWalk's: Qt for Python によるチャート (10) [2021-07-28]

 

ブログランキング・にほんブログ村へ bitWalk's - にほんブログ村 にほんブログ村 IT技術ブログ Linuxへ
にほんブログ村

2021-07-28

Qt for Python によるチャート (10)

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)

StackedBarChart(積み上げ棒グラフ)

BarChart(棒グラフ)は、縦軸(あるいは横軸)にデータ量をとり、棒の高さ(長さ)でデータの大小を表現したグラフです。前回紹介した棒グラフのサンプル [3] では、横軸のカテゴリに対して、異なるデータ列 (series) を並べて異なる色の棒であらわしましたが、今回は積み上げてカテゴリ毎に一本の棒であらわした積み上げ棒グラフのサンプル (StackedBarChart) を紹介します。

qtcharts_stackedbarchart.py
#!/usr/bin/env python
# coding: utf-8
# Reference
# https://doc.qt.io/qt-6/qtcharts-stackedbarchart-example.html
import sys
from PySide6.QtCharts import (
QBarCategoryAxis,
QBarSet,
QChart,
QChartView,
QStackedBarSeries,
QValueAxis,
)
from PySide6.QtCore import Qt
from PySide6.QtGui import QPainter
from PySide6.QtWidgets import (
QApplication,
QMainWindow,
)
class StackedBarChart(QChartView):
def __init__(self):
super().__init__()
chart = self.init_ui()
self.setChart(chart)
self.setRenderHint(QPainter.Antialiasing)
def init_ui(self):
set0 = QBarSet('Jane')
set1 = QBarSet('John')
set2 = QBarSet('Axel')
set3 = QBarSet('Mary')
set4 = QBarSet('Samantha')
set0 << 1 << 2 << 3 << 4 << 5 << 6
set1 << 5 << 0 << 0 << 4 << 0 << 7
set2 << 3 << 5 << 8 << 13 << 8 << 5
set3 << 5 << 6 << 7 << 3 << 4 << 5
set4 << 9 << 7 << 5 << 3 << 1 << 2
series = QStackedBarSeries()
series.append(set0)
series.append(set1)
series.append(set2)
series.append(set3)
series.append(set4)
chart = QChart()
chart.addSeries(series)
chart.setTitle('Simple stackedbarchart example')
chart.setAnimationOptions(QChart.SeriesAnimations)
categories = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']
axisX = QBarCategoryAxis()
axisX.append(categories)
chart.addAxis(axisX, Qt.AlignBottom)
series.attachAxis(axisX)
axisY = QValueAxis()
chart.addAxis(axisY, Qt.AlignLeft)
series.attachAxis(axisY)
chart.legend().setVisible(True)
chart.legend().setAlignment(Qt.AlignBottom)
return chart
class Example(QMainWindow):
def __init__(self):
super().__init__()
barchart = StackedBarChart()
self.setCentralWidget(barchart)
self.resize(500, 300)
self.setWindowTitle('StackedBarChart')
def main():
app = QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec())
if __name__ == '__main__':
main()

実行例を下記に示しました。

qtcharts_stackedbarchart.py の実行例

積み上げ棒グラフを作成する場合は、QBarSeries クラスの代わりに QStackedBarSeries クラスのインスタンスをデータ列の定義に使用します。

        series = QStackedBarSeries()
        series.append(set0)
        series.append(set1)
        ...
        ...

参考サイト

  1. Qt Charts Examples | Qt Charts 6.1.2
  2. Qt for Python Examples — Qt for Python
  3. bitWalk's: Qt for Python によるチャート (3) [2021-07-21]

 

ブログランキング・にほんブログ村へ bitWalk's - にほんブログ村 にほんブログ村 IT技術ブログ Linuxへ
にほんブログ村

2021-07-27

Qt for Python によるチャート (9)

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)

InteractScatterChart(やりとりできる散布図)

ScatterChart(散布図)をインタラクティブに変化させるサンプルです。

qtcharts_interactscatterchart.py
#!/usr/bin/env python
# coding: utf-8
# Reference
# https://doc.qt.io/qt-6/qtcharts-scatterinteractions-example.html
import math
import sys
from PySide6.QtCharts import (
QChart,
QChartView,
QScatterSeries,
)
from PySide6.QtCore import (
QPointF,
Qt,
)
from PySide6.QtGui import QPainter
from PySide6.QtWidgets import (
QApplication,
QMainWindow,
)
class InteractScatterChart(QChartView):
def __init__(self):
super().__init__()
chart = self.init_ui()
self.setChart(chart)
self.setRenderHint(QPainter.Antialiasing)
def init_ui(self):
series_a = QScatterSeries()
series_a.setName('scatter1')
series_a.setColor('cyan')
for i in range(8):
x = 0.5 * (i + 1)
for j in range(8):
y = 0.5 * (j + 1)
series_a << QPointF(x, y)
series_b = QScatterSeries()
series_b.setName('scatter2')
series_b.setColor('magenta')
series_a.clicked.connect(lambda point: self.handleClickedPoint(point, series_a, series_b))
series_b.clicked.connect(lambda point: self.handleClickedPoint(point, series_b, series_a))
chart = QChart()
chart.legend().hide()
chart.addSeries(series_a)
chart.addSeries(series_b)
chart.setTitle('Click to interact with scatter points')
chart.createDefaultAxes()
chart.axes(Qt.Horizontal)[0].setRange(0, 4.5)
chart.axes(Qt.Vertical)[0].setRange(0, 4.5)
return chart
def handleClickedPoint(self, clickedPoint: QPointF, series_old: QScatterSeries, series_new: QScatterSeries):
# Find the closest point from series 1
INT_MAX = 100000
closest = QPointF(INT_MAX, INT_MAX)
distance = float(INT_MAX)
points = series_old.points()
for currentPoint in points:
currentDistance = math.sqrt((currentPoint.x() - clickedPoint.x())
* (currentPoint.x() - clickedPoint.x())
+ (currentPoint.y() - clickedPoint.y())
* (currentPoint.y() - clickedPoint.y()))
if currentDistance < distance:
distance = currentDistance
closest = currentPoint
# Remove the closes point from series 1 and append it to series 2
series_old.remove(closest)
series_new.append(closest)
class Example(QMainWindow):
def __init__(self):
super().__init__()
scatter = InteractScatterChart()
self.setCentralWidget(scatter)
self.resize(500, 300)
self.setWindowTitle('InteractScatterChart')
def main():
app = QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec())
if __name__ == '__main__':
main()

実行例を下記に示しました。マウスでプロット点をクリックすると水色から赤紫色(あるいはその逆)に変化します。

qtcharts_interactscatterchart.py の実行例

データ点クリック時のイベントで何か処理をするには、データ列(このサンプルの場合、series_a と series_b )にバインディングを指定します。

        series_a.clicked.connect(lambda point: self.handleClickedPoint(point, series_a, series_b))
        series_b.clicked.connect(lambda point: self.handleClickedPoint(point, series_b, series_a))
    def handleClickedPoint(self, clickedPoint: QPointF, series_old: QScatterSeries, series_new: QScatterSeries):        ...
        ...
        ...

データ点をクリックするイベントから簡単に処理へバインディングできるのは、データ解析用のアプリを作る場合に魅力的な機能ですが、大量のデータを扱ったときにリソースをどれだけ消費することになるかが気になるところです。別途、調べてみる予定です。

参考サイト

  1. Qt Charts Examples | Qt Charts 6.1.2
  2. Qt for Python Examples — Qt for Python

 

ブログランキング・にほんブログ村へ bitWalk's - にほんブログ村 にほんブログ村 IT技術ブログ Linuxへ
にほんブログ村

2021-07-26

Qt for Python によるチャート (8)

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)

ScatterChart(散布図)

ScatterChart(散布図)は、横軸と縦軸それぞれに別の量をとり、データが当てはまるところに点をプロットするグラフです。2つの量に関係があるかどうかをみるのに便利です。

qtcharts_scatterchart.py
#!/usr/bin/env python
# coding: utf-8
# Reference
# https://doc.qt.io/qt-6/qtcharts-scatterchart-example.html
import math
import sys
from PySide6.QtCharts import (
QChart,
QChartView,
QLegend,
QScatterSeries,
)
from PySide6.QtCore import (
QPointF,
Qt,
)
from PySide6.QtGui import (
QColor,
QImage,
QPainter,
QPainterPath,
)
from PySide6.QtWidgets import (
QApplication,
QMainWindow,
)
class ScatterChart(QChartView):
def __init__(self):
super().__init__()
chart = self.init_ui()
self.setChart(chart)
self.setRenderHint(QPainter.Antialiasing)
def init_ui(self):
series1 = QScatterSeries()
series1.setName('scatter1')
series1.setMarkerShape(QScatterSeries.MarkerShapeCircle)
series1.setMarkerSize(15.0)
series2 = QScatterSeries()
series2.setName('scatter2')
series2.setMarkerShape(QScatterSeries.MarkerShapeRectangle)
series2.setMarkerSize(20.0)
series3 = QScatterSeries()
series3.setName('scatter3')
series3.setMarkerShape(QScatterSeries.MarkerShapeRectangle)
series3.setMarkerSize(30.0)
series1.append(0, 6)
series1.append(2, 4)
series1.append(3, 8)
series1.append(7, 4)
series1.append(10, 5)
series2 << QPointF(1, 1) << QPointF(3, 3) << QPointF(7, 6) << QPointF(8, 3) << QPointF(10, 2)
series3 << QPointF(1, 5) << QPointF(4, 6) << QPointF(6, 3) << QPointF(9, 5)
starPath = QPainterPath()
starPath.moveTo(28, 15)
for i in range(1, 6):
starPath.lineTo(14 + 14 * math.cos(0.8 * i * math.pi),
15 + 14 * math.sin(0.8 * i * math.pi))
starPath.closeSubpath()
star = QImage(30, 30, QImage.Format_ARGB32)
star.fill(Qt.transparent)
painter = QPainter(star)
painter.setRenderHint(QPainter.Antialiasing)
painter.setPen(QColor(246, 166, 37))
painter.setBrush(painter.pen().color())
painter.drawPath(starPath)
painter.end()
series3.setBrush(star)
series3.setPen(QColor(Qt.transparent))
chart = QChart()
chart.addSeries(series1)
chart.addSeries(series2)
chart.addSeries(series3)
chart.setTitle('Simple scatterchart example')
chart.createDefaultAxes()
chart.setDropShadowEnabled(False)
chart.legend().setMarkerShape(QLegend.MarkerShapeFromSeries)
return chart
class Example(QMainWindow):
def __init__(self):
super().__init__()
scatter = ScatterChart()
self.setCentralWidget(scatter)
self.resize(500, 300)
self.setWindowTitle('ScatterChart')
def main():
app = QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec())
if __name__ == '__main__':
main()

実行例を下記に示しました。

qtcharts_scatterchart.py の実行例

QScatterSeries クラスのインスタンスに、表示するシンボル (Marker) の種類、大きさを指定して、データ列を定義するのが基本です。

        series = QScatterSeries()
        series.setName('scatter')
        series.setMarkerShape(QScatterSeries.MarkerShapeCircle)
        series.setMarkerSize(15.0)

        series.append(0, 6)
        series.append(2, 4)
        ...
        ...

サンプルでは series3 で星型のイメージを定義していますが、QPainterPath や QPainter クラスの使用経験が自分に不足していますので、経験を積んで別の機会に説明します。🙇🙏

参考サイト

  1. Qt Charts Examples | Qt Charts 6.1.2
  2. Qt for Python Examples — Qt for Python

 

ブログランキング・にほんブログ村へ bitWalk's - にほんブログ村 にほんブログ村 IT技術ブログ Linuxへ
にほんブログ村

2021-07-25

Qt for Python によるチャート (7)

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)

ZoomLineChart(ズーム付き折れ線グラフ)

ZoomLineChart(ズーム付き折れ線グラフ)は、拡大縮小機能が付いた時系列などの連続的変化をとらえるときに使用するグラフです。

qtcharts_zoomlinechart.py
#!/usr/bin/env python
# coding: utf-8
# Reference
# https://doc.qt.io/qt-6/qtcharts-zoomlinechart-example.html
import math
import sys
from PySide6.QtCharts import (
QChart,
QChartView,
QLineSeries,
)
from PySide6.QtCore import (
QPointF,
QRandomGenerator
)
from PySide6.QtGui import QPainter
from PySide6.QtWidgets import (
QApplication,
QMainWindow,
)
class ZoomLineChart(QChartView):
def __init__(self):
super().__init__()
chart = self.init_ui()
self.setChart(chart)
self.setRenderHint(QPainter.Antialiasing)
self.setMouseTracking(True)
self.setInteractive(True)
self.setRubberBand(QChartView.RectangleRubberBand)
def init_ui(self):
series = QLineSeries()
for i in range(500):
p = QPointF(i, math.sin(math.pi / 50 * i) * 100 + QRandomGenerator.global_().bounded(50))
series << p
chart = QChart()
chart.legend().hide()
chart.addSeries(series)
chart.createDefaultAxes()
chart.setTitle('Zoom in/out example')
return chart
class Example(QMainWindow):
def __init__(self):
super().__init__()
linechart = ZoomLineChart()
self.setCentralWidget(linechart)
self.resize(500, 300)
self.setWindowTitle('ZoomLineChart')
def main():
app = QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec())
if __name__ == '__main__':
main()

実行例を下記に示しました。左クリック+ドラッグで拡大する矩形領域を選び、マウスボタンを離すと拡大されます。

qtcharts_zoomlinechart.py の実行例 (1)

右クリックすると、縮小されますが元に戻るというわけではないようです。

qtcharts_zoomlinechart.py の実行例 (2)

ズームの機能は、QChartView クラスのインスタンス、あるいは継承したクラスのコンストラクタで下記の黒字三行を追加するだけです。

class ZoomLineChart(QChartView):
    def __init__(self):
        super().__init__()
        chart = self.init_ui()
        self.setChart(chart)
        self.setRenderHint(QPainter.Antialiasing)
        self.setMouseTracking(True)
        self.setInteractive(True)
        self.setRubberBand(QChartView.RectangleRubberBand)

self.setRubberBand の rubber band って輪ゴムのことです。Qt では拡大縮小を輪ゴムの伸び縮みに例えているのでしょうか。

いや、QRubberBand クラスの説明 [3] によると、

ラバーバンド (rubber band) は、新しい境界線を示すのによく使われます。

とありますので、ズームに直接関係しているわけではなく、境界線、このサンプルではドラッグして定めた矩形領域の境目のことのようです。

ラバーバンド (rubber band) は、英語では輪ゴムとかゴムバンドぐらいの意味ですので、直感的な印象とはギャップがあるネーミングです。

参考サイト

  1. Qt Charts Examples | Qt Charts 6.1.2
  2. Qt for Python Examples — Qt for Python
  3. QRubberBand Class | Qt Widgets 6.2.0

 

ブログランキング・にほんブログ村へ bitWalk's - にほんブログ村 にほんブログ村 IT技術ブログ Linuxへ
にほんブログ村