[{"data":1,"prerenderedAt":1547},["ShallowReactive",2],{"doc:\u002Fspatial-data-processing-automation\u002Fraster-analysis-workflows\u002Fclip-raster-by-mask-layer-pyqgis":3},{"id":4,"title":5,"body":6,"description":1540,"extension":1541,"meta":1542,"navigation":113,"path":1543,"seo":1544,"stem":1545,"__hash__":1546},"docs\u002Fspatial-data-processing-automation\u002Fraster-analysis-workflows\u002Fclip-raster-by-mask-layer-pyqgis\u002Findex.md","Clip a Raster by a Mask Layer in PyQGIS",{"type":7,"value":8,"toc":1526},"minimark",[9,13,33,40,45,65,71,75,86,249,281,285,288,330,427,443,447,460,620,646,650,661,802,828,832,838,939,958,962,965,1276,1284,1288,1295,1355,1366,1370,1431,1435,1453,1457,1466,1477,1489,1504,1508,1522],[10,11,5],"h1",{"id":12},"clip-a-raster-by-a-mask-layer-in-pyqgis",[14,15,16,17,21,22,26,27,32],"p",{},"Clipping a raster to a polygon boundary is how you restrict a DEM, satellite scene, or land-cover grid to a study area, a watershed, or an administrative unit. Unlike clipping a vector layer, a raster clip has to decide what happens to the pixels outside the mask: they become ",[18,19,20],"strong",{},"nodata",", and the output is usually cropped to the mask's bounding box to avoid carrying a sea of empty cells. In PyQGIS the workhorse is ",[23,24,25],"code",{},"gdal:cliprasterbymasklayer",". This is a fundamental step in ",[28,29,31],"a",{"href":30},"\u002Fspatial-data-processing-automation\u002Fraster-analysis-workflows\u002F","Raster Analysis Workflows",".",[14,34,35,36,39],{},"This page shows a correct clip that preserves the source resolution and CRS, how to set the nodata value, how cropping to extent works, and when to reach for the ",[23,37,38],{},"native:"," equivalent instead.",[41,42,44],"h2",{"id":43},"prerequisites","Prerequisites",[46,47,48,52,55,58],"ul",{},[49,50,51],"li",{},"QGIS 3.34 LTR (bundled Python 3.12) with Processing available.",[49,53,54],{},"A raster to clip (single- or multi-band GeoTIFF).",[49,56,57],{},"A polygon vector layer to use as the mask.",[49,59,60,61,64],{},"The QGIS Python Console (",[23,62,63],{},"Plugins > Python Console",").",[14,66,67,68,70],{},"The raster and the mask should share a CRS. ",[23,69,25],{}," can reproject the mask on the fly, but matching them up front avoids surprises at the boundary.",[41,72,74],{"id":73},"run-a-basic-raster-clip","Run a Basic Raster Clip",[14,76,77,78,81,82,85],{},"Provide the raster as ",[23,79,80],{},"INPUT"," and the polygon layer as ",[23,83,84],{},"MASK",". The example crops to the mask extent and writes a GeoTIFF.",[87,88,93],"pre",{"className":89,"code":90,"language":91,"meta":92,"style":92},"language-python shiki shiki-themes github-dark","import processing\n\nresult = processing.run(\"gdal:cliprasterbymasklayer\", {\n    \"INPUT\": \"\u002Fdata\u002Fdem.tif\",\n    \"MASK\": \"\u002Fdata\u002Fwatershed.gpkg|layername=basin\",\n    \"CROP_TO_CUTLINE\": True,\n    \"KEEP_RESOLUTION\": True,\n    \"NODATA\": -9999,\n    \"OUTPUT\": \"\u002Fdata\u002Foutput\u002Fdem_clipped.tif\",\n})\n\nprint(\"Clipped raster:\", result[\"OUTPUT\"])\n","python","",[23,94,95,108,115,134,149,162,176,188,204,217,223,228],{"__ignoreMap":92},[96,97,100,104],"span",{"class":98,"line":99},"line",1,[96,101,103],{"class":102},"snl16","import",[96,105,107],{"class":106},"s95oV"," processing\n",[96,109,111],{"class":98,"line":110},2,[96,112,114],{"emptyLinePlaceholder":113},true,"\n",[96,116,118,121,124,127,131],{"class":98,"line":117},3,[96,119,120],{"class":106},"result ",[96,122,123],{"class":102},"=",[96,125,126],{"class":106}," processing.run(",[96,128,130],{"class":129},"sU2Wk","\"gdal:cliprasterbymasklayer\"",[96,132,133],{"class":106},", {\n",[96,135,137,140,143,146],{"class":98,"line":136},4,[96,138,139],{"class":129},"    \"INPUT\"",[96,141,142],{"class":106},": ",[96,144,145],{"class":129},"\"\u002Fdata\u002Fdem.tif\"",[96,147,148],{"class":106},",\n",[96,150,152,155,157,160],{"class":98,"line":151},5,[96,153,154],{"class":129},"    \"MASK\"",[96,156,142],{"class":106},[96,158,159],{"class":129},"\"\u002Fdata\u002Fwatershed.gpkg|layername=basin\"",[96,161,148],{"class":106},[96,163,165,168,170,174],{"class":98,"line":164},6,[96,166,167],{"class":129},"    \"CROP_TO_CUTLINE\"",[96,169,142],{"class":106},[96,171,173],{"class":172},"sDLfK","True",[96,175,148],{"class":106},[96,177,179,182,184,186],{"class":98,"line":178},7,[96,180,181],{"class":129},"    \"KEEP_RESOLUTION\"",[96,183,142],{"class":106},[96,185,173],{"class":172},[96,187,148],{"class":106},[96,189,191,194,196,199,202],{"class":98,"line":190},8,[96,192,193],{"class":129},"    \"NODATA\"",[96,195,142],{"class":106},[96,197,198],{"class":102},"-",[96,200,201],{"class":172},"9999",[96,203,148],{"class":106},[96,205,207,210,212,215],{"class":98,"line":206},9,[96,208,209],{"class":129},"    \"OUTPUT\"",[96,211,142],{"class":106},[96,213,214],{"class":129},"\"\u002Fdata\u002Foutput\u002Fdem_clipped.tif\"",[96,216,148],{"class":106},[96,218,220],{"class":98,"line":219},10,[96,221,222],{"class":106},"})\n",[96,224,226],{"class":98,"line":225},11,[96,227,114],{"emptyLinePlaceholder":113},[96,229,231,234,237,240,243,246],{"class":98,"line":230},12,[96,232,233],{"class":172},"print",[96,235,236],{"class":106},"(",[96,238,239],{"class":129},"\"Clipped raster:\"",[96,241,242],{"class":106},", result[",[96,244,245],{"class":129},"\"OUTPUT\"",[96,247,248],{"class":106},"])\n",[14,250,251,254,255,257,258,260,261,264,265,268,269,272,273,276,277,280],{},[18,252,253],{},"Breakdown:"," ",[23,256,80],{}," is the raster and ",[23,259,84],{}," is the polygon layer (the ",[23,262,263],{},"|layername="," suffix targets one layer inside a GeoPackage). ",[23,266,267],{},"CROP_TO_CUTLINE=True"," trims the output to the mask's bounding box; ",[23,270,271],{},"KEEP_RESOLUTION=True"," forces the output pixel size to match the source so cells stay aligned; ",[23,274,275],{},"NODATA=-9999"," is the value assigned to pixels outside the polygon. The output path's ",[23,278,279],{},".tif"," extension selects the GeoTIFF driver.",[41,282,284],{"id":283},"set-nodata-and-crop-behavior","Set Nodata and Crop Behavior",[14,286,287],{},"Two parameters control the shape and fill of the result, and getting them right matters for downstream statistics:",[46,289,290,310],{},[49,291,292,297,298,301,302,305,306,309],{},[18,293,294],{},[23,295,296],{},"NODATA"," — the value written to cells outside the mask polygon. Choose a value that cannot occur in your real data (for elevation, ",[23,299,300],{},"-9999","; for an 8-bit byte raster, ",[23,303,304],{},"0"," or ",[23,307,308],{},"255"," if those are unused). If your source already defines a nodata value, reuse it for consistency.",[49,311,312,317,318,320,321,324,325,329],{},[18,313,314],{},[23,315,316],{},"CROP_TO_CUTLINE"," — when ",[23,319,173],{},", the output extent shrinks to the mask's bounding box. When ",[23,322,323],{},"False",", the output keeps the ",[326,327,328],"em",{},"input"," raster's full extent and merely sets outside-the-polygon pixels to nodata, leaving a large mostly-empty grid.",[87,331,333],{"className":89,"code":332,"language":91,"meta":92,"style":92},"import processing\n\n# Keep the full input extent, only mask out the values\nprocessing.run(\"gdal:cliprasterbymasklayer\", {\n    \"INPUT\": \"\u002Fdata\u002Flandcover.tif\",\n    \"MASK\": \"\u002Fdata\u002Fcounty.gpkg\",\n    \"CROP_TO_CUTLINE\": False,\n    \"KEEP_RESOLUTION\": True,\n    \"NODATA\": 0,\n    \"OUTPUT\": \"\u002Fdata\u002Foutput\u002Flandcover_masked.tif\",\n})\n",[23,334,335,341,345,351,360,371,382,392,402,412,423],{"__ignoreMap":92},[96,336,337,339],{"class":98,"line":99},[96,338,103],{"class":102},[96,340,107],{"class":106},[96,342,343],{"class":98,"line":110},[96,344,114],{"emptyLinePlaceholder":113},[96,346,347],{"class":98,"line":117},[96,348,350],{"class":349},"sAwPA","# Keep the full input extent, only mask out the values\n",[96,352,353,356,358],{"class":98,"line":136},[96,354,355],{"class":106},"processing.run(",[96,357,130],{"class":129},[96,359,133],{"class":106},[96,361,362,364,366,369],{"class":98,"line":151},[96,363,139],{"class":129},[96,365,142],{"class":106},[96,367,368],{"class":129},"\"\u002Fdata\u002Flandcover.tif\"",[96,370,148],{"class":106},[96,372,373,375,377,380],{"class":98,"line":164},[96,374,154],{"class":129},[96,376,142],{"class":106},[96,378,379],{"class":129},"\"\u002Fdata\u002Fcounty.gpkg\"",[96,381,148],{"class":106},[96,383,384,386,388,390],{"class":98,"line":178},[96,385,167],{"class":129},[96,387,142],{"class":106},[96,389,323],{"class":172},[96,391,148],{"class":106},[96,393,394,396,398,400],{"class":98,"line":190},[96,395,181],{"class":129},[96,397,142],{"class":106},[96,399,173],{"class":172},[96,401,148],{"class":106},[96,403,404,406,408,410],{"class":98,"line":206},[96,405,193],{"class":129},[96,407,142],{"class":106},[96,409,304],{"class":172},[96,411,148],{"class":106},[96,413,414,416,418,421],{"class":98,"line":219},[96,415,209],{"class":129},[96,417,142],{"class":106},[96,419,420],{"class":129},"\"\u002Fdata\u002Foutput\u002Flandcover_masked.tif\"",[96,422,148],{"class":106},[96,424,425],{"class":98,"line":225},[96,426,222],{"class":106},[14,428,429,431,432,435,436,438,439,32],{},[18,430,253],{}," With ",[23,433,434],{},"CROP_TO_CUTLINE=False"," the file footprint matches the original raster, which is useful when several masked outputs must stay on the same grid for overlay or differencing. Set ",[23,437,296],{}," to a code that is genuinely absent from the land-cover legend so masked cells are unambiguous. The masked output is then ready for accurate summaries with ",[28,440,442],{"href":441},"\u002Fspatial-data-processing-automation\u002Fraster-analysis-workflows\u002Fcalculate-raster-statistics-pyqgis\u002F","Calculate Raster Statistics in PyQGIS",[41,444,446],{"id":445},"preserve-resolution-and-crs","Preserve Resolution and CRS",[14,448,449,451,452,455,456,459],{},[23,450,271],{}," is the safeguard against silent resampling. Without it, GDAL may snap the output to a slightly different grid, shifting pixel centers and corrupting later raster math. Pairing it with an explicit ",[23,453,454],{},"SOURCE_CRS","\u002F",[23,457,458],{},"TARGET_CRS"," keeps the projection intact:",[87,461,463],{"className":89,"code":462,"language":91,"meta":92,"style":92},"import processing\nfrom qgis.core import QgsRasterLayer\n\nraster = QgsRasterLayer(\"\u002Fdata\u002Fdem.tif\", \"dem\")\nsrc_crs = raster.crs().authid()\n\nprocessing.run(\"gdal:cliprasterbymasklayer\", {\n    \"INPUT\": \"\u002Fdata\u002Fdem.tif\",\n    \"MASK\": \"\u002Fdata\u002Fwatershed.gpkg|layername=basin\",\n    \"SOURCE_CRS\": src_crs,\n    \"TARGET_CRS\": src_crs,        # no reprojection — keep the source CRS\n    \"CROP_TO_CUTLINE\": True,\n    \"KEEP_RESOLUTION\": True,\n    \"NODATA\": -9999,\n    \"OUTPUT\": \"\u002Fdata\u002Foutput\u002Fdem_clipped.tif\",\n})\n",[23,464,465,471,484,488,509,519,523,531,541,551,559,570,580,591,604,615],{"__ignoreMap":92},[96,466,467,469],{"class":98,"line":99},[96,468,103],{"class":102},[96,470,107],{"class":106},[96,472,473,476,479,481],{"class":98,"line":110},[96,474,475],{"class":102},"from",[96,477,478],{"class":106}," qgis.core ",[96,480,103],{"class":102},[96,482,483],{"class":106}," QgsRasterLayer\n",[96,485,486],{"class":98,"line":117},[96,487,114],{"emptyLinePlaceholder":113},[96,489,490,493,495,498,500,503,506],{"class":98,"line":136},[96,491,492],{"class":106},"raster ",[96,494,123],{"class":102},[96,496,497],{"class":106}," QgsRasterLayer(",[96,499,145],{"class":129},[96,501,502],{"class":106},", ",[96,504,505],{"class":129},"\"dem\"",[96,507,508],{"class":106},")\n",[96,510,511,514,516],{"class":98,"line":151},[96,512,513],{"class":106},"src_crs ",[96,515,123],{"class":102},[96,517,518],{"class":106}," raster.crs().authid()\n",[96,520,521],{"class":98,"line":164},[96,522,114],{"emptyLinePlaceholder":113},[96,524,525,527,529],{"class":98,"line":178},[96,526,355],{"class":106},[96,528,130],{"class":129},[96,530,133],{"class":106},[96,532,533,535,537,539],{"class":98,"line":190},[96,534,139],{"class":129},[96,536,142],{"class":106},[96,538,145],{"class":129},[96,540,148],{"class":106},[96,542,543,545,547,549],{"class":98,"line":206},[96,544,154],{"class":129},[96,546,142],{"class":106},[96,548,159],{"class":129},[96,550,148],{"class":106},[96,552,553,556],{"class":98,"line":219},[96,554,555],{"class":129},"    \"SOURCE_CRS\"",[96,557,558],{"class":106},": src_crs,\n",[96,560,561,564,567],{"class":98,"line":225},[96,562,563],{"class":129},"    \"TARGET_CRS\"",[96,565,566],{"class":106},": src_crs,        ",[96,568,569],{"class":349},"# no reprojection — keep the source CRS\n",[96,571,572,574,576,578],{"class":98,"line":230},[96,573,167],{"class":129},[96,575,142],{"class":106},[96,577,173],{"class":172},[96,579,148],{"class":106},[96,581,583,585,587,589],{"class":98,"line":582},13,[96,584,181],{"class":129},[96,586,142],{"class":106},[96,588,173],{"class":172},[96,590,148],{"class":106},[96,592,594,596,598,600,602],{"class":98,"line":593},14,[96,595,193],{"class":129},[96,597,142],{"class":106},[96,599,198],{"class":102},[96,601,201],{"class":172},[96,603,148],{"class":106},[96,605,607,609,611,613],{"class":98,"line":606},15,[96,608,209],{"class":129},[96,610,142],{"class":106},[96,612,214],{"class":129},[96,614,148],{"class":106},[96,616,618],{"class":98,"line":617},16,[96,619,222],{"class":106},[14,621,622,624,625,628,629,632,633,635,636,638,639,641,642,32],{},[18,623,253],{}," Reading ",[23,626,627],{},"raster.crs().authid()"," gives the source CRS as an authority string (e.g. ",[23,630,631],{},"EPSG:32633","). Passing the same value to both ",[23,634,454],{}," and ",[23,637,458],{}," explicitly tells GDAL to clip without reprojecting, so resolution and alignment survive. To actually reproject during the clip, set a different ",[23,640,458],{}," — but for separate reprojection of many files see ",[28,643,645],{"href":644},"\u002Fspatial-data-processing-automation\u002Fcoordinate-reference-systems\u002Fbatch-reprojecting-raster-datasets\u002F","Batch Reprojecting Raster Datasets in PyQGIS",[41,647,649],{"id":648},"the-native-equivalent","The native Equivalent",[14,651,652,653,656,657,660],{},"QGIS also ships ",[23,654,655],{},"native:cliprasterbymasklayer",", a thin wrapper exposing similar options without invoking the GDAL provider directly. It is convenient when you want a ",[23,658,659],{},"TEMPORARY_OUTPUT"," layer object for chaining rather than a file on disk:",[87,662,664],{"className":89,"code":663,"language":91,"meta":92,"style":92},"import processing\n\nclipped = processing.run(\"native:cliprasterbymasklayer\", {\n    \"INPUT\": \"\u002Fdata\u002Fdem.tif\",\n    \"MASK\": \"\u002Fdata\u002Fwatershed.gpkg|layername=basin\",\n    \"SOURCE_CRS\": None,\n    \"TARGET_CRS\": None,\n    \"TARGET_EXTENT\": None,\n    \"NODATA\": -9999,\n    \"OUTPUT\": \"TEMPORARY_OUTPUT\",\n})[\"OUTPUT\"]\n\nprint(\"In-memory clip:\", clipped.width(), \"x\", clipped.height(), \"px\")\n",[23,665,666,672,676,690,700,710,721,731,742,754,765,775,779],{"__ignoreMap":92},[96,667,668,670],{"class":98,"line":99},[96,669,103],{"class":102},[96,671,107],{"class":106},[96,673,674],{"class":98,"line":110},[96,675,114],{"emptyLinePlaceholder":113},[96,677,678,681,683,685,688],{"class":98,"line":117},[96,679,680],{"class":106},"clipped ",[96,682,123],{"class":102},[96,684,126],{"class":106},[96,686,687],{"class":129},"\"native:cliprasterbymasklayer\"",[96,689,133],{"class":106},[96,691,692,694,696,698],{"class":98,"line":136},[96,693,139],{"class":129},[96,695,142],{"class":106},[96,697,145],{"class":129},[96,699,148],{"class":106},[96,701,702,704,706,708],{"class":98,"line":151},[96,703,154],{"class":129},[96,705,142],{"class":106},[96,707,159],{"class":129},[96,709,148],{"class":106},[96,711,712,714,716,719],{"class":98,"line":164},[96,713,555],{"class":129},[96,715,142],{"class":106},[96,717,718],{"class":172},"None",[96,720,148],{"class":106},[96,722,723,725,727,729],{"class":98,"line":178},[96,724,563],{"class":129},[96,726,142],{"class":106},[96,728,718],{"class":172},[96,730,148],{"class":106},[96,732,733,736,738,740],{"class":98,"line":190},[96,734,735],{"class":129},"    \"TARGET_EXTENT\"",[96,737,142],{"class":106},[96,739,718],{"class":172},[96,741,148],{"class":106},[96,743,744,746,748,750,752],{"class":98,"line":206},[96,745,193],{"class":129},[96,747,142],{"class":106},[96,749,198],{"class":102},[96,751,201],{"class":172},[96,753,148],{"class":106},[96,755,756,758,760,763],{"class":98,"line":219},[96,757,209],{"class":129},[96,759,142],{"class":106},[96,761,762],{"class":129},"\"TEMPORARY_OUTPUT\"",[96,764,148],{"class":106},[96,766,767,770,772],{"class":98,"line":225},[96,768,769],{"class":106},"})[",[96,771,245],{"class":129},[96,773,774],{"class":106},"]\n",[96,776,777],{"class":98,"line":230},[96,778,114],{"emptyLinePlaceholder":113},[96,780,781,783,785,788,791,794,797,800],{"class":98,"line":582},[96,782,233],{"class":172},[96,784,236],{"class":106},[96,786,787],{"class":129},"\"In-memory clip:\"",[96,789,790],{"class":106},", clipped.width(), ",[96,792,793],{"class":129},"\"x\"",[96,795,796],{"class":106},", clipped.height(), ",[96,798,799],{"class":129},"\"px\"",[96,801,508],{"class":106},[14,803,804,806,807,809,810,813,814,816,817,819,820,823,824,827],{},[18,805,253],{}," The ",[23,808,38],{}," variant returns a ",[23,811,812],{},"QgsRasterLayer"," when given ",[23,815,659],{},", ideal for feeding the next step in a script without writing intermediate files. The GDAL variant (",[23,818,25],{},") exposes the full set of GDAL warp options like ",[23,821,822],{},"KEEP_RESOLUTION"," and creation ",[23,825,826],{},"OPTIONS",", so prefer it for final outputs where compression and tiling matter.",[41,829,831],{"id":830},"compress-and-tile-the-output","Compress and Tile the Output",[14,833,834,835,837],{},"For deliverables, an uncompressed clipped GeoTIFF can be many times larger than necessary. Pass GDAL creation options through the ",[23,836,826],{}," parameter to compress and tile the result in the same step:",[87,839,841],{"className":89,"code":840,"language":91,"meta":92,"style":92},"import processing\n\nprocessing.run(\"gdal:cliprasterbymasklayer\", {\n    \"INPUT\": \"\u002Fdata\u002Fdem.tif\",\n    \"MASK\": \"\u002Fdata\u002Fwatershed.gpkg|layername=basin\",\n    \"CROP_TO_CUTLINE\": True,\n    \"KEEP_RESOLUTION\": True,\n    \"NODATA\": -9999,\n    \"OPTIONS\": \"COMPRESS=DEFLATE|TILED=YES|BIGTIFF=IF_SAFER\",\n    \"OUTPUT\": \"\u002Fdata\u002Foutput\u002Fdem_clipped.tif\",\n})\n",[23,842,843,849,853,861,871,881,891,901,913,925,935],{"__ignoreMap":92},[96,844,845,847],{"class":98,"line":99},[96,846,103],{"class":102},[96,848,107],{"class":106},[96,850,851],{"class":98,"line":110},[96,852,114],{"emptyLinePlaceholder":113},[96,854,855,857,859],{"class":98,"line":117},[96,856,355],{"class":106},[96,858,130],{"class":129},[96,860,133],{"class":106},[96,862,863,865,867,869],{"class":98,"line":136},[96,864,139],{"class":129},[96,866,142],{"class":106},[96,868,145],{"class":129},[96,870,148],{"class":106},[96,872,873,875,877,879],{"class":98,"line":151},[96,874,154],{"class":129},[96,876,142],{"class":106},[96,878,159],{"class":129},[96,880,148],{"class":106},[96,882,883,885,887,889],{"class":98,"line":164},[96,884,167],{"class":129},[96,886,142],{"class":106},[96,888,173],{"class":172},[96,890,148],{"class":106},[96,892,893,895,897,899],{"class":98,"line":178},[96,894,181],{"class":129},[96,896,142],{"class":106},[96,898,173],{"class":172},[96,900,148],{"class":106},[96,902,903,905,907,909,911],{"class":98,"line":190},[96,904,193],{"class":129},[96,906,142],{"class":106},[96,908,198],{"class":102},[96,910,201],{"class":172},[96,912,148],{"class":106},[96,914,915,918,920,923],{"class":98,"line":206},[96,916,917],{"class":129},"    \"OPTIONS\"",[96,919,142],{"class":106},[96,921,922],{"class":129},"\"COMPRESS=DEFLATE|TILED=YES|BIGTIFF=IF_SAFER\"",[96,924,148],{"class":106},[96,926,927,929,931,933],{"class":98,"line":219},[96,928,209],{"class":129},[96,930,142],{"class":106},[96,932,214],{"class":129},[96,934,148],{"class":106},[96,936,937],{"class":98,"line":225},[96,938,222],{"class":106},[14,940,941,254,943,945,946,949,950,953,954,957],{},[18,942,253],{},[23,944,826],{}," takes pipe-separated GDAL creation flags. ",[23,947,948],{},"COMPRESS=DEFLATE"," shrinks the file losslessly, ",[23,951,952],{},"TILED=YES"," stores the raster in internal tiles for faster windowed reads, and ",[23,955,956],{},"BIGTIFF=IF_SAFER"," automatically switches to the BigTIFF format if the output would exceed the 4 GB classic-TIFF limit. These travel through to GDAL untouched.",[41,959,961],{"id":960},"clip-many-rasters-to-one-mask","Clip Many Rasters to One Mask",[14,963,964],{},"When a whole folder of tiles or scenes must be clipped to the same boundary, loop over them and reuse the mask. Wrapping each call in a try\u002Fexcept keeps a single failure from stopping the batch:",[87,966,968],{"className":89,"code":967,"language":91,"meta":92,"style":92},"from pathlib import Path\nimport processing\n\nsource_dir = Path(\"\u002Fdata\u002Fscenes\")\noutput_dir = Path(\"\u002Fdata\u002Fclipped\")\noutput_dir.mkdir(parents=True, exist_ok=True)\nmask = \"\u002Fdata\u002Fwatershed.gpkg|layername=basin\"\n\nfor src in sorted(source_dir.glob(\"*.tif\")):\n    out_path = output_dir \u002F f\"{src.stem}_clip.tif\"\n    try:\n        processing.run(\"gdal:cliprasterbymasklayer\", {\n            \"INPUT\": str(src),\n            \"MASK\": mask,\n            \"CROP_TO_CUTLINE\": True,\n            \"KEEP_RESOLUTION\": True,\n            \"NODATA\": -9999,\n            \"OUTPUT\": str(out_path),\n        })\n        print(f\"Clipped {src.name}\")\n    except Exception as exc:\n        print(f\"Failed {src.name}: {exc}\")\n",[23,969,970,982,988,992,1007,1021,1045,1055,1059,1082,1112,1120,1129,1142,1150,1161,1172,1186,1199,1205,1230,1245],{"__ignoreMap":92},[96,971,972,974,977,979],{"class":98,"line":99},[96,973,475],{"class":102},[96,975,976],{"class":106}," pathlib ",[96,978,103],{"class":102},[96,980,981],{"class":106}," Path\n",[96,983,984,986],{"class":98,"line":110},[96,985,103],{"class":102},[96,987,107],{"class":106},[96,989,990],{"class":98,"line":117},[96,991,114],{"emptyLinePlaceholder":113},[96,993,994,997,999,1002,1005],{"class":98,"line":136},[96,995,996],{"class":106},"source_dir ",[96,998,123],{"class":102},[96,1000,1001],{"class":106}," Path(",[96,1003,1004],{"class":129},"\"\u002Fdata\u002Fscenes\"",[96,1006,508],{"class":106},[96,1008,1009,1012,1014,1016,1019],{"class":98,"line":151},[96,1010,1011],{"class":106},"output_dir ",[96,1013,123],{"class":102},[96,1015,1001],{"class":106},[96,1017,1018],{"class":129},"\"\u002Fdata\u002Fclipped\"",[96,1020,508],{"class":106},[96,1022,1023,1026,1030,1032,1034,1036,1039,1041,1043],{"class":98,"line":164},[96,1024,1025],{"class":106},"output_dir.mkdir(",[96,1027,1029],{"class":1028},"s9osk","parents",[96,1031,123],{"class":102},[96,1033,173],{"class":172},[96,1035,502],{"class":106},[96,1037,1038],{"class":1028},"exist_ok",[96,1040,123],{"class":102},[96,1042,173],{"class":172},[96,1044,508],{"class":106},[96,1046,1047,1050,1052],{"class":98,"line":178},[96,1048,1049],{"class":106},"mask ",[96,1051,123],{"class":102},[96,1053,1054],{"class":129}," \"\u002Fdata\u002Fwatershed.gpkg|layername=basin\"\n",[96,1056,1057],{"class":98,"line":190},[96,1058,114],{"emptyLinePlaceholder":113},[96,1060,1061,1064,1067,1070,1073,1076,1079],{"class":98,"line":206},[96,1062,1063],{"class":102},"for",[96,1065,1066],{"class":106}," src ",[96,1068,1069],{"class":102},"in",[96,1071,1072],{"class":172}," sorted",[96,1074,1075],{"class":106},"(source_dir.glob(",[96,1077,1078],{"class":129},"\"*.tif\"",[96,1080,1081],{"class":106},")):\n",[96,1083,1084,1087,1089,1092,1094,1097,1100,1103,1106,1109],{"class":98,"line":219},[96,1085,1086],{"class":106},"    out_path ",[96,1088,123],{"class":102},[96,1090,1091],{"class":106}," output_dir ",[96,1093,455],{"class":102},[96,1095,1096],{"class":102}," f",[96,1098,1099],{"class":129},"\"",[96,1101,1102],{"class":172},"{",[96,1104,1105],{"class":106},"src.stem",[96,1107,1108],{"class":172},"}",[96,1110,1111],{"class":129},"_clip.tif\"\n",[96,1113,1114,1117],{"class":98,"line":225},[96,1115,1116],{"class":102},"    try",[96,1118,1119],{"class":106},":\n",[96,1121,1122,1125,1127],{"class":98,"line":230},[96,1123,1124],{"class":106},"        processing.run(",[96,1126,130],{"class":129},[96,1128,133],{"class":106},[96,1130,1131,1134,1136,1139],{"class":98,"line":582},[96,1132,1133],{"class":129},"            \"INPUT\"",[96,1135,142],{"class":106},[96,1137,1138],{"class":172},"str",[96,1140,1141],{"class":106},"(src),\n",[96,1143,1144,1147],{"class":98,"line":593},[96,1145,1146],{"class":129},"            \"MASK\"",[96,1148,1149],{"class":106},": mask,\n",[96,1151,1152,1155,1157,1159],{"class":98,"line":606},[96,1153,1154],{"class":129},"            \"CROP_TO_CUTLINE\"",[96,1156,142],{"class":106},[96,1158,173],{"class":172},[96,1160,148],{"class":106},[96,1162,1163,1166,1168,1170],{"class":98,"line":617},[96,1164,1165],{"class":129},"            \"KEEP_RESOLUTION\"",[96,1167,142],{"class":106},[96,1169,173],{"class":172},[96,1171,148],{"class":106},[96,1173,1175,1178,1180,1182,1184],{"class":98,"line":1174},17,[96,1176,1177],{"class":129},"            \"NODATA\"",[96,1179,142],{"class":106},[96,1181,198],{"class":102},[96,1183,201],{"class":172},[96,1185,148],{"class":106},[96,1187,1189,1192,1194,1196],{"class":98,"line":1188},18,[96,1190,1191],{"class":129},"            \"OUTPUT\"",[96,1193,142],{"class":106},[96,1195,1138],{"class":172},[96,1197,1198],{"class":106},"(out_path),\n",[96,1200,1202],{"class":98,"line":1201},19,[96,1203,1204],{"class":106},"        })\n",[96,1206,1208,1211,1213,1216,1219,1221,1224,1226,1228],{"class":98,"line":1207},20,[96,1209,1210],{"class":172},"        print",[96,1212,236],{"class":106},[96,1214,1215],{"class":102},"f",[96,1217,1218],{"class":129},"\"Clipped ",[96,1220,1102],{"class":172},[96,1222,1223],{"class":106},"src.name",[96,1225,1108],{"class":172},[96,1227,1099],{"class":129},[96,1229,508],{"class":106},[96,1231,1233,1236,1239,1242],{"class":98,"line":1232},21,[96,1234,1235],{"class":102},"    except",[96,1237,1238],{"class":172}," Exception",[96,1240,1241],{"class":102}," as",[96,1243,1244],{"class":106}," exc:\n",[96,1246,1248,1250,1252,1254,1257,1259,1261,1263,1265,1267,1270,1272,1274],{"class":98,"line":1247},22,[96,1249,1210],{"class":172},[96,1251,236],{"class":106},[96,1253,1215],{"class":102},[96,1255,1256],{"class":129},"\"Failed ",[96,1258,1102],{"class":172},[96,1260,1223],{"class":106},[96,1262,1108],{"class":172},[96,1264,142],{"class":129},[96,1266,1102],{"class":172},[96,1268,1269],{"class":106},"exc",[96,1271,1108],{"class":172},[96,1273,1099],{"class":129},[96,1275,508],{"class":106},[14,1277,1278,254,1280,1283],{},[18,1279,253],{},[23,1281,1282],{},"Path.glob(\"*.tif\")"," collects the rasters, the mask path is reused for every input, and per-file error handling logs problems while the loop continues. This is the raster analog of the vector batch pattern and slots directly into a headless pipeline once Processing is initialized.",[41,1285,1287],{"id":1286},"qgis-version-compatibility","QGIS Version Compatibility",[14,1289,1290,1291,1294],{},"The code targets ",[18,1292,1293],{},"QGIS 3.34 LTR"," (Python 3.12).",[1296,1297,1298,1314],"table",{},[1299,1300,1301],"thead",{},[1302,1303,1304,1308,1311],"tr",{},[1305,1306,1307],"th",{},"QGIS version",[1305,1309,1310],{},"Python",[1305,1312,1313],{},"Notes",[1315,1316,1317,1334,1345],"tbody",{},[1302,1318,1319,1323,1326],{},[1320,1321,1322],"td",{},"3.28 LTR",[1320,1324,1325],{},"3.9",[1320,1327,1328,1330,1331,1333],{},[23,1329,25],{}," identical; ",[23,1332,38],{}," variant present.",[1302,1335,1336,1339,1342],{},[1320,1337,1338],{},"3.34 LTR",[1320,1340,1341],{},"3.12",[1320,1343,1344],{},"Baseline for this page.",[1302,1346,1347,1350,1352],{},[1320,1348,1349],{},"3.40 \u002F 3.44",[1320,1351,1341],{},[1320,1353,1354],{},"Same algorithm IDs and parameters; newer GDAL improves nodata handling.",[14,1356,1357,1358,502,1360,1362,1363,1365],{},"Both algorithm IDs and their ",[23,1359,316],{},[23,1361,822],{},", and ",[23,1364,296],{}," parameters are stable across the current 3.x line. The exact GDAL version bundled differs per release, which can affect edge-pixel handling on very large rasters, but the PyQGIS interface is unchanged.",[41,1367,1369],{"id":1368},"troubleshooting","Troubleshooting",[46,1371,1372,1378,1392,1406,1419],{},[49,1373,1374,1377],{},[18,1375,1376],{},"Output is all nodata."," The mask does not overlap the raster, or their CRS differ so the polygon lands outside the raster footprint. Confirm both extents intersect in a common CRS.",[49,1379,1380,254,1383,1385,1386,1388,1389,1391],{},[18,1381,1382],{},"Pixels look shifted after clipping.",[23,1384,822],{}," was ",[23,1387,323],{},", letting GDAL resample to a new grid. Set it to ",[23,1390,173],{}," to preserve the source cell size and alignment.",[49,1393,1394,254,1397,1399,1400,1402,1403,1405],{},[18,1395,1396],{},"Output extent is huge and mostly empty.",[23,1398,316],{}," is ",[23,1401,323],{},". Set it ",[23,1404,173],{}," to trim the output to the mask's bounding box.",[49,1407,1408,1411,1412,1414,1415,1418],{},[18,1409,1410],{},"Statistics include the fill value."," The clip's ",[23,1413,296],{}," was not recognized downstream. Verify with ",[23,1416,1417],{},"gdalinfo"," that the output declares the nodata value, and reuse the source's existing nodata when possible.",[49,1420,1421,1426,1427,1430],{},[18,1422,1423,32],{},[23,1424,1425],{},"Mask layer geometry invalid"," Self-intersecting mask polygons can break the cutline. Run ",[23,1428,1429],{},"native:fixgeometries"," on the mask first.",[41,1432,1434],{"id":1433},"conclusion","Conclusion",[14,1436,1437,1438,1440,1441,1443,1444,1446,1447,1449,1450,1452],{},"Clipping a raster by a mask in PyQGIS is reliable once three settings are deliberate: a ",[23,1439,296],{}," value that cannot collide with real data, ",[23,1442,316],{}," to control whether the output is trimmed or kept full-extent, and ",[23,1445,822],{}," to stop GDAL from silently resampling. Use ",[23,1448,25],{}," for final, compressed file outputs and the ",[23,1451,38],{}," variant when you want an in-memory layer to chain. Keeping the raster and mask in the same CRS ties it all together and produces clean, analysis-ready clips.",[41,1454,1456],{"id":1455},"frequently-asked-questions","Frequently Asked Questions",[14,1458,1459,1462,1463,1465],{},[18,1460,1461],{},"What value should I use for NODATA?","\nPick a number that cannot appear in your real data — ",[23,1464,300],{}," for elevation, or an unused legend code for categorical rasters. If the source already declares a nodata value, reuse it so masked cells stay consistent through the pipeline.",[14,1467,1468,1471,1473,1474,1476],{},[18,1469,1470],{},"What is the difference between CROP_TO_CUTLINE True and False?",[23,1472,173],{}," shrinks the output to the mask's bounding box, dropping the empty surround. ",[23,1475,323],{}," keeps the input raster's full extent and only sets outside-the-polygon pixels to nodata, leaving a larger, mostly-empty grid useful for keeping multiple outputs on one grid.",[14,1478,1479,1482,1483,1485,1486,1488],{},[18,1480,1481],{},"How do I keep the original resolution?","\nSet ",[23,1484,822],{}," to ",[23,1487,173],{},". Otherwise GDAL may snap the output to a slightly different grid, shifting pixel centers and breaking later raster algebra.",[14,1490,1491,1494,1495,1497,1498,1500,1501,1503],{},[18,1492,1493],{},"When should I use the native variant instead of the GDAL one?","\nUse ",[23,1496,655],{}," with ",[23,1499,659],{}," when you want an in-memory layer to feed straight into the next algorithm. Use ",[23,1502,25],{}," for final files where you need GDAL options like compression, tiling, and explicit resolution control.",[41,1505,1507],{"id":1506},"related","Related",[46,1509,1510,1514,1518],{},[49,1511,1512],{},[28,1513,31],{"href":30},[49,1515,1516],{},[28,1517,442],{"href":441},[49,1519,1520],{},[28,1521,645],{"href":644},[1523,1524,1525],"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 .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}",{"title":92,"searchDepth":110,"depth":110,"links":1527},[1528,1529,1530,1531,1532,1533,1534,1535,1536,1537,1538,1539],{"id":43,"depth":110,"text":44},{"id":73,"depth":110,"text":74},{"id":283,"depth":110,"text":284},{"id":445,"depth":110,"text":446},{"id":648,"depth":110,"text":649},{"id":830,"depth":110,"text":831},{"id":960,"depth":110,"text":961},{"id":1286,"depth":110,"text":1287},{"id":1368,"depth":110,"text":1369},{"id":1433,"depth":110,"text":1434},{"id":1455,"depth":110,"text":1456},{"id":1506,"depth":110,"text":1507},"Clip a raster by a polygon mask in PyQGIS with gdal:cliprasterbymasklayer. Set nodata, crop to extent, and keep the original resolution and CRS.","md",{},"\u002Fspatial-data-processing-automation\u002Fraster-analysis-workflows\u002Fclip-raster-by-mask-layer-pyqgis",{"title":5,"description":1540},"spatial-data-processing-automation\u002Fraster-analysis-workflows\u002Fclip-raster-by-mask-layer-pyqgis\u002Findex","-qogtK78Kvl4ETXso0948MZMdHACiD5mUF1Ggr0IzCY",1781792483477]