[{"data":1,"prerenderedAt":693},["ShallowReactive",2],{"doc:\u002Fspatial-data-processing-automation\u002Fvector-data-manipulation\u002Fpyqgis-script-to-calculate-polygon-areas":3},{"id":4,"title":5,"body":6,"description":686,"extension":687,"meta":688,"navigation":95,"path":689,"seo":690,"stem":691,"__hash__":692},"docs\u002Fspatial-data-processing-automation\u002Fvector-data-manipulation\u002Fpyqgis-script-to-calculate-polygon-areas\u002Findex.md","PyQGIS Script to Calculate Polygon Areas",{"type":7,"value":8,"toc":680},"minimark",[9,13,33,38,49,347,351,365,369,415,421,502,513,631,635,676],[10,11,5],"h1",{"id":12},"pyqgis-script-to-calculate-polygon-areas",[14,15,16,17,21,22,26,27,32],"p",{},"To calculate polygon areas with a ",[18,19,20],"strong",{},"PyQGIS script to calculate polygon areas",", use the ",[23,24,25],"code",{},"QgsGeometry.area()"," method inside a feature iteration loop. The script below adds a numeric field to your layer, computes planar area in the layer’s native coordinate reference system (CRS), and writes values directly to the attribute table. For accurate linear measurements, your dataset must use a projected CRS (e.g., UTM or a national grid). Geographic CRS layers (like WGS84) will return meaningless square degrees. This workflow is a foundational step in ",[28,29,31],"a",{"href":30},"\u002Fspatial-data-processing-automation\u002Fvector-data-manipulation\u002F","Vector Data Manipulation"," for automated GIS tasks.",[34,35,37],"h3",{"id":36},"working-script","Working Script",[14,39,40,41,44,45,48],{},"Run this in the QGIS Python Console (",[23,42,43],{},"Plugins > Python Console",") or save as a ",[23,46,47],{},".py"," file and execute via the Processing Toolbox.",[50,51,56],"pre",{"className":52,"code":53,"language":54,"meta":55,"style":55},"language-python shiki shiki-themes github-dark","from qgis.core import QgsProject, QgsField, edit\nfrom qgis.PyQt.QtCore import QVariant\n\n# 1. Reference target polygon layer\nlayer_name = \"your_polygon_layer\"\nlayers = QgsProject.instance().mapLayersByName(layer_name)\nif not layers:\n raise RuntimeError(f\"Layer '{layer_name}' not found in project.\")\nlayer = layers[0]\n\n# 2. Add output field\nfield_name = \"area_sqm\"\nif field_name not in layer.fields().names():\n layer.dataProvider().addAttributes([QgsField(field_name, QVariant.Double)])\n layer.updateFields()\n\n# 3. Calculate and write areas\nwith edit(layer):\n for feat in layer.getFeatures():\n geom = feat.geometry()\n if geom.isGeosValid() and not geom.isEmpty():\n feat.setAttribute(field_name, geom.area())\n layer.updateFeature(feat)\n\nprint(f\"Area calculation complete for {layer.featureCount()} features.\")\n","python","",[23,57,58,77,90,97,104,117,128,140,174,191,196,202,213,230,236,242,247,253,262,277,288,305,311,317,322],{"__ignoreMap":55},[59,60,63,67,71,74],"span",{"class":61,"line":62},"line",1,[59,64,66],{"class":65},"snl16","from",[59,68,70],{"class":69},"s95oV"," qgis.core ",[59,72,73],{"class":65},"import",[59,75,76],{"class":69}," QgsProject, QgsField, edit\n",[59,78,80,82,85,87],{"class":61,"line":79},2,[59,81,66],{"class":65},[59,83,84],{"class":69}," qgis.PyQt.QtCore ",[59,86,73],{"class":65},[59,88,89],{"class":69}," QVariant\n",[59,91,93],{"class":61,"line":92},3,[59,94,96],{"emptyLinePlaceholder":95},true,"\n",[59,98,100],{"class":61,"line":99},4,[59,101,103],{"class":102},"sAwPA","# 1. Reference target polygon layer\n",[59,105,107,110,113],{"class":61,"line":106},5,[59,108,109],{"class":69},"layer_name ",[59,111,112],{"class":65},"=",[59,114,116],{"class":115},"sU2Wk"," \"your_polygon_layer\"\n",[59,118,120,123,125],{"class":61,"line":119},6,[59,121,122],{"class":69},"layers ",[59,124,112],{"class":65},[59,126,127],{"class":69}," QgsProject.instance().mapLayersByName(layer_name)\n",[59,129,131,134,137],{"class":61,"line":130},7,[59,132,133],{"class":65},"if",[59,135,136],{"class":65}," not",[59,138,139],{"class":69}," layers:\n",[59,141,143,146,150,153,156,159,162,165,168,171],{"class":61,"line":142},8,[59,144,145],{"class":65}," raise",[59,147,149],{"class":148},"sDLfK"," RuntimeError",[59,151,152],{"class":69},"(",[59,154,155],{"class":65},"f",[59,157,158],{"class":115},"\"Layer '",[59,160,161],{"class":148},"{",[59,163,164],{"class":69},"layer_name",[59,166,167],{"class":148},"}",[59,169,170],{"class":115},"' not found in project.\"",[59,172,173],{"class":69},")\n",[59,175,177,180,182,185,188],{"class":61,"line":176},9,[59,178,179],{"class":69},"layer ",[59,181,112],{"class":65},[59,183,184],{"class":69}," layers[",[59,186,187],{"class":148},"0",[59,189,190],{"class":69},"]\n",[59,192,194],{"class":61,"line":193},10,[59,195,96],{"emptyLinePlaceholder":95},[59,197,199],{"class":61,"line":198},11,[59,200,201],{"class":102},"# 2. Add output field\n",[59,203,205,208,210],{"class":61,"line":204},12,[59,206,207],{"class":69},"field_name ",[59,209,112],{"class":65},[59,211,212],{"class":115}," \"area_sqm\"\n",[59,214,216,218,221,224,227],{"class":61,"line":215},13,[59,217,133],{"class":65},[59,219,220],{"class":69}," field_name ",[59,222,223],{"class":65},"not",[59,225,226],{"class":65}," in",[59,228,229],{"class":69}," layer.fields().names():\n",[59,231,233],{"class":61,"line":232},14,[59,234,235],{"class":69}," layer.dataProvider().addAttributes([QgsField(field_name, QVariant.Double)])\n",[59,237,239],{"class":61,"line":238},15,[59,240,241],{"class":69}," layer.updateFields()\n",[59,243,245],{"class":61,"line":244},16,[59,246,96],{"emptyLinePlaceholder":95},[59,248,250],{"class":61,"line":249},17,[59,251,252],{"class":102},"# 3. Calculate and write areas\n",[59,254,256,259],{"class":61,"line":255},18,[59,257,258],{"class":65},"with",[59,260,261],{"class":69}," edit(layer):\n",[59,263,265,268,271,274],{"class":61,"line":264},19,[59,266,267],{"class":65}," for",[59,269,270],{"class":69}," feat ",[59,272,273],{"class":65},"in",[59,275,276],{"class":69}," layer.getFeatures():\n",[59,278,280,283,285],{"class":61,"line":279},20,[59,281,282],{"class":69}," geom ",[59,284,112],{"class":65},[59,286,287],{"class":69}," feat.geometry()\n",[59,289,291,294,297,300,302],{"class":61,"line":290},21,[59,292,293],{"class":65}," if",[59,295,296],{"class":69}," geom.isGeosValid() ",[59,298,299],{"class":65},"and",[59,301,136],{"class":65},[59,303,304],{"class":69}," geom.isEmpty():\n",[59,306,308],{"class":61,"line":307},22,[59,309,310],{"class":69}," feat.setAttribute(field_name, geom.area())\n",[59,312,314],{"class":61,"line":313},23,[59,315,316],{"class":69}," layer.updateFeature(feat)\n",[59,318,320],{"class":61,"line":319},24,[59,321,96],{"emptyLinePlaceholder":95},[59,323,325,328,330,332,335,337,340,342,345],{"class":61,"line":324},25,[59,326,327],{"class":148},"print",[59,329,152],{"class":69},[59,331,155],{"class":65},[59,333,334],{"class":115},"\"Area calculation complete for ",[59,336,161],{"class":148},[59,338,339],{"class":69},"layer.featureCount()",[59,341,167],{"class":148},[59,343,344],{"class":115}," features.\"",[59,346,173],{"class":69},[34,348,350],{"id":349},"how-it-works","How It Works",[14,352,353,354,356,357,360,361,364],{},"The script follows a standard reference → schema update → iteration → commit pattern. ",[23,355,25],{}," returns planar area based on the layer’s CRS units (meters → square meters). The ",[23,358,359],{},"with edit(layer):"," context manager batches all changes into a single transaction, drastically improving performance over per-feature disk writes. The ",[23,362,363],{},"isGeosValid()"," check prevents runtime crashes from self-intersecting rings, duplicate vertices, or collapsed geometries. Multi-polygon features are automatically aggregated, requiring no manual flattening.",[34,366,368],{"id":367},"compatibility-fallbacks","Compatibility & Fallbacks",[370,371,372,395,405],"ul",{},[373,374,375,378,379,382,383,386,387,390,391,394],"li",{},[18,376,377],{},"QGIS 3.x Required:"," Uses modern ",[23,380,381],{},"edit()"," context manager and ",[23,384,385],{},"QgsField"," API. Legacy QGIS 2.x ",[23,388,389],{},"startEditing()","\u002F",[23,392,393],{},"commitChanges()"," patterns are deprecated.",[373,396,397,400,401,404],{},[18,398,399],{},"CRS Dependency:"," ",[23,402,403],{},"geom.area()"," is strictly planar. For geographic CRS (EPSG:4326), results will be in square degrees. Reproject first, or use the geodesic fallback below.",[373,406,407,410,411,414],{},[18,408,409],{},"Provider Support:"," Works with Shapefiles, GeoPackage, PostGIS, and FileGDB. Read-only sources will fail on ",[23,412,413],{},"addAttributes()",".",[14,416,417,420],{},[18,418,419],{},"1. Geodesic Area Fallback (No Reprojection Needed)","\nWhen you cannot change the layer CRS, switch to ellipsoidal calculations:",[50,422,424],{"className":52,"code":423,"language":54,"meta":55,"style":55},"from qgis.core import QgsDistanceArea, edit\n\nda = QgsDistanceArea()\nda.setEllipsoid(layer.crs().ellipsoidAcronym())\nda.setEllipsoidalMode(True)\n\nwith edit(layer):\n for feat in layer.getFeatures():\n if feat.geometry().isGeosValid():\n feat.setAttribute(field_name, da.measureArea(feat.geometry()))\n layer.updateFeature(feat)\n",[23,425,426,437,441,451,456,466,470,476,486,493,498],{"__ignoreMap":55},[59,427,428,430,432,434],{"class":61,"line":62},[59,429,66],{"class":65},[59,431,70],{"class":69},[59,433,73],{"class":65},[59,435,436],{"class":69}," QgsDistanceArea, edit\n",[59,438,439],{"class":61,"line":79},[59,440,96],{"emptyLinePlaceholder":95},[59,442,443,446,448],{"class":61,"line":92},[59,444,445],{"class":69},"da ",[59,447,112],{"class":65},[59,449,450],{"class":69}," QgsDistanceArea()\n",[59,452,453],{"class":61,"line":99},[59,454,455],{"class":69},"da.setEllipsoid(layer.crs().ellipsoidAcronym())\n",[59,457,458,461,464],{"class":61,"line":106},[59,459,460],{"class":69},"da.setEllipsoidalMode(",[59,462,463],{"class":148},"True",[59,465,173],{"class":69},[59,467,468],{"class":61,"line":119},[59,469,96],{"emptyLinePlaceholder":95},[59,471,472,474],{"class":61,"line":130},[59,473,258],{"class":65},[59,475,261],{"class":69},[59,477,478,480,482,484],{"class":61,"line":142},[59,479,267],{"class":65},[59,481,270],{"class":69},[59,483,273],{"class":65},[59,485,276],{"class":69},[59,487,488,490],{"class":61,"line":176},[59,489,293],{"class":65},[59,491,492],{"class":69}," feat.geometry().isGeosValid():\n",[59,494,495],{"class":61,"line":193},[59,496,497],{"class":69}," feat.setAttribute(field_name, da.measureArea(feat.geometry()))\n",[59,499,500],{"class":61,"line":198},[59,501,316],{"class":69},[14,503,504,507,508,512],{},[18,505,506],{},"2. Processing Algorithm Alternative","\nIf direct PyQGIS editing fails due to provider locks or permission issues, use the native field calculator algorithm. This approach is safer for batch workflows within ",[28,509,511],{"href":510},"\u002Fspatial-data-processing-automation\u002F","Spatial Data Processing & Automation"," pipelines:",[50,514,516],{"className":52,"code":515,"language":54,"meta":55,"style":55},"import processing\nfrom qgis.core import QgsProject\n\nresult = processing.run(\"native:fieldcalculator\", {\n 'INPUT': layer,\n 'FIELD_NAME': 'area_sqm',\n 'FIELD_TYPE': 0, # Float\n 'FORMULA': '$area',\n 'OUTPUT': 'TEMPORARY_OUTPUT'\n})\nQgsProject.instance().addMapLayer(result['OUTPUT'])\n",[23,517,518,525,536,540,556,564,578,593,605,615,620],{"__ignoreMap":55},[59,519,520,522],{"class":61,"line":62},[59,521,73],{"class":65},[59,523,524],{"class":69}," processing\n",[59,526,527,529,531,533],{"class":61,"line":79},[59,528,66],{"class":65},[59,530,70],{"class":69},[59,532,73],{"class":65},[59,534,535],{"class":69}," QgsProject\n",[59,537,538],{"class":61,"line":92},[59,539,96],{"emptyLinePlaceholder":95},[59,541,542,545,547,550,553],{"class":61,"line":99},[59,543,544],{"class":69},"result ",[59,546,112],{"class":65},[59,548,549],{"class":69}," processing.run(",[59,551,552],{"class":115},"\"native:fieldcalculator\"",[59,554,555],{"class":69},", {\n",[59,557,558,561],{"class":61,"line":106},[59,559,560],{"class":115}," 'INPUT'",[59,562,563],{"class":69},": layer,\n",[59,565,566,569,572,575],{"class":61,"line":119},[59,567,568],{"class":115}," 'FIELD_NAME'",[59,570,571],{"class":69},": ",[59,573,574],{"class":115},"'area_sqm'",[59,576,577],{"class":69},",\n",[59,579,580,583,585,587,590],{"class":61,"line":130},[59,581,582],{"class":115}," 'FIELD_TYPE'",[59,584,571],{"class":69},[59,586,187],{"class":148},[59,588,589],{"class":69},", ",[59,591,592],{"class":102},"# Float\n",[59,594,595,598,600,603],{"class":61,"line":142},[59,596,597],{"class":115}," 'FORMULA'",[59,599,571],{"class":69},[59,601,602],{"class":115},"'$area'",[59,604,577],{"class":69},[59,606,607,610,612],{"class":61,"line":176},[59,608,609],{"class":115}," 'OUTPUT'",[59,611,571],{"class":69},[59,613,614],{"class":115},"'TEMPORARY_OUTPUT'\n",[59,616,617],{"class":61,"line":193},[59,618,619],{"class":69},"})\n",[59,621,622,625,628],{"class":61,"line":198},[59,623,624],{"class":69},"QgsProject.instance().addMapLayer(result[",[59,626,627],{"class":115},"'OUTPUT'",[59,629,630],{"class":69},"])\n",[34,632,634],{"id":633},"troubleshooting","Troubleshooting",[370,636,637,646,655,669],{},[373,638,639,642,643,414],{},[23,640,641],{},"AttributeError: 'QgsVectorLayer' object has no attribute 'dataProvider'",": The layer is likely a raster or not fully loaded. Verify with ",[23,644,645],{},"layer.type() == QgsMapLayer.VectorLayer",[373,647,648,651,652,414],{},[23,649,650],{},"QgsVectorLayerError: Could not add field",": The data source is read-only or lacks write permissions. Export to GeoPackage first using ",[23,653,654],{},"QgsVectorFileWriter",[373,656,657,660,661,664,665,668],{},[23,658,659],{},"NaN"," or ",[23,662,663],{},"0.0"," results: Usually caused by invalid topologies. Run ",[23,666,667],{},"processing.run(\"native:fixgeometries\", {'INPUT': layer, 'OUTPUT': 'memory:'})"," before calculating.",[373,670,671,672,675],{},"Always verify results by sampling polygons with known dimensions or comparing against the QGIS Identify tool. Wrap production runs in ",[23,673,674],{},"try\u002Fexcept"," and log failed feature IDs to maintain data integrity.",[677,678,679],"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 .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}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);}",{"title":55,"searchDepth":79,"depth":79,"links":681},[682,683,684,685],{"id":36,"depth":92,"text":37},{"id":349,"depth":92,"text":350},{"id":367,"depth":92,"text":368},{"id":633,"depth":92,"text":634},"To calculate polygon areas with a PyQGIS script to calculate polygon areas, use the QgsGeometry.area() method inside a feature iteration loop. The script below adds a numeric field to your layer, computes planar area in the layer’s native coordinate reference system (CRS), and writes values directly to the attribute table. For accurate linear measurements, your dataset must use a projected CRS (e.g., UTM or a national grid). Geographic CRS layers (like WGS84) will return meaningless square degrees. This workflow is a foundational step in Vector Data Manipulation for automated GIS tasks.","md",{},"\u002Fspatial-data-processing-automation\u002Fvector-data-manipulation\u002Fpyqgis-script-to-calculate-polygon-areas",{"title":5,"description":686},"spatial-data-processing-automation\u002Fvector-data-manipulation\u002Fpyqgis-script-to-calculate-polygon-areas\u002Findex","Diszu1qRICjeHQAKQyNLgrolucQpGzvKCwRu148aIuo",1777824788958]