画半无限线?
Draw half infinite lines?
我使用 pyqtgraph 进行数据采集,我必须在图形视图上表示一些阈值。例如表示高压限制等。
我使用了 pyqtgraph 中的 class InfiniteLine
,但现在,我必须考虑在采集过程中阈值的一些可能变化。它看起来像是两条无限线之间的一步(请查找所附示例)。
为此,我必须画一条半无限线。你知道一个简单的方法吗?
我考虑过使用一些受 viewBox 最小值和最大值限制的 plotCurveItem :
thresholdValue = 60V # just an example
range = self.viewBox.viewRange()
xRange = range[0] # we only want ViewBox horizontal limits
minView = xRange[0]
maxView = xRange[1]
myPlotCurveItem = pyqtgraph.PlotCurveItem([minView, maxView],[thresholdValue, thresholdValue])
如果改变阈值:
newThresholdValue = 70V
plotCurveItem 的 x 数据将变为:
[minView, changingTime] #with changinTime : the moment we change the threshold
我们将添加一个新的 plotCurveItem :
myNewPlotCurveItem = pyqtgraph.plotCurveItem([changingTime, maxView],[newThresholdValue, newThresholdValue])
这个解决方案看起来不错吗?您认为它有什么问题吗?
您的方法看起来不错,而且主要是 pyqtgraph.InfiniteLine
正在做的事情。我检查了 the source of InfiniteLine 并提取了那些绝对必要的部分并添加了变化点和二级信息,然后画了三条线(左边界到左级别的变化点,变化点到右级别的右边界,连接两者)。
完整代码如下:
from pyqtgraph.Qt import QtGui
import numpy as np
import pyqtgraph as pg
class InfiniteLineWithBreak(pg.GraphicsObject):
def __init__(self, changeX, levelsY, pen=None):
pg.GraphicsObject.__init__(self)
self.changeX = changeX
self.levelsY = levelsY
self.maxRange = [None, None]
self.moving = False
self.movable = False
self.mouseHovering = False
pen = (200, 200, 100)
self.setPen(pen)
self.setHoverPen(color=(255,0,0), width=self.pen.width())
self.currentPen = self.pen
def setBounds(self, bounds):
self.maxRange = bounds
self.setValue(self.value())
def setPen(self, *args, **kwargs):
self.pen = pg.fn.mkPen(*args, **kwargs)
if not self.mouseHovering:
self.currentPen = self.pen
self.update()
def setHoverPen(self, *args, **kwargs):
self.hoverPen = pg.fn.mkPen(*args, **kwargs)
if self.mouseHovering:
self.currentPen = self.hoverPen
self.update()
def boundingRect(self):
br = self.viewRect()
return br.normalized()
def paint(self, p, *args):
br = self.boundingRect()
p.setPen(self.currentPen)
# three lines (left border to change point, change point vertical, change point to right)
p.drawLine(pg.Point(br.left(), self.levelsY[0]), pg.Point(self.changeX, self.levelsY[0]))
p.drawLine(pg.Point(self.changeX, self.levelsY[0]), pg.Point(self.changeX, self.levelsY[1]))
p.drawLine(pg.Point(self.changeX, self.levelsY[1]), pg.Point(br.right(), self.levelsY[1]))
def dataBounds(self, axis, frac=1.0, orthoRange=None):
if axis == 0:
return None ## x axis should never be auto-scaled
else:
return (0,0)
def setMouseHover(self, hover):
pass
app = QtGui.QApplication([])
w = pg.GraphicsWindow()
w.resize(1000, 600)
v = w.addPlot(y=np.random.normal(size=100))
v.addItem(InfiniteLineWithBreak(changeX=50, levelsY=(-1, 1)))
app.exec_()
看起来像:
可以添加的是对悬停和使用鼠标更改值(更改点和级别)甚至旋转 90 度的反应。 InfiniteLine
是一个很好的例子。
谢谢你非常完整的回答!
您的代码运行良好。
我对您的 class InfiniteLineWithBreak 进行了一些修改,以设置多个阈值转换。
我只修改了 init 和 paint 方法:
def __init__(self, listOfcouplesOfThresholdAndItsDate, pen=None):
pg.GraphicsObject.__init__(self)
self.listOfcouplesOfThresholdAndItsDate=listOfcouplesOfThresholdAndItsDate
self.maxRange = [None, None]
self.moving = False
self.movable = False
self.mouseHovering = False
pen = (200, 200, 100)
self.setPen(pen)
self.setHoverPen(color=(255,0,0), width=self.pen.width())
self.currentPen = self.pen
def paint(self, p, *args):
br = self.boundingRect()
p.setPen(self.currentPen)
if len(self.listOfcouplesOfThresholdAndItsDate)==0:
pass
elif len(self.listOfcouplesOfThresholdAndItsDate)==1:
threshold = self.listOfcouplesOfThresholdAndItsDate[0][1]
date = self.listOfcouplesOfThresholdAndItsDate[0][0]
p.drawLine(pg.Point(date, threshold), pg.Point(br.right(), threshold))
else:
threshold = self.listOfcouplesOfThresholdAndItsDate[0][1]
date = self.listOfcouplesOfThresholdAndItsDate[0][0]
i=0
for i in range(0, len(self.listOfcouplesOfThresholdAndItsDate)-2):
threshold = self.listOfcouplesOfThresholdAndItsDate[i][1]
date = self.listOfcouplesOfThresholdAndItsDate[i][0]
nexteDate = self.listOfcouplesOfThresholdAndItsDate[i+1][0]
nextThreshold = self.listOfcouplesOfThresholdAndItsDate[i+1][1]
p.drawLine(pg.Point(date, threshold), pg.Point(nexteDate, threshold))
p.drawLine(pg.Point(nexteDate, threshold), pg.Point(nexteDate, nextThreshold))
threshold = self.listOfcouplesOfThresholdAndItsDate[-2][1]
date = self.listOfcouplesOfThresholdAndItsDate[-2][0]
nexteDate = self.listOfcouplesOfThresholdAndItsDate[-1][0]
nextThreshold = self.listOfcouplesOfThresholdAndItsDate[-1][1]
p.drawLine(pg.Point(date, threshold), pg.Point(nexteDate, threshold))
p.drawLine(pg.Point(nexteDate, threshold), pg.Point(nexteDate, nextThreshold))
p.drawLine(pg.Point(nexteDate, nextThreshold), pg.Point(br.right(), nextThreshold))
此外,我添加了一种将新阈值转换点附加到 listOfcouplesOfThersholdAndItsDate 的方法:
def addANewThreshold(self,date, threshold):
self.listOfcouplesOfThresholdAndItsDate.append((date, threshold))
下面是它的外观示例:
example of multiple thresholds
您觉得代码还好吗?
谢谢,
我使用 pyqtgraph 进行数据采集,我必须在图形视图上表示一些阈值。例如表示高压限制等。
我使用了 pyqtgraph 中的 class InfiniteLine
,但现在,我必须考虑在采集过程中阈值的一些可能变化。它看起来像是两条无限线之间的一步(请查找所附示例)。
为此,我必须画一条半无限线。你知道一个简单的方法吗?
我考虑过使用一些受 viewBox 最小值和最大值限制的 plotCurveItem :
thresholdValue = 60V # just an example
range = self.viewBox.viewRange()
xRange = range[0] # we only want ViewBox horizontal limits
minView = xRange[0]
maxView = xRange[1]
myPlotCurveItem = pyqtgraph.PlotCurveItem([minView, maxView],[thresholdValue, thresholdValue])
如果改变阈值:
newThresholdValue = 70V
plotCurveItem 的 x 数据将变为:
[minView, changingTime] #with changinTime : the moment we change the threshold
我们将添加一个新的 plotCurveItem :
myNewPlotCurveItem = pyqtgraph.plotCurveItem([changingTime, maxView],[newThresholdValue, newThresholdValue])
这个解决方案看起来不错吗?您认为它有什么问题吗?
您的方法看起来不错,而且主要是 pyqtgraph.InfiniteLine
正在做的事情。我检查了 the source of InfiniteLine 并提取了那些绝对必要的部分并添加了变化点和二级信息,然后画了三条线(左边界到左级别的变化点,变化点到右级别的右边界,连接两者)。
完整代码如下:
from pyqtgraph.Qt import QtGui
import numpy as np
import pyqtgraph as pg
class InfiniteLineWithBreak(pg.GraphicsObject):
def __init__(self, changeX, levelsY, pen=None):
pg.GraphicsObject.__init__(self)
self.changeX = changeX
self.levelsY = levelsY
self.maxRange = [None, None]
self.moving = False
self.movable = False
self.mouseHovering = False
pen = (200, 200, 100)
self.setPen(pen)
self.setHoverPen(color=(255,0,0), width=self.pen.width())
self.currentPen = self.pen
def setBounds(self, bounds):
self.maxRange = bounds
self.setValue(self.value())
def setPen(self, *args, **kwargs):
self.pen = pg.fn.mkPen(*args, **kwargs)
if not self.mouseHovering:
self.currentPen = self.pen
self.update()
def setHoverPen(self, *args, **kwargs):
self.hoverPen = pg.fn.mkPen(*args, **kwargs)
if self.mouseHovering:
self.currentPen = self.hoverPen
self.update()
def boundingRect(self):
br = self.viewRect()
return br.normalized()
def paint(self, p, *args):
br = self.boundingRect()
p.setPen(self.currentPen)
# three lines (left border to change point, change point vertical, change point to right)
p.drawLine(pg.Point(br.left(), self.levelsY[0]), pg.Point(self.changeX, self.levelsY[0]))
p.drawLine(pg.Point(self.changeX, self.levelsY[0]), pg.Point(self.changeX, self.levelsY[1]))
p.drawLine(pg.Point(self.changeX, self.levelsY[1]), pg.Point(br.right(), self.levelsY[1]))
def dataBounds(self, axis, frac=1.0, orthoRange=None):
if axis == 0:
return None ## x axis should never be auto-scaled
else:
return (0,0)
def setMouseHover(self, hover):
pass
app = QtGui.QApplication([])
w = pg.GraphicsWindow()
w.resize(1000, 600)
v = w.addPlot(y=np.random.normal(size=100))
v.addItem(InfiniteLineWithBreak(changeX=50, levelsY=(-1, 1)))
app.exec_()
看起来像:
可以添加的是对悬停和使用鼠标更改值(更改点和级别)甚至旋转 90 度的反应。 InfiniteLine
是一个很好的例子。
谢谢你非常完整的回答! 您的代码运行良好。 我对您的 class InfiniteLineWithBreak 进行了一些修改,以设置多个阈值转换。 我只修改了 init 和 paint 方法:
def __init__(self, listOfcouplesOfThresholdAndItsDate, pen=None):
pg.GraphicsObject.__init__(self)
self.listOfcouplesOfThresholdAndItsDate=listOfcouplesOfThresholdAndItsDate
self.maxRange = [None, None]
self.moving = False
self.movable = False
self.mouseHovering = False
pen = (200, 200, 100)
self.setPen(pen)
self.setHoverPen(color=(255,0,0), width=self.pen.width())
self.currentPen = self.pen
def paint(self, p, *args):
br = self.boundingRect()
p.setPen(self.currentPen)
if len(self.listOfcouplesOfThresholdAndItsDate)==0:
pass
elif len(self.listOfcouplesOfThresholdAndItsDate)==1:
threshold = self.listOfcouplesOfThresholdAndItsDate[0][1]
date = self.listOfcouplesOfThresholdAndItsDate[0][0]
p.drawLine(pg.Point(date, threshold), pg.Point(br.right(), threshold))
else:
threshold = self.listOfcouplesOfThresholdAndItsDate[0][1]
date = self.listOfcouplesOfThresholdAndItsDate[0][0]
i=0
for i in range(0, len(self.listOfcouplesOfThresholdAndItsDate)-2):
threshold = self.listOfcouplesOfThresholdAndItsDate[i][1]
date = self.listOfcouplesOfThresholdAndItsDate[i][0]
nexteDate = self.listOfcouplesOfThresholdAndItsDate[i+1][0]
nextThreshold = self.listOfcouplesOfThresholdAndItsDate[i+1][1]
p.drawLine(pg.Point(date, threshold), pg.Point(nexteDate, threshold))
p.drawLine(pg.Point(nexteDate, threshold), pg.Point(nexteDate, nextThreshold))
threshold = self.listOfcouplesOfThresholdAndItsDate[-2][1]
date = self.listOfcouplesOfThresholdAndItsDate[-2][0]
nexteDate = self.listOfcouplesOfThresholdAndItsDate[-1][0]
nextThreshold = self.listOfcouplesOfThresholdAndItsDate[-1][1]
p.drawLine(pg.Point(date, threshold), pg.Point(nexteDate, threshold))
p.drawLine(pg.Point(nexteDate, threshold), pg.Point(nexteDate, nextThreshold))
p.drawLine(pg.Point(nexteDate, nextThreshold), pg.Point(br.right(), nextThreshold))
此外,我添加了一种将新阈值转换点附加到 listOfcouplesOfThersholdAndItsDate 的方法:
def addANewThreshold(self,date, threshold):
self.listOfcouplesOfThresholdAndItsDate.append((date, threshold))
下面是它的外观示例: example of multiple thresholds
您觉得代码还好吗? 谢谢,