Repository: geopandas/geopandas
Pull request #3337 (2024-06-10 10:22:51)

BUG/REVERT: Keep geometry col name as "geometry" in `GeoDataFrame.__init__`
Relates to #3312 (and rolls back part of #3237).

Thought I'd open this up to see if it generates any further discussion, and then we have it if we want it for the rc.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b471a8c7..eebf28ee 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,9 +6,9 @@ Notes on dependencies:
 
 - GeoPandas 1.0 drops support for shapely<2 and PyGEOS. The only geometry engine that is
   currently supported is shapely >= 2. As a consequence, spatial indexing based on the
-  rtree package has also been removed. (#3035)
+  rtree package has also been removed (#3035).
 - The I/O engine now defaults to Pyogrio which is now installed with GeoPandas instead
-  of Fiona. (#3223)
+  of Fiona (#3223).
 
 New methods:
 
@@ -56,19 +56,22 @@ New features and improvements:
 - Added support to ``to_parquet`` and ``read_parquet`` for writing and reading files
   using the GeoArrow-based native geometry encoding of GeoParquet 1.1 (#3253, #3275).
 - Add `sort` keyword to `clip` method for GeoSeries and GeoDataFrame to allow optional
-  preservation of the original order of observations. (#3233)
+  preservation of the original order of observations (#3233).
 - Added `show_bbox`, `drop_id` and `to_wgs84` arguments to allow further customization of
-  `GeoSeries.to_json` (#3226)
+  `GeoSeries.to_json` (#3226).
 - `explore` now supports `GeoDataFrame`s with additional columns containing datetimes, uuids and
   other non JSON serializable objects (#3261).
 - The `GeoSeries.fillna` method now supports the `limit` keyword (#3290).
 - Added support for `bbox` covering encoding in geoparquet. Can filter reading of parquet
-files based on a bounding box, and write out a bounding box column to parquet files (#3282)
+files based on a bounding box, and write out a bounding box column to parquet files (#3282).
 - `align` keyword in binary methods now defaults to `None`, treated as True. Explicit True
-  will silence the warning about mismachted indices. (#3212)
+  will silence the warning about mismatched indices (#3212).
 - `GeoSeries.set_crs` can now be used to remove CRS information by passing
-  `crs=None, allow_override=True`. (#3316)
+  `crs=None, allow_override=True` (#3316).
 - Added ``autolim`` keyword argument to ``GeoSeries.plot()`` and ``GeoDataFrame.plot()`` (#2817).
+- Updated documentation to clarify that passing a named (Geo)Series as the `geometry`
+  argument to the GeoDataFrame constructor will not use the name but will always  
+  produce a GeoDataFrame with an active geometry column named "geometry" (#3337).
 
 Backwards incompatible API changes:
 
@@ -84,7 +87,12 @@ Backwards incompatible API changes:
   the previous active geometry column name. This means that if the new and old names are
   different, then both columns will be preserved in the GeoDataFrame. To replicate the previous
   behaviour, you can instead call `gdf.set_geometry(ser.rename(gdf.active_geometry_name))` (#3237).
-- `delaunay_triangles` now considers all geometries together when creating the Delaunay trianguation
+  Note that this behaviour change does not affect the `GeoDataframe` constructor, passing a named 
+  GeoSeries `ser` to `GeoDataFrame(df, geometry=ser)` will always produce a GeoDataFrame with a
+  geometry column named "geometry" to preserve backwards compatibility. If you would like to
+  instead propagate the name of `ser` when constructing a GeoDataFrame, you can instead call
+  `df.set_geometry(ser)` or `GeoDataFrame(df, geometry=ser).rename_geometry(ser.name)` (#3337).
+- `delaunay_triangles` now considers all geometries together when creating the Delaunay triangulation
   instead of performing the operation element-wise. If you want to generate Delaunay
   triangles for each geometry separately, use ``shapely.delaunay_triangles`` instead. (#3273)
 - Reading a data source that does not have a geometry field using ``read_file``
@@ -113,6 +121,8 @@ Enforced deprecations:
     method directly instead.
   - Removed deprecated GeoSeries/GeoDataFrame `.plot` parameters `axes` and `colormap`, instead use
     `ax` and `cmap` respectively.
+  - Removed compatibility for specifying the `version` keyword in `to_parquet` and `to_feather`.
+    This keyword will now be passed through to pyarrow and use `schema_version` to specify the GeoParquet specification version (#3334).
 
 New deprecations:
 
diff --git a/doc/source/docs/user_guide/projections.rst b/doc/source/docs/user_guide/projections.rst
index b589c10a..fbba9c15 100644
--- a/doc/source/docs/user_guide/projections.rst
+++ b/doc/source/docs/user_guide/projections.rst
@@ -252,7 +252,7 @@ One possible way to find out the EPSG code is using pyproj for this:
 value if the match is not perfect)
 
 Further, on websites such as `Spatial Reference <https://spatialreference.org/>`__
-and `epsg.io <https://epsg.io/>`__ the descriptions of many CRS can be found
+and `epsg.org <https://epsg.org/>`__ the descriptions of many CRS can be found
 including their EPSG codes and proj4 string definitions.
 
 **Other formats**
@@ -363,7 +363,7 @@ can be a reason that the CRS object is not equal to the expected EPSG code.
 
 Consider the following example of a Canadian projected CRS EPSG:2953. When
 constructing the CRS object from the WKT string as provided on
-`EPSG:2953 <https://epsg.io/2953>`__:
+`EPSG:2953 <https://spatialreference.org/ref/epsg/2953/>`__:
 
 .. code-block:: python
 
diff --git a/doc/source/gallery/plotting_basemap_background.ipynb b/doc/source/gallery/plotting_basemap_background.ipynb
index 6b0ddc12..77da1a89 100644
--- a/doc/source/gallery/plotting_basemap_background.ipynb
+++ b/doc/source/gallery/plotting_basemap_background.ipynb
@@ -57,7 +57,7 @@
     "coordinate reference systems (CRS) of the tiles and the data match.\n",
     "Web map tiles are typically provided in\n",
     "[Web Mercator](https://en.wikipedia.org/wiki/Web_Mercator>)\n",
-    "([EPSG 3857](https://epsg.io/3857)), so let us first check what\n",
+    "([EPSG 3857](https://spatialreference.org/ref/epsg/3857/)), so let us first check what\n",
     "CRS our NYC boroughs are in:"
    ]
   },
diff --git a/doc/source/gallery/polygon_plotting_with_folium.ipynb b/doc/source/gallery/polygon_plotting_with_folium.ipynb
index 1da13782..b6f7b68a 100644
--- a/doc/source/gallery/polygon_plotting_with_folium.ipynb
+++ b/doc/source/gallery/polygon_plotting_with_folium.ipynb
@@ -81,7 +81,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "The [epsg:2263](https://epsg.io/2263) crs is a projected coordinate reference system with linear units (ft in this case).\n",
+    "The [EPSG:2263](https://spatialreference.org/ref/epsg/2263/) crs is a projected coordinate reference system with linear units (ft in this case).\n",
     "As folium (i.e. leaflet.js) by default accepts values of latitude and longitude (angular units) as input, we need to project the geometry to a geographic coordinate system first."
    ]
   },
diff --git a/geopandas/geodataframe.py b/geopandas/geodataframe.py
index d5a6ee4e..2b35629d 100644
--- a/geopandas/geodataframe.py
+++ b/geopandas/geodataframe.py
@@ -87,9 +87,13 @@ class GeoDataFrame(GeoPandasBase, DataFrame):
         Coordinate Reference System of the geometry objects. Can be anything accepted by
         :meth:`pyproj.CRS.from_user_input() <pyproj.crs.CRS.from_user_input>`,
         such as an authority string (eg "EPSG:4326") or a WKT string.
-    geometry : str or array (optional)
-        If str, column to use as geometry. If array, will be set as 'geometry'
-        column on GeoDataFrame.
+    geometry : str or array-like (optional)
+        If str, column to use as active geometry column. If array-like, it will be
+        added as new column named 'geometry' column on GeoDataFrame and set as the
+        active geometry column. Note that if ``geometry`` is a (Geo)Series with a
+        name, the name will not be used, a column named "geometry" will still be
+        added. To preserve the name, you can use :meth:`~GeoDataFrame.rename_geometry`
+        to update the geometry column name.
 
     Examples
     --------
@@ -194,6 +198,11 @@ class GeoDataFrame(GeoPandasBase, DataFrame):
             ):
                 raise ValueError(crs_mismatch_error)
 
+            if hasattr(geometry, "name") and geometry.name not in ("geometry", None):
+                # __init__ always creates geometry col named "geometry"
+                # rename as `set_geometry` respects the given series name
+                geometry = geometry.rename("geometry")
+
             self.set_geometry(geometry, inplace=True, crs=crs)
 
         if geometry is None and crs:
@@ -1299,7 +1308,8 @@ properties': {'col1': 'name1'}, 'geometry': {'type': 'Point', 'coordinates': (1.
     ):
         """Write a GeoDataFrame to the Parquet format.
 
-        Any geometry columns present are serialized to WKB format in the file.
+        By default, all geometry columns present are serialized to WKB format
+        in the file.
 
         Requires 'pyarrow'.
 
@@ -1320,14 +1330,21 @@ properties': {'col1': 'name1'}, 'geometry': {'type': 'Point', 'coordinates': (1.
             The encoding to use for the geometry columns. Defaults to "WKB"
             for maximum interoperability. Specify "geoarrow" to use one of the
             native GeoArrow-based single-geometry type encodings.
-        schema_version : {'0.1.0', '0.4.0', '1.0.0', None}
-            GeoParquet specification version; if not provided will default to
-            latest supported version.
+            Note: the "geoarrow" option is part of the newer GeoParquet 1.1
+            specification, should be considered as experimental, and may not
+            be supported by all readers.
         write_covering_bbox : bool, default False
             Writes the bounding box column for each row entry with column
             name 'bbox'. Writing a bbox column can be computationally
             expensive, but allows you to specify a `bbox` in :
             func:`read_parquet` for filtered reading.
+            Note: this bbox column is part of the newer GeoParquet 1.1
+            specification and should be considered as experimental. While
+            writing the column is backwards compatible, using it for filtering
+            may not be supported by all readers.
+        schema_version : {'0.1.0', '0.4.0', '1.0.0', '1.1.0', None}
+            GeoParquet specification version; if not provided, will default to
+            latest supported stable version (1.0.0).
         kwargs
             Additional keyword arguments passed to :func:`pyarrow.parquet.write_table`.
 


Test patch:
diff --git a/geopandas/tests/test_geodataframe.py b/geopandas/tests/test_geodataframe.py
index 8efb81ab..c9d74b1f 100644
--- a/geopandas/tests/test_geodataframe.py
+++ b/geopandas/tests/test_geodataframe.py
@@ -1323,18 +1323,17 @@ class TestConstructor:
         check_geodataframe(gdf)
         assert list(gdf.columns) == ["geometry", "a"]
 
-    def test_preserve_series_name(self):
+    def test_do_not_preserve_series_name_in_constructor(self):
+        # GH3337
+        # GeoDataFrame(... geometry=...) should always create geom col "geometry"
         geoms = [Point(1, 1), Point(2, 2), Point(3, 3)]
         gs = GeoSeries(geoms)
         gdf = GeoDataFrame({"a": [1, 2, 3]}, geometry=gs)
-
         check_geodataframe(gdf, geometry_column="geometry")
-
-        geoms = [Point(1, 1), Point(2, 2), Point(3, 3)]
+        # still get "geometry", even with custom geoseries name
         gs = GeoSeries(geoms, name="my_geom")
         gdf = GeoDataFrame({"a": [1, 2, 3]}, geometry=gs)
-
-        check_geodataframe(gdf, geometry_column="my_geom")
+        check_geodataframe(gdf, geometry_column="geometry")
 
     def test_overwrite_geometry(self):
         # GH602