diff --git a/bigframes/bigquery/__init__.py b/bigframes/bigquery/__init__.py index 21e61bc4b1..56aee38bfe 100644 --- a/bigframes/bigquery/__init__.py +++ b/bigframes/bigquery/__init__.py @@ -27,6 +27,7 @@ unix_millis, unix_seconds, ) +from bigframes.bigquery._operations.geo import st_area from bigframes.bigquery._operations.json import ( json_extract, json_extract_array, @@ -45,6 +46,8 @@ "array_length", "array_agg", "array_to_string", + # geo ops + "st_area", # json ops "json_set", "json_extract", diff --git a/bigframes/bigquery/_operations/geo.py b/bigframes/bigquery/_operations/geo.py new file mode 100644 index 0000000000..262ced4fe8 --- /dev/null +++ b/bigframes/bigquery/_operations/geo.py @@ -0,0 +1,93 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from bigframes import operations as ops +import bigframes.geopandas +import bigframes.series + +""" +Search functions defined from +https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions +""" + + +def st_area(self) -> bigframes.series.Series: + """ + Returns the area in square meters covered by the polygons in the input + GEOGRAPHY. + + If geography_expression is a point or a line, returns zero. If + geography_expression is a collection, returns the area of the polygons + in the collection; if the collection doesn't contain polygons, returns zero. + + + ..note:: + BigQuery's Geography functions, like `st_area`, interpet the geomtry + data type as a point set on the Earth's surface. A point set is a set + of points, lines, and polygons on the WGS84 reference spheroid, with + geodesic edges. See: https://cloud.google.com/bigquery/docs/geospatial-data + + + **Examples:** + + >>> import bigframes.geopandas + >>> import bigframes.pandas as bpd + >>> import bigframes.bigquery as bbq + >>> from shapely.geometry import Polygon, LineString, Point + >>> bpd.options.display.progress_bar = None + + >>> series = bigframes.geopandas.GeoSeries( + ... [ + ... Polygon([(0.0, 0.0), (0.1, 0.1), (0.0, 0.1)]), + ... Polygon([(0.10, 0.4), (0.9, 0.5), (0.10, 0.5)]), + ... Polygon([(0.1, 0.1), (0.2, 0.1), (0.2, 0.2)]), + ... LineString([(0, 0), (1, 1), (0, 1)]), + ... Point(0, 1), + ... ] + ... ) + >>> series + 0 POLYGON ((0 0, 0.1 0.1, 0 0.1, 0 0)) + 1 POLYGON ((0.1 0.4, 0.9 0.5, 0.1 0.5, 0.1 0.4)) + 2 POLYGON ((0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1)) + 3 LINESTRING (0 0, 1 1, 0 1) + 4 POINT (0 1) + dtype: geometry + + >>> bbq.st_area(series) + 0 61821689.855985 + 1 494563347.88721 + 2 61821689.855841 + 3 0.0 + 4 0.0 + dtype: Float64 + + Use `round()` to round the outputed areas to the neares ten millions + + >>> bbq.st_area(series).round(-7) + 0 60000000.0 + 1 490000000.0 + 2 60000000.0 + 3 0.0 + 4 0.0 + dtype: Float64 + + Returns: + bigframes.pandas.Series: + Series of float representing the areas. + """ + series = self._apply_unary_op(ops.geo_area_op) + series.name = None + return series diff --git a/bigframes/core/compile/scalar_op_compiler.py b/bigframes/core/compile/scalar_op_compiler.py index b42f983619..78c3c23abd 100644 --- a/bigframes/core/compile/scalar_op_compiler.py +++ b/bigframes/core/compile/scalar_op_compiler.py @@ -993,6 +993,11 @@ 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_area_op) +def geo_area_op_impl(x: ibis_types.Value): + return typing.cast(ibis_types.GeoSpatialValue, x).area() + + # 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): diff --git a/bigframes/geopandas/geoseries.py b/bigframes/geopandas/geoseries.py index 7a5b24f413..bc0482f60d 100644 --- a/bigframes/geopandas/geoseries.py +++ b/bigframes/geopandas/geoseries.py @@ -13,6 +13,7 @@ # limitations under the License. from __future__ import annotations +import bigframes_vendored.constants as constants import bigframes_vendored.geopandas.geoseries as vendored_geoseries import geopandas.array # type: ignore @@ -39,3 +40,29 @@ def y(self) -> bigframes.series.Series: series = self._apply_unary_op(ops.geo_y_op) series.name = None return series + + # GeoSeries.area overrides Series.area with something totally different. + # Ignore this type error, as we are trying to be as close to geopandas as + # we can. + @property + def area(self, crs=None) -> bigframes.series.Series: # type: ignore + """Returns a Series containing the area of each geometry in the GeoSeries + expressed in the units of the CRS. + + Args: + crs (optional): + Coordinate Reference System of the geometry objects. Can be + anything accepted by pyproj.CRS.from_user_input(), such as an + authority string (eg “EPSG:4326”) or a WKT string. + + Returns: + bigframes.pandas.Series: + Series of float representing the areas. + + Raises: + NotImplementedError: + GeoSeries.area is not supported. Use bigframes.bigquery.st_area(series), insetead. + """ + raise NotImplementedError( + f"GeoSeries.area is not supported. Use bigframes.bigquery.st_area(series), instead. {constants.FEEDBACK_LINK}" + ) diff --git a/bigframes/operations/__init__.py b/bigframes/operations/__init__.py index d8b0447686..da1fc36cae 100644 --- a/bigframes/operations/__init__.py +++ b/bigframes/operations/__init__.py @@ -84,7 +84,7 @@ SqlScalarOp, where_op, ) -from bigframes.operations.geo_ops import geo_x_op, geo_y_op +from bigframes.operations.geo_ops import geo_area_op, geo_x_op, geo_y_op from bigframes.operations.json_ops import ( JSONExtract, JSONExtractArray, @@ -332,6 +332,7 @@ # Geo ops "geo_x_op", "geo_y_op", + "geo_area_op", # Numpy ops mapping "NUMPY_TO_BINOP", "NUMPY_TO_OP", diff --git a/bigframes/operations/geo_ops.py b/bigframes/operations/geo_ops.py index 73e7e89197..bc14fa611b 100644 --- a/bigframes/operations/geo_ops.py +++ b/bigframes/operations/geo_ops.py @@ -29,3 +29,10 @@ 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( + dtypes.is_geo_like, dtypes.FLOAT_DTYPE, description="geo-like" + ), +) diff --git a/notebooks/geo/geoseries.ipynb b/notebooks/geo/geoseries.ipynb index 160d19ce91..7dc4c596ca 100644 --- a/notebooks/geo/geoseries.ipynb +++ b/notebooks/geo/geoseries.ipynb @@ -37,7 +37,6 @@ "import bigframes\n", "import bigframes.geopandas\n", "import bigframes.pandas as bpd\n", - "import shapely\n", "bpd.options.display.progress_bar = None" ] }, @@ -57,7 +56,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "/usr/local/google/home/arwas/src1/python-bigquery-dataframes/bigframes/session/_io/bigquery/read_gbq_table.py:274: DefaultIndexWarning: Table 'bigquery-public-data.geo_us_boundaries.counties' is clustered and/or partitioned, but BigQuery DataFrames was not able to find a suitable index. To avoid this warning, set at least one of: `index_col` or `filters`.\n", + "/usr/local/google/home/arwas/src1/python-bigquery-dataframes/bigframes/session/_io/bigquery/read_gbq_table.py:280: DefaultIndexWarning: Table 'bigquery-public-data.geo_us_boundaries.counties' is clustered and/or partitioned, but BigQuery DataFrames was not able to find a suitable index. To avoid this warning, set at least one of: `index_col` or `filters`.\n", " warnings.warn(msg, category=bfe.DefaultIndexWarning)\n" ] } @@ -98,21 +97,21 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "54 POINT (-93.47523 45.00612)\n", - "256 POINT (-89.60507 42.67552)\n", - "266 POINT (-104.11408 39.31516)\n", - "485 POINT (-91.23193 32.34688)\n", - "765 POINT (-83.42808 38.20427)\n", + "37 POINT (-91.19496 39.98605)\n", + "406 POINT (-84.86717 33.92103)\n", + "926 POINT (-82.47974 35.33641)\n", + "940 POINT (-75.50298 39.09709)\n", + "996 POINT (-92.56434 39.8298)\n", "Name: int_point_geom, dtype: geometry" ] }, - "execution_count": 12, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -129,13 +128,6 @@ "### Convert the five geo points to `bigframes.gopandas.GeoSeries`" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Note: TypeError is raised if the GEOGRAPHY column contains geometry type other than `Point`." - ] - }, { "cell_type": "code", "execution_count": 6, @@ -144,11 +136,11 @@ { "data": { "text/plain": [ - "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", + "0 POINT (-91.19496 39.98605)\n", + "1 POINT (-84.86717 33.92103)\n", + "2 POINT (-82.47974 35.33641)\n", + "3 POINT (-75.50298 39.09709)\n", + "4 POINT (-92.56434 39.8298)\n", "dtype: geometry" ] }, @@ -171,6 +163,13 @@ "### Retrieve the x (longitude) and y (latitude) from the GeoSeries with `.x` and `.y`." ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Note: TypeError is raised if `.x` and `.y` are used with a geometry type other than `Point`." + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -186,11 +185,11 @@ { "data": { "text/plain": [ - "0 -86.873385\n", - "1 -118.48037\n", - "2 -92.5617\n", - "3 -83.461893\n", - "4 -119.467788\n", + "0 -91.194961\n", + "1 -84.867169\n", + "2 -82.479741\n", + "3 -75.502982\n", + "4 -92.56434\n", "dtype: Float64" ] }, @@ -218,11 +217,11 @@ { "data": { "text/plain": [ - "0 38.373344\n", - "1 46.254606\n", - "2 32.30429\n", - "3 39.555246\n", - "4 47.213633\n", + "0 39.986053\n", + "1 33.92103\n", + "2 35.336415\n", + "3 39.097088\n", + "4 39.829795\n", "dtype: Float64" ] }, @@ -251,7 +250,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 9, "metadata": {}, "outputs": [ { @@ -285,7 +284,7 @@ "dtype: Float64" ] }, - "execution_count": 13, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -303,7 +302,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -337,7 +336,7 @@ "dtype: Float64" ] }, - "execution_count": 14, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -345,6 +344,160 @@ "source": [ "point_geom_series.geo.y" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Retrive the `area` of different geometry shapes. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Create a geometry collection from local data with `Peek`" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "10 POLYGON ((-101.7778 40.34969, -101.77812 40.34...\n", + "127 POLYGON ((-89.22333 44.50398, -89.22334 44.499...\n", + "253 POLYGON ((-76.69446 37.07288, -76.69515 37.072...\n", + "261 POLYGON ((-98.70136 44.45055, -98.70136 44.450...\n", + "303 POLYGON ((-85.99565 30.28131, -85.99566 30.280...\n", + "Name: county_geom, dtype: geometry" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "geom_series = df[\"county_geom\"].peek(n = 5)\n", + "geom_series" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Convert the geometry collection to `bigframes.gopandas.GeoSeries`" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0 POLYGON ((-101.7778 40.34969, -101.77812 40.34...\n", + "1 POLYGON ((-89.22333 44.50398, -89.22334 44.499...\n", + "2 POLYGON ((-76.69446 37.07288, -76.69515 37.072...\n", + "3 POLYGON ((-98.70136 44.45055, -98.70136 44.450...\n", + "4 POLYGON ((-85.99565 30.28131, -85.99566 30.280...\n", + "dtype: geometry" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "five_geom = bigframes.geopandas.GeoSeries(\n", + " [point for point in geom_series]\n", + ")\n", + "five_geom" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [ + "raises-exception" + ] + }, + "source": [ + "## Note: `bigframes.geopandas.GeoSeries.area` raises NotImplementedError. " + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "tags": [ + "raises-exception" + ] + }, + "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.34.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", + "File \u001b[0;32m~/src1/python-bigquery-dataframes/bigframes/geopandas/geoseries.py:66\u001b[0m, in \u001b[0;36mGeoSeries.area\u001b[0;34m(self, crs)\u001b[0m\n\u001b[1;32m 47\u001b[0m \u001b[38;5;129m@property\u001b[39m\n\u001b[1;32m 48\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 49\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 50\u001b[0m \u001b[38;5;124;03m expressed in the units of the CRS.\u001b[39;00m\n\u001b[1;32m 51\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 64\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 65\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m---> 66\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mNotImplementedError\u001b[39;00m(\n\u001b[1;32m 67\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 68\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.34.0" + ] + } + ], + "source": [ + "five_geom.area" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Use `bigframes.bigquery.st_area` to retirive the `area` in square meters instead. See: https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_area" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "import bigframes.bigquery as bbq" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0 2382382043.48891\n", + "1 1977633097.26862\n", + "2 939388839.499466\n", + "3 3269015229.381782\n", + "4 2678752241.321673\n", + "dtype: Float64" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "geom_area = bbq.st_area(five_geom)\n", + "geom_area" + ] } ], "metadata": { diff --git a/tests/system/small/bigquery/test_geo.py b/tests/system/small/bigquery/test_geo.py new file mode 100644 index 0000000000..7d38cd7d91 --- /dev/null +++ b/tests/system/small/bigquery/test_geo.py @@ -0,0 +1,53 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import geopandas # type: ignore +import pandas as pd +from shapely.geometry import LineString, Point, Polygon # type: ignore + +import bigframes.bigquery as bbq +import bigframes.geopandas +import bigframes.series + + +def test_geo_st_area(): + data = [ + Polygon([(0.000, 0.0), (0.001, 0.001), (0.000, 0.001)]), + Polygon([(0.0010, 0.004), (0.009, 0.005), (0.0010, 0.005)]), + Polygon([(0.001, 0.001), (0.002, 0.001), (0.002, 0.002)]), + LineString([(0, 0), (1, 1), (0, 1)]), + Point(0, 1), + ] + + geopd_s = geopandas.GeoSeries(data=data, crs="EPSG:4326") + geobf_s = bigframes.geopandas.GeoSeries(data=data) + + # For `geopd_s`, the data was further projected with `geopandas.GeoSeries.to_crs` + # to `to_crs(26393)` to get the area in square meter. See: https://geopandas.org/en/stable/docs/user_guide/projections.html + # and https://spatialreference.org/ref/epsg/26393/. We then rounded both results + # to get them as close to each other as possible. Initially, the area results + # were +ten-millions. We added more zeros after the decimal point to round the + # area results to the nearest thousands. + geopd_s_result = geopd_s.to_crs(26393).area.round(-3) + geobf_s_result = bbq.st_area(geobf_s).to_pandas().round(-3) + assert geobf_s_result.iloc[0] >= 1000 + + pd.testing.assert_series_equal( + geobf_s_result, + geopd_s_result, + check_dtype=False, + check_index_type=False, + check_exact=False, + rtol=1, + ) diff --git a/tests/system/small/geopandas/test_geoseries.py b/tests/system/small/geopandas/test_geoseries.py index a30460d461..2967e4d247 100644 --- a/tests/system/small/geopandas/test_geoseries.py +++ b/tests/system/small/geopandas/test_geoseries.py @@ -12,10 +12,15 @@ # See the License for the specific language governing permissions and # limitations under the License. +import re + +import bigframes_vendored.constants as constants import geopandas # type: ignore +from geopandas.array import GeometryDtype # type:ignore import google.api_core.exceptions import pandas as pd import pytest +from shapely.geometry import LineString, Point, Polygon # type: ignore import bigframes.geopandas import bigframes.series @@ -61,3 +66,24 @@ def test_geo_y(urban_areas_dfs): pd_result.astype(pd.Float64Dtype()), bf_result, ) + + +def test_geo_area_not_supported(): + 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), + ], + dtype=GeometryDtype(), + ) + bf_series: bigframes.geopandas.GeoSeries = s.geo + with pytest.raises( + NotImplementedError, + match=re.escape( + f"GeoSeries.area is not supported. Use bigframes.bigquery.st_area(series), instead. {constants.FEEDBACK_LINK}" + ), + ): + bf_series.area diff --git a/third_party/bigframes_vendored/geopandas/geoseries.py b/third_party/bigframes_vendored/geopandas/geoseries.py index 2ad35ed852..d84dec94a8 100644 --- a/third_party/bigframes_vendored/geopandas/geoseries.py +++ b/third_party/bigframes_vendored/geopandas/geoseries.py @@ -17,8 +17,9 @@ class GeoSeries: >>> import bigframes.geopandas >>> import bigframes.pandas as bpd - >>> bpd.options.display.progress_bar = None >>> from shapely.geometry import Point + >>> bpd.options.display.progress_bar = None + >>> s = bigframes.geopandas.GeoSeries([Point(1, 1), Point(2, 2), Point(3, 3)]) >>> s 0 POINT (1 1) @@ -43,9 +44,9 @@ def x(self) -> bigframes.series.Series: **Examples:** >>> import bigframes.pandas as bpd - >>> bpd.options.display.progress_bar = None >>> import geopandas.array >>> import shapely + >>> bpd.options.display.progress_bar = None >>> series = bpd.Series( ... [shapely.Point(1, 2), shapely.Point(2, 3), shapely.Point(3, 4)], @@ -58,7 +59,7 @@ def x(self) -> bigframes.series.Series: dtype: Float64 Returns: - bigframes.series.Series: + bigframes.pandas.Series: Return the x location (longitude) of point geometries. """ raise NotImplementedError(constants.ABSTRACT_METHOD_ERROR_MESSAGE) @@ -70,9 +71,9 @@ def y(self) -> bigframes.series.Series: **Examples:** >>> import bigframes.pandas as bpd - >>> bpd.options.display.progress_bar = None >>> import geopandas.array >>> import shapely + >>> bpd.options.display.progress_bar = None >>> series = bpd.Series( ... [shapely.Point(1, 2), shapely.Point(2, 3), shapely.Point(3, 4)], @@ -85,7 +86,7 @@ def y(self) -> bigframes.series.Series: dtype: Float64 Returns: - bigframes.series.Series: + bigframes.pandas.Series: Return the y location (latitude) of point geometries. """ raise NotImplementedError(constants.ABSTRACT_METHOD_ERROR_MESSAGE)