0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[pyqtgraph] グラフにregionを追加してグラフ領域とリンクさせる

Last updated at Posted at 2021-01-10

やりたいこと

メイングラフにregionを追加してその領域を別のグラフに表示したい
region.gif

pyqtgraph.exsamples.run()のCrosshair / Mouse interactionを参考にしながら作成する
exsample.gif

環境

Mac OS
Python 3.8.5

PyQt5 5.15.2
PyQt5-sip 12.8.1
pyqtgraph 0.11.1

pip install PyQt5 PyQt5-sip pyqtgraph

pyqtgraph.exsamples

import pyqtgraph.examples as ex
ex.run()

で色々なサンプルグラフが見れます。今回参考にしたのはCrosshair / Mouse interactionです。
exsamples.png

コード

プロット用にnumpyを使用しています。 pip install numpy

"""グラフにregionを追加してグラフ領域とリンクさせる"""

import dataclasses
from typing import Optional
import sys

import numpy as np
from PyQt5 import QtWidgets, QtCore
import pyqtgraph as pg

SAMPLE_DATA1 = np.random.rand(500) * 10
SAMPLE_DATA2 = 10 + np.random.rand(500) * 10
SAMPLE_DATA3 = 20 + np.random.rand(500) * 10


@dataclasses.dataclass
class AddRegionWidget(pg.GraphicsLayoutWidget):
    """メイン画面
    Attributes #
    ----------
    parent: Optional[QtWidgets.QWidget] default=None
        親画面
    main_plotter: pyqtgraph.graphicsItems.PlotItem.PlotItem.PlotItem
        メイングラフ
    zoom_plotter: pyqtgraph.graphicsItems.PlotItem.PlotItem.PlotItem
        メイングラフをregionの領域でズームしたグラフ
    region: pyqtgraph.graphicsItems.LinearRegionItem.LinearRegionItem
        zoom_plotterのx軸領域を指定するregion
    """
    parent: Optional[QtWidgets.QWidget] = None

    def __post_init__(self) -> None:
        """スーパークラス読み込みとplot, region追加"""
        super(AddRegionWidget, self).__init__(parent=self.parent)

        self.add_plot()
        self.add_region()
        self.connect_slot()

    def add_plot(self) -> None:
        """plotを追加する"""
        self.main_plotter = self.addPlot(row=0, col=0)
        self.main_plotter.showGrid(x=True, y=True, alpha=0.8)
        main_curve1 = self.main_plotter.plot(pen=pg.mkPen('#f00'))
        main_curve2 = self.main_plotter.plot(pen=pg.mkPen('#0f0'))
        main_curve3 = self.main_plotter.plot(pen=pg.mkPen('#00f'))
        main_curve1.setData(SAMPLE_DATA1)
        main_curve2.setData(SAMPLE_DATA2)
        main_curve3.setData(SAMPLE_DATA3)

        self.zoom_plotter = self.addPlot(row=0, col=1)
        # y軸は値に合わせて調整する
        self.zoom_plotter.setAutoVisible(y=True)
        self.zoom_plotter.showGrid(x=True, y=True, alpha=0.8)
        zoom_curve1 = self.zoom_plotter.plot(pen=pg.mkPen('#f00'))
        zoom_curve2 = self.zoom_plotter.plot(pen=pg.mkPen('#0f0'))
        zoom_curve3 = self.zoom_plotter.plot(pen=pg.mkPen('#00f'))
        zoom_curve1.setData(SAMPLE_DATA1)
        zoom_curve2.setData(SAMPLE_DATA2)
        zoom_curve3.setData(SAMPLE_DATA3)

        self.zoom_plotter.setXRange(0.0, len(SAMPLE_DATA1) / 8, padding=0)

        self.ci.layout.setColumnStretchFactor(0, 8)
        self.ci.layout.setColumnStretchFactor(1, 5)

    def add_region(self) -> None:
        """regionを追加する"""
        self.region = pg.LinearRegionItem()
        # regionの高さ設定。regionが複数ある&重なった場合Zが高い方が操作可能(今回は1つなので適当に10に設定)
        self.region.setZValue(10)
        self.main_plotter.addItem(self.region, ignoreBounds=True)
        self.update_region()

    def connect_slot(self) -> None:
        """slot接続"""
        self.region.sigRegionChanged.connect(self.update_zoom_plotter)
        self.zoom_plotter.sigRangeChanged.connect(self.update_region)

    @QtCore.pyqtSlot()
    def update_zoom_plotter(self) -> None:
        """regionが動いた時にself.zoom_plotterの領域を変える"""
        self.region.setZValue(10)
        min_x, max_x = self.region.getRegion()
        self.zoom_plotter.setXRange(min_x, max_x, padding=0)

    @QtCore.pyqtSlot()
    def update_region(self) -> None:
        """self.zoom_plotterが動いた時regionの領域を変える
        viewRangeはグラフの表示範囲を返す。型は
        [[Xmin, Xmax], [Ymin, Ymax]]
        """
        rgn = self.zoom_plotter.viewRange()[0]
        self.region.setRegion(rgn)


def main() -> None:
    app = QtWidgets.QApplication(sys.argv)
    window = AddRegionWidget(parent=None)
    window.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

詳細

regionが変わった時にzoom_plotterの範囲を変更する

    @QtCore.pyqtSlot()
    def update_zoom_plotter(self) -> None:
        """regionが動いた時にself.zoom_plotterの領域を変える"""
        self.region.setZValue(10)
        min_x, max_x = self.region.getRegion()
        self.zoom_plotter.setXRange(min_x, max_x, padding=0)

min_x, max_xはregionのx座標です。
ex) min_x=231.1511878655732 max_x=293.6511878655732
それをzoom_potterのx軸範囲に指定しています。

padding=0は余白を無しにしているイメージです。
例えばself.zoom_plotter.setXRange(100, 1000, padding=0.1)の時、実際に表示される範囲は[100*(1 - 0.1), 1000*(1 + 0.1)]の[90, 1100]です。

regionの範囲とzoom_plotterの範囲を一致させたいので0にしています。

zoom_plotterの範囲が変わった時にregionの範囲を変更する

    @QtCore.pyqtSlot()
    def update_region(self) -> None:
        """self.zoom_plotterが動いた時regionの領域を変える
        viewRangeはグラフの表示範囲を返す。型は
        [[Xmin: float, Xmax: float], [Ymin: float, Ymax: float]]
        """
        rgn = self.zoom_plotter.viewRange()[0]
        self.region.setRegion(rgn)

zoom_plotterの範囲を直接変更した時にregionの範囲をそれに合わせています。
[Xmin: float, Xmax: float]の範囲をsetRegionでregionにセットしています。

その他regionの設定

横向きのregionの作成
horizontal_region = pg.LinearRegionItem(orientation='horizontal')
region領域内の色設定
region = pg.LinearRegionItem(brush=pg.mkBrush('#f004'))
#RGBA以外でも色を渡せます。

| ‘c’ | one of: r, g, b, c, m, y, k, w |
| -------------- | ------------------------------------------------------------ |
| R, G, B, [A] | integers 0-255 |
| (R, G, B, [A]) | tuple of integers 0-255 |
| float | greyscale, 0.0-1.0 |
| int | see intColor() |
| (int, hues) | see intColor() |
| “RGB” | hexadecimal strings; may begin with ‘#’ |
| “RGBA” | |
| “RRGGBB” | |
| “RRGGBBAA” | |
| QColor | QColor instance; makes a copy. |

PyQtGraph’s Helper Functions — pyqtgraph 0.11.1.dev0 documentation

region境界線の色設定(色の指定は上と同じ方法で可能)
region = pg.LinearRegionItem(pen=pg.mkPen('#fff'))

カーソルがregion上にある時の領域内色設定
region = pg.LinearRegionItem(hoverBrush=pg.mkBrush('#fff4'))

カーソルがregionの境界線上にある時の境界線色設定
region = pg.LinearRegionItem(hoverPen=pg.mkPen('#f00'))

参考

pyqtgraph.exsamples.run()のCrosshair / Mouse interaction

region
LinearRegionItem — pyqtgraph0.11.1.dev0ドキュメント

regionの色設定
PyQtGraph’s Helper Functions — pyqtgraph 0.11.1.dev0 documentation

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?