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
It worked!!! Now I need to add those values to their corresponding parcel. Would I use and input cursor of some kind for that?
I tried adding an update cursor to the end of the code to add the areasum
to the "Bldg_Area" field of the parcel layer. It didn't work.
Import the Arcpy Module
import arcinfo
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, ) 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
with arcpy.da.UpdateCursor(Parcels, ) as parcelcursor:
for parcelrow in parcelcursor:
row[0]=areasum
Not sure if having update cursor within search cursors is a good idea. I think you may want to research on populating some kind of list or dictionary with the area totals and their OID's, then use that dictionary in a new update cursor. Sorry I haven't gone down that road.
Instead of using a SearchCursor, you can use an UpdateCursor for the parcel layer. You can then update the additional fields. In the below example I added to fields to the parcel feature class called 'BuildingArea' and 'FreeArea'.
with arcpy.da.UpdateCursor(Parc_Lyr, ['Shape@', 'BuildingArea', 'FreeArea']) 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]
del newcursor
parcelrow[1] = areasum
if areasum != 0:
parcelrow[2] = geom.area / areasum
else:
parcelrow[2] = 0
parcelcursor.updateRow(parcelrow)
del parcelcursor
Also, here is a link that discusses how to post code in GeoNET:
https://community.esri.com/docs/DOC-8691-posting-code-with-syntax-highlighting-on-geonet
Thank you for the additional help. I added the field to the table that you selected and added the additional code. I am getting an error at line 60. Any idea why I would be getting the error?
# Import the Arcpy Module
import arcinfo
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(Parcels,"Bldg_Area","DOUBLE")
arcpy.AddField_management(Parcels,"Free_Area","DOUBLE")
with arcpy.da.UpdateCursor(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
del newcursor
parcelrow[1]= areasum
if areasum != 0:
parcelrow[2] = geom.area / areasum
else:
parcelrow[2] = 0
parcelcursor.updateRow(parcelrow)
del parcelcursor
You need to add your additional fields to line 25:
with arcpy.da.UpdateCursor(Parc_Lyr, ['Shape@']) as parcelcursor:
Take a look at what I have:
with arcpy.da.UpdateCursor(Parc_Lyr, ['Shape@', 'BuildingArea', 'FreeArea']) as parcelcursor:
Thank you! The Script is working exactly as I had hoped. I am now trying to apply the same script to figuring out frontage. I want the script to select the lines I created from the parcels that fall within the buffer of the road, sum the total length of frontage lines and out put the sum to the frontage field. The script runs but nothing is put into the frontage field. Any suggestions?
# Import the Arcpy Module
import arcinfo
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"
Street_Center = "ROAD_CL_2017_12"
arcpy.MakeFeatureLayer_management(Parcels,"Parcels_lyr")
arcpy.MakeFeatureLayer_management(Street_Center,"Street_Lyr")
Street_Lyr = "Street_Lyr"
Parcels_lyr = "Parcels_Lyr"
#Add a field to parcels to be populated with building area
arcpy.AddField_management(Parcels,"Frontage","DOUBLE")
arcpy.Buffer_analysis(Street_Lyr,"Street_Buff","40 Feet","FULL","ROUND","ALL")
Street_Buff = "Street_Buff"
arcpy.PolygonToLine_management(Parcels_lyr,"R40_PolyToLine")
R40_Line = "R40_PolyToLine"
arcpy.MakeFeatureLayer_management(R40_Line,"R40_Line_Lyr")
R40_Line_Lyr = "R40_Line_Lyr"
#Create a cursor to select all parcel lines that fall within the street buffer
with arcpy.da.UpdateCursor(Parcels_lyr, ['Shape@','Frontage']) as linecursor:
for linerow in linecursor:
#get the geometry to use in the spatial selection
geom = linerow[0]
#select feature from the other layer using the geom variable
arcpy.SelectLayerByLocation_management(R40_Line_Lyr, "COMPLETELY_WITHIN", Street_Buff, "", "NEW_SELECTION")
#get the Length of the selected features and sum
lengthsum = 0
with arcpy.da.SearchCursor(Street_Lyr,['SHAPE@LENGTH']) as newcursor:
for newrow in newcursor:
lengthsum = lengthsum + newrow[0]
print lengthsum
del newcursor
parcelrow[1]= lengthsum
if areasum != 0:
parcelrow[2] = geom.length / lengthsum
else:
parcelrow[2] = 0
linecursor.updateRow(linerow)
del linecursor
I realized I have another problem. I need it to use the other attribute to determine which parcel the line segments belong to otherwise it will just sum every line segment that falls within the buffer area.
I would suggest to use the Geoprocessing Tool "Tabulate Intersect", which is very fast also on huge data:
arcpy.TabulateIntersection_analysis("Parcel", "OBJECTID", "Building", r"in_memory\TabIntSum")
This results in a Table with the fields
- OBJECTID_1 = Parcel-Objectid
- AREA = Sum of overlapped Building area
- PERCENTAGE = Overlapping Area Percentage
You may then use "MakeFeatureLayer" for the parcels, "Add Join" to Join the resulting table by objectid/objectid_1 and "Calculate Field" to populate the desired field. For clean code you should then use "Remove Join" or "Delete" for the Feature layer.
If you have overlapping parcels, then you would have to add a "Sort" for the resulting table on "OBJECTID_1 and AREA (Descending)" followed by a summary statistics on the OBJECTID_1 to select first Areas per parcel.
Thank you! I am trying to use your suggestion for another code. The purpose is to determine the frontage of parcels along a road system. I have created a buffer to use in select by location. I want to select all lines that completely fall within the buffer and then calculate the sum of lines that correspond to each parcel and then populate a field called "Frontage". I have used most of the code from this thread to try and accomplish the frontage calculation. I dont think I put the TabulateIntersection_analysis in the correct place and I am not sure that everything from line 72 down is necessary. Any suggestions?
# Import the Arcpy Module
import arcinfo
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"
Street_Center = "ROAD_CL_2017_12"
arcpy.MakeFeatureLayer_management(Parcels,"Parcels_lyr")
arcpy.MakeFeatureLayer_management(Street_Center,"Street_Lyr")
Street_Lyr = "Street_Lyr"
Parcels_lyr = "Parcels_Lyr"
#Add a field to parcels to be populated with building area
arcpy.AddField_management(Parcels,"Frontage","DOUBLE")
# Buffer Street Center Lines
arcpy.Buffer_analysis(Street_Lyr,"Street_Buff","40 Feet","FULL","ROUND","ALL")
Street_Buff = "Street_Buff"
#Convert parcel layer polygons to lines
arcpy.PolygonToLine_management(Parcels_lyr,"R40_PolyToLine")
R40_Line = "R40_PolyToLine"
###Convert parcel lines to a layer for use in select by location
##arcpy.MakeFeatureLayer_management(R40_Line,"R40_Line_Lyr")
##
##R40_Line_Lyr = "R40_Line_Lyr"
#Create a cursor to select all parcel lines that fall within the street buffer
with arcpy.da.UpdateCursor(Parcels_lyr, ['Shape@','Frontage','OID@']) as linecursor:
for linerow in linecursor:
#get the geometry to use in the spatial selection
geom = linerow[0]
oid = str(linerow[2])
R40_Line = "R40_PolyToLine"
arcpy.TabulateIntersection_analysis(R40_Line, "OBJECTID", Parcels_lyr, r"in_memory\TabIntSum")
#Convert parcel lines to a layer for use in a select by location
arcpy.MakeFeatureLayer_management(R40_Line,"R40_Line_Lyr","LEFT_FID = " + oid)
arcpy.JoinField_management(r"in_memory\TabIntSum","OBJECTID_1",Parcels_lyr,"OBJECTID")
#select parcel lines from the street buffer using the geom variable
arcpy.SelectLayerByLocation_management("R40_Line_Lyr", "COMPLETELY_WITHIN", Street_Buff, "", "NEW_SELECTION")
#get the Length of the selected features and sum
lengthsum = 0
with arcpy.da.SearchCursor("R40_Line_Lyr",['SHAPE@LENGTH']) as newcursor:
for newrow in newcursor:
lengthsum = lengthsum + newrow[0]
print lengthsum
del newcursor
parcelrow[1]= lengthsum
if lengthsum != 0:
parcelrow[2] = lengthsum
else:
parcelrow[2] = 0
linecursor.updateRow(linerow)
del linecursor