Hi all, I've been trying to automate the calculation of some land cover percentages per area, but I'm not a programmer so I'm not sure how to fix where I've gotten stuck. So far, I have been able to create and calculate a field with the sum of all of the area values, and new fields for the percentage calculations to be in.
import arcpy
#Set path to the feature class or the table put name within the quotations
table = r""
# Add a new field to the table
arcpy.management.AddField(table, "SumField", "DOUBLE")
# Use UpdateCursor to iterate through the rows of the table
with arcpy.da.UpdateCursor(table, "*") as cursor:
for row in cursor:
# Initialize a variable to store the sum
total = 0
# Iterate through each field in the row
for i in range(len(row)):
# Check if the field is numeric and not OBJECTID, Shape_Length, and Shape_Area
if isinstance(row[i], (int, float, complex)) and cursor.fields[i] not in ['OBJECTID', 'Shape_Length', 'Shape_Area']:
# Add the field's value to the total
total += row[i]
# Update the new field with the total
row[cursor.fields.index('SumField')] = total
cursor.updateRow(row)
#make fields into a list
fields = arcpy.ListFields("")
for field in fields:
#exclude fields with these names
if field.name not in ['OBJECTID', 'Shape_Length', 'Shape_Area', 'SumField', 'Spatial_ID']:
#add copies of all not excluded fields adding _perc after the name
arcpy.management.AddField(table, field.name + "_perc", "DOUBLE")
I've tried a few things to calculate these new fields, including using CalculateField() in the place of AddField(), but I wasn't able to get the expression to work because referencing a variable which is a field name breaks it and makes it think they're both strings instead of using the values within the fields.
fields = arcpy.ListFields("perc_test_table")
for field in fields:
if field.name not in ['OBJECTID', 'Shape_Length', 'Shape_Area', 'SumField', 'Spatial_ID']:
field_name = "'!"+ field.name+ "!'"
arcpy.management.CalculateField(table, field.name + "_perc", field_name/'!SumField!', "PYTHON3",field_type="DOUBLE")
Thank you!
You can use an f-string to dynamically insert the field name into the calculate field expression.
fields = arcpy.ListFields("perc_test_table")
for field in fields:
if field.name not in ['OBJECTID', 'Shape_Length', 'Shape_Area', 'SumField', 'Spatial_ID']:
arcpy.management.CalculateField(table, f"{field.name}_perc", f"!{field.name}!/!SumField!", "PYTHON3", field_type="DOUBLE")
You're doing a lot of work inside the update cursor, see if this works for you:
import arcpy
from arcpy.da import SearchCursor, UpdateCursor, InsertCursor, Editor
table = r"path/to/your/table"
fields = arcpy.Describe(table).fields
for idx, field in enumerate(fields):
# Notify User of progress
print(f"Calculating percentage for field: {field.name} {idx}/{len(fields)}")
# Skip not numeric fields
if field.type not in ['Double', 'Integer', 'BigInteger', 'Single', 'SmallInteger',]: continue
# Skip system fields
if field.name in ['OBJECTID', 'Shape_Length', 'Shape_Area', 'SumField']: continue
# Calculate the sum of the field values
total = sum(val[0] for val in arcpy.da.SearchCursor(table, [field.name]) if val[0])
# Skip if no values
if not total: continue
# Add _perc field
arcpy.management.AddField(table, field.name + "_perc", "DOUBLE")
# Start update cursor
with UpdateCursor(table, [field.name, field.name + "_perc"]) as cursor:
for row in cursor:
row = dict(zip(cursor.fields, row))
# Calculate the percentage of the field value (rounded to 2 decimal places)
row[f"{field.name}_perc"] = round((row[field.name] / total) * 100, 2)
cursor.updateRow(list(row.values()))
Notice that there's barely anything happening in the cursor