diff --git a/examples/__main__.py b/examples/__main__.py index 02c27b76..628b93fd 100644 --- a/examples/__main__.py +++ b/examples/__main__.py @@ -17,6 +17,7 @@ examples = OrderedDict([ ('Region-of-Interest', 'ROItypes.py'), ('GraphicsLayout', 'GraphicsLayout.py'), ('Scatter Plot', 'ScatterPlot.py'), + ('Text Item', 'text.py'), ('ViewBox', 'ViewBox.py'), ('Arrow', 'Arrow.py'), ])), diff --git a/examples/text.py b/examples/text.py index da2025fd..202fb572 100644 --- a/examples/text.py +++ b/examples/text.py @@ -9,15 +9,44 @@ from pyqtgraph.Qt import QtCore, QtGui import numpy as np -x = np.linspace(-100, 100, 1000) +x = np.linspace(-20, 20, 1000) y = np.sin(x) / x -plot = pg.plot(x, y) +plot = pg.plot() ## create an empty plot widget +plot.setYRange(-1, 2) +curve = plot.plot(x,y) ## add a single curve -## Create text object, use HTML tags to specify color (default is black; won't be visible) -text = pg.TextItem(html='
This is the
PEAK
') +## Create text object, use HTML tags to specify color/size +text = pg.TextItem(html='
This is the
PEAK
', anchor=(-0.3,1.3), border='w', fill=(0, 0, 255, 100)) plot.addItem(text) text.setPos(0, y.max()) +## Draw an arrowhead next to the text box +arrow = pg.ArrowItem(pos=(0, y.max()), angle=-45) +plot.addItem(arrow) + + +## Set up an animated arrow and text that track the curve +curvePoint = pg.CurvePoint(curve) +plot.addItem(curvePoint) +text2 = pg.TextItem("test", anchor=(0.5, -1.0)) +text2.setParentItem(curvePoint) +arrow2 = pg.ArrowItem(angle=90) +arrow2.setParentItem(curvePoint) + +## update position every 10ms +index = 0 +def update(): + global curvePoint, index + index = (index + 1) % len(x) + curvePoint.setPos(float(index)/(len(x)-1)) + #text2.viewRangeChanged() + text2.setText('[%0.1f, %0.1f]' % (x[index], y[index])) + +timer = QtCore.QTimer() +timer.timeout.connect(update) +timer.start(10) + + ## Start Qt event loop unless running in interactive mode or using pyside. import sys diff --git a/graphicsItems/CurvePoint.py b/graphicsItems/CurvePoint.py index a1ec5ae4..8fae5e7f 100644 --- a/graphicsItems/CurvePoint.py +++ b/graphicsItems/CurvePoint.py @@ -14,12 +14,15 @@ class CurvePoint(GraphicsObject): Note: This class does not display anything; see CurveArrow for an applied example """ - def __init__(self, curve, index=0, pos=None): + 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""" + 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) @@ -76,7 +79,8 @@ class CurvePoint(GraphicsObject): p2 = self.parentItem().mapToScene(QtCore.QPointF(x[i2], y[i2])) ang = np.arctan2(p2.y()-p1.y(), p2.x()-p1.x()) ## returns radians self.resetTransform() - self.rotate(180+ ang * 180 / np.pi) ## takes degrees + if self._rotate: + self.rotate(180+ ang * 180 / np.pi) ## takes degrees QtGui.QGraphicsItem.setPos(self, *newPos) return True diff --git a/graphicsItems/TextItem.py b/graphicsItems/TextItem.py new file mode 100644 index 00000000..734de9c3 --- /dev/null +++ b/graphicsItems/TextItem.py @@ -0,0 +1,120 @@ +from pyqtgraph.Qt import QtCore, QtGui +import pyqtgraph as pg +from UIGraphicsItem import * + +class TextItem(UIGraphicsItem): + """ + 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): + """ + Arguments: + *text* The text to display + *color* The color of the text (any format accepted by pg.mkColor) + *html* If specified, this overrides both *text* and *color* + *anchor* A QPointF or (x,y) sequence indicating what region of the text box will + be anchored to the item's position. A value of (0,0) sets the upper-left corner + of the text box to be at the position specified by setPos(), while a value of (1,1) + sets the lower-right corner. + *border* A pen to use when drawing the border + *fill* A brush to use when filling within the border + """ + UIGraphicsItem.__init__(self) + self.textItem = QtGui.QGraphicsTextItem() + self.lastTransform = None + self._bounds = QtCore.QRectF() + if html is None: + self.setText(text, color) + else: + self.setHtml(html) + self.anchor = pg.Point(anchor) + self.fill = pg.mkBrush(fill) + self.border = pg.mkPen(border) + #self.setFlag(self.ItemIgnoresTransformations) ## This is required to keep the text unscaled inside the viewport + + def setText(self, text, color=(200,200,200)): + color = pg.mkColor(color) + self.textItem.setDefaultTextColor(color) + self.textItem.setPlainText(text) + #html = '%s' % (color, text) + #self.setHtml(html) + + def updateAnchor(self): + pass + #self.resetTransform() + #self.translate(0, 20) + + def setPlainText(self, *args): + self.textItem.setPlainText(*args) + self.updateText() + + def setHtml(self, *args): + self.textItem.setHtml(*args) + self.updateText() + + def setTextWidth(self, *args): + self.textItem.setTextWidth(*args) + self.updateText() + + def setFont(self, *args): + self.textItem.setFont(*args) + self.updateText() + + def updateText(self): + self.viewRangeChanged() + + #def getImage(self): + #if self.img is None: + #br = self.textItem.boundingRect() + #img = QtGui.QImage(int(br.width()), int(br.height()), QtGui.QImage.Format_ARGB32) + #p = QtGui.QPainter(img) + #self.textItem.paint(p, QtGui.QStyleOptionGraphicsItem(), None) + #p.end() + #self.img = img + #return self.img + + def textBoundingRect(self): + ## return the bounds of the text box in device coordinates + pos = self.mapToDevice(QtCore.QPointF(0,0)) + if pos is None: + return None + tbr = self.textItem.boundingRect() + return QtCore.QRectF(pos.x() - tbr.width()*self.anchor.x(), pos.y() - tbr.height()*self.anchor.y(), tbr.width(), tbr.height()) + + + def viewRangeChanged(self): + br = self.textBoundingRect() + if br is None: + return + self.prepareGeometryChange() + self._bounds = self.deviceTransform().inverted()[0].mapRect(br) + #print self._bounds + + def boundingRect(self): + return self._bounds + + def paint(self, p, *args): + tr = p.transform() + if self.lastTransform is not None: + if tr != self.lastTransform: + self.viewRangeChanged() + self.lastTransform = tr + + + tbr = self.textBoundingRect() + + #p.setPen(pg.mkPen('r')) + #p.drawRect(self.boundingRect()) + + p.setPen(self.border) + p.setBrush(self.fill) + + + #p.fillRect(tbr) + p.resetTransform() + p.drawRect(tbr) + + + p.translate(tbr.left(), tbr.top()) + self.textItem.paint(p, QtGui.QStyleOptionGraphicsItem(), None) + \ No newline at end of file