Python | PyQtGraph リージョンの実装方法

PyQtGraph

Python PyQtGraphでリージョンを実装する方法を説明する。

結論

LinearRegionItem()のインスタンスを生成し(下記例ではself.region)、addPlot()のインスタンス(下記例ではself.p0)に.addItemする。

self.region = pg.LinearRegionItem(values=(0,0.2))  # values=(リージョンの最小値、最大値)
self.p0.addItem(self.region, ignoreBounds=True)

コード例

  1. リージョンを設置
  2. リージョン変更時の動作にコネクト
  3. リージョン変更時の動作を記述
#!/usr/bin/env python3

import numpy as np
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QGraphicsProxyWidget, QLabel
import pyqtgraph as pg


class GuiWindow(QWidget):

    def __init__(self, parent=None):
        super().__init__(parent)
        self.サイン波を作成()
        self.グラフを描画()
        self.文字表示版を設置()
        self.リージョンを設置()
        self.リージョン変更時の動作にコネクト()

    def サイン波を作成(self):
        self.freq = 1    # サイン波の周波数 [Hz]
        self.Ts = 0.001  # サンプリング周期 [秒]
        self.Ns = 1000   # サンプリング点数 [個]
        self.ns = np.arange(0, self.Ns)  # サンプル番号
        self.time = self.ns * self.Ts
        self.sin = 10 * np.sin(2 * np.pi * self.freq * (self.ns * self.Ts))

    def グラフを描画(self):
        self.graph = pg.GraphicsLayoutWidget(show=True)
        self.p0 = self.graph.addPlot(row=0, colspan=3)
        self.p0.plot(x=self.time, y=self.sin, pen=pg.mkPen((255,255,0), width=10))

    def 文字表示版を設置(self):
        self.文字表示版_項目_max = FlexibleSpace(app=self, win=self.graph, row=1, col=0, h=25, w=50, text='max : ')
        self.文字表示版_項目_min = FlexibleSpace(app=self, win=self.graph, row=2, col=0, h=25, w=50, text='min : ')
        self.文字表示版_値_max  = FlexibleSpace(app=self, win=self.graph, row=1, col=1, h=25, w=100)
        self.文字表示版_値_min  = FlexibleSpace(app=self, win=self.graph, row=2, col=1, h=25, w=100)
        self.スペーサー1       = FlexibleSpace(app=self, win=self.graph, row=1, col=2, h=25)
        self.スペーサー2       = FlexibleSpace(app=self, win=self.graph, row=2, col=2, h=25)

    def リージョンを設置(self):                                      # ? 1
        self.region = pg.LinearRegionItem(values=(0,0.2))
        self.region.lines[0].setPen(128,128,128)
        self.region.lines[1].setPen(128,128,128)
        # self.region.setBrush(pg.mkBrush(255,255,0,100))  # region内の色
        # self.region.setHoverBrush(pg.mkBrush(255,255,0,100))  # ホバー時のregion内の色
        self.region.setZValue(10)
        self.p0.addItem(self.region, ignoreBounds=True)

    def リージョン変更時の動作にコネクト(self):                         # ? 2
        self.region.sigRegionChanged.connect(self.update_region)

    def update_region(self):                                      # ? 3
        def リージョンに含まれるデータのインデックスを取得():
            r_min, r_max = self.region.getRegion()
            self.ind_rmin = int(np.ceil (r_min/self.Ts))
            self.ind_rmax = int(np.floor(r_max/self.Ts))

        def リージョンがデータ範囲を超えたらインデックスをクリップ():
            if  self.ind_rmin < 0:
                self.ind_rmin = 0
            if  self.ind_rmax < 0:
                self.ind_rmax = 0
            if  self.ind_rmin > self.Ns:
                self.ind_rmin = self.Ns
            if  self.ind_rmax > self.Ns:
                self.ind_rmax = self.Ns

        def 文字表示版を更新():
            最大値 = np.max(self.sin[self.ind_rmin : self.ind_rmax + 1])
            最小値 = np.min(self.sin[self.ind_rmin : self.ind_rmax + 1])
            self.文字表示版_値_max.setInnerText(str(np.round(最大値,3)))
            self.文字表示版_値_min.setInnerText(str(np.round(最小値,3)))

        try:
            リージョンに含まれるデータのインデックスを取得()
            リージョンがデータ範囲を超えたらインデックスをクリップ()
            文字表示版を更新()
        except:
            pass


class FlexibleSpace(QWidget):
    def __init__(self, app, win, row, col, rowspan=1, colspan=1, w=0, h=0, name='', text=''):
        super().__init__()
        self.set_layout(win=win, row=row, col=col, rowspan=rowspan, colspan=colspan)
        self.set_object(app=app, w=w, h=h, name=name, text=text)
        self.set_proxy()
        self.setInnerText(text=text)

    def set_layout(self, win, row, col, rowspan, colspan):
        self.p = win.addLayout(row=row, col=col, rowspan=rowspan, colspan=colspan)
        self.p.setContentsMargins(10,0,10,0)  # 左,上,右,下

    def set_object(self, app, w, h, name, text):
        def make_object():
            self.object = QLabel()

        def set_style():
            style = ('QLabel{'
                    'background-color: rgba(0,0,0,0);'
                    'color: darkgray;'
                    '}')
            self.object.setStyleSheet(style)

        def set_size(w, h):
            def set_wsize(w):
                self.object.setMinimumWidth(w)
                self.object.setMaximumWidth(w)

            def set_hsize(h):
                self.object.setMinimumHeight(h)
                self.object.setMaximumHeight(h)

            if w > 0:
                set_wsize(w)
            else:
                pass  # free size
            if h > 0:
                set_hsize(h)
            else:
                pass  # free size

        make_object()
        set_style()
        set_size(w=w, h=h)

    def set_proxy(self):
        self.proxy = QGraphicsProxyWidget()
        self.item = self.p.addItem(self.proxy)
        self.proxy.setWidget(self.object)

    def setInnerText(self, text):
        self.object.setText(text)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = GuiWindow()
    sys.exit(app.exec())

まとめ

Python PyQtGraphでリージョンを実装する方法を説明した。

コメント