12

It is possible to label QgsRubberBand or QgsVertexMarker with a text annotation (QgsTextAnnotationItem).

See this MWE:

...
r_polyline = QgsRubberBand(iface.mapCanvas(), False)
r_polyline.setToGeometry(QgsGeometry.fromPolyline(points), None)
r_polyline.setWidth(2)
r_polyline.setColor(QColor(0,255,0,255))
seg = QgsFeature()
seg.setGeometry(QgsGeometry.fromPolyline(points))
length = seg.geometry().length()
self.distance_list.append(length)
symbol = QgsMarkerSymbolV2()
symbol.setSize(0)
lbltext = QTextDocument(str(round(length,2)) + ' m')
label = QgsTextAnnotationItem(iface.mapCanvas())
label.setMapPosition(seg.geometry().interpolate(length/2.0).asPoint())
label.setDocument(lbltext)
label.setFrameSize(QSizeF(lbltext.size().width(),lbltext.size().height()))
label.setFrameBorderWidth(0)
label.setFrameColor(QColor("#ffffff"))
label.setFrameBackgroundColor(QColor("#ffffff"))
label.setMarkerSymbol(symbol)
...

In the moment it looks like this:

enter image description here

Is it possible to label a rubber band (or edit the text annotations) like in this picture?

enter image description here

1 Answer 1

4

The recent addition of the annotations feature in QGIS 3.22 allows to place labels anywhere on the map canvas. Most importantly it allows placing labels at an angle which doesn't seem possible with the older QgsTextAnnotation. With a bit of effort this can be used to label a rubber band geometry.

The underlying API changes had already been implemented since QGIS 3.16, meaning the example script below can be used on version 3.16 and upwards.

# define some test data LineString
pt1 = QgsPoint(12.354931, 56.761697)
pt2 = QgsPoint(12.468290, 56.124512)
line = QgsLineString(pt1, pt2)
line_geom = QgsGeometry(line)

# calculate length of line
d = QgsDistanceArea()
d.setEllipsoid('WGS84')
length = d.measureLength(line_geom)

# calculate gradient of line to place label at an angle
gradient = QgsGeometryUtils.gradient(pt1, pt2)
# some math to convert gradient to an angle in degrees
angle = math.degrees(math.atan(gradient))

# calculate point along line with offset 
# to place label beneath line and not directly on top
# (since QGIS 3.20 use QgsGeometryUtils.perpendicularOffsetPointAlongSegment() instead)
# https://qgis.org/api/classQgsGeometryUtils.html#a84f1836941047aff664e7b913c051ae0
mX = pt1.x() + ( pt2.x() - pt1.x() ) * 0.5
mY = pt1.y() + ( pt2.y() - pt1.y() ) * 0.5
pX = pt1.x() - pt2.x()
pY = pt1.y() - pt2.y()
normalX = -pY
normalY = pX
normalLength = math.sqrt(( normalX * normalX ) + ( normalY * normalY ))
normalX /= normalLength
normalY /= normalLength
x = mX - 0.001 * normalX
y = mY - 0.001 * normalY

# add annotation label
annotation_layer = QgsProject.instance().mainAnnotationLayer()
label = QgsAnnotationPointTextItem(str(round(length,2)) + ' m', QgsPointXY(x, y))
label.setAngle(angle)
annotation_layer.addItem(label)

# display geometry as rubber band
r = QgsRubberBand(iface.mapCanvas(), QgsWkbTypes.LineGeometry)
r.setWidth(2)
r.setColor(QColor(0,255,0,255))
r.setToGeometry(line_geom, None)

iface.mapCanvas().refresh()

label

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.