From 20527da2b277ec2051a12d2de0c53ccbb7ee61b0 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Sat, 21 Jan 2023 04:02:00 +0100 Subject: [PATCH] BUG: avoid invalid bbox for empty GeoDataFrame in to_parquet (#2761) --- CHANGELOG.md | 2 ++ geopandas/io/arrow.py | 7 ++++++- geopandas/io/tests/test_arrow.py | 14 ++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 904fe2d..04eef7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ Bug fixes: - Ensure that GeoDataFrame created from DataFrame is a copy, not a view (#2667) - Fix mismatch between geometries and colors in ``plot()`` if an empty or missing geometry is present (#2224) +- Fix `to_parquet`/`to_feather` to not write an invalid bbox (with NaNs) in the + metadata in case of an empty GeoDataFrame (#2653) Notes on (optional) dependencies: diff --git a/geopandas/io/arrow.py b/geopandas/io/arrow.py index fea924c..440eded 100644 --- a/geopandas/io/arrow.py +++ b/geopandas/io/arrow.py @@ -2,6 +2,7 @@ from packaging.version import Version import json import warnings +import numpy as np from pandas import DataFrame, Series from geopandas._compat import import_optional_dependency @@ -108,9 +109,13 @@ def _create_metadata(df, schema_version=None): "geometry_type": geometry_types[0] if len(geometry_types) == 1 else geometry_types, - "bbox": series.total_bounds.tolist(), } + bbox = series.total_bounds.tolist() + if np.isfinite(bbox).all(): + # don't add bbox with NaNs for empty / all-NA geometry column + column_metadata[col]["bbox"] = bbox + return { "primary_column": df._geometry_column_name, "columns": column_metadata, diff --git a/geopandas/io/tests/test_arrow.py b/geopandas/io/tests/test_arrow.py index 8e87524..2543eb1 100644 --- a/geopandas/io/tests/test_arrow.py +++ b/geopandas/io/tests/test_arrow.py @@ -653,6 +653,20 @@ def test_write_read_feather_expand_user(): os.remove(os.path.expanduser(test_file)) +@pytest.mark.parametrize("geometry", [[], [None]]) +def test_write_empty_bbox(tmpdir, geometry): + # empty dataframe or all missing geometries -> avoid bbox with NaNs + gdf = geopandas.GeoDataFrame({"col": [1] * len(geometry)}, geometry=geometry) + gdf.to_parquet(tmpdir / "test.parquet") + + from pyarrow.parquet import read_table + + table = read_table(tmpdir / "test.parquet") + metadata = json.loads(table.schema.metadata[b"geo"]) + assert "encoding" in metadata["columns"]["geometry"] + assert "bbox" not in metadata["columns"]["geometry"] + + @pytest.mark.parametrize("format", ["feather", "parquet"]) def test_write_read_default_crs(tmpdir, format): if format == "feather":