Labels can rotate with line
This commit is contained in:
parent
a8510c3354
commit
069a5bfeea
@ -17,12 +17,14 @@ win.resize(1000,600)
|
|||||||
pg.setConfigOptions(antialias=True)
|
pg.setConfigOptions(antialias=True)
|
||||||
|
|
||||||
p1 = win.addPlot(title="Plot Items example", y=np.random.normal(size=100))
|
p1 = win.addPlot(title="Plot Items example", y=np.random.normal(size=100))
|
||||||
inf1 = pg.InfiniteLine(movable=True, angle=90, label=True, textPosition=[0.5, 0.2], textColor=(200,200,100), textFill=(200,200,200,50))
|
inf1 = pg.InfiniteLine(movable=True, angle=90, text='x={value:0.2f}',
|
||||||
inf2 = pg.InfiniteLine(movable=True, angle=0, label=True, pen=(0, 0, 200), textColor=(200,0,0), bounds = [-2, 2], suffix="mm", hoverPen=(0,200,0), draggableLabel=True, textFill=0.5)
|
textOpts={'position':0.2, 'color': (200,200,100), 'fill': (200,200,200,50)})
|
||||||
inf3 = pg.InfiniteLine(movable=True, angle=45)
|
inf2 = pg.InfiniteLine(movable=True, angle=0, pen=(0, 0, 200), bounds = [-2, 2], hoverPen=(0,200,0), text='y={value:0.2f}mm',
|
||||||
|
textOpts={'color': (200,0,0), 'movable': True, 'fill': 0.5})
|
||||||
|
inf3 = pg.InfiniteLine(movable=True, angle=45, text='diagonal', textOpts={'rotateAxis': [1, 0]})
|
||||||
inf1.setPos([2,2])
|
inf1.setPos([2,2])
|
||||||
inf1.setTextLocation(position=0.75)
|
#inf1.setTextLocation(position=0.75)
|
||||||
inf2.setTextLocation(shift=0.8)
|
#inf2.setTextLocation(shift=0.8)
|
||||||
p1.addItem(inf1)
|
p1.addItem(inf1)
|
||||||
p1.addItem(inf2)
|
p1.addItem(inf2)
|
||||||
p1.addItem(inf3)
|
p1.addItem(inf3)
|
||||||
|
@ -23,7 +23,7 @@ plot.setWindowTitle('pyqtgraph example: text')
|
|||||||
curve = plot.plot(x,y) ## add a single curve
|
curve = plot.plot(x,y) ## add a single curve
|
||||||
|
|
||||||
## Create text object, use HTML tags to specify color/size
|
## Create text object, use HTML tags to specify color/size
|
||||||
text = pg.TextItem(html='<div style="text-align: center"><span style="color: #FFF;">This is the</span><br><span style="color: #FF0; font-size: 16pt;">PEAK</span></div>', anchor=(-0.3,1.3), border='w', fill=(0, 0, 255, 100))
|
text = pg.TextItem(html='<div style="text-align: center"><span style="color: #FFF;">This is the</span><br><span style="color: #FF0; font-size: 16pt;">PEAK</span></div>', anchor=(-0.3,0.5), angle=45, border='w', fill=(0, 0, 255, 100))
|
||||||
plot.addItem(text)
|
plot.addItem(text)
|
||||||
text.setPos(0, y.max())
|
text.setPos(0, y.max())
|
||||||
|
|
||||||
|
@ -31,9 +31,7 @@ class InfiniteLine(GraphicsObject):
|
|||||||
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,
|
hoverPen=None, text=None, textOpts=None, name=None):
|
||||||
textPosition=[0.05, 0.5], textFormat="{:.3f}", draggableLabel=False,
|
|
||||||
suffix=None, name='InfiniteLine'):
|
|
||||||
"""
|
"""
|
||||||
=============== ==================================================================
|
=============== ==================================================================
|
||||||
**Arguments:**
|
**Arguments:**
|
||||||
@ -49,21 +47,12 @@ class InfiniteLine(GraphicsObject):
|
|||||||
Default pen is red.
|
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
|
text Text to be displayed in a label attached to the line, or
|
||||||
location in data coordinates
|
None to show no label (default is None). May optionally
|
||||||
textColor color of the label. Can be any argument fn.mkColor can understand.
|
include formatting strings to display the line value.
|
||||||
textFill A brush to use when filling within the border of the text.
|
textOpts A dict of keyword arguments to use when constructing the
|
||||||
textPosition list of float (0-1) that defines when the precise location of the
|
text label. See :class:`InfLineLabel`.
|
||||||
label. The first float governs the location of the label in the
|
name Name of the item
|
||||||
direction of the line, whereas the second one governs the shift
|
|
||||||
of the label from one side of the line to the other in the
|
|
||||||
orthogonal direction.
|
|
||||||
textFormat Any new python 3 str.format() format.
|
|
||||||
draggableLabel Bool. If True, the user can relocate the label during the dragging.
|
|
||||||
If set to True, the first entry of textPosition is no longer
|
|
||||||
useful.
|
|
||||||
suffix If not None, corresponds to the unit to show next to the label
|
|
||||||
name name of the item
|
|
||||||
=============== ==================================================================
|
=============== ==================================================================
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -79,18 +68,10 @@ class InfiniteLine(GraphicsObject):
|
|||||||
self.p = [0, 0]
|
self.p = [0, 0]
|
||||||
self.setAngle(angle)
|
self.setAngle(angle)
|
||||||
|
|
||||||
if textColor is None:
|
if text is not None:
|
||||||
textColor = (200, 200, 100)
|
textOpts = {} if textOpts is None else textOpts
|
||||||
self.textColor = textColor
|
self.textItem = InfLineLabel(self, text=text, **textOpts)
|
||||||
self.textFill = textFill
|
|
||||||
self.textPosition = textPosition
|
|
||||||
self.suffix = suffix
|
|
||||||
|
|
||||||
|
|
||||||
self.textItem = InfLineLabel(self, fill=textFill)
|
|
||||||
self.textItem.setParentItem(self)
|
self.textItem.setParentItem(self)
|
||||||
self.setDraggableLabel(draggableLabel)
|
|
||||||
self.showLabel(label)
|
|
||||||
|
|
||||||
self.anchorLeft = (1., 0.5)
|
self.anchorLeft = (1., 0.5)
|
||||||
self.anchorRight = (0., 0.5)
|
self.anchorRight = (0., 0.5)
|
||||||
@ -110,8 +91,6 @@ class InfiniteLine(GraphicsObject):
|
|||||||
self.setHoverPen(hoverPen)
|
self.setHoverPen(hoverPen)
|
||||||
self.currentPen = self.pen
|
self.currentPen = self.pen
|
||||||
|
|
||||||
self.format = textFormat
|
|
||||||
|
|
||||||
self._name = name
|
self._name = name
|
||||||
|
|
||||||
# Cache complex value for drawing speed-up (#PR267)
|
# Cache complex value for drawing speed-up (#PR267)
|
||||||
@ -308,45 +287,6 @@ class InfiniteLine(GraphicsObject):
|
|||||||
(eg, the view range has changed or the view was resized)
|
(eg, the view range has changed or the view was resized)
|
||||||
"""
|
"""
|
||||||
self._invalidateCache()
|
self._invalidateCache()
|
||||||
self.textItem.updatePosition()
|
|
||||||
|
|
||||||
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.
|
|
||||||
============== ======================================================
|
|
||||||
"""
|
|
||||||
self.textItem.setVisible(state)
|
|
||||||
|
|
||||||
def setTextLocation(self, position=0.05, shift=0.5):
|
|
||||||
"""
|
|
||||||
Set the parameters that defines the location of the label on the axis.
|
|
||||||
The position *parameter* governs the location of the label in the
|
|
||||||
direction of the line, whereas the *shift* governs the shift of the
|
|
||||||
label from one side of the line to the other in the orthogonal
|
|
||||||
direction.
|
|
||||||
|
|
||||||
============== ======================================================
|
|
||||||
**Arguments:**
|
|
||||||
position float (range of value = [0-1])
|
|
||||||
shift float (range of value = [0-1]).
|
|
||||||
============== ======================================================
|
|
||||||
"""
|
|
||||||
self.textItem.orthoPos = position
|
|
||||||
self.textItem.shiftPos = shift
|
|
||||||
self.textItem.updatePosition()
|
|
||||||
|
|
||||||
def setDraggableLabel(self, state):
|
|
||||||
"""
|
|
||||||
Set the state of the label regarding its behaviour during the dragging
|
|
||||||
of the line. If True, then the location of the label change during the
|
|
||||||
dragging of the line.
|
|
||||||
"""
|
|
||||||
self.textItem.setMovable(state)
|
|
||||||
|
|
||||||
def setName(self, name):
|
def setName(self, name):
|
||||||
self._name = name
|
self._name = name
|
||||||
@ -356,13 +296,21 @@ class InfiniteLine(GraphicsObject):
|
|||||||
|
|
||||||
|
|
||||||
class InfLineLabel(TextItem):
|
class InfLineLabel(TextItem):
|
||||||
# a text label that attaches itself to an InfiniteLine
|
"""
|
||||||
def __init__(self, line, **kwds):
|
A TextItem that attaches itself to an InfiniteLine.
|
||||||
|
|
||||||
|
This class extends TextItem with the following features:
|
||||||
|
|
||||||
|
* Automatically positions adjacent to the line at a fixed position along
|
||||||
|
the line and within the view box.
|
||||||
|
* Automatically reformats text when the line value has changed.
|
||||||
|
* Can optionally be dragged to change its location along the line.
|
||||||
|
"""
|
||||||
|
def __init__(self, line, text="", movable=False, position=0.5, **kwds):
|
||||||
self.line = line
|
self.line = line
|
||||||
self.movable = False
|
self.movable = movable
|
||||||
self.dragAxis = None # 0=x, 1=y
|
self.orthoPos = position # text will always be placed on the line at a position relative to view bounds
|
||||||
self.orthoPos = 0.5 # text will always be placed on the line at a position relative to view bounds
|
self.format = text
|
||||||
self.format = "{value}"
|
|
||||||
self.line.sigPositionChanged.connect(self.valueChanged)
|
self.line.sigPositionChanged.connect(self.valueChanged)
|
||||||
TextItem.__init__(self, **kwds)
|
TextItem.__init__(self, **kwds)
|
||||||
self.valueChanged()
|
self.valueChanged()
|
||||||
@ -412,7 +360,7 @@ class InfLineLabel(TextItem):
|
|||||||
return
|
return
|
||||||
|
|
||||||
rel = self._posToRel(ev.pos())
|
rel = self._posToRel(ev.pos())
|
||||||
self.orthoPos = self._startPosition + rel - self._cursorOffset
|
self.orthoPos = np.clip(self._startPosition + rel - self._cursorOffset, 0, 1)
|
||||||
self.updatePosition()
|
self.updatePosition()
|
||||||
if ev.isFinish():
|
if ev.isFinish():
|
||||||
self._moving = False
|
self._moving = False
|
||||||
@ -427,6 +375,10 @@ class InfLineLabel(TextItem):
|
|||||||
if not ev.isExit() and self.movable:
|
if not ev.isExit() and self.movable:
|
||||||
ev.acceptDrags(QtCore.Qt.LeftButton)
|
ev.acceptDrags(QtCore.Qt.LeftButton)
|
||||||
|
|
||||||
|
def viewTransformChanged(self):
|
||||||
|
self.updatePosition()
|
||||||
|
TextItem.viewTransformChanged(self)
|
||||||
|
|
||||||
def _posToRel(self, pos):
|
def _posToRel(self, pos):
|
||||||
# convert local position to relative position along line between view bounds
|
# convert local position to relative position along line between view bounds
|
||||||
view = self.getViewBox()
|
view = self.getViewBox()
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
|
import numpy as np
|
||||||
from ..Qt import QtCore, QtGui
|
from ..Qt import QtCore, QtGui
|
||||||
from ..Point import Point
|
from ..Point import Point
|
||||||
from .UIGraphicsItem import *
|
|
||||||
from .. import functions as fn
|
from .. import functions as fn
|
||||||
|
from .GraphicsObject import GraphicsObject
|
||||||
|
|
||||||
class TextItem(UIGraphicsItem):
|
|
||||||
|
class TextItem(GraphicsObject):
|
||||||
"""
|
"""
|
||||||
GraphicsItem displaying unscaled text (the text will always appear normal even inside a scaled ViewBox).
|
GraphicsItem displaying unscaled text (the text will always appear normal even inside a scaled ViewBox).
|
||||||
"""
|
"""
|
||||||
def __init__(self, text='', color=(200,200,200), html=None, anchor=(0,0), border=None, fill=None, angle=0):
|
def __init__(self, text='', color=(200,200,200), html=None, anchor=(0,0),
|
||||||
|
border=None, fill=None, angle=0, rotateAxis=None):
|
||||||
"""
|
"""
|
||||||
============== =================================================================================
|
============== =================================================================================
|
||||||
**Arguments:**
|
**Arguments:**
|
||||||
@ -20,16 +23,19 @@ class TextItem(UIGraphicsItem):
|
|||||||
sets the lower-right corner.
|
sets the lower-right corner.
|
||||||
*border* A pen to use when drawing the border
|
*border* A pen to use when drawing the border
|
||||||
*fill* A brush to use when filling within the border
|
*fill* A brush to use when filling within the border
|
||||||
|
*angle* Angle in degrees to rotate text. Default is 0; text will be displayed upright.
|
||||||
|
*rotateAxis* If None, then a text angle of 0 always points along the +x axis of the scene.
|
||||||
|
If a QPointF or (x,y) sequence is given, then it represents a vector direction
|
||||||
|
in the parent's coordinate system that the 0-degree line will be aligned to. This
|
||||||
|
Allows text to follow both the position and orientation of its parent while still
|
||||||
|
discarding any scale and shear factors.
|
||||||
============== =================================================================================
|
============== =================================================================================
|
||||||
"""
|
"""
|
||||||
|
|
||||||
## not working yet
|
|
||||||
#*angle* Angle in degrees to rotate text (note that the rotation assigned in this item's
|
|
||||||
#transformation will be ignored)
|
|
||||||
|
|
||||||
self.anchor = Point(anchor)
|
self.anchor = Point(anchor)
|
||||||
|
self.rotateAxis = None if rotateAxis is None else Point(rotateAxis)
|
||||||
#self.angle = 0
|
#self.angle = 0
|
||||||
UIGraphicsItem.__init__(self)
|
GraphicsObject.__init__(self)
|
||||||
self.textItem = QtGui.QGraphicsTextItem()
|
self.textItem = QtGui.QGraphicsTextItem()
|
||||||
self.textItem.setParentItem(self)
|
self.textItem.setParentItem(self)
|
||||||
self._lastTransform = None
|
self._lastTransform = None
|
||||||
@ -101,9 +107,8 @@ class TextItem(UIGraphicsItem):
|
|||||||
self.updateText()
|
self.updateText()
|
||||||
|
|
||||||
def setAngle(self, angle):
|
def setAngle(self, angle):
|
||||||
self.textItem.resetTransform()
|
self.angle = angle
|
||||||
self.textItem.rotate(angle)
|
self.updateTransform()
|
||||||
self.updateText()
|
|
||||||
|
|
||||||
def updateText(self):
|
def updateText(self):
|
||||||
# update text position to obey anchor
|
# update text position to obey anchor
|
||||||
@ -120,9 +125,6 @@ class TextItem(UIGraphicsItem):
|
|||||||
#s = self._exportOpts['resolutionScale']
|
#s = self._exportOpts['resolutionScale']
|
||||||
#self.textItem.scale(s, s)
|
#self.textItem.scale(s, s)
|
||||||
|
|
||||||
def viewRangeChanged(self):
|
|
||||||
self.updateText()
|
|
||||||
|
|
||||||
def boundingRect(self):
|
def boundingRect(self):
|
||||||
return self.textItem.mapToParent(self.textItem.boundingRect()).boundingRect()
|
return self.textItem.mapToParent(self.textItem.boundingRect()).boundingRect()
|
||||||
|
|
||||||
@ -160,7 +162,19 @@ class TextItem(UIGraphicsItem):
|
|||||||
t = pt.inverted()[0]
|
t = pt.inverted()[0]
|
||||||
# reset translation
|
# reset translation
|
||||||
t.setMatrix(t.m11(), t.m12(), t.m13(), t.m21(), t.m22(), t.m23(), 0, 0, t.m33())
|
t.setMatrix(t.m11(), t.m12(), t.m13(), t.m21(), t.m22(), t.m23(), 0, 0, t.m33())
|
||||||
|
|
||||||
|
# apply rotation
|
||||||
|
angle = -self.angle
|
||||||
|
if self.rotateAxis is not None:
|
||||||
|
d = pt.map(self.rotateAxis) - pt.map(Point(0, 0))
|
||||||
|
a = np.arctan2(d.y(), d.x()) * 180 / np.pi
|
||||||
|
angle += a
|
||||||
|
t.rotate(angle)
|
||||||
|
|
||||||
self.setTransform(t)
|
self.setTransform(t)
|
||||||
|
|
||||||
self._lastTransform = pt
|
self._lastTransform = pt
|
||||||
|
|
||||||
|
self.updateText()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user