Merge branch 'plot_curve_picking' into develop
This commit is contained in:
commit
3b94b0d93b
37
examples/MouseSelection.py
Normal file
37
examples/MouseSelection.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Demonstrates selecting plot curves by mouse click
|
||||||
|
"""
|
||||||
|
import initExample ## Add path to library (just for examples; you do not need this)
|
||||||
|
|
||||||
|
import pyqtgraph as pg
|
||||||
|
from pyqtgraph.Qt import QtCore, QtGui
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
win = pg.plot()
|
||||||
|
win.setWindowTitle('pyqtgraph example: Plot data selection')
|
||||||
|
|
||||||
|
curves = [
|
||||||
|
pg.PlotCurveItem(y=np.sin(np.linspace(0, 20, 1000)), pen='r', clickable=True),
|
||||||
|
pg.PlotCurveItem(y=np.sin(np.linspace(1, 21, 1000)), pen='g', clickable=True),
|
||||||
|
pg.PlotCurveItem(y=np.sin(np.linspace(2, 22, 1000)), pen='b', clickable=True),
|
||||||
|
]
|
||||||
|
|
||||||
|
def plotClicked(curve):
|
||||||
|
global curves
|
||||||
|
for i,c in enumerate(curves):
|
||||||
|
if c is curve:
|
||||||
|
c.setPen('rgb'[i], width=3)
|
||||||
|
else:
|
||||||
|
c.setPen('rgb'[i], width=1)
|
||||||
|
|
||||||
|
|
||||||
|
for c in curves:
|
||||||
|
win.addItem(c)
|
||||||
|
c.sigClicked.connect(plotClicked)
|
||||||
|
|
||||||
|
## Start Qt event loop unless running in interactive mode or using pyside.
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import sys
|
||||||
|
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
|
||||||
|
QtGui.QApplication.instance().exec_()
|
@ -53,9 +53,6 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
"""
|
"""
|
||||||
GraphicsObject.__init__(self, kargs.get('parent', None))
|
GraphicsObject.__init__(self, kargs.get('parent', None))
|
||||||
self.clear()
|
self.clear()
|
||||||
self.path = None
|
|
||||||
self.fillPath = None
|
|
||||||
self._boundsCache = [None, None]
|
|
||||||
|
|
||||||
## this is disastrous for performance.
|
## this is disastrous for performance.
|
||||||
#self.setCacheMode(QtGui.QGraphicsItem.DeviceCoordinateCache)
|
#self.setCacheMode(QtGui.QGraphicsItem.DeviceCoordinateCache)
|
||||||
@ -70,6 +67,7 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
'name': None,
|
'name': None,
|
||||||
'antialias': pg.getConfigOption('antialias'),\
|
'antialias': pg.getConfigOption('antialias'),\
|
||||||
'connect': 'all',
|
'connect': 'all',
|
||||||
|
'mouseWidth': 8, # width of shape responding to mouse click
|
||||||
}
|
}
|
||||||
self.setClickable(kargs.get('clickable', False))
|
self.setClickable(kargs.get('clickable', False))
|
||||||
self.setData(*args, **kargs)
|
self.setData(*args, **kargs)
|
||||||
@ -80,9 +78,17 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
return ints
|
return ints
|
||||||
return interface in ints
|
return interface in ints
|
||||||
|
|
||||||
def setClickable(self, s):
|
def setClickable(self, s, width=None):
|
||||||
"""Sets whether the item responds to mouse clicks."""
|
"""Sets whether the item responds to mouse clicks.
|
||||||
|
|
||||||
|
The *width* argument specifies the width in pixels orthogonal to the
|
||||||
|
curve that will respond to a mouse click.
|
||||||
|
"""
|
||||||
self.clickable = s
|
self.clickable = s
|
||||||
|
if width is not None:
|
||||||
|
self.opts['mouseWidth'] = width
|
||||||
|
self._mouseShape = None
|
||||||
|
self._boundingRect = None
|
||||||
|
|
||||||
|
|
||||||
def getData(self):
|
def getData(self):
|
||||||
@ -148,6 +154,8 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
w += pen.widthF()*0.7072
|
w += pen.widthF()*0.7072
|
||||||
if spen is not None and spen.isCosmetic() and spen.style() != QtCore.Qt.NoPen:
|
if spen is not None and spen.isCosmetic() and spen.style() != QtCore.Qt.NoPen:
|
||||||
w = max(w, spen.widthF()*0.7072)
|
w = max(w, spen.widthF()*0.7072)
|
||||||
|
if self.clickable:
|
||||||
|
w = max(w, self.opts['mouseWidth']//2 + 1)
|
||||||
return w
|
return w
|
||||||
|
|
||||||
def boundingRect(self):
|
def boundingRect(self):
|
||||||
@ -171,6 +179,7 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
#px += self._maxSpotWidth * 0.5
|
#px += self._maxSpotWidth * 0.5
|
||||||
#py += self._maxSpotWidth * 0.5
|
#py += self._maxSpotWidth * 0.5
|
||||||
self._boundingRect = QtCore.QRectF(xmn-px, ymn-py, (2*px)+xmx-xmn, (2*py)+ymx-ymn)
|
self._boundingRect = QtCore.QRectF(xmn-px, ymn-py, (2*px)+xmx-xmn, (2*py)+ymx-ymn)
|
||||||
|
|
||||||
return self._boundingRect
|
return self._boundingRect
|
||||||
|
|
||||||
def viewTransformChanged(self):
|
def viewTransformChanged(self):
|
||||||
@ -328,6 +337,7 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
|
|
||||||
self.path = None
|
self.path = None
|
||||||
self.fillPath = None
|
self.fillPath = None
|
||||||
|
self._mouseShape = None
|
||||||
#self.xDisp = self.yDisp = None
|
#self.xDisp = self.yDisp = None
|
||||||
|
|
||||||
if 'name' in kargs:
|
if 'name' in kargs:
|
||||||
@ -376,12 +386,14 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
return path
|
return path
|
||||||
|
|
||||||
|
|
||||||
def shape(self):
|
def getPath(self):
|
||||||
if self.path is None:
|
if self.path is None:
|
||||||
try:
|
x,y = self.getData()
|
||||||
self.path = self.generatePath(*self.getData())
|
if x is None or len(x) == 0 or y is None or len(y) == 0:
|
||||||
except:
|
|
||||||
return QtGui.QPainterPath()
|
return QtGui.QPainterPath()
|
||||||
|
self.path = self.generatePath(*self.getData())
|
||||||
|
self.fillPath = None
|
||||||
|
self._mouseShape = None
|
||||||
return self.path
|
return self.path
|
||||||
|
|
||||||
@pg.debug.warnOnException ## raising an exception here causes crash
|
@pg.debug.warnOnException ## raising an exception here causes crash
|
||||||
@ -396,14 +408,8 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
|
|
||||||
x = None
|
x = None
|
||||||
y = None
|
y = None
|
||||||
if self.path is None:
|
path = self.getPath()
|
||||||
x,y = self.getData()
|
|
||||||
if x is None or len(x) == 0 or y is None or len(y) == 0:
|
|
||||||
return
|
|
||||||
self.path = self.generatePath(x,y)
|
|
||||||
self.fillPath = None
|
|
||||||
|
|
||||||
path = self.path
|
|
||||||
profiler('generate path')
|
profiler('generate path')
|
||||||
|
|
||||||
if self._exportOpts is not False:
|
if self._exportOpts is not False:
|
||||||
@ -522,13 +528,36 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
self.xDisp = None ## display values (after log / fft)
|
self.xDisp = None ## display values (after log / fft)
|
||||||
self.yDisp = None
|
self.yDisp = None
|
||||||
self.path = None
|
self.path = None
|
||||||
|
self.fillPath = None
|
||||||
|
self._mouseShape = None
|
||||||
|
self._mouseBounds = None
|
||||||
|
self._boundsCache = [None, None]
|
||||||
#del self.xData, self.yData, self.xDisp, self.yDisp, self.path
|
#del self.xData, self.yData, self.xDisp, self.yDisp, self.path
|
||||||
|
|
||||||
|
def mouseShape(self):
|
||||||
|
"""
|
||||||
|
Return a QPainterPath representing the clickable shape of the curve
|
||||||
|
|
||||||
|
"""
|
||||||
|
if self._mouseShape is None:
|
||||||
|
view = self.getViewBox()
|
||||||
|
if view is None:
|
||||||
|
return QtGui.QPainterPath()
|
||||||
|
stroker = QtGui.QPainterPathStroker()
|
||||||
|
path = self.getPath()
|
||||||
|
path = self.mapToItem(view, path)
|
||||||
|
stroker.setWidth(self.opts['mouseWidth'])
|
||||||
|
mousePath = stroker.createStroke(path)
|
||||||
|
self._mouseShape = self.mapFromItem(view, mousePath)
|
||||||
|
return self._mouseShape
|
||||||
|
|
||||||
def mouseClickEvent(self, ev):
|
def mouseClickEvent(self, ev):
|
||||||
if not self.clickable or ev.button() != QtCore.Qt.LeftButton:
|
if not self.clickable or ev.button() != QtCore.Qt.LeftButton:
|
||||||
return
|
return
|
||||||
ev.accept()
|
if self.mouseShape().contains(ev.pos()):
|
||||||
self.sigClicked.emit(self)
|
ev.accept()
|
||||||
|
self.sigClicked.emit(self)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ROIPlotItem(PlotCurveItem):
|
class ROIPlotItem(PlotCurveItem):
|
||||||
|
Loading…
Reference in New Issue
Block a user