[{"data":1,"prerenderedAt":1497},["ShallowReactive",2],{"doc:\u002Fspatial-data-processing-automation\u002Fgeometry-operations-and-predicates\u002Fsimplify-geometry-pyqgis":3},{"id":4,"title":5,"body":6,"description":1486,"extension":1487,"meta":1488,"navigation":301,"path":1493,"seo":1494,"stem":1495,"__hash__":1496},"docs\u002Fspatial-data-processing-automation\u002Fgeometry-operations-and-predicates\u002Fsimplify-geometry-pyqgis\u002Findex.md","Simplify Geometry in PyQGIS",{"type":7,"value":8,"toc":1474},"minimark",[9,13,17,26,226,231,257,261,268,462,475,478,607,617,621,624,709,726,730,733,818,821,1005,1026,1030,1038,1158,1256,1276,1279,1283,1289,1347,1356,1360,1408,1412,1415,1419,1425,1431,1437,1443,1447,1470],[10,11,5],"h1",{"id":12},"simplify-geometry-in-pyqgis",[14,15,16],"p",{},"Simplification removes vertices that contribute little to a shape. It is what turns a coastline digitised at survey precision into something that renders at 1:2 000 000 without melting the browser, and what shrinks a GeoJSON payload from eighty megabytes to three. It is also destructive: vertices are gone, areas shift slightly, and — the failure that catches people — adjacent polygons simplified independently no longer share a boundary, leaving visible gaps and slivers between them.",[14,18,19,20,25],{},"This page is a focused recipe within ",[21,22,24],"a",{"href":23},"\u002Fspatial-data-processing-automation\u002Fgeometry-operations-and-predicates\u002F","Geometry Operations and Spatial Predicates in PyQGIS",". It covers the Douglas-Peucker method and its tolerance, measuring the effect before committing, preserving topology across neighbours, and choosing between simplification and generalisation.",[14,27,28],{},[29,30,35,39,43,50,59,150,196],"svg",{"viewBox":31,"role":32,"ariaLabel":33,"xmlns":34},"0 0 760 258","img","One coastline drawn at three simplification tolerances, showing progressively fewer vertices and increasing departure from the original outline","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg",[36,37,38],"title",{},"The same coastline at three tolerances",[40,41,42],"desc",{},"A detailed coastline with many vertices is shown at tolerance zero with every vertex marked. At a small tolerance about half the vertices remain and the shape is visually identical. At a large tolerance only a handful of vertices remain and the outline noticeably departs from the original, which is drawn dashed behind it.",[44,45],"rect",{"x":46,"y":46,"width":47,"height":48,"fill":49},"0","760","258","#f6f3ea",[51,52,58],"text",{"x":53,"y":54,"style":55,"fill":56,"textAnchor":57},"380","26","text-anchor:middle;font-size:14px;font-weight:bold;font-family:sans-serif","#17211d","middle","Tolerance is the maximum distance a dropped vertex may be from the kept line",[60,61,62,72,78,85,144],"g",{},[44,63],{"x":64,"y":65,"width":66,"height":67,"rx":68,"fill":69,"stroke":70,"style":71},"12","44","236","196","10","#fffdf7","#59645f","stroke-width:2",[51,73,77],{"x":74,"y":75,"style":76,"fill":56,"textAnchor":57},"130","68","text-anchor:middle;font-size:12px;font-weight:bold;font-family:sans-serif","original · 24 vertices",[79,80],"path",{"d":81,"fill":82,"stroke":83,"style":84},"M32 190 L48 160 L60 172 L74 138 L88 150 L100 120 L116 132 L130 104 L146 118 L158 96 L172 110 L188 88 L204 104 L220 84 L232 96","none","#0f766e","stroke-width:2.5;stroke-linejoin:round",[60,86,87,93,97,101,105,109,113,117,120,124,128,131,134,137,141],{"fill":83},[88,89],"circle",{"cx":90,"cy":91,"r":92},"32","190","3",[88,94],{"cx":95,"cy":96,"r":92},"48","160",[88,98],{"cx":99,"cy":100,"r":92},"60","172",[88,102],{"cx":103,"cy":104,"r":92},"74","138",[88,106],{"cx":107,"cy":108,"r":92},"88","150",[88,110],{"cx":111,"cy":112,"r":92},"100","120",[88,114],{"cx":115,"cy":116,"r":92},"116","132",[88,118],{"cx":74,"cy":119,"r":92},"104",[88,121],{"cx":122,"cy":123,"r":92},"146","118",[88,125],{"cx":126,"cy":127,"r":92},"158","96",[88,129],{"cx":100,"cy":130,"r":92},"110",[88,132],{"cx":133,"cy":107,"r":92},"188",[88,135],{"cx":136,"cy":119,"r":92},"204",[88,138],{"cx":139,"cy":140,"r":92},"220","84",[88,142],{"cx":143,"cy":127,"r":92},"232",[51,145,149],{"x":74,"y":146,"style":147,"fill":148,"textAnchor":57},"222","text-anchor:middle;font-size:11px;font-family:sans-serif","#2f3b35","every survey point kept",[60,151,152,157,160,164,167,193],{},[44,153],{"x":154,"y":65,"width":66,"height":67,"rx":68,"fill":69,"stroke":155,"style":156},"262","#15803d","stroke-width:2.5",[51,158,159],{"x":53,"y":75,"style":76,"fill":155,"textAnchor":57},"simplify(8) · 8 vertices",[79,161],{"d":162,"fill":82,"stroke":70,"style":163},"M282 190 L298 160 L310 172 L324 138 L338 150 L350 120 L366 132 L380 104 L396 118 L408 96 L422 110 L438 88 L454 104 L470 84 L482 96","stroke-width:1.5;stroke-dasharray:3 3",[79,165],{"d":166,"fill":82,"stroke":155,"style":84},"M282 190 L324 138 L350 120 L380 104 L408 96 L438 88 L470 84 L482 96",[60,168,169,173,176,179,181,184,187,190],{"fill":155},[88,170],{"cx":171,"cy":91,"r":172},"282","3.5",[88,174],{"cx":175,"cy":104,"r":172},"324",[88,177],{"cx":178,"cy":112,"r":172},"350",[88,180],{"cx":53,"cy":119,"r":172},[88,182],{"cx":183,"cy":127,"r":172},"408",[88,185],{"cx":186,"cy":107,"r":172},"438",[88,188],{"cx":189,"cy":140,"r":172},"470",[88,191],{"cx":192,"cy":127,"r":172},"482",[51,194,195],{"x":53,"y":146,"style":147,"fill":148,"textAnchor":57},"visually identical, 3× smaller",[60,197,198,202,206,209,212,223],{},[44,199],{"x":200,"y":65,"width":66,"height":67,"rx":68,"fill":69,"stroke":201,"style":156},"512","#b45309",[51,203,205],{"x":204,"y":75,"style":76,"fill":201,"textAnchor":57},"630","simplify(40) · 3 vertices",[79,207],{"d":208,"fill":82,"stroke":70,"style":163},"M532 190 L548 160 L560 172 L574 138 L588 150 L600 120 L616 132 L630 104 L646 118 L658 96 L672 110 L688 88 L704 104 L720 84 L732 96",[79,210],{"d":211,"fill":82,"stroke":201,"style":84},"M532 190 L630 104 L732 96",[60,213,214,218,220],{"fill":201},[88,215],{"cx":216,"cy":91,"r":217},"532","4",[88,219],{"cx":204,"cy":119,"r":217},[88,221],{"cx":222,"cy":127,"r":217},"732",[51,224,225],{"x":204,"y":146,"style":147,"fill":201,"textAnchor":57},"shape is now a caricature",[227,228,230],"h2",{"id":229},"prerequisites","Prerequisites",[232,233,234,242,249],"ul",{},[235,236,237,241],"li",{},[238,239,240],"strong",{},"QGIS 3.34 LTR"," (bundled Python 3.12) or newer.",[235,243,244,245,248],{},"A layer in a ",[238,246,247],{},"projected CRS",", because the tolerance is expressed in map units and a tolerance in degrees is almost never what you want.",[235,250,251,252,256],{},"Valid geometry — simplification of a self-intersecting polygon can produce a worse self-intersection. Repair first with ",[21,253,255],{"href":254},"\u002Fspatial-data-processing-automation\u002Fgeometry-operations-and-predicates\u002Ffix-invalid-geometries-pyqgis\u002F","Find and Fix Invalid Geometries",".",[227,258,260],{"id":259},"simplify-one-geometry","Simplify one geometry",[14,262,263,267],{},[264,265,266],"code",{},"simplify()"," implements Douglas-Peucker: it keeps the endpoints, finds the vertex furthest from the line joining them, and recurses on either side while that distance exceeds the tolerance.",[269,270,275],"pre",{"className":271,"code":272,"language":273,"meta":274,"style":274},"language-python shiki shiki-themes github-dark","from qgis.core import QgsProject\n\nlayer = QgsProject.instance().mapLayersByName(\"coastline\")[0]\ngeometry = next(layer.getFeatures()).geometry()\n\nbefore = geometry.constGet().vertexCount()\nsimplified = geometry.simplify(10.0)\nafter = simplified.constGet().vertexCount()\n\nprint(f\"{before} -> {after} vertices ({100 * (1 - after \u002F before):.1f}% removed)\")\n","python","",[264,276,277,296,303,328,342,347,358,375,386,391],{"__ignoreMap":274},[278,279,282,286,290,293],"span",{"class":280,"line":281},"line",1,[278,283,285],{"class":284},"snl16","from",[278,287,289],{"class":288},"s95oV"," qgis.core ",[278,291,292],{"class":284},"import",[278,294,295],{"class":288}," QgsProject\n",[278,297,299],{"class":280,"line":298},2,[278,300,302],{"emptyLinePlaceholder":301},true,"\n",[278,304,306,309,312,315,319,322,325],{"class":280,"line":305},3,[278,307,308],{"class":288},"layer ",[278,310,311],{"class":284},"=",[278,313,314],{"class":288}," QgsProject.instance().mapLayersByName(",[278,316,318],{"class":317},"sU2Wk","\"coastline\"",[278,320,321],{"class":288},")[",[278,323,46],{"class":324},"sDLfK",[278,326,327],{"class":288},"]\n",[278,329,331,334,336,339],{"class":280,"line":330},4,[278,332,333],{"class":288},"geometry ",[278,335,311],{"class":284},[278,337,338],{"class":324}," next",[278,340,341],{"class":288},"(layer.getFeatures()).geometry()\n",[278,343,345],{"class":280,"line":344},5,[278,346,302],{"emptyLinePlaceholder":301},[278,348,350,353,355],{"class":280,"line":349},6,[278,351,352],{"class":288},"before ",[278,354,311],{"class":284},[278,356,357],{"class":288}," geometry.constGet().vertexCount()\n",[278,359,361,364,366,369,372],{"class":280,"line":360},7,[278,362,363],{"class":288},"simplified ",[278,365,311],{"class":284},[278,367,368],{"class":288}," geometry.simplify(",[278,370,371],{"class":324},"10.0",[278,373,374],{"class":288},")\n",[278,376,378,381,383],{"class":280,"line":377},8,[278,379,380],{"class":288},"after ",[278,382,311],{"class":284},[278,384,385],{"class":288}," simplified.constGet().vertexCount()\n",[278,387,389],{"class":280,"line":388},9,[278,390,302],{"emptyLinePlaceholder":301},[278,392,394,397,400,403,406,409,412,415,418,420,423,425,428,431,434,437,440,443,446,449,452,455,457,460],{"class":280,"line":393},10,[278,395,396],{"class":324},"print",[278,398,399],{"class":288},"(",[278,401,402],{"class":284},"f",[278,404,405],{"class":317},"\"",[278,407,408],{"class":324},"{",[278,410,411],{"class":288},"before",[278,413,414],{"class":324},"}",[278,416,417],{"class":317}," -> ",[278,419,408],{"class":324},[278,421,422],{"class":288},"after",[278,424,414],{"class":324},[278,426,427],{"class":317}," vertices (",[278,429,430],{"class":324},"{100",[278,432,433],{"class":284}," *",[278,435,436],{"class":288}," (",[278,438,439],{"class":324},"1",[278,441,442],{"class":284}," -",[278,444,445],{"class":288}," after ",[278,447,448],{"class":284},"\u002F",[278,450,451],{"class":288}," before)",[278,453,454],{"class":284},":.1f",[278,456,414],{"class":324},[278,458,459],{"class":317},"% removed)\"",[278,461,374],{"class":288},[14,463,464,467,468,470,471,474],{},[238,465,466],{},"Breakdown:"," The tolerance is in map units, so ",[264,469,371],{}," in a metric CRS means no dropped vertex is more than ten metres from the retained line. ",[264,472,473],{},"constGet().vertexCount()"," is the honest measure of how much was removed — file size and render time both track it closely. Printing the percentage rather than the raw numbers makes it easy to compare tolerances quickly.",[14,476,477],{},"Choosing a tolerance is a rendering decision, and the useful rule of thumb ties it to the scale the data will be drawn at: a vertex closer than half a pixel to its neighbour cannot be seen. At 1:50 000 on a 96 DPI screen, one pixel is roughly 13 m on the ground, so a tolerance around 6 m is invisible.",[269,479,481],{"className":271,"code":480,"language":273,"meta":274,"style":274},"def tolerance_for_scale(scale, dpi=96, pixels=0.5):\n    \"\"\"Ground distance corresponding to a fraction of a pixel at a given scale.\"\"\"\n    metres_per_pixel = (0.0254 \u002F dpi) * scale\n    return metres_per_pixel * pixels\n\nprint(round(tolerance_for_scale(50000), 1), \"m at 1:50 000\")\nprint(round(tolerance_for_scale(2000000), 1), \"m at 1:2 000 000\")\n",[264,482,483,510,515,539,552,556,583],{"__ignoreMap":274},[278,484,485,488,492,495,497,499,502,504,507],{"class":280,"line":281},[278,486,487],{"class":284},"def",[278,489,491],{"class":490},"svObZ"," tolerance_for_scale",[278,493,494],{"class":288},"(scale, dpi",[278,496,311],{"class":284},[278,498,127],{"class":324},[278,500,501],{"class":288},", pixels",[278,503,311],{"class":284},[278,505,506],{"class":324},"0.5",[278,508,509],{"class":288},"):\n",[278,511,512],{"class":280,"line":298},[278,513,514],{"class":317},"    \"\"\"Ground distance corresponding to a fraction of a pixel at a given scale.\"\"\"\n",[278,516,517,520,522,524,527,530,533,536],{"class":280,"line":305},[278,518,519],{"class":288},"    metres_per_pixel ",[278,521,311],{"class":284},[278,523,436],{"class":288},[278,525,526],{"class":324},"0.0254",[278,528,529],{"class":284}," \u002F",[278,531,532],{"class":288}," dpi) ",[278,534,535],{"class":284},"*",[278,537,538],{"class":288}," scale\n",[278,540,541,544,547,549],{"class":280,"line":330},[278,542,543],{"class":284},"    return",[278,545,546],{"class":288}," metres_per_pixel ",[278,548,535],{"class":284},[278,550,551],{"class":288}," pixels\n",[278,553,554],{"class":280,"line":344},[278,555,302],{"emptyLinePlaceholder":301},[278,557,558,560,562,565,568,571,574,576,578,581],{"class":280,"line":349},[278,559,396],{"class":324},[278,561,399],{"class":288},[278,563,564],{"class":324},"round",[278,566,567],{"class":288},"(tolerance_for_scale(",[278,569,570],{"class":324},"50000",[278,572,573],{"class":288},"), ",[278,575,439],{"class":324},[278,577,573],{"class":288},[278,579,580],{"class":317},"\"m at 1:50 000\"",[278,582,374],{"class":288},[278,584,585,587,589,591,593,596,598,600,602,605],{"class":280,"line":360},[278,586,396],{"class":324},[278,588,399],{"class":288},[278,590,564],{"class":324},[278,592,567],{"class":288},[278,594,595],{"class":324},"2000000",[278,597,573],{"class":288},[278,599,439],{"class":324},[278,601,573],{"class":288},[278,603,604],{"class":317},"\"m at 1:2 000 000\"",[278,606,374],{"class":288},[14,608,609,611,612,616],{},[238,610,466],{}," The chain is pixels → inches (divide by DPI) → metres on paper (× 0.0254) → metres on the ground (× the scale denominator) — the same conversion used for ",[21,613,615],{"href":614},"\u002Fpyqgis-cartography-visualization\u002Fmap-canvas-and-image-export\u002F","map scale and DPI"," when exporting images. Deriving the tolerance rather than guessing it means the simplification is provably invisible at the target scale.",[227,618,620],{"id":619},"simplify-a-whole-layer","Simplify a whole layer",[14,622,623],{},"The Processing algorithm handles the iteration and offers two additional methods beyond Douglas-Peucker.",[269,625,627],{"className":271,"code":626,"language":273,"meta":274,"style":274},"import processing\n\nprocessing.run(\"native:simplifygeometries\", {\n    \"INPUT\": \"\u002Fdata\u002Fcoastline.gpkg|layername=coastline\",\n    \"METHOD\": 0,          # 0 distance (Douglas-Peucker), 1 snap to grid, 2 area (Visvalingam)\n    \"TOLERANCE\": 10.0,\n    \"OUTPUT\": \"\u002Fdata\u002Foutput\u002Fcoastline_simple.gpkg\",\n})\n",[264,628,629,636,640,651,665,681,692,704],{"__ignoreMap":274},[278,630,631,633],{"class":280,"line":281},[278,632,292],{"class":284},[278,634,635],{"class":288}," processing\n",[278,637,638],{"class":280,"line":298},[278,639,302],{"emptyLinePlaceholder":301},[278,641,642,645,648],{"class":280,"line":305},[278,643,644],{"class":288},"processing.run(",[278,646,647],{"class":317},"\"native:simplifygeometries\"",[278,649,650],{"class":288},", {\n",[278,652,653,656,659,662],{"class":280,"line":330},[278,654,655],{"class":317},"    \"INPUT\"",[278,657,658],{"class":288},": ",[278,660,661],{"class":317},"\"\u002Fdata\u002Fcoastline.gpkg|layername=coastline\"",[278,663,664],{"class":288},",\n",[278,666,667,670,672,674,677],{"class":280,"line":344},[278,668,669],{"class":317},"    \"METHOD\"",[278,671,658],{"class":288},[278,673,46],{"class":324},[278,675,676],{"class":288},",          ",[278,678,680],{"class":679},"sjoCn","# 0 distance (Douglas-Peucker), 1 snap to grid, 2 area (Visvalingam)\n",[278,682,683,686,688,690],{"class":280,"line":349},[278,684,685],{"class":317},"    \"TOLERANCE\"",[278,687,658],{"class":288},[278,689,371],{"class":324},[278,691,664],{"class":288},[278,693,694,697,699,702],{"class":280,"line":360},[278,695,696],{"class":317},"    \"OUTPUT\"",[278,698,658],{"class":288},[278,700,701],{"class":317},"\"\u002Fdata\u002Foutput\u002Fcoastline_simple.gpkg\"",[278,703,664],{"class":288},[278,705,706],{"class":280,"line":377},[278,707,708],{"class":288},"})\n",[14,710,711,713,714,717,718,721,722,725],{},[238,712,466],{}," ",[238,715,716],{},"Distance"," (0) is Douglas-Peucker and preserves the extremes of a shape, which suits coastlines and boundaries. ",[238,719,720],{},"Snap to grid"," (1) rounds coordinates onto a regular grid, which is blunt but produces coordinates that compress extremely well. ",[238,723,724],{},"Area"," (2) is Visvalingam-Whyatt, which removes the vertices forming the smallest triangles and tends to look more natural on smooth curves — it degrades more gracefully at aggressive tolerances than Douglas-Peucker, which can produce visible spikes.",[227,727,729],{"id":728},"preserve-shared-boundaries","Preserve shared boundaries",[14,731,732],{},"This is the failure that turns a tidy simplification into a day of repair work. Two polygons that share a boundary, simplified independently, keep different subsets of the shared vertices — so the boundary no longer matches and gaps and overlaps appear along it.",[14,734,735],{},[29,736,739,742,745,748,751,771,798],{"viewBox":737,"role":32,"ariaLabel":738,"xmlns":34},"0 0 760 254","Two adjacent polygons simplified independently develop gaps and slivers along their shared boundary, while topology-preserving simplification keeps the boundary identical on both sides",[36,740,741],{},"Why independent simplification breaks shared boundaries",[40,743,744],{},"On the left, two adjacent polygons share a jagged boundary. In the middle, each has been simplified on its own and the two versions of the shared boundary no longer coincide, leaving a gap on one side and an overlap on the other. On the right, topology-preserving simplification produces one shared boundary used identically by both polygons.",[44,746],{"x":46,"y":46,"width":47,"height":747,"fill":49},"254",[51,749,750],{"x":53,"y":54,"style":55,"fill":56,"textAnchor":57},"Simplifying neighbours independently pulls their shared edge apart",[60,752,753,756,759,764,767],{},[44,754],{"x":64,"y":65,"width":66,"height":755,"rx":68,"fill":69,"stroke":70,"style":71},"192",[51,757,758],{"x":74,"y":75,"style":76,"fill":56,"textAnchor":57},"original neighbours",[79,760],{"d":761,"fill":762,"fillOpacity":763,"stroke":762,"style":71},"M36 200 L36 96 L110 104 L96 130 L120 152 L102 176 L118 200 Z","#2563eb",0.16,[79,765],{"d":766,"fill":83,"fillOpacity":763,"stroke":83,"style":71},"M118 200 L102 176 L120 152 L96 130 L110 104 L224 96 L224 200 Z",[51,768,770],{"x":74,"y":769,"style":147,"fill":148,"textAnchor":57},"224","one shared boundary",[60,772,773,776,779,782,785,790,795],{},[44,774],{"x":154,"y":65,"width":66,"height":755,"rx":68,"fill":69,"stroke":775,"style":156},"#b91c1c",[51,777,778],{"x":53,"y":75,"style":76,"fill":775,"textAnchor":57},"simplified separately",[79,780],{"d":781,"fill":762,"fillOpacity":763,"stroke":762,"style":71},"M286 200 L286 96 L360 104 L368 200 Z",[79,783],{"d":784,"fill":83,"fillOpacity":763,"stroke":83,"style":71},"M344 200 L352 152 L360 104 L474 96 L474 200 Z",[79,786],{"d":787,"fill":775,"fillOpacity":788,"stroke":775,"style":789},"M344 200 L352 152 L360 104 L368 200 Z",0.4,"stroke-width:1.5",[51,791,794],{"x":792,"y":122,"style":793,"fill":775},"404","font-size:11px;font-weight:bold;font-family:sans-serif","sliver",[51,796,797],{"x":53,"y":769,"style":147,"fill":775,"textAnchor":57},"two boundaries that disagree",[60,799,800,802,805,808,811,815],{},[44,801],{"x":200,"y":65,"width":66,"height":755,"rx":68,"fill":69,"stroke":155,"style":156},[51,803,804],{"x":204,"y":75,"style":76,"fill":155,"textAnchor":57},"topology preserved",[79,806],{"d":807,"fill":762,"fillOpacity":763,"stroke":762,"style":71},"M536 200 L536 96 L610 104 L618 200 Z",[79,809],{"d":810,"fill":83,"fillOpacity":763,"stroke":83,"style":71},"M618 200 L610 104 L724 96 L724 200 Z",[79,812],{"d":813,"fill":82,"stroke":155,"style":814},"M618 200 L610 104","stroke-width:3.5",[51,816,817],{"x":204,"y":769,"style":147,"fill":155,"textAnchor":57},"one boundary, used by both",[14,819,820],{},"QGIS's own simplification does not preserve topology across features. When the shared boundary matters — administrative areas, land parcels, anything that tiles a surface — convert the polygons to their boundary lines, simplify those once, and rebuild the polygons:",[269,822,824],{"className":271,"code":823,"language":273,"meta":274,"style":274},"import processing\n\nlines = processing.run(\"native:polygonstolines\", {\n    \"INPUT\": \"\u002Fdata\u002Fdistricts.gpkg|layername=districts\",\n    \"OUTPUT\": \"TEMPORARY_OUTPUT\",\n})[\"OUTPUT\"]\n\nsimple_lines = processing.run(\"native:simplifygeometries\", {\n    \"INPUT\": lines, \"METHOD\": 0, \"TOLERANCE\": 25.0,\n    \"OUTPUT\": \"TEMPORARY_OUTPUT\",\n})[\"OUTPUT\"]\n\npolygons = processing.run(\"native:polygonize\", {\n    \"INPUT\": simple_lines, \"KEEP_FIELDS\": False,\n    \"OUTPUT\": \"\u002Fdata\u002Foutput\u002Fdistricts_simple.gpkg\",\n})[\"OUTPUT\"]\n",[264,825,826,832,836,851,862,873,883,887,900,927,937,946,951,966,984,996],{"__ignoreMap":274},[278,827,828,830],{"class":280,"line":281},[278,829,292],{"class":284},[278,831,635],{"class":288},[278,833,834],{"class":280,"line":298},[278,835,302],{"emptyLinePlaceholder":301},[278,837,838,841,843,846,849],{"class":280,"line":305},[278,839,840],{"class":288},"lines ",[278,842,311],{"class":284},[278,844,845],{"class":288}," processing.run(",[278,847,848],{"class":317},"\"native:polygonstolines\"",[278,850,650],{"class":288},[278,852,853,855,857,860],{"class":280,"line":330},[278,854,655],{"class":317},[278,856,658],{"class":288},[278,858,859],{"class":317},"\"\u002Fdata\u002Fdistricts.gpkg|layername=districts\"",[278,861,664],{"class":288},[278,863,864,866,868,871],{"class":280,"line":344},[278,865,696],{"class":317},[278,867,658],{"class":288},[278,869,870],{"class":317},"\"TEMPORARY_OUTPUT\"",[278,872,664],{"class":288},[278,874,875,878,881],{"class":280,"line":349},[278,876,877],{"class":288},"})[",[278,879,880],{"class":317},"\"OUTPUT\"",[278,882,327],{"class":288},[278,884,885],{"class":280,"line":360},[278,886,302],{"emptyLinePlaceholder":301},[278,888,889,892,894,896,898],{"class":280,"line":377},[278,890,891],{"class":288},"simple_lines ",[278,893,311],{"class":284},[278,895,845],{"class":288},[278,897,647],{"class":317},[278,899,650],{"class":288},[278,901,902,904,907,910,912,914,917,920,922,925],{"class":280,"line":388},[278,903,655],{"class":317},[278,905,906],{"class":288},": lines, ",[278,908,909],{"class":317},"\"METHOD\"",[278,911,658],{"class":288},[278,913,46],{"class":324},[278,915,916],{"class":288},", ",[278,918,919],{"class":317},"\"TOLERANCE\"",[278,921,658],{"class":288},[278,923,924],{"class":324},"25.0",[278,926,664],{"class":288},[278,928,929,931,933,935],{"class":280,"line":393},[278,930,696],{"class":317},[278,932,658],{"class":288},[278,934,870],{"class":317},[278,936,664],{"class":288},[278,938,940,942,944],{"class":280,"line":939},11,[278,941,877],{"class":288},[278,943,880],{"class":317},[278,945,327],{"class":288},[278,947,949],{"class":280,"line":948},12,[278,950,302],{"emptyLinePlaceholder":301},[278,952,954,957,959,961,964],{"class":280,"line":953},13,[278,955,956],{"class":288},"polygons ",[278,958,311],{"class":284},[278,960,845],{"class":288},[278,962,963],{"class":317},"\"native:polygonize\"",[278,965,650],{"class":288},[278,967,969,971,974,977,979,982],{"class":280,"line":968},14,[278,970,655],{"class":317},[278,972,973],{"class":288},": simple_lines, ",[278,975,976],{"class":317},"\"KEEP_FIELDS\"",[278,978,658],{"class":288},[278,980,981],{"class":324},"False",[278,983,664],{"class":288},[278,985,987,989,991,994],{"class":280,"line":986},15,[278,988,696],{"class":317},[278,990,658],{"class":288},[278,992,993],{"class":317},"\"\u002Fdata\u002Foutput\u002Fdistricts_simple.gpkg\"",[278,995,664],{"class":288},[278,997,999,1001,1003],{"class":280,"line":998},16,[278,1000,877],{"class":288},[278,1002,880],{"class":317},[278,1004,327],{"class":288},[14,1006,1007,1009,1010,1013,1014,1017,1018,1021,1022,1025],{},[238,1008,466],{}," Each shared boundary segment appears once in the line layer, so simplifying it once guarantees both neighbours end up with the identical edge. ",[264,1011,1012],{},"native:polygonize"," rebuilds closed areas from the line network. The cost is that attributes do not survive the round trip — ",[264,1015,1016],{},"KEEP_FIELDS: False"," acknowledges that — so the result has to be re-joined to the original attributes by a spatial relationship, typically with ",[264,1019,1020],{},"native:joinattributesbylocation"," using the original centroids. For heavy generalisation of administrative boundaries, dedicated tools such as GRASS ",[264,1023,1024],{},"v.generalize"," with its topology support are worth the extra dependency.",[227,1027,1029],{"id":1028},"simplify-for-display-only","Simplify for display only",[14,1031,1032,1033,1037],{},"Simplification is destructive, and often what you actually want is a ",[1034,1035,1036],"em",{},"faster render"," rather than a smaller dataset. QGIS can simplify at draw time, leaving the stored geometry untouched — full precision for analysis, few vertices for the screen.",[14,1039,1040],{},[29,1041,1044,1047,1050,1053,1068,1071,1076,1080,1086,1091,1095,1099,1103,1106,1109,1114,1117,1121,1124,1128,1131,1135,1137,1140,1144,1146,1149,1153,1155],{"viewBox":1042,"role":32,"ariaLabel":1043,"xmlns":34},"0 0 760 240","Two strategies compared: stored simplification writes a reduced dataset used for both analysis and rendering, while render-time simplification keeps full precision on disk and reduces only what is drawn",[36,1045,1046],{},"Stored simplification versus render-time simplification",[40,1048,1049],{},"On the left, a source layer is simplified once and written to disk, so both the analysis path and the rendering path consume the reduced geometry. On the right, the full-precision layer is kept and only the rendering path applies simplification, so analysis still sees every vertex.",[44,1051],{"x":46,"y":46,"width":47,"height":1052,"fill":49},"240",[1054,1055,1056],"defs",{},[1057,1058,1065],"marker",{"id":1059,"viewBox":1060,"refX":1061,"refY":1062,"markerWidth":1063,"markerHeight":1063,"orient":1064},"simpModeArrow","0 0 10 10","8","5","7","auto-start-reverse",[79,1066],{"d":1067,"fill":148},"M0 0 L10 5 L0 10 z",[51,1069,1070],{"x":53,"y":54,"style":55,"fill":56,"textAnchor":57},"Only one of these keeps your measurements exact",[44,1072],{"x":1073,"y":65,"width":1074,"height":1075,"rx":68,"fill":69,"stroke":201,"style":156},"16","356","180",[51,1077,1079],{"x":1078,"y":75,"style":76,"fill":201,"textAnchor":57},"194","simplify and store",[44,1081],{"x":1082,"y":1083,"width":119,"height":1084,"rx":1085,"fill":69,"stroke":70,"style":789},"40","86","42","6",[51,1087,1090],{"x":1088,"y":1089,"style":147,"fill":148,"textAnchor":57},"92","112","source",[44,1092],{"x":1093,"y":1083,"width":1089,"height":1084,"rx":1085,"fill":201,"fillOpacity":1094,"stroke":201,"style":71},"176",0.2,[51,1096,1098],{"x":143,"y":1097,"style":147,"fill":148,"textAnchor":57},"106","simplified",[51,1100,1102],{"x":143,"y":1101,"style":147,"fill":148,"textAnchor":57},"121","on disk",[44,1104],{"x":1093,"y":108,"width":1089,"height":1105,"rx":1085,"fill":69,"stroke":775,"style":71},"34",[51,1107,1108],{"x":143,"y":100,"style":147,"fill":775,"textAnchor":57},"analysis too",[280,1110],{"x1":1111,"y1":1112,"x2":100,"y2":1112,"stroke":148,"style":1113},"144","107","stroke-width:2;marker-end:url(#simpModeArrow)",[280,1115],{"x1":143,"y1":1116,"x2":143,"y2":122,"stroke":775,"style":1113},"128",[51,1118,1120],{"x":1078,"y":1119,"style":147,"fill":775,"textAnchor":57},"208","areas and lengths now approximate",[44,1122],{"x":1123,"y":65,"width":1074,"height":1075,"rx":68,"fill":69,"stroke":155,"style":156},"388",[51,1125,1127],{"x":1126,"y":75,"style":76,"fill":155,"textAnchor":57},"566","simplify at render time",[44,1129],{"x":1130,"y":1083,"width":1089,"height":1084,"rx":1085,"fill":155,"fillOpacity":763,"stroke":155,"style":71},"412",[51,1132,1134],{"x":1133,"y":1097,"style":147,"fill":148,"textAnchor":57},"468","full precision",[51,1136,1102],{"x":1133,"y":1101,"style":147,"fill":148,"textAnchor":57},[44,1138],{"x":1139,"y":1083,"width":116,"height":1084,"rx":1085,"fill":69,"stroke":762,"style":71},"588",[51,1141,1143],{"x":1142,"y":1089,"style":147,"fill":148,"textAnchor":57},"654","reduced for drawing",[44,1145],{"x":1130,"y":108,"width":1089,"height":1105,"rx":1085,"fill":69,"stroke":155,"style":71},[51,1147,1148],{"x":1133,"y":100,"style":147,"fill":155,"textAnchor":57},"analysis exact",[280,1150],{"x1":1151,"y1":1112,"x2":1152,"y2":1112,"stroke":762,"style":1113},"524","584",[280,1154],{"x1":1133,"y1":1116,"x2":1133,"y2":122,"stroke":155,"style":1113},[51,1156,1157],{"x":1126,"y":1119,"style":147,"fill":155,"textAnchor":57},"nothing on disk is altered",[269,1159,1161],{"className":271,"code":1160,"language":273,"meta":274,"style":274},"from qgis.core import QgsProject, QgsVectorSimplifyMethod\n\nlayer = QgsProject.instance().mapLayersByName(\"coastline\")[0]\n\nmethod = QgsVectorSimplifyMethod()\nmethod.setSimplifyHints(QgsVectorSimplifyMethod.GeometrySimplification)\nmethod.setSimplifyAlgorithm(QgsVectorSimplifyMethod.Distance)\nmethod.setThreshold(1.0)                 # in pixels, not map units\nmethod.setForceLocalOptimization(True)\n\nlayer.setSimplifyMethod(method)\nlayer.triggerRepaint()\n",[264,1162,1163,1174,1178,1194,1198,1208,1213,1218,1232,1242,1246,1251],{"__ignoreMap":274},[278,1164,1165,1167,1169,1171],{"class":280,"line":281},[278,1166,285],{"class":284},[278,1168,289],{"class":288},[278,1170,292],{"class":284},[278,1172,1173],{"class":288}," QgsProject, QgsVectorSimplifyMethod\n",[278,1175,1176],{"class":280,"line":298},[278,1177,302],{"emptyLinePlaceholder":301},[278,1179,1180,1182,1184,1186,1188,1190,1192],{"class":280,"line":305},[278,1181,308],{"class":288},[278,1183,311],{"class":284},[278,1185,314],{"class":288},[278,1187,318],{"class":317},[278,1189,321],{"class":288},[278,1191,46],{"class":324},[278,1193,327],{"class":288},[278,1195,1196],{"class":280,"line":330},[278,1197,302],{"emptyLinePlaceholder":301},[278,1199,1200,1203,1205],{"class":280,"line":344},[278,1201,1202],{"class":288},"method ",[278,1204,311],{"class":284},[278,1206,1207],{"class":288}," QgsVectorSimplifyMethod()\n",[278,1209,1210],{"class":280,"line":349},[278,1211,1212],{"class":288},"method.setSimplifyHints(QgsVectorSimplifyMethod.GeometrySimplification)\n",[278,1214,1215],{"class":280,"line":360},[278,1216,1217],{"class":288},"method.setSimplifyAlgorithm(QgsVectorSimplifyMethod.Distance)\n",[278,1219,1220,1223,1226,1229],{"class":280,"line":377},[278,1221,1222],{"class":288},"method.setThreshold(",[278,1224,1225],{"class":324},"1.0",[278,1227,1228],{"class":288},")                 ",[278,1230,1231],{"class":679},"# in pixels, not map units\n",[278,1233,1234,1237,1240],{"class":280,"line":388},[278,1235,1236],{"class":288},"method.setForceLocalOptimization(",[278,1238,1239],{"class":324},"True",[278,1241,374],{"class":288},[278,1243,1244],{"class":280,"line":393},[278,1245,302],{"emptyLinePlaceholder":301},[278,1247,1248],{"class":280,"line":939},[278,1249,1250],{"class":288},"layer.setSimplifyMethod(method)\n",[278,1252,1253],{"class":280,"line":948},[278,1254,1255],{"class":288},"layer.triggerRepaint()\n",[14,1257,1258,713,1260,1263,1264,1267,1268,1271,1272,1275],{},[238,1259,466],{},[264,1261,1262],{},"setThreshold()"," here is in ",[238,1265,1266],{},"screen pixels",", not map units — a threshold of 1.0 drops any vertex that would land within a pixel of its neighbour at the current zoom, which is by definition invisible. Because the tolerance is relative to the display, the simplification automatically becomes gentler as the user zooms in. ",[264,1269,1270],{},"setForceLocalOptimization(True)"," lets QGIS simplify in the provider where supported, so the vertices are never even transferred. Nothing about the stored data changes, so ",[264,1273,1274],{},"measureArea()"," and every predicate still see the full-precision geometry.",[14,1277,1278],{},"Use render-time simplification whenever the goal is a responsive canvas, and stored simplification only when the deliverable itself needs to be smaller — a web tile set, a mobile export, an API payload.",[227,1280,1282],{"id":1281},"qgis-version-compatibility","QGIS version compatibility",[14,1284,1285,1286,1288],{},"The examples target ",[238,1287,240],{}," (Python 3.12).",[1290,1291,1292,1308],"table",{},[1293,1294,1295],"thead",{},[1296,1297,1298,1302,1305],"tr",{},[1299,1300,1301],"th",{},"QGIS version",[1299,1303,1304],{},"Python",[1299,1306,1307],{},"Notes",[1309,1310,1311,1323,1334],"tbody",{},[1296,1312,1313,1317,1320],{},[1314,1315,1316],"td",{},"3.28 LTR",[1314,1318,1319],{},"3.9",[1314,1321,1322],{},"Identical API and algorithm parameters.",[1296,1324,1325,1328,1331],{},[1314,1326,1327],{},"3.34 LTR",[1314,1329,1330],{},"3.12",[1314,1332,1333],{},"Baseline for this page.",[1296,1335,1336,1339,1341],{},[1314,1337,1338],{},"3.40 \u002F 3.44",[1314,1340,1330],{},[1314,1342,1343,1346],{},[264,1344,1345],{},"QgsGeometry.simplifyCoverageVW()"," adds coverage-aware simplification, removing the need for the lines round trip.",[14,1348,1349,1351,1352,1355],{},[264,1350,266],{}," and ",[264,1353,1354],{},"native:simplifygeometries"," are unchanged across 3.x. If you are on 3.40 or newer and simplifying a polygon coverage, prefer the coverage-aware method.",[227,1357,1359],{"id":1358},"troubleshooting","Troubleshooting",[232,1361,1362,1368,1378,1384,1394,1402],{},[235,1363,1364,1367],{},[238,1365,1366],{},"Nothing was removed."," The tolerance is smaller than the spacing between vertices. Raise it, or check the CRS — a tolerance of 10 in EPSG:4326 means ten degrees, which flattens everything to a straight line.",[235,1369,1370,1373,1374,1377],{},[238,1371,1372],{},"The shape collapsed to a line or vanished."," The tolerance exceeded the shape's own dimensions. Compare ",[264,1375,1376],{},"vertexCount()"," before and after and back the tolerance off.",[235,1379,1380,1383],{},[238,1381,1382],{},"Gaps and slivers between neighbours."," Each polygon was simplified independently. Use the lines round trip above, or the coverage-aware method on 3.40+.",[235,1385,1386,1389,1390,1393],{},[238,1387,1388],{},"Self-intersections appeared."," Douglas-Peucker can create them at aggressive tolerances on convoluted shapes. Run ",[264,1391,1392],{},"native:fixgeometries"," afterwards, or switch to the area method.",[235,1395,1396,713,1399,1401],{},[238,1397,1398],{},"Attributes are missing from the rebuilt polygons.",[264,1400,1012],{}," does not carry attributes. Re-join them by location using the original centroids.",[235,1403,1404,1407],{},[238,1405,1406],{},"File size barely changed."," Vertex count is not the only cost — check whether the layer's size is dominated by attributes rather than coordinates.",[227,1409,1411],{"id":1410},"conclusion","Conclusion",[14,1413,1414],{},"Simplification is a scale decision expressed as a tolerance: derive it from the map scale the data will be drawn at rather than guessing, verify the effect by comparing vertex counts, and pick Douglas-Peucker for boundaries and the area method for smooth curves. Whenever polygons share edges, simplify the shared boundaries once rather than each polygon independently.",[227,1416,1418],{"id":1417},"frequently-asked-questions","Frequently Asked Questions",[14,1420,1421,1424],{},[238,1422,1423],{},"What tolerance should I use?","\nDerive it from the target map scale. A vertex closer than half a pixel to the retained line is invisible, so at 1:50 000 and 96 DPI a tolerance around 6 m is imperceptible. Guessing tends to be either too timid to help or aggressive enough to distort shapes.",[14,1426,1427,1430],{},[238,1428,1429],{},"Why did gaps appear between my polygons?","\nThey were simplified independently, so each kept a different subset of the shared boundary's vertices. Convert to lines, simplify once, and polygonize — or use the coverage-aware simplification available in QGIS 3.40 and newer.",[14,1432,1433,1436],{},[238,1434,1435],{},"Which simplification method is best?","\nDistance (Douglas-Peucker) preserves the extremes of a shape and suits boundaries and coastlines. Area (Visvalingam) removes the least significant vertices by triangle area and looks more natural on smooth curves at aggressive tolerances.",[14,1438,1439,1442],{},[238,1440,1441],{},"Does simplifying change the area of a polygon?","\nYes, slightly. Douglas-Peucker does not preserve area, so a simplified polygon's measured area differs from the original. If area must be preserved exactly, keep the original geometry for measurement and use the simplified copy only for rendering.",[227,1444,1446],{"id":1445},"related","Related",[232,1448,1449,1454,1459,1465],{},[235,1450,1451,1453],{},[21,1452,24],{"href":23}," — the guide this recipe belongs to",[235,1455,1456],{},[21,1457,1458],{"href":254},"Find and Fix Invalid Geometries in PyQGIS",[235,1460,1461],{},[21,1462,1464],{"href":1463},"\u002Fspatial-data-processing-automation\u002Fgeometry-operations-and-predicates\u002Fbuffer-geometry-pyqgis\u002F","Buffer a Geometry in PyQGIS",[235,1466,1467],{},[21,1468,1469],{"href":614},"Map Canvas Control and Image Export in PyQGIS",[1471,1472,1473],"style",{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sjoCn, html code.shiki .sjoCn{--shiki-default:#9AA79F}",{"title":274,"searchDepth":298,"depth":298,"links":1475},[1476,1477,1478,1479,1480,1481,1482,1483,1484,1485],{"id":229,"depth":298,"text":230},{"id":259,"depth":298,"text":260},{"id":619,"depth":298,"text":620},{"id":728,"depth":298,"text":729},{"id":1028,"depth":298,"text":1029},{"id":1281,"depth":298,"text":1282},{"id":1358,"depth":298,"text":1359},{"id":1410,"depth":298,"text":1411},{"id":1417,"depth":298,"text":1418},{"id":1445,"depth":298,"text":1446},"Reduce vertex counts in PyQGIS with QgsGeometry.simplify and native:simplifygeometries, pick a tolerance, and preserve shared boundaries between neighbouring polygons.","md",{"slug":1489,"type":1490,"breadcrumb":1491,"datePublished":1492,"dateModified":1492},"simplify-geometry-pyqgis","article","Simplify Geometry","2026-08-01","\u002Fspatial-data-processing-automation\u002Fgeometry-operations-and-predicates\u002Fsimplify-geometry-pyqgis",{"title":5,"description":1486},"spatial-data-processing-automation\u002Fgeometry-operations-and-predicates\u002Fsimplify-geometry-pyqgis\u002Findex","0ce2EXiIEC3yF08FCalgfJoXliyCvk9us-pRuo-6kaQ",1785585990477]