1

I have an ArcPy code that I am using to find various characteristics about certain watersheds in Indiana. I start with a shapefile of all 800 watersheds and go through it row by row and perform a bunch of calculations on each one. Right now the way it is set up I have one large loop to go through all of these calculations and get all of the outputs into lists to get the output as an excel file. This process takes an extremely long time, and I am new to Python and do not know how to improve the code so that it will be faster.

    #search cursor through each row of county subwatersheds file
rows = arcpy.SearchCursor(all_subwatersheds)

for row in rows:
    subwatershed_number = row.getValue("HUC12")

    subwatershed_list.append(subwatershed_number)

    print(subwatershed_number, " is the subwatershed to be worked on")

    #select subwatershed from shapefile with all of them
    subwatershed_selection = arcpy.SelectLayerByAttribute_management(all_subwatersheds, "NEW_SELECTION",
                                                                     "HUC12 = " + "'"+subwatershed_number+"'")

    #copy selected subwatershed to it's own file
    subwatershed = arcpy.CopyFeatures_management(subwatershed_selection, "subwatershed")

    #clip dem to subwatershed area
    dem_clip = arcpy.Clip_management(dem_Indiana, "#", "dem_clip.tif", subwatershed, "#" , "ClippingGeometry", "NO_MAINTAIN_EXTENT")
    print("clipped dem to subwatershed area")

    #calculate area of subwatershed
    arcpy.AddField_management(subwatershed, "AREA", "DOUBLE")

    area = arcpy.CalculateGeometryAttributes_management(subwatershed, "AREA AREA_GEODESIC", '', 
                                                        "SQUARE_KILOMETERS",
                                                        None)

    #print area
    rows = arcpy.SearchCursor(area)

    for row in rows:
        area = row.getValue("AREA")

    area_list.append(area)
    print(area, " square kilometers")


    #calculate perimeter of subwatershed
    arcpy.AddField_management(subwatershed, "PERIMETER", "DOUBLE")
    perimeter = arcpy.CalculateGeometryAttributes_management(subwatershed, "PERIMETER PERIMETER_LENGTH_GEODESIC",
                                                             "KILOMETERS")

    print("perimeter calculated")

    #print perimeter
    rows = arcpy.SearchCursor(perimeter)

    for row in rows:
        perimeter = row.getValue("PERIMETER")

    perimeter_list.append(perimeter)
    print(perimeter, " kilometers")



    #get average slope using zonal statistics from slope dem
    avg_slope = arcpy.sa.ZonalStatistics(subwatershed, "FID", dem_slope, "MEAN")

    #get slope value
    avg_slope_result = arcpy.GetRasterProperties_management(avg_slope, "MAXIMUM")

    avg_slope_value = avg_slope_result.getOutput(0)

    avg_slope_list.append(avg_slope_value)

    print(avg_slope_value, " = avg slope (%)")
2
  • 2
    Why do you Think the code is slow? The same Tools run manually or with modebuilder finishes much faster?
    – BERA
    Apr 29, 2020 at 14:50
  • 2
    You might see an order of magnitude improvement in cursor operation just by using a Data Access cursor. General performance improvement is not really a GIS SE focus. But you need to be able to quantify performance characteristics in seconds or milliseconds (vice " a long time"), for each step in your process before you're really ready for optimization (if you take 20 minutes to rewrite the cursor, but it only loses 100 milliseconds per execution, it will take a 12,000 executions to make the edit worthwhile)
    – Vince
    Apr 29, 2020 at 16:25

2 Answers 2

2

The first thing to do to run faster is to use arcpy.da.SearchCursor instead of arcpy.SearchCursor

Also it seems to me that there are too many commands in your loop. For example, "Add field" would be more efficient if you run it once before you split, some with most of the watershed geoprocessing.

And it seems to me that you could avoid writing new datasets if you work with selected features.

EDIT: as mentioned in the comments, print statment also slow down your process and should be avoided in loops (except for debugging), but here I think that tha add field, for example, has much more impact.

2
  • Yes to DA cursors! And ditch the print statements. stackoverflow.com/questions/13288185/…
    – GBG
    Jun 2, 2020 at 1:24
  • I agree. You are looping through each individual feature when almost all of your steps could be done for the whole dataset at once. dem_clip is maybe the only one, but it may honor a selection so you may not need to copy features.
    – Rex
    Oct 16, 2020 at 21:47
0

If we kept the logic and code you posted, the one small change that could improve performance is to make you 'subwatershed' from CopyFeatures_management an in_memory feature class rather than write it to disk. esri link

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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