Hello, I have a script that uses a search cursor to go to a selected feature in a table called SplicePoints_test, that is selected based on it intersecting with some fibercable. After that I use the selected feature and extract the last 2 digits of the string of the selected entry in the SplicePoints_test layer. However when I use the searchcursor to extract the closure_name row, it iterates through all splice points and only appends the last one in the table. I used a break statement to get it to stop iterating, but it only goes to the first one instead, any ideas on how I might get the search cursor to only acknowledge the selected feature?
with arcpy.da.SearchCursor("Fibercable_Test", ['comments']) as cursor:
# Iterate through the rows
for row in cursor:
arcpy.management.SelectLayerByLocation(
in_layer="SplicePoints_test",
overlap_type="INTERSECT",
select_features="Fibercable_test",
search_distance=None,
selection_type="NEW_SELECTION",
invert_spatial_relationship="NOT_INVERT"
)
#iterate through the selected splice point, and split the last digit
with arcpy.da.SearchCursor("SplicePoints_Select", ['closure_name']) as cursor:
for row in cursor:
last_2 = row[0].split('_')[3]
arcpy.AddMessage(last_2)
# add split string to the end of the comments field
expr = "'{}{}{}'".format(entry, '.', last_2)
arcpy.management.CalculateField(
in_table="Fibercable_test",
field="comments",
expression=expr,
expression_type="PYTHON3",
code_block="",
field_type="TEXT",
enforce_domains="NO_ENFORCE_DOMAINS"
)
You’re selecting on a feature class, then cursors read the entire table. Make a feature layer first—SearchCursor will then honor the selection. Also don’t reuse cursor/row names and use next() if you only want the first selected splice point.
Try this pattern:
# Make layers so selections stick
arcpy.management.MakeFeatureLayer("Fibercable_Test", "fc_lyr")
arcpy.management.MakeFeatureLayer("SplicePoints_test","sp_lyr")
with arcpy.da.SearchCursor("fc_lyr", ["OID@", "SHAPE@", "comments"]) as fc_cur:
for oid, geom, comments in fc_cur:
# select splice points intersecting the current fiber feature
arcpy.management.SelectLayerByLocation(
in_layer="sp_lyr",
overlap_type="INTERSECT",
select_features="fc_lyr", # selection is the current feature because fc_lyr is selected by OID below
selection_type="NEW_SELECTION"
)
# limit fc_lyr to the current feature so location uses just this one
arcpy.management.SelectLayerByAttribute("fc_lyr", "NEW_SELECTION", f"OBJECTID = {oid}")
# read ONLY the selected splice points
last_2 = None
with arcpy.da.SearchCursor("sp_lyr", ["closure_name"]) as sp_cur:
row = next(sp_cur, None) # first selected
if row and row[0]:
parts = row[0].split("_")
if len(parts) > 3:
last_2 = parts[3][-2:] # or parts[3] if exactly two digits
if last_2:
expr = f"'{comments}.{last_2}'"
arcpy.management.CalculateField(
in_table="fc_lyr", field="comments",
expression=expr, expression_type="PYTHON3"
)
Key points:
MakeFeatureLayer for both inputs; run SelectLayerByLocation on layers, not raw FCs.
SearchCursor("sp_lyr", …) will return only selected rows.
Use SelectLayerByAttribute to isolate the current fiber feature by OID before the spatial select.
Use next() to avoid looping and accidentally grabbing the last record.
If multiple splice points can intersect one fiber and you need a specific one, add an order (e.g., nearest) or filter before next()
Might be misunderstanding - but I feel a spatial join then a calculate field would work.
Hi @rsnider43.,
You need to clean up your code, you have a nested SearchCursor an using "as cursor" and "row" twice. Keep these separate for each SearchCursor call. See below.
## iterate over the fiber_fc
## use the geometry of each line in the Select by Location
with arcpy.da.SearchCursor(fiber_fc, ["comments", "SHAPE@"]) as s_cursor_1:
## for each row in the Search Cursor
for s1_row in s_cursor_1:
## select the Splice Points that intersect with the cable
splice_selections = arcpy.management.SelectLayerByLocation(
in_layer=splice_fc,
overlap_type="INTERSECT",
select_features=s1_row[1], # using the geometry of the fibre
selection_type="NEW_SELECTION"
)
## iterate over the splice point selection with a second Search Cursor
with arcpy.da.SearchCursor(splice_selections, ["closure_name"]) as s_cursor_2:
## for each splice point
for s2_row in s_cursor_2:
## get the last two characters
last_2 = s2_row[0].split('_')[3]
arcpy.AddMessage(last_2)
## I would probably make the first SearchCursor an Update Cursor and just
## update the Fibre comments here.
You can actually accomplish this whole thing using cursors:
from arcpy.da import SearchCursor, UpdateCursor
with UpdateCursor("Fibercable_Test", ['OID@', 'SHAPE@', 'comments']) as cur:
for oid, cable, comment in cur:
int_closures: list[str] = [
closure_name.split('_')[-1]
for closure_name, in
SearchCursor(
"SplicePoints_test", ['closure_name'],
spatial_filter=cable)
]
if not int_closures:
continue
print(f"Found {len(int_closures)} closures for cable {oid}")
# Your original code only stores the last intersecting splice
# You may want to join them?
all_closures = f"({','.join(int_closures)})"
cur.updateRow((cable, f"{comment}.{int_closures[-1]}"))
Edit: typo in that script, I forgot to add oid to the updateRow call. It should be the first element of the tuple.
Cursors accept geometry objects as spatial filters! Which means you can skip using layer selections and just keep it compact.
Edit: Made some minor changes after re-reading your script and realizing that you just drop all but the last intersecting splice closure.
Beautiful! I always forget about the (not so) new spatial_filter. Very neat.
In my experience it can sometimes be significantly faster than SelectByLocation or a full iterative filter. Here's a quick test using my cursor module that wraps all that in a nice interface:
The top call is getting a count of features that intersect the indexed polygon using the Cursor spatial_filter and the last one is using a SelectByLocation.