I am creating a tool to write information from one layer to another via a spatial join. I am setting a definition query on a my points layer (successfully sets definition query) - then running a select by location to intersect my line layer with the queried points layer. The select by location does not honor the definition query and selects the lines that intersect the unqueried point layer.
Here is my code:
def script_tool(map_name, Point_Name,Line_Name,query):
# Pro project env variables
arcpy.env.overwriteOutput = True
aprx = arcpy.mp.ArcGISProject('CURRENT')
MasterMap=aprx.listMaps(map_name)[0]
Points_Layer = MasterMap.listLayers(Point_Name)[0]
# # # SET DEFINITION QUERY # # #
def setDefinitionQuery(layer, sqlFilter):
layer.updateDefinitionQueries(
[
{'name': 'Query 1', 'sql': sqlFilter, 'isActive': True}
]
)
setDefinitionQuery(Point_Name,query)# this is sucessful - layer is queried after tool is finished running
arcpy.RefreshLayer(Points_Layer) # Refresh Layer
# # # Select Anchors by location # # #
arcpy.management.SelectLayerByLocation(
in_layer=Line_Name,
overlap_type="INTERSECT",
select_features= Point_Name, #also used layer object with same result.
search_distance=None,
selection_type="NEW_SELECTION",
invert_spatial_relationship="NOT_INVERT"
)
This selects 10,000 features instead of the desired 18. It works fine in a notebook, but not as a tool. How do I ensure the layer refreshes before doing a select layer by location.
I could do a select by attribute, but visually I only want those queried points in my map.
Try using feature layer with definition query.
temp_points = "memory/temp_points"
arcpy.management.MakeFeatureLayer(
points_lyr,
temp_points,
where_clause=query
)
arcpy.management.SelectLayerByLocation(
in_layer=line_lyr,
overlap_type="INTERSECT",
select_features=temp_points,
search_distance=None,
selection_type="NEW_SELECTION"
)
Ah, that's a good idea. Not exactly the functionality I am hoping for but it should suffice if def query is not possible. Thank you!
I think you just need to save the aprx:
...
setDefinitionQuery(Point_Name,query)# this is sucessful - layer is queried after tool is finished running
arcpy.RefreshLayer(Points_Layer) # Refresh Layer
+ aprx.save()
...
I also started down my cursor rabbit hole and came up with a version that only uses geometry and SearchCursors lol:
from arcpy.da import SearchCursor
from arcpy import PointGeometry
from functools import reduce
from arcpy import (
AddError,
)
from arcpy._mp import (
Layer,
Map,
ArcGISProject,
)
from arcpy.management import SelectLayerByAttribute
def script_tool(map_name: str, point_layer_name: str, line_layer_name: str, sql_query: str) -> None:
# Grab layers and such
aprx = ArcGISProject('CURRENT')
map_objs: list[Map] = aprx.listMaps(map_name)
if not map_objs:
AddError(f"{map_name} does not exist!")
return
map_obj = map_objs[0]
point_layer_objs: list[Layer] = map_obj.listLayers(point_layer_name)
if not point_layer_objs:
AddError(f"{point_layer_name} does not exist in {map_name}!")
return
point_layer_obj = point_layer_objs[0]
line_layer_objs: list[Layer] = map_obj.listLayers(line_layer_name)
if not line_layer_objs:
AddError(f"{line_layer_name} does not exist in {map_name}!")
return
line_layer_obj = line_layer_objs[0]
# Get point geos of points that match the query
point_geos: list[PointGeometry] = [
rec[0]
for rec in SearchCursor(point_layer_obj.dataSource, ['SHAPE@'], where_clause=sql_query)
]
# Merge points into a multipoint
multipoint = reduce(lambda a, b: a+b, point_geos)
# Grab all line ids that intersect the multipoint
# Need to cast to string for query interpolation
line_ids: list[str] = [
str(oid)
for oid, line in SearchCursor(line_layer_obj, ['OID@'], spatial_filter=multipoint)
]
SelectLayerByAttribute(
in_layer_or_view=line_layer_obj,
selection_type='NEW_SELECTION',
where_clause=f"OBJECTID IN ({','.join(line_ids)})"
)