triangulo - reconocimiento de figuras geometricas en python
Dibuja lĂneas medias infinitas? (2)
Yo uso pyqtgraph para la adquisición de datos y tengo que representar algunos umbrales en la vista de gráficos. Por ejemplo, para representar un límite de alto voltaje, etc. Utilicé la clase InfiniteLine
de pyqtgraph, pero ahora, debo tener en cuenta algunos cambios posibles en el valor de umbral durante la adquisición. Parecería un paso entre dos líneas infinitas (encuentre un ejemplo adjunto).
Para esto, tendría que dibujar una línea media infinita. ¿Conoces una manera simple de hacerlo?
Pensé en usar un plotCurveItem limitado por viewBox mínimo y máximo:
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])
En caso de cambiar el valor del umbral:
newThresholdValue = 70V
los datos de x para plotCurveItem se convertirían en:
[minView, changingTime] #with changinTime : the moment we change the threshold
y agregaríamos un nuevo plotCurveItem:
myNewPlotCurveItem = pyqtgraph.plotCurveItem([changingTime, maxView],[newThresholdValue, newThresholdValue])
¿Esta solución se ve bien o ves algún problema con eso?
Su enfoque se ve bien y es principalmente lo que pyqtgraph.InfiniteLine
está haciendo. Examiné la fuente de InfiniteLine y extraje aquellas partes que son absolutamente necesarias y agregué el punto de cambio y la información de dos niveles, luego dibujé tres líneas (borde izquierdo para cambiar de punto en el nivel izquierdo, punto de cambio a borde derecho en el nivel derecho, conexión de ambos )
Aquí está el código completo:
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_()
Parece que:
Lo que se podría agregar es la reacción al vuelo estacionario y el cambio de los valores con el mouse (cambio de punto y niveles) o incluso girar 90 grados. InfiniteLine
es un buen ejemplo de cómo hacer eso.
gracias por tu respuesta muy completa! Tu código funciona muy bien. Hice algunas modificaciones en su clase InfiniteLineWithBreak para establecer múltiples transiciones de umbral. Modifiqué el init y los métodos de pintura solamente:
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))
Además, agregué un método para agregar un nuevo punto de transición de umbral a listOfcouplesOfThersholdAndItsDate:
def addANewThreshold(self,date, threshold):
self.listOfcouplesOfThresholdAndItsDate.append((date, threshold))
Aquí hay un ejemplo de cómo se ve: ejemplo de umbrales múltiples
¿El código te parece bien? Gracias,