在某个 X 刻度值处开始水平 pyqtgraph 的 LinearRegionItem

Start horizontal pyqtgraph's LinearRegionItem at a certain X tick value

我试图在图形上从某个 x 值开始对水平区域进行阴影处理。我目前正在使用 pyqtgraph 的 LinearRegionItem 创建这个区域,它从负无穷大跨越到正无穷大,如下图所示:

有没有办法在水平区域设置 x 边界?例如,我想对 1<=x<infinity 的图形进行阴影处理,并使 0<=x<1 不带阴影。

我看到 LinearRegionItem 有设置跨度和边界的选项,但是这与 LinearRegionItem 的方向相同。

编辑:跨度按百分比限制区域(例如,下面代码中绘图区域的最后 80%,主要来自 here)。边界将区域限制在与创建区域时定义的值相同的方向(如果 moveable=True 有用)。

from PyQt5 import QtWidgets
from pyqtgraph import PlotWidget, plot
import pyqtgraph as pg
import sys  # We need sys so that we can pass argv to QApplication
import os

class MainWindow(QtWidgets.QMainWindow):

    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.graphWidget = pg.PlotWidget()
        self.setCentralWidget(self.graphWidget)

        hour = [1,2,3,4,5,6,7,8,9,10]
        temperature = [30,32,34,32,33,31,29,32,35,45]

        region = pg.LinearRegionItem(values=(34,36), orientation="horizontal", brush=(255,255,255,50), bounds=[35,36], span=(0.2,1))
        self.graphWidget.addItem(region)

        # plot data: x, y values
        self.graphWidget.plot(hour, temperature)


def main():
    app = QtWidgets.QApplication(sys.argv)
    main = MainWindow()
    main.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

Is there a way to set x bounds on the horizontal region? For instance, I'd like to shade the graph from 1<=x<infinity and leave 0<=x<1 unshaded.

是的,有。可以在新的class继承classLinearRegionItem.

中定义新的boundingRect()函数
"LinearRegionItemPatch.py"

from pyqtgraph import LinearRegionItem

class LimitsTypeError(Exception):
    def __init__(self,err='Limits type must be type int or tuple of ints', *args, **kwargs):
        super().__init__(self, err, *args, **kwargs)

class FiniteLinearRegionItem(LinearRegionItem):
    def __init__(self, limits = None, *args, **kwargs):
        super(FiniteLinearRegionItem, self).__init__(*args, **kwargs)
        """Create a new LinearRegionItem.
            
            Now you can define the shading area. Enjoy!

        ==============  =====================================================================
        **Arguments:**
        limits          A tuple containing the upper and lower bounds prependicular to the orientation.
                        Or a int/float containing the lower bounds prependicular to the orientation.
                        The default value is None.
        ==============  =====================================================================
        """
        self.limit = limits

    def boundingRect(self):
        br = self.viewRect()       
        rng = self.getRegion()
        
        # Infinite with one end close
        if isinstance(self.limit, int):
            if self.orientation in ('vertical', LinearRegionItem.Vertical):
                br.setLeft(rng[0])
                br.setRight(rng[1])
                length = br.height()
                br.setBottom(self.limit)
                br.setTop(br.top() + length * self.span[0])
            else:
                br.setTop(rng[0])
                br.setBottom(rng[1])
                length = br.width()
                br.setRight(br.left() + length * self.span[1])
                br.setLeft(self.limit)
        # Finite 
        elif isinstance(self.limit, tuple):
            if self.orientation in ('vertical', LinearRegionItem.Vertical):
                br.setLeft(rng[0])
                br.setRight(rng[1])
                length = br.height()
                br.setBottom(self.limit[0])
                br.setTop(self.limit[1])
            else:
                br.setTop(rng[0])
                br.setBottom(rng[1])
                length = br.width()
                br.setRight(self.limit[1])
                br.setLeft(self.limit[0])
        elif self.limit is None:    
            if self.orientation in ('vertical', LinearRegionItem.Vertical):
                br.setLeft(rng[0])
                br.setRight(rng[1])
                length = br.height()
                br.setBottom(br.top() + length * self.span[1])
                br.setTop(br.top() + length * self.span[0])
            else:
                br.setTop(rng[0])
                br.setBottom(rng[1])
                length = br.width()
                br.setRight(br.left() + length * self.span[1])
                br.setLeft(br.left() + length * self.span[0])
        else:
            raise LimitsTypeError
        
        br = br.normalized()
        
        if self._bounds != br:
            self._bounds = br
            self.prepareGeometryChange()        
        return br

使用class,您可以定义一端封闭或两端封闭的阴影区域。

这是一个例子。

from PyQt5 import QtWidgets
from pyqtgraph import PlotWidget, plot
import pyqtgraph as pg
import sys  # We need sys so that we can pass argv to QApplication
import os
# LinearRegionItemPatch is the file name
from LinearRegionItemPatch import FiniteLinearRegionItem

class MainWindow(QtWidgets.QMainWindow):

    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.graphWidget = pg.PlotWidget()
        self.setCentralWidget(self.graphWidget)

        hour = [1,2,3,4,5,6,7,8,9,10]
        temperature = [30,32,34,32,33,31,29,32,35,45]

        region = FiniteLinearRegionItem(values=(34,36), limits = 1, orientation="horizontal", brush=(255,255,255,100), bounds =(33, 37))
        self.graphWidget.addItem(region)

        # plot data: x, y values
        self.graphWidget.plot(hour, temperature)
        self.graphWidget.setXRange(0, 10, padding = 0.1)


def main():
    app = QtWidgets.QApplication(sys.argv)
    main = MainWindow()
    main.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

结果:

如果这有用,经过一些重构,我可能会把它贡献给 pyqtgraph 模块。