Hi, I just discovered the shape length calculated for a polygon feature is the perimeter of the feature and not the feature length. Is this always the case or is there a way to make it so the shape length field automatically calculates and shows the feature length?
You can create a field that contains whatever you want to populate, but polygons don't have length, just (2D) perimeter.
- V
Interesting problem.
But! Very doable with some scripting.
To test, I made three rectangles, aligned to grid (Tried testing on irregular shapes but I couldn't be certain of my results, there).
(The one on the left)
From the documentation:
Click the Horizontal / Grid Aligned button to constrain a rectangle orthogonal to the map's coordinates system or thegrid for editingif it is turned on. This setting is available on the construction toolbar and on the context menu when you right-click the map.
My rectangles, from left to right:
I added two double fields to my feature class: ShapeLenEW for the horizontal length and ShapeLenNS for the vertical length.
I then pasted this code into the Python window and clicked Enter twice.
import arcpy
aprx = arcpy.mp.ArcGISProject("Current")
mp = aprx.activeMap
# Whatever the name is of the layer you want to update
poly = mp.listLayers("poly")[0]
# Insert your Length(X) and Length(Y) fields
fields = ["ShapeLenEW", "ShapeLenNS"]
# Add SHAPE@ to front of list
fields.insert(0,"SHAPE@")
# Run cursor.
# Beware cursors honor selection, so if only one record is selected,
# only one gets updated.
with arcpy.da.UpdateCursor(poly, fields) as cursor:
for row in cursor:
ext= row[0].extent
# X Field is Max X minus Min X, Y field ditto.
row[1] = ext.XMax-ext.XMin
row[2] = ext.YMax-ext.YMin
cursor.updateRow(row)
print("Done")
After running, the table has to be manually refreshed.
And hey, presto! We have the maximum lengths of our polygons.
Major caveat: This will not make any real sense if your data is in a geographic coordinate system. Make sure it's in a projected coordinate system or it'll give you your answer in degrees (?).
Also, fair warning, measuring these geodesically with the measure tool will add a little bit of extra length (.028%, in my case) to your measures.
The other thing, of course, to keep in mind, is that this will only give you the max lengths at 90° intervals- either straight up or straight to the side. I don't think there's a half-easy way to calculate at anything other than those, unless you want to use SHAPE@.hullrectangle and calculate diagonally from corner to corner.
But even with that, if you had a rectangular feature rotated at like, 23°, you wouldn't be able to get the length of its longest side.
Hope this helps!
Edit, if you prefer field calculator:
!Shape!.extent.XMax- !Shape!.extent.XMin
and
!Shape!.extent.YMax- !Shape!.extent.YMin
Not sure if it meets your needs, but the post here by @JohannesLindner are working for me with attribute rules.
R_
Is this always the case or is there a way to make it so the shape length field automatically calculates and shows the feature length?
The Shape_Length field always shows the polygon's perimeter. Most areas represented by polygons are not regular shapes like rectangles, where the concepts of "length" and "width" make sense. They are mostly irregular, so the perimeter is the only sensible choice for Shape_Length.
If you want to calculate "Length" as "The longest side of this polygon", you can do it with code in Calculate Field.
Arcade (copied from my answer here😞
var distances = []
// get the polygon parts
var rings = Geometry($feature).rings
// loop over the parts
for(var r in rings) {
var ring = rings[r]
// loop over the vertices (skip first)
for(var v = 1; v < Count(ring); v++) {
Push(distances, Distance(ring[v - 1], ring[v]))
}
}
return Max(distances)
Python:
# LengthField =
get_longest_side(!Shape!)
# Code Block
def get_longest_side(polygon):
sr = polygon.spatialReference
distances = []
for p in range(polygon.partCount):
ring = polygon.getPart(p)
for i in range(1, len(ring)):
c1 = ring.getObject(i-1)
p1 = arcpy.PointGeometry(arcpy.Point(c1.X, c1.Y, c1.Z), spatial_reference=sr)
c2 = ring.getObject(i)
p2 = arcpy.PointGeometry(arcpy.Point(c2.X, c2.Y, c2.Z), spatial_reference=sr)
distances.append(p1.distanceTo(p2))
return max(distances)
You can also do it in the Python Window:
with arcpy.da.UpdateCursor("TestPolygons", ["SHAPE@", "DoubleField1"]) as cursor:
for polygon, length in cursor:
sr = polygon.spatialReference
distances = []
for ring in polygon:
for i in range(1, len(ring)):
p1 = arcpy.PointGeometry(arcpy.Point(ring[i-1].X, ring[i-1].Y, ring[i-1].Z))
p2 = arcpy.PointGeometry(arcpy.Point(ring[i].X, ring[i].Y, ring[i].Z))
distances.append(p1.distanceTo(p2))
cursor.updateRow([polygon, max(distances)])
Thanks Johannes. I wonder if the scripts work for irregularly shaped polygons?