I am writing a function to update the value of some features inside a feature class after selecting them with arcpy.SelectLayerByLocation_management().
everything works fine in Pro but when I move to standalone script (that does not reference a specific aprx project) I am having issues.
in Pro I used
desc = arcpy.Describe(inFc)
if desc.FIDSet:
to check if some features was selected by the function SelectLayerByLocation and if so I update the values with a cursor.
In a standalone script this method is not available (DescribeData: Method FIDSet does not exist).
someone say to use arcpy.GetCount_management()
, but this method returns the total number of features in the FC is no feature is selected; this way my cursor will update everything ignoring the SelectLayerByLocation step.
ChatGPT says to create a new layer with the selection made by SelectLayerByLocation but still if 0 features have been selected the newly created temp layer will contain all the features in the main Feature class.
is there a way to solve my problem without referencing the layers in a aprx project but by working on a gdb as I am doing now?
this is my function that works in PRO but not in standalone
def checkFilling(inFc, mode, intersectFc, timeFile):
try:
# Select only gaps contained in the coverage map
arcpy.SelectLayerByLocation_management(inFc, "WITHIN", intersectFc)
# Get the selected feature count
desc = arcpy.Describe("inFc_layer")
if desc.FIDSet:
# Update the end date for selected features
with arcpy.da.UpdateCursor(inFc, ["end_date"]) as cursor:
for row in cursor:
# Update the field value as needed
row[0] = timeFile
cursor.updateRow(row)
print("Update completed successfully.")
else:
print("No features selected.")
except Exception as e:
print("An error occurred: {}".format(str(e)))
timeFile = "25/12/2023"
checkFilling("layerToUpdate", "WITHIN", "layerThatMightContainFeatures", dateVariable)
-
1Use make feature layer first and getSelectionset afterFelixIP– FelixIP2023年12月21日 08:46:11 +00:00Commented Dec 21, 2023 at 8:46
-
You can also call get count on the feature class without selection. Assign the arcpy.SelectLayerByLocation_management() call to a variable, selection for example. The result object has a count of the selected features, you can access with selection[2] (check the Derived Outputs section of the tool documentation). Although the docs say a Long is returned for the selection count, I'm pretty sure its a string so you may need to cast to int. You can then say if selection count is less than original count, you have a subset.Clubdebambos– Clubdebambos2023年12月21日 09:20:30 +00:00Commented Dec 21, 2023 at 9:20
-
Starting with ArcGIS Pro 3.2, the ArcPy Data Access cursors support spatial filters and expressions directly, so you no longer have to rely on Select Layer By Location first.bixb0012– bixb00122023年12月21日 15:23:17 +00:00Commented Dec 21, 2023 at 15:23
2 Answers 2
The FIDSet returns the selected features of a layer, but if you are working directly on a featureclass, there is no such thing as a selected feature. It should probably work if you create a featurelayer first, and then select some features in that layer.
However, there is no need to do that. You can skip the check for FIDSet altogether, and use a where
clause in the UpdateCursor
. That is, if you don't want to update all features, but only a subset.
When selecting by location, you can't use just the UpdateCursor, but must use SelectByLocation
first. The good thing is that SelectLayerByLocation
already returns a layer, so there is no need for MakeFeatureLayer
. Here's an example:
layer = arcpy.management.SelectLayerByLocation(inFc, "WITHIN", intersectFc)
desc = arcpy.da.Describe(layer)
arcpy.AddMessage(len(desc["FIDSet"]))
-
Hi Berend thanks for your reply. I thought about that but I am not sure how to "link" the where clause to the result of the
arcpy.SelectLayerByLocation_management
.fed– fed2023年12月21日 11:34:26 +00:00Commented Dec 21, 2023 at 11:34
If you take a look at the example in the documentation for Select Layer By Location, there is an example that should help you.
Try this:
def checkFilling(inFc, mode, intersectFc, timeFile):
try:
select_layer = arcpy.SelectLayerByLocation_management(inFc, "WITHIN", intersectFc)
select_count = int(arcpy.GetCount_management(select_layer)[0])
if select_count:
with arcpy.da.UpdateCursor(select_layer, ["end_date"]) as cursor:
for row in cursor:
row[0] = timeFile
cursor.updateRow(row)
print("Update completed successfully.")
else:
print("No features selected.")
except Exception as e:
print("An error occurred: {}".format(str(e)))
Note two specific changes:
- You need to use the output of the
SelectLayer
function. In Pro, this is easy to find: usually it just appends_layer
to your layer name, but you're picking it for forward operations from a list anyway. Where this goes in arcpy is a little more complicated because the context is different. The function makes it easy for you by returning a result object with the layer it created. - If you want to update selections, as opposed to the underlying original source FC, you need to use this result layer in your cursor operation. Otherwise you're updating all items. Alternately, you could use a WHERE clause on the
UpdateCursor
, but that's probably unnecessary complexity.
Also, you could replace this:
select_count = int(arcpy.GetCount_management(select_layer)[0])
with this:
select_count = int(select_layer[2])
The result object returned from SelectLayer
has multiple values, one of which is the selection count. When using the result as a layer in a future arcpy call, it is implicitly coerced into just the layer name so it works. I personally prefer an explicit GetCount
call, because explicit is better than implicit and I've found that the return values for arcpy functions aren't always quite stable across different versions. The direct access to the result object, the implicit way, is probably more performant so maybe use that if you have to do this tens of thousands of times.