2

I have found a script that can add multiple fields to my existing shapefefile. Now, I need to add to my existing script so that it will calculate the new fields that have been added. In most cases, these calculations will derive from existing values in other fields ex. Crdrt1 = [Field1], Crdrt_min1 = [Field2]. I know that I need to use "fields.arcpy.CalculateField_management" but not sure how or where to add to existing script to get it to loop through and calculate.

import arcpy

#Select Geodatabase
arcpy.env.workspace = "C:.. FOLDER\CASINGS_DATA\casings.gdb"
#Select FeatureClass
shapefile = "Casings"

#List of fields to add, all with same type, precision, and scale
#Fields added to attribute table in reverse order
fields = {
    "Crdrt1": "[DES]",
    "Crdrt_min1": "[GRADE]",
    "Testing": "[NAME]"
}
alias = {
    "Crdrt1": "ok",
    "Crdrt_min1": "test"
}

existing_fields = arcpy.Describe(shapefile).fields


for field in fields:
    if not field in existing_fields:
        arcpy.AddField_management(shapefile, field, "TEXT", 0, 0, 50, alias [aliass])
    arcpy.CalculateField_management(shapefile, field, fields[field])
  • 1
    ArcGIS Pro has Calculate Fields (note the plural) – Paul Feb 28 at 15:46
  • You can use the da.UpdateCursor instead of Field Calculator – BERA Feb 28 at 17:32
  • Could you please provide an example of the type of calculations you would like to do? – Aaron Feb 28 at 20:12
  • Calculations will be simply populating based off of other columns as described in initial post. Created_Field_1 = [Existing_Field_1], Created_Field_2 = [Existing_Field_2] – huskersila Feb 28 at 22:19
  • I noticed that your for/if blocks might mix tab and spaces. you should avoid this and it might have confused the python 2.7 interpreter (you get an error in modern pythons when you mix tabs and spaces) – Paul H Mar 5 at 16:58
4

You need to call CalculateField_management for each field you want to calculate. E.g.

arcpy.CalculateField_management(shapefile, "Crdrt1", "[Field1]")
arcpy.CalculateField_management(shapefile, "Crdrt_min1", "[Field2]")

If you want to use a loop, you could create a dictionary that contains the fieldnames and the expressions for each field. The syntax of the expression depends on the type of database and the expression type. See here for details.

fields = {
    "Crdrt1": "[Field1]",
    "Crdrt_min1": "[Field2]"
}

existing_fields = arcpy.Describe(shapefile).fields

for field in fields:
    if not field in existing_fields:
        arcpy.AddField_management(shapefile, field, "TEXT", 0, 0, 250)
    arcpy.CalculateField_management(shapefile, field, fields[field])
  • Only thing that may be an issue is that I need this to potentially overwrite existing data. its throwing back an error that the field already exist if i try running twice. Anyway to avoid that or will i need to delete the fields before each run? – huskersila Feb 28 at 19:21
  • Nice, clean approach +1. For comparison, and to satisfy my curiosity, I included a benchmark test using your approach and an Update Cursor approach. – Aaron Mar 1 at 5:57
  • @huskersila I added a check for existing fields. The data in those fields will still be overwritten of course. – Berend Mar 1 at 8:11
  • @Berend Thank you for your help! Much appreciated friend – huskersila Mar 4 at 14:51
  • @Berend What about taking this a step further and adding a field alias ? I would prefer the fields display without the "_" between field names. Adding an alias would resolve this. – huskersila Mar 4 at 16:11
3

In your case, using an UpdateCursor is much more efficient than the Field Calculator approach (see benchmark results below). The example I include uses a shapefile with three fields and 500,000 rows. I have included code to handle existing fields as per your comments.

import arcpy, time

shp = r'X:\temp\some_shapefile1.shp'
shp2 = r'X:\temp\some_shapefile2.shp'

# Dictionary of existing and created field names for Update Cursor
dict = {
    "created1": "existing1",
    "created2": "existing2",
    "created3": "existing3",
}

dict2 = {
    "created1": "[existing1]",
    "created2": "[existing2]",
    "created3": "[existing3]",
}

def add_fields(in_table, fields):
    """
    Add fields from dictionary if they do not already exist
    """
    field_names = [f.name for f in arcpy.ListFields(in_table)]
    for field in fields:
        if not field in field_names:
            arcpy.AddField_management(in_table, field, field_type = "TEXT", field_precision = 250)

def calc_update_cursor(shp, dict):
    """
    Copy values from existing to created in dictionary
    """
    for key, value in dict.items():
        with arcpy.da.UpdateCursor(shp, (key, value)) as cursor:
            for row in cursor:
                row[0] = row[1]
                cursor.updateRow(row)

def calc_field_calculator(shp2, dict2):
    for field in dict2:
        arcpy.CalculateField_management(shp2, field, dict2[field])

if __name__ == '__main__':
    # Speed test for update cursor
    start = time.time()
    add_fields(shp, dict.keys())
    calc_update_cursor(shp, dict)
    end = time.time()
    total = end - start
    print "%s seconds for the update cursor method" % total

    # Speed test for field calculator
    start = time.time()
    add_fields(shp2, dict.keys())
    calc_field_calculator(shp2, dict2)
    end = time.time()
    total = end - start
    print "%s seconds for the field calculator method" % total

*** Python 2.7.14 (v2.7.14:84471935ed, Sep 16 2017, 20:19:30) [MSC v.1500 32 bit (Intel)] on win32. ***
>>> 
87.7679998875 seconds for the update cursor method
263.031000137 seconds for the field calculator method
>>> 
40.0729999542 seconds for the update cursor method
213.185000181 seconds for the field calculator method
>>> 
38.8159999847 seconds for the update cursor method
218.700000048 seconds for the field calculator method
>>> 

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.