やりたいこと
メイングラフにregionを追加してその領域を別のグラフに表示したい
pyqtgraph.exsamples.run()
のCrosshair / Mouse interactionを参考にしながら作成する
環境
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です。
コード
プロット用に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 | seeintColor()
|
| (int, hues) | seeintColor()
|
| “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