Repository: geopandas/geopandas

Issue:
BUG: 0.10 overlay fails where 0.9 succeeded
- [x] I have checked that this issue has not already been reported.

- [x] I have confirmed this bug exists on the latest version of geopandas.

- [ ] (optional) I have confirmed this bug exists on the master branch of geopandas.

---


#### Code Sample, a copy-pastable example

Data gzipped so github would allow upload: [overlay_bug.gpkg.gz](https://github.com/geopandas/geopandas/files/7337850/overlay_bug.gpkg.gz)

```python
import geopandas as gpd

gdf = gpd.read_file("overlay_bug.gpkg", driver="GPKG")
overlay_gdf = gdf.overlay(gdf, how="intersection")
```

Gives
```
Traceback (most recent call last):
  File "bug_report_2.py", line 4, in <module>
    overlay_gdf = gdf.overlay(gdf, how="intersection")
  File "/opt/conda/envs/pyai/lib/python3.8/site-packages/geopandas/geodataframe.py", line 2196, in overlay
    return geopandas.overlay(
  File "/opt/conda/envs/pyai/lib/python3.8/site-packages/geopandas/tools/overlay.py", line 358, in overlay
    result.loc[is_collection, geom_col] = dissolved[geom_col].values
  File "/opt/conda/envs/pyai/lib/python3.8/site-packages/pandas/core/indexing.py", line 723, in __setitem__
    iloc._setitem_with_indexer(indexer, value, self.name)
  File "/opt/conda/envs/pyai/lib/python3.8/site-packages/pandas/core/indexing.py", line 1730, in _setitem_with_indexer
    self._setitem_with_indexer_split_path(indexer, value, name)
  File "/opt/conda/envs/pyai/lib/python3.8/site-packages/pandas/core/indexing.py", line 1785, in _setitem_with_indexer_split_path
    raise ValueError(
ValueError: Must have equal len keys and value when setting with an iterable
```

#### Problem description

New and unexpected failure

#### Expected Output

Overlay should complete, or at least fail gracefully with error message.

#### Output of ``geopandas.show_versions()``

<details>

SYSTEM INFO
-----------
python     : 3.8.12 | packaged by conda-forge | (default, Oct 12 2021, 21:59:51)  [GCC 9.4.0]
executable : /opt/conda/envs/pyai/bin/python
machine    : Linux-5.10.47-linuxkit-x86_64-with-glibc2.10

GEOS, GDAL, PROJ INFO
---------------------
GEOS       : 3.9.1
GEOS lib   : /opt/conda/envs/pyai/lib/libgeos_c.so
GDAL       : 3.3.1
GDAL data dir: /opt/conda/envs/pyai/share/gdal
PROJ       : 8.0.1
PROJ data dir: /opt/conda/envs/pyai/share/proj

PYTHON DEPENDENCIES
-------------------
geopandas  : 0.10.1
pandas     : 1.3.3
fiona      : 1.8.20
numpy      : 1.21.2
shapely    : 1.7.1
rtree      : 0.9.7
pyproj     : 3.2.1
matplotlib : 3.4.3
mapclassify: 2.4.3
geopy      : 2.2.0
psycopg2   : 2.9.1 (dt dec pq3 ext lo64)
geoalchemy2: None
pyarrow    : 5.0.0
pygeos     : 0.10.2

</details>



Discussion:
Thanks for the report!

I can confirm the issue.

What happens here is that the current code assumes that within a resulting GeometryCollection is at least one geometry of a correct type. But in this case, some collections are composed of LineString and Point geometries while the gdf itself is made of polygons. That results in this issue.

Resolving patch:
diff --git a/geopandas/tools/overlay.py b/geopandas/tools/overlay.py
--- a/geopandas/tools/overlay.py
+++ b/geopandas/tools/overlay.py
@@ -343,16 +343,18 @@ def _make_valid(df):
 
             orig_num_geoms_exploded = exploded.shape[0]
             if geom_type in polys:
-                exploded = exploded.loc[exploded.geom_type.isin(polys)]
+                exploded.loc[~exploded.geom_type.isin(polys), geom_col] = None
             elif geom_type in lines:
-                exploded = exploded.loc[exploded.geom_type.isin(lines)]
+                exploded.loc[~exploded.geom_type.isin(lines), geom_col] = None
             elif geom_type in points:
-                exploded = exploded.loc[exploded.geom_type.isin(points)]
+                exploded.loc[~exploded.geom_type.isin(points), geom_col] = None
             else:
                 raise TypeError(
                     "`keep_geom_type` does not support {}.".format(geom_type)
                 )
-            num_dropped_collection = orig_num_geoms_exploded - exploded.shape[0]
+            num_dropped_collection = (
+                orig_num_geoms_exploded - exploded.geometry.isna().sum()
+            )
 
             # level_0 created with above reset_index operation
             # and represents the original geometry collections


Test patch:
diff --git a/geopandas/tests/test_overlay.py b/geopandas/tests/test_overlay.py
--- a/geopandas/tests/test_overlay.py
+++ b/geopandas/tests/test_overlay.py
@@ -628,6 +628,38 @@ def test_keep_geom_type_geometry_collection2():
     assert_geodataframe_equal(result1, expected1)
 
 
+def test_keep_geom_type_geomcoll_different_types():
+    polys1 = [box(0, 1, 1, 3), box(10, 10, 12, 12)]
+    polys2 = [
+        Polygon([(1, 0), (3, 0), (3, 3), (1, 3), (1, 2), (2, 2), (2, 1), (1, 1)]),
+        box(11, 11, 13, 13),
+    ]
+    df1 = GeoDataFrame({"left": [0, 1], "geometry": polys1})
+    df2 = GeoDataFrame({"right": [0, 1], "geometry": polys2})
+    result1 = overlay(df1, df2, keep_geom_type=True)
+    expected1 = GeoDataFrame(
+        {
+            "left": [1],
+            "right": [1],
+            "geometry": [box(11, 11, 12, 12)],
+        }
+    )
+    assert_geodataframe_equal(result1, expected1)
+
+    result2 = overlay(df1, df2, keep_geom_type=False)
+    expected2 = GeoDataFrame(
+        {
+            "left": [0, 1],
+            "right": [0, 1],
+            "geometry": [
+                GeometryCollection([LineString([(1, 2), (1, 3)]), Point(1, 1)]),
+                box(11, 11, 12, 12),
+            ],
+        }
+    )
+    assert_geodataframe_equal(result2, expected2)
+
+
 def test_keep_geom_type_geometry_collection_difference():
     # GH 2163