Infiniteline enhancement

This commit is contained in:
lesauxvi 2016-01-15 16:10:24 +01:00
parent 9e8c2082ed
commit ce36ea4eb6
3 changed files with 377 additions and 102 deletions

35
examples/plottingItems.py Normal file
View File

@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
"""
This example demonstrates some of the plotting items available in pyqtgraph.
"""
import initExample ## Add path to library (just for examples; you do not need this)
from pyqtgraph.Qt import QtGui, QtCore
import numpy as np
import pyqtgraph as pg
app = QtGui.QApplication([])
win = pg.GraphicsWindow(title="Plotting items examples")
win.resize(1000,600)
win.setWindowTitle('pyqtgraph example: plotting with items')
# Enable antialiasing for prettier plots
pg.setConfigOptions(antialias=True)
p1 = win.addPlot(title="Plot Items example", y=np.random.normal(size=100))
inf1 = pg.InfiniteLine(movable=True, angle=90, label=True, textColor=(200,200,100), textFill=(200,200,200,50))
inf2 = pg.InfiniteLine(movable=True, angle=0, label=True, pen=(0, 0, 200), bounds = [-2, 2], unit="mm", hoverPen=(0,200,0))
inf3 = pg.InfiniteLine(movable=True, angle=45)
inf1.setPos([2,2])
p1.addItem(inf1)
p1.addItem(inf2)
p1.addItem(inf3)
lr = pg.LinearRegionItem(values=[0, 10])
p1.addItem(lr)
## 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_()

View File

@ -1,32 +1,73 @@
from ..Qt import QtGui, QtCore from ..Qt import QtGui, QtCore
from ..Point import Point from ..Point import Point
from .GraphicsObject import GraphicsObject from .UIGraphicsItem import UIGraphicsItem
from .TextItem import TextItem
from .. import functions as fn from .. import functions as fn
import numpy as np import numpy as np
import weakref import weakref
import math
__all__ = ['InfiniteLine'] __all__ = ['InfiniteLine']
class InfiniteLine(GraphicsObject):
def _calcLine(pos, angle, xmin, ymin, xmax, ymax):
""" """
**Bases:** :class:`GraphicsObject <pyqtgraph.GraphicsObject>` Evaluate the location of the points that delimitates a line into a viewbox
described by x and y ranges. Depending on the angle value, pos can be a
float (if angle=0 and 90) or a list of float (x and y coordinates).
Could be possible to beautify this piece of code.
New in verson 0.9.11
"""
if angle == 0:
x1, y1, x2, y2 = xmin, pos, xmax, pos
elif angle == 90:
x1, y1, x2, y2 = pos, ymin, pos, ymax
else:
x0, y0 = pos
tana = math.tan(angle*math.pi/180)
y1 = tana*(xmin-x0) + y0
y2 = tana*(xmax-x0) + y0
if angle > 0:
y1 = max(y1, ymin)
y2 = min(y2, ymax)
else:
y1 = min(y1, ymax)
y2 = max(y2, ymin)
x1 = (y1-y0)/tana + x0
x2 = (y2-y0)/tana + x0
p1 = Point(x1, y1)
p2 = Point(x2, y2)
return p1, p2
class InfiniteLine(UIGraphicsItem):
"""
**Bases:** :class:`UIGraphicsItem <pyqtgraph.UIGraphicsItem>`
Displays a line of infinite length. Displays a line of infinite length.
This line may be dragged to indicate a position in data coordinates. This line may be dragged to indicate a position in data coordinates.
=============================== =================================================== =============================== ===================================================
**Signals:** **Signals:**
sigDragged(self) sigDragged(self)
sigPositionChangeFinished(self) sigPositionChangeFinished(self)
sigPositionChanged(self) sigPositionChanged(self)
=============================== =================================================== =============================== ===================================================
Major changes have been performed in this class since version 0.9.11. The
number of methods in the public API has been increased, but the already
existing methods can be used in the same way.
""" """
sigDragged = QtCore.Signal(object) sigDragged = QtCore.Signal(object)
sigPositionChangeFinished = QtCore.Signal(object) sigPositionChangeFinished = QtCore.Signal(object)
sigPositionChanged = QtCore.Signal(object) sigPositionChanged = QtCore.Signal(object)
def __init__(self, pos=None, angle=90, pen=None, movable=False, bounds=None): def __init__(self, pos=None, angle=90, pen=None, movable=False, bounds=None,
hoverPen=None, label=False, textColor=None, textFill=None,
textLocation=0.05, textShift=0.5, textFormat="{:.3f}",
unit=None, name=None):
""" """
=============== ================================================================== =============== ==================================================================
**Arguments:** **Arguments:**
@ -37,79 +78,125 @@ class InfiniteLine(GraphicsObject):
for :func:`mkPen <pyqtgraph.mkPen>`. Default pen is transparent for :func:`mkPen <pyqtgraph.mkPen>`. Default pen is transparent
yellow. yellow.
movable If True, the line can be dragged to a new position by the user. movable If True, the line can be dragged to a new position by the user.
hoverPen Pen to use when drawing line when hovering over it. Can be any
arguments that are valid for :func:`mkPen <pyqtgraph.mkPen>`.
Default pen is red.
bounds Optional [min, max] bounding values. Bounds are only valid if the bounds Optional [min, max] bounding values. Bounds are only valid if the
line is vertical or horizontal. line is vertical or horizontal.
label if True, a label is displayed next to the line to indicate its
location in data coordinates
textColor color of the label. Can be any argument fn.mkColor can understand.
textFill A brush to use when filling within the border of the text.
textLocation A float [0-1] that defines the location of the text.
textShift A float [0-1] that defines when the text shifts from one side to
another.
textFormat Any new python 3 str.format() format.
unit If not None, corresponds to the unit to show next to the label
name If not None, corresponds to the name of the object
=============== ================================================================== =============== ==================================================================
""" """
GraphicsObject.__init__(self) UIGraphicsItem.__init__(self)
if bounds is None: ## allowed value boundaries for orthogonal lines if bounds is None: ## allowed value boundaries for orthogonal lines
self.maxRange = [None, None] self.maxRange = [None, None]
else: else:
self.maxRange = bounds self.maxRange = bounds
self.moving = False self.moving = False
self.setMovable(movable)
self.mouseHovering = False self.mouseHovering = False
self.angle = ((angle+45) % 180) - 45
if textColor is None:
textColor = (200, 200, 200)
self.textColor = textColor
self.location = textLocation
self.shift = textShift
self.label = label
self.format = textFormat
self.unit = unit
self._name = name
self.anchorLeft = (1., 0.5)
self.anchorRight = (0., 0.5)
self.anchorUp = (0.5, 1.)
self.anchorDown = (0.5, 0.)
self.text = TextItem(fill=textFill)
self.text.setParentItem(self) # important
self.p = [0, 0] self.p = [0, 0]
self.setAngle(angle)
if pen is None:
pen = (200, 200, 100)
self.setPen(pen)
if hoverPen is None:
self.setHoverPen(color=(255,0,0), width=self.pen.width())
else:
self.setHoverPen(hoverPen)
self.currentPen = self.pen
self.setMovable(movable)
if pos is None: if pos is None:
pos = Point(0,0) pos = Point(0,0)
self.setPos(pos) self.setPos(pos)
if pen is None: if (self.angle == 0 or self.angle == 90) and self.label:
pen = (200, 200, 100) self.text.show()
else:
self.setPen(pen) self.text.hide()
self.setHoverPen(color=(255,0,0), width=self.pen.width())
self.currentPen = self.pen
def setMovable(self, m): def setMovable(self, m):
"""Set whether the line is movable by the user.""" """Set whether the line is movable by the user."""
self.movable = m self.movable = m
self.setAcceptHoverEvents(m) self.setAcceptHoverEvents(m)
def setBounds(self, bounds): def setBounds(self, bounds):
"""Set the (minimum, maximum) allowable values when dragging.""" """Set the (minimum, maximum) allowable values when dragging."""
self.maxRange = bounds self.maxRange = bounds
self.setValue(self.value()) self.setValue(self.value())
def setPen(self, *args, **kwargs): def setPen(self, *args, **kwargs):
"""Set the pen for drawing the line. Allowable arguments are any that are valid """Set the pen for drawing the line. Allowable arguments are any that are valid
for :func:`mkPen <pyqtgraph.mkPen>`.""" for :func:`mkPen <pyqtgraph.mkPen>`."""
self.pen = fn.mkPen(*args, **kwargs) self.pen = fn.mkPen(*args, **kwargs)
if not self.mouseHovering: if not self.mouseHovering:
self.currentPen = self.pen self.currentPen = self.pen
self.update() self.update()
def setHoverPen(self, *args, **kwargs): def setHoverPen(self, *args, **kwargs):
"""Set the pen for drawing the line while the mouse hovers over it. """Set the pen for drawing the line while the mouse hovers over it.
Allowable arguments are any that are valid Allowable arguments are any that are valid
for :func:`mkPen <pyqtgraph.mkPen>`. for :func:`mkPen <pyqtgraph.mkPen>`.
If the line is not movable, then hovering is also disabled. If the line is not movable, then hovering is also disabled.
Added in version 0.9.9.""" Added in version 0.9.9."""
self.hoverPen = fn.mkPen(*args, **kwargs) self.hoverPen = fn.mkPen(*args, **kwargs)
if self.mouseHovering: if self.mouseHovering:
self.currentPen = self.hoverPen self.currentPen = self.hoverPen
self.update() self.update()
def setAngle(self, angle): def setAngle(self, angle):
""" """
Takes angle argument in degrees. Takes angle argument in degrees.
0 is horizontal; 90 is vertical. 0 is horizontal; 90 is vertical.
Note that the use of value() and setValue() changes if the line is Note that the use of value() and setValue() changes if the line is
not vertical or horizontal. not vertical or horizontal.
""" """
self.angle = ((angle+45) % 180) - 45 ## -45 <= angle < 135 self.angle = ((angle+45) % 180) - 45 ## -45 <= angle < 135
self.resetTransform() # self.resetTransform() # no longer needed since version 0.9.11
self.rotate(self.angle) # self.rotate(self.angle) # no longer needed since version 0.9.11
if (self.angle == 0 or self.angle == 90) and self.label:
self.text.show()
else:
self.text.hide()
self.update() self.update()
def setPos(self, pos): def setPos(self, pos):
if type(pos) in [list, tuple]: if type(pos) in [list, tuple]:
newPos = pos newPos = pos
elif isinstance(pos, QtCore.QPointF): elif isinstance(pos, QtCore.QPointF):
@ -121,10 +208,10 @@ class InfiniteLine(GraphicsObject):
newPos = [0, pos] newPos = [0, pos]
else: else:
raise Exception("Must specify 2D coordinate for non-orthogonal lines.") raise Exception("Must specify 2D coordinate for non-orthogonal lines.")
## check bounds (only works for orthogonal lines) ## check bounds (only works for orthogonal lines)
if self.angle == 90: if self.angle == 90:
if self.maxRange[0] is not None: if self.maxRange[0] is not None:
newPos[0] = max(newPos[0], self.maxRange[0]) newPos[0] = max(newPos[0], self.maxRange[0])
if self.maxRange[1] is not None: if self.maxRange[1] is not None:
newPos[0] = min(newPos[0], self.maxRange[1]) newPos[0] = min(newPos[0], self.maxRange[1])
@ -133,24 +220,24 @@ class InfiniteLine(GraphicsObject):
newPos[1] = max(newPos[1], self.maxRange[0]) newPos[1] = max(newPos[1], self.maxRange[0])
if self.maxRange[1] is not None: if self.maxRange[1] is not None:
newPos[1] = min(newPos[1], self.maxRange[1]) newPos[1] = min(newPos[1], self.maxRange[1])
if self.p != newPos: if self.p != newPos:
self.p = newPos self.p = newPos
GraphicsObject.setPos(self, Point(self.p)) # UIGraphicsItem.setPos(self, Point(self.p)) # thanks Sylvain!
self.update() self.update()
self.sigPositionChanged.emit(self) self.sigPositionChanged.emit(self)
def getXPos(self): def getXPos(self):
return self.p[0] return self.p[0]
def getYPos(self): def getYPos(self):
return self.p[1] return self.p[1]
def getPos(self): def getPos(self):
return self.p return self.p
def value(self): def value(self):
"""Return the value of the line. Will be a single number for horizontal and """Return the value of the line. Will be a single number for horizontal and
vertical lines, and a list of [x,y] values for diagonal lines.""" vertical lines, and a list of [x,y] values for diagonal lines."""
if self.angle%180 == 0: if self.angle%180 == 0:
return self.getYPos() return self.getYPos()
@ -158,10 +245,10 @@ class InfiniteLine(GraphicsObject):
return self.getXPos() return self.getXPos()
else: else:
return self.getPos() return self.getPos()
def setValue(self, v): def setValue(self, v):
"""Set the position of the line. If line is horizontal or vertical, v can be """Set the position of the line. If line is horizontal or vertical, v can be
a single value. Otherwise, a 2D coordinate must be specified (list, tuple and a single value. Otherwise, a 2D coordinate must be specified (list, tuple and
QPointF are all acceptable).""" QPointF are all acceptable)."""
self.setPos(v) self.setPos(v)
@ -174,25 +261,59 @@ class InfiniteLine(GraphicsObject):
#else: #else:
#print "ignore", change #print "ignore", change
#return GraphicsObject.itemChange(self, change, val) #return GraphicsObject.itemChange(self, change, val)
def boundingRect(self): def boundingRect(self):
#br = UIGraphicsItem.boundingRect(self) br = UIGraphicsItem.boundingRect(self) # directly in viewBox coordinates
br = self.viewRect() # we need to limit the boundingRect to the appropriate value.
## add a 4-pixel radius around the line for mouse interaction. val = self.value()
if self.angle == 0: # horizontal line
px = self.pixelLength(direction=Point(1,0), ortho=True) ## get pixel length orthogonal to the line self._p1, self._p2 = _calcLine(val, 0, *br.getCoords())
if px is None: px = self.pixelLength(direction=Point(1,0), ortho=True) ## get pixel length orthogonal to the line
px = 0 if px is None:
w = (max(4, self.pen.width()/2, self.hoverPen.width()/2)+1) * px px = 0
br.setBottom(-w) w = (max(4, self.pen.width()/2, self.hoverPen.width()/2)+1) * px
br.setTop(w) o1, o2 = _calcLine(val-w, 0, *br.getCoords())
o3, o4 = _calcLine(val+w, 0, *br.getCoords())
elif self.angle == 90: # vertical line
self._p1, self._p2 = _calcLine(val, 90, *br.getCoords())
px = self.pixelLength(direction=Point(0,1), ortho=True) ## get pixel length orthogonal to the line
if px is None:
px = 0
w = (max(4, self.pen.width()/2, self.hoverPen.width()/2)+1) * px
o1, o2 = _calcLine(val-w, 90, *br.getCoords())
o3, o4 = _calcLine(val+w, 90, *br.getCoords())
else: # oblique line
self._p1, self._p2 = _calcLine(val, self.angle, *br.getCoords())
pxy = self.pixelLength(direction=Point(0,1), ortho=True)
if pxy is None:
pxy = 0
wy = (max(4, self.pen.width()/2, self.hoverPen.width()/2)+1) * pxy
pxx = self.pixelLength(direction=Point(1,0), ortho=True)
if pxx is None:
pxx = 0
wx = (max(4, self.pen.width()/2, self.hoverPen.width()/2)+1) * pxx
o1, o2 = _calcLine([val[0]-wy, val[1]-wx], self.angle, *br.getCoords())
o3, o4 = _calcLine([val[0]+wy, val[1]+wx], self.angle, *br.getCoords())
self._polygon = QtGui.QPolygonF([o1, o2, o4, o3])
br = self._polygon.boundingRect()
return br.normalized() return br.normalized()
def shape(self):
# returns a QPainterPath. Needed when the item is non rectangular if
# accurate mouse click detection is required.
# New in version 0.9.11
qpp = QtGui.QPainterPath()
qpp.addPolygon(self._polygon)
return qpp
def paint(self, p, *args): def paint(self, p, *args):
br = self.boundingRect() br = self.boundingRect()
p.setPen(self.currentPen) p.setPen(self.currentPen)
p.drawLine(Point(br.right(), 0), Point(br.left(), 0)) p.drawLine(self._p1, self._p2)
def dataBounds(self, axis, frac=1.0, orthoRange=None): def dataBounds(self, axis, frac=1.0, orthoRange=None):
if axis == 0: if axis == 0:
return None ## x axis should never be auto-scaled return None ## x axis should never be auto-scaled
@ -203,19 +324,20 @@ class InfiniteLine(GraphicsObject):
if self.movable and ev.button() == QtCore.Qt.LeftButton: if self.movable and ev.button() == QtCore.Qt.LeftButton:
if ev.isStart(): if ev.isStart():
self.moving = True self.moving = True
self.cursorOffset = self.pos() - self.mapToParent(ev.buttonDownPos()) self.cursorOffset = self.value() - ev.buttonDownPos()
self.startPosition = self.pos() self.startPosition = self.value()
ev.accept() ev.accept()
if not self.moving: if not self.moving:
return return
self.setPos(self.cursorOffset + self.mapToParent(ev.pos())) self.setPos(self.cursorOffset + ev.pos())
self.prepareGeometryChange() # new in version 0.9.11
self.sigDragged.emit(self) self.sigDragged.emit(self)
if ev.isFinish(): if ev.isFinish():
self.moving = False self.moving = False
self.sigPositionChangeFinished.emit(self) self.sigPositionChangeFinished.emit(self)
def mouseClickEvent(self, ev): def mouseClickEvent(self, ev):
if self.moving and ev.button() == QtCore.Qt.RightButton: if self.moving and ev.button() == QtCore.Qt.RightButton:
ev.accept() ev.accept()
@ -240,3 +362,122 @@ class InfiniteLine(GraphicsObject):
else: else:
self.currentPen = self.pen self.currentPen = self.pen
self.update() self.update()
def update(self):
# new in version 0.9.11
UIGraphicsItem.update(self)
br = UIGraphicsItem.boundingRect(self) # directly in viewBox coordinates
xmin, ymin, xmax, ymax = br.getCoords()
if self.angle == 90: # vertical line
diffX = xmax-xmin
diffMin = self.value()-xmin
limInf = self.shift*diffX
ypos = ymin+self.location*(ymax-ymin)
if diffMin < limInf:
self.text.anchor = Point(self.anchorRight)
else:
self.text.anchor = Point(self.anchorLeft)
fmt = " x = " + self.format
if self.unit is not None:
fmt = fmt + self.unit
self.text.setText(fmt.format(self.value()), color=self.textColor)
self.text.setPos(self.value(), ypos)
elif self.angle == 0: # horizontal line
diffY = ymax-ymin
diffMin = self.value()-ymin
limInf = self.shift*(ymax-ymin)
xpos = xmin+self.location*(xmax-xmin)
if diffMin < limInf:
self.text.anchor = Point(self.anchorUp)
else:
self.text.anchor = Point(self.anchorDown)
fmt = " y = " + self.format
if self.unit is not None:
fmt = fmt + self.unit
self.text.setText(fmt.format(self.value()), color=self.textColor)
self.text.setPos(xpos, self.value())
def showLabel(self, state):
"""
Display or not the label indicating the location of the line in data
coordinates.
============== ==============================================
**Arguments:**
state If True, the label is shown. Otherwise, it is hidden.
============== ==============================================
"""
if state:
self.text.show()
else:
self.text.hide()
self.update()
def setLocation(self, loc):
"""
Set the location of the textItem with respect to a specific axis. If the
line is vertical, the location is based on the normalized range of the
yaxis. Otherwise, it is based on the normalized range of the xaxis.
============== ==============================================
**Arguments:**
loc the normalized location of the textItem.
============== ==============================================
"""
if loc > 1.:
loc = 1.
if loc < 0.:
loc = 0.
self.location = loc
self.update()
def setShift(self, shift):
"""
Set the value with respect to the normalized range of the corresponding
axis where the location of the textItem shifts from one side to another.
============== ==============================================
**Arguments:**
shift the normalized shift value of the textItem.
============== ==============================================
"""
if shift > 1.:
shift = 1.
if shift < 0.:
shift = 0.
self.shift = shift
self.update()
def setFormat(self, format):
"""
Set the format of the label used to indicate the location of the line.
============== ==============================================
**Arguments:**
format Any format compatible with the new python
str.format() format style.
============== ==============================================
"""
self.format = format
self.update()
def setUnit(self, unit):
"""
Set the unit of the label used to indicate the location of the line.
============== ==============================================
**Arguments:**
unit Any string.
============== ==============================================
"""
self.unit = unit
self.update()
def setName(self, name):
self._name = name
def name(self):
return self._name

View File

@ -9,10 +9,10 @@ __all__ = ['LinearRegionItem']
class LinearRegionItem(UIGraphicsItem): class LinearRegionItem(UIGraphicsItem):
""" """
**Bases:** :class:`UIGraphicsItem <pyqtgraph.UIGraphicsItem>` **Bases:** :class:`UIGraphicsItem <pyqtgraph.UIGraphicsItem>`
Used for marking a horizontal or vertical region in plots. Used for marking a horizontal or vertical region in plots.
The region can be dragged and is bounded by lines which can be dragged individually. The region can be dragged and is bounded by lines which can be dragged individually.
=============================== ============================================================================= =============================== =============================================================================
**Signals:** **Signals:**
sigRegionChangeFinished(self) Emitted when the user has finished dragging the region (or one of its lines) sigRegionChangeFinished(self) Emitted when the user has finished dragging the region (or one of its lines)
@ -21,15 +21,15 @@ class LinearRegionItem(UIGraphicsItem):
and when the region is changed programatically. and when the region is changed programatically.
=============================== ============================================================================= =============================== =============================================================================
""" """
sigRegionChangeFinished = QtCore.Signal(object) sigRegionChangeFinished = QtCore.Signal(object)
sigRegionChanged = QtCore.Signal(object) sigRegionChanged = QtCore.Signal(object)
Vertical = 0 Vertical = 0
Horizontal = 1 Horizontal = 1
def __init__(self, values=[0,1], orientation=None, brush=None, movable=True, bounds=None): def __init__(self, values=[0,1], orientation=None, brush=None, movable=True, bounds=None):
"""Create a new LinearRegionItem. """Create a new LinearRegionItem.
============== ===================================================================== ============== =====================================================================
**Arguments:** **Arguments:**
values A list of the positions of the lines in the region. These are not values A list of the positions of the lines in the region. These are not
@ -44,7 +44,7 @@ class LinearRegionItem(UIGraphicsItem):
bounds Optional [min, max] bounding values for the region bounds Optional [min, max] bounding values for the region
============== ===================================================================== ============== =====================================================================
""" """
UIGraphicsItem.__init__(self) UIGraphicsItem.__init__(self)
if orientation is None: if orientation is None:
orientation = LinearRegionItem.Vertical orientation = LinearRegionItem.Vertical
@ -53,30 +53,30 @@ class LinearRegionItem(UIGraphicsItem):
self.blockLineSignal = False self.blockLineSignal = False
self.moving = False self.moving = False
self.mouseHovering = False self.mouseHovering = False
if orientation == LinearRegionItem.Horizontal: if orientation == LinearRegionItem.Horizontal:
self.lines = [ self.lines = [
InfiniteLine(QtCore.QPointF(0, values[0]), 0, movable=movable, bounds=bounds), InfiniteLine(QtCore.QPointF(0, values[0]), 0, movable=movable, bounds=bounds),
InfiniteLine(QtCore.QPointF(0, values[1]), 0, movable=movable, bounds=bounds)] InfiniteLine(QtCore.QPointF(0, values[1]), 0, movable=movable, bounds=bounds)]
elif orientation == LinearRegionItem.Vertical: elif orientation == LinearRegionItem.Vertical:
self.lines = [ self.lines = [
InfiniteLine(QtCore.QPointF(values[1], 0), 90, movable=movable, bounds=bounds), InfiniteLine(QtCore.QPointF(values[1], 0), 90, movable=movable, bounds=bounds),
InfiniteLine(QtCore.QPointF(values[0], 0), 90, movable=movable, bounds=bounds)] InfiniteLine(QtCore.QPointF(values[0], 0), 90, movable=movable, bounds=bounds)]
else: else:
raise Exception('Orientation must be one of LinearRegionItem.Vertical or LinearRegionItem.Horizontal') raise Exception('Orientation must be one of LinearRegionItem.Vertical or LinearRegionItem.Horizontal')
for l in self.lines: for l in self.lines:
l.setParentItem(self) l.setParentItem(self)
l.sigPositionChangeFinished.connect(self.lineMoveFinished) l.sigPositionChangeFinished.connect(self.lineMoveFinished)
l.sigPositionChanged.connect(self.lineMoved) l.sigPositionChanged.connect(self.lineMoved)
if brush is None: if brush is None:
brush = QtGui.QBrush(QtGui.QColor(0, 0, 255, 50)) brush = QtGui.QBrush(QtGui.QColor(0, 0, 255, 50))
self.setBrush(brush) self.setBrush(brush)
self.setMovable(movable) self.setMovable(movable)
def getRegion(self): def getRegion(self):
"""Return the values at the edges of the region.""" """Return the values at the edges of the region."""
#if self.orientation[0] == 'h': #if self.orientation[0] == 'h':
@ -88,7 +88,7 @@ class LinearRegionItem(UIGraphicsItem):
def setRegion(self, rgn): def setRegion(self, rgn):
"""Set the values for the edges of the region. """Set the values for the edges of the region.
============== ============================================== ============== ==============================================
**Arguments:** **Arguments:**
rgn A list or tuple of the lower and upper values. rgn A list or tuple of the lower and upper values.
@ -114,14 +114,14 @@ class LinearRegionItem(UIGraphicsItem):
def setBounds(self, bounds): def setBounds(self, bounds):
"""Optional [min, max] bounding values for the region. To have no bounds on the """Optional [min, max] bounding values for the region. To have no bounds on the
region use [None, None]. region use [None, None].
Does not affect the current position of the region unless it is outside the new bounds. Does not affect the current position of the region unless it is outside the new bounds.
See :func:`setRegion <pyqtgraph.LinearRegionItem.setRegion>` to set the position See :func:`setRegion <pyqtgraph.LinearRegionItem.setRegion>` to set the position
of the region.""" of the region."""
for l in self.lines: for l in self.lines:
l.setBounds(bounds) l.setBounds(bounds)
def setMovable(self, m): def setMovable(self, m):
"""Set lines to be movable by the user, or not. If lines are movable, they will """Set lines to be movable by the user, or not. If lines are movable, they will
also accept HoverEvents.""" also accept HoverEvents."""
for l in self.lines: for l in self.lines:
l.setMovable(m) l.setMovable(m)
@ -138,7 +138,7 @@ class LinearRegionItem(UIGraphicsItem):
br.setTop(rng[0]) br.setTop(rng[0])
br.setBottom(rng[1]) br.setBottom(rng[1])
return br.normalized() return br.normalized()
def paint(self, p, *args): def paint(self, p, *args):
profiler = debug.Profiler() profiler = debug.Profiler()
UIGraphicsItem.paint(self, p, *args) UIGraphicsItem.paint(self, p, *args)
@ -158,12 +158,12 @@ class LinearRegionItem(UIGraphicsItem):
self.prepareGeometryChange() self.prepareGeometryChange()
#self.emit(QtCore.SIGNAL('regionChanged'), self) #self.emit(QtCore.SIGNAL('regionChanged'), self)
self.sigRegionChanged.emit(self) self.sigRegionChanged.emit(self)
def lineMoveFinished(self): def lineMoveFinished(self):
#self.emit(QtCore.SIGNAL('regionChangeFinished'), self) #self.emit(QtCore.SIGNAL('regionChangeFinished'), self)
self.sigRegionChangeFinished.emit(self) self.sigRegionChangeFinished.emit(self)
#def updateBounds(self): #def updateBounds(self):
#vb = self.view().viewRect() #vb = self.view().viewRect()
#vals = [self.lines[0].value(), self.lines[1].value()] #vals = [self.lines[0].value(), self.lines[1].value()]
@ -176,7 +176,7 @@ class LinearRegionItem(UIGraphicsItem):
#if vb != self.bounds: #if vb != self.bounds:
#self.bounds = vb #self.bounds = vb
#self.rect.setRect(vb) #self.rect.setRect(vb)
#def mousePressEvent(self, ev): #def mousePressEvent(self, ev):
#if not self.movable: #if not self.movable:
#ev.ignore() #ev.ignore()
@ -188,11 +188,11 @@ class LinearRegionItem(UIGraphicsItem):
##self.pressDelta = self.mapToParent(ev.pos()) - QtCore.QPointF(*self.p) ##self.pressDelta = self.mapToParent(ev.pos()) - QtCore.QPointF(*self.p)
##else: ##else:
##ev.ignore() ##ev.ignore()
#def mouseReleaseEvent(self, ev): #def mouseReleaseEvent(self, ev):
#for l in self.lines: #for l in self.lines:
#l.mouseReleaseEvent(ev) #l.mouseReleaseEvent(ev)
#def mouseMoveEvent(self, ev): #def mouseMoveEvent(self, ev):
##print "move", ev.pos() ##print "move", ev.pos()
#if not self.movable: #if not self.movable:
@ -208,16 +208,16 @@ class LinearRegionItem(UIGraphicsItem):
if not self.movable or int(ev.button() & QtCore.Qt.LeftButton) == 0: if not self.movable or int(ev.button() & QtCore.Qt.LeftButton) == 0:
return return
ev.accept() ev.accept()
if ev.isStart(): if ev.isStart():
bdp = ev.buttonDownPos() bdp = ev.buttonDownPos()
self.cursorOffsets = [l.pos() - bdp for l in self.lines] self.cursorOffsets = [l.value() - bdp for l in self.lines]
self.startPositions = [l.pos() for l in self.lines] self.startPositions = [l.value() for l in self.lines]
self.moving = True self.moving = True
if not self.moving: if not self.moving:
return return
#delta = ev.pos() - ev.lastPos() #delta = ev.pos() - ev.lastPos()
self.lines[0].blockSignals(True) # only want to update once self.lines[0].blockSignals(True) # only want to update once
for i, l in enumerate(self.lines): for i, l in enumerate(self.lines):
@ -226,13 +226,13 @@ class LinearRegionItem(UIGraphicsItem):
#l.mouseDragEvent(ev) #l.mouseDragEvent(ev)
self.lines[0].blockSignals(False) self.lines[0].blockSignals(False)
self.prepareGeometryChange() self.prepareGeometryChange()
if ev.isFinish(): if ev.isFinish():
self.moving = False self.moving = False
self.sigRegionChangeFinished.emit(self) self.sigRegionChangeFinished.emit(self)
else: else:
self.sigRegionChanged.emit(self) self.sigRegionChanged.emit(self)
def mouseClickEvent(self, ev): def mouseClickEvent(self, ev):
if self.moving and ev.button() == QtCore.Qt.RightButton: if self.moving and ev.button() == QtCore.Qt.RightButton:
ev.accept() ev.accept()
@ -248,7 +248,7 @@ class LinearRegionItem(UIGraphicsItem):
self.setMouseHover(True) self.setMouseHover(True)
else: else:
self.setMouseHover(False) self.setMouseHover(False)
def setMouseHover(self, hover): def setMouseHover(self, hover):
## Inform the item that the mouse is(not) hovering over it ## Inform the item that the mouse is(not) hovering over it
if self.mouseHovering == hover: if self.mouseHovering == hover:
@ -276,15 +276,14 @@ class LinearRegionItem(UIGraphicsItem):
#print "rgn hover leave" #print "rgn hover leave"
#ev.ignore() #ev.ignore()
#self.updateHoverBrush(False) #self.updateHoverBrush(False)
#def updateHoverBrush(self, hover=None): #def updateHoverBrush(self, hover=None):
#if hover is None: #if hover is None:
#scene = self.scene() #scene = self.scene()
#hover = scene.claimEvent(self, QtCore.Qt.LeftButton, scene.Drag) #hover = scene.claimEvent(self, QtCore.Qt.LeftButton, scene.Drag)
#if hover: #if hover:
#self.currentBrush = fn.mkBrush(255, 0,0,100) #self.currentBrush = fn.mkBrush(255, 0,0,100)
#else: #else:
#self.currentBrush = self.brush #self.currentBrush = self.brush
#self.update() #self.update()