1

I work with zoning info and have a series of census blocks that are overlapped by a larger zone. I used the identity tool to split the census blocks so that where they overlap they are separated, which increased my zones from about 8,000 to 15,000. In order to have a number of other statistics calculated I need to calculate the percent of area that each split zone is of the whole area (poor wording - i.e. my first zone was 100 acres, split into 3 that are 25, 25, and 50, so the zones are 25%, 25% and 50% of the original acreage).

I'm pretty new to ArcPy and used the following code but keep getting an error message when trying to run my code. It says my error is on line 2850 but I only have 21 lines of code.

"RuntimeError                              Traceback (most recent call last)
In  [12]:
Line 21:    row.setValue(percent, row.getValue(originalblockarea)/(blockarea))

File C:\Program Files\ArcGIS\Pro\Resources\ArcPy\arcpy\arcobjects\arcobjects.py, in getValue:
Line 2580:  return convertArcObjectToPythonObject(self._arc_object.GetValue(*gp_fixargs(args)))

RuntimeError: ERROR 999999: Something unexpected caused the tool to fail. Contact Esri Technical Support (http://esriurl.com/support) to Report a Bug, and refer to the error help for potential solutions or workarounds."

My code is as follows:


censusblocks = r'C:\Users\c.....'
evaczone = r'C:\Users\c.....'
originalblocks = r'C:\Users\.....Blocks_ExportFeatures'

with arcpy.da.SearchCursor(censusblocks, ["SHAPE@", "GEOID", "Shape_Area", "Percentage_OG"]) as blockcursor:
    blockshape = [0]
    blockid = [1]
    blockarea = [2]
    percent = [3]
    
    with arcpy.da.SearchCursor(originalblocks, ["SHAPE@", "GEOID", "Shape_Area"]) as originalcursor: 
        originalblockid = [1]
        originalblockarea = [2]
        
        cursor = arcpy.UpdateCursor(censusblocks)
        for row in cursor: 
            if blockid == originalblockid:
                idmatch = True
                row.setValue(percent, row.getValue(originalblockarea)/(blockarea))

I'm trying to divide the original acreage (originalblockarea) by the new area (blockarea) and then update the field "Percentage_OG" with the value. I was not taught ArcPy and have been trying to learn it myself so please let me know if there's an issue with my code too.

3
  • 2
    Don't do an update cursor inside a search cursor, it makes it hella slow. Ingest your search cursor (preferably arcpy.da.SearchCursor) into a dictionary ref: gis.stackexchange.com/questions/348201/…, calculate the final value for each and finally update. Your code is pretty bad, blockshape = [0] means that blockshape is a list with one element (0) and not accessing the row at all. You can't divide shapes, if you want the area use the "SHAPE@AREA" token, that will give you a floating point number that can be divided. Commented Jul 16, 2024 at 0:30
  • 4
    Rule #1 of cursors: Do not nest cursors. Rule #2 of cursors: Never, ever, ever double-nest cursors. Rule #3 of cursors: NEVER UNDER ANY CIRCUMSTANCES USE "OLD" CURSORS, ESPECIALLY NESTED INSIDE A DA CURSOR ON THE SAME SOURCE. The error you are receiving probably relates to Rule #3, but the code up above is very wrong: 1) There's no for loop inside the two DA cursors 2) You are not assigning row contents, but one element constant arrays to variables. There are code samples to teach you how to use cursors in the documentation. And lots of code examples here on proper use of dictionaries. Commented Jul 16, 2024 at 0:31
  • Vince and Michael, thank you so much for your help! I appreciate it a ton. I've been really struggling to learn this stuff (my professor even told us to use ChatGPT...) and this is my first time using stack exchange. You all are the best! Commented Jul 16, 2024 at 18:37

1 Answer 1

1

You have a number of issues.

  1. Don't nest cursors. But if you do nest cursors (just don't), you need to reset() it after each complete iteration of the inner cursor.

  2. You never loop over your originalcursor or blockcursor to access the cursor values. originalblockid = [1] isn't accessing the cursor and will do nothing other than set originalblockid to a list with a single element with the literal 1 value

  3. Your blockcursor is redundant.

  4. Don't use old-style arcpy.Search/Insert/UpdateCursors. They are slow and were retained for backwards compatibility with legacy code in later versions of ArcMap but they really should have been removed in ArcGIS Pro I think. Always use arcpy.da.Search/Insert/UpdateCursors

  5. Getting the "SHAPE@" column is expensive and slow so only do that if you actually need the geometry object itself. Don't include it if you just need attribute columns

Here's a completely untested example I wrote (on a PC without ArcGIS available to test) that loads originalblocks data into a dict so it can be accessed inside the UpdateCursor without having to nest:

censusblocks = r'C:\Users\c.....'
evaczone = r'C:\Users\c.....'
originalblocks = r'C:\Users\.....Blocks_ExportFeatures'

with arcpy.da.SearchCursor(originalblocks, ["GEOID", "Shape_Area"]) as rows:
    originaldata = {blockid: area for (blockid, area) in rows}  # <== make a dict of id and area

with arcpy.da.UpdateCursor(censusblocks, ["GEOID", "Shape_Area", "Percentage_OG"]) as rows:
    for blockid, blockarea, percentage in rows:
        originalblockarea = originaldata.get(blockid)  # <== a dict.get() returns None if there's no match
        if originalblockarea is not None:
            #  blockarea / originalblockarea is a proportion, 
            # if you want a percentage then multiply by 100. 
            row = (blockid, area, blockarea / originalblockarea * 100)
            rows.updateRow(row)
1
  • Hi! Thank you so much for heling me and using the # for explanations - I really appreciate it so much! Commented Jul 16, 2024 at 18:38

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.