File: CurvePoint.py

package info (click to toggle)
python-pyqtgraph 0.13.7-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 8,068 kB
  • sloc: python: 54,043; makefile: 129; ansic: 40; sh: 2
file content (122 lines) | stat: -rw-r--r-- 4,689 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import weakref
from math import atan2, degrees

from ..functions import clip_scalar
from ..Qt import QtCore, QtWidgets
from . import ArrowItem
from .GraphicsObject import GraphicsObject

__all__ = ['CurvePoint', 'CurveArrow']
class CurvePoint(GraphicsObject):
    """A GraphicsItem that sets its location to a point on a PlotCurveItem.
    Also rotates to be tangent to the curve.
    The position along the curve is a Qt property, and thus can be easily animated.
    
    Note: This class does not display anything; see CurveArrow for an applied example
    """
    
    def __init__(self, curve, index=0, pos=None, rotate=True):
        """Position can be set either as an index referring to the sample number or
        the position 0.0 - 1.0
        If *rotate* is True, then the item rotates to match the tangent of the curve.
        """
        
        GraphicsObject.__init__(self)
        #QObjectWorkaround.__init__(self)
        self._rotate = rotate
        self.curve = weakref.ref(curve)
        self.setParentItem(curve)
        self.setProperty('position', 0.0)
        self.setProperty('index', 0)
        
        self.setFlags(self.flags() | self.GraphicsItemFlag.ItemHasNoContents)
        
        if pos is not None:
            self.setPos(pos)
        else:
            self.setIndex(index)
            
    def setPos(self, pos):
        self.setProperty('position', float(pos))## cannot use numpy types here, MUST be python float.
        
    def setIndex(self, index):
        self.setProperty('index', int(index))  ## cannot use numpy types here, MUST be python int.
        
    def event(self, ev):
        if not isinstance(ev, QtCore.QDynamicPropertyChangeEvent) or self.curve() is None:
            return False
            
        if ev.propertyName() == 'index':
            index = self.property('index')
            if 'QVariant' in repr(index):
                index = index.toInt()[0]
        elif ev.propertyName() == 'position':
            index = None
        else:
            return False
            
        (x, y) = self.curve().getData()
        if index is None:
            #print ev.propertyName(), self.property('position').toDouble()[0], self.property('position').typeName()
            pos = self.property('position')
            if 'QVariant' in repr(pos):   ## need to support 2 APIs  :(
                pos = pos.toDouble()[0]
            index = (len(x)-1) * clip_scalar(pos, 0.0, 1.0)
            
        if index != int(index):  ## interpolate floating-point values
            i1 = int(index)
            i2 = clip_scalar(i1+1, 0, len(x)-1)
            s2 = index-i1
            s1 = 1.0-s2
            newPos = (x[i1]*s1+x[i2]*s2, y[i1]*s1+y[i2]*s2)
        else:
            index = int(index)
            i1 = clip_scalar(index-1, 0, len(x)-1)
            i2 = clip_scalar(index+1, 0, len(x)-1)
            newPos = (x[index], y[index])
            
        p1 = self.parentItem().mapToScene(QtCore.QPointF(x[i1], y[i1]))
        p2 = self.parentItem().mapToScene(QtCore.QPointF(x[i2], y[i2]))
        rads = atan2(p2.y()-p1.y(), p2.x()-p1.x()) ## returns radians
        self.resetTransform()
        if self._rotate:
            self.setRotation(180 + degrees(rads))
        QtWidgets.QGraphicsItem.setPos(self, *newPos)
        return True
        
    def boundingRect(self):
        return QtCore.QRectF()
        
    def paint(self, *args):
        pass
    
    def makeAnimation(self, prop='position', start=0.0, end=1.0, duration=10000, loop=1):
        # In Python 3, a bytes object needs to be used as a property name in
        # QPropertyAnimation. PyQt stopped automatically encoding a str when a
        # QByteArray was expected in v5.5 (see qbytearray.sip).
        if not isinstance(prop, bytes):
            prop = prop.encode('latin-1')
        anim = QtCore.QPropertyAnimation(self, prop)
        anim.setDuration(duration)
        anim.setStartValue(start)
        anim.setEndValue(end)
        anim.setLoopCount(loop)
        return anim


class CurveArrow(CurvePoint):
    """Provides an arrow that points to any specific sample on a PlotCurveItem.
    Provides properties that can be animated."""
    
    def __init__(self, curve, index=0, pos=None, **opts):
        CurvePoint.__init__(self, curve, index=index, pos=pos)
        if opts.get('pxMode', True):
            opts['pxMode'] = False
            self.setFlags(self.flags() | self.GraphicsItemFlag.ItemIgnoresTransformations)
        opts['angle'] = 0
        self.arrow = ArrowItem.ArrowItem(**opts)
        self.arrow.setParentItem(self)
        
    def setStyle(self, **opts):
        return self.arrow.setStyle(**opts)