|
POST
|
Using Arcade: Is there a way to update the geometry of an existing feature after an edit is made? It would be the equivalent of a DB trigger, but using logic similar to the Python field calculator script below: #written for ArcMap (https://gis.stackexchange.com/q/423806/62572) def new_shape(geom):
spatial_reference = geom.spatialReference
geom = geom.densify("ANGLE", 10000, 0.174533)
parts = arcpy.Array()
for i in range(geom.partCount):
part = geom.getPart(i)
points = arcpy.Array()
for j in range(part.count):
point = part.getObject(j)
point.M = geom.measureOnLine(point)
points.append(point)
parts.append(points)
return arcpy.Polyline(parts, spatial_reference) I suspect that's not possible, but just wanted to check to be sure. I'm having a hard time finding a solution — something that will be executed in real time after a feature is edited. There doesn't seem to be a way to do that. Even the SDE.ST_GEOMETRY functions (for an Oracle db trigger) are too limited.
... View more
02-23-2022
05:31 PM
|
0
|
2
|
1684
|
|
POST
|
Thanks very much. That really helps. I posted an ArcGIS Pro Idea about it here: Enhance the geoprocessing array: Directly iterate over items in a container Feel free to suggest improvements to that idea.
... View more
02-22-2022
03:36 PM
|
0
|
1
|
1918
|
|
IDEA
|
The answer in this post describes it best: Why does "for point in part:" work in a standalone ArcPy script, but not in the Field Calculator? The difference in behavior is due to the fact that objects within geoprocessing tools are not the same as objects within ArcPy. The pattern of directly iterating over items in a container, for point in part:, is a Python use pattern that is implemented in most ArcPy classes but not in ArcObjects classes being used by geoprocessing tools. The geoprocessing array does not implement the __iter__ special method while ArcPy Array does implement it. Idea: Could ESRI please enhance the geoprocessing array so that we can directly iterate over items in a container? Examples: for part in geometry: for point in part: Thanks.
... View more
02-22-2022
03:33 PM
|
1
|
1
|
978
|
|
POST
|
Regarding this recent video from ESRI: ArcGIS Platform - A Developer's Introduction The presenter talks about the following: "There is a client-side geometry engine that includes an SQL API for querying features in-memory (for both spatial queries and attribute queries) and thus minimizing trips back and forth to the server." Question: Where can I find more information about the "SQL API"? I tried googling it, and found a page called JavaScript API —> geometryEngine. But it doesn't seem to mention anything about SQL. Thanks.
... View more
02-22-2022
10:16 AM
|
0
|
1
|
713
|
|
POST
|
ArcMap 10.7.1 — Oracle 18c SDE.St_Geometry — Polyline FC I have an ArcPy function that works as expected in a standalone ArcPy script (PyScripter): def new_shape(geom):
spatial_reference = geom.spatialReference
parts = arcpy.Array()
for i in range(geom.partCount):
part = geom.getPart(i)
points = arcpy.Array()
for point in part:
point.M = geom.measureOnLine(point)
points.append(point)
parts.append(points)
return arcpy.Polyline(parts, spatial_reference) That function works correctly, including the following for loop. It returns a reconstructed shape to the main ArcPy Script. for point in part:
point.M = geom.measureOnLine(point)
points.append(point) However, when I use that same function in the Field Calculator, the script runs without errors, but it returns an empty shape. The problem seems to be the for loop: for point in part:. When I debug the code, I can see that the script doesn't enter the for loop. I was able to work around the issue by using a different style of for loop and the .getObject() array property. Now, the script enters the for loop and constructs the shape from the points, as expected: for j in range(part.count):
point = part.getObject(j)
point.M = geom.measureOnLine(point)
points.append(point) Question: Why does for point in part: work in a standalone ArcPy script, but not in the Field Calculator? I would like to understand this better — in case I'm doing something wrong.
... View more
02-21-2022
10:00 PM
|
0
|
5
|
2093
|
|
POST
|
ArcMap & Enterprise 10.7.1 — Oracle 18c SDE.ST_GEOMETRY — SQL Developer 18: I have an SDE.ST_GEOMETRY polyline FC that is M-enabled: In an SQL client like SQL Developer, I can query for the M-value of the endpoint of the line: select
sde.st_m(sde.st_endpoint(shape))
from
my_fc The result of that query is -Infinity. I didn't know that was possible and I wouldn't have thought to account for it when querying for possible values. Question: Is that behavior expected from ST_GEOMETRY functions? If anything, I would have expected the value to be Null, not -Infinity.
... View more
02-18-2022
02:19 PM
|
0
|
0
|
436
|
|
IDEA
|
@RandyCasey Thanks for the details. In hindsight, my original post wasn't clear. I've updated it. I'm thinking it might be handy if we could make Python selections right in the Select by Attributes window...using really short snippets of Python code, instead of full Python scripts. Kind of like what we do in the field calculator in ArcMap: have the option of using VB Script or Python. But instead, in the Select by Attributes window, have the option of using a SQL WHERE clause or a Python snippet.
... View more
02-16-2022
01:38 PM
|
0
|
0
|
19157
|
|
IDEA
|
We have scenarios where we want to select rows in a FC in the attribute table, but there isn't a way to run the query using the Select by Attributes window — due to limitations in SQL / SDE.ST_GEOEMTRY functions. For example: Select features that have true curves. While it's not possible to make that selection via SQL, it's relatively easy to find the records via ArcPy using the hasCurves Geometry property. Could ESRI consider giving us a way to Select by Attributes using Python — via functionality right in the Attribute Table window? Something kind of like this?
... View more
02-16-2022
10:23 AM
|
7
|
8
|
19197
|
|
POST
|
I have a field calculator Python script that I use to update the shape field of a FC. - Densifies any true curves. - Populates M-values of coordinates. - Reconstructs shape. Expression:
-----------
new_shape( !SHAPE! )
Code Block:
-----------
def new_shape(geom):
spatial_reference = geom.spatialReference
geom = geom.densify("ANGLE", 10000, 0.174533)
parts = arcpy.Array()
for i in range(geom.partCount):
part = geom.getPart(i)
points = arcpy.Array()
for j in range(part.count):
point = part.getObject(j)
point.M = geom.measureOnLine(point)
points.append(point)
parts.append(points)
return arcpy.Polyline(parts, spatial_reference) Screenshot Question: I want to add logic to the script that will check the new geometry for issues. I know from experience that problems in the code can mean that an empty geometry gets returned to the feature (not what I want). - I believe an empty geometry is a valid geometry. That's why the code doesn't error-out. What kinds of things should I check for in the new geometry? Ideas: 1. New shape isn't empty. 2. New point count vs. old point count. 3. New length vs. old length. 4. New part count vs. old part count. 5. Other? if new_geom and new_geom.pointCount>=orig_geom.pointCount and abs(orig_geom.length-new_geom.length) < 1 and new_geom.partCount==orig_geom.partCount:
return new_geom
else:
return orig_geom Or is it unnecessary to check those things, other than checking for an empty shape, since ArcPy validates the geometry for us? I'm using ArcMap 10.7.1. But I believe this would apply to ArcGIS Pro too. (Oracle 18c SDE.ST_GEOMETRY)
... View more
02-16-2022
08:15 AM
|
0
|
1
|
1981
|
|
POST
|
Here's one way of doing it — similar to what Dan showed above. (it does involve Python, not strictly GP tools) 1. Create a copy of the polyline FC in a FGDB. 2. Optional: Delete unneeded fields using the Delete Field GP tool. 3. Add new fields: Points_Before, Points_After, and Has_Curve. 4. Use Python in the field calculator to populate Points_Before. The Python is: !shape!.pointcount. Source: How To: Count the vertices for line or polygon features in ArcMap 5. Convert the curves to straight segments via using the Densify GP tool. I used the Angle option: 10 degrees. 6. Use Python in the field calculator to populate Points_After. 7. Use Select by Attributes to select lines where Points_Before <> Points_After. 8. Use the field calculator to populate the selected records in the Has_Curve field. That field is now a static flag that indicates if a line has a curve or not. In hindsight, using straight python might have been easier: Use Python in the Field Calculator on a custom Has_Curves field: def has_curves(geom):
geom_orig = geom
geom_densified = geom.densify("ANGLE", 10000, 0.174533)
if geom_orig.pointCount != geom_densified.pointCount:
return "Y"
else:
return None has_curves( !SHAPE! )
... View more
02-15-2022
07:49 PM
|
3
|
3
|
6295
|
|
POST
|
Solved: For whatever reason, for point in part: doesn't seem to work in the Field Calculator. It runs without errors, but it doesn't actually loop through the points. So the script returns an empty shape, which isn't what we want. I'm not sure what the root cause is. But if we replace it with: for j in range(part.count):
point = part.getObject(j) ...then that works as expected. It loops through the points. Expression:
-----------
new_shape( !SHAPE! )
Code Block:
-----------
def new_shape(geom):
spatial_reference = geom.spatialReference
geom = geom.densify("ANGLE", 10000, 0.174533)
parts = arcpy.Array()
for i in range(geom.partCount):
part = geom.getPart(i) #I think "part" is an ArcPy array: https://desktop.arcgis.com/en/arcmap/10.7/analyze/arcpy-classes/array.htm
points = arcpy.Array()
for j in range(part.count): #Alternatively, this would work in the Calculate Field GP tool too: "for j in range(len(part)):" ...and this as well: "for j, point in enumerate(part):"
#...but "for point in part:" doesn't work in the Calculate Field GP tool. It runs without errors, but it doesn't actually loop through the points. So the script returns an empty shape, which isn't what we want.
#Note: this doesn't work in the Calculate Field GP tool: "point = part[j]" ...although that might work in newer versions of ArcPy. See a newer version of the ArcPy Array docs: "The getObject method is equivalent to indexing an object; that is, obj.getObject(0) is equivalent to obj[0]."
point = part.getObject(j) #But this does work: ".getObject(j)"
point.M = geom.measureOnLine(point)
points.append(point)
parts.append(points)
return arcpy.Polyline(parts, spatial_reference) Screenshot of using the field calculator on the shape column.
... View more
02-15-2022
02:12 PM
|
0
|
0
|
1219
|
|
IDEA
|
@DWynne Yes, now I realize that the Geometry class isn't as hierarchical as I originally thought. So I think the link you mentioned is sufficient. Thanks.
... View more
02-15-2022
08:16 AM
|
0
|
0
|
2082
|
|
POST
|
The following code almost works. It runs without errors in the Calculate Field GP tool. But unfortunately, the shape column gets set to null (not what I want). I think the problem is: When the function is used by the Calculate Field gp tool, the points aren't being iterated (this bit is being skipped: for point in part:). So the shape that is returned is empty/invalid...that's why the shape is being set to null. Expression:
-----------
new_shape( !SHAPE! )
Code Block:
-----------
def new_shape(geom):
spatial_reference = geom.spatialReference
geom = geom.densify("ANGLE", 10000, 0.174533)
parts = arcpy.Array()
for i in range(geom.partCount):
part = geom.getPart(i)
points = arcpy.Array()
for point in part:
point.M = geom.measureOnLine(point)
points.append(point)
parts.append(points)
return arcpy.Polyline(parts, spatial_reference) For what it's worth, the Python function above works fine, when run within a full-blown script in an IDE like PyScripter: import arcpy
connection = "Database Connections\my_conn.sde"
feature_class = connection + "\my_owner.my_fc"
def new_shape(geom):
spatial_reference = geom.spatialReference
geom = geom.densify("ANGLE", 10000, 0.174533)
parts = arcpy.Array()
for i in range(geom.partCount):
part = geom.getPart(i)
points = arcpy.Array()
for point in part:
point.M = geom.measureOnLine(point)
points.append(point)
parts.append(points)
return arcpy.Polyline(parts, spatial_reference)
with arcpy.da.Editor(connection) as edit_session:
with arcpy.da.UpdateCursor(feature_class, ["SHAPE@","OID@"]) as cursor:
for row in cursor:
if row[1] == 1928:
geom = new_shape(row[0])
row[0] = geom
cursor.updateRow(row) But when I use the function in the Calculate Field tool (in ArcMap-->Calculate Field GP, or as a standalone Calculate Field GP script in PyScripter), the shape gets set to null. I think the problem is: When the function is used by the Calculate Field gp tool, the points aren't being iterated properly (in other words, this bit is being skipped: for point in part:). So the shape that is returned is invalid and that's why the shape is being set to null.
... View more
02-14-2022
05:31 PM
|
0
|
0
|
1230
|
|
POST
|
ArcMap 10.7.1 (Oracle SDE.ST_GEOMETRY): I'm hoping to use the Calculate Field GP tool to update the coordinates of a polyline FC's shape column. I have a script that works in a standalone Python IDE (PyScripter): Source: Set M-values to cumulative length of line (via ArcPy) import arcpy
connection = "Database Connections\my_conn.sde"
feature_class = connection + "\my_owner.my_fc"
spatial_reference = arcpy.Describe(feature_class).spatialReference
with arcpy.da.Editor(connection) as edit_session:
with arcpy.da.UpdateCursor(feature_class, "SHAPE@") as cursor:
for row in cursor:
geometry = row[0].densify("ANGLE", 10000, 0.174533)
parts = arcpy.Array()
for part in geometry:
points = arcpy.Array()
for point in part:
point.M = geometry.measureOnLine(point)
points.append(point)
parts.append(points)
row[0] = arcpy.Polyline(parts, spatial_reference)
cursor.updateRow(row) I want to use that same logic, but in the Calculate Field GP tool: Screenshot Expression:
-----------
new_shape( !SHAPE! )
Code Block:
-----------
def new_shape(geometry):
geometry = geometry.densify("ANGLE", 10000, 0.174533)
parts = arcpy.Array()
for part in geometry:
points = arcpy.Array()
for point in part:
point.M = geometry.measureOnLine(point)
points.append(point)
parts.append(points)
return arcpy.Polyline(parts) But when I run that Calculate Field code, I get an error: "geoprocessing describe geometry object' object is not iterable" ERROR 000539: Error running expression: new_shape( GPVARIANTOBJECT0 )
Traceback (most recent call last):
File "<expression>", line 1, in <module>
File "<string>", line 4, in new_shape
TypeError: 'geoprocessing describe geometry object' object is not iterable
Failed to execute (CalculateField). Question: What am I doing wrong? The geometry was iterable when using the full blown script in PyScripter. I don't understand why it isn't iterable in the Calculate Field script too. Edit: I can get part of the script work. I can densify the shape: Screenshot Expression:
-----------
new_shape( !SHAPE! )
Code Block:
-----------
def new_shape(geometry): geometry = geometry.densify("ANGLE", 10000, 0.174533) return geometry (And if I wanted to, I could also set the shape to None via the Calculate Field GP tool.) But when I try to loop through the geometry's parts, I get the aforementioned error. Any ideas? Thanks!
... View more
02-14-2022
02:15 PM
|
0
|
2
|
1263
|
|
IDEA
|
This Idea is no longer needed. ESRI, feel free to delete it. I don't think I can do that on my end.
... View more
02-09-2022
03:35 PM
|
0
|
0
|
4177
|
| Title | Kudos | Posted |
|---|---|---|
| 1 | 04-30-2026 11:08 AM | |
| 1 | 05-11-2026 11:23 AM | |
| 2 | 05-07-2026 04:19 AM | |
| 1 | 05-06-2026 09:03 AM | |
| 1 | 03-19-2026 09:29 AM |