0

I have parcels and a buffer around greenways. I'm trying to populate a field in the parcel fc with a '1' if the parcel intersects the buffer. I can get that fine with an update cursor and select layer by location. My problem is getting out of the cursor with all of the records rather than just those selected. Here is my code:

arcpy.management.AddField(regionParcels,"BufferParcels","SHORT")
arcpy.management.MakeFeatureLayer(regionParcels,"layerParcels")

with arcpy.da.UpdateCursor("layerParcels","BufferParcels") as cursor:
    arcpy.management.SelectLayerByLocation("layerParcels",'INTERSECT',bigBuffer)
    for row in cursor:
        row[0] = 1
        cursor.updateRow(row)

arcpy.management.SelectLayerByAttribute("layerParcels",'CLEAR_SELECTION')
arcpy.management.CopyFeatures("layerParcels",markedParcels)

With this code, every record is in the output, but they all have '1' in that field. If I drop the 'clear selection' command, I get just the selected features with the field populated, but I need the entire dataset. I've tried moving the clear command into the for loop, but that didn't work either. Any other suggestions?

2
  • Sounds like this might be better suited to a single spatial join
    – mikewatt
    Commented May 30 at 19:36
  • 1
    Never change the selection environment inside a cursor. Change your order of execution to SelectLayerByLocation above the with.
    – Vince
    Commented May 30 at 19:41

2 Answers 2

0

I'm still not sure why it was doing what it was doing, but I got it to do what I want. In case others have the same issue, here is what worked.

arcpy.management.AddField(resParcels,"BufferParcels","SHORT")
arcpy.management.MakeFeatureLayer(resParcels,"layerParcels")

arcpy.management.SelectLayerByLocation("layerParcels",'INTERSECT',bigBuffer)

with arcpy.da.UpdateCursor("layerParcels","BufferParcels") as cursor:    
    for row in cursor:
        row[0] = 1
        cursor.updateRow(row)

arcpy.management.SelectLayerByLocation("layerParcels",selection_type = 'SWITCH_SELECTION')

with arcpy.da.UpdateCursor("layerParcels","BufferParcels") as cursor:
    for row in cursor:
        row[0] = 0
        cursor.updateRow(row)

arcpy.management.SelectLayerByAttribute("layerParcels",'CLEAR_SELECTION')
arcpy.management.CopyFeatures("layerParcels",markedParcels)
1
  • The UpdateCursor generated the list of rows to process at instantiation, before your SelectLayerByLocation. Changing the selection set after the fact didn't change that.
    – Vince
    Commented May 31 at 14:07
0

All you need to do is use a Cursor spatial_filter:

The issue with your code is that the select by attributes does nothing to a Cursor. Selecting a layer modifies the OID set of the layer object and the cursor only looks at the raw SQL table.

If you want to filter a Cursor, you need to use spatial filters and where clauses:

Cursor Spatial Filter documentation

Cursor Where Clause documentation

Here's some updated code from my unedited answer that solves exactly the problem you had. The making a layer and copying features can be run in a separate operation to the flagging, so I made it into a function.

import arcpy
import os
     
def flag_parcel(parcel_path: os.PathLike, buffer: arcpy.Polyline):
    desc = arcpy.Describe(parcel_path)
    if 'BufferParcels' in [f.name for f in desc.fields]:
        arcpy.management.DeleteField(parcel_path, 'BufferParcels')
    
    # Create the field and set it to 0 (default)
    arcpy.management.AddField(parcel_path, 'BufferParcels', 'SHORT')
    
    # Set the BufferParcels field to 1 for all parcels that intersect the buffer
    with arcpy.da.UpdateCursor(parcel_path, ['BufferParcels'], spatial_filter=buffer) as cursor:
        for row in cursor:
            row = dict(zip(cursor.fields, row))
            row['BufferParcels'] = 1
            cursor.updateRow(list(row.values()))
    
def main():
    resParcels = r"<path>"
    bigBuffer: arcpy.Polygon = arcpy.Polygon()
    flag_parcel(resParcels, bigBuffer)
    
    # If you have multiple buffers, you can use the following code to flag parcels for each buffer
    # bigBuffers: List[arcpy.Polygon] = [arcpy.Polygon(), arcpy.Polygon(), ...]
    # for buffer in bigBuffers:
    #     flag_parcel(resParcels, buffer)
    # 
    # Or Merge the buffers into a single buffer
    # bigBuffer: arcpy.Polygon = [bigBuffers[0].union(buf) for buf in bigBuffers[1:]][0]
    # flag_parcel(resParcels, bigBuffer)

if __name__ == "__main__":
    main(
2
  • Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
    – Community Bot
    Commented Jun 21 at 8:12
  • fixed, sorry I was writing all that on mobile because I got excited about sharing the new spatial filter feature
    – hwelch
    Commented Jun 22 at 0:03

Your Answer

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

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