What process is necessary to select each row of a feature class and then perform a select by location using the individually selected rows?

5877
19
12-06-2017 07:12 AM
Travispreston
Emerging Contributor

I am trying to use cursor and for loop to select each row of a feature class, then select features from another feature class using select by location and the selection from the former feature class. Then add up the shape areas of the selection and out put them into a field in the first feature class. 

1. Step through each row of a feature class selecting them one at a time (Parcels)

   -I tried using a cursor for this step

2. perform a select by location using the selection from the first step and another feature class (Buildings)

   -I cannot figure out how to get the row to be used in the select by location

3. Sum the "shape area" of the selection from step 2

   - I don't know the command to perform this step

4. Output the sum into a field in the first feature class (Parcels)

   - I don't know the command to perform this step

5. divide the shape area of Buildings by the Parcel shape area to get a % of development

   - I believe I can write this command but I have not been able to get this far in the code

I have not been able to find a similar python process on stack exchange. I have made several attempts at writing the code in what I feel like is a logical order but have not had any luck. Does anyone possibly have a similar code or can anyone provide me with a list of python processes to use?

Thank you

0 Kudos
19 Replies
JakeSkinner
Esri Esteemed Contributor

Hi Travis,

1.  I would get a list of all the OBJECTIDs of the feature class:

oidList = []

with arcpy.da.SearchCursor(fc, ["OID@"]) as cursor:
    for row in cursor:
        oidList.append(row[0])
del cursor

2.  You can then create a feature layer by iterating through the oidList:

arcpy.MakeFeatureLayer_management(buildings, "buildingsLyr")

for OID in oidList:
    arcpy.MakeFeatureLayer_management(fc, "fcLyr", "OBJECTID = " + str(OID))
    arcpy.SelectLayerByLocation_management("fcLyr", "buildingsLyr", "BOUNDARY_TOUCHES")

3.  You can use the Summary Statistics tool to sum the shape area

4.  You can query the summary stats output using a search cursor to get the sum value and then insert this into the "fcLyr"

Travispreston
Emerging Contributor

This is awesome, thank you!

Would the Summary Statistics (3) and the summary stats output (4) be inside

of step 2's for loop?

0 Kudos
JamesCrandall
MVP Frequent Contributor

Here's part of the requirement to iterate the parcel features and select by location for each feature.  But untested, likely needs work:

with arcpy.da.SearchCursor(parcel_featureclass, ['SHAPE@']) as parcelcursor:
    for parcelrow in parcelcursor:
    
     #get the geometry to use in the spatial selection
     geom = parcelrow[0]
     
     #select feature from the other layer using the geom variable
     arcpy.SelectLayerByLocation_management(the_other_lyr, "INTERSECT", geom, "", "NEW_SELECTION")
     
     #get the area of the selected features and sum
     areasum = 0
     with arcpy.da.SearchCursor(the_other_lyr,['SHAPE@AREA']) as newcursor:
      for newrow in newcursor:
       areasum = totarea + rewrow[0]‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
Travispreston
Emerging Contributor

This is what I have so far. It still is not working though. Something is wring with the search cursor at line 31. in your line 1 you have input_fc. Should this be the parcel feature class? you then have parcel_feature class stated after the field to be used. Why?

0 Kudos
JamesCrandall
MVP Frequent Contributor

Yes, I fixed the code sample. Sorry, pulled this from another implementation and missed that -- it just needs some tweaking.

Looks like you have line indent issues.  Look at your line #34 and make it line up with the line below it  Also, you need to set "SHAPE@" as the field to use in the first cursor, not "Shape_Area".

Also, make sure your "Structures" is a FeatureLayer, not a feature class for your SelectLayerByLocation_management.  http://desktop.arcgis.com/en/arcmap/10.3/tools/data-management-toolbox/select-layer-by-location.htm

with arcpy.da.SearchCursor(parcels, ['SHAPE@']) as parcelcursor:

     for parcelrow in parcelcursor:

          #get the geometry to use in the spatial selection
          geom = parcelrow[0]
 
          #select feature from the other layer
          arcpy.SelectLayerByLocation_management(Structures, "HAVE_THEIR_CENTER_IN", geom, "", "NEW_SELECTION")‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
Travispreston
Emerging Contributor

I am hitting a snag at line 50. I am getting an error stating totarea is not defined. should line 47 be totarea instead of areasum? 

0 Kudos
JamesCrandall
MVP Frequent Contributor

Travis -- it's much easier for us to reply with the corrected code if you paste in your code rather than a screenshot.

It looks like the problem is with the cursor.  Change "Shape@" to "SHAPE@AREA'").  Like this,

with arcpy.da.SearchCursor(Struc_lyr, ['SHAPE@AREA']) as newcursor:
     for newrow in newcursor:
          areasum = areasum + newrow[0]‍‍‍‍‍‍‍‍
Travispreston
Emerging Contributor

I am not sure how you are getting the to paste in correctly. When I paste it in this is how it ends up. The code is running now. The only issue is that it doesn't seem to be giving me the sum of all buildings together in each parcel. It is giving me the area of each individual building. 

# Set the necessary product code
# import arcinfo


# Import the Arcpy Module

import arcpy
from arcpy import env

# Set up the working Environment

env.workspace = r"D:\Travis\Personal\Geoff\Nantucket\Zoning\Backlots\Backlots.gdb"
env.overwriteOutput = True

#Variables
Parcels ="R40_80000sqft"
Structures = "Nantucket_Structres"

arcpy.MakeFeatureLayer_management(parcels,"Parcels_lyr")
arcpy.MakeFeatureLayer_management(Structures,"Struc_Lyr")

Struc_Lyr = "Struc_Lyr"
Parc_Lyr = "Parcels_Lyr"

#Add a field to parcels to be populated with building area
#arcpy.AddField_management("R40_80000sqft","Bldg_Area","DOUBLE")

with arcpy.da.SearchCursor(Parc_Lyr, ['Shape@']) as parcelcursor:
for parcelrow in parcelcursor:

#get the geometry to use in the spatial selection
geom = parcelrow[0]

#select feature from the other layer using the geom variable
arcpy.SelectLayerByLocation_management(Struc_Lyr, "HAVE_THEIR_CENTER_IN", geom, "", "NEW_SELECTION")

#get the area of the selected features and sum
areasum = 0
with arcpy.da.SearchCursor(Struc_Lyr,['Shape@AREA']) as newcursor:
for newrow in newcursor:
areasum = areasum + newrow[0]
print areasum

0 Kudos
JamesCrandall
MVP Frequent Contributor

See if this works:

# Set the necessary product code
# import arcinfo


# Import the Arcpy Module

import arcpy
from arcpy import env

# Set up the working Environment

env.workspace = r"D:\Travis\Personal\Geoff\Nantucket\Zoning\Backlots\Backlots.gdb"
env.overwriteOutput = True

#Variables
Parcels ="R40_80000sqft"
Structures = "Nantucket_Structres"

arcpy.MakeFeatureLayer_management(parcels,"Parcels_lyr")
arcpy.MakeFeatureLayer_management(Structures,"Struc_Lyr")

Struc_Lyr = "Struc_Lyr"
Parc_Lyr = "Parcels_Lyr"

#Add a field to parcels to be populated with building area
#arcpy.AddField_management("R40_80000sqft","Bldg_Area","DOUBLE")

with arcpy.da.SearchCursor(Parc_Lyr, ['Shape@']) as parcelcursor:
    
    for parcelrow in parcelcursor:

        #get the geometry to use in the spatial selection
        geom = parcelrow[0]

        #select feature from the other layer using the geom variable
        arcpy.SelectLayerByLocation_management(Struc_Lyr, "HAVE_THEIR_CENTER_IN", geom, "", "NEW_SELECTION")

        #get the area of the selected features and sum
        areasum = 0
        with arcpy.da.SearchCursor(Struc_Lyr,['Shape@AREA']) as newcursor:
            for newrow in newcursor:
                areasum = areasum + newrow[0]

        print areasum