有没有办法防止矩形 pyqtgraph ROI 不左右移动?

Is there a way to prevent a rectangular pyqtgraph ROI to not move left-right?

我从我正在使用 pyqtgraph ROI 处理的部分代码中获得了这个片段。我还设置了投资回报率不能跨越所有方面的界限。当我移动任一垂直刻度手柄时,如果在其内部单击,它会为 ROI 提供左右移动的机会。有没有办法防止这种情况发生?我只希望它上下移动。这有点像根据当前的 X 开始位置和 X 停止位置在原始边界内设置另一个边界到 ROI。

我尝试使用信号修改 ROI class 中的 self.maxBound 变量,但它变得混乱,并且 ROI 一直忽略右边界。

任何帮助将不胜感激

from PyQt5.QtWidgets import (
    QApplication,
    QMainWindow,
    QGridLayout,
    QWidget)
import pyqtgraph as pg
import sys
import numpy as np
from PyQt5.QtCore import QRectF, QRect


class TestROI(QMainWindow):

    imageWidth = 1000
    imageHardLimitTop = 1048
    imageHardLimitBottom = 2047
    shallowestPixel = 1400
    deepestPixel = 1699
    ROITopBottomMargin = 20
    shaderDarkness = 185
    shaderColor = (0, 0, 50, shaderDarkness)
    imageHardLimitDepth = imageHardLimitBottom - imageHardLimitTop + 1

    def __init__(self):
        super(TestROI, self).__init__()

        self.mainWidget = QWidget()
        self.imagePlotCanvas = pg.GraphicsLayoutWidget()
        self.graphGridLayout = QGridLayout(self.mainWidget)
        self.graphGridLayout.addWidget(self.imagePlotCanvas)
        self.setCentralWidget(self.mainWidget)

        self.showMaximized()

        # Place for 2D images:
        self.plotArea = self.imagePlotCanvas.addPlot()
        self.plotArea.setRange(
            QRect(0, self.imageHardLimitTop, self.imageWidth, self.imageHardLimitDepth))
        self.plotArea.setLimits(xMin=-1000, xMax=2000)
        self.plotArea.setAspectLocked(True)
        self.plotArea.invertY(b=True)
        self.plotArea.showGrid(x=True, y=True, alpha=1.0)
        self.plotArea.showButtons()

        self.twoDImageROI = pg.ROI(pos=[0, self.shallowestPixel],
                                      size=[
                                          self.imageWidth, self.deepestPixel - self.shallowestPixel + 1],
                                      removable=False,
                                      maxBounds=QRectF(-1, self.imageHardLimitTop-1,
                                                       self.imageWidth + 2, self.imageHardLimitDepth+1),
                                      scaleSnap=False, translateSnap=False)
        self.twoDImageROI.setZValue(20)


        self.shadedTopRegion = pg.LinearRegionItem(
            [self.imageHardLimitTop, self.shallowestPixel], orientation=pg.LinearRegionItem.Horizontal, movable=False)
        self.shadedTopRegion.setBrush(color=self.shaderColor)
        self.shadedTopRegion.setZValue(10)
        self.plotArea.addItem(self.shadedTopRegion)

        self.shadedBottomRegion = pg.LinearRegionItem(
            [self.deepestPixel + 1, self.imageHardLimitBottom+1], orientation=pg.LinearRegionItem.Horizontal, movable=False)
        self.shadedBottomRegion.setBrush(color=self.shaderColor)
        self.shadedBottomRegion.setZValue(10)
        self.plotArea.addItem(self.shadedBottomRegion)

        # self.twoDImageROI.setAcceptedMouseButtons(Qt.LeftButton)
        self.twoDImageROI.sigRegionChanged.connect(self.imageROIChanged)

        # Shaded Region on the left and right to cover up the above two vertical lines when out of image bound.
        self.shadedLeftRegion = pg.LinearRegionItem(
            [-1000, 0], orientation=pg.LinearRegionItem.Vertical, movable=False)
        self.shadedLeftRegion.setBrush(color=(0, 0, 0))
        self.shadedLeftRegion.setZValue(20)
        self.plotArea.addItem(self.shadedLeftRegion)

        self.shadedRightRegion = pg.LinearRegionItem(
            [1000, 2000], orientation=pg.LinearRegionItem.Vertical, movable=False)
        self.shadedRightRegion.setBrush(color=(0, 0, 0))
        self.shadedRightRegion.setZValue(20)
        self.plotArea.addItem(self.shadedRightRegion)

        self.twoDImageROI.addScaleHandle([0.5, 0.0], [0.5, 1.0], index=0)
        self.twoDImageROI.addScaleHandle([0.5, 1.0], [0.5, 0.0], index=1)
        self.twoDImageROI.addScaleHandle([1.0, 0.5], [0.5, 0.5])
        self.twoDImageROI.addScaleHandle([0.0, 0.5], [0.5, 0.5])

        self.twoDOCMImage = pg.ImageItem(border='c')
        self.twoDOCMImage.setParentItem(self.plotArea)

        self.plotArea.addItem(self.twoDOCMImage)
        self.plotArea.addItem(self.twoDImageROI)

        zeroImage = np.zeros(self.imageWidth * self.imageHardLimitDepth)\
            .reshape((self.imageWidth, self.imageHardLimitDepth))
        self.twoDOCMImage.setImage(zeroImage)
        startingRect = QRect(0, self.imageHardLimitTop,
                             self.imageWidth, self.imageHardLimitDepth)
        self.twoDOCMImage.setRect(startingRect)

    def imageROIChanged(self):
        x, top = self.twoDImageROI.pos()
        top = int(round(top, 0))

        w, h = self.twoDImageROI.size()
        h = int(round(h, 0))

        bot = top + h - 1

        self.shallowestPixel = top
        self.deepestPixel = bot

        self.updateLinearRegion()

    def updateLinearRegion(self):
        x, top = self.twoDImageROI.pos()
        top = int(round(top, 0))

        w, h = self.twoDImageROI.size()
        h = int(round(h, 0))

        bot = top + h - 1

        self.shadedTopRegion.setRegion([self.imageHardLimitTop, top])
        self.shadedBottomRegion.setRegion([bot, self.imageHardLimitBottom+1])


if __name__ == '__main__':

    app = QApplication(sys.argv)
    main_window = TestROI()
    main_window.show()
    sys.exit(app.exec_())

我相信您所说的问题是在上下移动 ROI 时从左到右的 1px 摆动。这种效果是由于将实际 ROI 位置转换为绘制 X、Y 值。总会有四舍五入,因此投资回报率总是会左右摆动。

为防止这种情况,您可以手动设置您的投资回报率的常量 x 位置。为此,您必须覆盖 ROI class.

的 setPos

这是投资回报率示例 class,您可以使用:

class ConstantXROI(ROI):
    constant_x = 0

    def setPos(self, pos, y=None, update=True, finish=True):
        pos.setX(self.constant_x)
        super().setPos(pos, y=y, update=update, finish=finish)

然后在您的代码中,只需使用:

self.twoDImageROI = ConstantXROI(...)