Select to view content in your preferred language

Using SelectLayerByLocation and CalculateField - all records populated, not just selected

818
6
Jump to solution
12-22-2023 10:02 AM
KarlKeough2
Emerging Contributor

I am using for loops to loop through a list of hexagon feature classes, selecting those hexagons in each feature class that overlap hexagons in each of the other feature classes and then calculating conflict scores for each of the overlapping records. The conflict scores are derived from an Excel table containing names of the two feature classes being compared and the relevant conflict score. The code seems to work fine, with no errors, except that it populates all records with the relevant conflict score, not just those records that overlap (the selected records). The code below shows the last few lines of the code. fc1 and fc2 represent the two layers being compared; fieldnames 1, 2 and 3 are defined earlier in the code and are derived by modifying feature class and field names. 

with arcpy.da.SearchCursor(conflictScores, ["Activity1", "Activity2", "ConflictScore"]) as cursor:
            for row in cursor:
                print("START ROWS)")
                if row[0] == fieldname1 and row[1] == fieldname2:
                    score = row[2]
                    print(score)
                    arcpy.management.SelectLayerByLocation(fc1, "HAVE_THEIR_CENTER_IN", fc2, "", "NEW_SELECTION")
                    arcpy.management.CalculateField(fc1, fieldname3, score)
                    print(fc1, fieldname3, score)

 

0 Kudos
1 Solution

Accepted Solutions
AlfredBaldenweck
MVP Regular Contributor

So, unless I'm missing something, this should be a very simple fix.

with arcpy.da.SearchCursor(conflictScores, ["Activity1", "Activity2", "ConflictScore"]) as cursor:
    for row in cursor:
        print("START ROWS)")
        if row[0] == fieldname1 and row[1] == fieldname2:
            score = row[2]
            print(score)
            sel = arcpy.management.SelectLayerByLocation(fc1, "HAVE_THEIR_CENTER_IN", fc2, "", "NEW_SELECTION")
            arcpy.management.CalculateField(sel, fieldname3, score)
            print(fc1, fieldname3, score)

 What was happening was you were making a selection on a layer, but not feeding the selection to calculate field.

Give this a shot and see how it goes.

Also not sure if you meant to post a picture, but if you did, it didn't come through.

View solution in original post

0 Kudos
6 Replies
DavidPike
MVP Frequent Contributor

I've never seen a select by location in a cursor but I'd guess you need to use the geometry of each cursor row - rather than fc1 and fc2 which I assume are your entire features.

Maybe try this but no idea if it would work.  If not I'd prefer to compare with a geometry.disjoint on the SHAPE token.

 

#needs to be a feature layer if not already
arcpy.MakeFeatureLayer_management(fc1,"fc1_layer")

with arcpy.da.SearchCursor(conflictScores, ["Activity1", "Activity2", "ConflictScore", "SHAPE@"]) as cursor:
            for row in cursor:
                print("START ROWS)")
                if row[0] == fieldname1 and row[1] == fieldname2:
                    score = row[2]
                    print(score)
                    arcpy.management.SelectLayerByLocation("fc1_layer", "HAVE_THEIR_CENTER_IN", row[3], "", "NEW_SELECTION")
                    arcpy.management.CalculateField("fc1_layer", fieldname3, score)
                    print(fc1, fieldname3, score)

 

 

0 Kudos
KarlKeough2
Emerging Contributor
Thanks for the quick reply David. The use of the SearchCursor may be a little confusing or unorthodox. The SearchCursor is on the Excel table which shows the various combinations of layer names (text fields) and the associated conflict score. I had to loop through the Excel records to find the name of the two layers that were being considered (fc1, fc2, from feature class lists earlier in the code) and the associated conflict score. That conflict score was then used to populate the selected records (using the SelectLayerByLocation tool) in the field called fieldname in fc1. I felt that had to be done within the cursor because the code had to look through the records of the Excel file to find the right combination of layers to assign the scores and then assign them before moving on to the next pair of layers. Not sure if this clarifies much. Perhaps I should try creating a layer file for the SelectLayerByLocation tool as you suggest. If seeing the rest of the code helps I can certainly send that. Thanks again for your help.
Karl
0 Kudos
AlfredBaldenweck
MVP Regular Contributor

You have to make the selection a variable, then feed that variable into calculatefield

KarlKeough2
Emerging Contributor
Thank you for the response Alfred. From the examples I have seen in the CalculateField help page, it seems the expression that has to be passed into CalculateField (and that represents the selection), is based on attributes from the table, whereas in my case the selection is based on location in reference to another layer. It seems then that there must be two things passed into CalculateField - the records that are selected based on location and the value that will populate the selected records, which comes from the Excel table. Can these both be accommodated in the expression variable? Or is there another way?
Karl
[cid:image001.png@01DA38B8.60229CF0]
0 Kudos
AlfredBaldenweck
MVP Regular Contributor

So, unless I'm missing something, this should be a very simple fix.

with arcpy.da.SearchCursor(conflictScores, ["Activity1", "Activity2", "ConflictScore"]) as cursor:
    for row in cursor:
        print("START ROWS)")
        if row[0] == fieldname1 and row[1] == fieldname2:
            score = row[2]
            print(score)
            sel = arcpy.management.SelectLayerByLocation(fc1, "HAVE_THEIR_CENTER_IN", fc2, "", "NEW_SELECTION")
            arcpy.management.CalculateField(sel, fieldname3, score)
            print(fc1, fieldname3, score)

 What was happening was you were making a selection on a layer, but not feeding the selection to calculate field.

Give this a shot and see how it goes.

Also not sure if you meant to post a picture, but if you did, it didn't come through.

0 Kudos
KarlKeough2
Emerging Contributor
That's great, Alfred. Thank you. I simply had to define the selection. An easy fix!
Karl
0 Kudos