Original blog post available here.
ArcGIS Pro 3.5 saw the addition of the Spatial Clause functionality for a Definition Query. While limited, it is a very useful addition where we can filter a layers features where they intersect another layer entirely or based on a selection. We are limited to intersects and we ae also limited to one spatial clause per definition query.
In this blog post we are going to use ArcPy to overcome this limitation. We will show that we can create a definition query where we filter points based on intersection with a polygon layer, but we also want to filter out points that intersect features in a second polygon layer. In our example, we want to create a definition query, using the spatial clause, where points intersect the green highlighted area below, but do not intersect the red areas.
We access the open APRX we are working in, access the relevant Map, and we access each layer where pt_lyr is the layer we want to apply a definition query to using the spatial clause functionality, where the points intersect the right-most polygon in ply2_lyr, but do not intersect the polygons on ply1_lyr.
aprx = arcpy.mp.ArcGISProject("CURRENT")
m = aprx.listMaps("Blog")[0]
m.name
'Blog'
pt_lyr, ply1_lyr, ply2_lyr = m.listLayers()
pt_lyr.name, ply1_lyr.name, ply2_lyr.name
('points_fc', 'polygon_1', 'polygon_2')
We will grab the Polygon geometry for our main area from ply2_lyr. We want points that intersect this area. We also get all polygons from ply1_lyr which we do not want points that intersect these.
## get the polygon where we want points that intersect
ply2_geom = [row[0] for row in arcpy.da.SearchCursor(ply2_lyr, "SHAPE@", "OBJECTID=1")][0]
## get the polygons for where we do not want points to intersect
ply1_geoms = [row[0] for row in arcpy.da.SearchCursor(ply1_lyr,"SHAPE@")]
We union all polygons from ply1_lyr together to give us one geometry object (Polygon).
We then erase these areas from the geometry from ply2_lyr. This will give us the geometry to use in our spatial clause in the definition query. The spatial clause uses a geometry object to perform the intersect. At the time of writing this, you could use a layer in its entirety, a selection, or a custom extent via the GUI.
## union the two geometries for non-intersection
## you could iterate over more geometries, the goal here is a single multi-geom object
ply1_geom = ply1_geoms[0].union(ply1_geoms[1])
## erase the non-intersecting polygons from the intersecting
sc_geom = ply2_geom.difference(ply1_geom)
We define the definition query dictionary and apply the definition query to our pt_lyr. The workflow below will remove any current definition query and make this one the solo one available for the point layer.
## define the definition query
dq = {"name" : "Spatial Clause Testing", "sql" : "", "isActive" : True, "spatialClause" : [{"geometry":sc_geom}]}
## apply the definition query
## NOTE: this will remove any definition queries and replace with a single definition query
pt_lyr.updateDefinitionQueries([dq])
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.