2

I am building a script to populate a field in one feature class based on a field in another feature class. First I have a leases layer which is all small polygons. Then I have an index grid layer which is large polygons. I want to know which leases exist within which index grid polygon. The index grid layer has an "Id" field, and I want the Id value from the index grid that each lease exists within to be written to a new column in the leases layer.

For example, index grid polygon with an 'Id' of '7' contains leases '14' '6' and '12'. The final result should be a column where lease 14, 6, and 12 all have a value of '7' in the new column.

Here is what I have so far:

import arcpy, sys

grid = arcpy.GetParameterAsText(0)
leases = arcpy.GetParameterAsText(1)
workspace = arcpy.GetParameterAsText(2)
new_field = arcpy.GetParameterAsText(3)

if arcpy.ListFields(leases, new_field):
    sys.exit(arcpy.AddError("Error:Field Already exists"))

arcpy.AddField_management(leases, new_field, 'SHORT', '', '', '')

grid_lyr = arcpy.MakeFeatureLayer_management(grid, 'grid_lyr')
leases_lyr = arcpy.MakeFeatureLayer_management(leases, 'leases_lyr')

fields = ['file',new_field]
with arcpy.da.UpdateCursor(leases_lyr,fields) as cur:
    for row in cur:

        leases = row[0]
        where = '"file" = \'{}\''.format(leases)
        arcpy.SelectLayerByAttribute_management(leases_lyr, 'NEW_SELECTION', where)

        arcpy.SelectLayerByLocation_management(grid_lyr, 'CONTAINS', leases_lyr)
        map_no =  #I think this is all that is missing

        row[1] = map_no
        cur.updateRow(row)

The value 'map_no' represents the index grid Id which the lease belongs to.

As I have a comment in my code, I think there is only one line that is missing...in the original script which this is derived from, this line uses the arcpy.GetCount_management, but obviously it needs to be something different. It just needs to be some kind of get value function, but I simply cannot figure it out.

I derived this work so far from a script that counts the number of points in in a polygon, and then writes that value to a new column in the polygon layer. I mention this because maybe there is a better solution.

Using ArcMap 10.1.

  • 5
    Most of select layer code should be able to be replaced with a single call to Spatial Join. No need to loop over each feature. – Paul Sep 15 '15 at 18:22
  • Thanks Paul - I didn't even realize there was a separate spatial join tool (Analysis toolbox). I ran that and was able to achieve exactly what I wanted. However, I would still be interested to see if anyone has something simple to add to my script to make it work. – ge0m3try Sep 15 '15 at 18:34
  • 1
    I'd probably use a cursor on grid_lyr to access the id field value. – Paul Sep 15 '15 at 18:45
3

Going to assume that not all grids contain leases and that grids completely contain leases. No need to make the "in_memory" feature class if all grids will be used. If some leases overlap grids, you will only get the last grid id value.

import arcpy, sys

grid = arcpy.GetParameterAsText(0)
leases = arcpy.GetParameterAsText(1)
workspace = arcpy.GetParameterAsText(2)
new_field = arcpy.GetParameterAsText(3)

if arcpy.ListFields(leases, new_field):
    sys.exit(arcpy.AddError("Error:Field Already exists"))

arcpy.AddField_management(leases, new_field, 'SHORT', '', '', '')

grid_lyr = arcpy.MakeFeatureLayer_management(grid, 'grid_lyr')
leases_lyr = arcpy.MakeFeatureLayer_management(leases, 'leases_lyr')

fields = ['file',new_field]
arcpy.SelectLayerByLocation_management(grid_lyr, "CONTAINS", leases_lyr)
arcpy.FeatureClassToFeatureClass_conversion(grid_lyr, "in_memory", "gridsWithLeases")
gridsWithLeases = r"in_memory/gridsWithLeases"
arcpy.MakeFeatureLayer_management(gridsWithLeases, 'gridLease_lyr')
with arcpy.da.SearchCursor('gridLease_lyr', ['ID']) as gridCursor:
    for gridRow in gridCursor:
        arcpy.SelectLayerByLocation_management(leases_lyr, "WITHIN", 'gridLease_lyr')
        with arcpy.da.UpdateCursor(leases_lyr, fields) as leaseCursor:
            for leaseRow in leaseCursor:
                leaseRow[1] = gridRow[0]
                leaseCursor.updateRow(leaseRow) 
  • Updated with corrections. – KJYDavis Sep 16 '15 at 12:40
  • Thanks for this answer - there were, and still are, a few issues with this script. I had to indent line 23 and below of your code (starting with arcpy.SelecyLayerByLocation_management) and I had to change the spelling of conversion on line 18. I won't be able to do any more debugging for a while, but the error that is coming up now is NameError: name 'gridsWithLeases' is not defined . I think this may have something to do with adding quotes around gridsWithLeases but I could be wrong. Either way there is still work to be done here. – ge0m3try Sep 16 '15 at 12:41
1

The solution is to use the Spatial Join (Analysis) Tool.

Use the index grid as the target feature and the leases as the join feature. Enter the output Feature Class. Select one to many relationship. Join type - keep all. Leave field mapping as is or remove unnecessary fields (it is only necessary to keep the 'index grid id' field as this will be the final result). Lastly, select the join operator 'CONTAINS'.

The link above also shows how to access this tool using arcpy if desired.

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.