1 year ago
#336550
talz
How to perform more complex spatial joins with GeoDataFrames?
Given two GeoDataFrame
s, g1
, g2
, I want to get all the rows from g1
which do not intersect any rows from g2
, or only touch them.
For this there are some operations which I am missing in the interface:
- (Left) Semi-Join (only keep data from left side after filtering it by binary predicate with right side)
- (Left) Anti-Join (only keep rows that do not fulfill the binary predicate with any of the rows of the right side)
- Logical operators (OR, NOT, AND, etc.) for the binary predicate.
- Unique (do not duplicate left rows on multiple hits)
I would like to be able to write a query like this:
result = g1.sjoin(g2, how="left-anti-semi", predicate="intersects & ~touches")
Or at least:
intersect_but_not_touch = lambda left_shape, right_shape: left_shape.intersects(right_shape) and not left_shape.touches(right_shape)
joined = g1.sjoin(g2, how="left", predicate=intersect_but_not_touch)
result = joined.query('right_index != right_index') # anti-join.
But I did not see any way to combine predicates, or to pass a function as a predicate. Is there any way to do any of that with sjoin
or do we have to do that "manually"?
This is the solution I have got so far, but this is far too complicated:
# Duplicate geometry column so it remains after sjoin.
g2["right_geometry"] = g2["geometry"]
intersect = g1.sjoin(g2, how="left")
# right index is Nan, no intersection found.
dont_intersect = intersect.query("right_index != right_index") # anti-join
intersect = intersect.query("right_index == right_index")
# row-wise "touches" predicate.
intersect["just_touch"] = intersect.touches(intersect["right_geometry"])
intersect_but_just_touch = intersect.groupby(intersect.index).filter(
lambda x: x.just_touch.all()
)
result = pd.concat([dont_intersect, intersect_but_just_touch])
python
geopandas
shapely
spatial-query
0 Answers
Your Answer