[{"data":1,"prerenderedAt":1783},["ShallowReactive",2],{"doc:\u002Fpyqgis-fundamentals-environment-setup\u002Fworking-with-qgis-expressions\u002Fselect-features-by-expression-pyqgis":3},{"id":4,"title":5,"body":6,"description":1772,"extension":1773,"meta":1774,"navigation":285,"path":1779,"seo":1780,"stem":1781,"__hash__":1782},"docs\u002Fpyqgis-fundamentals-environment-setup\u002Fworking-with-qgis-expressions\u002Fselect-features-by-expression-pyqgis\u002Findex.md","Select Features by Expression in PyQGIS",{"type":7,"value":8,"toc":1758},"minimark",[9,13,27,36,214,219,245,249,252,359,372,375,455,468,472,475,574,594,598,601,738,762,766,769,915,1006,1018,1022,1029,1160,1176,1180,1183,1391,1406,1516,1520,1526,1588,1598,1602,1667,1671,1682,1686,1695,1708,1721,1727,1731,1754],[10,11,5],"h1",{"id":12},"select-features-by-expression-in-pyqgis",[14,15,16,17,21,22,26],"p",{},"Selecting features by attribute is the scripted equivalent of the \"Select by Expression\" dialog, and it is the fastest way to turn a rule into a visible, actionable set of rows on the map. ",[18,19,20],"code",{},"selectByExpression()"," does it in one line — but a selection is a piece of ",[23,24,25],"em",{},"interface state",", and treating it as a data-processing tool is where scripts go wrong: selections do not survive a project reload, they interact with what the user has clicked, and iterating them is not the same as filtering.",[14,28,29,30,35],{},"This page is a focused recipe within ",[31,32,34],"a",{"href":33},"\u002Fpyqgis-fundamentals-environment-setup\u002Fworking-with-qgis-expressions\u002F","Working with QGIS Expressions in PyQGIS",". It covers making a selection, combining it with an existing one, reading it back, deciding when a selection is the wrong tool entirely, and feeding a selection into Processing algorithms.",[14,37,38],{},[39,40,45,49,53,60,69,108,128,161,192],"svg",{"viewBox":41,"role":42,"ariaLabel":43,"xmlns":44},"0 0 760 252","img","The four selection behaviours: set replaces the current selection, add to it, subtract from it, or intersect with it, each shown as a Venn-style result","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg",[46,47,48],"title",{},"The four SelectBehavior modes",[50,51,52],"desc",{},"An existing selection of features is shown as a teal set and a new expression match as a blue set. Four panels show the result of each behaviour: SetSelection keeps only the new match, AddToSelection keeps the union, RemoveFromSelection keeps the existing set minus the new match, and IntersectSelection keeps only features in both.",[54,55],"rect",{"x":56,"y":56,"width":57,"height":58,"fill":59},"0","760","252","#f6f3ea",[61,62,68],"text",{"x":63,"y":64,"style":65,"fill":66,"textAnchor":67},"380","24","text-anchor:middle;font-size:14px;font-weight:bold;font-family:sans-serif","#17211d","middle","The second argument decides what happens to what was already selected",[70,71,72,82,88,96,102],"g",{},[54,73],{"x":74,"y":75,"width":76,"height":77,"rx":78,"fill":79,"stroke":80,"style":81},"8","42","176","150","10","#fffdf7","#0f766e","stroke-width:2.5",[61,83,87],{"x":84,"y":85,"style":86,"fill":80,"textAnchor":67},"96","66","text-anchor:middle;font-size:12px;font-weight:bold;font-family:sans-serif","SetSelection",[89,90],"circle",{"cx":91,"cy":92,"r":93,"fill":94,"stroke":80,"style":95},"76","126","38","none","stroke-width:2;stroke-dasharray:5 4",[89,97],{"cx":98,"cy":92,"r":93,"fill":99,"fillOpacity":100,"stroke":99,"style":101},"116","#2563eb",0.45,"stroke-width:2",[61,103,107],{"x":84,"y":104,"style":105,"fill":106,"textAnchor":67},"182","text-anchor:middle;font-size:11px;font-family:sans-serif","#2f3b35","replaces (default)",[70,109,110,114,118,122,125],{},[54,111],{"x":112,"y":75,"width":76,"height":77,"rx":78,"fill":79,"stroke":113,"style":81},"196","#15803d",[61,115,117],{"x":116,"y":85,"style":86,"fill":113,"textAnchor":67},"284","AddToSelection",[89,119],{"cx":120,"cy":92,"r":93,"fill":113,"fillOpacity":121,"stroke":80,"style":101},"264",0.4,[89,123],{"cx":124,"cy":92,"r":93,"fill":113,"fillOpacity":121,"stroke":99,"style":101},"304",[61,126,127],{"x":116,"y":104,"style":105,"fill":106,"textAnchor":67},"the union",[70,129,130,134,138,152,156,158],{},[54,131],{"x":132,"y":75,"width":76,"height":77,"rx":78,"fill":79,"stroke":133,"style":81},"384","#b45309",[61,135,137],{"x":136,"y":85,"style":86,"fill":133,"textAnchor":67},"472","RemoveFromSelection",[139,140,141],"defs",{},[142,143,145,148],"mask",{"id":144},"selRemoveMask",[54,146],{"x":132,"y":75,"width":76,"height":77,"fill":147},"#ffffff",[89,149],{"cx":150,"cy":92,"r":93,"fill":151},"492","#000000",[89,153],{"cx":154,"cy":92,"r":93,"fill":133,"fillOpacity":100,"stroke":80,"style":155},"452","stroke-width:2;mask:url(#selRemoveMask)",[89,157],{"cx":150,"cy":92,"r":93,"fill":94,"stroke":99,"style":95},[61,159,160],{"x":136,"y":104,"style":105,"fill":106,"textAnchor":67},"existing minus new",[70,162,163,166,170,180,182,187,189],{},[54,164],{"x":165,"y":75,"width":76,"height":77,"rx":78,"fill":79,"stroke":99,"style":81},"572",[61,167,169],{"x":168,"y":85,"style":86,"fill":99,"textAnchor":67},"660","IntersectSelection",[139,171,172],{},[142,173,175,177],{"id":174},"selIntersectClip",[54,176],{"x":56,"y":56,"width":57,"height":58,"fill":151},[89,178],{"cx":179,"cy":92,"r":93,"fill":147},"640",[89,181],{"cx":179,"cy":92,"r":93,"fill":94,"stroke":80,"style":95},[89,183],{"cx":184,"cy":92,"r":93,"fill":99,"fillOpacity":185,"style":186},"680",0.5,"mask:url(#selIntersectClip)",[89,188],{"cx":184,"cy":92,"r":93,"fill":94,"stroke":99,"style":95},[61,190,191],{"x":168,"y":104,"style":105,"fill":106,"textAnchor":67},"in both sets",[70,193,194,201,207,210],{},[54,195],{"x":196,"y":197,"width":198,"height":199,"fill":94,"stroke":80,"style":200},"248","212","14","12","stroke-width:2;stroke-dasharray:4 3",[61,202,206],{"x":203,"y":204,"style":205,"fill":106},"270","223","font-size:11px;font-family:sans-serif","already selected",[54,208],{"x":209,"y":197,"width":198,"height":199,"fill":94,"stroke":99,"style":101},"404",[61,211,213],{"x":212,"y":204,"style":205,"fill":106},"426","matched by the expression",[215,216,218],"h2",{"id":217},"prerequisites","Prerequisites",[220,221,222,230,237],"ul",{},[223,224,225,229],"li",{},[226,227,228],"strong",{},"QGIS 3.34 LTR"," (bundled Python 3.12) or newer.",[223,231,232,233,236],{},"A vector layer loaded in the project. Selections only exist on layers registered with ",[18,234,235],{},"QgsProject","; a layer opened but never added has nothing to select on.",[223,238,239,240,244],{},"Familiarity with expression quoting — double quotes for fields, single for literals. See ",[31,241,243],{"href":242},"\u002Fpyqgis-fundamentals-environment-setup\u002Fworking-with-qgis-expressions\u002Fevaluate-qgis-expression-in-pyqgis\u002F","Evaluate a QGIS Expression in PyQGIS",".",[215,246,248],{"id":247},"make-a-selection","Make a selection",[14,250,251],{},"The one-line form replaces whatever was selected before and highlights the matches on the canvas immediately.",[253,254,259],"pre",{"className":255,"code":256,"language":257,"meta":258,"style":258},"language-python shiki shiki-themes github-dark","from qgis.core import QgsProject\n\nlayer = QgsProject.instance().mapLayersByName(\"parcels\")[0]\n\nlayer.selectByExpression('\"zoning\" = \\'residential\\' AND \"assessed_value\" > 250000')\n\nprint(layer.selectedFeatureCount(), \"feature(s) selected\")\n","python","",[18,260,261,280,287,312,317,340,345],{"__ignoreMap":258},[262,263,266,270,274,277],"span",{"class":264,"line":265},"line",1,[262,267,269],{"class":268},"snl16","from",[262,271,273],{"class":272},"s95oV"," qgis.core ",[262,275,276],{"class":268},"import",[262,278,279],{"class":272}," QgsProject\n",[262,281,283],{"class":264,"line":282},2,[262,284,286],{"emptyLinePlaceholder":285},true,"\n",[262,288,290,293,296,299,303,306,309],{"class":264,"line":289},3,[262,291,292],{"class":272},"layer ",[262,294,295],{"class":268},"=",[262,297,298],{"class":272}," QgsProject.instance().mapLayersByName(",[262,300,302],{"class":301},"sU2Wk","\"parcels\"",[262,304,305],{"class":272},")[",[262,307,56],{"class":308},"sDLfK",[262,310,311],{"class":272},"]\n",[262,313,315],{"class":264,"line":314},4,[262,316,286],{"emptyLinePlaceholder":285},[262,318,320,323,326,329,332,334,337],{"class":264,"line":319},5,[262,321,322],{"class":272},"layer.selectByExpression(",[262,324,325],{"class":301},"'\"zoning\" = ",[262,327,328],{"class":308},"\\'",[262,330,331],{"class":301},"residential",[262,333,328],{"class":308},[262,335,336],{"class":301}," AND \"assessed_value\" > 250000'",[262,338,339],{"class":272},")\n",[262,341,343],{"class":264,"line":342},6,[262,344,286],{"emptyLinePlaceholder":285},[262,346,348,351,354,357],{"class":264,"line":347},7,[262,349,350],{"class":308},"print",[262,352,353],{"class":272},"(layer.selectedFeatureCount(), ",[262,355,356],{"class":301},"\"feature(s) selected\"",[262,358,339],{"class":272},[14,360,361,364,365,367,368,371],{},[226,362,363],{},"Breakdown:"," The expression is an ordinary Python string, so the single quotes that delimit the literal ",[18,366,331],{}," in the expression have to be escaped — using a double-quoted Python string with single quotes inside, or a triple-quoted string, avoids the backslashes entirely. ",[18,369,370],{},"selectedFeatureCount()"," is the cheap way to confirm a match without pulling the features themselves; a count of zero almost always means a quoting mistake rather than genuinely empty data.",[14,373,374],{},"For values that come from anywhere other than a literal in your source, build the expression with the quoting helpers rather than an f-string:",[253,376,378],{"className":255,"code":377,"language":257,"meta":258,"style":258},"from qgis.core import QgsExpression\n\nzoning = user_input          # e.g. \"O'Brien Estate\"\nclause = f'{QgsExpression.quotedColumnRef(\"zoning\")} = {QgsExpression.quotedValue(zoning)}'\nlayer.selectByExpression(clause)\n",[18,379,380,391,395,409,450],{"__ignoreMap":258},[262,381,382,384,386,388],{"class":264,"line":265},[262,383,269],{"class":268},[262,385,273],{"class":272},[262,387,276],{"class":268},[262,389,390],{"class":272}," QgsExpression\n",[262,392,393],{"class":264,"line":282},[262,394,286],{"emptyLinePlaceholder":285},[262,396,397,400,402,405],{"class":264,"line":289},[262,398,399],{"class":272},"zoning ",[262,401,295],{"class":268},[262,403,404],{"class":272}," user_input          ",[262,406,408],{"class":407},"sjoCn","# e.g. \"O'Brien Estate\"\n",[262,410,411,414,416,419,422,425,428,431,434,437,440,442,445,447],{"class":264,"line":314},[262,412,413],{"class":272},"clause ",[262,415,295],{"class":268},[262,417,418],{"class":268}," f",[262,420,421],{"class":301},"'",[262,423,424],{"class":308},"{",[262,426,427],{"class":272},"QgsExpression.quotedColumnRef(",[262,429,430],{"class":301},"\"zoning\"",[262,432,433],{"class":272},")",[262,435,436],{"class":308},"}",[262,438,439],{"class":301}," = ",[262,441,424],{"class":308},[262,443,444],{"class":272},"QgsExpression.quotedValue(zoning)",[262,446,436],{"class":308},[262,448,449],{"class":301},"'\n",[262,451,452],{"class":264,"line":319},[262,453,454],{"class":272},"layer.selectByExpression(clause)\n",[14,456,457,459,460,463,464,467],{},[226,458,363],{}," ",[18,461,462],{},"quotedValue()"," doubles internal apostrophes the way the expression grammar requires, so a name containing one selects correctly instead of producing a parser error. ",[18,465,466],{},"quotedColumnRef()"," does the same for the field name. This matters in any plugin where the value originates in a dialog.",[215,469,471],{"id":470},"combine-with-an-existing-selection","Combine with an existing selection",[14,473,474],{},"The optional second argument controls how the new match interacts with what is already selected, which is what makes multi-step refinement possible.",[253,476,478],{"className":255,"code":477,"language":257,"meta":258,"style":258},"from qgis.core import Qgis, QgsProject\n\nlayer = QgsProject.instance().mapLayersByName(\"parcels\")[0]\n\nlayer.selectByExpression('\"zoning\" = \\'residential\\'', Qgis.SelectBehavior.SetSelection)\nlayer.selectByExpression('\"assessed_value\" > 500000', Qgis.SelectBehavior.IntersectSelection)\nlayer.selectByExpression('\"status\" = \\'exempt\\'', Qgis.SelectBehavior.RemoveFromSelection)\n\nprint(layer.selectedFeatureCount())\n",[18,479,480,491,495,511,515,532,542,561,566],{"__ignoreMap":258},[262,481,482,484,486,488],{"class":264,"line":265},[262,483,269],{"class":268},[262,485,273],{"class":272},[262,487,276],{"class":268},[262,489,490],{"class":272}," Qgis, QgsProject\n",[262,492,493],{"class":264,"line":282},[262,494,286],{"emptyLinePlaceholder":285},[262,496,497,499,501,503,505,507,509],{"class":264,"line":289},[262,498,292],{"class":272},[262,500,295],{"class":268},[262,502,298],{"class":272},[262,504,302],{"class":301},[262,506,305],{"class":272},[262,508,56],{"class":308},[262,510,311],{"class":272},[262,512,513],{"class":264,"line":314},[262,514,286],{"emptyLinePlaceholder":285},[262,516,517,519,521,523,525,527,529],{"class":264,"line":319},[262,518,322],{"class":272},[262,520,325],{"class":301},[262,522,328],{"class":308},[262,524,331],{"class":301},[262,526,328],{"class":308},[262,528,421],{"class":301},[262,530,531],{"class":272},", Qgis.SelectBehavior.SetSelection)\n",[262,533,534,536,539],{"class":264,"line":342},[262,535,322],{"class":272},[262,537,538],{"class":301},"'\"assessed_value\" > 500000'",[262,540,541],{"class":272},", Qgis.SelectBehavior.IntersectSelection)\n",[262,543,544,546,549,551,554,556,558],{"class":264,"line":347},[262,545,322],{"class":272},[262,547,548],{"class":301},"'\"status\" = ",[262,550,328],{"class":308},[262,552,553],{"class":301},"exempt",[262,555,328],{"class":308},[262,557,421],{"class":301},[262,559,560],{"class":272},", Qgis.SelectBehavior.RemoveFromSelection)\n",[262,562,564],{"class":264,"line":563},8,[262,565,286],{"emptyLinePlaceholder":285},[262,567,569,571],{"class":264,"line":568},9,[262,570,350],{"class":308},[262,572,573],{"class":272},"(layer.selectedFeatureCount())\n",[14,575,576,578,579,581,582,585,586,589,590,593],{},[226,577,363],{}," Reading down, this selects residential parcels, narrows to the expensive ones, then drops the exempt ones — three simple expressions instead of one long boolean. ",[18,580,87],{}," is the default and is what makes the first call a clean starting point regardless of previous state. On QGIS 3.28 and earlier these constants live on ",[18,583,584],{},"QgsVectorLayer"," (",[18,587,588],{},"QgsVectorLayer.SetSelection","); both spellings work on 3.34, and the ",[18,591,592],{},"Qgis.SelectBehavior"," form is the one to write in new code.",[215,595,597],{"id":596},"read-the-selection-back","Read the selection back",[14,599,600],{},"A selection is a set of feature IDs, and there are two ways to consume it depending on whether you need the features or just the identifiers.",[253,602,604],{"className":255,"code":603,"language":257,"meta":258,"style":258},"selected_ids = layer.selectedFeatureIds()\nprint(len(selected_ids), \"id(s)\")\n\nfor feature in layer.getSelectedFeatures():\n    print(feature[\"parcel_id\"], feature[\"assessed_value\"])\n\ntotal = sum(f[\"assessed_value\"] or 0 for f in layer.getSelectedFeatures())\nprint(f\"total assessed value: {total:,.0f}\")\n",[18,605,606,616,634,638,652,672,676,711],{"__ignoreMap":258},[262,607,608,611,613],{"class":264,"line":265},[262,609,610],{"class":272},"selected_ids ",[262,612,295],{"class":268},[262,614,615],{"class":272}," layer.selectedFeatureIds()\n",[262,617,618,620,623,626,629,632],{"class":264,"line":282},[262,619,350],{"class":308},[262,621,622],{"class":272},"(",[262,624,625],{"class":308},"len",[262,627,628],{"class":272},"(selected_ids), ",[262,630,631],{"class":301},"\"id(s)\"",[262,633,339],{"class":272},[262,635,636],{"class":264,"line":289},[262,637,286],{"emptyLinePlaceholder":285},[262,639,640,643,646,649],{"class":264,"line":314},[262,641,642],{"class":268},"for",[262,644,645],{"class":272}," feature ",[262,647,648],{"class":268},"in",[262,650,651],{"class":272}," layer.getSelectedFeatures():\n",[262,653,654,657,660,663,666,669],{"class":264,"line":319},[262,655,656],{"class":308},"    print",[262,658,659],{"class":272},"(feature[",[262,661,662],{"class":301},"\"parcel_id\"",[262,664,665],{"class":272},"], feature[",[262,667,668],{"class":301},"\"assessed_value\"",[262,670,671],{"class":272},"])\n",[262,673,674],{"class":264,"line":342},[262,675,286],{"emptyLinePlaceholder":285},[262,677,678,681,683,686,689,691,694,697,700,703,706,708],{"class":264,"line":347},[262,679,680],{"class":272},"total ",[262,682,295],{"class":268},[262,684,685],{"class":308}," sum",[262,687,688],{"class":272},"(f[",[262,690,668],{"class":301},[262,692,693],{"class":272},"] ",[262,695,696],{"class":268},"or",[262,698,699],{"class":308}," 0",[262,701,702],{"class":268}," for",[262,704,705],{"class":272}," f ",[262,707,648],{"class":268},[262,709,710],{"class":272}," layer.getSelectedFeatures())\n",[262,712,713,715,717,720,723,725,728,731,733,736],{"class":264,"line":563},[262,714,350],{"class":308},[262,716,622],{"class":272},[262,718,719],{"class":268},"f",[262,721,722],{"class":301},"\"total assessed value: ",[262,724,424],{"class":308},[262,726,727],{"class":272},"total",[262,729,730],{"class":268},":,.0f",[262,732,436],{"class":308},[262,734,735],{"class":301},"\"",[262,737,339],{"class":272},[14,739,740,459,742,745,746,749,750,753,754,757,758,761],{},[226,741,363],{},[18,743,744],{},"selectedFeatureIds()"," returns just the IDs and is nearly free — use it when you only need a count, a membership test, or something to pass to another call. ",[18,747,748],{},"getSelectedFeatures()"," returns an iterator of full features and reads from the provider, so it costs the same as any other iteration. The ",[18,751,752],{},"or 0"," guard handles ",[18,755,756],{},"NULL"," values, which would otherwise make the ",[18,759,760],{},"sum()"," raise on the first empty cell.",[215,763,765],{"id":764},"when-a-selection-is-the-wrong-tool","When a selection is the wrong tool",[14,767,768],{},"A selection is user-interface state. It is visible, it is what the user sees highlighted, and it does not persist. For pure data processing — reading rows that match a rule — a feature request is faster, does not disturb what the user has selected, and works on layers that are not in the project at all.",[14,770,771],{},[39,772,775,778,781,784,798,802,808,813,821,846,851,854,858,861,865,869,884,887,894,899,903,909,912],{"viewBox":773,"role":42,"ariaLabel":774,"xmlns":44},"0 0 760 262","Comparison of selecting features, which changes visible interface state, against filtering with a feature request, which reads matching rows without touching the selection",[46,776,777],{},"Select for the user, request for the script",[50,779,780],{},"On the left, selectByExpression highlights matching parcels on the canvas, changes what the user sees, and is cleared when the project reloads. On the right, a QgsFeatureRequest with a filter expression streams only the matching rows into the script, leaves the canvas untouched, and pushes the predicate down to the data provider.",[54,782],{"x":56,"y":56,"width":57,"height":783,"fill":59},"262",[139,785,786],{},[787,788,794],"marker",{"id":789,"viewBox":790,"refX":74,"refY":791,"markerWidth":792,"markerHeight":792,"orient":793},"selPickArrow","0 0 10 10","5","7","auto-start-reverse",[795,796],"path",{"d":797,"fill":106},"M0 0 L10 5 L0 10 z",[61,799,801],{"x":63,"y":800,"style":65,"fill":66,"textAnchor":67},"26","One changes what the user sees; the other does not",[54,803],{"x":804,"y":805,"width":806,"height":807,"rx":78,"fill":79,"stroke":99,"style":81},"16","46","356","200",[61,809,20],{"x":810,"y":811,"style":812,"fill":99,"textAnchor":67},"194","70","text-anchor:middle;font-size:12.5px;font-weight:bold;font-family:sans-serif",[54,814],{"x":815,"y":816,"width":817,"height":816,"rx":818,"fill":59,"stroke":819,"style":820},"44","86","300","6","#59645f","stroke-width:1.5",[70,822,823,829,832,835,837,840,842,844],{},[54,824],{"x":825,"y":826,"width":827,"height":800,"fill":80,"fillOpacity":828,"stroke":80,"style":820},"60","100","52",0.15,[54,830],{"x":831,"y":826,"width":827,"height":800,"fill":99,"fillOpacity":185,"stroke":99,"style":81},"124",[54,833],{"x":834,"y":826,"width":827,"height":800,"fill":80,"fillOpacity":828,"stroke":80,"style":820},"188",[54,836],{"x":58,"y":826,"width":827,"height":800,"fill":99,"fillOpacity":185,"stroke":99,"style":81},[54,838],{"x":825,"y":839,"width":827,"height":800,"fill":99,"fillOpacity":185,"stroke":99,"style":81},"136",[54,841],{"x":831,"y":839,"width":827,"height":800,"fill":80,"fillOpacity":828,"stroke":80,"style":820},[54,843],{"x":834,"y":839,"width":827,"height":800,"fill":80,"fillOpacity":828,"stroke":80,"style":820},[54,845],{"x":58,"y":839,"width":827,"height":800,"fill":80,"fillOpacity":828,"stroke":80,"style":820},[61,847,850],{"x":810,"y":848,"style":849,"fill":106,"textAnchor":67},"192","text-anchor:middle;font-size:11.5px;font-family:sans-serif","highlighted on the canvas",[61,852,853],{"x":810,"y":197,"style":849,"fill":106,"textAnchor":67},"every feature still read",[61,855,857],{"x":810,"y":856,"style":849,"fill":133,"textAnchor":67},"232","lost on project reload",[54,859],{"x":860,"y":805,"width":806,"height":807,"rx":78,"fill":79,"stroke":113,"style":81},"388",[61,862,864],{"x":863,"y":811,"style":812,"fill":113,"textAnchor":67},"566","QgsFeatureRequest",[54,866],{"x":867,"y":816,"width":868,"height":816,"rx":818,"fill":59,"stroke":819,"style":820},"416","140",[70,870,871,876,879,882],{},[54,872],{"x":873,"y":826,"width":815,"height":874,"fill":819,"fillOpacity":828,"stroke":819,"style":875},"430","22","stroke-width:1.2",[54,877],{"x":878,"y":826,"width":815,"height":874,"fill":819,"fillOpacity":828,"stroke":819,"style":875},"486",[54,880],{"x":873,"y":881,"width":815,"height":874,"fill":819,"fillOpacity":828,"stroke":819,"style":875},"132",[54,883],{"x":878,"y":881,"width":815,"height":874,"fill":819,"fillOpacity":828,"stroke":819,"style":875},[61,885,886],{"x":878,"y":834,"style":105,"fill":819,"textAnchor":67},"canvas untouched",[54,888],{"x":889,"y":890,"width":891,"height":892,"rx":818,"fill":113,"fillOpacity":893,"stroke":113,"style":101},"620","98","104","74",0.14,[61,895,898],{"x":896,"y":92,"style":897,"fill":113,"textAnchor":67},"672","text-anchor:middle;font-size:11.5px;font-weight:bold;font-family:sans-serif","matching",[61,900,902],{"x":896,"y":901,"style":897,"fill":113,"textAnchor":67},"144","rows only",[264,904],{"x1":905,"y1":906,"x2":907,"y2":906,"stroke":113,"style":908},"560","130","614","stroke-width:2.5;marker-end:url(#selPickArrow)",[61,910,911],{"x":863,"y":197,"style":849,"fill":106,"textAnchor":67},"predicate pushed to the provider",[61,913,914],{"x":863,"y":856,"style":849,"fill":113,"textAnchor":67},"works on unregistered layers",[253,916,918],{"className":255,"code":917,"language":257,"meta":258,"style":258},"from qgis.core import QgsFeatureRequest\n\nrequest = QgsFeatureRequest()\nrequest.setFilterExpression('\"zoning\" = \\'residential\\' AND \"assessed_value\" > 250000')\nrequest.setSubsetOfAttributes([\"parcel_id\", \"assessed_value\"], layer.fields())\n\nfor feature in layer.getFeatures(request):\n    print(feature[\"parcel_id\"], feature[\"assessed_value\"])\n",[18,919,920,931,935,945,962,977,981,992],{"__ignoreMap":258},[262,921,922,924,926,928],{"class":264,"line":265},[262,923,269],{"class":268},[262,925,273],{"class":272},[262,927,276],{"class":268},[262,929,930],{"class":272}," QgsFeatureRequest\n",[262,932,933],{"class":264,"line":282},[262,934,286],{"emptyLinePlaceholder":285},[262,936,937,940,942],{"class":264,"line":289},[262,938,939],{"class":272},"request ",[262,941,295],{"class":268},[262,943,944],{"class":272}," QgsFeatureRequest()\n",[262,946,947,950,952,954,956,958,960],{"class":264,"line":314},[262,948,949],{"class":272},"request.setFilterExpression(",[262,951,325],{"class":301},[262,953,328],{"class":308},[262,955,331],{"class":301},[262,957,328],{"class":308},[262,959,336],{"class":301},[262,961,339],{"class":272},[262,963,964,967,969,972,974],{"class":264,"line":319},[262,965,966],{"class":272},"request.setSubsetOfAttributes([",[262,968,662],{"class":301},[262,970,971],{"class":272},", ",[262,973,668],{"class":301},[262,975,976],{"class":272},"], layer.fields())\n",[262,978,979],{"class":264,"line":342},[262,980,286],{"emptyLinePlaceholder":285},[262,982,983,985,987,989],{"class":264,"line":347},[262,984,642],{"class":268},[262,986,645],{"class":272},[262,988,648],{"class":268},[262,990,991],{"class":272}," layer.getFeatures(request):\n",[262,993,994,996,998,1000,1002,1004],{"class":264,"line":563},[262,995,656],{"class":308},[262,997,659],{"class":272},[262,999,662],{"class":301},[262,1001,665],{"class":272},[262,1003,668],{"class":301},[262,1005,671],{"class":272},[14,1007,1008,1010,1011,1013,1014,1017],{},[226,1009,363],{}," The filter is translated into SQL for providers that support it — PostGIS and GeoPackage among them — so the database does the matching and only the matching rows are transferred. ",[18,1012,20],{},", by contrast, must evaluate the expression against every feature to decide what to highlight. Adding ",[18,1015,1016],{},"setSubsetOfAttributes()"," narrows the columns as well. Use a selection when a human needs to see the result; use a request when only the script does.",[215,1019,1021],{"id":1020},"feed-a-selection-into-processing","Feed a selection into Processing",[14,1023,1024,1025,1028],{},"When a selection ",[23,1026,1027],{},"is"," the right starting point — because the user made it — Processing algorithms can operate on just those features rather than the whole layer.",[253,1030,1032],{"className":255,"code":1031,"language":257,"meta":258,"style":258},"import processing\nfrom qgis.core import QgsProcessingFeatureSourceDefinition\n\nsource = QgsProcessingFeatureSourceDefinition(layer.id(), selectedFeaturesOnly=True)\n\nresult = processing.run(\"native:buffer\", {\n    \"INPUT\": source,\n    \"DISTANCE\": 50,\n    \"OUTPUT\": \"TEMPORARY_OUTPUT\",\n})[\"OUTPUT\"]\n\nprint(result.featureCount(), \"buffered feature(s)\")\n",[18,1033,1034,1041,1052,1056,1077,1081,1097,1105,1119,1131,1142,1147],{"__ignoreMap":258},[262,1035,1036,1038],{"class":264,"line":265},[262,1037,276],{"class":268},[262,1039,1040],{"class":272}," processing\n",[262,1042,1043,1045,1047,1049],{"class":264,"line":282},[262,1044,269],{"class":268},[262,1046,273],{"class":272},[262,1048,276],{"class":268},[262,1050,1051],{"class":272}," QgsProcessingFeatureSourceDefinition\n",[262,1053,1054],{"class":264,"line":289},[262,1055,286],{"emptyLinePlaceholder":285},[262,1057,1058,1061,1063,1066,1070,1072,1075],{"class":264,"line":314},[262,1059,1060],{"class":272},"source ",[262,1062,295],{"class":268},[262,1064,1065],{"class":272}," QgsProcessingFeatureSourceDefinition(layer.id(), ",[262,1067,1069],{"class":1068},"s9osk","selectedFeaturesOnly",[262,1071,295],{"class":268},[262,1073,1074],{"class":308},"True",[262,1076,339],{"class":272},[262,1078,1079],{"class":264,"line":319},[262,1080,286],{"emptyLinePlaceholder":285},[262,1082,1083,1086,1088,1091,1094],{"class":264,"line":342},[262,1084,1085],{"class":272},"result ",[262,1087,295],{"class":268},[262,1089,1090],{"class":272}," processing.run(",[262,1092,1093],{"class":301},"\"native:buffer\"",[262,1095,1096],{"class":272},", {\n",[262,1098,1099,1102],{"class":264,"line":347},[262,1100,1101],{"class":301},"    \"INPUT\"",[262,1103,1104],{"class":272},": source,\n",[262,1106,1107,1110,1113,1116],{"class":264,"line":563},[262,1108,1109],{"class":301},"    \"DISTANCE\"",[262,1111,1112],{"class":272},": ",[262,1114,1115],{"class":308},"50",[262,1117,1118],{"class":272},",\n",[262,1120,1121,1124,1126,1129],{"class":264,"line":568},[262,1122,1123],{"class":301},"    \"OUTPUT\"",[262,1125,1112],{"class":272},[262,1127,1128],{"class":301},"\"TEMPORARY_OUTPUT\"",[262,1130,1118],{"class":272},[262,1132,1134,1137,1140],{"class":264,"line":1133},10,[262,1135,1136],{"class":272},"})[",[262,1138,1139],{"class":301},"\"OUTPUT\"",[262,1141,311],{"class":272},[262,1143,1145],{"class":264,"line":1144},11,[262,1146,286],{"emptyLinePlaceholder":285},[262,1148,1150,1152,1155,1158],{"class":264,"line":1149},12,[262,1151,350],{"class":308},[262,1153,1154],{"class":272},"(result.featureCount(), ",[262,1156,1157],{"class":301},"\"buffered feature(s)\"",[262,1159,339],{"class":272},[14,1161,1162,459,1164,1167,1168,1170,1171,1175],{},[226,1163,363],{},[18,1165,1166],{},"QgsProcessingFeatureSourceDefinition"," wraps a layer ID with the ",[18,1169,1069],{}," flag, which is how the GUI's \"Selected features only\" checkbox is expressed in a script. Passing the layer object directly instead would silently process everything. This composes with the pipelines in ",[31,1172,1174],{"href":1173},"\u002Fspatial-data-processing-automation\u002Fchaining-processing-algorithms\u002F","Chaining Processing Algorithms in PyQGIS",", where a user-driven selection often defines the study area for a whole chain.",[215,1177,1179],{"id":1178},"select-across-several-layers-at-once","Select across several layers at once",[14,1181,1182],{},"A study area is rarely one layer. Applying the same rule across every layer that has the relevant field — and reporting which ones did not — turns a repetitive manual job into four lines.",[253,1184,1186],{"className":255,"code":1185,"language":257,"meta":258,"style":258},"from qgis.core import QgsProject\n\nRULE = '\"status\" = \\'active\\''\nreport = {}\n\nfor layer in QgsProject.instance().mapLayers().values():\n    if layer.type() != layer.VectorLayer:\n        continue\n    if layer.fields().indexOf(\"status\") == -1:\n        report[layer.name()] = \"no status field\"\n        continue\n    layer.selectByExpression(RULE)\n    report[layer.name()] = f\"{layer.selectedFeatureCount()} selected\"\n\nfor name, outcome in sorted(report.items()):\n    print(f\"{name:\u003C28} {outcome}\")\n",[18,1187,1188,1198,1202,1222,1232,1236,1248,1262,1267,1292,1302,1306,1315,1337,1342,1358],{"__ignoreMap":258},[262,1189,1190,1192,1194,1196],{"class":264,"line":265},[262,1191,269],{"class":268},[262,1193,273],{"class":272},[262,1195,276],{"class":268},[262,1197,279],{"class":272},[262,1199,1200],{"class":264,"line":282},[262,1201,286],{"emptyLinePlaceholder":285},[262,1203,1204,1207,1210,1213,1215,1218,1220],{"class":264,"line":289},[262,1205,1206],{"class":308},"RULE",[262,1208,1209],{"class":268}," =",[262,1211,1212],{"class":301}," '\"status\" = ",[262,1214,328],{"class":308},[262,1216,1217],{"class":301},"active",[262,1219,328],{"class":308},[262,1221,449],{"class":301},[262,1223,1224,1227,1229],{"class":264,"line":314},[262,1225,1226],{"class":272},"report ",[262,1228,295],{"class":268},[262,1230,1231],{"class":272}," {}\n",[262,1233,1234],{"class":264,"line":319},[262,1235,286],{"emptyLinePlaceholder":285},[262,1237,1238,1240,1243,1245],{"class":264,"line":342},[262,1239,642],{"class":268},[262,1241,1242],{"class":272}," layer ",[262,1244,648],{"class":268},[262,1246,1247],{"class":272}," QgsProject.instance().mapLayers().values():\n",[262,1249,1250,1253,1256,1259],{"class":264,"line":347},[262,1251,1252],{"class":268},"    if",[262,1254,1255],{"class":272}," layer.type() ",[262,1257,1258],{"class":268},"!=",[262,1260,1261],{"class":272}," layer.VectorLayer:\n",[262,1263,1264],{"class":264,"line":563},[262,1265,1266],{"class":268},"        continue\n",[262,1268,1269,1271,1274,1277,1280,1283,1286,1289],{"class":264,"line":568},[262,1270,1252],{"class":268},[262,1272,1273],{"class":272}," layer.fields().indexOf(",[262,1275,1276],{"class":301},"\"status\"",[262,1278,1279],{"class":272},") ",[262,1281,1282],{"class":268},"==",[262,1284,1285],{"class":268}," -",[262,1287,1288],{"class":308},"1",[262,1290,1291],{"class":272},":\n",[262,1293,1294,1297,1299],{"class":264,"line":1133},[262,1295,1296],{"class":272},"        report[layer.name()] ",[262,1298,295],{"class":268},[262,1300,1301],{"class":301}," \"no status field\"\n",[262,1303,1304],{"class":264,"line":1144},[262,1305,1266],{"class":268},[262,1307,1308,1311,1313],{"class":264,"line":1149},[262,1309,1310],{"class":272},"    layer.selectByExpression(",[262,1312,1206],{"class":308},[262,1314,339],{"class":272},[262,1316,1318,1321,1323,1325,1327,1329,1332,1334],{"class":264,"line":1317},13,[262,1319,1320],{"class":272},"    report[layer.name()] ",[262,1322,295],{"class":268},[262,1324,418],{"class":268},[262,1326,735],{"class":301},[262,1328,424],{"class":308},[262,1330,1331],{"class":272},"layer.selectedFeatureCount()",[262,1333,436],{"class":308},[262,1335,1336],{"class":301}," selected\"\n",[262,1338,1340],{"class":264,"line":1339},14,[262,1341,286],{"emptyLinePlaceholder":285},[262,1343,1345,1347,1350,1352,1355],{"class":264,"line":1344},15,[262,1346,642],{"class":268},[262,1348,1349],{"class":272}," name, outcome ",[262,1351,648],{"class":268},[262,1353,1354],{"class":308}," sorted",[262,1356,1357],{"class":272},"(report.items()):\n",[262,1359,1361,1363,1365,1367,1369,1371,1374,1377,1379,1382,1385,1387,1389],{"class":264,"line":1360},16,[262,1362,656],{"class":308},[262,1364,622],{"class":272},[262,1366,719],{"class":268},[262,1368,735],{"class":301},[262,1370,424],{"class":308},[262,1372,1373],{"class":272},"name",[262,1375,1376],{"class":268},":\u003C28",[262,1378,436],{"class":308},[262,1380,1381],{"class":308}," {",[262,1383,1384],{"class":272},"outcome",[262,1386,436],{"class":308},[262,1388,735],{"class":301},[262,1390,339],{"class":272},[14,1392,1393,459,1395,1398,1399,1401,1402,1405],{},[226,1394,363],{},[18,1396,1397],{},"mapLayers()"," returns every layer in the project keyed by ID, including rasters, so the type check comes first — calling ",[18,1400,20],{}," on a raster raises. Testing ",[18,1403,1404],{},"indexOf(\"status\") == -1"," before selecting distinguishes \"no matching rows\" from \"this layer does not have that column\", which are very different findings and look identical in a bare count. Building a report dictionary rather than printing inside the loop keeps the output ordered and makes the whole thing easy to return from a function.",[14,1407,1408],{},[39,1409,1412,1415,1418,1421,1428,1431,1436,1442,1445,1448,1454,1460,1463,1467,1470,1472,1476,1479,1481,1485,1489,1495,1499,1502,1506,1510,1513],{"viewBox":1410,"role":42,"ariaLabel":1411,"xmlns":44},"0 0 760 238","One expression applied across four project layers, with two selecting successfully, one reporting no matching rows and one skipped because it lacks the field",[46,1413,1414],{},"Applying one rule across every layer in a project",[50,1416,1417],{},"A single status expression fans out to four layers. Parcels and buildings each report a count of selected features. Roads reports zero matches, which is a valid result. Hillshade is skipped because it is a raster and has no attribute table, and a fourth vector layer is skipped because it has no status field.",[54,1419],{"x":56,"y":56,"width":57,"height":1420,"fill":59},"238",[139,1422,1423],{},[787,1424,1426],{"id":1425,"viewBox":790,"refX":74,"refY":791,"markerWidth":792,"markerHeight":792,"orient":793},"selFanArrow",[795,1427],{"d":797,"fill":106},[61,1429,1430],{"x":63,"y":800,"style":65,"fill":66,"textAnchor":67},"Distinguish \"nothing matched\" from \"this layer cannot match\"",[54,1432],{"x":804,"y":1433,"width":1434,"height":85,"rx":78,"fill":1435,"stroke":80,"style":81},"92","180","#26322d",[61,1437,1441],{"x":1438,"y":1439,"style":86,"fill":1440,"textAnchor":67},"106","118","#d9f99d","\"status\" = 'active'",[61,1443,1444],{"x":1438,"y":868,"style":105,"fill":1440,"textAnchor":67},"one rule",[54,1446],{"x":817,"y":815,"width":1447,"height":93,"rx":74,"fill":79,"stroke":113,"style":101},"240",[61,1449,1453],{"x":1450,"y":1451,"style":1452,"fill":106},"320","68","font-size:11.5px;font-family:sans-serif","parcels",[61,1455,1459],{"x":1456,"y":1451,"style":1457,"fill":113,"textAnchor":1458},"520","text-anchor:end;font-size:11.5px;font-weight:bold;font-family:sans-serif","end","412 selected",[54,1461],{"x":817,"y":1462,"width":1447,"height":93,"rx":74,"fill":79,"stroke":113,"style":101},"90",[61,1464,1466],{"x":1450,"y":1465,"style":1452,"fill":106},"114","buildings",[61,1468,1469],{"x":1456,"y":1465,"style":1457,"fill":113,"textAnchor":1458},"87 selected",[54,1471],{"x":817,"y":839,"width":1447,"height":93,"rx":74,"fill":79,"stroke":133,"style":101},[61,1473,1475],{"x":1450,"y":1474,"style":1452,"fill":106},"160","roads",[61,1477,1478],{"x":1456,"y":1474,"style":1457,"fill":133,"textAnchor":1458},"0 selected",[54,1480],{"x":817,"y":104,"width":1447,"height":93,"rx":74,"fill":79,"stroke":819,"style":95},[61,1482,1484],{"x":1450,"y":1483,"style":1452,"fill":106},"206","hillshade",[61,1486,1488],{"x":1456,"y":1483,"style":1487,"fill":819,"textAnchor":1458},"text-anchor:end;font-size:11.5px;font-family:sans-serif","skipped — raster",[264,1490],{"x1":112,"y1":1491,"x2":1492,"y2":1493,"stroke":113,"style":1494},"112","296","63","stroke-width:2;marker-end:url(#selFanArrow)",[264,1496],{"x1":112,"y1":1497,"x2":1492,"y2":1498,"stroke":113,"style":1494},"120","109",[264,1500],{"x1":112,"y1":906,"x2":1492,"y2":1501,"stroke":133,"style":1494},"155",[264,1503],{"x1":112,"y1":868,"x2":1492,"y2":1504,"stroke":819,"style":1505},"201","stroke-width:2;stroke-dasharray:5 4;marker-end:url(#selFanArrow)",[61,1507,1509],{"x":1508,"y":1491,"style":105,"fill":106,"textAnchor":67},"628","a real result",[61,1511,1512],{"x":1508,"y":1474,"style":105,"fill":133,"textAnchor":67},"also a real result",[61,1514,1515],{"x":1508,"y":1483,"style":105,"fill":819,"textAnchor":67},"not comparable",[215,1517,1519],{"id":1518},"qgis-version-compatibility","QGIS version compatibility",[14,1521,1522,1523,1525],{},"The examples target ",[226,1524,228],{}," (Python 3.12).",[1527,1528,1529,1545],"table",{},[1530,1531,1532],"thead",{},[1533,1534,1535,1539,1542],"tr",{},[1536,1537,1538],"th",{},"QGIS version",[1536,1540,1541],{},"Python",[1536,1543,1544],{},"Notes",[1546,1547,1548,1565,1576],"tbody",{},[1533,1549,1550,1554,1557],{},[1551,1552,1553],"td",{},"3.28 LTR",[1551,1555,1556],{},"3.9",[1551,1558,1559,1560,1562,1563,244],{},"Use ",[18,1561,588],{}," etc. rather than ",[18,1564,592],{},[1533,1566,1567,1570,1573],{},[1551,1568,1569],{},"3.34 LTR",[1551,1571,1572],{},"3.12",[1551,1574,1575],{},"Baseline. Both enum spellings accepted.",[1533,1577,1578,1581,1583],{},[1551,1579,1580],{},"3.40 \u002F 3.44",[1551,1582,1572],{},[1551,1584,1585,1587],{},[18,1586,592],{}," is the documented form; the old constants still resolve.",[14,1589,1590,971,1592,1594,1595,1597],{},[18,1591,20],{},[18,1593,744],{}," and ",[18,1596,748],{}," are unchanged across the whole 3.x line.",[215,1599,1601],{"id":1600},"troubleshooting","Troubleshooting",[220,1603,1604,1618,1624,1640,1646,1658],{},[223,1605,1606,1609,1610,1613,1614,1617],{},[226,1607,1608],{},"Zero features selected but the data clearly matches."," A quoting error. ",[18,1611,1612],{},"\"zoning\" = \"residential\""," compares two field references; ",[18,1615,1616],{},"'zoning' = 'residential'"," compares two literals and is always false. Only the mixed form is right.",[223,1619,1620,1623],{},[226,1621,1622],{},"The selection is empty after a Processing run."," Some algorithms replace the layer rather than editing it. Re-select on the output layer, not the input.",[223,1625,1626,1632,1633,1594,1636,1639],{},[226,1627,1628,1631],{},[18,1629,1630],{},"selectByExpression"," raises about an unknown field."," The field name has a typo or the layer is not the one you think it is. Print ",[18,1634,1635],{},"layer.fields().names()",[18,1637,1638],{},"layer.name()"," together.",[223,1641,1642,1645],{},[226,1643,1644],{},"The selection does not appear on the canvas."," The layer is not registered with the project, or its visibility is off. Selections are drawn as part of the layer's render.",[223,1647,1648,1651,1652,1654,1655,1657],{},[226,1649,1650],{},"The user's selection disappears when your script runs."," You used ",[18,1653,87],{}," where ",[18,1656,117],{}," was meant, or you should not be selecting at all — use a feature request instead.",[223,1659,1660,1663,1664,244],{},[226,1661,1662],{},"A Processing algorithm ignores the selection."," The input was passed as a layer object. Wrap it in ",[18,1665,1666],{},"QgsProcessingFeatureSourceDefinition(layer.id(), selectedFeaturesOnly=True)",[215,1668,1670],{"id":1669},"conclusion","Conclusion",[14,1672,1673,1675,1676,1678,1679,1681],{},[18,1674,20],{}," is the right tool when a person needs to see the result: it is one line, it composes through the four selection behaviours, and it feeds Processing cleanly through ",[18,1677,1166],{},". When only the script consumes the rows, reach for a ",[18,1680,864],{}," instead — it is faster, it pushes work to the provider, and it leaves the user's own selection alone.",[215,1683,1685],{"id":1684},"frequently-asked-questions","Frequently Asked Questions",[14,1687,1688,1691,1692,1694],{},[226,1689,1690],{},"Why does my selection expression match nothing?","\nAlmost always quoting. Field names take double quotes and string values take single quotes; getting either wrong produces a valid expression that is never true rather than an error. Verify with ",[18,1693,1331],{}," immediately after the call.",[14,1696,1697,1700,1701,1704,1705,1707],{},[226,1698,1699],{},"How do I add to a selection instead of replacing it?","\nPass ",[18,1702,1703],{},"Qgis.SelectBehavior.AddToSelection"," as the second argument. ",[18,1706,87],{}," is the default, which is why a second call normally appears to discard the first result.",[14,1709,1710,1713,1714,1716,1717,1720],{},[226,1711,1712],{},"Is selecting features faster than filtering them?","\nNo — it is slower for pure data work. A selection evaluates the expression against every feature and updates interface state. A ",[18,1715,864],{}," with ",[18,1718,1719],{},"setFilterExpression()"," lets the provider do the matching and returns only the rows you want.",[14,1722,1723,1726],{},[226,1724,1725],{},"Does a selection persist when the project is saved?","\nNo. Selections are transient interface state and are empty again after a reload. If a set of features needs to persist, write a flag to an attribute or export them to their own layer.",[215,1728,1730],{"id":1729},"related","Related",[220,1732,1733,1738,1742,1748],{},[223,1734,1735,1737],{},[31,1736,34],{"href":33}," — the guide this recipe belongs to",[223,1739,1740],{},[31,1741,243],{"href":242},[223,1743,1744],{},[31,1745,1747],{"href":1746},"\u002Fpyqgis-fundamentals-environment-setup\u002Fworking-with-qgis-expressions\u002Fdata-defined-symbol-size-expression-pyqgis\u002F","Data-Defined Symbol Size with an Expression in PyQGIS",[223,1749,1750],{},[31,1751,1753],{"href":1752},"\u002Fspatial-data-processing-automation\u002Fvector-data-manipulation\u002Fclip-vector-layer-pyqgis\u002F","Clip a Vector Layer in PyQGIS",[1755,1756,1757],"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 .sjoCn, html code.shiki .sjoCn{--shiki-default:#9AA79F}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}",{"title":258,"searchDepth":282,"depth":282,"links":1759},[1760,1761,1762,1763,1764,1765,1766,1767,1768,1769,1770,1771],{"id":217,"depth":282,"text":218},{"id":247,"depth":282,"text":248},{"id":470,"depth":282,"text":471},{"id":596,"depth":282,"text":597},{"id":764,"depth":282,"text":765},{"id":1020,"depth":282,"text":1021},{"id":1178,"depth":282,"text":1179},{"id":1518,"depth":282,"text":1519},{"id":1600,"depth":282,"text":1601},{"id":1669,"depth":282,"text":1670},{"id":1684,"depth":282,"text":1685},{"id":1729,"depth":282,"text":1730},"Select features with selectByExpression in PyQGIS, add to or subtract from a selection, iterate only the selected rows, and push the filter down to the data provider.","md",{"slug":1775,"type":1776,"breadcrumb":1777,"datePublished":1778,"dateModified":1778},"select-features-by-expression-pyqgis","article","Select by Expression","2026-08-01","\u002Fpyqgis-fundamentals-environment-setup\u002Fworking-with-qgis-expressions\u002Fselect-features-by-expression-pyqgis",{"title":5,"description":1772},"pyqgis-fundamentals-environment-setup\u002Fworking-with-qgis-expressions\u002Fselect-features-by-expression-pyqgis\u002Findex","FjLkrgq9WFvS8QTrF9laBK4ubAc1DMKMZ4TObGglygo",1785585990473]