23

In ArcGIS 10 and Python I want to get the extent (xmax, ymax, xmin, ymin) info of each of the polygons in a shapefile.

I can get the extent of the whole shapefile using

file=r"D:\SCRATCH\ARCGIS\100k_trc_tiles_TVM.shp"
desc=arcpy.Describe(file)
print desc.extent.Xmax

394551.52085039532

But I can't seem to figure out how to get the same info for each row in the dataset.

rows = arcpy.SearchCursor("100k_trc_tiles_TVM")
for row in rows:
 print row

prints the 31 rows in the dataset but

for row in rows:
 desc=arcpy.Describe(row)
 print desc.extent.Xmax

gives an error.

Runtime error : Object: Describe input value is not valid type

I was thinking of adding the extent values to the table using "calculate geometry" but this only gives the centroid. Then I guess we can use something like row.GetValue("xmax").

That being said I know that we can create the X/Y, max/min using the function from http://www.ian-ko.com/free/free_arcgis.htm but it would be best if we can avoid having to add fields, especially if ArcPy can get these values.

Basically I need to get the extents to feed into the clip tool to clip out 30 areas of data (according to the 1:100,000 map sheets) for geoprocessing since the Split tool fails due to the large size of the dataset (see Why Intersect gives ERROR 999999: Error executing function Invalid Topology [Too many lineseg endpoints]?). I want to automate this as it is repeated on a number of datasets.

=== working script ===

# Emulates Arc Info SPLIT tool by using Clip but
# Requires a FC from which each row is used as the input clip feature.
# Each row must be rectangular.
# Used on 12GB FGDB with 100 million records.


#Licence: Creative Commons
#Created by: George Corea; georgec@atgis.com.au, coreagc@gmail.com
import arcpy, string

#inFrame=arcpy.GetParameterAsText(0) # Input dataframe FC
#inFile=arcpy.GetParameterAsText(1) # Input FC for splitting
#outDir=arcpy.GetParameterAsText(2) # Output FGDB

inFrame=r"D:\SCRATCH\ARCGIS\100k_trc_tiles_TVM.shp"
inFile=r"c:\junk\106\data\7_Merge.gdb\FullRez_m2b"
outDir=r"D:\SCRATCH\Projects\206\datasplit\test_slaasp.gdb"
#NameField="Name_1"

#arcpy.env.workspace = r"C:/Workspace"
arcpy.env.overwriteOutput = True

rows = arcpy.SearchCursor(inFrame)
shapeName = arcpy.Describe(inFrame).shapeFieldName
for row in rows:
    feat = row.getValue(shapeName)
    Name = row.Name_1
    print "Executing clip on: "+str(Name)
    extent = feat.extent
    #print extent.XMin,extent.YMin,extent.XMax,extent.YMax
# Create an in_memory polygon
    XMAX = extent.XMax
    XMIN = extent.XMin
    YMAX = extent.YMax
    YMIN = extent.YMin
    pnt1 = arcpy.Point(XMIN, YMIN)
    pnt2 = arcpy.Point(XMIN, YMAX)
    pnt3 = arcpy.Point(XMAX, YMAX)
    pnt4 = arcpy.Point(XMAX, YMIN)
    array = arcpy.Array()
    array.add(pnt1)
    array.add(pnt2)
    array.add(pnt3)
    array.add(pnt4)
    array.add(pnt1)
    polygon = arcpy.Polygon(array)
    ShapeFile = outDir+"\\temp_poly"
    arcpy.CopyFeatures_management(polygon, ShapeFile)

    #print Name
### Set local variables
    in_features = inFile
    clip_features = ShapeFile
    out_feature_class = outDir+"\\"+Name
    xy_tolerance = "0.22"

    # Execute Clip

    try:
        arcpy.Clip_analysis(in_features, clip_features, out_feature_class, xy_tolerance)
        print "Completed: "+str(Name)
    except:
        error = arcpy.GetMessages()
        print "Failed on: "+str(Name)+" due to "+str(error)
PolyGeo
  • 65,136
  • 29
  • 109
  • 338
GeorgeC
  • 8,228
  • 7
  • 52
  • 136

5 Answers5

29

Get the shape object in your cursor and access its extent property. See ArcGIS Help Working with geometry in Python:

rows = arcpy.SearchCursor(inFeatures)

shapeName = arcpy.Describe(inFeatures).shapeFieldName for row in rows: feat = row.getValue(shapeName) extent = feat.extent print extent.XMin,extent.YMin,extent.XMax,extent.YMax

While the above works it is better to use the newer, more performant arcpy.da cursor syntax which was introduced in ArcGIS Desktop 10.1:

with arcpy.da.SearchCursor(inFeatures, ['SHAPE@']) as rows:
    for row in rows:
        extent = row[0].extent
        print(extent.XMin,extent.YMin,extent.XMax,extent.YMax)
PolyGeo
  • 65,136
  • 29
  • 109
  • 338
user2856
  • 65,736
  • 6
  • 115
  • 196
2

Another way would be to do a SearchCursor() on the shapefile, then you can use row.shape.extent:

rows = arcpy.SearchCursor(shapefileName)

for row in rows:
   extent = row.shape.extent
   ...
   ...
PolyGeo
  • 65,136
  • 29
  • 109
  • 338
Ruth
  • 41
  • 3
2

I just tried the Minimum Bounding Geometry (Envelope) (in Data Management) in ArcGIS 10 and it seems to do exactly the same, for all the fields.

PolyGeo
  • 65,136
  • 29
  • 109
  • 338
Sid
  • 21
  • 1
1

Try capitalizing the "M" in "XMax". I think it's supposed to be:

print desc.extent.XMax

instead of

print desc.extent.Xmax

according to the documentation. Of course that makes me wonder how your first code snippet worked.

PolyGeo
  • 65,136
  • 29
  • 109
  • 338
dmahr
  • 11,833
  • 40
  • 68
0

As covered in Extracting coordinates of polygon vertices in ArcMap? you can get get the vertices of a polygon and then add the x and y coordinates of each vertex as fields in the attribute table. This has the limitation of not attaching the max/min coordinates directly to each polygon but this can be achieved in a few ways.

The method I am most familiar with is to read the x and y fields into python lists using the pyshp module, which can then be sorted to find maximum and minimum values for each polygon. Pyshp can then be used to open a writer class to add new fields to the original polygons and write these max and min values to the correct polygon.

I believe this can be done using the arcpy, but I had a lot of problems with writing to shapefiles in 9.3 using the geoprocessor, so I prefer the pyshp method, however I am unsure if the arcpy module has solved these issues.

sgrieve
  • 3,726
  • 1
  • 19
  • 36