PlotCurveItem 和 SetLogMode 的问题

Issue with PlotCurveItem and SetLogMode

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

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

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

p1 = w.addPlot(0, 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]))),
                              width=4, clickable=True)

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

问题与解决方案

这里有很多问题。

问题

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

方案一(不方便)

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

方案二(更方便)

  • 您可以改用 PlotDataItem,因为它会生成一个 PlotCurveItem 作为它的一部分(请阅读:PlotCurveItem's doc. and PlotDataItem's doc.). This PlotDataItem updates the data of the plot when you change the scale. Because that is how it works. If you want to know how the changes of scale work I suggest to read the 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, pen=pg.mkPen(pg.mkColor((70,70,70))),
    width=4 # , clickable = True   <-- This don't work
    )

解决方案2的问题(及其解决方案)

  • 现在新问题出现了,这个PlotDataItem有点错误。它在被点击时有信号,但从不激活在其中创建的 PlotCurveItem 的“可点击”属性。尽管您传递了 clickable = True 参数,但这将导致您在点击绘图时永远得不到响应。
  • 我们可以做很多事情来解决这个问题,最好的和一般的解决方案将在 __init__()PlotDataItem() 构建器中进行大的返工。但是考虑到你想实现 clickable 多个具有对数刻度的图,我们可以强制它是可点击的。为此,我们必须在 PlotDataItem 中设置曲线项的可点击 属性:
curve_1.curve.setClickable(True)
curve_2.curve.setClickable(True)
  • 现在您可以像这样连接 PlotCurveItem 发出的信号 (sigClicked):
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, y1, pen=pg.mkPen(pg.mkColor((70,70,30))),
            width=4 # , clickable = True   <-- This don't work
        )
        self.curve_2 = pg.PlotDataItem(
            x, y2, pen=pg.mkPen(pg.mkColor((70,70,70))),
            width=4 # , 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_())