Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

draggable line with multiple break points

I have a application very similar to the following question:Draw half infinite lines?

I would like to have a infinite line with multiple thresholds.

enter image description here

The solution provided in the question is a great starting point: https://stackoverflow.com/a/37836348/7163293

I attempted to make the lines movable by modifying the movable attribute in __init__ and add a setMovable method just as the source code in source:

http://www.pyqtgraph.org/documentation/_modules/pyqtgraph/graphicsItems/InfiniteLine.html#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 = True
        self.setMovable(self.movable)
        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 setMovable(self, m):
        """Set whether the line is movable by the user."""
        self.movable = m
        self.setAcceptHoverEvents(m)


    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_()

However, the line is still not movable after the modifications.So I am kind of stuck here. Would someone be able to provide some pointers?

Also, ideally, the line on the applications should be movable by segments. So when the user drag a line, only the portion in between break points are moving. So ideally I would like to have something like:

Draggable line with draggable points

in my application. Ideally it would look something like

enter image description here

with the threshold point level (TH_Px_L1) draggable but not the timing (TH_Px_T1), so the points can only move vertically.

If someone can also help on the second item and provide some pointers or solution that will be very helpful.

like image 551
SunnyIsaLearner Avatar asked Oct 18 '22 07:10

SunnyIsaLearner


1 Answers

Based on this example from docs.

A scatter type graph is similar to one where graphs are drawn, but where the connecting lines are between the i-point point and the i + 1-point point they are connected. Then we limit the movement only to the vertical axis since it is a requirement of the author.

import numpy as np
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui

pg.setConfigOptions(antialias=True)

w = pg.GraphicsWindow()
w.setWindowTitle('Draggable')


class Graph(pg.GraphItem):
    def __init__(self):
        self.dragPoint = None
        self.dragOffset = None
        pg.GraphItem.__init__(self)

    def setData(self, **kwds):
        self.data = kwds
        if 'pos' in self.data:
            npts = self.data['pos'].shape[0]
            self.data['adj'] = np.column_stack((np.arange(0, npts-1), np.arange(1, npts)))
            self.data['data'] = np.empty(npts, dtype=[('index', int)])
            self.data['data']['index'] = np.arange(npts)
        self.updateGraph()

    def updateGraph(self):
        pg.GraphItem.setData(self, **self.data)

    def mouseDragEvent(self, ev):
        if ev.button() != QtCore.Qt.LeftButton:
            ev.ignore()
            return

        if ev.isStart():
            pos = ev.buttonDownPos()
            pts = self.scatter.pointsAt(pos)
            if len(pts) == 0:
                ev.ignore()
                return
            self.dragPoint = pts[0]
            ind = pts[0].data()[0]
            self.dragOffset = self.data['pos'][ind][1] - pos[1]
        elif ev.isFinish():
            self.dragPoint = None
            return
        else:
            if self.dragPoint is None:
                ev.ignore()
                return

        ind = self.dragPoint.data()[0]
        self.data['pos'][ind][1] = ev.pos()[1] + self.dragOffset
        self.updateGraph()
        ev.accept()


g = Graph()
v = w.addPlot()
v.addItem(g)

x = np.linspace(1, 100, 40)
pos = np.column_stack((x, np.sin(x)))

g.setData(pos=pos, size=10, pxMode=True)

if __name__ == '__main__':
    import sys

    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()

enter image description here

like image 181
eyllanesc Avatar answered Oct 21 '22 01:10

eyllanesc