将 pyqtgraph linearregionitem 与 plotitem 的轴连接时出现递归错误
Getting a recursion error when connecting a pyqtgraph linearregionitem with a plotitem's axis
我正在尝试做一些类似于 pyqtgraph 示例 'Crosshair/Mouse Interaction' 中所做的事情。基本上我想将一个图上的线性区域项连接到另一个图上的 x 轴。然后一张图将显示 linearregionitem 中的数据,您可以通过更改 linearregionitem 来放大和缩小,反之亦然。
我的问题是它崩溃了:
RecursionError: maximum recursion depth exceeded while calling a
Python object
这里是示例中的代码,如果您想尝试它让您了解我想要做什么...
"""
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_()
如果您不想阅读所有内容,linearregionitem 和 plotitem 通过线条连接...
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)
这是我的代码的一个最小工作示例...我正在做几乎相同的事情,但我在 class...
中进行
当你运行它时,如果你调整linearregionitem,或者如果你改变plotA的轴,它会崩溃。如果您注释掉任何 'connect' 行,那么该程序将运行(中途)。
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 证明是好的 MVCE。这让我做了一些实验,我发现了问题。没有它就解决不了。
更新绘图的 x 范围时必须将填充设置为零。所以把update
方法改成:
def update(self):
minX, maxX = self.lri.getRegion()
self.PlotA.setXRange(minX, maxX, padding=0)
通常在 QT 中,当新值与旧值不同时,仅通过更新变量(并发出相应的信号)来防止这些无限信号循环。在 Qt/PyQtGraph 的某处,此检查也已完成。但是由于你的填充不为零,新的 xrange 每次迭代都会比旧的 xrange 大一点,循环不会结束。
顺便说一句,在 Python 中通常让变量名以小写字母开头,而 class 中以大写字母开头。我建议将 self.PlotA
重命名为 self.plotA
。这使您的代码对其他 Python 程序员来说更易读。此外,它还会在 Stack Overflow 上提供更好的语法高亮显示。
我正在尝试做一些类似于 pyqtgraph 示例 'Crosshair/Mouse Interaction' 中所做的事情。基本上我想将一个图上的线性区域项连接到另一个图上的 x 轴。然后一张图将显示 linearregionitem 中的数据,您可以通过更改 linearregionitem 来放大和缩小,反之亦然。
我的问题是它崩溃了:
RecursionError: maximum recursion depth exceeded while calling a Python object
这里是示例中的代码,如果您想尝试它让您了解我想要做什么...
"""
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_()
如果您不想阅读所有内容,linearregionitem 和 plotitem 通过线条连接...
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)
这是我的代码的一个最小工作示例...我正在做几乎相同的事情,但我在 class...
中进行当你运行它时,如果你调整linearregionitem,或者如果你改变plotA的轴,它会崩溃。如果您注释掉任何 'connect' 行,那么该程序将运行(中途)。
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 证明是好的 MVCE。这让我做了一些实验,我发现了问题。没有它就解决不了。
更新绘图的 x 范围时必须将填充设置为零。所以把update
方法改成:
def update(self):
minX, maxX = self.lri.getRegion()
self.PlotA.setXRange(minX, maxX, padding=0)
通常在 QT 中,当新值与旧值不同时,仅通过更新变量(并发出相应的信号)来防止这些无限信号循环。在 Qt/PyQtGraph 的某处,此检查也已完成。但是由于你的填充不为零,新的 xrange 每次迭代都会比旧的 xrange 大一点,循环不会结束。
顺便说一句,在 Python 中通常让变量名以小写字母开头,而 class 中以大写字母开头。我建议将 self.PlotA
重命名为 self.plotA
。这使您的代码对其他 Python 程序员来说更易读。此外,它还会在 Stack Overflow 上提供更好的语法高亮显示。