Search code examples
containsgeopandas

Finding features of one geodataframe that contain at least one feature from another geodataframe


I have two polygon layers. One is a parcel layer (name "parcl") and the other one is a polygon layer (named "houses"). I am trying to find all parcels that contain at least one feature from the houses dataframe. I attempted to do so through a loop as shown below:

same = np.empty((0,parcl.shape[1]))

for i in parcl.index:
  for j in houses.index:
    a = parcl.loc[i]
    b = houses.loc[j]
    if (a.contains(b))==True:
      same.append(a)

Unfortunately, I got the following error message:

---------------------------------------------------------------------------

AttributeError                            Traceback (most recent call last)

<ipython-input-36-cedb059e5a3b> in <module>()
      5     a = parcl.loc[i]
      6     b = houses.loc[j]
----> 7     if (a.contains(b))==True:
      8       same.append(a)

/usr/local/lib/python3.7/dist-packages/pandas/core/generic.py in __getattr__(self, name)
   5139             if self._info_axis._can_hold_identifiers_and_holds_name(name):
   5140                 return self[name]
-> 5141             return object.__getattribute__(self, name)
   5142 
   5143     def __setattr__(self, name: str, value) -> None:

AttributeError: 'Series' object has no attribute 'contains'

Any help would be much appreciated! :)


Solution

  • This is a simple case of sjoin()

    • have simulated some houses (rectangles)
    • used some UK county definitions as parcels
    • gdf_contains which is result of sjoin() are now parcels that contain at least one house
    • visualised to demonstrate it has worked (green parcels)
    import geopandas as gpd
    import shapely.geometry
    import numpy as np
    import requests
    
    
    world = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres")).loc[lambda d: d["iso_a3"].eq("GBR")]
    BOXES = 25
    a, b, c, d = world.total_bounds
    
    # manufactuer some houses
    gdf_houses = gpd.GeoDataFrame(
        geometry=[
            shapely.geometry.box(minx, miny, maxx, maxy)
            for minx, maxx in zip(np.linspace(a, c, BOXES), np.linspace(a, c, BOXES)[1:])
            for miny, maxy in zip(np.linspace(b, d, BOXES), np.linspace(b, d, BOXES)[1:])
        ],
        crs="epsg:4326",
    ).sample(35)
    
    gdf_houses.explore()
    res = requests.get(
        "https://opendata.arcgis.com/datasets/37363d379f4f40fa8c3f0d28eedfdd37_0.geojson"
    )
    gdf_parcl = gpd.GeoDataFrame.from_features(res.json(), crs="epsg:4326")
    
    gdf_contains = gdf_parcl.sjoin(gdf_houses)
    
    m = gdf_parcl.explore(color="grey")
    m = gdf_contains.explore(m=m, color="green")
    m = gdf_houses.explore(m=m, style_kwds=dict(fillOpacity=.9))
    
    m
    

    enter image description here