1 year ago

#336550

test-img

talz

How to perform more complex spatial joins with GeoDataFrames?

Given two GeoDataFrames, 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

Accepted video resources