【问题标题】:Start horizontal pyqtgraph's LinearRegionItem at a certain X tick value在某个 X 刻度值处开始水平 pyqtgraph 的 LinearRegionItem
【发布时间】:2021-05-22 20:00:44
【问题描述】:

我正在尝试在图表上从某个 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()

【问题讨论】:

标签: python pyqt5 pyqtgraph


【解决方案1】:

有没有办法在水平区域设置 x 边界?例如, 我想将图形从 1

是的,有。可以在继承类LinearRegionItem的新类中定义新的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

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

这是一个例子。

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 模块。

【讨论】:

    猜你喜欢
    • 2013-08-14
    • 2016-12-30
    • 2017-11-20
    • 2021-11-26
    • 1970-01-01
    • 2022-12-03
    • 2021-10-10
    • 2023-03-29
    • 1970-01-01
    相关资源
    最近更新 更多