@@ -282,8 +282,9 @@ def set_crs(
282282
283283 Examples
284284 --------
285+ >>> from sedona.geopandas import GeoSeries
285286 >>> from shapely.geometry import Point
286- >>> s = geopandas. GeoSeries([Point(1, 1), Point(2, 2), Point(3, 3)])
287+ >>> s = GeoSeries([Point(1, 1), Point(2, 2), Point(3, 3)])
287288 >>> s
288289 0 POINT (1 1)
289290 1 POINT (2 2)
@@ -479,10 +480,10 @@ def _to_geopandas(self) -> gpd.GeoSeries:
479480 pd_series = self ._to_internal_pandas ()
480481 try :
481482 return gpd .GeoSeries (
482- pd_series .map (lambda wkb : shapely .wkb .loads (bytes (wkb )))
483+ pd_series .map (lambda wkb : shapely .wkb .loads (bytes (wkb ))), crs = self . crs
483484 )
484- except Exception as e :
485- return gpd .GeoSeries (pd_series )
485+ except TypeError :
486+ return gpd .GeoSeries (pd_series , crs = self . crs )
486487
487488 def to_spark_pandas (self ) -> pspd .Series :
488489 return pspd .Series (self ._psdf ._to_internal_pandas ())
@@ -512,7 +513,6 @@ def copy(self, deep=False):
512513
513514 Examples:
514515 >>> from shapely.geometry import Point
515- >>> import geopandas as gpd
516516 >>> from sedona.geopandas import GeoSeries
517517
518518 >>> gs = GeoSeries([Point(1, 1), Point(2, 2)])
@@ -542,7 +542,6 @@ def area(self) -> pspd.Series:
542542 Examples
543543 --------
544544 >>> from shapely.geometry import Polygon
545- >>> import geopandas as gpd
546545 >>> from sedona.geopandas import GeoSeries
547546
548547 >>> gs = GeoSeries([Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]), Polygon([(0, 0), (2, 0), (2, 2), (0, 2)])])
@@ -615,7 +614,6 @@ def length(self) -> pspd.Series:
615614 Examples
616615 --------
617616 >>> from shapely.geometry import Polygon
618- >>> import geopandas as gpd
619617 >>> from sedona.geopandas import GeoSeries
620618
621619 >>> gs = GeoSeries([Point(0, 0), LineString([(0, 0), (1, 1)]), Polygon([(0, 0), (1, 0), (1, 1)]), GeometryCollection([Point(0, 0), LineString([(0, 0), (1, 1)]), Polygon([(0, 0), (1, 0), (1, 1)])])])
@@ -649,8 +647,9 @@ def is_valid(self) -> pspd.Series:
649647 An example with one invalid polygon (a bowtie geometry crossing itself)
650648 and one missing geometry:
651649
650+ >>> from sedona.geopandas import GeoSeries
652651 >>> from shapely.geometry import Polygon
653- >>> s = geopandas. GeoSeries(
652+ >>> s = GeoSeries(
654653 ... [
655654 ... Polygon([(0, 0), (1, 1), (0, 1)]),
656655 ... Polygon([(0,0), (1, 1), (1, 0), (0, 1)]), # bowtie geometry
@@ -697,16 +696,15 @@ def is_empty(self) -> pspd.Series:
697696 An example of a GeoDataFrame with one empty point, one point and one missing
698697 value:
699698
699+ >>> from sedona.geopandas import GeoSeries
700700 >>> from shapely.geometry import Point
701- >>> d = {'geometry': [Point(), Point(2, 1), None]}
702- >>> gdf = geopandas.GeoDataFrame(d, crs="EPSG:4326")
703- >>> gdf
704- geometry
701+ >>> geoseries = GeoSeries([Point(), Point(2, 1), None], crs="EPSG:4326")
702+ >>> geoseries
705703 0 POINT EMPTY
706704 1 POINT (2 1)
707705 2 None
708706
709- >>> gdf .is_empty
707+ >>> geoseries .is_empty
710708 0 True
711709 1 False
712710 2 False
@@ -743,8 +741,9 @@ def is_simple(self) -> pspd.Series:
743741
744742 Examples
745743 --------
744+ >>> from sedona.geopandas import GeoSeries
746745 >>> from shapely.geometry import LineString
747- >>> s = geopandas. GeoSeries(
746+ >>> s = GeoSeries(
748747 ... [
749748 ... LineString([(0, 0), (1, 1), (1, -1), (0, 1)]),
750749 ... LineString([(0, 0), (1, 1), (1, -1)]),
@@ -793,8 +792,9 @@ def has_z(self) -> pspd.Series:
793792
794793 Examples
795794 --------
795+ >>> from sedona.geopandas import GeoSeries
796796 >>> from shapely.geometry import Point
797- >>> s = geopandas. GeoSeries(
797+ >>> s = GeoSeries(
798798 ... [
799799 ... Point(0, 1),
800800 ... Point(0, 1, 2),
@@ -967,16 +967,17 @@ def intersects(
967967
968968 Examples
969969 --------
970+ >>> from sedona.geopandas import GeoSeries
970971 >>> from shapely.geometry import Polygon, LineString, Point
971- >>> s = geopandas. GeoSeries(
972+ >>> s = GeoSeries(
972973 ... [
973974 ... Polygon([(0, 0), (2, 2), (0, 2)]),
974975 ... LineString([(0, 0), (2, 2)]),
975976 ... LineString([(2, 0), (0, 2)]),
976977 ... Point(0, 1),
977978 ... ],
978979 ... )
979- >>> s2 = geopandas. GeoSeries(
980+ >>> s2 = GeoSeries(
980981 ... [
981982 ... LineString([(1, 0), (1, 3)]),
982983 ... LineString([(2, 0), (0, 2)]),
@@ -1051,8 +1052,9 @@ def intersection(
10511052
10521053 Examples
10531054 --------
1055+ >>> from sedona.geopandas import GeoSeries
10541056 >>> from shapely.geometry import Polygon, LineString, Point
1055- >>> s = geopandas. GeoSeries(
1057+ >>> s = GeoSeries(
10561058 ... [
10571059 ... Polygon([(0, 0), (2, 2), (0, 2)]),
10581060 ... Polygon([(0, 0), (2, 2), (0, 2)]),
@@ -1061,7 +1063,7 @@ def intersection(
10611063 ... Point(0, 1),
10621064 ... ],
10631065 ... )
1064- >>> s2 = geopandas. GeoSeries(
1066+ >>> s2 = GeoSeries(
10651067 ... [
10661068 ... Polygon([(0, 0), (1, 1), (0, 1)]),
10671069 ... LineString([(1, 0), (1, 3)]),
@@ -1277,8 +1279,9 @@ def x(self) -> pspd.Series:
12771279 Examples
12781280 --------
12791281
1282+ >>> from sedona.geopandas import GeoSeries
12801283 >>> from shapely.geometry import Point
1281- >>> s = geopandas. GeoSeries([Point(1, 1), Point(2, 2), Point(3, 3)])
1284+ >>> s = GeoSeries([Point(1, 1), Point(2, 2), Point(3, 3)])
12821285 >>> s.x
12831286 0 1.0
12841287 1 2.0
@@ -1305,8 +1308,9 @@ def y(self) -> pspd.Series:
13051308 Examples
13061309 --------
13071310
1311+ >>> from sedona.geopandas import GeoSeries
13081312 >>> from shapely.geometry import Point
1309- >>> s = geopandas. GeoSeries([Point(1, 1), Point(2, 2), Point(3, 3)])
1313+ >>> s = GeoSeries([Point(1, 1), Point(2, 2), Point(3, 3)])
13101314 >>> s.y
13111315 0 1.0
13121316 1 2.0
@@ -1334,8 +1338,9 @@ def z(self) -> pspd.Series:
13341338 Examples
13351339 --------
13361340
1341+ >>> from sedona.geopandas import GeoSeries
13371342 >>> from shapely.geometry import Point
1338- >>> s = geopandas. GeoSeries([Point(1, 1, 1), Point(2, 2, 2), Point(3, 3, 3)])
1343+ >>> s = GeoSeries([Point(1, 1, 1), Point(2, 2, 2), Point(3, 3, 3)])
13391344 >>> s.z
13401345 0 1.0
13411346 1 2.0
@@ -1681,7 +1686,101 @@ def explode(self, ignore_index=False, index_parts=False) -> "GeoSeries":
16811686 def to_crs (
16821687 self , crs : Union [Any , None ] = None , epsg : Union [int , None ] = None
16831688 ) -> "GeoSeries" :
1684- raise NotImplementedError ("GeoSeries.to_crs() is not implemented yet." )
1689+ """Returns a ``GeoSeries`` with all geometries transformed to a new
1690+ coordinate reference system.
1691+
1692+ Transform all geometries in a GeoSeries to a different coordinate
1693+ reference system. The ``crs`` attribute on the current GeoSeries must
1694+ be set. Either ``crs`` or ``epsg`` may be specified for output.
1695+
1696+ This method will transform all points in all objects. It has no notion
1697+ of projecting entire geometries. All segments joining points are
1698+ assumed to be lines in the current projection, not geodesics. Objects
1699+ crossing the dateline (or other projection boundary) will have
1700+ undesirable behavior.
1701+
1702+ Parameters
1703+ ----------
1704+ crs : pyproj.CRS, optional if `epsg` is specified
1705+ The value can be anything accepted
1706+ by :meth:`pyproj.CRS.from_user_input() <pyproj.crs.CRS.from_user_input>`,
1707+ such as an authority string (eg "EPSG:4326") or a WKT string.
1708+ epsg : int, optional if `crs` is specified
1709+ EPSG code specifying output projection.
1710+
1711+ Returns
1712+ -------
1713+ GeoSeries
1714+
1715+ Examples
1716+ --------
1717+ >>> from shapely.geometry import Point
1718+ >>> from sedona.geopandas import GeoSeries
1719+ >>> geoseries = GeoSeries([Point(1, 1), Point(2, 2), Point(3, 3)], crs=4326)
1720+ >>> geoseries.crs
1721+ <Geographic 2D CRS: EPSG:4326>
1722+ Name: WGS 84
1723+ Axis Info [ellipsoidal]:
1724+ - Lat[north]: Geodetic latitude (degree)
1725+ - Lon[east]: Geodetic longitude (degree)
1726+ Area of Use:
1727+ - name: World
1728+ - bounds: (-180.0, -90.0, 180.0, 90.0)
1729+ Datum: World Geodetic System 1984
1730+ - Ellipsoid: WGS 84
1731+ - Prime Meridian: Greenwich
1732+
1733+ >>> geoseries = geoseries.to_crs(3857)
1734+ >>> print(geoseries)
1735+ 0 POINT (111319.491 111325.143)
1736+ 1 POINT (222638.982 222684.209)
1737+ 2 POINT (333958.472 334111.171)
1738+ dtype: geometry
1739+ >>> geoseries.crs
1740+ <Projected CRS: EPSG:3857>
1741+ Name: WGS 84 / Pseudo-Mercator
1742+ Axis Info [cartesian]:
1743+ - X[east]: Easting (metre)
1744+ - Y[north]: Northing (metre)
1745+ Area of Use:
1746+ - name: World - 85°S to 85°N
1747+ - bounds: (-180.0, -85.06, 180.0, 85.06)
1748+ Coordinate Operation:
1749+ - name: Popular Visualisation Pseudo-Mercator
1750+ - method: Popular Visualisation Pseudo Mercator
1751+ Datum: World Geodetic System 1984
1752+ - Ellipsoid: WGS 84
1753+ - Prime Meridian: Greenwich
1754+
1755+ """
1756+
1757+ from pyproj import CRS
1758+
1759+ old_crs = self .crs
1760+ if old_crs is None :
1761+ raise ValueError (
1762+ "Cannot transform naive geometries. "
1763+ "Please set a crs on the object first."
1764+ )
1765+ assert isinstance (old_crs , CRS )
1766+
1767+ if crs is not None :
1768+ crs = CRS .from_user_input (crs )
1769+ elif epsg is not None :
1770+ crs = CRS .from_epsg (epsg )
1771+ else :
1772+ raise ValueError ("Must pass either crs or epsg." )
1773+
1774+ # skip if the input CRS and output CRS are the exact same
1775+ if old_crs .is_exact_same (crs ):
1776+ return self
1777+
1778+ col = self .get_first_geometry_column ()
1779+ return self ._query_geometry_column (
1780+ f"ST_Transform(`{ col } `, 'EPSG:{ old_crs .to_epsg ()} ', 'EPSG:{ crs .to_epsg ()} ')" ,
1781+ col ,
1782+ "" ,
1783+ )
16851784
16861785 def estimate_utm_crs (self , datum_name : str = "WGS 84" ):
16871786 raise NotImplementedError (
0 commit comments