将pyqtgraph linearregionitem与plotitem的轴连接时出现递归错误

时间:2018-06-12 16:06:43

标签: python pyqt pyqtgraph

我尝试做类似于pyqtgraph示例中所做的事情' Crosshair / Mouse Interaction'。基本上我想将一个绘图上的线性区域项连接到另一个绘图上的x轴。那么一个图将显示线性区域中的数据,你可以通过改变线性区域来放大和缩小,反之亦然。

我的问题是它崩溃了:

  

RecursionError:调用a时超出了最大递归深度   Python对象

以下是示例中的代码,如果您想尝试让它了解我想要做什么......

"""
Demonstrates some customized mouse interaction by drawing a crosshair that follows 
the mouse.


"""
import numpy as np
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui, QtCore
from pyqtgraph.Point import Point

#generate layout
app = QtGui.QApplication([])
win = pg.GraphicsWindow()
win.setWindowTitle('pyqtgraph example: crosshair')
label = pg.LabelItem(justify='right')
win.addItem(label)
p1 = win.addPlot(row=1, col=0)
p2 = win.addPlot(row=2, col=0)

region = pg.LinearRegionItem()
region.setZValue(10)
# Add the LinearRegionItem to the ViewBox, but tell the ViewBox to exclude this 
# item when doing auto-range calculations.
p2.addItem(region, ignoreBounds=True)

#pg.dbg()
p1.setAutoVisible(y=True)


#create numpy arrays
#make the numbers large to show that the xrange shows data from 10000 to all the way 0
data1 = 10000 + 15000 * pg.gaussianFilter(np.random.random(size=10000), 10) + 3000 * np.random.random(size=10000)
data2 = 15000 + 15000 * pg.gaussianFilter(np.random.random(size=10000), 10) + 3000 * np.random.random(size=10000)

p1.plot(data1, pen="r")
p1.plot(data2, pen="g")

p2.plot(data1, pen="w")

def update():
    region.setZValue(10)
    minX, maxX = region.getRegion()
    p1.setXRange(minX, maxX, padding=0)    

region.sigRegionChanged.connect(update)

def updateRegion(window, viewRange):
    rgn = viewRange[0]
    region.setRegion(rgn)

p1.sigRangeChanged.connect(updateRegion)

region.setRegion([1000, 2000])

#cross hair
vLine = pg.InfiniteLine(angle=90, movable=False)
hLine = pg.InfiniteLine(angle=0, movable=False)
p1.addItem(vLine, ignoreBounds=True)
p1.addItem(hLine, ignoreBounds=True)


vb = p1.vb

def mouseMoved(evt):
    pos = evt[0]  ## using signal proxy turns original arguments into a tuple
    if p1.sceneBoundingRect().contains(pos):
        mousePoint = vb.mapSceneToView(pos)
        index = int(mousePoint.x())
        if index > 0 and index < len(data1):
            label.setText("<span style='font-size: 12pt'>x=%0.1f,   <span style='color: red'>y1=%0.1f</span>,   <span style='color: green'>y2=%0.1f</span>" % (mousePoint.x(), data1[index], data2[index]))
        vLine.setPos(mousePoint.x())
        hLine.setPos(mousePoint.y())



proxy = pg.SignalProxy(p1.scene().sigMouseMoved, rateLimit=60, slot=mouseMoved)
#p1.scene().sigMouseMoved.connect(mouseMoved)


## Start Qt event loop unless running in interactive mode or using pyside.
if __name__ == '__main__':
    import sys
    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()

如果您不想阅读所有内容,则线性区域和绘图项目将通过线路连接......

def update():
    region.setZValue(10)
    minX, maxX = region.getRegion()
    p1.setXRange(minX, maxX, padding=0)    

region.sigRegionChanged.connect(update)

def updateRegion(window, viewRange):
    rgn = viewRange[0]
    region.setRegion(rgn)

p1.sigRangeChanged.connect(updateRegion)

这是我的代码的一个最小的工作示例......我做了几乎相同的事情,但我在课堂上这样做......

运行时,如果调整linearregionitem,或者更改plotA的轴,它将会崩溃。如果你注释掉了“连接”中的任何一个。行,然后程序将工作(中途)。

import pyqtgraph as pg
import sys

# PyQt5 includes
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication


class MyApplicationWindow(QtWidgets.QMainWindow):

    def __init__(self):
        super().__init__()
        self.__buildUI()


    def __buildUI(self):

        plotWidget = pg.GraphicsLayoutWidget()

        self.PlotA = pg.PlotItem()
        self.PlotA.setXRange(10, 20)


        self.PlotB = pg.PlotItem()
        self.PlotB.setXRange(0, 100)


        self.lri = pg.LinearRegionItem()
        self.lri.setRegion((10, 20))
        self.PlotB.addItem(self.lri)

        # The following two connections set up a recursive loop
        self.lri.sigRegionChanged.connect(self.update)
        self.PlotA.sigRangeChanged.connect(self.update_lri)

        plotWidget.addItem(self.PlotA)
        plotWidget.nextRow()
        plotWidget.addItem(self.PlotB)

        self.setCentralWidget(plotWidget)

        self.show()


    def update(self):
        minX, maxX = self.lri.getRegion()
        self.PlotA.setXRange(minX, maxX)


    def update_lri(self, window, viewRange):
        A_xrange = viewRange[0]
        self.lri.setRegion(A_xrange)


if __name__ == '__main__':
    app = QApplication(sys.argv)

    widget = MyApplicationWindow()
    sys.exit(app.exec_())

发生了什么?谁能告诉我如何使这个工作?这是在Python 3.6

1 个答案:

答案 0 :(得分:2)

+1,用于证明MVCE良好。这使我可以进行一些试验,然后发现了问题。没有它就无法解决。

在更新绘图的x范围时,必须将填充设置为零。因此,将update方法更改为:

def update(self):
    minX, maxX = self.lri.getRegion()
    self.PlotA.setXRange(minX, maxX, padding=0)

通常,对于QT,仅当新值与旧值不同时才通过更新变量(并发出相应的信号)来防止这些无限信号环路。在Qt / PyQtGraph中的某处也执行此检查。但是,由于您的填充不为零,因此每次迭代时新的xrange都会比旧的xrange大一点,并且循环不会结束。

顺便说一句,在Python中,通常让变量名以小写字母开头,而类名以大写字母开头。我建议将self.PlotA重命名为self.plotA。这使您的代码更易于其他Python程序员阅读。另外,在Stack Overflow上,它还会使语法突出显示。