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 a263fdb113 [DOCS] Enhance GeoPandas classes documentation and
organization (#2119)
a263fdb113 is described below
commit a263fdb113a69b28d3a0f33e5bcc0db527522773
Author: Feng Zhang <[email protected]>
AuthorDate: Fri Jul 18 21:36:56 2025 -0700
[DOCS] Enhance GeoPandas classes documentation and organization (#2119)
* [DOCS] Enhance geospatial classes documentation and organization
The changes include:
- Comprehensive class-level documentation
- Implementation status tracking (46+ methods documented)
- Logical code organization with section separators
- Standardized error messages with helpful workarounds
- Clear development roadmap and priorities
* fix pre-commit lint
* clean up the implementation list
---
python/sedona/geopandas/geodataframe.py | 349 ++++++++++++++++++++++++++++-
python/sedona/geopandas/geoseries.py | 381 ++++++++++++++++++++++++++++++--
2 files changed, 703 insertions(+), 27 deletions(-)
diff --git a/python/sedona/geopandas/geodataframe.py
b/python/sedona/geopandas/geodataframe.py
index 0305153ec0..6e80270698 100644
--- a/python/sedona/geopandas/geodataframe.py
+++ b/python/sedona/geopandas/geodataframe.py
@@ -43,9 +43,265 @@ from shapely.geometry.base import BaseGeometry
register_extension_dtype(GeometryDtype)
+# ============================================================================
+# IMPLEMENTATION STATUS TRACKING
+# ============================================================================
+
+IMPLEMENTATION_STATUS = {
+ "IMPLEMENTED": [
+ "area",
+ "buffer",
+ "crs",
+ "geometry",
+ "active_geometry_name",
+ "sindex",
+ "rename_geometry",
+ "copy",
+ "sjoin",
+ "to_parquet",
+ ],
+ "NOT_IMPLEMENTED": [
+ "to_geopandas",
+ "_to_geopandas",
+ "geom_type",
+ "type",
+ "length",
+ "is_valid",
+ "is_valid_reason",
+ "is_empty",
+ "is_simple",
+ "is_ring",
+ "is_ccw",
+ "is_closed",
+ "has_z",
+ "boundary",
+ "centroid",
+ "convex_hull",
+ "envelope",
+ "exterior",
+ "interiors",
+ "unary_union",
+ "count_coordinates",
+ "count_geometries",
+ "count_interior_rings",
+ "get_precision",
+ "get_geometry",
+ "concave_hull",
+ "delaunay_triangles",
+ "voronoi_polygons",
+ "minimum_rotated_rectangle",
+ "extract_unique_points",
+ "offset_curve",
+ "remove_repeated_points",
+ "set_precision",
+ "representative_point",
+ "minimum_bounding_circle",
+ "minimum_bounding_radius",
+ "minimum_clearance",
+ "normalize",
+ "make_valid",
+ "reverse",
+ "segmentize",
+ "transform",
+ "force_2d",
+ "force_3d",
+ "line_merge",
+ "union_all",
+ "intersection_all",
+ "contains",
+ "contains_properly",
+ ],
+ "PARTIALLY_IMPLEMENTED": ["set_geometry"], # Only drop=True case is not
implemented
+}
+
+IMPLEMENTATION_PRIORITY = {
+ "HIGH": [
+ "to_geopandas",
+ "_to_geopandas",
+ "contains",
+ "contains_properly",
+ "convex_hull",
+ "count_coordinates",
+ "count_geometries",
+ "is_ring",
+ "is_closed",
+ "make_valid",
+ ],
+ "MEDIUM": [
+ "force_2d",
+ "force_3d",
+ "transform",
+ "segmentize",
+ "line_merge",
+ "union_all",
+ "intersection_all",
+ "reverse",
+ "normalize",
+ "get_geometry",
+ ],
+ "LOW": [
+ "delaunay_triangles",
+ "voronoi_polygons",
+ "minimum_bounding_circle",
+ "representative_point",
+ "extract_unique_points",
+ "offset_curve",
+ "minimum_rotated_rectangle",
+ "concave_hull",
+ ],
+}
+
+
+def _not_implemented_error(method_name: str, additional_info: str = "") -> str:
+ """
+ Generate a standardized NotImplementedError message for GeoDataFrame
methods.
+
+ Parameters
+ ----------
+ method_name : str
+ The name of the method that is not implemented.
+ additional_info : str, optional
+ Additional information about the method or workarounds.
+
+ Returns
+ -------
+ str
+ Formatted error message.
+ """
+ base_message = (
+ f"GeoDataFrame.{method_name}() is not implemented yet.\n"
+ f"This method will be added in a future release."
+ )
+
+ if additional_info:
+ base_message += f"\n\n{additional_info}"
+
+ workaround = (
+ "\n\nTemporary workaround - use GeoPandas:\n"
+ " gpd_df = sedona_gdf.to_geopandas()\n"
+ f" result = gpd_df.{method_name}(...)\n"
+ " # Note: This will collect all data to the driver."
+ )
+
+ return base_message + workaround
+
+
class GeoDataFrame(GeoFrame, pspd.DataFrame):
"""
- A class representing a GeoDataFrame, inheriting from GeoFrame and
pyspark.pandas.DataFrame.
+ A pandas-on-Spark DataFrame for geospatial data with geometry columns.
+
+ GeoDataFrame extends pyspark.pandas.DataFrame to provide geospatial
operations
+ using Apache Sedona's spatial functions. It maintains compatibility with
+ GeoPandas GeoDataFrame while operating on distributed datasets.
+
+ Parameters
+ ----------
+ data : dict, array-like, DataFrame, or GeoDataFrame
+ Data to initialize the GeoDataFrame. Can be a dictionary, array-like
structure,
+ pandas DataFrame, GeoPandas GeoDataFrame, or another GeoDataFrame.
+ geometry : str, array-like, or GeoSeries, optional
+ Column name, array of geometries, or GeoSeries to use as the active
geometry.
+ If None, will look for existing geometry columns.
+ crs : pyproj.CRS, optional
+ Coordinate Reference System for the geometries.
+ columns : Index or array-like, optional
+ Column labels to use for the resulting frame.
+ index : Index or array-like, optional
+ Index to use for the resulting frame.
+
+ Attributes
+ ----------
+ geometry : GeoSeries
+ The active geometry column.
+ crs : pyproj.CRS
+ The Coordinate Reference System (CRS) for the geometries.
+ active_geometry_name : str
+ Name of the active geometry column.
+ area : Series
+ Area of each geometry in CRS units.
+ sindex : SpatialIndex
+ Spatial index for the geometries.
+
+ Methods
+ -------
+ buffer(distance)
+ Buffer geometries by specified distance.
+ sjoin(right, how='inner', predicate='intersects')
+ Spatial join with another GeoDataFrame.
+ set_geometry(col, drop=False, inplace=False)
+ Set the active geometry column.
+ rename_geometry(col, inplace=False)
+ Rename the active geometry column.
+ to_parquet(path, **kwargs)
+ Save to GeoParquet format.
+ copy(deep=False)
+ Make a copy of the GeoDataFrame.
+
+ Examples
+ --------
+ >>> from shapely.geometry import Point, Polygon
+ >>> from sedona.geopandas import GeoDataFrame
+ >>> import pandas as pd
+ >>>
+ >>> # Create from dictionary with geometry
+ >>> data = {
+ ... 'name': ['A', 'B', 'C'],
+ ... 'geometry': [Point(0, 0), Point(1, 1), Point(2, 2)]
+ ... }
+ >>> gdf = GeoDataFrame(data, crs='EPSG:4326')
+ >>> gdf
+ name geometry
+ 0 A POINT (0 0)
+ 1 B POINT (1 1)
+ 2 C POINT (2 2)
+ >>>
+ >>> # Spatial operations
+ >>> buffered = gdf.buffer(0.1)
+ >>> buffered.area
+ 0 0.031416
+ 1 0.031416
+ 2 0.031416
+ dtype: float64
+ >>>
+ >>> # Spatial joins
+ >>> polygons = GeoDataFrame({
+ ... 'region': ['Region1', 'Region2'],
+ ... 'geometry': [
+ ... Polygon([(-1, -1), (1, -1), (1, 1), (-1, 1)]),
+ ... Polygon([(0.5, 0.5), (2.5, 0.5), (2.5, 2.5), (0.5, 2.5)])
+ ... ]
+ ... })
+ >>> result = gdf.sjoin(polygons, how='left', predicate='within')
+ >>> result['region']
+ 0 Region1
+ 1 Region2
+ 2 Region2
+ dtype: object
+
+ Notes
+ -----
+ This implementation differs from GeoPandas in several ways:
+ - Uses Spark for distributed processing
+ - Geometries are stored in WKB (Well-Known Binary) format internally
+ - Some methods may have different performance characteristics
+ - Not all GeoPandas methods are implemented yet (see IMPLEMENTATION_STATUS)
+
+ Performance Considerations:
+ - Operations are distributed across Spark cluster
+ - Avoid converting to GeoPandas (.to_geopandas()) on large datasets
+ - Use .sample() for testing with large datasets
+ - Spatial joins are optimized for distributed processing
+
+ Geometry Column Management:
+ - Supports multiple geometry columns
+ - One geometry column is designated as 'active' at a time
+ - Active geometry is used for spatial operations and plotting
+ - Use set_geometry() to change the active geometry column
+
+ See Also
+ --------
+ geopandas.GeoDataFrame : The GeoPandas equivalent
+ sedona.geopandas.GeoSeries : Series with geometry data
"""
def __getitem__(self, key: Any) -> Any:
@@ -120,6 +376,10 @@ class GeoDataFrame(GeoFrame, pspd.DataFrame):
_geometry_column_name = None
+ #
============================================================================
+ # CONSTRUCTION AND INITIALIZATION
+ #
============================================================================
+
def __init__(
self,
data=None,
@@ -236,6 +496,10 @@ class GeoDataFrame(GeoFrame, pspd.DataFrame):
if crs is not None and data.crs != crs:
raise ValueError(crs_mismatch_error)
+ #
============================================================================
+ # GEOMETRY COLUMN MANAGEMENT
+ #
============================================================================
+
def _get_geometry(self) -> sgpd.GeoSeries:
if self._geometry_column_name not in self:
if self._geometry_column_name is None:
@@ -432,7 +696,12 @@ class GeoDataFrame(GeoFrame, pspd.DataFrame):
stacklevel=2,
)
if drop:
- raise NotImplementedError("Not implemented.")
+ raise NotImplementedError(
+ _not_implemented_error(
+ "set_geometry",
+ "Setting geometry with drop=True parameter is not
supported.",
+ )
+ )
else:
# if not dropping, set the active geometry name to the given
col name
geo_column_name = col
@@ -516,6 +785,10 @@ class GeoDataFrame(GeoFrame, pspd.DataFrame):
sdf = sdf.set_geometry(col)
return sdf
+ #
============================================================================
+ # PROPERTIES AND ATTRIBUTES
+ #
============================================================================
+
@property
def active_geometry_name(self) -> Any:
"""Return the name of the active geometry column
@@ -591,11 +864,21 @@ class GeoDataFrame(GeoFrame, pspd.DataFrame):
def to_geopandas(self) -> gpd.GeoDataFrame | pd.Series:
# Implementation of the abstract method
- raise NotImplementedError("This method is not implemented yet.")
+ raise NotImplementedError(
+ _not_implemented_error(
+ "to_geopandas",
+ "Converts to GeoPandas GeoDataFrame by collecting all data to
driver.",
+ )
+ )
def _to_geopandas(self) -> gpd.GeoDataFrame | pd.Series:
# Implementation of the abstract method
- raise NotImplementedError("This method is not implemented yet.")
+ raise NotImplementedError(
+ _not_implemented_error(
+ "_to_geopandas",
+ "Internal method for GeoPandas conversion without logging
warnings.",
+ )
+ )
@property
def sindex(self) -> SpatialIndex | None:
@@ -692,22 +975,37 @@ class GeoDataFrame(GeoFrame, pspd.DataFrame):
@property
def geom_type(self):
# Implementation of the abstract method
- raise NotImplementedError("This method is not implemented yet.")
+ raise NotImplementedError(
+ _not_implemented_error(
+ "geom_type",
+ "Returns the geometry type of each geometry (Point,
LineString, Polygon, etc.).",
+ )
+ )
@property
def type(self):
# Implementation of the abstract method
- raise NotImplementedError("This method is not implemented yet.")
+ raise NotImplementedError(
+ _not_implemented_error("type", "Returns numeric geometry type
codes.")
+ )
@property
def length(self):
# Implementation of the abstract method
- raise NotImplementedError("This method is not implemented yet.")
+ raise NotImplementedError(
+ _not_implemented_error(
+ "length", "Returns the length/perimeter of each geometry."
+ )
+ )
@property
def is_valid(self):
# Implementation of the abstract method
- raise NotImplementedError("This method is not implemented yet.")
+ raise NotImplementedError(
+ _not_implemented_error(
+ "is_valid", "Tests if geometries are valid according to OGC
standards."
+ )
+ )
def is_valid_reason(self):
# Implementation of the abstract method
@@ -720,11 +1018,21 @@ class GeoDataFrame(GeoFrame, pspd.DataFrame):
def count_coordinates(self):
# Implementation of the abstract method
- raise NotImplementedError("This method is not implemented yet.")
+ raise NotImplementedError(
+ _not_implemented_error(
+ "count_coordinates",
+ "Counts the number of coordinate tuples in each geometry.",
+ )
+ )
def count_geometries(self):
# Implementation of the abstract method
- raise NotImplementedError("This method is not implemented yet.")
+ raise NotImplementedError(
+ _not_implemented_error(
+ "count_geometries",
+ "Counts the number of geometries in each multi-geometry or
collection.",
+ )
+ )
def count_interior_rings(self):
# Implementation of the abstract method
@@ -888,11 +1196,24 @@ class GeoDataFrame(GeoFrame, pspd.DataFrame):
def contains(self, other, align=None):
# Implementation of the abstract method
- raise NotImplementedError("This method is not implemented yet.")
+ raise NotImplementedError(
+ _not_implemented_error(
+ "contains", "Tests if geometries contain other geometries."
+ )
+ )
def contains_properly(self, other, align=None):
# Implementation of the abstract method
- raise NotImplementedError("This method is not implemented yet.")
+ raise NotImplementedError(
+ _not_implemented_error(
+ "contains_properly",
+ "Tests if geometries properly contain other geometries (no
boundary contact).",
+ )
+ )
+
+ #
============================================================================
+ # SPATIAL OPERATIONS
+ #
============================================================================
def buffer(
self,
@@ -1013,6 +1334,10 @@ class GeoDataFrame(GeoFrame, pspd.DataFrame):
**kwargs,
)
+ #
============================================================================
+ # I/O OPERATIONS
+ #
============================================================================
+
def to_parquet(self, path, **kwargs):
"""
Write the GeoSeries to a GeoParquet file.
diff --git a/python/sedona/geopandas/geoseries.py
b/python/sedona/geopandas/geoseries.py
index 9a42285a23..0075b82c0e 100644
--- a/python/sedona/geopandas/geoseries.py
+++ b/python/sedona/geopandas/geoseries.py
@@ -24,7 +24,6 @@ import pandas as pd
import pyspark.pandas as pspd
import pyspark
from pyspark.pandas import Series as PandasOnSparkSeries
-from pyspark.pandas._typing import Dtype
from pyspark.pandas.frame import DataFrame as PandasOnSparkDataFrame
from pyspark.pandas.internal import InternalFrame
from pyspark.pandas.series import first_series
@@ -45,9 +44,271 @@ from pyspark.pandas.internal import (
)
+# ============================================================================
+# IMPLEMENTATION STATUS TRACKING
+# ============================================================================
+
+IMPLEMENTATION_STATUS = {
+ "IMPLEMENTED": [
+ "area",
+ "buffer",
+ "bounds",
+ "centroid",
+ "contains",
+ "crs",
+ "distance",
+ "envelope",
+ "geometry",
+ "intersection",
+ "intersects",
+ "is_empty",
+ "is_simple",
+ "is_valid",
+ "is_valid_reason",
+ "length",
+ "make_valid",
+ "set_crs",
+ "to_crs",
+ "to_geopandas",
+ "to_wkb",
+ "to_wkt",
+ "x",
+ "y",
+ "z",
+ "has_z",
+ "get_geometry",
+ "boundary",
+ "total_bounds",
+ "estimate_utm_crs",
+ "isna",
+ "isnull",
+ "notna",
+ "notnull",
+ "from_xy",
+ "copy",
+ "geom_type",
+ "sindex",
+ ],
+ "NOT_IMPLEMENTED": [
+ "clip",
+ "contains_properly",
+ "convex_hull",
+ "count_coordinates",
+ "count_geometries",
+ "count_interior_rings",
+ "explode",
+ "force_2d",
+ "force_3d",
+ "from_file",
+ "from_shapely",
+ "from_arrow",
+ "line_merge",
+ "reverse",
+ "segmentize",
+ "to_json",
+ "to_arrow",
+ "to_file",
+ "transform",
+ "unary_union",
+ "union_all",
+ "intersection_all",
+ "type",
+ "is_ring",
+ "is_ccw",
+ "is_closed",
+ "get_precision",
+ "concave_hull",
+ "delaunay_triangles",
+ "voronoi_polygons",
+ "minimum_rotated_rectangle",
+ "exterior",
+ "extract_unique_points",
+ "offset_curve",
+ "interiors",
+ "remove_repeated_points",
+ "set_precision",
+ "representative_point",
+ "minimum_bounding_circle",
+ "minimum_bounding_radius",
+ "minimum_clearance",
+ "normalize",
+ "m",
+ ],
+ "PARTIALLY_IMPLEMENTED": [
+ "fillna", # Limited parameter support (no 'limit' parameter)
+ "from_wkb",
+ "from_wkt", # Limited error handling options (only 'raise' supported)
+ ],
+}
+
+IMPLEMENTATION_PRIORITY = {
+ "HIGH": [
+ "contains",
+ "contains_properly",
+ "convex_hull",
+ "explode",
+ "clip",
+ "from_shapely",
+ "count_coordinates",
+ "count_geometries",
+ "is_ring",
+ "is_closed",
+ "reverse",
+ ],
+ "MEDIUM": [
+ "force_2d",
+ "force_3d",
+ "transform",
+ "segmentize",
+ "line_merge",
+ "unary_union",
+ "union_all",
+ "to_json",
+ "from_file",
+ "count_interior_rings",
+ ],
+ "LOW": [
+ "delaunay_triangles",
+ "voronoi_polygons",
+ "minimum_bounding_circle",
+ "representative_point",
+ "extract_unique_points",
+ "from_arrow",
+ "to_arrow",
+ ],
+}
+
+
+def _not_implemented_error(method_name: str, additional_info: str = "") -> str:
+ """
+ Generate a standardized NotImplementedError message.
+
+ Parameters
+ ----------
+ method_name : str
+ The name of the method that is not implemented.
+ additional_info : str, optional
+ Additional information about the method or workarounds.
+
+ Returns
+ -------
+ str
+ Formatted error message.
+ """
+ base_message = (
+ f"GeoSeries.{method_name}() is not implemented yet.\n"
+ f"This method will be added in a future release."
+ )
+
+ if additional_info:
+ base_message += f"\n\n{additional_info}"
+
+ workaround = (
+ "\n\nTemporary workaround - use GeoPandas:\n"
+ " gpd_series = sedona_series.to_geopandas()\n"
+ f" result = gpd_series.{method_name}(...)\n"
+ " # Note: This will collect all data to the driver."
+ )
+
+ return base_message + workaround
+
+
class GeoSeries(GeoFrame, pspd.Series):
"""
- A class representing a GeoSeries, inheriting from GeoFrame and
pyspark.pandas.DataFrame.
+ A pandas-on-Spark Series for geometric/spatial operations.
+
+ GeoSeries extends pyspark.pandas.Series to provide spatial operations
+ using Apache Sedona's spatial functions. It maintains compatibility
+ with GeoPandas GeoSeries while operating on distributed datasets.
+
+ Parameters
+ ----------
+ data : array-like, Iterable, dict, or scalar value
+ Contains the data for the GeoSeries. Can be geometries, WKB bytes,
+ or other GeoSeries/GeoDataFrame objects.
+ index : array-like or Index (1d), optional
+ Values must be hashable and have the same length as `data`.
+ crs : pyproj.CRS, optional
+ Coordinate Reference System for the geometries.
+ dtype : dtype, optional
+ Data type for the GeoSeries.
+ name : str, optional
+ Name of the GeoSeries.
+ copy : bool, default False
+ Whether to copy the input data.
+
+ Attributes
+ ----------
+ crs : pyproj.CRS
+ The Coordinate Reference System (CRS) for the geometries.
+ area : Series
+ Area of each geometry in CRS units.
+ length : Series
+ Length/perimeter of each geometry in CRS units.
+ bounds : DataFrame
+ Bounding box coordinates for each geometry.
+ geometry : GeoSeries
+ The geometry column (returns self).
+ sindex : SpatialIndex
+ Spatial index for the geometries.
+
+ Methods
+ -------
+ buffer(distance)
+ Buffer geometries by specified distance.
+ intersection(other)
+ Compute intersection with other geometries.
+ intersects(other)
+ Test if geometries intersect with other geometries.
+ to_geopandas()
+ Convert to GeoPandas GeoSeries.
+ to_crs(crs)
+ Transform geometries to a different CRS.
+ set_crs(crs)
+ Set the CRS without transforming geometries.
+
+ Examples
+ --------
+ >>> from shapely.geometry import Point, Polygon
+ >>> from sedona.geopandas import GeoSeries
+ >>>
+ >>> # Create from geometries
+ >>> s = GeoSeries([Point(0, 0), Point(1, 1)], crs='EPSG:4326')
+ >>> s
+ 0 POINT (0 0)
+ 1 POINT (1 1)
+ dtype: geometry
+ >>>
+ >>> # Spatial operations
+ >>> s.buffer(0.1).area
+ 0 0.031416
+ 1 0.031416
+ dtype: float64
+ >>>
+ >>> # CRS operations
+ >>> s_utm = s.to_crs('EPSG:32633')
+ >>> s_utm.crs
+ <Projected CRS: EPSG:32633>
+ Name: WGS 84 / UTM zone 33N
+ ...
+
+ Notes
+ -----
+ This implementation differs from GeoPandas in several ways:
+ - Uses Spark for distributed processing
+ - Geometries are stored in WKB (Well-Known Binary) format internally
+ - Some methods may have different performance characteristics
+ - Not all GeoPandas methods are implemented yet (see IMPLEMENTATION_STATUS)
+
+ Performance Considerations:
+ - Operations are distributed across Spark cluster
+ - Avoid calling .to_geopandas() on large datasets
+ - Use .sample() for testing with large datasets
+
+ See Also
+ --------
+ geopandas.GeoSeries : The GeoPandas equivalent
+ sedona.geopandas.GeoDataFrame : DataFrame with geometry column
"""
def __getitem__(self, key: Any) -> Any:
@@ -217,6 +478,10 @@ class GeoSeries(GeoFrame, pspd.Series):
if crs:
self.set_crs(crs, inplace=True)
+ #
============================================================================
+ # COORDINATE REFERENCE SYSTEM (CRS) OPERATIONS
+ #
============================================================================
+
@property
def crs(self) -> Union["CRS", None]:
"""The Coordinate Reference System (CRS) as a ``pyproj.CRS`` object.
@@ -397,6 +662,10 @@ class GeoSeries(GeoFrame, pspd.Series):
return result
+ #
============================================================================
+ # INTERNAL HELPER METHODS
+ #
============================================================================
+
def _process_geometry_column(
self,
operation: str,
@@ -538,6 +807,10 @@ class GeoSeries(GeoFrame, pspd.Series):
return GeoSeries(ps_series) if returns_geom else ps_series
+ #
============================================================================
+ # CONVERSION AND SERIALIZATION METHODS
+ #
============================================================================
+
def to_geopandas(self) -> gpd.GeoSeries:
"""
Convert the GeoSeries to a geopandas GeoSeries.
@@ -573,6 +846,10 @@ class GeoSeries(GeoFrame, pspd.Series):
def to_spark_pandas(self) -> pspd.Series:
return pspd.Series(self._psdf._to_internal_pandas())
+ #
============================================================================
+ # PROPERTIES AND ATTRIBUTES
+ #
============================================================================
+
@property
def geometry(self) -> "GeoSeries":
return self
@@ -700,7 +977,9 @@ class GeoSeries(GeoFrame, pspd.Series):
@property
def type(self):
# Implementation of the abstract method
- raise NotImplementedError("This method is not implemented yet.")
+ raise NotImplementedError(
+ _not_implemented_error("type", "Returns numeric geometry type
codes.")
+ )
@property
def length(self) -> pspd.Series:
@@ -866,15 +1145,30 @@ class GeoSeries(GeoFrame, pspd.Series):
def count_coordinates(self):
# Implementation of the abstract method
- raise NotImplementedError("This method is not implemented yet.")
+ raise NotImplementedError(
+ _not_implemented_error(
+ "count_coordinates",
+ "Counts the number of coordinate tuples in each geometry.",
+ )
+ )
def count_geometries(self):
# Implementation of the abstract method
- raise NotImplementedError("This method is not implemented yet.")
+ raise NotImplementedError(
+ _not_implemented_error(
+ "count_geometries",
+ "Counts the number of geometries in each multi-geometry or
collection.",
+ )
+ )
def count_interior_rings(self):
# Implementation of the abstract method
- raise NotImplementedError("This method is not implemented yet.")
+ raise NotImplementedError(
+ _not_implemented_error(
+ "count_interior_rings",
+ "Counts the number of interior rings (holes) in each polygon.",
+ )
+ )
@property
def is_simple(self) -> pspd.Series:
@@ -911,17 +1205,31 @@ class GeoSeries(GeoFrame, pspd.Series):
@property
def is_ring(self):
# Implementation of the abstract method
- raise NotImplementedError("This method is not implemented yet.")
+ raise NotImplementedError(
+ _not_implemented_error(
+ "is_ring", "Tests if LineString geometries are closed rings."
+ )
+ )
@property
def is_ccw(self):
# Implementation of the abstract method
- raise NotImplementedError("This method is not implemented yet.")
+ raise NotImplementedError(
+ _not_implemented_error(
+ "is_ccw",
+ "Tests if LinearRing geometries are oriented
counter-clockwise.",
+ )
+ )
@property
def is_closed(self):
# Implementation of the abstract method
- raise NotImplementedError("This method is not implemented yet.")
+ raise NotImplementedError(
+ _not_implemented_error(
+ "is_closed",
+ "Tests if LineString geometries are closed (start equals end
point).",
+ )
+ )
@property
def has_z(self) -> pspd.Series:
@@ -1144,7 +1452,11 @@ class GeoSeries(GeoFrame, pspd.Series):
@property
def convex_hull(self):
# Implementation of the abstract method
- raise NotImplementedError("This method is not implemented yet.")
+ raise NotImplementedError(
+ _not_implemented_error(
+ "convex_hull", "Computes the convex hull of each geometry."
+ )
+ )
def delaunay_triangles(self, tolerance=0.0, only_edges=False):
# Implementation of the abstract method
@@ -1339,6 +1651,10 @@ class GeoSeries(GeoFrame, pspd.Series):
# Implementation of the abstract method
raise NotImplementedError("This method is not implemented yet.")
+ #
============================================================================
+ # GEOMETRIC OPERATIONS
+ #
============================================================================
+
@property
def unary_union(self):
# Implementation of the abstract method
@@ -2469,6 +2785,10 @@ class GeoSeries(GeoFrame, pspd.Series):
# Implementation of the abstract method
raise NotImplementedError("This method is not implemented yet.")
+ #
============================================================================
+ # SPATIAL PREDICATES
+ #
============================================================================
+
def contains(self, other, align=None) -> pspd.Series:
"""Returns a ``Series`` of ``dtype('bool')`` with value ``True`` for
each aligned geometry that contains `other`.
@@ -2590,7 +2910,12 @@ class GeoSeries(GeoFrame, pspd.Series):
def contains_properly(self, other, align=None):
# Implementation of the abstract method
- raise NotImplementedError("This method is not implemented yet.")
+ raise NotImplementedError(
+ _not_implemented_error(
+ "contains_properly",
+ "Tests if geometries properly contain other geometries (no
boundary contact).",
+ )
+ )
def buffer(
self,
@@ -2797,11 +3122,20 @@ class GeoSeries(GeoFrame, pspd.Series):
def m(self) -> pspd.Series:
raise NotImplementedError("GeoSeries.m() is not implemented yet.")
+ #
============================================================================
+ # CONSTRUCTION METHODS
+ #
============================================================================
+
@classmethod
def from_file(
cls, filename: Union[os.PathLike, typing.IO], **kwargs
) -> "GeoSeries":
- raise NotImplementedError("GeoSeries.from_file() is not implemented
yet.")
+ raise NotImplementedError(
+ _not_implemented_error(
+ "from_file",
+ "Creates GeoSeries from geometry files (shapefile, GeoJSON,
etc.).",
+ )
+ )
@classmethod
def from_wkb(
@@ -3052,7 +3386,11 @@ class GeoSeries(GeoFrame, pspd.Series):
def from_shapely(
cls, data, index=None, crs: Union[Any, None] = None, **kwargs
) -> "GeoSeries":
- raise NotImplementedError("GeoSeries.from_shapely() is not implemented
yet.")
+ raise NotImplementedError(
+ _not_implemented_error(
+ "from_shapely", "Creates GeoSeries from Shapely geometry
objects."
+ )
+ )
@classmethod
def from_arrow(cls, arr, **kwargs) -> "GeoSeries":
@@ -3109,6 +3447,10 @@ class GeoSeries(GeoFrame, pspd.Series):
):
raise NotImplementedError("GeoSeries.to_file() is not implemented
yet.")
+ #
============================================================================
+ # DATA ACCESS AND MANIPULATION
+ #
============================================================================
+
def isna(self) -> pspd.Series:
"""
Detect missing values.
@@ -3330,7 +3672,12 @@ class GeoSeries(GeoFrame, pspd.Series):
return result
def explode(self, ignore_index=False, index_parts=False) -> "GeoSeries":
- raise NotImplementedError("GeoSeries.explode() is not implemented
yet.")
+ raise NotImplementedError(
+ _not_implemented_error(
+ "explode",
+ "Explodes multi-part geometries into separate single-part
geometries.",
+ )
+ )
def to_crs(
self, crs: Union[Any, None] = None, epsg: Union[int, None] = None
@@ -3756,7 +4103,11 @@ class GeoSeries(GeoFrame, pspd.Series):
raise NotImplementedError("GeoSeries.to_arrow() is not implemented
yet.")
def clip(self, mask, keep_geom_type: bool = False, sort=False) ->
"GeoSeries":
- raise NotImplementedError("GeoSeries.clip() is not implemented yet.")
+ raise NotImplementedError(
+ _not_implemented_error(
+ "clip", "Clips geometries to the bounds of a mask geometry."
+ )
+ )
#
-----------------------------------------------------------------------------
# # Utils