Skip to content

Commit 2993b28

Browse files
arwas11tswast
andauthored
feat: add GeoSeries.from_wkt() and GeoSeries.to_wkt() (#1401)
* feat: add GeoSeries.from_wkt() and GeoSeries.to_wkt() * update paramas and test * fix to_wkt test by removing whitespace * fix docstrings missing import * fix to_wkt test * remove comment from docstrings * Apply suggestions from code review --------- Co-authored-by: Tim Sweña (Swast) <[email protected]>
1 parent 317ec2b commit 2993b28

File tree

9 files changed

+309
-58
lines changed

9 files changed

+309
-58
lines changed

bigframes/bigquery/_operations/geo.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"""
2525

2626

27-
def st_area(self) -> bigframes.series.Series:
27+
def st_area(series: bigframes.series.Series) -> bigframes.series.Series:
2828
"""
2929
Returns the area in square meters covered by the polygons in the input
3030
GEOGRAPHY.
@@ -35,7 +35,7 @@ def st_area(self) -> bigframes.series.Series:
3535
3636
3737
..note::
38-
BigQuery's Geography functions, like `st_area`, interpet the geomtry
38+
BigQuery's Geography functions, like `st_area`, interpret the geometry
3939
data type as a point set on the Earth's surface. A point set is a set
4040
of points, lines, and polygons on the WGS84 reference spheroid, with
4141
geodesic edges. See: https://cloud.google.com/bigquery/docs/geospatial-data
@@ -88,6 +88,6 @@ def st_area(self) -> bigframes.series.Series:
8888
bigframes.pandas.Series:
8989
Series of float representing the areas.
9090
"""
91-
series = self._apply_unary_op(ops.geo_area_op)
91+
series = series._apply_unary_op(ops.geo_area_op)
9292
series.name = None
9393
return series

bigframes/core/compile/scalar_op_compiler.py

+17
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,18 @@ def geo_area_op_impl(x: ibis_types.Value):
10131013
return typing.cast(ibis_types.GeoSpatialValue, x).area()
10141014

10151015

1016+
@scalar_op_compiler.register_unary_op(ops.geo_st_astext_op)
1017+
def geo_st_astext_op_impl(x: ibis_types.Value):
1018+
return typing.cast(ibis_types.GeoSpatialValue, x).as_text()
1019+
1020+
1021+
@scalar_op_compiler.register_unary_op(ops.geo_st_geogfromtext_op)
1022+
def geo_st_geogfromtext_op_impl(x: ibis_types.Value):
1023+
# Ibis doesn't seem to provide a dedicated method to cast from string to geography,
1024+
# so we use a BigQuery scalar function, st_geogfromtext(), directly.
1025+
return st_geogfromtext(x)
1026+
1027+
10161028
@scalar_op_compiler.register_binary_op(ops.geo_st_geogpoint_op, pass_op=False)
10171029
def geo_st_geogpoint_op_impl(x: ibis_types.Value, y: ibis_types.Value):
10181030
return typing.cast(ibis_types.NumericValue, x).point(
@@ -1930,6 +1942,11 @@ def _ibis_num(number: float):
19301942
return typing.cast(ibis_types.NumericValue, ibis_types.literal(number))
19311943

19321944

1945+
@ibis_udf.scalar.builtin
1946+
def st_geogfromtext(a: str) -> ibis_dtypes.geography: # type: ignore
1947+
"""Convert string to geography."""
1948+
1949+
19331950
@ibis_udf.scalar.builtin
19341951
def timestamp(a: str) -> ibis_dtypes.timestamp: # type: ignore
19351952
"""Convert string to timestamp."""

bigframes/geopandas/geoseries.py

+12
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import bigframes_vendored.geopandas.geoseries as vendored_geoseries
1818
import geopandas.array # type: ignore
1919

20+
import bigframes.geopandas
2021
import bigframes.operations as ops
2122
import bigframes.series
2223

@@ -67,6 +68,12 @@ def area(self, crs=None) -> bigframes.series.Series: # type: ignore
6768
f"GeoSeries.area is not supported. Use bigframes.bigquery.st_area(series), instead. {constants.FEEDBACK_LINK}"
6869
)
6970

71+
@classmethod
72+
def from_wkt(cls, data, index=None) -> GeoSeries:
73+
series = bigframes.series.Series(data, index=index)
74+
75+
return cls(series._apply_unary_op(ops.geo_st_geogfromtext_op))
76+
7077
@classmethod
7178
def from_xy(cls, x, y, index=None, session=None, **kwargs) -> GeoSeries:
7279
# TODO: if either x or y is local and the other is remote. Use the
@@ -75,3 +82,8 @@ def from_xy(cls, x, y, index=None, session=None, **kwargs) -> GeoSeries:
7582
series_y = bigframes.series.Series(y, index=index, session=session, **kwargs)
7683

7784
return cls(series_x._apply_binary_op(series_y, ops.geo_st_geogpoint_op))
85+
86+
def to_wkt(self: GeoSeries) -> bigframes.series.Series:
87+
series = self._apply_unary_op(ops.geo_st_astext_op)
88+
series.name = None
89+
return series

bigframes/operations/__init__.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@
8787
)
8888
from bigframes.operations.geo_ops import (
8989
geo_area_op,
90+
geo_st_astext_op,
91+
geo_st_geogfromtext_op,
9092
geo_st_geogpoint_op,
9193
geo_x_op,
9294
geo_y_op,
@@ -353,10 +355,12 @@
353355
"euclidean_distance_op",
354356
"manhattan_distance_op",
355357
# Geo ops
356-
"geo_x_op",
357-
"geo_y_op",
358358
"geo_area_op",
359+
"geo_st_astext_op",
360+
"geo_st_geogfromtext_op",
359361
"geo_st_geogpoint_op",
362+
"geo_x_op",
363+
"geo_y_op",
360364
# Numpy ops mapping
361365
"NUMPY_TO_BINOP",
362366
"NUMPY_TO_OP",

bigframes/operations/geo_ops.py

+16
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,22 @@
3737
),
3838
)
3939

40+
41+
geo_st_astext_op = base_ops.create_unary_op(
42+
name="geo_st_astext",
43+
type_signature=op_typing.FixedOutputType(
44+
dtypes.is_geo_like, dtypes.STRING_DTYPE, description="geo-like"
45+
),
46+
)
47+
48+
49+
geo_st_geogfromtext_op = base_ops.create_unary_op(
50+
name="geo_st_geogfromtext",
51+
type_signature=op_typing.FixedOutputType(
52+
dtypes.is_string_like, dtypes.GEO_DTYPE, description="string-like"
53+
),
54+
)
55+
4056
geo_st_geogpoint_op = base_ops.create_binary_op(
4157
name="geo_st_geogpoint", type_signature=op_typing.BinaryNumericGeo()
4258
)

0 commit comments

Comments
 (0)