Select to view content in your preferred language

How to get select by location to honor definition query that is set in tool?

93
3
yesterday
ZacharyKasson
Occasional Contributor

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.

Tags (2)
3 Replies
TonyAlmeida
MVP Regular Contributor

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"
    )

 

ZacharyKasson
Occasional Contributor

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!

HaydenWelch
MVP Regular Contributor

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)})"  
    )
0 Kudos