# 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
#
#     https://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.

Analyzing a GEOGRAPHY column with bigframes.geopandas.GeoSeries#

import bigframes
import bigframes.geopandas
import bigframes.pandas as bpd
bpd.options.display.progress_bar = None

1. Load the Counties table from the Census Bureau US Boundaries dataset#

df = bpd.read_gbq("bigquery-public-data.geo_us_boundaries.counties")
/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`.
  warnings.warn(msg, category=bfe.DefaultIndexWarning)

2. Create a series from the int_point_geom column#

point_geom_series = df['int_point_geom']

The GeoSeries constructor accepts local data or a bigframes.pandas.Series object.#

1. Create a GeoSeries from local data with Peek#

five_geo_points = point_geom_series.peek(n = 5)
five_geo_points
18      POINT (-83.91172 42.60253)
86      POINT (-90.13369 43.00102)
177    POINT (-117.23219 48.54382)
208     POINT (-84.50352 36.43523)
300     POINT (-91.85079 43.29299)
Name: int_point_geom, dtype: geometry

2. Convert the five geo points to GeoSeries#

geo_points = bigframes.geopandas.GeoSeries(
        [point for point in five_geo_points]
)
geo_points
0     POINT (-83.91172 42.60253)
1     POINT (-90.13369 43.00102)
2    POINT (-117.23219 48.54382)
3     POINT (-84.50352 36.43523)
4     POINT (-91.85079 43.29299)
dtype: geometry

3. Retrieve the x (longitude) and y (latitude) from the GeoSeries with .x and .y.#

Note: TypeError is raised if .x and .y are used with a geometry type other than Point.#

.x#

geo_points.x
0    -83.911718
1    -90.133691
2   -117.232191
3     -84.50352
4    -91.850788
dtype: Float64

.y#

geo_points.y
0    42.602532
1    43.001021
2    48.543825
3    36.435234
4    43.292989
dtype: Float64

4. Alternatively, use the .geo accessor to access GeoSeries methods from a bigframes.pandas.Series object.#

geo.x#

point_geom_series.geo.x
0    -101.298265
1     -99.111085
2      -66.58687
3    -102.601791
4     -71.578625
5     -88.961529
6     -87.492986
7     -82.422666
8    -100.208166
9     -85.815939
10   -101.681133
11   -119.516659
12    -89.398306
13    -107.78848
14    -91.159306
15   -113.887042
16    -83.470416
17    -98.520146
18    -83.911718
19    -87.321865
20    -91.727626
21    -93.466093
22   -101.143324
23    -78.657634
24    -94.272323
dtype: Float64

geo.y#

point_geom_series.geo.y
0     46.710819
1     29.353661
2     18.211152
3     38.835646
4     41.869768
5     39.860237
6     36.892059
7     38.143642
8     34.524623
9     30.862007
10    40.180165
11    46.228125
12    36.054196
13    38.154731
14    38.761902
15    44.928506
16    30.447232
17    29.448671
18    42.602532
19    34.529776
20    33.957675
21    42.037538
22    29.875285
23    36.299884
24    44.821657
dtype: Float64

Retrive the area of different geometry shapes.#

1. Create a geometry collection from local data with Peek#

geom_series = df["county_geom"].peek(n = 5)
geom_series
304    POLYGON ((-88.69875 38.56219, -88.69876 38.562...
288    POLYGON ((-100.55792 46.24588, -100.5579 46.24...
42     POLYGON ((-98.09779 30.49744, -98.0978 30.4971...
775    POLYGON ((-90.33573 41.67043, -90.33592 41.669...
83     POLYGON ((-85.98402 35.6552, -85.98402 35.6551...
Name: county_geom, dtype: geometry

2. Convert the geometry collection to GeoSeries#

five_geom = bigframes.geopandas.GeoSeries(
        [point for point in geom_series]
)
five_geom
0    POLYGON ((-88.69875 38.56219, -88.69876 38.562...
1    POLYGON ((-100.55792 46.24588, -100.5579 46.24...
2    POLYGON ((-98.09779 30.49744, -98.0978 30.4971...
3    POLYGON ((-90.33573 41.67043, -90.33592 41.669...
4    POLYGON ((-85.98402 35.6552, -85.98402 35.6551...
dtype: geometry

Note: GeoSeries.area raises NotImplementedError.#

five_geom.area
---------------------------------------------------------------------------
NotImplementedError                       Traceback (most recent call last)
Cell In[13], line 1
----> 1 five_geom.area

File ~/src1/python-bigquery-dataframes/bigframes/geopandas/geoseries.py:67, in GeoSeries.area(self, crs)
     48 @property
     49 def area(self, crs=None) -> bigframes.series.Series:  # type: ignore
     50     """Returns a Series containing the area of each geometry in the GeoSeries
     51     expressed in the units of the CRS.
     52 
   (...)
     65             GeoSeries.area is not supported. Use bigframes.bigquery.st_area(series), instead.
     66     """
---> 67     raise NotImplementedError(
     68         f"GeoSeries.area is not supported. Use bigframes.bigquery.st_area(series), instead. {constants.FEEDBACK_LINK}"
     69     )

NotImplementedError: 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.41.0.

3. Use bigframes.bigquery.st_area to retrieve the area in square meters instead. See: https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_area#

import bigframes.bigquery as bbq
geom_area = bbq.st_area(five_geom)
geom_area
0    1851741847.416806
1    4018075889.856168
2    2652483302.084653
3     1167209931.07698
4      1124055521.2818
dtype: Float64

Use GeoSeries.from_xy() to create a GeoSeries of Point geometries.#

1. Reuse the geo_points.x and geo_points.y results by passing them to .from_xy()#

bigframes.geopandas.GeoSeries.from_xy(geo_points.x, geo_points.y)
0     POINT (-83.91172 42.60253)
1     POINT (-90.13369 43.00102)
2    POINT (-117.23219 48.54382)
3     POINT (-84.50352 36.43523)
4     POINT (-91.85079 43.29299)
dtype: geometry

Use GeoSeries.to_wkt() to convert geo points from geometry data type to Well-Knonw Text (WKT).#

1. Reuse the geo_points#

geo_to_wkts = bigframes.geopandas.GeoSeries.to_wkt(geo_points)
geo_to_wkts
0     POINT(-83.9117183 42.6025316)
1     POINT(-90.1336915 43.0010208)
2    POINT(-117.2321913 48.5438247)
3        POINT(-84.50352 36.435234)
4      POINT(-91.850788 43.2929889)
dtype: string

Use GeoSeries.from_wkt() to convert geo points from Well-Knonw Text (WKT) to geometry data type.#

1. Reuse geo_to_wkts results from GeoSeries.to_wkts#

wkts_from_geo = bigframes.geopandas.GeoSeries.from_wkt(geo_to_wkts)
wkts_from_geo
0     POINT (-83.91172 42.60253)
1     POINT (-90.13369 43.00102)
2    POINT (-117.23219 48.54382)
3     POINT (-84.50352 36.43523)
4     POINT (-91.85079 43.29299)
dtype: geometry

Discover the set-theoretic boundary of geometry objects with GeoSeries.boundary#

from shapely.geometry import Polygon, LineString, Point
geom_obj = bigframes.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),
            ]
)
geom_obj
0       POLYGON ((0 0, 1 1, 0 1, 0 0))
1    POLYGON ((10 0, 10 5, 0 0, 10 0))
2       POLYGON ((0 0, 2 2, 2 0, 0 0))
3           LINESTRING (0 0, 1 1, 0 1)
4                          POINT (0 1)
dtype: geometry
geom_obj.geo.boundary
0       LINESTRING (0 0, 1 1, 0 1, 0 0)
1    LINESTRING (10 0, 10 5, 0 0, 10 0)
2       LINESTRING (0 0, 2 2, 2 0, 0 0)
3                 MULTIPOINT (0 0, 0 1)
4              GEOMETRYCOLLECTION EMPTY
dtype: geometry

Find the difference between two GeoSeries#

Reuse five_geom and geom_obj to find the difference between the geometry objects#

five_geom.difference(geom_obj)
0    POLYGON ((-88.69875 38.56219, -88.69876 38.562...
1    POLYGON ((-100.55792 46.24588, -100.5579 46.24...
2                             GEOMETRYCOLLECTION EMPTY
3    POLYGON ((-90.33573 41.67043, -90.33592 41.669...
4    POLYGON ((-85.98402 35.6552, -85.98402 35.6551...
dtype: geometry

Find the difference between a GeoSeries and a single geometry shape.#

five_geom.difference([Polygon([(0, 0), (10, 0), (10, 10), (0, 0)])])
0    POLYGON ((-88.69875 38.56219, -88.69876 38.562...
1                                                 None
2                                                 None
3                                                 None
4                                                 None
dtype: geometry

Find the difference in GeoSeries with the same shapes#

five_geom.difference(five_geom)
0    GEOMETRYCOLLECTION EMPTY
1    GEOMETRYCOLLECTION EMPTY
2    GEOMETRYCOLLECTION EMPTY
3    GEOMETRYCOLLECTION EMPTY
4    GEOMETRYCOLLECTION EMPTY
dtype: geometry

You can also useBigQuery.st_difference() to find the difference between two GeoSeries. See, https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_difference#

bbq.st_difference(five_geom, geom_obj)
0    POLYGON ((-88.69875 38.56219, -88.69876 38.562...
1    POLYGON ((-100.55792 46.24588, -100.5579 46.24...
2                             GEOMETRYCOLLECTION EMPTY
3    POLYGON ((-90.33573 41.67043, -90.33592 41.669...
4    POLYGON ((-85.98402 35.6552, -85.98402 35.6551...
dtype: geometry

Find the difference between a GeoSeries and a single geometry shape.#

bbq.st_difference(five_geom, [Polygon([(0, 0), (10, 0), (10, 10), (0, 0)])])
0    POLYGON ((-88.69875 38.56219, -88.69876 38.562...
1                                                 None
2                                                 None
3                                                 None
4                                                 None
dtype: geometry

Find the difference in GeoSeries with the same shapes#

bbq.st_difference(geom_obj, geom_obj)
0    GEOMETRYCOLLECTION EMPTY
1    GEOMETRYCOLLECTION EMPTY
2    GEOMETRYCOLLECTION EMPTY
3    GEOMETRYCOLLECTION EMPTY
4    GEOMETRYCOLLECTION EMPTY
dtype: geometry

Use GeoSeries.intersection() to find the intersecting points in two geometry shapes#

Reuse wkts_from_geo and geom_obj#

five_geom.intersection(geom_obj)
0                             GEOMETRYCOLLECTION EMPTY
1                             GEOMETRYCOLLECTION EMPTY
2    POLYGON ((-98.09779 30.49744, -98.0978 30.4971...
3                             GEOMETRYCOLLECTION EMPTY
4                             GEOMETRYCOLLECTION EMPTY
dtype: geometry

Find the difference between a GeoSeries and a single geometry shape.#

five_geom.intersection([Polygon([(0, 0), (10, 0), (10, 10), (0, 0)])])
0    GEOMETRYCOLLECTION EMPTY
1                        None
2                        None
3                        None
4                        None
dtype: geometry

You can also useBigQuery.st_intersection() to find the intersecting points between two GeoSeries. See, https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_intersection#

bbq.st_intersection(five_geom, geom_obj)
0                             GEOMETRYCOLLECTION EMPTY
1                             GEOMETRYCOLLECTION EMPTY
2    POLYGON ((-98.09779 30.49744, -98.0978 30.4971...
3                             GEOMETRYCOLLECTION EMPTY
4                             GEOMETRYCOLLECTION EMPTY
dtype: geometry

Find the difference between a GeoSeries and a single geometry shape.#

bbq.st_intersection(five_geom, [Polygon([(0, 0), (1, 0), (10, 10), (0, 0)])])
0    GEOMETRYCOLLECTION EMPTY
1                        None
2                        None
3                        None
4                        None
dtype: geometry