PlotCurveItem 和 SetLogMode 的问题

问题描述

我尝试使用对数刻度实现可点击的多重绘图。 因为我想让图可点击,所以我使用了 PlotCurveItem() 和 addItem 而不是仅仅使用 plot()。但不幸的是,如果我将 SetLogMode 与 PlotCurveItem() 一起使用,x 轴和 y 轴将具有几乎无限的值(实际上,it is not displayed in logarithmic)。当我使用 plot() 时不会发生这样的问题。

有什么解决办法吗?或者你知道其他用对数刻度实现可点击多图的好方法吗?谢谢。

app = QtGui.QApplication([])
w = pg.GraphicslayoutWidget(show=True)
w.resize(800,800)

p1 = w.addplot(0,title="p1")
p1.setLogMode(True,True)

temp_curve = pg.PlotCurveItem(y=2*x,pen=pg.mkPen(pg.mkColor(str(color[0]))),width=4,clickable=True)

temp_curve2 = pg.PlotCurveItem(y=3*x,pen=pg.mkPen(pg.mkColor(str(color[1]))),clickable=True)

p1.addItem(temp_curve)
p1.addItem(temp_curve2)

解决方法

问题和解决方案

这里有很多问题。

问题

  • 当您更改 Plot 小部件的比例时,它不会更新 PlotCurveItem 上的数据。然后你有相同的曲线,但轴比例错误。它在您使用 plot() 时有效,因为它创建了一个 PlotDataItem 而不是 PlotCurveItem,下面我将对此进行更多解释。

方案一(不方便)

  • PlotDataItem's doc.里面创建一个类似getData()的函数来获取数据,将其转换为对数/线性模式,然后每次更改时再次将数据设置到PlotCurveItem中规模。这可能会很混乱。

方案二(更方便)

  • 您可以改用 PlotDataItem,因为它会生成 PlotCurveItem 作为其中的一部分(请阅读:PlotCurveItem's doc.PlotDataItem's doc.)。当您更改比例时,此 PlotDataItem 会更新绘图数据。因为这就是它的工作方式。如果您想知道比例的变化是如何工作的,我建议您阅读PlotDataItem's source code。实现这一点,您可以使用以下方法创建图:
curve_1 = pg.PlotDataItem(
    x,y1,pen=pg.mkPen(pg.mkColor((70,70,30))),width=4 #,clickable = True   <-- This don't work
    )
curve_2 = pg.PlotDataItem(
    x,y2,70))),clickable = True   <-- This don't work
    )

方案二的问题(及其方案)

  • 现在出现了一个新问题,这个 PlotDataItem 有一个小错误。它在被点击时有信号,但从不激活在其中创建的 PlotCurveItem 的“可点击”属性。尽管您传递了 clickable = True 参数,但这将导致您在单击绘图时永远不会得到响应。
  • 我们可以做很多事情来解决这个问题,最好的和通用的解决方案将意味着在 __init__()PlotDataItem() 构建器中进行大量的返工。但是考虑到您想要使用对数刻度实现 clickable 多个图,我们可以强制它是可点击的。为此,我们必须在 PlotDataItem 中设置曲线项的可点击属性:
curve_1.curve.setClickable(True)
curve_2.curve.setClickable(True)
  • 现在您可以连接 sigClicked 发出的信号 (PlotCurveItem),如下所示:
curve_1.sigClicked.connect(curve_1_clicked)
curve_2.sigClicked.connect(curve_2_clicked)

def curve_1_clicked(ev):
    print('Curve 1 clicked')
    ## Do more things...

def curve_1_clicked(ev):
    print('Curve 2 clicked')
    ## Do more things...

我使用与您不同的代码对其进行了测试,使用 PlotWidget 并使用对象来构建 GUI,但它的工作方式必须相同。这是我的代码:

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

class MyApp(QtWidgets.QWidget):
    def __init__(self):
        QtWidgets.QWidget.__init__(self)
        lay = QtWidgets.QVBoxLayout()
        self.setLayout(lay)
        self.glw = pg.PlotWidget(show=True)
        lay.addWidget(self.glw)
        x = np.arange(100)
        y1 = 2*x
        y2 = 3*x**3
        self.curve_1 = pg.PlotDataItem(
            x,clickable = True   <-- This don't work
        )
        self.curve_2 = pg.PlotDataItem(
            x,clickable = True   <-- This don't work
        )
        self.curve_1.curve.setClickable(True)
        self.curve_2.curve.setClickable(True)
        self.glw.addItem(self.curve_1)
        self.glw.addItem(self.curve_2)
        # self.glw.setLogMode(False,False)
        self.glw.setLogMode(True,True)
        self.curve_1.sigClicked.connect(self.c1click)
        self.curve_2.sigClicked.connect(self.c2click)
        
    def c1click(self,ev):
        print('Curve 1 clicked')
    
    def c2click(self,ev):
        print('Curve 2 clicked')

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    window = MyApp()
    window.show()
    sys.exit(app.exec_())