[{"data":1,"prerenderedAt":2126},["ShallowReactive",2],{"doc:\u002Fspatial-data-processing-automation\u002Fchaining-processing-algorithms\u002Fchain-buffer-and-clip-pyqgis":3},{"id":4,"title":5,"body":6,"description":2114,"extension":2115,"meta":2116,"navigation":120,"path":2122,"seo":2123,"stem":2124,"__hash__":2125},"docs\u002Fspatial-data-processing-automation\u002Fchaining-processing-algorithms\u002Fchain-buffer-and-clip-pyqgis\u002Findex.md","Chain Buffer and Clip in PyQGIS",{"type":7,"value":8,"toc":2100},"minimark",[9,13,32,35,40,68,80,84,87,324,354,358,368,582,610,614,628,719,761,764,869,872,876,879,1037,1528,1558,1562,1569,1670,1705,1709,1715,1837,1844,1848,1861,1910,1923,1927,1943,1959,1967,1973,1992,1996,2011,2015,2027,2045,2058,2071,2075,2096],[10,11,5],"h1",{"id":12},"chain-buffer-and-clip-in-pyqgis",[14,15,16,17,21,22,25,26,31],"p",{},"Buffering a vector layer and then clipping the result to a study area is one of the most common two-step operations in GIS. Done by hand it is two toolbox dialogs, two intermediate files, and two manual checks. Done in PyQGIS it is a single script: run ",[18,19,20],"code",{},"native:buffer",", pass its output straight into ",[18,23,24],{},"native:clip"," using a temporary intermediate, then write only the final layer to disk. This page is a focused, runnable recipe for exactly that chain, and it builds on the general patterns in ",[27,28,30],"a",{"href":29},"\u002Fspatial-data-processing-automation\u002Fchaining-processing-algorithms\u002F","Chaining Processing Algorithms in PyQGIS",".",[14,33,34],{},"The goal is a script you can paste into the QGIS Python Console, point at your data, and trust: it reports progress, validates inputs and outputs, and never leaves a stray buffer file behind because the intermediate lives in memory.",[36,37,39],"h2",{"id":38},"prerequisites","Prerequisites",[41,42,43,51,54,61],"ul",{},[44,45,46,50],"li",{},[47,48,49],"strong",{},"QGIS 3.34 LTR"," (Python 3.12) recommended; the script also runs on 3.28 LTR and the 3.40\u002F3.44 line.",[44,52,53],{},"A source vector layer (points, lines, or polygons) and an overlay polygon layer defining the area to keep.",[44,55,56,57,60],{},"Both layers in the ",[47,58,59],{},"same CRS",", or a destination CRS set on the context. Buffer distances are in the layer's map units, so a projected CRS in metres is strongly preferred.",[44,62,63,64,67],{},"The ",[18,65,66],{},"processing"," module available — automatic in the QGIS Python Console.",[14,69,70,71,75,76,79],{},"If you have never invoked a single algorithm from code, read ",[27,72,74],{"href":73},"\u002Fspatial-data-processing-automation\u002Fbatch-processing-with-pyqgis\u002Frun-processing-algorithm-from-script\u002F","running a processing algorithm from a script"," first; this page assumes you can make one ",[18,77,78],{},"processing.run()"," call and chains two of them.",[36,81,83],{"id":82},"step-1-validate-inputs-before-running-anything","Step 1: Validate Inputs Before Running Anything",[14,85,86],{},"A chain that fails on step two after a slow step one wastes time. Validate both layers and warn on geographic CRS up front.",[88,89,94],"pre",{"className":90,"code":91,"language":92,"meta":93,"style":93},"language-python shiki shiki-themes github-dark","from qgis.core import QgsVectorLayer\n\n\ndef load_and_check(path: str, name: str) -> QgsVectorLayer:\n    layer = QgsVectorLayer(path, name, \"ogr\")\n    if not layer.isValid():\n        raise ValueError(f\"Could not load {name}: {path}\")\n    if layer.featureCount() == 0:\n        raise ValueError(f\"{name} has no features: {path}\")\n    if layer.crs().isGeographic():\n        print(f\"WARNING: {name} is in a geographic CRS; buffer distance is in \"\n              f\"degrees, not metres. Reproject to a projected CRS first.\")\n    return layer\n","python","",[18,95,96,115,122,127,152,171,183,225,242,274,282,304,315],{"__ignoreMap":93},[97,98,101,105,109,112],"span",{"class":99,"line":100},"line",1,[97,102,104],{"class":103},"snl16","from",[97,106,108],{"class":107},"s95oV"," qgis.core ",[97,110,111],{"class":103},"import",[97,113,114],{"class":107}," QgsVectorLayer\n",[97,116,118],{"class":99,"line":117},2,[97,119,121],{"emptyLinePlaceholder":120},true,"\n",[97,123,125],{"class":99,"line":124},3,[97,126,121],{"emptyLinePlaceholder":120},[97,128,130,133,137,140,144,147,149],{"class":99,"line":129},4,[97,131,132],{"class":103},"def",[97,134,136],{"class":135},"svObZ"," load_and_check",[97,138,139],{"class":107},"(path: ",[97,141,143],{"class":142},"sDLfK","str",[97,145,146],{"class":107},", name: ",[97,148,143],{"class":142},[97,150,151],{"class":107},") -> QgsVectorLayer:\n",[97,153,155,158,161,164,168],{"class":99,"line":154},5,[97,156,157],{"class":107},"    layer ",[97,159,160],{"class":103},"=",[97,162,163],{"class":107}," QgsVectorLayer(path, name, ",[97,165,167],{"class":166},"sU2Wk","\"ogr\"",[97,169,170],{"class":107},")\n",[97,172,174,177,180],{"class":99,"line":173},6,[97,175,176],{"class":103},"    if",[97,178,179],{"class":103}," not",[97,181,182],{"class":107}," layer.isValid():\n",[97,184,186,189,192,195,198,201,204,207,210,213,215,218,220,223],{"class":99,"line":185},7,[97,187,188],{"class":103},"        raise",[97,190,191],{"class":142}," ValueError",[97,193,194],{"class":107},"(",[97,196,197],{"class":103},"f",[97,199,200],{"class":166},"\"Could not load ",[97,202,203],{"class":142},"{",[97,205,206],{"class":107},"name",[97,208,209],{"class":142},"}",[97,211,212],{"class":166},": ",[97,214,203],{"class":142},[97,216,217],{"class":107},"path",[97,219,209],{"class":142},[97,221,222],{"class":166},"\"",[97,224,170],{"class":107},[97,226,228,230,233,236,239],{"class":99,"line":227},8,[97,229,176],{"class":103},[97,231,232],{"class":107}," layer.featureCount() ",[97,234,235],{"class":103},"==",[97,237,238],{"class":142}," 0",[97,240,241],{"class":107},":\n",[97,243,245,247,249,251,253,255,257,259,261,264,266,268,270,272],{"class":99,"line":244},9,[97,246,188],{"class":103},[97,248,191],{"class":142},[97,250,194],{"class":107},[97,252,197],{"class":103},[97,254,222],{"class":166},[97,256,203],{"class":142},[97,258,206],{"class":107},[97,260,209],{"class":142},[97,262,263],{"class":166}," has no features: ",[97,265,203],{"class":142},[97,267,217],{"class":107},[97,269,209],{"class":142},[97,271,222],{"class":166},[97,273,170],{"class":107},[97,275,277,279],{"class":99,"line":276},10,[97,278,176],{"class":103},[97,280,281],{"class":107}," layer.crs().isGeographic():\n",[97,283,285,288,290,292,295,297,299,301],{"class":99,"line":284},11,[97,286,287],{"class":142},"        print",[97,289,194],{"class":107},[97,291,197],{"class":103},[97,293,294],{"class":166},"\"WARNING: ",[97,296,203],{"class":142},[97,298,206],{"class":107},[97,300,209],{"class":142},[97,302,303],{"class":166}," is in a geographic CRS; buffer distance is in \"\n",[97,305,307,310,313],{"class":99,"line":306},12,[97,308,309],{"class":103},"              f",[97,311,312],{"class":166},"\"degrees, not metres. Reproject to a projected CRS first.\"",[97,314,170],{"class":107},[97,316,318,321],{"class":99,"line":317},13,[97,319,320],{"class":103},"    return",[97,322,323],{"class":107}," layer\n",[14,325,326,329,330,333,334,337,338,341,342,345,346,349,350,353],{},[47,327,328],{},"Breakdown:"," ",[18,331,332],{},"QgsVectorLayer(path, name, \"ogr\")"," opens the file through the OGR provider. ",[18,335,336],{},"isValid()"," catches bad paths and unsupported formats; an empty ",[18,339,340],{},"featureCount()"," catches a file that loads but contains nothing to process. The ",[18,343,344],{},"crs().isGeographic()"," check is the single most useful guard for buffering — a ",[18,347,348],{},"DISTANCE"," of ",[18,351,352],{},"250"," against EPSG:4326 buffers by 250 degrees, which silently produces nonsense rather than an error.",[36,355,357],{"id":356},"step-2-buffer-into-a-temporary-output","Step 2: Buffer into a Temporary Output",[14,359,360,361,363,364,367],{},"Run ",[18,362,20],{}," and request ",[18,365,366],{},"'TEMPORARY_OUTPUT'"," so the framework keeps the result without writing a file you would have to delete.",[88,369,371],{"className":90,"code":370,"language":92,"meta":93,"style":93},"import processing\nfrom qgis.core import QgsProcessingContext, QgsProcessingFeedback, QgsProject\n\n\ndef buffer_layer(source, distance_m, context, feedback):\n    feedback.pushInfo(f\"Buffering by {distance_m} m ...\")\n    result = processing.run(\"native:buffer\", {\n        \"INPUT\": source,\n        \"DISTANCE\": distance_m,\n        \"SEGMENTS\": 8,\n        \"END_CAP_STYLE\": 0,      # 0 = round\n        \"JOIN_STYLE\": 0,         # 0 = round\n        \"MITER_LIMIT\": 2,\n        \"DISSOLVE\": False,\n        \"OUTPUT\": \"TEMPORARY_OUTPUT\",\n    }, context=context, feedback=feedback)\n    return result[\"OUTPUT\"]\n",[18,372,373,380,391,395,399,409,431,447,455,463,476,493,507,519,532,545,568],{"__ignoreMap":93},[97,374,375,377],{"class":99,"line":100},[97,376,111],{"class":103},[97,378,379],{"class":107}," processing\n",[97,381,382,384,386,388],{"class":99,"line":117},[97,383,104],{"class":103},[97,385,108],{"class":107},[97,387,111],{"class":103},[97,389,390],{"class":107}," QgsProcessingContext, QgsProcessingFeedback, QgsProject\n",[97,392,393],{"class":99,"line":124},[97,394,121],{"emptyLinePlaceholder":120},[97,396,397],{"class":99,"line":129},[97,398,121],{"emptyLinePlaceholder":120},[97,400,401,403,406],{"class":99,"line":154},[97,402,132],{"class":103},[97,404,405],{"class":135}," buffer_layer",[97,407,408],{"class":107},"(source, distance_m, context, feedback):\n",[97,410,411,414,416,419,421,424,426,429],{"class":99,"line":173},[97,412,413],{"class":107},"    feedback.pushInfo(",[97,415,197],{"class":103},[97,417,418],{"class":166},"\"Buffering by ",[97,420,203],{"class":142},[97,422,423],{"class":107},"distance_m",[97,425,209],{"class":142},[97,427,428],{"class":166}," m ...\"",[97,430,170],{"class":107},[97,432,433,436,438,441,444],{"class":99,"line":185},[97,434,435],{"class":107},"    result ",[97,437,160],{"class":103},[97,439,440],{"class":107}," processing.run(",[97,442,443],{"class":166},"\"native:buffer\"",[97,445,446],{"class":107},", {\n",[97,448,449,452],{"class":99,"line":227},[97,450,451],{"class":166},"        \"INPUT\"",[97,453,454],{"class":107},": source,\n",[97,456,457,460],{"class":99,"line":244},[97,458,459],{"class":166},"        \"DISTANCE\"",[97,461,462],{"class":107},": distance_m,\n",[97,464,465,468,470,473],{"class":99,"line":276},[97,466,467],{"class":166},"        \"SEGMENTS\"",[97,469,212],{"class":107},[97,471,472],{"class":142},"8",[97,474,475],{"class":107},",\n",[97,477,478,481,483,486,489],{"class":99,"line":284},[97,479,480],{"class":166},"        \"END_CAP_STYLE\"",[97,482,212],{"class":107},[97,484,485],{"class":142},"0",[97,487,488],{"class":107},",      ",[97,490,492],{"class":491},"sjoCn","# 0 = round\n",[97,494,495,498,500,502,505],{"class":99,"line":306},[97,496,497],{"class":166},"        \"JOIN_STYLE\"",[97,499,212],{"class":107},[97,501,485],{"class":142},[97,503,504],{"class":107},",         ",[97,506,492],{"class":491},[97,508,509,512,514,517],{"class":99,"line":317},[97,510,511],{"class":166},"        \"MITER_LIMIT\"",[97,513,212],{"class":107},[97,515,516],{"class":142},"2",[97,518,475],{"class":107},[97,520,522,525,527,530],{"class":99,"line":521},14,[97,523,524],{"class":166},"        \"DISSOLVE\"",[97,526,212],{"class":107},[97,528,529],{"class":142},"False",[97,531,475],{"class":107},[97,533,535,538,540,543],{"class":99,"line":534},15,[97,536,537],{"class":166},"        \"OUTPUT\"",[97,539,212],{"class":107},[97,541,542],{"class":166},"\"TEMPORARY_OUTPUT\"",[97,544,475],{"class":107},[97,546,548,551,555,557,560,563,565],{"class":99,"line":547},16,[97,549,550],{"class":107},"    }, ",[97,552,554],{"class":553},"s9osk","context",[97,556,160],{"class":103},[97,558,559],{"class":107},"context, ",[97,561,562],{"class":553},"feedback",[97,564,160],{"class":103},[97,566,567],{"class":107},"feedback)\n",[97,569,571,573,576,579],{"class":99,"line":570},17,[97,572,320],{"class":103},[97,574,575],{"class":107}," result[",[97,577,578],{"class":166},"\"OUTPUT\"",[97,580,581],{"class":107},"]\n",[14,583,584,586,587,589,590,593,594,597,598,601,602,605,606,609],{},[47,585,328],{}," Every key here is a real ",[18,588,20],{}," parameter. ",[18,591,592],{},"SEGMENTS"," controls how many line segments approximate each quarter-circle (8 is a good default). ",[18,595,596],{},"DISSOLVE=False"," keeps one buffer polygon per input feature; set it ",[18,599,600],{},"True"," to merge overlaps. The return value ",[18,603,604],{},"result[\"OUTPUT\"]"," is a ",[18,607,608],{},"QgsVectorLayer"," held in memory — it is what step three consumes, never a path on disk.",[36,611,613],{"id":612},"step-3-clip-the-buffer-to-the-study-area","Step 3: Clip the Buffer to the Study Area",[14,615,616,617,619,620,623,624,627],{},"Feed the buffer's output straight into ",[18,618,24],{}," as its ",[18,621,622],{},"INPUT",", using the study-area polygon as the ",[18,625,626],{},"OVERLAY",". This is the join that makes it a chain.",[88,629,631],{"className":90,"code":630,"language":92,"meta":93,"style":93},"def clip_to_area(buffered_layer, overlay, out_path, context, feedback):\n    feedback.pushInfo(\"Clipping buffer to study area ...\")\n    result = processing.run(\"native:clip\", {\n        \"INPUT\": buffered_layer,     # the OUTPUT from native:buffer\n        \"OVERLAY\": overlay,\n        \"OUTPUT\": out_path,          # final result -> permanent file\n    }, context=context, feedback=feedback)\n    return result[\"OUTPUT\"]\n",[18,632,633,643,652,665,675,683,693,709],{"__ignoreMap":93},[97,634,635,637,640],{"class":99,"line":100},[97,636,132],{"class":103},[97,638,639],{"class":135}," clip_to_area",[97,641,642],{"class":107},"(buffered_layer, overlay, out_path, context, feedback):\n",[97,644,645,647,650],{"class":99,"line":117},[97,646,413],{"class":107},[97,648,649],{"class":166},"\"Clipping buffer to study area ...\"",[97,651,170],{"class":107},[97,653,654,656,658,660,663],{"class":99,"line":124},[97,655,435],{"class":107},[97,657,160],{"class":103},[97,659,440],{"class":107},[97,661,662],{"class":166},"\"native:clip\"",[97,664,446],{"class":107},[97,666,667,669,672],{"class":99,"line":129},[97,668,451],{"class":166},[97,670,671],{"class":107},": buffered_layer,     ",[97,673,674],{"class":491},"# the OUTPUT from native:buffer\n",[97,676,677,680],{"class":99,"line":154},[97,678,679],{"class":166},"        \"OVERLAY\"",[97,681,682],{"class":107},": overlay,\n",[97,684,685,687,690],{"class":99,"line":173},[97,686,537],{"class":166},[97,688,689],{"class":107},": out_path,          ",[97,691,692],{"class":491},"# final result -> permanent file\n",[97,694,695,697,699,701,703,705,707],{"class":99,"line":185},[97,696,550],{"class":107},[97,698,554],{"class":553},[97,700,160],{"class":103},[97,702,559],{"class":107},[97,704,562],{"class":553},[97,706,160],{"class":103},[97,708,567],{"class":107},[97,710,711,713,715,717],{"class":99,"line":227},[97,712,320],{"class":103},[97,714,575],{"class":107},[97,716,578],{"class":166},[97,718,581],{"class":107},[14,720,721,329,723,725,726,728,729,732,733,736,737,741,742,744,745,748,749,752,753,757,758,760],{},[47,722,328],{},[18,724,622],{}," is the in-memory buffer layer object returned by step two — no filename is involved between buffer and clip. ",[18,727,626],{}," is the polygon layer that defines what to keep. Because this is the final step, ",[18,730,731],{},"OUTPUT"," is a real path (for example ",[18,734,735],{},"\u002Fdata\u002Fbuffer_clipped.gpkg","), so the result is written to disk. If you would rather keep only features that ",[738,739,740],"em",{},"intersect"," the area without trimming their geometry, swap ",[18,743,24],{}," for ",[18,746,747],{},"native:extractbylocation"," with ",[18,750,751],{},"PREDICATE: [0]"," (intersects). For the geometry-trimming behaviour described in the dedicated ",[27,754,756],{"href":755},"\u002Fspatial-data-processing-automation\u002Fvector-data-manipulation\u002Fclip-vector-layer-pyqgis\u002F","clip a vector layer in PyQGIS"," guide, ",[18,759,24],{}," is correct.",[14,762,763],{},"The order of the two steps is not interchangeable, and reversing it answers a different question entirely.",[14,765,766],{},[767,768,773,777,781,787,796,841],"svg",{"viewBox":769,"role":770,"ariaLabel":771,"xmlns":772},"0 0 760 246","img","Buffer then clip compared with clip then buffer on the same inputs, producing different results because the second order buffers outward past the study boundary","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg",[774,775,776],"title",{},"Buffer-then-clip is not the same as clip-then-buffer",[778,779,780],"desc",{},"The same road and study area are processed twice. Buffering first and clipping second produces a corridor that stops exactly at the study boundary. Clipping first and buffering second trims the road at the boundary and then expands outward from the cut end, so the result spills past the study area.",[782,783],"rect",{"x":485,"y":485,"width":784,"height":785,"fill":786},"760","246","#f6f3ea",[788,789,795],"text",{"x":790,"y":791,"style":792,"fill":793,"textAnchor":794},"380","26","text-anchor:middle;font-size:14px;font-weight:bold;font-family:sans-serif","#17211d","middle","Swap the order and the corridor leaks past the boundary",[797,798,799,809,815,824,829,832,836],"g",{},[782,800],{"x":801,"y":802,"width":803,"height":804,"rx":805,"fill":806,"stroke":807,"style":808},"16","46","356","184","10","#fffdf7","#15803d","stroke-width:2.5",[788,810,814],{"x":811,"y":812,"style":813,"fill":807,"textAnchor":794},"194","70","text-anchor:middle;font-size:12px;font-weight:bold;font-family:sans-serif","buffer → clip",[782,816],{"x":817,"y":818,"width":819,"height":820,"fill":821,"fillOpacity":822,"stroke":821,"style":823},"52","88","200","118","#0f766e",0.08,"stroke-width:2;stroke-dasharray:5 4",[217,825],{"d":826,"fill":827,"stroke":807,"style":828},"M60 190 L120 140 L196 164 L252 118","none","stroke-width:26;stroke-opacity:0.3;stroke-linecap:butt;stroke-linejoin:round",[217,830],{"d":826,"fill":827,"stroke":831,"style":808},"#2563eb",[217,833],{"d":834,"fill":827,"stroke":831,"style":835},"M252 118 L332 96","stroke-width:2.5;stroke-dasharray:4 3",[788,837,840],{"x":811,"y":838,"style":839,"fill":807,"textAnchor":794},"222","text-anchor:middle;font-size:11px;font-family:sans-serif","corridor stops at the boundary",[797,842,843,847,851,854,858,860,866],{},[782,844],{"x":845,"y":802,"width":803,"height":804,"rx":805,"fill":806,"stroke":846,"style":808},"388","#b91c1c",[788,848,850],{"x":849,"y":812,"style":813,"fill":846,"textAnchor":794},"566","clip → buffer",[782,852],{"x":853,"y":818,"width":819,"height":820,"fill":821,"fillOpacity":822,"stroke":821,"style":823},"424",[217,855],{"d":856,"fill":827,"stroke":846,"style":857},"M432 190 L492 140 L568 164 L624 118","stroke-width:26;stroke-opacity:0.3;stroke-linecap:round;stroke-linejoin:round",[217,859],{"d":856,"fill":827,"stroke":831,"style":808},[861,862],"circle",{"cx":863,"cy":820,"r":864,"fill":827,"stroke":846,"style":865},"624","14","stroke-width:2",[788,867,868],{"x":849,"y":838,"style":839,"fill":846,"textAnchor":794},"rounded cap spills outside",[14,870,871],{},"Buffer first when the question is \"what is within 50 m of a road, inside this area\". Clip first only when the roads themselves must be trimmed before anything else happens — and expect the buffer to extend beyond the study boundary if you do.",[36,873,875],{"id":874},"step-4-assemble-and-run-the-full-chain","Step 4: Assemble and Run the Full Chain",[14,877,878],{},"The orchestrator wires the three steps together, shares one context and one feedback object, and validates the final output.",[767,880,883,884,883,887,883,890,883,893,883,883,898,883,903,883,909,883,915,883,883,920,883,925,883,931,883,935,883,938,883,940,883,943,883,945,883,947,883,950,883,955,883,960,883,883,963,883,968,883,972,883,976,883,980,883,883,985,883,990,883,883,996,883,1000,883,1005,883,1009,883,1014,883,1016],{"viewBox":881,"role":770,"ariaLabel":882,"xmlns":772},"0 0 760 340","Data-flow diagram of the buffer-then-clip chain: a source layer is buffered to a temporary in-memory output, clipped against a study-area overlay, and only the final result is written to a GeoPackage on disk","\n  ",[774,885,886],{},"Buffer-then-clip chain data flow",[778,888,889],{},"The source layer flows into native:buffer producing a TEMPORARY_OUTPUT held in memory; that in-memory layer becomes the INPUT of native:clip, which uses the study-area polygon as its OVERLAY; only the final clip step writes a GeoPackage to disk. A single shared processing context and feedback object spans both algorithm steps.",[782,891],{"x":485,"y":485,"width":784,"height":892,"fill":786},"340",[788,894,897],{"x":790,"y":895,"fill":793,"style":896,"textAnchor":794},"30","text-anchor:middle;font-family:sans-serif;font-size:15px;font-weight:bold","Buffer → Clip: one in-memory intermediate, one written result",[782,899],{"x":900,"y":817,"width":901,"height":817,"rx":472,"fill":806,"stroke":902,"style":808},"360","120","#b45309",[788,904,908],{"x":905,"y":906,"fill":793,"style":907,"textAnchor":794},"420","76","text-anchor:middle;font-family:sans-serif;font-size:12px;font-weight:bold","Study area",[788,910,914],{"x":905,"y":911,"fill":912,"style":913,"textAnchor":794},"93","#2f3b35","text-anchor:middle;font-family:sans-serif;font-size:11px","OVERLAY polygon",[99,916],{"x1":905,"y1":917,"x2":905,"y2":918,"stroke":902,"style":919},"104","138","stroke-width:2.5;marker-end:url(#ar)",[782,921],{"x":922,"y":923,"width":901,"height":924,"rx":472,"fill":806,"stroke":821,"style":808},"20","140","64",[788,926,930],{"x":927,"y":928,"fill":793,"style":929,"textAnchor":794},"80","168","text-anchor:middle;font-family:sans-serif;font-size:13px;font-weight:bold","Source",[788,932,934],{"x":927,"y":933,"fill":912,"style":913,"textAnchor":794},"187","layer.gpkg",[782,936],{"x":937,"y":923,"width":923,"height":924,"rx":472,"fill":806,"stroke":831,"style":808},"180",[788,939,20],{"x":352,"y":928,"fill":793,"style":929,"textAnchor":794},[788,941,942],{"x":352,"y":933,"fill":912,"style":913,"textAnchor":794},"TEMPORARY_OUTPUT",[782,944],{"x":900,"y":923,"width":901,"height":924,"rx":472,"fill":806,"stroke":831,"style":808},[788,946,24],{"x":905,"y":928,"fill":793,"style":929,"textAnchor":794},[788,948,949],{"x":905,"y":933,"fill":912,"style":913,"textAnchor":794},"INPUT + OVERLAY",[782,951],{"x":952,"y":923,"width":953,"height":924,"rx":472,"fill":954,"stroke":807,"style":808},"600","130","#26322d",[788,956,959],{"x":957,"y":928,"fill":958,"style":929,"textAnchor":794},"665","#d9f99d","Write result",[788,961,962],{"x":957,"y":933,"fill":958,"style":913,"textAnchor":794},"clipped.gpkg",[99,964],{"x1":923,"y1":965,"x2":966,"y2":965,"stroke":912,"style":967},"172","178","stroke-width:2.5;marker-end:url(#ar2)",[99,969],{"x1":970,"y1":965,"x2":971,"y2":965,"stroke":912,"style":967},"320","358",[99,973],{"x1":974,"y1":965,"x2":975,"y2":965,"stroke":912,"style":967},"480","598",[788,977,979],{"x":892,"y":953,"fill":902,"style":978,"textAnchor":794},"text-anchor:middle;font-family:sans-serif;font-size:10px","OUTPUT (in memory)",[788,981,984],{"x":982,"y":983,"fill":807,"style":978,"textAnchor":794},"539","162","final OUTPUT → disk",[99,986],{"x1":987,"y1":820,"x2":987,"y2":988,"stroke":807,"style":989},"540","290","stroke-width:1.5;stroke-dasharray:5 4;opacity:0.6",[788,991,995],{"x":992,"y":993,"fill":807,"style":994,"textAnchor":794},"640","228","text-anchor:middle;font-family:sans-serif;font-size:10px;font-weight:bold","only step to touch disk",[782,997],{"x":937,"y":352,"width":998,"height":802,"rx":472,"fill":806,"stroke":902,"style":999},"300","stroke-width:2.5;stroke-dasharray:6 4",[788,1001,1004],{"x":1002,"y":1003,"fill":793,"style":907,"textAnchor":794},"330","270","shared QgsProcessingContext",[788,1006,1008],{"x":1002,"y":1007,"fill":912,"style":913,"textAnchor":794},"287","+ ProgressFeedback",[99,1010],{"x1":352,"y1":1011,"x2":352,"y2":1012,"stroke":902,"style":1013},"204","248","stroke-width:2;stroke-dasharray:4 3",[99,1015],{"x1":905,"y1":1011,"x2":905,"y2":1012,"stroke":902,"style":1013},[1017,1018,1019,1020,1019,1032,883],"defs",{},"\n    ",[1021,1022,1028,1029,1019],"marker",{"id":1023,"markerWidth":1024,"markerHeight":1024,"refX":1025,"refY":1026,"orient":1027},"ar","9","7","4","auto","\n      ",[217,1030],{"d":1031,"fill":902},"M0,0 L8,4 L0,8 Z",[1021,1033,1028,1035,1019],{"id":1034,"markerWidth":1024,"markerHeight":1024,"refX":1025,"refY":1026,"orient":1027},"ar2",[217,1036],{"d":1031,"fill":912},[88,1038,1040],{"className":90,"code":1039,"language":92,"meta":93,"style":93},"import processing\nfrom qgis.core import (\n    QgsVectorLayer,\n    QgsProcessingContext,\n    QgsProcessingFeedback,\n    QgsProcessingException,\n    QgsProject,\n)\n\n\nclass ProgressFeedback(QgsProcessingFeedback):\n    def setProgress(self, progress):\n        print(f\"\\r  {progress:5.1f}%\", end=\"\", flush=True)\n\n    def pushInfo(self, info):\n        print(f\"\\n{info}\")\n\n\ndef buffer_then_clip(source_path, overlay_path, out_path, distance_m):\n    source = load_and_check(source_path, \"source\")\n    overlay = load_and_check(overlay_path, \"overlay\")\n\n    context = QgsProcessingContext()\n    context.setProject(QgsProject.instance())\n    feedback = ProgressFeedback()\n\n    try:\n        buffered = buffer_layer(source, distance_m, context, feedback)\n        final = clip_to_area(buffered, overlay, out_path, context, feedback)\n    except QgsProcessingException as exc:\n        feedback.pushInfo(f\"Pipeline failed: {exc}\")\n        raise\n\n    # Validate the written result\n    written = QgsVectorLayer(out_path, \"result\", \"ogr\")\n    if not written.isValid():\n        raise RuntimeError(f\"Final output is not a valid layer: {out_path}\")\n    feedback.pushInfo(f\"Done. {written.featureCount()} features written to {out_path}\")\n    return written\n\n\n# Run in the QGIS Python Console:\n# buffer_then_clip(\n#     \"\u002Fdata\u002Fwells.gpkg\",\n#     \"\u002Fdata\u002Fcatchment.gpkg\",\n#     \"\u002Fdata\u002Fwells_buffer_clipped.gpkg\",\n#     distance_m=500,\n# )\n",[18,1041,1042,1048,1059,1064,1069,1074,1079,1084,1088,1092,1096,1112,1123,1172,1176,1186,1208,1212,1217,1228,1244,1260,1265,1276,1282,1293,1298,1306,1317,1328,1343,1365,1371,1376,1382,1402,1412,1438,1468,1476,1481,1486,1492,1498,1504,1510,1516,1522],{"__ignoreMap":93},[97,1043,1044,1046],{"class":99,"line":100},[97,1045,111],{"class":103},[97,1047,379],{"class":107},[97,1049,1050,1052,1054,1056],{"class":99,"line":117},[97,1051,104],{"class":103},[97,1053,108],{"class":107},[97,1055,111],{"class":103},[97,1057,1058],{"class":107}," (\n",[97,1060,1061],{"class":99,"line":124},[97,1062,1063],{"class":107},"    QgsVectorLayer,\n",[97,1065,1066],{"class":99,"line":129},[97,1067,1068],{"class":107},"    QgsProcessingContext,\n",[97,1070,1071],{"class":99,"line":154},[97,1072,1073],{"class":107},"    QgsProcessingFeedback,\n",[97,1075,1076],{"class":99,"line":173},[97,1077,1078],{"class":107},"    QgsProcessingException,\n",[97,1080,1081],{"class":99,"line":185},[97,1082,1083],{"class":107},"    QgsProject,\n",[97,1085,1086],{"class":99,"line":227},[97,1087,170],{"class":107},[97,1089,1090],{"class":99,"line":244},[97,1091,121],{"emptyLinePlaceholder":120},[97,1093,1094],{"class":99,"line":276},[97,1095,121],{"emptyLinePlaceholder":120},[97,1097,1098,1101,1104,1106,1109],{"class":99,"line":284},[97,1099,1100],{"class":103},"class",[97,1102,1103],{"class":135}," ProgressFeedback",[97,1105,194],{"class":107},[97,1107,1108],{"class":135},"QgsProcessingFeedback",[97,1110,1111],{"class":107},"):\n",[97,1113,1114,1117,1120],{"class":99,"line":306},[97,1115,1116],{"class":103},"    def",[97,1118,1119],{"class":135}," setProgress",[97,1121,1122],{"class":107},"(self, progress):\n",[97,1124,1125,1127,1129,1131,1133,1136,1139,1142,1145,1147,1150,1153,1156,1158,1161,1163,1166,1168,1170],{"class":99,"line":317},[97,1126,287],{"class":142},[97,1128,194],{"class":107},[97,1130,197],{"class":103},[97,1132,222],{"class":166},[97,1134,1135],{"class":142},"\\r",[97,1137,1138],{"class":142},"  {",[97,1140,1141],{"class":107},"progress",[97,1143,1144],{"class":103},":5.1f",[97,1146,209],{"class":142},[97,1148,1149],{"class":166},"%\"",[97,1151,1152],{"class":107},", ",[97,1154,1155],{"class":553},"end",[97,1157,160],{"class":103},[97,1159,1160],{"class":166},"\"\"",[97,1162,1152],{"class":107},[97,1164,1165],{"class":553},"flush",[97,1167,160],{"class":103},[97,1169,600],{"class":142},[97,1171,170],{"class":107},[97,1173,1174],{"class":99,"line":521},[97,1175,121],{"emptyLinePlaceholder":120},[97,1177,1178,1180,1183],{"class":99,"line":534},[97,1179,1116],{"class":103},[97,1181,1182],{"class":135}," pushInfo",[97,1184,1185],{"class":107},"(self, info):\n",[97,1187,1188,1190,1192,1194,1196,1199,1202,1204,1206],{"class":99,"line":547},[97,1189,287],{"class":142},[97,1191,194],{"class":107},[97,1193,197],{"class":103},[97,1195,222],{"class":166},[97,1197,1198],{"class":142},"\\n{",[97,1200,1201],{"class":107},"info",[97,1203,209],{"class":142},[97,1205,222],{"class":166},[97,1207,170],{"class":107},[97,1209,1210],{"class":99,"line":570},[97,1211,121],{"emptyLinePlaceholder":120},[97,1213,1215],{"class":99,"line":1214},18,[97,1216,121],{"emptyLinePlaceholder":120},[97,1218,1220,1222,1225],{"class":99,"line":1219},19,[97,1221,132],{"class":103},[97,1223,1224],{"class":135}," buffer_then_clip",[97,1226,1227],{"class":107},"(source_path, overlay_path, out_path, distance_m):\n",[97,1229,1231,1234,1236,1239,1242],{"class":99,"line":1230},20,[97,1232,1233],{"class":107},"    source ",[97,1235,160],{"class":103},[97,1237,1238],{"class":107}," load_and_check(source_path, ",[97,1240,1241],{"class":166},"\"source\"",[97,1243,170],{"class":107},[97,1245,1247,1250,1252,1255,1258],{"class":99,"line":1246},21,[97,1248,1249],{"class":107},"    overlay ",[97,1251,160],{"class":103},[97,1253,1254],{"class":107}," load_and_check(overlay_path, ",[97,1256,1257],{"class":166},"\"overlay\"",[97,1259,170],{"class":107},[97,1261,1263],{"class":99,"line":1262},22,[97,1264,121],{"emptyLinePlaceholder":120},[97,1266,1268,1271,1273],{"class":99,"line":1267},23,[97,1269,1270],{"class":107},"    context ",[97,1272,160],{"class":103},[97,1274,1275],{"class":107}," QgsProcessingContext()\n",[97,1277,1279],{"class":99,"line":1278},24,[97,1280,1281],{"class":107},"    context.setProject(QgsProject.instance())\n",[97,1283,1285,1288,1290],{"class":99,"line":1284},25,[97,1286,1287],{"class":107},"    feedback ",[97,1289,160],{"class":103},[97,1291,1292],{"class":107}," ProgressFeedback()\n",[97,1294,1296],{"class":99,"line":1295},26,[97,1297,121],{"emptyLinePlaceholder":120},[97,1299,1301,1304],{"class":99,"line":1300},27,[97,1302,1303],{"class":103},"    try",[97,1305,241],{"class":107},[97,1307,1309,1312,1314],{"class":99,"line":1308},28,[97,1310,1311],{"class":107},"        buffered ",[97,1313,160],{"class":103},[97,1315,1316],{"class":107}," buffer_layer(source, distance_m, context, feedback)\n",[97,1318,1320,1323,1325],{"class":99,"line":1319},29,[97,1321,1322],{"class":107},"        final ",[97,1324,160],{"class":103},[97,1326,1327],{"class":107}," clip_to_area(buffered, overlay, out_path, context, feedback)\n",[97,1329,1331,1334,1337,1340],{"class":99,"line":1330},30,[97,1332,1333],{"class":103},"    except",[97,1335,1336],{"class":107}," QgsProcessingException ",[97,1338,1339],{"class":103},"as",[97,1341,1342],{"class":107}," exc:\n",[97,1344,1346,1349,1351,1354,1356,1359,1361,1363],{"class":99,"line":1345},31,[97,1347,1348],{"class":107},"        feedback.pushInfo(",[97,1350,197],{"class":103},[97,1352,1353],{"class":166},"\"Pipeline failed: ",[97,1355,203],{"class":142},[97,1357,1358],{"class":107},"exc",[97,1360,209],{"class":142},[97,1362,222],{"class":166},[97,1364,170],{"class":107},[97,1366,1368],{"class":99,"line":1367},32,[97,1369,1370],{"class":103},"        raise\n",[97,1372,1374],{"class":99,"line":1373},33,[97,1375,121],{"emptyLinePlaceholder":120},[97,1377,1379],{"class":99,"line":1378},34,[97,1380,1381],{"class":491},"    # Validate the written result\n",[97,1383,1385,1388,1390,1393,1396,1398,1400],{"class":99,"line":1384},35,[97,1386,1387],{"class":107},"    written ",[97,1389,160],{"class":103},[97,1391,1392],{"class":107}," QgsVectorLayer(out_path, ",[97,1394,1395],{"class":166},"\"result\"",[97,1397,1152],{"class":107},[97,1399,167],{"class":166},[97,1401,170],{"class":107},[97,1403,1405,1407,1409],{"class":99,"line":1404},36,[97,1406,176],{"class":103},[97,1408,179],{"class":103},[97,1410,1411],{"class":107}," written.isValid():\n",[97,1413,1415,1417,1420,1422,1424,1427,1429,1432,1434,1436],{"class":99,"line":1414},37,[97,1416,188],{"class":103},[97,1418,1419],{"class":142}," RuntimeError",[97,1421,194],{"class":107},[97,1423,197],{"class":103},[97,1425,1426],{"class":166},"\"Final output is not a valid layer: ",[97,1428,203],{"class":142},[97,1430,1431],{"class":107},"out_path",[97,1433,209],{"class":142},[97,1435,222],{"class":166},[97,1437,170],{"class":107},[97,1439,1441,1443,1445,1448,1450,1453,1455,1458,1460,1462,1464,1466],{"class":99,"line":1440},38,[97,1442,413],{"class":107},[97,1444,197],{"class":103},[97,1446,1447],{"class":166},"\"Done. ",[97,1449,203],{"class":142},[97,1451,1452],{"class":107},"written.featureCount()",[97,1454,209],{"class":142},[97,1456,1457],{"class":166}," features written to ",[97,1459,203],{"class":142},[97,1461,1431],{"class":107},[97,1463,209],{"class":142},[97,1465,222],{"class":166},[97,1467,170],{"class":107},[97,1469,1471,1473],{"class":99,"line":1470},39,[97,1472,320],{"class":103},[97,1474,1475],{"class":107}," written\n",[97,1477,1479],{"class":99,"line":1478},40,[97,1480,121],{"emptyLinePlaceholder":120},[97,1482,1484],{"class":99,"line":1483},41,[97,1485,121],{"emptyLinePlaceholder":120},[97,1487,1489],{"class":99,"line":1488},42,[97,1490,1491],{"class":491},"# Run in the QGIS Python Console:\n",[97,1493,1495],{"class":99,"line":1494},43,[97,1496,1497],{"class":491},"# buffer_then_clip(\n",[97,1499,1501],{"class":99,"line":1500},44,[97,1502,1503],{"class":491},"#     \"\u002Fdata\u002Fwells.gpkg\",\n",[97,1505,1507],{"class":99,"line":1506},45,[97,1508,1509],{"class":491},"#     \"\u002Fdata\u002Fcatchment.gpkg\",\n",[97,1511,1513],{"class":99,"line":1512},46,[97,1514,1515],{"class":491},"#     \"\u002Fdata\u002Fwells_buffer_clipped.gpkg\",\n",[97,1517,1519],{"class":99,"line":1518},47,[97,1520,1521],{"class":491},"#     distance_m=500,\n",[97,1523,1525],{"class":99,"line":1524},48,[97,1526,1527],{"class":491},"# )\n",[14,1529,1530,1532,1533,1536,1537,1540,1541,1543,1544,1546,1547,1550,1551,1553,1554,31],{},[47,1531,328],{}," One ",[18,1534,1535],{},"QgsProcessingContext"," and one ",[18,1538,1539],{},"ProgressFeedback"," are created once and threaded through both algorithms, so progress and any destination-CRS policy are consistent across the chain. The buffer's in-memory ",[18,1542,731],{}," flows into the clip's ",[18,1545,622],{}," with no disk write between them. Wrapping both runs in a single ",[18,1548,1549],{},"try\u002Fexcept QgsProcessingException"," makes a failure in either step report clearly and stop. The final block re-opens the written file with a fresh ",[18,1552,608],{}," and confirms validity and feature count — proof the chain produced real data, not an empty shell. This mirrors the shared-context discipline detailed in ",[27,1555,1557],{"href":1556},"\u002Fspatial-data-processing-automation\u002Fbatch-processing-with-pyqgis\u002F","batch processing with PyQGIS",[36,1559,1561],{"id":1560},"optional-swap-clip-for-extract-by-location","Optional: Swap Clip for Extract by Location",[14,1563,1564,1566,1567,31],{},[18,1565,24],{}," trims geometry to the overlay boundary — a buffer that straddles the study-area edge comes out cut along that edge. Sometimes you instead want every whole feature whose buffer touches the area, with geometry untouched. That is ",[18,1568,747],{},[88,1570,1572],{"className":90,"code":1571,"language":92,"meta":93,"style":93},"def extract_intersecting(buffered_layer, reference, out_path, context, feedback):\n    feedback.pushInfo(\"Extracting buffers intersecting the area ...\")\n    result = processing.run(\"native:extractbylocation\", {\n        \"INPUT\": buffered_layer,\n        \"PREDICATE\": [0],          # 0 = intersects\n        \"INTERSECT\": reference,\n        \"OUTPUT\": out_path,\n    }, context=context, feedback=feedback)\n    return result[\"OUTPUT\"]\n",[18,1573,1574,1584,1593,1606,1613,1629,1637,1644,1660],{"__ignoreMap":93},[97,1575,1576,1578,1581],{"class":99,"line":100},[97,1577,132],{"class":103},[97,1579,1580],{"class":135}," extract_intersecting",[97,1582,1583],{"class":107},"(buffered_layer, reference, out_path, context, feedback):\n",[97,1585,1586,1588,1591],{"class":99,"line":117},[97,1587,413],{"class":107},[97,1589,1590],{"class":166},"\"Extracting buffers intersecting the area ...\"",[97,1592,170],{"class":107},[97,1594,1595,1597,1599,1601,1604],{"class":99,"line":124},[97,1596,435],{"class":107},[97,1598,160],{"class":103},[97,1600,440],{"class":107},[97,1602,1603],{"class":166},"\"native:extractbylocation\"",[97,1605,446],{"class":107},[97,1607,1608,1610],{"class":99,"line":129},[97,1609,451],{"class":166},[97,1611,1612],{"class":107},": buffered_layer,\n",[97,1614,1615,1618,1621,1623,1626],{"class":99,"line":154},[97,1616,1617],{"class":166},"        \"PREDICATE\"",[97,1619,1620],{"class":107},": [",[97,1622,485],{"class":142},[97,1624,1625],{"class":107},"],          ",[97,1627,1628],{"class":491},"# 0 = intersects\n",[97,1630,1631,1634],{"class":99,"line":173},[97,1632,1633],{"class":166},"        \"INTERSECT\"",[97,1635,1636],{"class":107},": reference,\n",[97,1638,1639,1641],{"class":99,"line":185},[97,1640,537],{"class":166},[97,1642,1643],{"class":107},": out_path,\n",[97,1645,1646,1648,1650,1652,1654,1656,1658],{"class":99,"line":227},[97,1647,550],{"class":107},[97,1649,554],{"class":553},[97,1651,160],{"class":103},[97,1653,559],{"class":107},[97,1655,562],{"class":553},[97,1657,160],{"class":103},[97,1659,567],{"class":107},[97,1661,1662,1664,1666,1668],{"class":99,"line":244},[97,1663,320],{"class":103},[97,1665,575],{"class":107},[97,1667,578],{"class":166},[97,1669,581],{"class":107},[14,1671,1672,329,1674,1677,1678,1680,1681,1684,1685,1687,1688,1691,1692,1695,1696,1698,1699,1701,1702,1704],{},[47,1673,328],{},[18,1675,1676],{},"PREDICATE"," is a list of integer codes (",[18,1679,485],{}," = intersects, ",[18,1682,1683],{},"1"," = contains, ",[18,1686,516],{}," = disjoint, and so on). With ",[18,1689,1690],{},"intersects",", any buffer polygon that overlaps the ",[18,1693,1694],{},"INTERSECT"," reference is kept in full — no trimming. ",[18,1697,622],{}," is still the buffer layer from step two, so the chain is identical up to the final operation; only the algorithm and the keep-vs-trim semantics differ. Choose ",[18,1700,24],{}," for cookie-cutter geometry and ",[18,1703,747],{}," for whole-feature selection.",[36,1706,1708],{"id":1707},"temporary-outputs-and-where-they-live","Temporary outputs and where they live",[14,1710,1711,1712,1714],{},"Every ",[18,1713,942],{}," in a chain becomes a real GeoPackage in the QGIS temp folder. Knowing that explains both why a long chain can fill a disk and why the intermediate results are inspectable when something goes wrong.",[14,1716,1717],{},[767,1718,1721,1724,1727,1730,1741,1744,1775,1779,1781,1785,1823,1826,1828,1830,1832],{"viewBox":1719,"role":770,"ariaLabel":1720,"xmlns":772},"0 0 760 238","A four-step chain where each temporary output is written to the temp folder, with only the final step writing to the intended destination",[774,1722,1723],{},"Where each step's output actually goes",[778,1725,1726],{},"A chain of four algorithms is shown. The first three write temporary GeoPackages into the QGIS temp folder, each of which can be opened and inspected. Only the final step writes to the intended output path. A note records that the temporary files persist until QGIS exits.",[782,1728],{"x":485,"y":485,"width":784,"height":1729,"fill":786},"238",[1017,1731,1732],{},[1021,1733,1738],{"id":1734,"viewBox":1735,"refX":472,"refY":1736,"markerWidth":1025,"markerHeight":1025,"orient":1737},"chainTmpArrow","0 0 10 10","5","auto-start-reverse",[217,1739],{"d":1740,"fill":821},"M0 0 L10 5 L0 10 z",[788,1742,1743],{"x":790,"y":791,"style":792,"fill":793,"textAnchor":794},"Three real files you did not ask for — and can inspect",[797,1745,1746,1749,1754,1756,1760,1763,1767,1771],{},[782,1747],{"x":801,"y":817,"width":1748,"height":817,"rx":472,"fill":806,"stroke":831,"style":865},"152",[788,1750,1753],{"x":1751,"y":1752,"style":839,"fill":912,"textAnchor":794},"92","83","fixgeometries",[782,1755],{"x":1011,"y":817,"width":1748,"height":817,"rx":472,"fill":806,"stroke":831,"style":865},[788,1757,1759],{"x":1758,"y":1752,"style":839,"fill":912,"textAnchor":794},"280","buffer",[782,1761],{"x":1762,"y":817,"width":1748,"height":817,"rx":472,"fill":806,"stroke":831,"style":865},"392",[788,1764,1766],{"x":1765,"y":1752,"style":839,"fill":912,"textAnchor":794},"468","clip",[782,1768],{"x":1769,"y":817,"width":1770,"height":817,"rx":472,"fill":954,"stroke":821,"style":808},"580","164",[788,1772,1774],{"x":1773,"y":1752,"style":839,"fill":958,"textAnchor":794},"662","dissolve → file",[99,1776],{"x1":928,"y1":1777,"x2":819,"y2":1777,"stroke":821,"style":1778},"78","stroke-width:2;marker-end:url(#chainTmpArrow)",[99,1780],{"x1":803,"y1":1777,"x2":845,"y2":1777,"stroke":821,"style":1778},[99,1782],{"x1":1783,"y1":1777,"x2":1784,"y2":1777,"stroke":821,"style":1778},"544","576",[797,1786,1787,1793,1797,1802,1804,1806,1808,1810,1812,1814,1817,1820],{},[782,1788],{"x":801,"y":1789,"width":1748,"height":802,"rx":1790,"fill":902,"fillOpacity":1791,"stroke":902,"style":1792},"144","6",0.14,"stroke-width:1.6",[788,1794,1796],{"x":1751,"y":1770,"style":1795,"fill":912,"textAnchor":794},"text-anchor:middle;font-size:10px;font-family:monospace","tmp\u002F…\u002Fout.gpkg",[788,1798,1801],{"x":1751,"y":1799,"style":1800,"fill":902,"textAnchor":794},"181","text-anchor:middle;font-size:10px;font-family:sans-serif","inspectable",[782,1803],{"x":1011,"y":1789,"width":1748,"height":802,"rx":1790,"fill":902,"fillOpacity":1791,"stroke":902,"style":1792},[788,1805,1796],{"x":1758,"y":1770,"style":1795,"fill":912,"textAnchor":794},[788,1807,1801],{"x":1758,"y":1799,"style":1800,"fill":902,"textAnchor":794},[782,1809],{"x":1762,"y":1789,"width":1748,"height":802,"rx":1790,"fill":902,"fillOpacity":1791,"stroke":902,"style":1792},[788,1811,1796],{"x":1765,"y":1770,"style":1795,"fill":912,"textAnchor":794},[788,1813,1801],{"x":1765,"y":1799,"style":1800,"fill":902,"textAnchor":794},[782,1815],{"x":1769,"y":1789,"width":1770,"height":802,"rx":1790,"fill":807,"fillOpacity":1816,"stroke":807,"style":865},0.18,[788,1818,1819],{"x":1773,"y":1770,"style":1795,"fill":912,"textAnchor":794},"\u002Fdata\u002Foutput\u002F…",[788,1821,1822],{"x":1773,"y":1799,"style":1800,"fill":807,"textAnchor":794},"the deliverable",[99,1824],{"x1":1751,"y1":917,"x2":1751,"y2":923,"stroke":902,"style":1825},"stroke-width:1.6;stroke-dasharray:4 3;marker-end:url(#chainTmpArrow)",[99,1827],{"x1":1758,"y1":917,"x2":1758,"y2":923,"stroke":902,"style":1825},[99,1829],{"x1":1765,"y1":917,"x2":1765,"y2":923,"stroke":902,"style":1825},[99,1831],{"x1":1773,"y1":917,"x2":1773,"y2":923,"stroke":807,"style":1778},[788,1833,1836],{"x":790,"y":1834,"style":839,"fill":1835,"textAnchor":794},"216","#59645f","temporary files persist until QGIS exits — a long batch can fill a disk",[14,1838,1839,1840,1843],{},"When a chain produces an unexpected result, printing ",[18,1841,1842],{},"result[\"OUTPUT\"].source()"," at each step gives you the path of that step's intermediate file, which can be opened directly to see exactly where the data went wrong.",[36,1845,1847],{"id":1846},"qgis-version-compatibility","QGIS Version Compatibility",[14,1849,1850,1851,1854,1855,1857,1858,1860],{},"The script targets ",[47,1852,1853],{},"QGIS 3.34 LTR (Python 3.12)"," as the baseline. Both ",[18,1856,20],{}," and ",[18,1859,24],{}," have been stable native algorithms since the early 3.x series, so the chain runs unchanged across recent releases.",[1862,1863,1864,1877],"table",{},[1865,1866,1867],"thead",{},[1868,1869,1870,1874],"tr",{},[1871,1872,1873],"th",{},"QGIS \u002F Python",[1871,1875,1876],{},"Notes",[1878,1879,1880,1892,1902],"tbody",{},[1868,1881,1882,1886],{},[1883,1884,1885],"td",{},"3.28 LTR \u002F Py 3.9",[1883,1887,1888,1889,1891],{},"Fully supported. ",[18,1890,20],{}," parameter keys identical.",[1868,1893,1894,1899],{},[1883,1895,1896],{},[47,1897,1898],{},"3.34 LTR \u002F Py 3.12 (baseline)",[1883,1900,1901],{},"Recommended. Round-cap\u002Fround-join defaults as shown.",[1868,1903,1904,1907],{},[1883,1905,1906],{},"3.40 \u002F 3.44 \u002F Py 3.12",[1883,1908,1909],{},"Same parameters; some additional optional keys exist. Use \"Copy as Python Command\" to confirm.",[14,1911,1912,1152,1915,1918,1919,1922],{},[18,1913,1914],{},"END_CAP_STYLE",[18,1916,1917],{},"JOIN_STYLE",", and ",[18,1920,1921],{},"MITER_LIMIT"," are integers in every version (0 = round, 1 = flat\u002Fmiter, 2 = square\u002Fbevel depending on the parameter). When in doubt, configure the buffer dialog interactively and copy the exact parameter dictionary.",[36,1924,1926],{"id":1925},"troubleshooting","Troubleshooting",[14,1928,1929,1932,1933,349,1935,1938,1939,1942],{},[47,1930,1931],{},"Buffer produces enormous or empty geometries."," The source layer is in a geographic CRS (degrees). A ",[18,1934,348],{},[18,1936,1937],{},"500"," then means 500 degrees. Reproject to a projected, metre-based CRS (for example ",[18,1940,1941],{},"native:reprojectlayer"," to a local UTM zone) before buffering, or set the distance in degrees deliberately.",[14,1944,1945,1948,1949,1857,1952,1955,1956,31],{},[47,1946,1947],{},"Clip returns zero features."," The buffer and overlay do not overlap, or they are in different CRSs so they appear not to intersect. Confirm ",[18,1950,1951],{},"source.crs()",[18,1953,1954],{},"overlay.crs()"," match, and check extents overlap with ",[18,1957,1958],{},"source.extent().intersects(overlay.extent())",[14,1960,1961,1966],{},[47,1962,1963,31],{},[18,1964,1965],{},"QgsProcessingException: Unknown parameter"," A parameter key is misspelled or does not exist for that algorithm. Open the algorithm dialog, set it up, and use \"Advanced > Copy as Python Command\" to get the authoritative keys.",[14,1968,1969,1972],{},[47,1970,1971],{},"The output file is locked or cannot be overwritten."," A previous run's layer is still loaded in QGIS, or another program (a GIS viewer, cloud-sync) holds the file. Remove the layer from the project or write to a fresh path, then retry.",[14,1974,1975,1978,1979,1981,1982,1984,1985,1857,1988,1991],{},[47,1976,1977],{},"Nothing prints during a long buffer."," The default ",[18,1980,1108],{}," is silent. Pass the ",[18,1983,1539],{}," subclass shown above so ",[18,1986,1987],{},"setProgress",[18,1989,1990],{},"pushInfo"," reach the console.",[36,1993,1995],{"id":1994},"conclusion","Conclusion",[14,1997,1998,1999,2001,2002,2004,2005,2007,2008,2010],{},"Chaining ",[18,2000,20],{}," into ",[18,2003,24],{}," is the canonical small pipeline: two algorithms, one in-memory intermediate, one written result. The pattern scales — drop a dissolve or reproject step in the middle, or loop the whole function over many inputs — because the mechanics never change: capture ",[18,2006,604],{},", hand it to the next step's ",[18,2009,622],{},", and write only at the end. Validate before you start and after you finish, share one context and feedback object, and you have a reliable, repeatable operation you can fold into any larger automation.",[36,2012,2014],{"id":2013},"frequently-asked-questions","Frequently Asked Questions",[14,2016,2017,2023,2024,2026],{},[47,2018,2019,2020,2022],{},"Why use ",[18,2021,942],{}," instead of writing the buffer to a file?","\nThe buffer is an intermediate you immediately consume. ",[18,2025,942],{}," keeps it managed in memory, so the chain is faster and leaves no file to clean up. Only the clip — the final step — writes to disk.",[14,2028,2029,2038,2039,2041,2042,2044],{},[47,2030,2031,2032,2034,2035,2037],{},"Should I use ",[18,2033,24],{}," or ",[18,2036,747],{},"?","\nUse ",[18,2040,24],{}," when you want features trimmed to the overlay boundary. Use ",[18,2043,747],{}," (predicate intersects) when you want whole features that touch the area, with their geometry unchanged.",[14,2046,2047,2050,2051,2053,2054,2057],{},[47,2048,2049],{},"How do I buffer by a field value instead of a fixed distance?","\nSet ",[18,2052,348],{}," to a ",[18,2055,2056],{},"QgsProperty.fromExpression('\"radius_m\"')"," to drive the distance from an attribute, or pass the field reference supported by the buffer parameter in your QGIS version. Confirm the exact form with \"Copy as Python Command\".",[14,2059,2060,2063,2064,2067,2068,2070],{},[47,2061,2062],{},"Can I run this on hundreds of files?","\nYes — wrap ",[18,2065,2066],{},"buffer_then_clip()"," in a loop over your inputs, reusing the validation and feedback pattern. See ",[27,2069,1557],{"href":1556}," for the iteration and error-isolation structure.",[36,2072,2074],{"id":2073},"related","Related",[41,2076,2077,2081,2086,2091],{},[44,2078,2079],{},[27,2080,30],{"href":29},[44,2082,2083],{},[27,2084,2085],{"href":73},"Run a Processing Algorithm from a Script in PyQGIS",[44,2087,2088],{},[27,2089,2090],{"href":1556},"Batch Processing with PyQGIS",[44,2092,2093],{},[27,2094,2095],{"href":755},"Clip a Vector Layer in PyQGIS",[2097,2098,2099],"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 .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}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":93,"searchDepth":117,"depth":117,"links":2101},[2102,2103,2104,2105,2106,2107,2108,2109,2110,2111,2112,2113],{"id":38,"depth":117,"text":39},{"id":82,"depth":117,"text":83},{"id":356,"depth":117,"text":357},{"id":612,"depth":117,"text":613},{"id":874,"depth":117,"text":875},{"id":1560,"depth":117,"text":1561},{"id":1707,"depth":117,"text":1708},{"id":1846,"depth":117,"text":1847},{"id":1925,"depth":117,"text":1926},{"id":1994,"depth":117,"text":1995},{"id":2013,"depth":117,"text":2014},{"id":2073,"depth":117,"text":2074},"Chain native:buffer into native:clip in one PyQGIS script using TEMPORARY_OUTPUT, with progress feedback, validation, and a written final result.","md",{"slug":2117,"type":2118,"breadcrumb":2119,"datePublished":2120,"dateModified":2121},"chain-buffer-and-clip-pyqgis","article","Chain Buffer and Clip","2025-06-12","2026-07-18","\u002Fspatial-data-processing-automation\u002Fchaining-processing-algorithms\u002Fchain-buffer-and-clip-pyqgis",{"title":5,"description":2114},"spatial-data-processing-automation\u002Fchaining-processing-algorithms\u002Fchain-buffer-and-clip-pyqgis\u002Findex","bnad2wTEZHfbwKzHVA0nLutc0Qdqu1_Y__6XNezDA5s",1787823363545]