This is an automated email from the ASF dual-hosted git repository.
jiayu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sedona.git
The following commit(s) were added to refs/heads/master by this push:
new 812923e675 [GH-2031] Geopandas.GeoSeries: Implement isna, notna and
aliases (isnull, notnull) (#2032)
812923e675 is described below
commit 812923e675bb7e6000fe335bef3d18427802bbcc
Author: Peter Nguyen <[email protected]>
AuthorDate: Sun Jul 6 11:14:12 2025 -0700
[GH-2031] Geopandas.GeoSeries: Implement isna, notna and aliases (isnull,
notnull) (#2032)
* Refactor process_geometry_column to create a more flexible
query_geometry_column()
* Implement length()
* Implement isna and isnull
* Implement notna
* Fix doc strings to use sedona instead of geoseries
* Update python/sedona/geopandas/geoseries.py
Co-authored-by: Copilot <[email protected]>
* Update python/sedona/geopandas/geoseries.py
---------
Co-authored-by: Jia Yu <[email protected]>
Co-authored-by: Copilot <[email protected]>
---
python/sedona/geopandas/geoseries.py | 85 +++++++++++++++++++++-
python/tests/geopandas/test_geoseries.py | 23 +++---
.../tests/geopandas/test_match_geopandas_series.py | 28 ++++---
3 files changed, 114 insertions(+), 22 deletions(-)
diff --git a/python/sedona/geopandas/geoseries.py
b/python/sedona/geopandas/geoseries.py
index 146edaca8e..de5927c618 100644
--- a/python/sedona/geopandas/geoseries.py
+++ b/python/sedona/geopandas/geoseries.py
@@ -1826,13 +1826,92 @@ class GeoSeries(GeoFrame, pspd.Series):
raise NotImplementedError("GeoSeries.to_file() is not implemented
yet.")
def isna(self) -> pspd.Series:
- raise NotImplementedError("GeoSeries.isna() is not implemented yet.")
+ """
+ Detect missing values.
+
+ Returns
+ -------
+ A boolean Series of the same size as the GeoSeries,
+ True where a value is NA.
+
+ Examples
+ --------
+
+ >>> from sedona.geopandas import GeoSeries
+ >>> from shapely.geometry import Polygon
+ >>> s = GeoSeries(
+ ... [Polygon([(0, 0), (1, 1), (0, 1)]), None, Polygon([])]
+ ... )
+ >>> s
+ 0 POLYGON ((0 0, 1 1, 0 1, 0 0))
+ 1 None
+ 2 POLYGON EMPTY
+ dtype: geometry
+
+ >>> s.isna()
+ 0 False
+ 1 True
+ 2 False
+ dtype: bool
+
+ See Also
+ --------
+ GeoSeries.notna : inverse of isna
+ GeoSeries.is_empty : detect empty geometries
+ """
+ col = self.get_first_geometry_column()
+ select = f"`{col}` IS NULL"
+ return (
+ self._query_geometry_column(select, col, rename="isna")
+ .to_spark_pandas()
+ .astype("bool")
+ )
def isnull(self) -> pspd.Series:
- raise NotImplementedError("GeoSeries.isnull() is not implemented yet.")
+ """Alias for `isna` method. See `isna` for more detail."""
+ return self.isna()
def notna(self) -> pspd.Series:
- raise NotImplementedError("GeoSeries.notna() is not implemented yet.")
+ """
+ Detect non-missing values.
+
+ Returns
+ -------
+ A boolean pandas Series of the same size as the GeoSeries,
+ False where a value is NA.
+
+ Examples
+ --------
+
+ >>> from sedona.geopandas import GeoSeries
+ >>> from shapely.geometry import Polygon
+ >>> s = GeoSeries(
+ ... [Polygon([(0, 0), (1, 1), (0, 1)]), None, Polygon([])]
+ ... )
+ >>> s
+ 0 POLYGON ((0 0, 1 1, 0 1, 0 0))
+ 1 None
+ 2 POLYGON EMPTY
+ dtype: geometry
+
+ >>> s.notna()
+ 0 True
+ 1 False
+ 2 True
+ dtype: bool
+
+ See Also
+ --------
+ GeoSeries.isna : inverse of notna
+ GeoSeries.is_empty : detect empty geometries
+ """
+ col = self.get_first_geometry_column()
+ select = f"`{col}` IS NOT NULL"
+ return (
+ self._query_geometry_column(select, col, rename="notna")
+ .to_spark_pandas()
+ .astype("bool")
+ )
def notnull(self) -> pspd.Series:
"""Alias for `notna` method. See `notna` for more detail."""
diff --git a/python/tests/geopandas/test_geoseries.py
b/python/tests/geopandas/test_geoseries.py
index 9d73082dfd..e9caad3904 100644
--- a/python/tests/geopandas/test_geoseries.py
+++ b/python/tests/geopandas/test_geoseries.py
@@ -34,6 +34,7 @@ from shapely.geometry import (
LinearRing,
)
from pandas.testing import assert_series_equal
+import pytest
class TestGeoSeries(TestBase):
@@ -173,17 +174,19 @@ class TestGeoSeries(TestBase):
def test_to_file(self):
pass
- def test_isna(self):
- pass
-
- def test_isnull(self):
- pass
-
- def test_notna(self):
- pass
+ @pytest.mark.parametrize("fun", ["isna", "isnull"])
+ def test_isna(self, fun):
+ geoseries = GeoSeries([Polygon([(0, 0), (1, 1), (0, 1)]), None,
Polygon([])])
+ result = getattr(geoseries, fun)()
+ expected = pd.Series([False, True, False])
+ assert_series_equal(result.to_pandas(), expected)
- def test_notnull(self):
- pass
+ @pytest.mark.parametrize("fun", ["notna", "notnull"])
+ def test_notna(self, fun):
+ geoseries = GeoSeries([Polygon([(0, 0), (1, 1), (0, 1)]), None,
Polygon([])])
+ result = getattr(geoseries, fun)()
+ expected = pd.Series([True, False, True])
+ assert_series_equal(result.to_pandas(), expected)
def test_fillna(self):
pass
diff --git a/python/tests/geopandas/test_match_geopandas_series.py
b/python/tests/geopandas/test_match_geopandas_series.py
index 3c3695aed7..3c159a7df9 100644
--- a/python/tests/geopandas/test_match_geopandas_series.py
+++ b/python/tests/geopandas/test_match_geopandas_series.py
@@ -284,17 +284,27 @@ class TestMatchGeopandasSeries(TestBase):
def test_to_file(self):
pass
- def test_isna(self):
- pass
-
- def test_isnull(self):
- pass
+ @pytest.mark.parametrize("fun", ["isna", "isnull"])
+ def test_isna(self, fun):
+ for _, geom in self.geoms:
+ sgpd_result = getattr(GeoSeries(geom), fun)()
+ assert isinstance(sgpd_result, ps.Series)
+ gpd_result = getattr(gpd.GeoSeries(geom), fun)()
+ self.check_pd_series_equal(sgpd_result, gpd_result)
- def test_notna(self):
- pass
+ @pytest.mark.parametrize("fun", ["notna", "notnull"])
+ def test_notna(self, fun):
+ for _, geom in self.geoms:
+ sgpd_result = getattr(GeoSeries(geom), fun)()
+ assert isinstance(sgpd_result, ps.Series)
+ gpd_result = getattr(gpd.GeoSeries(geom), fun)()
+ self.check_pd_series_equal(sgpd_result, gpd_result)
- def test_notnull(self):
- pass
+ data = [Point(0, 0), None]
+ series = GeoSeries(data)
+ sgpd_result = series.notna()
+ gpd_result = gpd.GeoSeries(data).notna()
+ self.check_pd_series_equal(sgpd_result, gpd_result)
def test_fillna(self):
pass