Repository: geopandas/geopandas

Issue:
ENH: add attribute checking for an active geometry column
It may be useful to have an attribute on a `GeoDataFrame` that tells a user if an active geometry column is set or not. In a use case in OSMnx (https://github.com/gboeing/osmnx/pull/1012), they pass dict-based data to the constructor but they do not know if the dict has a `geometry` or not. So they're then checking for a presence of a `"geometry"` column, which works but feels like we could do more to support such cases. If you are dealing with a more generic input, you may have an active geometry column called differently and checking for that is a bit unwelcoming at the moment.

I would propose to add an attribute like `GeoDataFrame.has_geometry` or `.has_active_geometry` that would check the contents of `_geometry_column_name` and return a boolean depending if it is `None` or a string. You can then safely retrieve `GeoDataFrame.geometry` or set a new column, depending on what you need.


Discussion:
This sounds very helpful.

Resolving patch:
diff --git a/geopandas/geodataframe.py b/geopandas/geodataframe.py
--- a/geopandas/geodataframe.py
+++ b/geopandas/geodataframe.py
@@ -399,6 +399,26 @@ def rename_geometry(self, col, inplace=False):
             self.rename(columns={geometry_col: col}, inplace=inplace)
             self.set_geometry(col, inplace=inplace)
 
+    @property
+    def active_geometry_name(self):
+        """Return the name of the active geometry column
+
+        Returns a string name if a GeoDataFrame has an active geometry column set.
+        Otherwise returns None. You can also access the active geometry column using the
+        ``.geometry`` property. You can set a GeoSeries to be an active geometry
+        using the :meth:`~GeoDataFrame.set_geometry` method.
+
+        Returns
+        -------
+        str
+            name of an active geometry column or None
+
+        See also
+        --------
+        GeoDataFrame.set_geometry : set the active geometry
+        """
+        return self._geometry_column_name
+
     @property
     def crs(self):
         """


Test patch:
diff --git a/geopandas/tests/test_geodataframe.py b/geopandas/tests/test_geodataframe.py
--- a/geopandas/tests/test_geodataframe.py
+++ b/geopandas/tests/test_geodataframe.py
@@ -368,6 +368,21 @@ def test_get_geometry_geometry_inactive(self):
         with pytest.raises(AttributeError, match=msg_geo_col_missing):
             df.geometry
 
+    def test_active_geometry_name(self):
+        # default single active called "geometry"
+        assert self.df.active_geometry_name == "geometry"
+
+        # one GeoSeries, not active
+        no_active = GeoDataFrame({"foo": self.df.BoroName, "bar": self.df.geometry})
+        assert no_active.active_geometry_name is None
+        assert no_active.set_geometry("bar").active_geometry_name == "bar"
+
+        # multiple, none active
+        multiple = GeoDataFrame({"foo": self.df.geometry, "bar": self.df.geometry})
+        assert multiple.active_geometry_name is None
+        assert multiple.set_geometry("foo").active_geometry_name == "foo"
+        assert multiple.set_geometry("bar").active_geometry_name == "bar"
+
     def test_align(self):
         df = self.df2