3
import arcpy

arcpy.env.workspace = "c:/esripress/python/data"
fc = "Hawaii.shp"
   
cursor = arcpy.da.SearchCursor(fc, ["OID@","SHAPE@"])  
for shape in cursor:  
        print "Total area: {}".format(shape.area)  
        partnum = 0  
        for part in shape:  
            pn = arcpy.Polygon(part)  
            print "Part: {} Area: {} Perimeter {}".format(partnum, pn.area, pn.length)
            partnum += 0

I'm trying to figure out how to print the perimeter and area of each individual island of the Hawaii multipart feature. Initially, I kept receiving the error 'float not iterable'

However, after banging my head and changing the code over and over, I now receive a syntax error - invalid syntax without specifying which part of the code contains the syntax error. I think my error lies in the section of the code where I begin to iterate over the for part in shape: What am I not seeing? I know I can try adding a field and using the calculate field management tool, but I want to answer this question by reading the cursor.

  • 1
    print "Total area: {}".format(shape[1].area) then for part in shape[1]: you need to specify what field to use that contains the shape.. I think it's confusing to call your row shape. Shape is actually row[1] based on your cursor declaration. If you're creating a cursor like that don't forget to del cursor when you're done. – Michael Stimson Sep 13 '17 at 21:42
  • 2
    Personally I would MultipartToSinglepart your shapefile into a file geodatabase to see areas and perimeters as fields that you can run a simpler SearchCursor over to print out the same information. – PolyGeo Sep 13 '17 at 21:52
  • 5
    Last line should be partnum += 1 too – Marc Pfister Sep 13 '17 at 21:55
5

Putting the comments together:

import arcpy

arcpy.env.workspace = "c:/esripress/python/data"
fc = "Hawaii.shp"

with arcpy.da.SearchCursor(fc, ["OID@","SHAPE@"]) as cursor:
    for row in cursor:
        shape = row[1] # shape is the 2nd value in the row
        print "Total area: {}".format(shape.area)  
        partnum = 0  
        for part in shape:  
            pn = arcpy.Polygon(part)  
            print "Part: {} Area: {} Perimeter {}".format(partnum, pn.area, pn.length)
            partnum += 1 # Increase by 1, well spotted by Marc Pfister

IMO the best way to declare an arcpy.da cursor is using a with block, this handles the destruction of the cursor object automatically.. there's nothing wrong with declaring then destroying a cursor as you have done but if you forget to del your cursor (as you have done) a lock can be left on the featureclass which will cause problems later.

arcpy.da cursors iterate row tuples, not geometries, shapes are a value in the row for a spatial table that we call a feature class. To get the shape (geometry) for the row you can access by the index in the row. As you have specified SHAPE@ the object at that index (1) is a geometry object which can be either point, multipoint, plolyline or polygon for a simple geometry type (not annotation, dimension etc), if you assume the shape is a polygon you can get the geometry area and perimeter properties as shown in the code.

For this example you know that the feature class is a polygon but for your reference you can test the shape.type (if row[1].type.lower()=='polygon':) before trying to access a property that will not exist for other geometry types; if you try to access shape.area for a point geometry type you will get an error method does not exist or something similar.

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.