[{"data":1,"prerenderedAt":1881},["ShallowReactive",2],{"doc:\u002Fqgis-plugin-development\u002Fcustom-map-tools-and-canvas-interaction\u002Fhighlight-feature-with-rubber-band-pyqgis":3},{"id":4,"title":5,"body":6,"description":1870,"extension":1871,"meta":1872,"navigation":258,"path":1877,"seo":1878,"stem":1879,"__hash__":1880},"docs\u002Fqgis-plugin-development\u002Fcustom-map-tools-and-canvas-interaction\u002Fhighlight-feature-with-rubber-band-pyqgis\u002Findex.md","Highlight a Feature with a Rubber Band in PyQGIS",{"type":7,"value":8,"toc":1857},"minimark",[9,13,17,20,29,162,167,189,193,199,389,426,430,433,541,560,564,567,866,882,886,989,1058,1086,1100,1104,1107,1225,1607,1628,1632,1638,1703,1708,1712,1771,1775,1784,1788,1799,1809,1815,1824,1828,1853],[10,11,5],"h1",{"id":12},"highlight-a-feature-with-a-rubber-band-in-pyqgis",[14,15,16],"p",{},"A rubber band is the canvas's scratch layer: an overlay drawn on top of everything, owned by the canvas scene, holding no data and costing nothing to redraw. It is what QGIS itself uses for the selection halo, the measure line and the digitising preview, and it is the right answer whenever you want to point at something without altering the project.",[14,18,19],{},"The mistake is treating it like a layer. A rubber band added and forgotten stays on the canvas for the rest of the session — it is not in the layer panel, so the user cannot remove it, and it survives every zoom and pan.",[14,21,22,23,28],{},"This page is a focused recipe within ",[24,25,27],"a",{"href":26},"\u002Fqgis-plugin-development\u002Fcustom-map-tools-and-canvas-interaction\u002F","Custom Map Tools and Canvas Interaction",". It covers highlighting a feature's real geometry, styling the band, handling CRS differences, a flash animation, and the cleanup that keeps the canvas honest.",[14,30,31],{},[32,33,38,42,46,53,70,79,89,95,104,108,112,117,123,127,131,135,139,142,145,148,153,156,159],"svg",{"viewBox":34,"role":35,"ariaLabel":36,"xmlns":37},"0 0 760 250","img","A rubber band drawn as an overlay above the layers, compared with a temporary memory layer which sits in the layer tree and is visible to the user","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg",[39,40,41],"title",{},"Rubber band overlay versus a temporary layer",[43,44,45],"desc",{},"A stack of map layers is drawn with a rubber band floating above them all, outside the layer tree and invisible to the layer panel. Beside it, the same highlight implemented as a memory layer appears in the layer panel where a user can toggle or delete it, and participates in rendering and export.",[47,48],"rect",{"x":49,"y":49,"width":50,"height":51,"fill":52},"0","760","250","#f6f3ea",[54,55,56],"defs",{},[57,58,65],"marker",{"id":59,"viewBox":60,"refX":61,"refY":62,"markerWidth":63,"markerHeight":63,"orient":64},"bandLayerArrow","0 0 10 10","8","5","7","auto-start-reverse",[66,67],"path",{"d":68,"fill":69},"M0 0 L10 5 L0 10 z","#2f3b35",[71,72,78],"text",{"x":73,"y":74,"style":75,"fill":76,"textAnchor":77},"380","26","text-anchor:middle;font-size:14px;font-weight:bold;font-family:sans-serif","#17211d","middle","One is drawn over the map; the other is part of it",[47,80],{"x":81,"y":82,"width":83,"height":84,"rx":85,"fill":86,"stroke":87,"style":88},"16","46","356","188","10","#fffdf7","#0f766e","stroke-width:2.5",[71,90,94],{"x":91,"y":92,"style":93,"fill":87,"textAnchor":77},"194","70","text-anchor:middle;font-size:12px;font-weight:bold;font-family:sans-serif","QgsRubberBand",[47,96],{"x":97,"y":98,"width":99,"height":100,"fill":101,"stroke":102,"style":103},"72","150","200","17","#e7e2d4","#59645f","stroke-width:1.5",[47,105],{"x":106,"y":107,"width":99,"height":100,"fill":101,"stroke":102,"style":103},"88","130",[47,109],{"x":110,"y":111,"width":99,"height":100,"fill":101,"stroke":102,"style":103},"104","110",[47,113],{"x":114,"y":115,"width":99,"height":100,"fill":87,"fillOpacity":116,"stroke":87,"style":88},"120","90",0.3,[71,118,122],{"x":119,"y":120,"style":121,"fill":76,"textAnchor":77},"220","103","text-anchor:middle;font-size:10.5px;font-weight:bold;font-family:sans-serif","rubber band",[71,124,126],{"x":91,"y":99,"style":125,"fill":69,"textAnchor":77},"text-anchor:middle;font-size:11px;font-family:sans-serif","not in the layer panel",[71,128,130],{"x":91,"y":119,"style":125,"fill":129,"textAnchor":77},"#b45309","only your code can remove it",[47,132],{"x":133,"y":82,"width":83,"height":84,"rx":85,"fill":86,"stroke":134,"style":88},"388","#2563eb",[71,136,138],{"x":137,"y":92,"style":93,"fill":134,"textAnchor":77},"566","memory layer",[47,140],{"x":141,"y":98,"width":99,"height":100,"fill":101,"stroke":102,"style":103},"444",[47,143],{"x":144,"y":107,"width":99,"height":100,"fill":101,"stroke":102,"style":103},"460",[47,146],{"x":147,"y":111,"width":99,"height":100,"fill":134,"fillOpacity":116,"stroke":134,"style":88},"476",[71,149,152],{"x":150,"y":151,"style":121,"fill":76,"textAnchor":77},"576","123","highlight layer",[47,154],{"x":155,"y":115,"width":99,"height":100,"fill":101,"stroke":102,"style":103},"492",[71,157,158],{"x":137,"y":99,"style":125,"fill":69,"textAnchor":77},"appears in the layer panel",[71,160,161],{"x":137,"y":119,"style":125,"fill":134,"textAnchor":77},"exports and prints with the map",[163,164,166],"h2",{"id":165},"prerequisites","Prerequisites",[168,169,170,178,186],"ul",{},[171,172,173,177],"li",{},[174,175,176],"strong",{},"QGIS 3.34 LTR"," (bundled Python 3.12) or newer, running as a desktop application.",[171,179,180,181,185],{},"A plugin or a Python Console session with ",[182,183,184],"code",{},"iface"," available.",[171,187,188],{},"A vector layer with features to highlight.",[163,190,192],{"id":191},"highlight-a-features-geometry","Highlight a feature's geometry",[14,194,195,198],{},[182,196,197],{},"setToGeometry()"," takes the feature's real geometry, so the highlight follows its exact outline rather than a bounding box.",[200,201,206],"pre",{"className":202,"code":203,"language":204,"meta":205,"style":205},"language-python shiki shiki-themes github-dark","from qgis.core import QgsProject, QgsWkbTypes\nfrom qgis.gui import QgsRubberBand\nfrom qgis.PyQt.QtGui import QColor\n\ncanvas = iface.mapCanvas()\nlayer = QgsProject.instance().mapLayersByName(\"parcels\")[0]\nfeature = next(layer.getFeatures())\n\nband = QgsRubberBand(canvas, QgsWkbTypes.PolygonGeometry)\nband.setColor(QColor(180, 83, 9, 70))\nband.setStrokeColor(QColor(180, 83, 9))\nband.setWidth(3)\nband.setToGeometry(feature.geometry(), layer)\n","python","",[182,207,208,227,240,253,260,272,296,310,315,326,353,371,383],{"__ignoreMap":205},[209,210,213,217,221,224],"span",{"class":211,"line":212},"line",1,[209,214,216],{"class":215},"snl16","from",[209,218,220],{"class":219},"s95oV"," qgis.core ",[209,222,223],{"class":215},"import",[209,225,226],{"class":219}," QgsProject, QgsWkbTypes\n",[209,228,230,232,235,237],{"class":211,"line":229},2,[209,231,216],{"class":215},[209,233,234],{"class":219}," qgis.gui ",[209,236,223],{"class":215},[209,238,239],{"class":219}," QgsRubberBand\n",[209,241,243,245,248,250],{"class":211,"line":242},3,[209,244,216],{"class":215},[209,246,247],{"class":219}," qgis.PyQt.QtGui ",[209,249,223],{"class":215},[209,251,252],{"class":219}," QColor\n",[209,254,256],{"class":211,"line":255},4,[209,257,259],{"emptyLinePlaceholder":258},true,"\n",[209,261,263,266,269],{"class":211,"line":262},5,[209,264,265],{"class":219},"canvas ",[209,267,268],{"class":215},"=",[209,270,271],{"class":219}," iface.mapCanvas()\n",[209,273,275,278,280,283,287,290,293],{"class":211,"line":274},6,[209,276,277],{"class":219},"layer ",[209,279,268],{"class":215},[209,281,282],{"class":219}," QgsProject.instance().mapLayersByName(",[209,284,286],{"class":285},"sU2Wk","\"parcels\"",[209,288,289],{"class":219},")[",[209,291,49],{"class":292},"sDLfK",[209,294,295],{"class":219},"]\n",[209,297,299,302,304,307],{"class":211,"line":298},7,[209,300,301],{"class":219},"feature ",[209,303,268],{"class":215},[209,305,306],{"class":292}," next",[209,308,309],{"class":219},"(layer.getFeatures())\n",[209,311,313],{"class":211,"line":312},8,[209,314,259],{"emptyLinePlaceholder":258},[209,316,318,321,323],{"class":211,"line":317},9,[209,319,320],{"class":219},"band ",[209,322,268],{"class":215},[209,324,325],{"class":219}," QgsRubberBand(canvas, QgsWkbTypes.PolygonGeometry)\n",[209,327,329,332,335,338,341,343,346,348,350],{"class":211,"line":328},10,[209,330,331],{"class":219},"band.setColor(QColor(",[209,333,334],{"class":292},"180",[209,336,337],{"class":219},", ",[209,339,340],{"class":292},"83",[209,342,337],{"class":219},[209,344,345],{"class":292},"9",[209,347,337],{"class":219},[209,349,92],{"class":292},[209,351,352],{"class":219},"))\n",[209,354,356,359,361,363,365,367,369],{"class":211,"line":355},11,[209,357,358],{"class":219},"band.setStrokeColor(QColor(",[209,360,334],{"class":292},[209,362,337],{"class":219},[209,364,340],{"class":292},[209,366,337],{"class":219},[209,368,345],{"class":292},[209,370,352],{"class":219},[209,372,374,377,380],{"class":211,"line":373},12,[209,375,376],{"class":219},"band.setWidth(",[209,378,379],{"class":292},"3",[209,381,382],{"class":219},")\n",[209,384,386],{"class":211,"line":385},13,[209,387,388],{"class":219},"band.setToGeometry(feature.geometry(), layer)\n",[14,390,391,394,395,398,399,402,403,406,407,410,411,421,422,425],{},[174,392,393],{},"Breakdown:"," The geometry type in the constructor decides how the band draws — ",[182,396,397],{},"PolygonGeometry"," fills, ",[182,400,401],{},"LineGeometry"," strokes only, ",[182,404,405],{},"PointGeometry"," draws vertex markers. The fourth argument to the fill ",[182,408,409],{},"QColor"," is alpha; 70 out of 255 gives a translucent wash that highlights without hiding the map underneath. ",[174,412,413,414,417,418,420],{},"Passing ",[182,415,416],{},"layer"," as the second argument to ",[182,419,197],{}," is what handles the CRS"," — the band lives in canvas coordinates, and that argument tells it which system the geometry is in so it can transform. Omitting it, or passing ",[182,423,424],{},"None",", assumes the geometry is already in the canvas CRS, which silently puts the highlight in the wrong place whenever the project and layer differ.",[163,427,429],{"id":428},"highlight-several-features","Highlight several features",[14,431,432],{},"A single band can hold multiple geometries, which is both faster and easier to clean up than one band per feature.",[200,434,436],{"className":202,"code":435,"language":204,"meta":205,"style":205},"from qgis.core import QgsWkbTypes\n\nband = QgsRubberBand(canvas, QgsWkbTypes.PolygonGeometry)\nband.setColor(QColor(15, 118, 110, 60))\nband.setStrokeColor(QColor(15, 118, 110))\nband.setWidth(2)\n\nfor feature in layer.getSelectedFeatures():\n    band.addGeometry(feature.geometry(), layer)\n\ncanvas.refresh()\n",[182,437,438,449,453,461,484,500,509,513,527,532,536],{"__ignoreMap":205},[209,439,440,442,444,446],{"class":211,"line":212},[209,441,216],{"class":215},[209,443,220],{"class":219},[209,445,223],{"class":215},[209,447,448],{"class":219}," QgsWkbTypes\n",[209,450,451],{"class":211,"line":229},[209,452,259],{"emptyLinePlaceholder":258},[209,454,455,457,459],{"class":211,"line":242},[209,456,320],{"class":219},[209,458,268],{"class":215},[209,460,325],{"class":219},[209,462,463,465,468,470,473,475,477,479,482],{"class":211,"line":255},[209,464,331],{"class":219},[209,466,467],{"class":292},"15",[209,469,337],{"class":219},[209,471,472],{"class":292},"118",[209,474,337],{"class":219},[209,476,111],{"class":292},[209,478,337],{"class":219},[209,480,481],{"class":292},"60",[209,483,352],{"class":219},[209,485,486,488,490,492,494,496,498],{"class":211,"line":262},[209,487,358],{"class":219},[209,489,467],{"class":292},[209,491,337],{"class":219},[209,493,472],{"class":292},[209,495,337],{"class":219},[209,497,111],{"class":292},[209,499,352],{"class":219},[209,501,502,504,507],{"class":211,"line":274},[209,503,376],{"class":219},[209,505,506],{"class":292},"2",[209,508,382],{"class":219},[209,510,511],{"class":211,"line":298},[209,512,259],{"emptyLinePlaceholder":258},[209,514,515,518,521,524],{"class":211,"line":312},[209,516,517],{"class":215},"for",[209,519,520],{"class":219}," feature ",[209,522,523],{"class":215},"in",[209,525,526],{"class":219}," layer.getSelectedFeatures():\n",[209,528,529],{"class":211,"line":317},[209,530,531],{"class":219},"    band.addGeometry(feature.geometry(), layer)\n",[209,533,534],{"class":211,"line":328},[209,535,259],{"emptyLinePlaceholder":258},[209,537,538],{"class":211,"line":355},[209,539,540],{"class":219},"canvas.refresh()\n",[14,542,543,545,546,549,550,552,553,556,557,559],{},[174,544,393],{}," ",[182,547,548],{},"addGeometry()"," appends rather than replacing, so each call adds another part to the same band — again taking the layer for the CRS transform. One band with fifty geometries repaints as a single overlay; fifty bands repaint fifty times and each must be tracked and reset individually. ",[182,551,197],{}," is effectively ",[182,554,555],{},"reset()"," followed by ",[182,558,548],{},", which is why it replaces rather than accumulates.",[163,561,563],{"id":562},"flash-rather-than-persist","Flash rather than persist",[14,565,566],{},"A permanent highlight competes with the layer's own styling. A brief flash draws the eye and then gets out of the way, which is what QGIS's own \"flash feature\" does.",[200,568,570],{"className":202,"code":569,"language":204,"meta":205,"style":205},"from qgis.PyQt.QtCore import QTimer\n\n\ndef flash(canvas, geometry, layer, times=3, interval=180):\n    band = QgsRubberBand(canvas, QgsWkbTypes.PolygonGeometry)\n    band.setColor(QColor(220, 38, 38, 90))\n    band.setStrokeColor(QColor(185, 28, 28))\n    band.setWidth(3)\n\n    state = {\"count\": 0, \"visible\": False}\n\n    def tick():\n        state[\"visible\"] = not state[\"visible\"]\n        if state[\"visible\"]:\n            band.setToGeometry(geometry, layer)\n        else:\n            band.reset(QgsWkbTypes.PolygonGeometry)\n            state[\"count\"] += 1\n            if state[\"count\"] >= times:\n                timer.stop()\n                band.reset(QgsWkbTypes.PolygonGeometry)\n\n    timer = QTimer(canvas)\n    timer.timeout.connect(tick)\n    timer.start(interval)\n    return timer\n",[182,571,572,584,588,592,618,627,649,668,677,681,712,716,727,749,762,768,777,783,799,817,823,829,834,845,851,857],{"__ignoreMap":205},[209,573,574,576,579,581],{"class":211,"line":212},[209,575,216],{"class":215},[209,577,578],{"class":219}," qgis.PyQt.QtCore ",[209,580,223],{"class":215},[209,582,583],{"class":219}," QTimer\n",[209,585,586],{"class":211,"line":229},[209,587,259],{"emptyLinePlaceholder":258},[209,589,590],{"class":211,"line":242},[209,591,259],{"emptyLinePlaceholder":258},[209,593,594,597,601,604,606,608,611,613,615],{"class":211,"line":255},[209,595,596],{"class":215},"def",[209,598,600],{"class":599},"svObZ"," flash",[209,602,603],{"class":219},"(canvas, geometry, layer, times",[209,605,268],{"class":215},[209,607,379],{"class":292},[209,609,610],{"class":219},", interval",[209,612,268],{"class":215},[209,614,334],{"class":292},[209,616,617],{"class":219},"):\n",[209,619,620,623,625],{"class":211,"line":262},[209,621,622],{"class":219},"    band ",[209,624,268],{"class":215},[209,626,325],{"class":219},[209,628,629,632,634,636,639,641,643,645,647],{"class":211,"line":274},[209,630,631],{"class":219},"    band.setColor(QColor(",[209,633,119],{"class":292},[209,635,337],{"class":219},[209,637,638],{"class":292},"38",[209,640,337],{"class":219},[209,642,638],{"class":292},[209,644,337],{"class":219},[209,646,115],{"class":292},[209,648,352],{"class":219},[209,650,651,654,657,659,662,664,666],{"class":211,"line":298},[209,652,653],{"class":219},"    band.setStrokeColor(QColor(",[209,655,656],{"class":292},"185",[209,658,337],{"class":219},[209,660,661],{"class":292},"28",[209,663,337],{"class":219},[209,665,661],{"class":292},[209,667,352],{"class":219},[209,669,670,673,675],{"class":211,"line":312},[209,671,672],{"class":219},"    band.setWidth(",[209,674,379],{"class":292},[209,676,382],{"class":219},[209,678,679],{"class":211,"line":317},[209,680,259],{"emptyLinePlaceholder":258},[209,682,683,686,688,691,694,697,699,701,704,706,709],{"class":211,"line":328},[209,684,685],{"class":219},"    state ",[209,687,268],{"class":215},[209,689,690],{"class":219}," {",[209,692,693],{"class":285},"\"count\"",[209,695,696],{"class":219},": ",[209,698,49],{"class":292},[209,700,337],{"class":219},[209,702,703],{"class":285},"\"visible\"",[209,705,696],{"class":219},[209,707,708],{"class":292},"False",[209,710,711],{"class":219},"}\n",[209,713,714],{"class":211,"line":355},[209,715,259],{"emptyLinePlaceholder":258},[209,717,718,721,724],{"class":211,"line":373},[209,719,720],{"class":215},"    def",[209,722,723],{"class":599}," tick",[209,725,726],{"class":219},"():\n",[209,728,729,732,734,737,739,742,745,747],{"class":211,"line":385},[209,730,731],{"class":219},"        state[",[209,733,703],{"class":285},[209,735,736],{"class":219},"] ",[209,738,268],{"class":215},[209,740,741],{"class":215}," not",[209,743,744],{"class":219}," state[",[209,746,703],{"class":285},[209,748,295],{"class":219},[209,750,752,755,757,759],{"class":211,"line":751},14,[209,753,754],{"class":215},"        if",[209,756,744],{"class":219},[209,758,703],{"class":285},[209,760,761],{"class":219},"]:\n",[209,763,765],{"class":211,"line":764},15,[209,766,767],{"class":219},"            band.setToGeometry(geometry, layer)\n",[209,769,771,774],{"class":211,"line":770},16,[209,772,773],{"class":215},"        else",[209,775,776],{"class":219},":\n",[209,778,780],{"class":211,"line":779},17,[209,781,782],{"class":219},"            band.reset(QgsWkbTypes.PolygonGeometry)\n",[209,784,786,789,791,793,796],{"class":211,"line":785},18,[209,787,788],{"class":219},"            state[",[209,790,693],{"class":285},[209,792,736],{"class":219},[209,794,795],{"class":215},"+=",[209,797,798],{"class":292}," 1\n",[209,800,802,805,807,809,811,814],{"class":211,"line":801},19,[209,803,804],{"class":215},"            if",[209,806,744],{"class":219},[209,808,693],{"class":285},[209,810,736],{"class":219},[209,812,813],{"class":215},">=",[209,815,816],{"class":219}," times:\n",[209,818,820],{"class":211,"line":819},20,[209,821,822],{"class":219},"                timer.stop()\n",[209,824,826],{"class":211,"line":825},21,[209,827,828],{"class":219},"                band.reset(QgsWkbTypes.PolygonGeometry)\n",[209,830,832],{"class":211,"line":831},22,[209,833,259],{"emptyLinePlaceholder":258},[209,835,837,840,842],{"class":211,"line":836},23,[209,838,839],{"class":219},"    timer ",[209,841,268],{"class":215},[209,843,844],{"class":219}," QTimer(canvas)\n",[209,846,848],{"class":211,"line":847},24,[209,849,850],{"class":219},"    timer.timeout.connect(tick)\n",[209,852,854],{"class":211,"line":853},25,[209,855,856],{"class":219},"    timer.start(interval)\n",[209,858,860,863],{"class":211,"line":859},26,[209,861,862],{"class":215},"    return",[209,864,865],{"class":219}," timer\n",[14,867,868,870,871,874,875,877,878,881],{},[174,869,393],{}," Parenting the ",[182,872,873],{},"QTimer"," to the canvas means Qt destroys it if the canvas goes away, which prevents a timer firing into a dead object. Returning the timer lets the caller stop it early — and keeps a reference alive, without which the timer would be collected and never fire. The final ",[182,876,555],{}," inside the stop branch is what guarantees nothing is left behind even if the count arithmetic changes later. QGIS also offers ",[182,879,880],{},"canvas.flashGeometries()"," for exactly this, which is worth preferring when the default styling is acceptable.",[163,883,885],{"id":884},"style-and-clean-up","Style, and clean up",[14,887,888],{},[32,889,891,894,897,899,902,925,941,973],{"viewBox":34,"role":35,"ariaLabel":890,"xmlns":37},"Four rubber band styles for different purposes: a translucent fill for area selection, a thick stroke for a route, vertex markers for editing, and a dashed outline for a pending change",[39,892,893],{},"Four rubber band styles and what each is for",[43,895,896],{},"Four panels. A translucent teal fill with a solid outline marks a selected area. A thick amber stroke marks a route or a measured line. Blue vertex markers on a thin line mark an editing session. A dashed grey outline marks a pending or proposed change that has not been applied.",[47,898],{"x":49,"y":49,"width":50,"height":51,"fill":52},[71,900,901],{"x":73,"y":74,"style":75,"fill":76,"textAnchor":77},"Style carries meaning — keep it consistent across your plugin",[903,904,905,911,916,921],"g",{},[47,906],{"x":907,"y":82,"width":908,"height":909,"rx":85,"fill":86,"stroke":87,"style":910},"12","176","164","stroke-width:2",[71,912,915],{"x":913,"y":92,"style":914,"fill":87,"textAnchor":77},"100","text-anchor:middle;font-size:11.5px;font-weight:bold;font-family:sans-serif","area selected",[66,917],{"d":918,"fill":87,"fillOpacity":919,"stroke":87,"style":920},"M40 176 L40 100 L120 92 L156 138 L112 182 Z",0.28,"stroke-width:3;stroke-linejoin:round",[71,922,924],{"x":913,"y":99,"style":923,"fill":69,"textAnchor":77},"text-anchor:middle;font-size:10.5px;font-family:sans-serif","translucent fill",[903,926,927,929,933,938],{},[47,928],{"x":99,"y":82,"width":908,"height":909,"rx":85,"fill":86,"stroke":129,"style":910},[71,930,932],{"x":931,"y":92,"style":914,"fill":129,"textAnchor":77},"288","route or measure",[66,934],{"d":935,"fill":936,"stroke":129,"style":937},"M226 178 L262 118 L312 152 L350 96","none","stroke-width:5;stroke-linecap:round;stroke-linejoin:round",[71,939,940],{"x":931,"y":99,"style":923,"fill":69,"textAnchor":77},"thick stroke, no fill",[903,942,943,945,948,952,970],{},[47,944],{"x":133,"y":82,"width":908,"height":909,"rx":85,"fill":86,"stroke":134,"style":910},[71,946,947],{"x":147,"y":92,"style":914,"fill":134,"textAnchor":77},"editing vertices",[66,949],{"d":950,"fill":936,"stroke":134,"style":951},"M414 178 L450 118 L500 152 L538 96","stroke-width:1.8",[903,953,954,958,962,966],{"fill":134},[47,955],{"x":956,"y":957,"width":85,"height":85},"409","173",[47,959],{"x":960,"y":961,"width":85,"height":85},"445","113",[47,963],{"x":964,"y":965,"width":85,"height":85},"495","147",[47,967],{"x":968,"y":969,"width":85,"height":85},"533","91",[71,971,972],{"x":147,"y":99,"style":923,"fill":69,"textAnchor":77},"vertex markers on",[903,974,975,978,982,986],{},[47,976],{"x":150,"y":82,"width":977,"height":909,"rx":85,"fill":86,"stroke":102,"style":910},"172",[71,979,981],{"x":980,"y":92,"style":914,"fill":102,"textAnchor":77},"662","pending change",[66,983],{"d":984,"fill":936,"stroke":102,"style":985},"M602 176 L602 100 L682 92 L718 138 L674 182 Z","stroke-width:2.5;stroke-dasharray:7 5;stroke-linejoin:round",[71,987,988],{"x":980,"y":99,"style":923,"fill":69,"textAnchor":77},"dashed, unfilled",[200,990,992],{"className":202,"code":991,"language":204,"meta":205,"style":205},"from qgis.core import QgsWkbTypes\nfrom qgis.PyQt.QtCore import Qt\n\nband.setLineStyle(Qt.DashLine)\nband.setIconSize(9)\nband.setIcon(QgsRubberBand.ICON_BOX)\n\n# ... later, always:\nband.reset(QgsWkbTypes.PolygonGeometry)\n",[182,993,994,1004,1015,1019,1024,1033,1043,1047,1053],{"__ignoreMap":205},[209,995,996,998,1000,1002],{"class":211,"line":212},[209,997,216],{"class":215},[209,999,220],{"class":219},[209,1001,223],{"class":215},[209,1003,448],{"class":219},[209,1005,1006,1008,1010,1012],{"class":211,"line":229},[209,1007,216],{"class":215},[209,1009,578],{"class":219},[209,1011,223],{"class":215},[209,1013,1014],{"class":219}," Qt\n",[209,1016,1017],{"class":211,"line":242},[209,1018,259],{"emptyLinePlaceholder":258},[209,1020,1021],{"class":211,"line":255},[209,1022,1023],{"class":219},"band.setLineStyle(Qt.DashLine)\n",[209,1025,1026,1029,1031],{"class":211,"line":262},[209,1027,1028],{"class":219},"band.setIconSize(",[209,1030,345],{"class":292},[209,1032,382],{"class":219},[209,1034,1035,1038,1041],{"class":211,"line":274},[209,1036,1037],{"class":219},"band.setIcon(QgsRubberBand.",[209,1039,1040],{"class":292},"ICON_BOX",[209,1042,382],{"class":219},[209,1044,1045],{"class":211,"line":298},[209,1046,259],{"emptyLinePlaceholder":258},[209,1048,1049],{"class":211,"line":312},[209,1050,1052],{"class":1051},"sjoCn","# ... later, always:\n",[209,1054,1055],{"class":211,"line":317},[209,1056,1057],{"class":219},"band.reset(QgsWkbTypes.PolygonGeometry)\n",[14,1059,1060,545,1062,1065,1066,1069,1070,1073,1074,1077,1078,1080,1081,1085],{},[174,1061,393],{},[182,1063,1064],{},"setLineStyle()"," takes a Qt pen style — ",[182,1067,1068],{},"Qt.DashLine"," reads as provisional, which is the right signal for a proposed change the user has not confirmed. ",[182,1071,1072],{},"setIcon()"," and ",[182,1075,1076],{},"setIconSize()"," control the vertex markers, which only appear on point and line bands. ",[182,1079,555],{}," clears the band's geometry ",[1082,1083,1084],"em",{},"and"," takes the geometry type, because a band can be reused for a different type after clearing.",[14,1087,1088,1089,1091,1092,1095,1096,1099],{},"That final ",[182,1090,555],{}," is not optional. Call it in the tool's ",[182,1093,1094],{},"deactivate()",", in the plugin's ",[182,1097,1098],{},"unload()",", and anywhere the highlight logically ends — a band whose owning object is garbage collected is still drawn by the canvas scene, so there is no automatic cleanup to fall back on.",[163,1101,1103],{"id":1102},"keep-one-band-per-purpose","Keep one band per purpose",[14,1105,1106],{},"A plugin that highlights several different things — a hovered feature, a confirmed selection, a validation error — needs to be able to clear one without disturbing the others. Holding a named band per role makes that trivial and prevents the accumulation of orphaned overlays.",[14,1108,1109,1200,1203,1207,1211,1215],{},[32,1110,1113,1116,1119,1122,1129,1132,1135,1139,1146,1151,1153,1156,1160,1163,1167,1171,1175,1178,1184,1187,1192,1196],{"viewBox":1111,"role":35,"ariaLabel":1112,"xmlns":37},"0 0 760 240","Three named rubber bands held on the plugin, one per role, each cleared independently without affecting the others",[39,1114,1115],{},"One band per role, cleared independently",[43,1117,1118],{},"A plugin holds three rubber bands in a dictionary keyed by role: hover, selected and error. Clearing the hover band leaves the selected and error highlights untouched. A single shared band would force all three to be cleared together, and untracked bands could not be cleared at all.",[47,1120],{"x":49,"y":49,"width":50,"height":1121,"fill":52},"240",[54,1123,1124],{},[57,1125,1127],{"id":1126,"viewBox":60,"refX":61,"refY":62,"markerWidth":63,"markerHeight":63,"orient":64},"bandRoleArrow",[66,1128],{"d":68,"fill":87},[71,1130,1131],{"x":73,"y":74,"style":75,"fill":76,"textAnchor":77},"self.bands = {\"hover\": …, \"selected\": …, \"error\": …}",[47,1133],{"x":81,"y":1134,"width":908,"height":909,"rx":85,"fill":86,"stroke":102,"style":88},"52",[71,1136,1138],{"x":110,"y":1137,"style":93,"fill":76,"textAnchor":77},"76","the plugin",[47,1140],{"x":1141,"y":1142,"width":1143,"height":1144,"rx":62,"fill":134,"fillOpacity":1145,"stroke":134,"style":951},"36","92","136","30",0.2,[71,1147,1150],{"x":110,"y":1148,"style":1149,"fill":69,"textAnchor":77},"112","text-anchor:middle;font-size:11px;font-family:monospace","hover",[47,1152],{"x":1141,"y":107,"width":1143,"height":1144,"rx":62,"fill":87,"fillOpacity":1145,"stroke":87,"style":951},[71,1154,1155],{"x":110,"y":98,"style":1149,"fill":69,"textAnchor":77},"selected",[47,1157],{"x":1141,"y":1158,"width":1143,"height":1144,"rx":62,"fill":1159,"fillOpacity":1145,"stroke":1159,"style":951},"168","#b91c1c",[71,1161,1162],{"x":110,"y":84,"style":1149,"fill":69,"textAnchor":77},"error",[47,1164],{"x":1165,"y":1134,"width":1166,"height":909,"rx":85,"fill":86,"stroke":87,"style":88},"256","228",[71,1168,1170],{"x":1169,"y":1137,"style":93,"fill":87,"textAnchor":77},"370","the canvas",[66,1172],{"d":1173,"fill":134,"fillOpacity":1174,"stroke":134,"style":910},"M282 190 L282 108 L344 100 L376 140 L338 194 Z",0.22,[66,1176],{"d":1177,"fill":87,"fillOpacity":919,"stroke":87,"style":88},"M356 186 L352 116 L420 108 L426 182 Z",[1179,1180],"circle",{"cx":1181,"cy":1182,"r":1183,"fill":936,"stroke":1159,"style":88},"450","128","14",[66,1185],{"d":1186,"stroke":1159,"style":88},"M443 121 L457 135 M457 121 L443 135",[47,1188],{"x":1189,"y":1134,"width":1190,"height":909,"rx":85,"fill":86,"stroke":1191,"style":88},"548","196","#15803d",[71,1193,1195],{"x":1194,"y":1137,"style":93,"fill":1191,"textAnchor":77},"646","clear one role",[71,1197,1199],{"x":1194,"y":1198,"style":1149,"fill":69,"textAnchor":77},"106","bands",[209,1201,1202],{},"\"hover\"",[71,1204,1206],{"x":1194,"y":1205,"style":1149,"fill":69,"text-anchor":77},"124",".reset(...)",[71,1208,1210],{"x":1194,"y":1209,"style":125,"fill":69,"text-anchor":77},"154","selected and error",[71,1212,1214],{"x":1194,"y":977,"style":1213,"fill":1191,"text-anchor":77},"text-anchor:middle;font-size:11px;font-weight:bold;font-family:sans-serif","stay on screen",[211,1216,1221],{"x1":1217,"y1":1218,"x2":1219,"y2":1218,"stroke":87,"style":1220},"192","134","252","stroke-width:2.5;marker-end:url(#bandRoleArrow)",[211,1222],{"x1":1223,"y1":1218,"x2":1224,"y2":1218,"stroke":1191,"style":1220},"484","544",[200,1226,1228],{"className":202,"code":1227,"language":204,"meta":205,"style":205},"from qgis.core import QgsWkbTypes\nfrom qgis.gui import QgsRubberBand\nfrom qgis.PyQt.QtGui import QColor\n\nROLES = {\n    \"hover\": (QColor(37, 99, 235, 50), QColor(37, 99, 235), 2),\n    \"selected\": (QColor(15, 118, 110, 70), QColor(15, 118, 110), 3),\n    \"error\": (QColor(185, 28, 28, 60), QColor(185, 28, 28), 3),\n}\n\n\nclass Highlighter:\n    def __init__(self, canvas):\n        self.canvas = canvas\n        self.bands = {}\n        for role, (fill, stroke, width) in ROLES.items():\n            band = QgsRubberBand(canvas, QgsWkbTypes.PolygonGeometry)\n            band.setColor(fill)\n            band.setStrokeColor(stroke)\n            band.setWidth(width)\n            self.bands[role] = band\n\n    def show(self, role, geometry, layer):\n        self.bands[role].setToGeometry(geometry, layer)\n\n    def clear(self, role=None):\n        targets = self.bands.values() if role is None else [self.bands[role]]\n        for band in targets:\n            band.reset(QgsWkbTypes.PolygonGeometry)\n",[182,1229,1230,1240,1250,1260,1264,1275,1322,1361,1400,1404,1408,1412,1422,1432,1445,1457,1473,1482,1487,1492,1497,1510,1514,1524,1531,1535,1551,1589,1602],{"__ignoreMap":205},[209,1231,1232,1234,1236,1238],{"class":211,"line":212},[209,1233,216],{"class":215},[209,1235,220],{"class":219},[209,1237,223],{"class":215},[209,1239,448],{"class":219},[209,1241,1242,1244,1246,1248],{"class":211,"line":229},[209,1243,216],{"class":215},[209,1245,234],{"class":219},[209,1247,223],{"class":215},[209,1249,239],{"class":219},[209,1251,1252,1254,1256,1258],{"class":211,"line":242},[209,1253,216],{"class":215},[209,1255,247],{"class":219},[209,1257,223],{"class":215},[209,1259,252],{"class":219},[209,1261,1262],{"class":211,"line":255},[209,1263,259],{"emptyLinePlaceholder":258},[209,1265,1266,1269,1272],{"class":211,"line":262},[209,1267,1268],{"class":292},"ROLES",[209,1270,1271],{"class":215}," =",[209,1273,1274],{"class":219}," {\n",[209,1276,1277,1280,1283,1286,1288,1291,1293,1296,1298,1301,1304,1306,1308,1310,1312,1314,1317,1319],{"class":211,"line":274},[209,1278,1279],{"class":285},"    \"hover\"",[209,1281,1282],{"class":219},": (QColor(",[209,1284,1285],{"class":292},"37",[209,1287,337],{"class":219},[209,1289,1290],{"class":292},"99",[209,1292,337],{"class":219},[209,1294,1295],{"class":292},"235",[209,1297,337],{"class":219},[209,1299,1300],{"class":292},"50",[209,1302,1303],{"class":219},"), QColor(",[209,1305,1285],{"class":292},[209,1307,337],{"class":219},[209,1309,1290],{"class":292},[209,1311,337],{"class":219},[209,1313,1295],{"class":292},[209,1315,1316],{"class":219},"), ",[209,1318,506],{"class":292},[209,1320,1321],{"class":219},"),\n",[209,1323,1324,1327,1329,1331,1333,1335,1337,1339,1341,1343,1345,1347,1349,1351,1353,1355,1357,1359],{"class":211,"line":298},[209,1325,1326],{"class":285},"    \"selected\"",[209,1328,1282],{"class":219},[209,1330,467],{"class":292},[209,1332,337],{"class":219},[209,1334,472],{"class":292},[209,1336,337],{"class":219},[209,1338,111],{"class":292},[209,1340,337],{"class":219},[209,1342,92],{"class":292},[209,1344,1303],{"class":219},[209,1346,467],{"class":292},[209,1348,337],{"class":219},[209,1350,472],{"class":292},[209,1352,337],{"class":219},[209,1354,111],{"class":292},[209,1356,1316],{"class":219},[209,1358,379],{"class":292},[209,1360,1321],{"class":219},[209,1362,1363,1366,1368,1370,1372,1374,1376,1378,1380,1382,1384,1386,1388,1390,1392,1394,1396,1398],{"class":211,"line":312},[209,1364,1365],{"class":285},"    \"error\"",[209,1367,1282],{"class":219},[209,1369,656],{"class":292},[209,1371,337],{"class":219},[209,1373,661],{"class":292},[209,1375,337],{"class":219},[209,1377,661],{"class":292},[209,1379,337],{"class":219},[209,1381,481],{"class":292},[209,1383,1303],{"class":219},[209,1385,656],{"class":292},[209,1387,337],{"class":219},[209,1389,661],{"class":292},[209,1391,337],{"class":219},[209,1393,661],{"class":292},[209,1395,1316],{"class":219},[209,1397,379],{"class":292},[209,1399,1321],{"class":219},[209,1401,1402],{"class":211,"line":317},[209,1403,711],{"class":219},[209,1405,1406],{"class":211,"line":328},[209,1407,259],{"emptyLinePlaceholder":258},[209,1409,1410],{"class":211,"line":355},[209,1411,259],{"emptyLinePlaceholder":258},[209,1413,1414,1417,1420],{"class":211,"line":373},[209,1415,1416],{"class":215},"class",[209,1418,1419],{"class":599}," Highlighter",[209,1421,776],{"class":219},[209,1423,1424,1426,1429],{"class":211,"line":385},[209,1425,720],{"class":215},[209,1427,1428],{"class":292}," __init__",[209,1430,1431],{"class":219},"(self, canvas):\n",[209,1433,1434,1437,1440,1442],{"class":211,"line":751},[209,1435,1436],{"class":292},"        self",[209,1438,1439],{"class":219},".canvas ",[209,1441,268],{"class":215},[209,1443,1444],{"class":219}," canvas\n",[209,1446,1447,1449,1452,1454],{"class":211,"line":764},[209,1448,1436],{"class":292},[209,1450,1451],{"class":219},".bands ",[209,1453,268],{"class":215},[209,1455,1456],{"class":219}," {}\n",[209,1458,1459,1462,1465,1467,1470],{"class":211,"line":770},[209,1460,1461],{"class":215},"        for",[209,1463,1464],{"class":219}," role, (fill, stroke, width) ",[209,1466,523],{"class":215},[209,1468,1469],{"class":292}," ROLES",[209,1471,1472],{"class":219},".items():\n",[209,1474,1475,1478,1480],{"class":211,"line":779},[209,1476,1477],{"class":219},"            band ",[209,1479,268],{"class":215},[209,1481,325],{"class":219},[209,1483,1484],{"class":211,"line":785},[209,1485,1486],{"class":219},"            band.setColor(fill)\n",[209,1488,1489],{"class":211,"line":801},[209,1490,1491],{"class":219},"            band.setStrokeColor(stroke)\n",[209,1493,1494],{"class":211,"line":819},[209,1495,1496],{"class":219},"            band.setWidth(width)\n",[209,1498,1499,1502,1505,1507],{"class":211,"line":825},[209,1500,1501],{"class":292},"            self",[209,1503,1504],{"class":219},".bands[role] ",[209,1506,268],{"class":215},[209,1508,1509],{"class":219}," band\n",[209,1511,1512],{"class":211,"line":831},[209,1513,259],{"emptyLinePlaceholder":258},[209,1515,1516,1518,1521],{"class":211,"line":836},[209,1517,720],{"class":215},[209,1519,1520],{"class":599}," show",[209,1522,1523],{"class":219},"(self, role, geometry, layer):\n",[209,1525,1526,1528],{"class":211,"line":847},[209,1527,1436],{"class":292},[209,1529,1530],{"class":219},".bands[role].setToGeometry(geometry, layer)\n",[209,1532,1533],{"class":211,"line":853},[209,1534,259],{"emptyLinePlaceholder":258},[209,1536,1537,1539,1542,1545,1547,1549],{"class":211,"line":859},[209,1538,720],{"class":215},[209,1540,1541],{"class":599}," clear",[209,1543,1544],{"class":219},"(self, role",[209,1546,268],{"class":215},[209,1548,424],{"class":292},[209,1550,617],{"class":219},[209,1552,1554,1557,1559,1562,1565,1568,1571,1574,1577,1580,1583,1586],{"class":211,"line":1553},27,[209,1555,1556],{"class":219},"        targets ",[209,1558,268],{"class":215},[209,1560,1561],{"class":292}," self",[209,1563,1564],{"class":219},".bands.values() ",[209,1566,1567],{"class":215},"if",[209,1569,1570],{"class":219}," role ",[209,1572,1573],{"class":215},"is",[209,1575,1576],{"class":292}," None",[209,1578,1579],{"class":215}," else",[209,1581,1582],{"class":219}," [",[209,1584,1585],{"class":292},"self",[209,1587,1588],{"class":219},".bands[role]]\n",[209,1590,1592,1594,1597,1599],{"class":211,"line":1591},28,[209,1593,1461],{"class":215},[209,1595,1596],{"class":219}," band ",[209,1598,523],{"class":215},[209,1600,1601],{"class":219}," targets:\n",[209,1603,1605],{"class":211,"line":1604},29,[209,1606,782],{"class":219},[14,1608,1609,1611,1612,1614,1615,1618,1619,1073,1621,1623,1624,1627],{},[174,1610,393],{}," Creating every band up front and reusing them avoids the churn of constructing and destroying overlays as the cursor moves. Declaring the colours in one ",[182,1613,1268],{}," table keeps the visual language consistent, which matters because users learn what each colour means. ",[182,1616,1617],{},"clear()"," with no argument clearing everything is what ",[182,1620,1098],{},[182,1622,1094],{}," call, while ",[182,1625,1626],{},"clear(\"hover\")"," handles the common case of the cursor leaving a feature — a single shared band could not do both.",[163,1629,1631],{"id":1630},"qgis-version-compatibility","QGIS version compatibility",[14,1633,1634,1635,1637],{},"The examples target ",[174,1636,176],{}," (Python 3.12).",[1639,1640,1641,1657],"table",{},[1642,1643,1644],"thead",{},[1645,1646,1647,1651,1654],"tr",{},[1648,1649,1650],"th",{},"QGIS version",[1648,1652,1653],{},"Python",[1648,1655,1656],{},"Notes",[1658,1659,1660,1675,1686],"tbody",{},[1645,1661,1662,1666,1669],{},[1663,1664,1665],"td",{},"3.28 LTR",[1663,1667,1668],{},"3.9",[1663,1670,1671,1672,1674],{},"Identical API. ",[182,1673,880],{}," available since 3.6.",[1645,1676,1677,1680,1683],{},[1663,1678,1679],{},"3.34 LTR",[1663,1681,1682],{},"3.12",[1663,1684,1685],{},"Baseline for this page.",[1645,1687,1688,1691,1693],{},[1663,1689,1690],{},"3.40 \u002F 3.44",[1663,1692,1682],{},[1663,1694,1695,1698,1699,1702],{},[182,1696,1697],{},"Qgis.GeometryType"," replaces ",[182,1700,1701],{},"QgsWkbTypes.PolygonGeometry","; the old spelling still resolves.",[14,1704,1705,1707],{},[182,1706,94],{}," and its styling methods are unchanged across the 3.x line.",[163,1709,1711],{"id":1710},"troubleshooting","Troubleshooting",[168,1713,1714,1726,1734,1740,1749,1762],{},[171,1715,1716,1719,1720,1722,1723,1725],{},[174,1717,1718],{},"The highlight is in the wrong place."," The layer was not passed to ",[182,1721,197],{}," or ",[182,1724,548],{},", so no CRS transform was applied.",[171,1727,1728,545,1731,1733],{},[174,1729,1730],{},"The band never disappears.",[182,1732,555],{}," was not called. Nothing removes a rubber band automatically, not even collecting the Python object.",[171,1735,1736,1739],{},[174,1737,1738],{},"The highlight hides the feature."," The fill alpha is too high. Values around 60–90 out of 255 read as a highlight rather than a mask.",[171,1741,1742,1745,1746,1748],{},[174,1743,1744],{},"Nothing is drawn."," The geometry is null or empty, or the band's geometry type does not match — a polygon added to a ",[182,1747,401],{}," band draws only its outline.",[171,1750,1751,1754,1755,1758,1759,1761],{},[174,1752,1753],{},"Dragging is jerky."," Every ",[182,1756,1757],{},"addPoint()"," is repainting. Pass ",[182,1760,708],{}," for the update argument on intermediate points and repaint once at the end.",[171,1763,1764,1767,1768,1770],{},[174,1765,1766],{},"The flash never fires."," The ",[182,1769,873],{}," was created as a local and collected. Keep a reference, and parent it to the canvas.",[163,1772,1774],{"id":1773},"conclusion","Conclusion",[14,1776,1777,1778,1780,1781,1783],{},"A rubber band is an overlay, not a layer: it costs nothing, it draws above everything, and it is entirely your responsibility to remove. Pass the layer to ",[182,1779,197],{}," so the CRS is handled, prefer one band holding many geometries over many bands, and call ",[182,1782,555],{}," in every path that ends the highlight.",[163,1785,1787],{"id":1786},"frequently-asked-questions","Frequently Asked Questions",[14,1789,1790,1793,1794,1722,1796,1798],{},[174,1791,1792],{},"Why is my rubber band in the wrong place on the map?","\nThe geometry's CRS was not declared. Pass the layer as the second argument to ",[182,1795,197],{},[182,1797,548],{}," so the band transforms the coordinates into the canvas CRS.",[14,1800,1801,1804,1805,1808],{},[174,1802,1803],{},"How do I remove a rubber band?","\nCall ",[182,1806,1807],{},"band.reset(geometry_type)",". Nothing removes it automatically — the canvas scene owns the drawing, so even letting the Python object go out of scope leaves the highlight visible.",[14,1810,1811,1814],{},[174,1812,1813],{},"Should I use a rubber band or a memory layer?","\nA rubber band for transient feedback that the user should not manage, and a memory layer when the highlight needs to appear in the layer panel, be toggled, or be included in an export.",[14,1816,1817,1820,1821,1823],{},[174,1818,1819],{},"How do I highlight several features at once?","\nCreate one band and call ",[182,1822,548],{}," for each feature. One band with many geometries repaints once; many bands repaint many times and each needs its own cleanup.",[163,1825,1827],{"id":1826},"related","Related",[168,1829,1830,1835,1841,1847],{},[171,1831,1832,1834],{},[24,1833,27],{"href":26}," — the guide this recipe belongs to",[171,1836,1837],{},[24,1838,1840],{"href":1839},"\u002Fqgis-plugin-development\u002Fcustom-map-tools-and-canvas-interaction\u002Fidentify-feature-under-cursor-pyqgis\u002F","Identify the Feature Under the Cursor in PyQGIS",[171,1842,1843],{},[24,1844,1846],{"href":1845},"\u002Fqgis-plugin-development\u002Fcustom-map-tools-and-canvas-interaction\u002Fcreate-custom-map-tool-pyqgis\u002F","Create a Custom Map Tool in PyQGIS",[171,1848,1849],{},[24,1850,1852],{"href":1851},"\u002Fqgis-plugin-development\u002Fqt-designer-for-gis-interfaces\u002Fadd-custom-dock-widget-pyqgis\u002F","Add a Custom Dock Widget with PyQGIS",[1854,1855,1856],"style",{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sjoCn, html code.shiki .sjoCn{--shiki-default:#9AA79F}",{"title":205,"searchDepth":229,"depth":229,"links":1858},[1859,1860,1861,1862,1863,1864,1865,1866,1867,1868,1869],{"id":165,"depth":229,"text":166},{"id":191,"depth":229,"text":192},{"id":428,"depth":229,"text":429},{"id":562,"depth":229,"text":563},{"id":884,"depth":229,"text":885},{"id":1102,"depth":229,"text":1103},{"id":1630,"depth":229,"text":1631},{"id":1710,"depth":229,"text":1711},{"id":1773,"depth":229,"text":1774},{"id":1786,"depth":229,"text":1787},{"id":1826,"depth":229,"text":1827},"Draw temporary highlights on the QGIS canvas with QgsRubberBand. Follow a feature's geometry, style the band, animate a flash, and clean it up on deactivate.","md",{"slug":1873,"type":1874,"breadcrumb":1875,"datePublished":1876,"dateModified":1876},"highlight-feature-with-rubber-band-pyqgis","article","Rubber Band Highlight","2026-08-01","\u002Fqgis-plugin-development\u002Fcustom-map-tools-and-canvas-interaction\u002Fhighlight-feature-with-rubber-band-pyqgis",{"title":5,"description":1870},"qgis-plugin-development\u002Fcustom-map-tools-and-canvas-interaction\u002Fhighlight-feature-with-rubber-band-pyqgis\u002Findex","YR_cKOBuFv43IwNRPVwY9Rpor_A4T5hFdNKO0hPcqMI",1785585990474]