diff --git a/bigframes/core/compile/scalar_op_compiler.py b/bigframes/core/compile/scalar_op_compiler.py index 6e9b961971..35a307722f 100644 --- a/bigframes/core/compile/scalar_op_compiler.py +++ b/bigframes/core/compile/scalar_op_compiler.py @@ -1001,14 +1001,9 @@ def normalize_op_impl(x: ibis_types.Value): # Geo Ops -@scalar_op_compiler.register_unary_op(ops.geo_x_op) -def geo_x_op_impl(x: ibis_types.Value): - return typing.cast(ibis_types.GeoSpatialValue, x).x() - - -@scalar_op_compiler.register_unary_op(ops.geo_y_op) -def geo_y_op_impl(x: ibis_types.Value): - return typing.cast(ibis_types.GeoSpatialValue, x).y() +@scalar_op_compiler.register_unary_op(ops.geo_st_boundary_op, pass_op=False) +def geo_st_boundary_op_impl(x: ibis_types.Value): + return st_boundary(x) @scalar_op_compiler.register_unary_op(ops.geo_area_op) @@ -1035,6 +1030,16 @@ def geo_st_geogpoint_op_impl(x: ibis_types.Value, y: ibis_types.Value): ) +@scalar_op_compiler.register_unary_op(ops.geo_x_op) +def geo_x_op_impl(x: ibis_types.Value): + return typing.cast(ibis_types.GeoSpatialValue, x).x() + + +@scalar_op_compiler.register_unary_op(ops.geo_y_op) +def geo_y_op_impl(x: ibis_types.Value): + return typing.cast(ibis_types.GeoSpatialValue, x).y() + + # Parameterized ops @scalar_op_compiler.register_unary_op(ops.StructFieldOp, pass_op=True) def struct_field_op_impl(x: ibis_types.Value, op: ops.StructFieldOp): @@ -1965,6 +1970,11 @@ def unix_millis(a: ibis_dtypes.timestamp) -> int: # type: ignore """Convert a timestamp to milliseconds""" +@ibis_udf.scalar.builtin +def st_boundary(a: ibis_dtypes.geography) -> ibis_dtypes.geography: # type: ignore + """Find the boundary of a geography.""" + + @ibis_udf.scalar.builtin def unix_micros(a: ibis_dtypes.timestamp) -> int: # type: ignore """Convert a timestamp to microseconds""" diff --git a/bigframes/geopandas/geoseries.py b/bigframes/geopandas/geoseries.py index ce9a59f26a..44018b8c5c 100644 --- a/bigframes/geopandas/geoseries.py +++ b/bigframes/geopandas/geoseries.py @@ -68,6 +68,12 @@ def area(self, crs=None) -> bigframes.series.Series: # type: ignore f"GeoSeries.area is not supported. Use bigframes.bigquery.st_area(series), instead. {constants.FEEDBACK_LINK}" ) + @property + def boundary(self) -> bigframes.series.Series: # type: ignore + series = self._apply_unary_op(ops.geo_st_boundary_op) + series.name = None + return series + @classmethod def from_wkt(cls, data, index=None) -> GeoSeries: series = bigframes.series.Series(data, index=index) diff --git a/bigframes/operations/__init__.py b/bigframes/operations/__init__.py index 7128c10bb2..83cefbe6ba 100644 --- a/bigframes/operations/__init__.py +++ b/bigframes/operations/__init__.py @@ -89,6 +89,7 @@ from bigframes.operations.geo_ops import ( geo_area_op, geo_st_astext_op, + geo_st_boundary_op, geo_st_geogfromtext_op, geo_st_geogpoint_op, geo_x_op, @@ -364,6 +365,7 @@ "manhattan_distance_op", # Geo ops "geo_area_op", + "geo_st_boundary_op", "geo_st_astext_op", "geo_st_geogfromtext_op", "geo_st_geogpoint_op", diff --git a/bigframes/operations/geo_ops.py b/bigframes/operations/geo_ops.py index 04441957e7..9ef0983e24 100644 --- a/bigframes/operations/geo_ops.py +++ b/bigframes/operations/geo_ops.py @@ -16,20 +16,6 @@ from bigframes.operations import base_ops import bigframes.operations.type as op_typing -geo_x_op = base_ops.create_unary_op( - name="geo_x", - type_signature=op_typing.FixedOutputType( - dtypes.is_geo_like, dtypes.FLOAT_DTYPE, description="geo-like" - ), -) - -geo_y_op = base_ops.create_unary_op( - name="geo_y", - type_signature=op_typing.FixedOutputType( - dtypes.is_geo_like, dtypes.FLOAT_DTYPE, description="geo-like" - ), -) - geo_area_op = base_ops.create_unary_op( name="geo_area", type_signature=op_typing.FixedOutputType( @@ -37,7 +23,6 @@ ), ) - geo_st_astext_op = base_ops.create_unary_op( name="geo_st_astext", type_signature=op_typing.FixedOutputType( @@ -45,6 +30,12 @@ ), ) +geo_st_boundary_op = base_ops.create_unary_op( + name="geo_st_boundary", + type_signature=op_typing.FixedOutputType( + dtypes.is_geo_like, dtypes.GEO_DTYPE, description="geo-like" + ), +) geo_st_geogfromtext_op = base_ops.create_unary_op( name="geo_st_geogfromtext", @@ -53,6 +44,21 @@ ), ) + geo_st_geogpoint_op = base_ops.create_binary_op( name="geo_st_geogpoint", type_signature=op_typing.BinaryNumericGeo() ) + +geo_x_op = base_ops.create_unary_op( + name="geo_x", + type_signature=op_typing.FixedOutputType( + dtypes.is_geo_like, dtypes.FLOAT_DTYPE, description="geo-like" + ), +) + +geo_y_op = base_ops.create_unary_op( + name="geo_y", + type_signature=op_typing.FixedOutputType( + dtypes.is_geo_like, dtypes.FLOAT_DTYPE, description="geo-like" + ), +) diff --git a/notebooks/geo/geoseries.ipynb b/notebooks/geo/geoseries.ipynb index ffd772e7b4..7060128bf6 100644 --- a/notebooks/geo/geoseries.ipynb +++ b/notebooks/geo/geoseries.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -30,7 +30,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -49,7 +49,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -74,7 +74,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ @@ -97,21 +97,21 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "78 POINT (-95.84727 44.4092)\n", - "130 POINT (-94.90431 41.67918)\n", - "544 POINT (-95.85272 40.38739)\n", - "995 POINT (-101.83333 47.30715)\n", - "1036 POINT (-88.36343 37.20952)\n", + "137 POINT (-86.87338 38.37334)\n", + "164 POINT (-118.48037 46.25461)\n", + "333 POINT (-92.5617 32.30429)\n", + "703 POINT (-83.46189 39.55525)\n", + "846 POINT (-119.46779 47.21363)\n", "Name: int_point_geom, dtype: geometry" ] }, - "execution_count": 5, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -130,21 +130,21 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "0 POINT (-95.84727 44.4092)\n", - "1 POINT (-94.90431 41.67918)\n", - "2 POINT (-95.85272 40.38739)\n", - "3 POINT (-101.83333 47.30715)\n", - "4 POINT (-88.36343 37.20952)\n", + "0 POINT (-86.87338 38.37334)\n", + "1 POINT (-118.48037 46.25461)\n", + "2 POINT (-92.5617 32.30429)\n", + "3 POINT (-83.46189 39.55525)\n", + "4 POINT (-119.46779 47.21363)\n", "dtype: geometry" ] }, - "execution_count": 6, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -179,21 +179,21 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "0 -95.847268\n", - "1 -94.904312\n", - "2 -95.852721\n", - "3 -101.833328\n", - "4 -88.363426\n", + "0 -86.873385\n", + "1 -118.48037\n", + "2 -92.5617\n", + "3 -83.461893\n", + "4 -119.467788\n", "dtype: Float64" ] }, - "execution_count": 7, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -211,21 +211,21 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "0 44.409195\n", - "1 41.679178\n", - "2 40.387389\n", - "3 47.307147\n", - "4 37.209517\n", + "0 38.373344\n", + "1 46.254606\n", + "2 32.30429\n", + "3 39.555246\n", + "4 47.213633\n", "dtype: Float64" ] }, - "execution_count": 8, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -250,7 +250,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 14, "metadata": {}, "outputs": [ { @@ -284,7 +284,7 @@ "dtype: Float64" ] }, - "execution_count": 9, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } @@ -302,7 +302,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 15, "metadata": {}, "outputs": [ { @@ -336,7 +336,7 @@ "dtype: Float64" ] }, - "execution_count": 10, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } @@ -361,21 +361,21 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "59 POLYGON ((-96.92479 43.43217, -96.92477 43.430...\n", - "132 POLYGON ((-91.95104 40.05078, -91.95105 40.050...\n", - "223 POLYGON ((-84.39719 40.78658, -84.39718 40.783...\n", - "328 POLYGON ((-91.80469 31.48623, -91.80469 31.486...\n", - "396 POLYGON ((-79.87705 40.03683, -79.87688 40.036...\n", + "78 POLYGON ((-95.97154 44.6306, -95.97919 44.6305...\n", + "130 POLYGON ((-95.0933 41.77694, -95.09331 41.7764...\n", + "544 POLYGON ((-96.0664 40.43618, -96.06639 40.4352...\n", + "995 POLYGON ((-101.83583 47.49547, -101.83665 47.4...\n", + "1036 POLYGON ((-88.42474 37.15094, -88.42526 37.149...\n", "Name: county_geom, dtype: geometry" ] }, - "execution_count": 11, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -394,21 +394,21 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "0 POLYGON ((-96.92479 43.43217, -96.92477 43.430...\n", - "1 POLYGON ((-91.95104 40.05078, -91.95105 40.050...\n", - "2 POLYGON ((-84.39719 40.78658, -84.39718 40.783...\n", - "3 POLYGON ((-91.80469 31.48623, -91.80469 31.486...\n", - "4 POLYGON ((-79.87705 40.03683, -79.87688 40.036...\n", + "0 POLYGON ((-95.97154 44.6306, -95.97919 44.6305...\n", + "1 POLYGON ((-95.0933 41.77694, -95.09331 41.7764...\n", + "2 POLYGON ((-96.0664 40.43618, -96.06639 40.4352...\n", + "3 POLYGON ((-101.83583 47.49547, -101.83665 47.4...\n", + "4 POLYGON ((-88.42474 37.15094, -88.42526 37.149...\n", "dtype: geometry" ] }, - "execution_count": 12, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -433,7 +433,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 18, "metadata": { "tags": [ "raises-exception" @@ -442,14 +442,14 @@ "outputs": [ { "ename": "NotImplementedError", - "evalue": "GeoSeries.area is not supported. Use bigframes.bigquery.st_area(series), instead. Share your usecase with the BigQuery DataFrames team at the https://bit.ly/bigframes-feedback survey.You are currently running BigFrames version 1.36.0", + "evalue": "GeoSeries.area is not supported. Use bigframes.bigquery.st_area(series), instead. Share your usecase with the BigQuery DataFrames team at the https://bit.ly/bigframes-feedback survey.You are currently running BigFrames version 1.38.0", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNotImplementedError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[13], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mfive_geom\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43marea\u001b[49m\n", + "Cell \u001b[0;32mIn[18], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mfive_geom\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43marea\u001b[49m\n", "File \u001b[0;32m~/src1/python-bigquery-dataframes/bigframes/geopandas/geoseries.py:67\u001b[0m, in \u001b[0;36mGeoSeries.area\u001b[0;34m(self, crs)\u001b[0m\n\u001b[1;32m 48\u001b[0m \u001b[38;5;129m@property\u001b[39m\n\u001b[1;32m 49\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21marea\u001b[39m(\u001b[38;5;28mself\u001b[39m, crs\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m bigframes\u001b[38;5;241m.\u001b[39mseries\u001b[38;5;241m.\u001b[39mSeries: \u001b[38;5;66;03m# type: ignore\u001b[39;00m\n\u001b[1;32m 50\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Returns a Series containing the area of each geometry in the GeoSeries\u001b[39;00m\n\u001b[1;32m 51\u001b[0m \u001b[38;5;124;03m expressed in the units of the CRS.\u001b[39;00m\n\u001b[1;32m 52\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 65\u001b[0m \u001b[38;5;124;03m GeoSeries.area is not supported. Use bigframes.bigquery.st_area(series), insetead.\u001b[39;00m\n\u001b[1;32m 66\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m---> 67\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mNotImplementedError\u001b[39;00m(\n\u001b[1;32m 68\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mGeoSeries.area is not supported. Use bigframes.bigquery.st_area(series), instead. \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mconstants\u001b[38;5;241m.\u001b[39mFEEDBACK_LINK\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 69\u001b[0m )\n", - "\u001b[0;31mNotImplementedError\u001b[0m: GeoSeries.area is not supported. Use bigframes.bigquery.st_area(series), instead. Share your usecase with the BigQuery DataFrames team at the https://bit.ly/bigframes-feedback survey.You are currently running BigFrames version 1.36.0" + "\u001b[0;31mNotImplementedError\u001b[0m: GeoSeries.area is not supported. Use bigframes.bigquery.st_area(series), instead. Share your usecase with the BigQuery DataFrames team at the https://bit.ly/bigframes-feedback survey.You are currently running BigFrames version 1.38.0" ] } ], @@ -466,7 +466,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 19, "metadata": {}, "outputs": [], "source": [ @@ -475,21 +475,21 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "0 1493638545.448335\n", - "1 1321524759.411463\n", - "2 1052436575.522383\n", - "3 1937116615.360128\n", - "4 2065462414.544471\n", + "0 1865212769.084914\n", + "1 1146753653.723439\n", + "2 1059653048.84506\n", + "3 2873655557.502374\n", + "4 886267772.361455\n", "dtype: Float64" ] }, - "execution_count": 15, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -515,21 +515,21 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "0 POINT (-95.84727 44.4092)\n", - "1 POINT (-94.90431 41.67918)\n", - "2 POINT (-95.85272 40.38739)\n", - "3 POINT (-101.83333 47.30715)\n", - "4 POINT (-88.36343 37.20952)\n", + "0 POINT (-86.87338 38.37334)\n", + "1 POINT (-118.48037 46.25461)\n", + "2 POINT (-92.5617 32.30429)\n", + "3 POINT (-83.46189 39.55525)\n", + "4 POINT (-119.46779 47.21363)\n", "dtype: geometry" ] }, - "execution_count": 16, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } @@ -554,21 +554,21 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "0 POINT(-95.8472678 44.4091953)\n", - "1 POINT(-94.9043119 41.679178)\n", - "2 POINT(-95.8527214 40.3873891)\n", - "3 POINT(-101.8333279 47.3071473)\n", - "4 POINT(-88.3634261 37.2095174)\n", + "0 POINT(-86.8733845 38.3733441)\n", + "1 POINT(-118.4803697 46.2546057)\n", + "2 POINT(-92.5616997 32.3042901)\n", + "3 POINT(-83.4618927 39.5552462)\n", + "4 POINT(-119.467788 47.2136328)\n", "dtype: string" ] }, - "execution_count": 18, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -594,21 +594,21 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "0 POINT (-95.84727 44.4092)\n", - "1 POINT (-94.90431 41.67918)\n", - "2 POINT (-95.85272 40.38739)\n", - "3 POINT (-101.83333 47.30715)\n", - "4 POINT (-88.36343 37.20952)\n", + "0 POINT (-86.87338 38.37334)\n", + "1 POINT (-118.48037 46.25461)\n", + "2 POINT (-92.5617 32.30429)\n", + "3 POINT (-83.46189 39.55525)\n", + "4 POINT (-119.46779 47.21363)\n", "dtype: geometry" ] }, - "execution_count": 19, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } @@ -617,6 +617,73 @@ "wkts_from_geo = bigframes.geopandas.GeoSeries.from_wkt(geo_to_wkts)\n", "wkts_from_geo" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Discover the set-theoretic boundary of geometry objects with `GeoSeries.boundary`" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0 POLYGON ((0 0, 1 1, 0 1, 0 0))\n", + "1 POLYGON ((10 0, 10 5, 0 0, 10 0))\n", + "2 POLYGON ((0 0, 2 2, 2 0, 0 0))\n", + "3 LINESTRING (0 0, 1 1, 0 1)\n", + "4 POINT (0 1)\n", + "dtype: geometry" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from shapely.geometry import Polygon, LineString, Point\n", + "geom_obj = bigframes.geopandas.GeoSeries(\n", + " [\n", + " Polygon([(0, 0), (1, 1), (0, 1)]),\n", + " Polygon([(10, 0), (10, 5), (0, 0)]),\n", + " Polygon([(0, 0), (2, 2), (2, 0)]),\n", + " LineString([(0, 0), (1, 1), (0, 1)]),\n", + " Point(0, 1),\n", + " ]\n", + ")\n", + "geom_obj" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0 LINESTRING (0 0, 1 1, 0 1, 0 0)\n", + "1 LINESTRING (10 0, 10 5, 0 0, 10 0)\n", + "2 LINESTRING (0 0, 2 2, 2 0, 0 0)\n", + "3 MULTIPOINT (0 0, 0 1)\n", + "4 GEOMETRYCOLLECTION EMPTY\n", + "dtype: geometry" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "geom_obj.geo.boundary" + ] } ], "metadata": { diff --git a/tests/system/small/geopandas/test_geoseries.py b/tests/system/small/geopandas/test_geoseries.py index b27009d9d8..d0987dbdaf 100644 --- a/tests/system/small/geopandas/test_geoseries.py +++ b/tests/system/small/geopandas/test_geoseries.py @@ -162,3 +162,35 @@ def test_geo_to_wkt(): pd_result, check_index=False, ) + + +def test_geo_boundary(): + bf_s = bigframes.pandas.Series( + [ + Polygon([(0, 0), (1, 1), (0, 1)]), + Polygon([(10, 0), (10, 5), (0, 0)]), + Polygon([(0, 0), (2, 2), (2, 0)]), + LineString([(0, 0), (1, 1), (0, 1)]), + Point(0, 1), + ], + ) + + pd_s = geopandas.GeoSeries( + [ + Polygon([(0, 0), (1, 1), (0, 1)]), + Polygon([(10, 0), (10, 5), (0, 0)]), + Polygon([(0, 0), (2, 2), (2, 0)]), + LineString([(0, 0), (1, 1), (0, 1)]), + Point(0, 1), + ], + ) + + bf_result = bf_s.geo.boundary.to_pandas() + pd_result = pd_s.boundary + + pd.testing.assert_series_equal( + bf_result, + pd_result, + check_series_type=False, + check_index=False, + ) diff --git a/third_party/bigframes_vendored/geopandas/geoseries.py b/third_party/bigframes_vendored/geopandas/geoseries.py index b7040d4321..a2e7b74059 100644 --- a/third_party/bigframes_vendored/geopandas/geoseries.py +++ b/third_party/bigframes_vendored/geopandas/geoseries.py @@ -91,6 +91,46 @@ def y(self) -> bigframes.series.Series: """ raise NotImplementedError(constants.ABSTRACT_METHOD_ERROR_MESSAGE) + @property + def boundary(self) -> bigframes.geopandas.GeoSeries: + """ + Returns a GeoSeries of lower dimensional objects representing each + geometry's set-theoretic boundary. + + **Examples:** + + >>> import bigframes.pandas as bpd + >>> import geopandas.array + >>> import shapely + >>> bpd.options.display.progress_bar = None + + >>> from shapely.geometry import Polygon, LineString, Point + >>> s = geopandas.GeoSeries( + ... [ + ... Polygon([(0, 0), (1, 1), (0, 1)]), + ... LineString([(0, 0), (1, 1), (1, 0)]), + ... Point(0, 0), + ... ] + ... ) + >>> s + 0 POLYGON ((0 0, 1 1, 0 1, 0 0)) + 1 LINESTRING (0 0, 1 1, 1 0) + 2 POINT (0 0) + dtype: geometry + + >>> s.boundary + 0 LINESTRING (0 0, 1 1, 0 1, 0 0) + 1 MULTIPOINT (0 0, 1 0) + 2 GEOMETRYCOLLECTION EMPTY + dtype: geometry + + Returns: + bigframes.geopandas.GeoSeries: + A GeoSeries of lower dimensional objects representing each + geometry's set-theoretic boundary + """ + raise NotImplementedError(constants.ABSTRACT_METHOD_ERROR_MESSAGE) + @classmethod def from_xy(cls, x, y, index=None, **kwargs) -> bigframes.geopandas.GeoSeries: """