LoginSignup
0
0

More than 3 years have passed since last update.

[pyqtgraph] Plot Options -> Transformsの表示をリンクさせる

Last updated at Posted at 2021-01-09

やりたいこと

pyqtgraph内で右クリックしてPlot Options -> Transformsと進むとグラフの表示形式を変更してくれます。
describe.gif

表示変更の種類
transforms.png

この変更を複数のグラフでリンクさせるのが目的です。
link.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

コード

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

"""pyqtgraphのPlot Options -> Transformsをリンクさせる"""

import dataclasses
import itertools
from typing import Optional
import sys

import numpy as np
from PyQt5 import QtWidgets  # ほぼ使わない
import pyqtgraph as pg

SAMPLE_DATA1 = np.linspace(-100, 100) ** 2
SAMPLE_DATA2 = np.linspace(-100, 100) ** 3


@dataclasses.dataclass
class GraphLinkWidget(pg.GraphicsLayoutWidget):
    """メイン画面
    Attributes #
    ----------
    parent: Optional[QtWidgets.QWidget] default=None
        親画面
    """
    parent: Optional[QtWidgets.QWidget] = None

    def __post_init__(self) -> None:
        """スーパークラス読み込みとプロット追加"""
        super(GraphLinkWidget, self).__init__(parent=self.parent)

        self.plotter1 = self.addPlot(row=0, col=0)
        self.plotter1.showGrid(x=True, y=True, alpha=0.8)
        self.plotter1_curve = self.plotter1.plot(pen=pg.mkPen('#f00', width=5))  # 線色:赤, 幅:5
        self.plotter1_curve.setData(SAMPLE_DATA1)
        self.plotter2 = self.addPlot(row=0, col=1)
        self.plotter2.showGrid(x=True, y=True, alpha=0.8)
        self.plotter2_curve = self.plotter2.plot(pen=pg.mkPen('#00f', width=5))
        self.plotter2_curve.setData(SAMPLE_DATA2)

        self.connect_slot()

    def connect_slot(self) -> None:
        """スロット接続
        itertools.permutationsは順列を作成してくれる関数
        ex) list(itertools.permutations([1, 2, 3]))
        >> [(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
        """
        for plot1, plot2 in itertools.permutations([self.plotter1, self.plotter2]):
            plot1.ctrl.fftCheck.toggled.connect(plot2.ctrl.fftCheck.setChecked)
            plot1.ctrl.logXCheck.toggled.connect(plot2.ctrl.logXCheck.setChecked)
            plot1.ctrl.logYCheck.toggled.connect(plot2.ctrl.logYCheck.setChecked)
            plot1.ctrl.derivativeCheck.toggled.connect(plot2.ctrl.derivativeCheck.setChecked)
            plot1.ctrl.phasemapCheck.toggled.connect(plot2.ctrl.phasemapCheck.setChecked)


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


if __name__ == "__main__":
    main()

詳細

以下でリンクさせています

    def connect_slot(self) -> None:
        """スロット接続
        itertools.permutationsは順列を作成してくれる関数
        ex) list(itertools.permutations([1, 2, 3]))
        >> [(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
        """
        for plot1, plot2 in itertools.permutations([self.plotter1, self.plotter2]):
            plot1.ctrl.fftCheck.toggled.connect(plot2.ctrl.fftCheck.setChecked)
            plot1.ctrl.logXCheck.toggled.connect(plot2.ctrl.logXCheck.setChecked)
            plot1.ctrl.logYCheck.toggled.connect(plot2.ctrl.logYCheck.setChecked)
            plot1.ctrl.derivativeCheck.toggled.connect(plot2.ctrl.derivativeCheck.setChecked)
            plot1.ctrl.phasemapCheck.toggled.connect(plot2.ctrl.phasemapCheck.setChecked)

plot1.ctrl.logXCheck.toggled.connect(plot2.ctrl.logXCheck.setChecked)
例えば上記の場合、片方のグラフ(plot1)のlogXチェクボックスが押されたらもう片方(plot2)のlogXチェックボックスにもチェックをいれてリンクさせています。

self,plotter1, self.plotter2はPlotItemという型です。pg.PlotWidgetでグラフを作成した場合はgetPlotItem()で取得できます。

class 'pyqtgraph.graphicsItems.PlotItem.PlotItem.PlotItem'

PlotWidgetの場合
plotter = pg.PlotWidget()
plotitem = plotter1.getPlotItem()

応用

GUIのボタンからグラフ表示を変更する

"""GUIのボタンからグラフ表示を変更する"""

import dataclasses
from typing import Optional
import sys

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

SAMPLE_DATA1 = np.linspace(-10, 10) ** 2
SAMPLE_DATA2 = 2 * np.linspace(-10, 10) ** 2


@dataclasses.dataclass
class PlotLinkWindow(QtWidgets.QWidget):
    """メイン画面
    Attributes #
    ----------
    parent: Optional[QtWidgets.QWidget] default=None
        親画面
    """
    parent: Optional[QtWidgets.QWidget] = None

    def __post_init__(self) -> None:
        """スーパークラス読み込みとウィジット作成"""
        super(PlotLinkWindow, self).__init__(parent=self.parent)
        self.setGeometry(100, 100, 800, 500)
        self.setWindowTitle('PlotLinkWindow')

        self.create_widgets()
        self.create_layouts()
        self.set_layouts()
        self.connect_slot()

    def create_widgets(self) -> None:
        """ウィジット作成"""
        # toggle buttons
        self.fft_btn = QtWidgets.QPushButton('FFT')
        self.fft_btn.setCheckable(True)
        self.logX_btn = QtWidgets.QPushButton('logX')
        self.logX_btn.setCheckable(True)
        self.logY_btn = QtWidgets.QPushButton('logY')
        self.logY_btn.setCheckable(True)
        self.derivative_btn = QtWidgets.QPushButton('dy/dx')
        self.derivative_btn.setCheckable(True)
        self.phasemap_btn = QtWidgets.QPushButton("Y' vs Y")
        self.phasemap_btn.setCheckable(True)

        # graph
        self.plotter1 = pg.PlotWidget()
        self.plotter1.showGrid(x=True, y=True, alpha=0.8)
        self.plotter1_curve1 = self.plotter1.plot(pen=pg.mkPen('#f00', width=5))
        self.plotter1_curve2 = self.plotter1.plot(pen=pg.mkPen('#0f0', width=5))
        self.plotter1_curve1.setData(SAMPLE_DATA1)
        self.plotter1_curve2.setData(SAMPLE_DATA2)

        self.plotitem = self.plotter1.getPlotItem()

    def create_layouts(self) -> None:
        """レイアウト作成"""
        self.main_layout = QtWidgets.QHBoxLayout()
        self.button_layout = QtWidgets.QVBoxLayout()

    def set_layouts(self) -> None:
        """ウィジットをレイアウトにセット"""
        self.main_layout.addLayout(self.button_layout)
        self.main_layout.addWidget(self.plotter1)

        self.button_layout.addWidget(self.fft_btn)
        self.button_layout.addWidget(self.logX_btn)
        self.button_layout.addWidget(self.logY_btn)
        self.button_layout.addWidget(self.derivative_btn)
        self.button_layout.addWidget(self.phasemap_btn)

        self.setLayout(self.main_layout)

    def connect_slot(self) -> None:
        """スロット接続"""
        self.fft_btn.clicked.connect(lambda: self.plotitem.ctrl.fftCheck.setChecked(self.fft_btn.isChecked()))
        self.logX_btn.clicked.connect(lambda: self.plotitem.ctrl.logXCheck.setChecked(self.logX_btn.isChecked()))
        self.logY_btn.clicked.connect(lambda: self.plotitem.ctrl.logYCheck.setChecked(self.logY_btn.isChecked()))
        self.derivative_btn.clicked.connect(
            lambda: self.plotitem.ctrl.derivativeCheck.setChecked(self.derivative_btn.isChecked()))
        self.phasemap_btn.clicked.connect(
            lambda: self.plotitem.ctrl.phasemapCheck.setChecked(self.phasemap_btn.isChecked()))


def main():
    app = QtWidgets.QApplication(sys.argv)
    window = PlotLinkWindow()
    window.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

参考

pyqtgraph、リンク軸間のトラックログ/リニア軸変換の違い
pyqtgraph.graphicsItems.PlotItem.PlotItem — pyqtgraph 0.11.1.dev0 documentation
この辺り

self.ctrl = c = Ui_Form()
...
c.fftCheck.toggled.connect(self.updateSpectrumMode)
c.logXCheck.toggled.connect(self.updateLogMode)
c.logYCheck.toggled.connect(self.updateLogMode)
c.derivativeCheck.toggled.connect(self.updateDerivativeMode)
c.phasemapCheck.toggled.connect(self.updatePhasemapMode)

itertools
すごいぞitertoolsくん - Qiita

0
0
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
0