At the end of this script, I have an UpdateCursor that updates the PLOTS field in the Timber_Type_Polygon with the amount of plots that are within the Timber_Type_Polygon. There's 3 polygons within the Timber_Type_Polygon layer though, and this method updates the PLOTS field for each polygon with the amount of plots that fall within all the polygons. Hope that makes sense.

I want to figure out how to separate it out so it updates the attribute of each polygon with only the total that falls within that polygon. I'm hoping for a little direction into how to figure this out.

# Import arcpy module
import arcpy
import os
#arcpy.env.overwriteOutput = True


# Script Parameters
Timber_Type_Polygon = arcpy.GetParameterAsText(0)
Cell_Size_Height = arcpy.GetParameterAsText(1)
Cell_Size_Width = arcpy.GetParameterAsText(2)
Output_Coordinate_System = arcpy.GetParameterAsText(3)
Output_Folder = arcpy.GetParameterAsText(4)

# Set Geoprocessing environments
arcpy.env.outputCoordinateSystem = Output_Coordinate_System
arcpy.env.geographicTransformations = ""

# Process: Project
arcpy.AddMessage('...Projecting TimberType to Desired Projection')
arcpy.Project_management(Timber_Type_Polygon, os.path.join(Output_Folder, "Cruise_Polygon.shp"), Output_Coordinate_System, "", "PROJCS['NAD_1983_BC_Environment_Albers',GEOGCS['GCS_North_American_1983',DATUM['D_North_American_1983',SPHEROID['GRS_1980',6378137.0,298.257222101]],PRIMEM['Greenwich',0.0],UNIT['Degree',0.0174532925199433]],PROJECTION['Albers'],PARAMETER['False_Easting',1000000.0],PARAMETER['False_Northing',0.0],PARAMETER['Central_Meridian',-126.0],PARAMETER['Standard_Parallel_1',50.0],PARAMETER['Standard_Parallel_2',58.5],PARAMETER['Latitude_Of_Origin',45.0],UNIT['Meter',1.0]]", "NO_PRESERVE_SHAPE", "", "NO_VERTICAL")

NAR_U9 = os.path.join(Output_Folder, "Cruise_Polygon.shp")

# Process: Create Fishnet
desc = arcpy.Describe(NAR_U9)
arcpy.AddMessage('...Generating Cruise Grid')
arcpy.CreateFishnet_management("in_memory/fishnet", str(desc.extent.XMin) + " " + str(desc.extent.YMin), str(desc.extent.XMin) + " " + str(desc.extent.YMin + 10), Cell_Size_Width, Cell_Size_Height, "0", "0", str(desc.extent.XMax) + " " + str(desc.extent.YMax), "NO_LABELS", NAR_U9, "POLYLINE")

# Process: Clip
arcpy.AddMessage('...Clipping Grid to Block Area')
arcpy.Clip_analysis("in_memory/fishnet", NAR_U9, os.path.join(Output_Folder, "Cruise_Grid.shp"), "")

Cruise_Grid = os.path.join(Output_Folder, "Cruise_Grid.shp")

# Process: Intersect
arcpy.AddMessage('...Generating Cruise Plots')
arcpy.Intersect_analysis(Cruise_Grid, "in_memory/plots_before_dissolve", "NO_FID", "", "POINT")

# Process: Add XY Coordinates

# Process: Dissolve
arcpy.Dissolve_management("in_memory/plots_before_dissolve", os.path.join(Output_Folder, "Cruise_Plots.shp"), "POINT_X;POINT_Y", "", "SINGLE_PART", "DISSOLVE_LINES")

Cruise_Plots = os.path.join(Output_Folder, "Cruise_Plots.shp")

# Process: Add Sort Field
arcpy.AddField_management(Cruise_Plots, "Plot_ID", "SHORT", "", "", "5", "", "NULLABLE", "NON_REQUIRED", "")

# Sort Plots
arcpy.AddMessage('...Sorting Plots')
cursor = arcpy.UpdateCursor(Cruise_Plots, "", Output_Coordinate_System, "POINT_Y; POINT_X", "POINT_Y ASCENDING; POINT_X ASCENDING")

counter = 1
for row in cursor:
    row.Plot_ID = counter
    counter += 1

# Process: Add Field (2)
arcpy.AddField_management(Cruise_Plots, "Type", "TEXT", "", "", "5", "", "NULLABLE", "NON_REQUIRED", "")

# Process: Calculate Field
arcpy.CalculateField_management(Cruise_Plots, "Type", "Reclass(!Plot_ID!)", "PYTHON", "def Reclass (Plot_ID):\\n  if Plot_ID % 2: \\n    return \"M\"\\n  else :\\n    return \"C\"\\n\\n\\n")

# Count Total Plots in Each TimberType
arcpy.AddMessage('Counting Plots in Each Timber Type')
with arcpy.da.UpdateCursor(Timber_Type_Polygon, ['PLOTS']) as cursor:
    for row in cursor:
        arcpy.SelectLayerByLocation_management(Cruise_Plots, 'INTERSECT', Timber_Type_Polygon)
        number_of_plots = int(arcpy.GetCount_management(Cruise_Plots).getOutput(0))
        row[0] = number_of_plots

I'm not entirely sure I've understood the question correctly. But if I do, then you need to use a different layer in your 'SelectLayerByLocation' that includes only the Timber_Type_Polygon of interest, and not all of those polygons.


with arcpy.da.UpdateCursor(Timber_Type_Polygon, ['PLOTS', 'SomeFieldWithUniqueValues']) as cursor:
    singleTimberTypeLayer = "Single Timber Type Layer"
    for row in cursor:
        arcpy.MakeFeatureLayer(Timber_Type_Polygon, singleTimberTypeLayer, where_clause="SomeFieldWithUniqueValues = {}".format(row[1]}))
        arcpy.SelectLayerByLocation_management(Cruise_Plots, 'INTERSECT', singleTimberTypeLayer )
        number_of_plots = int(arcpy.GetCount_management(Cruise_Plots).getOutput(0))
        row[0] = number_of_plots

Note that for this to work, you need to include some field with unique values in the cursor. Then for each row in the cursor, create a layer that includes only the feature with this unique field value. I've used the example SomeFieldWithUniqueValues above.

Then you need to use this layer in your Select-by-location, and then must delete this layer afterwards (otherwise you won't be able to create it again the next time through the loop - for the next row.)

NB: If your field with unique values is a string field (and not a numeric type) then you'll need to include single quotes around that value in your where_clause like:

where_clause="SomeFieldWithUniqueValues = '{}'".format(row[1]})
  • That looks like it should do what I want to accomplish here. When creating the "singleTimberTypeLayer", will this cycle through each polygon and create a new polygon for each one? Also, what is the point of line 3? The singleTimberTypeLayer = "Single Timber Type layer" line
    – S. Price
    May 7 '19 at 18:58
  • The for row in cursor: will loop through each polygon. Then the singleTimberTypeLayer gets recreated from scratch for each iteration through this loop with a different polygon each time. So effectively, yes, it does cycle through each polygon. May 7 '19 at 22:37
  • That line 2 (I've moved it from line 3 to make the code more efficient) is not strictly necessary. You could use the string literal directly instead of using a variable. I prefer to use a string variable rather than a string literal if the same string needs to be used more than once and needs to match exactly. Diagnosing typos in string literals that should match can be difficult. Diagnosing typos in variable names is trivially simple. May 7 '19 at 22:41

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.