blob: 66558b6b54f37bd11fb29e14b474fae99b52ad0b [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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 shapely
import numpy as np
import pytest
import pandas as pd
import geopandas as gpd
import pyspark.pandas as ps
import sedona.spark.geopandas as sgpd
from sedona.spark.geopandas import GeoSeries, GeoDataFrame
from tests.geopandas.test_geopandas_base import TestGeopandasBase
from shapely import wkt
from shapely.geometry import (
Point,
LineString,
Polygon,
GeometryCollection,
MultiPoint,
MultiLineString,
MultiPolygon,
LinearRing,
box,
)
from pandas.testing import assert_series_equal
import pytest
from packaging.version import parse as parse_version
@pytest.mark.skipif(
parse_version(shapely.__version__) < parse_version("2.0.0"),
reason=f"Tests require shapely>=2.0.0, but found v{shapely.__version__}",
)
class TestGeoSeries(TestGeopandasBase):
def setup_method(self):
super().setup_method()
self.geoseries = sgpd.GeoSeries(
[
Point(2.3, -1),
LineString([(0.5, 0), (0, -3)]),
Polygon([(-1, -1), (-0.3, 5), (1, 1.2)]),
GeometryCollection(
[
Point(2.3, -1),
LineString([(0.5, 0), (0, -3)]),
Polygon([(-1, -1), (-0.3, 5), (1, 1.2)]),
]
),
]
)
def test_empty_list(self):
s = sgpd.GeoSeries([])
assert s.count() == 0
def test_non_geom_fails(self):
with pytest.raises(TypeError):
GeoSeries([0, 1, 2])
with pytest.raises(TypeError):
GeoSeries([0, 1, 2], crs="epsg:4326")
with pytest.raises(TypeError):
GeoSeries(["a", "b", "c"])
with pytest.raises(TypeError):
GeoSeries(pd.Series([0, 1, 2]), crs="epsg:4326")
with pytest.raises(TypeError):
GeoSeries(ps.Series([0, 1, 2]))
@pytest.mark.parametrize(
"obj",
[
[Point(x, x) for x in range(3)],
pd.Series([Point(x, x) for x in range(3)]),
gpd.GeoSeries([Point(x, x) for x in range(3)]),
],
)
def test_constructor(self, obj):
sgpd_series = sgpd.GeoSeries(obj)
assert isinstance(sgpd_series, sgpd.GeoSeries)
def test_constructor_pandas_on_spark(self):
obj = ps.Series([Point(x, x) for x in range(3)])
sgpd_series = GeoSeries(obj)
assert isinstance(sgpd_series, sgpd.GeoSeries)
def test_to_geopandas(self):
from geopandas.testing import assert_geoseries_equal
data = [Point(x, x) for x in range(3)]
index = [1, 2, 3]
crs = "EPSG:3857"
result = GeoSeries(data, index=index, crs=crs).to_geopandas()
gpd_df = gpd.GeoSeries(data, index=index, crs=crs)
assert_geoseries_equal(result, gpd_df)
def test_to_spark_pandas(self):
data = [Point(x, x) for x in range(3)]
index = [1, 2, 3]
crs = "EPSG:3857"
result = GeoSeries(data, index=index, crs=crs).to_spark_pandas()
ps_df = ps.Series(data, index=index)
assert_series_equal(result.to_pandas(), ps_df.to_pandas())
def test_sindex(self):
s = GeoSeries([Point(x, x) for x in range(5)])
assert not s.has_sindex
result = s.sindex.query(box(1, 1, 3, 3))
expected = [Point(1, 1), Point(2, 2), Point(3, 3)]
assert result == expected
assert s.has_sindex
result = s.sindex.query(box(1, 1, 3, 3), predicate="contains")
expected = [Point(1, 1), Point(2, 2), Point(3, 3)]
assert result == expected
assert s.has_sindex
# Check that it works with a GeoDataFrame
gdf = s.to_geoframe()
result = gdf.sindex.query(box(1, 1, 3, 3), predicate="contains")
assert result == expected
# This is challenging to support due to gdf.__setitem__ casting GeoSeries into pspd.Series
# assert gdf.has_sindex
def test_invalidate_sindex(self):
geoseries = GeoSeries([Point(0, 0), None, Point(2, 2)])
line = LineString([(1, 1), (3, 3)])
result1 = geoseries.sindex.query(line)
assert len(result1) == 1
assert geoseries.has_sindex
# Fill the None element with a new geometry that intersects with the line
# This should invalidate the sindex
geoseries.fillna(Point(1, 1), inplace=True)
assert not geoseries.has_sindex
result = geoseries.sindex.query(line)
assert len(result) == 2
# For set_crs, no need to invalidate the sindex
geoseries.set_crs(4326, inplace=True)
assert geoseries.has_sindex
def test_plot(self):
# Just make sure it doesn't error
self.geoseries.plot()
def test_area(self):
result = self.geoseries.area.to_pandas()
expected = pd.Series([0.0, 0.0, 5.23, 5.23])
assert_series_equal(result, expected)
# Test that GeoDataFrame.area also works
df_result = self.geoseries.to_geoframe().area.to_pandas()
assert_series_equal(result, df_result)
def test_buffer(self):
s = GeoSeries(
[
Point(0, 0),
LineString([(1, -1), (1, 0), (2, 0), (2, 1)]),
Polygon([(3, -1), (4, 0), (3, 1)]),
]
)
result = s.buffer(0.2)
expected = [
"POLYGON ((0.2 0, 0.1990369453344394 -0.0196034280659121, 0.1961570560806461 -0.0390180644032256, 0.1913880671464418 -0.0580569354508925, 0.1847759065022574 -0.076536686473018, 0.176384252869671 -0.0942793473651995, 0.1662939224605091 -0.1111140466039204, 0.1546020906725474 -0.1268786568327291, 0.1414213562373095 -0.1414213562373095, 0.1268786568327291 -0.1546020906725474, 0.1111140466039205 -0.1662939224605091, 0.0942793473651996 -0.176384252869671, 0.076536686473018 -0.1847759065022574, 0.0580569354508925 -0.1913880671464418, 0.0390180644032257 -0.1961570560806461, 0.0196034280659122 -0.1990369453344394, 0 -0.2, -0.0196034280659121 -0.1990369453344394, -0.0390180644032256 -0.1961570560806461, -0.0580569354508924 -0.1913880671464418, -0.076536686473018 -0.1847759065022574, -0.0942793473651996 -0.176384252869671, -0.1111140466039204 -0.1662939224605091, -0.1268786568327291 -0.1546020906725474, -0.1414213562373095 -0.1414213562373095, -0.1546020906725474 -0.1268786568327291, -0.1662939224605091 -0.1111140466039204, -0.176384252869671 -0.0942793473651996, -0.1847759065022574 -0.076536686473018, -0.1913880671464418 -0.0580569354508925, -0.1961570560806461 -0.0390180644032257, -0.1990369453344394 -0.0196034280659122, -0.2 0, -0.1990369453344394 0.0196034280659121, -0.1961570560806461 0.0390180644032257, -0.1913880671464418 0.0580569354508924, -0.1847759065022574 0.0765366864730179, -0.176384252869671 0.0942793473651995, -0.1662939224605091 0.1111140466039204, -0.1546020906725474 0.1268786568327291, -0.1414213562373095 0.1414213562373095, -0.1268786568327292 0.1546020906725474, -0.1111140466039204 0.1662939224605091, -0.0942793473651996 0.176384252869671, -0.0765366864730181 0.1847759065022573, -0.0580569354508925 0.1913880671464418, -0.0390180644032257 0.1961570560806461, -0.0196034280659121 0.1990369453344394, 0 0.2, 0.019603428065912 0.1990369453344394, 0.0390180644032257 0.1961570560806461, 0.0580569354508924 0.1913880671464418, 0.076536686473018 0.1847759065022573, 0.0942793473651995 0.176384252869671, 0.1111140466039204 0.1662939224605091, 0.1268786568327291 0.1546020906725474, 0.1414213562373095 0.1414213562373095, 0.1546020906725474 0.1268786568327292, 0.1662939224605091 0.1111140466039204, 0.176384252869671 0.0942793473651996, 0.1847759065022573 0.0765366864730181, 0.1913880671464418 0.0580569354508925, 0.1961570560806461 0.0390180644032258, 0.1990369453344394 0.0196034280659121, 0.2 0))",
"POLYGON ((0.8 0, 0.8009630546655606 0.0196034280659122, 0.803842943919354 0.0390180644032257, 0.8086119328535583 0.0580569354508925, 0.8152240934977426 0.076536686473018, 0.823615747130329 0.0942793473651996, 0.8337060775394909 0.1111140466039204, 0.8453979093274526 0.1268786568327291, 0.8585786437626906 0.1414213562373095, 0.8731213431672709 0.1546020906725474, 0.8888859533960796 0.1662939224605091, 0.9057206526348005 0.176384252869671, 0.9234633135269821 0.1847759065022574, 0.9419430645491076 0.1913880671464418, 0.9609819355967744 0.1961570560806461, 0.9803965719340879 0.1990369453344394, 1 0.2, 1.8 0.2, 1.8 1, 1.8009630546655606 1.019603428065912, 1.803842943919354 1.0390180644032256, 1.8086119328535581 1.0580569354508924, 1.8152240934977426 1.076536686473018, 1.823615747130329 1.0942793473651995, 1.8337060775394909 1.1111140466039204, 1.8453979093274526 1.1268786568327291, 1.8585786437626906 1.1414213562373094, 1.8731213431672709 1.1546020906725474, 1.8888859533960796 1.1662939224605091, 1.9057206526348005 1.176384252869671, 1.923463313526982 1.1847759065022574, 1.9419430645491076 1.1913880671464419, 1.9609819355967744 1.196157056080646, 1.980396571934088 1.1990369453344394, 2 1.2, 2.019603428065912 1.1990369453344394, 2.039018064403226 1.196157056080646, 2.0580569354508924 1.1913880671464419, 2.076536686473018 1.1847759065022574, 2.0942793473651995 1.176384252869671, 2.1111140466039204 1.1662939224605091, 2.126878656832729 1.1546020906725474, 2.1414213562373097 1.1414213562373094, 2.1546020906725474 1.1268786568327291, 2.166293922460509 1.1111140466039204, 2.176384252869671 1.0942793473651995, 2.1847759065022574 1.076536686473018, 2.1913880671464416 1.0580569354508924, 2.1961570560806463 1.0390180644032256, 2.1990369453344396 1.019603428065912, 2.2 1, 2.2 0, 2.1990369453344396 -0.0196034280659121, 2.1961570560806463 -0.0390180644032256, 2.1913880671464416 -0.0580569354508925, 2.1847759065022574 -0.076536686473018, 2.176384252869671 -0.0942793473651995, 2.166293922460509 -0.1111140466039204, 2.1546020906725474 -0.1268786568327291, 2.1414213562373097 -0.1414213562373095, 2.126878656832729 -0.1546020906725474, 2.1111140466039204 -0.1662939224605091, 2.0942793473651995 -0.176384252869671, 2.076536686473018 -0.1847759065022574, 2.0580569354508924 -0.1913880671464418, 2.039018064403226 -0.1961570560806461, 2.019603428065912 -0.1990369453344394, 2 -0.2, 1.2 -0.2, 1.2 -1, 1.1990369453344394 -1.019603428065912, 1.196157056080646 -1.0390180644032256, 1.1913880671464419 -1.0580569354508924, 1.1847759065022574 -1.076536686473018, 1.176384252869671 -1.0942793473651995, 1.1662939224605091 -1.1111140466039204, 1.1546020906725474 -1.1268786568327291, 1.1414213562373094 -1.1414213562373094, 1.1268786568327291 -1.1546020906725474, 1.1111140466039204 -1.1662939224605091, 1.0942793473651995 -1.176384252869671, 1.076536686473018 -1.1847759065022574, 1.0580569354508924 -1.1913880671464419, 1.0390180644032256 -1.196157056080646, 1.019603428065912 -1.1990369453344394, 1 -1.2, 0.9803965719340879 -1.1990369453344394, 0.9609819355967744 -1.196157056080646, 0.9419430645491076 -1.1913880671464419, 0.9234633135269821 -1.1847759065022574, 0.9057206526348005 -1.176384252869671, 0.8888859533960796 -1.1662939224605091, 0.8731213431672709 -1.1546020906725474, 0.8585786437626906 -1.1414213562373094, 0.8453979093274526 -1.1268786568327291, 0.8337060775394909 -1.1111140466039204, 0.823615747130329 -1.0942793473651995, 0.8152240934977426 -1.076536686473018, 0.8086119328535583 -1.0580569354508924, 0.803842943919354 -1.0390180644032256, 0.8009630546655606 -1.019603428065912, 0.8 -1, 0.8 0))",
"POLYGON ((2.8 -1, 2.8 1, 2.8009630546655604 1.019603428065912, 2.8038429439193537 1.0390180644032256, 2.8086119328535584 1.0580569354508924, 2.8152240934977426 1.076536686473018, 2.823615747130329 1.0942793473651995, 2.833706077539491 1.1111140466039204, 2.8453979093274526 1.1268786568327291, 2.8585786437626903 1.1414213562373094, 2.873121343167271 1.1546020906725474, 2.8888859533960796 1.1662939224605091, 2.9057206526348005 1.176384252869671, 2.923463313526982 1.1847759065022574, 2.9419430645491076 1.1913880671464419, 2.9609819355967746 1.196157056080646, 2.980396571934088 1.1990369453344394, 3 1.2, 3.019603428065912 1.1990369453344394, 3.039018064403226 1.196157056080646, 3.0580569354508924 1.1913880671464416, 3.076536686473018 1.1847759065022574, 3.0942793473651995 1.176384252869671, 3.1111140466039204 1.166293922460509, 3.126878656832729 1.1546020906725474, 3.1414213562373097 1.1414213562373094, 4.141421356237309 0.1414213562373095, 4.154602090672547 0.1268786568327292, 4.166293922460509 0.1111140466039206, 4.176384252869671 0.0942793473651996, 4.184775906502257 0.0765366864730181, 4.191388067146442 0.0580569354508926, 4.196157056080646 0.0390180644032257, 4.19903694533444 0.0196034280659121, 4.2 0, 4.19903694533444 -0.0196034280659121, 4.196157056080646 -0.0390180644032257, 4.191388067146442 -0.0580569354508926, 4.184775906502257 -0.076536686473018, 4.176384252869671 -0.0942793473651996, 4.166293922460509 -0.1111140466039206, 4.154602090672547 -0.1268786568327292, 4.141421356237309 -0.1414213562373095, 3.1414213562373097 -1.1414213562373094, 3.126878656832729 -1.1546020906725474, 3.1111140466039204 -1.166293922460509, 3.0942793473652 -1.1763842528696709, 3.076536686473018 -1.1847759065022574, 3.0580569354508924 -1.1913880671464416, 3.039018064403226 -1.196157056080646, 3.019603428065912 -1.1990369453344394, 3 -1.2, 2.980396571934088 -1.1990369453344394, 2.9609819355967746 -1.196157056080646, 2.9419430645491076 -1.1913880671464419, 2.923463313526982 -1.1847759065022574, 2.9057206526348005 -1.176384252869671, 2.8888859533960796 -1.1662939224605091, 2.873121343167271 -1.1546020906725474, 2.8585786437626908 -1.1414213562373097, 2.8453979093274526 -1.1268786568327291, 2.833706077539491 -1.1111140466039204, 2.823615747130329 -1.0942793473651995, 2.8152240934977426 -1.076536686473018, 2.8086119328535584 -1.0580569354508924, 2.8038429439193537 -1.0390180644032256, 2.8009630546655604 -1.019603428065912, 2.8 -1))",
]
expected = gpd.GeoSeries([wkt.loads(wkt_str) for wkt_str in expected])
self.check_sgpd_equals_gpd(result, expected)
# Check that GeoDataFrame works too
df_result = s.to_geoframe().buffer(0.2)
self.check_sgpd_equals_gpd(df_result, expected)
def test_simplify(self):
s = GeoSeries([Point(0, 0).buffer(1), LineString([(0, 0), (1, 10), (0, 20)])])
result = s.simplify(1)
expected = gpd.GeoSeries(
[Polygon([(0, 1), (0, -1), (-1, 0), (0, 1)]), LineString([(0, 0), (0, 20)])]
)
self.check_sgpd_equals_gpd(result, expected)
result = s.simplify(1.2, preserve_topology=False)
expected = gpd.GeoSeries([Polygon(), LineString([(0, 0), (0, 20)])])
self.check_sgpd_equals_gpd(result, expected)
s = GeoSeries([LineString([(0, 0), (1, 0.1), (2, 0)])])
result = s.simplify(0.2)
expected = gpd.GeoSeries([LineString([(0, 0), (2, 0)])])
self.check_sgpd_equals_gpd(result, expected)
result = s.simplify(0.2, preserve_topology=False)
expected = gpd.GeoSeries(
[
LineString([(0, 0), (2, 0)]),
]
)
self.check_sgpd_equals_gpd(result, expected)
# Check that GeoDataFrame works too
df_result = s.to_geoframe().simplify(0.2, preserve_topology=False)
self.check_sgpd_equals_gpd(df_result, expected)
def test_geometry(self):
sgpd_geoseries = sgpd.GeoSeries([Point(0, 0), Point(1, 1)])
assert isinstance(sgpd_geoseries.geometry, sgpd.GeoSeries)
assert_series_equal(
sgpd_geoseries.geometry.to_pandas(), sgpd_geoseries.to_pandas()
)
def test_x(self):
geoseries = sgpd.GeoSeries(
[Point(0, -1, 2.5), Point(2.5, 0, -1), Point(-1, 2.5, 0), Point(-1, 0)]
)
result = geoseries.x.to_pandas()
expected = pd.Series([0, 2.5, -1, -1])
assert_series_equal(result, expected)
def test_y(self):
geoseries = sgpd.GeoSeries(
[Point(0, -1, 2.5), Point(2.5, 0, -1), Point(-1, 2.5, 0), Point(-1, 0)]
)
result = geoseries.y.to_pandas()
expected = pd.Series([-1, 0, 2.5, 0])
assert_series_equal(result, expected)
def test_z(self):
geoseries = sgpd.GeoSeries(
[Point(0, -1, 2.5), Point(2.5, 0, -1), Point(-1, 2.5, 0), Point(-1, 0)]
)
result = geoseries.z.to_pandas()
expected = pd.Series([2.5, -1, 0, np.nan])
assert_series_equal(result, expected)
def test_m(self):
pass
def test_from_file(self):
pass
def test_from_wkb(self):
wkbs = [
(
b"\x01\x01\x00\x00\x00\x00\x00\x00\x00"
b"\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\xf0?"
),
(
b"\x01\x01\x00\x00\x00\x00\x00\x00\x00"
b"\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00@"
),
(
b"\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00"
b"\x00\x08@\x00\x00\x00\x00\x00\x00\x08@"
),
]
s = sgpd.GeoSeries.from_wkb(wkbs)
expected = gpd.GeoSeries([Point(1, 1), Point(2, 2), Point(3, 3)])
self.check_sgpd_equals_gpd(s, expected)
def test_from_wkt(self):
wkts = [
"POINT (1 1)",
"POINT (2 2)",
"POINT (3 3)",
]
s = sgpd.GeoSeries.from_wkt(wkts)
expected = gpd.GeoSeries([Point(1, 1), Point(2, 2), Point(3, 3)])
self.check_sgpd_equals_gpd(s, expected)
def test_from_xy(self):
x = [2.5, 5, -3.0]
y = [0.5, 1, 1.5]
s = sgpd.GeoSeries.from_xy(x, y, crs="EPSG:4326")
expected = gpd.GeoSeries([Point(2.5, 0.5), Point(5, 1), Point(-3, 1.5)])
self.check_sgpd_equals_gpd(s, expected)
z = [1, 2, 3]
s = sgpd.GeoSeries.from_xy(x, y, z)
expected = gpd.GeoSeries(
[Point(2.5, 0.5, 1), Point(5, 1, 2), Point(-3, 1.5, 3)]
)
self.check_sgpd_equals_gpd(s, expected)
def test_from_shapely(self):
pass
def test_from_arrow(self):
if parse_version(gpd.__version__) < parse_version("1.0.0"):
return
import pyarrow as pa
table = pa.table({"a": [0, 1, 2], "b": [0.1, 0.2, 0.3]})
with pytest.raises(ValueError, match="No GeoArrow geometry field found"):
GeoSeries.from_arrow(table["a"].chunk(0))
gpd_series = gpd.GeoSeries(
[Point(1, 1), Polygon(), LineString([(0, 0), (1, 1)]), None]
)
result = sgpd.GeoSeries.from_arrow(gpd_series.to_arrow())
self.check_sgpd_equals_gpd(result, gpd_series)
def test_to_file(self):
pass
@pytest.mark.parametrize("fun", ["isna", "isnull"])
def test_isna(self, fun):
geoseries = GeoSeries([Polygon([(0, 0), (1, 1), (0, 1)]), None, Polygon([])])
result = getattr(geoseries, fun)()
expected = pd.Series([False, True, False])
assert_series_equal(result.to_pandas(), expected)
@pytest.mark.parametrize("fun", ["notna", "notnull"])
def test_notna(self, fun):
geoseries = GeoSeries([Polygon([(0, 0), (1, 1), (0, 1)]), None, Polygon([])])
result = getattr(geoseries, fun)()
expected = pd.Series([True, False, True])
assert_series_equal(result.to_pandas(), expected)
def test_fillna(self):
s = sgpd.GeoSeries(
[
Polygon([(0, 0), (1, 1), (0, 1)]),
None,
Polygon([(0, 0), (-1, 1), (0, -1)]),
]
)
result = s.fillna()
expected = gpd.GeoSeries(
[
Polygon([(0, 0), (1, 1), (0, 1)]),
GeometryCollection(),
Polygon([(0, 0), (-1, 1), (0, -1)]),
]
)
self.check_sgpd_equals_gpd(result, expected)
result = s.fillna(Polygon([(0, 1), (2, 1), (1, 2)]))
expected = gpd.GeoSeries(
[
Polygon([(0, 0), (1, 1), (0, 1)]),
Polygon([(0, 1), (2, 1), (1, 2)]),
Polygon([(0, 0), (-1, 1), (0, -1)]),
]
)
self.check_sgpd_equals_gpd(result, expected)
# Check for GeoSeries fill value
s_fill = sgpd.GeoSeries(
[
Point(0, 0),
Point(1, 1),
Point(2, 2),
]
)
result = s.fillna(s_fill)
expected = gpd.GeoSeries(
[
Polygon([(0, 0), (1, 1), (0, 1)]),
Point(1, 1),
Polygon([(0, 0), (-1, 1), (0, -1)]),
]
)
self.check_sgpd_equals_gpd(result, expected)
# Ensure filling with np.nan or pd.NA returns None
# Also check that the name is preserved for fillna
import numpy as np
data = [Point(0, 0), None]
for fill_val in [np.nan, pd.NA]:
result = GeoSeries(data, name="geometry").fillna(fill_val)
expected = gpd.GeoSeries(data, name="geometry")
self.check_sgpd_equals_gpd(result, expected)
# Ensure filling with None is empty GeometryCollection and not None
# Also check that inplace works
result = GeoSeries(data, name="geometry")
result.fillna(None, inplace=True)
expected = gpd.GeoSeries([Point(0, 0), GeometryCollection()], name="geometry")
self.check_sgpd_equals_gpd(result, expected)
def test_explode(self):
pass
def test_to_crs(self):
from pyproj import CRS
geoseries = sgpd.GeoSeries(
[Point(1, 1), Point(2, 2), Point(3, 3)], crs=4326, name="geometry"
)
assert isinstance(geoseries.crs, CRS) and geoseries.crs.to_epsg() == 4326
result = geoseries.to_crs(3857)
assert isinstance(result.crs, CRS) and result.crs.to_epsg() == 3857
expected = gpd.GeoSeries(
[
Point(111319.49079327356, 111325.14286638486),
Point(222638.98158654712, 222684.20850554455),
Point(333958.4723798207, 334111.1714019597),
],
crs=3857,
name="geometry",
)
self.check_sgpd_equals_gpd(result, expected)
def test_bounds(self):
d = [
Point(2, 1),
Polygon([(0, 0), (1, 1), (1, 0)]),
LineString([(0, 1), (1, 2)]),
None,
]
geoseries = sgpd.GeoSeries(d, crs="EPSG:4326")
result = geoseries.bounds
expected = pd.DataFrame(
{
"minx": [2.0, 0.0, 0.0, np.nan],
"miny": [1.0, 0.0, 1.0, np.nan],
"maxx": [2.0, 1.0, 1.0, np.nan],
"maxy": [1.0, 1.0, 2.0, np.nan],
}
)
pd.testing.assert_frame_equal(result.to_pandas(), expected)
df_result = geoseries.to_geoframe().bounds
pd.testing.assert_frame_equal(df_result.to_pandas(), expected)
def test_total_bounds(self):
d = [
Point(3, -1),
Polygon([(0, 0), (1, 1), (1, 0)]),
LineString([(0, 1), (1, 2)]),
None,
]
geoseries = sgpd.GeoSeries(d, crs="EPSG:4326")
result = geoseries.total_bounds
expected = np.array([0.0, -1.0, 3.0, 2.0])
np.testing.assert_array_equal(result, expected)
df_result = geoseries.to_geoframe().total_bounds
np.testing.assert_array_equal(df_result, expected)
# These tests were taken directly from the TestEstimateUtmCrs class in the geopandas test suite
# https://github.com/geopandas/geopandas/blob/main/geopandas/tests/test_array.py
def test_estimate_utm_crs(self):
from pyproj import CRS
# setup
esb = Point(-73.9847, 40.7484)
sol = Point(-74.0446, 40.6893)
landmarks = sgpd.GeoSeries([esb, sol], crs="epsg:4326")
# geographic
assert landmarks.estimate_utm_crs() == CRS("EPSG:32618")
assert landmarks.estimate_utm_crs("NAD83") == CRS("EPSG:26918")
# projected
assert landmarks.to_crs("EPSG:3857").estimate_utm_crs() == CRS("EPSG:32618")
# antimeridian
antimeridian = sgpd.GeoSeries(
[
Point(1722483.900174921, 5228058.6143420935),
Point(4624385.494808555, 8692574.544944234),
],
crs="EPSG:3851",
)
assert antimeridian.estimate_utm_crs() == CRS("EPSG:32760")
# out of bounds
with pytest.raises(RuntimeError, match="Unable to determine UTM CRS"):
sgpd.GeoSeries(
[Polygon([(0, 90), (1, 90), (2, 90)])], crs="EPSG:4326"
).estimate_utm_crs()
# missing crs
with pytest.raises(RuntimeError, match="crs must be set"):
sgpd.GeoSeries([Polygon([(0, 90), (1, 90), (2, 90)])]).estimate_utm_crs()
def test_to_json(self):
s = GeoSeries([Point(1, 1), Point(2, 2), Point(3, 3)])
result = s.to_json()
expected = '{"type": "FeatureCollection", "features": [{"id": "0", "type": "Feature", "pr\
operties": {}, "geometry": {"type": "Point", "coordinates": [1.0, 1.0]}, "bbox": [1.0,\
1.0, 1.0, 1.0]}, {"id": "1", "type": "Feature", "properties": {}, "geometry": {"type"\
: "Point", "coordinates": [2.0, 2.0]}, "bbox": [2.0, 2.0, 2.0, 2.0]}, {"id": "2", "typ\
e": "Feature", "properties": {}, "geometry": {"type": "Point", "coordinates": [3.0, 3.\
0]}, "bbox": [3.0, 3.0, 3.0, 3.0]}], "bbox": [1.0, 1.0, 3.0, 3.0]}'
assert result == expected
result = s.to_json(show_bbox=True)
expected = '{"type": "FeatureCollection", "features": [{"id": "0", "type": "Feature", "properties": {}, "geometry": {"type": "Point", "coordinates": [1.0, 1.0]}, "bbox": [1.0, 1.0, 1.0, 1.0]}, {"id": "1", "type": "Feature", "properties": {}, "geometry": {"type": "Point", "coordinates": [2.0, 2.0]}, "bbox": [2.0, 2.0, 2.0, 2.0]}, {"id": "2", "type": "Feature", "properties": {}, "geometry": {"type": "Point", "coordinates": [3.0, 3.0]}, "bbox": [3.0, 3.0, 3.0, 3.0]}], "bbox": [1.0, 1.0, 3.0, 3.0]}'
assert result == expected
result = s.to_json(drop_id=True)
expected = '{"type": "FeatureCollection", "features": [{"type": "Feature", "properties": {}, "geometry": {"type": "Point", "coordinates": [1.0, 1.0]}, "bbox": [1.0, 1.0, 1.0, 1.0]}, {"type": "Feature", "properties": {}, "geometry": {"type": "Point", "coordinates": [2.0, 2.0]}, "bbox": [2.0, 2.0, 2.0, 2.0]}, {"type": "Feature", "properties": {}, "geometry": {"type": "Point", "coordinates": [3.0, 3.0]}, "bbox": [3.0, 3.0, 3.0, 3.0]}], "bbox": [1.0, 1.0, 3.0, 3.0]}'
assert result == expected
result = s.set_crs("EPSG:3857").to_json(to_wgs84=True)
expected = '{"type": "FeatureCollection", "features": [{"id": "0", "type": "Feature", "properties": {}, "geometry": {"type": "Point", "coordinates": [8.983152841195214e-06, 8.983152841195177e-06]}, "bbox": [8.983152841195214e-06, 8.983152841195177e-06, 8.983152841195214e-06, 8.983152841195177e-06]}, {"id": "1", "type": "Feature", "properties": {}, "geometry": {"type": "Point", "coordinates": [1.7966305682390428e-05, 1.7966305682390134e-05]}, "bbox": [1.7966305682390428e-05, 1.7966305682390134e-05, 1.7966305682390428e-05, 1.7966305682390134e-05]}, {"id": "2", "type": "Feature", "properties": {}, "geometry": {"type": "Point", "coordinates": [2.6949458523585642e-05, 2.694945852358465e-05]}, "bbox": [2.6949458523585642e-05, 2.694945852358465e-05, 2.6949458523585642e-05, 2.694945852358465e-05]}], "bbox": [8.983152841195214e-06, 8.983152841195177e-06, 2.6949458523585642e-05, 2.694945852358465e-05]}'
assert result == expected
def test_to_wkb(self):
if parse_version(shapely.__version__) < parse_version("2.0.0"):
return
data = [
Point(0, 0),
Polygon(),
Polygon([(0, 0), (1, 1), (1, 0)]),
None,
]
result = sgpd.GeoSeries(data).to_wkb()
expected = pd.Series(
[
b"\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
b"\x01\x03\x00\x00\x00\x00\x00\x00\x00",
b"\x01\x03\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
None,
]
)
self.check_pd_series_equal(result, expected)
result = sgpd.GeoSeries(data).to_wkb(hex=True)
expected = pd.Series(
[
"010100000000000000000000000000000000000000",
"010300000000000000",
"0103000000010000000400000000000000000000000000000000000000000000000000F03F000000000000F03F000000000000F03F000000000000000000000000000000000000000000000000",
None,
]
)
self.check_pd_series_equal(result, expected)
def test_to_wkt(self):
s = GeoSeries([Point(1, 1), Point(2, 2), Point(3, 3)])
result = s.to_wkt()
expected = pd.Series(
[
"POINT (1 1)",
"POINT (2 2)",
"POINT (3 3)",
]
)
self.check_pd_series_equal(result, expected)
s = GeoSeries(
[
Polygon(),
Point(1, 2),
LineString([(0, 0), (1, 1)]),
None,
]
)
result = s.to_wkt()
# Old versions return empty GeometryCollection instead of empty Polygon
if parse_version(shapely.__version__) < parse_version("2.0.0"):
return
expected = pd.Series(
[
"POLYGON EMPTY",
"POINT (1 2)",
"LINESTRING (0 0, 1 1)",
None,
]
)
self.check_pd_series_equal(result, expected)
def test_to_arrow(self):
if parse_version(gpd.__version__) < parse_version("1.0.0"):
return
import pyarrow as pa
gser = GeoSeries([Point(1, 2), Point(2, 1)])
arrow_array = gser.to_arrow()
result = pa.array(arrow_array)
expected = [
"0101000000000000000000F03F0000000000000040",
"01010000000000000000000040000000000000F03F",
]
expected = pa.array([bytes.fromhex(x) for x in expected], type=pa.binary())
assert result.equals(expected)
def test_clip(self):
pass
def test_geom_type(self):
geoseries = sgpd.GeoSeries(
[
Point(0, 0),
MultiPoint([Point(0, 0), Point(1, 1)]),
LineString([(0, 0), (1, 1)]),
MultiLineString(
[LineString([(0, 0), (1, 1)]), LineString([(2, 2), (3, 3)])]
),
Polygon([(0, 0), (1, 0), (0, 1)]),
MultiPolygon(
[
Polygon([(0, 0), (1, 0), (0, 1)]),
Polygon([(2, 2), (3, 2), (2, 3)]),
]
),
GeometryCollection([Point(0, 0), LineString([(0, 0), (1, 1)])]),
LinearRing([(0, 0), (1, 1), (1, 0), (0, 1), (0, 0)]),
]
)
result = geoseries.geom_type
expected = pd.Series(
[
"Point",
"MultiPoint",
"LineString",
"MultiLineString",
"Polygon",
"MultiPolygon",
"GeometryCollection",
"LineString", # Note: Sedona returns LineString instead of LinearRing
]
)
assert_series_equal(result.to_pandas(), expected)
df_result = geoseries.to_geoframe().geom_type
assert_series_equal(df_result.to_pandas(), expected)
def test_type(self):
pass
def test_length(self):
geoseries = 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)]),
]
),
]
)
result = geoseries.length.to_pandas()
expected = pd.Series([0.000000, 1.414214, 3.414214, 4.828427])
assert_series_equal(result, expected)
# Check that GeoDataFrame works too
df_result = geoseries.to_geoframe().length.to_pandas()
assert_series_equal(df_result, expected)
def test_is_valid(self):
geoseries = sgpd.GeoSeries(
[
Polygon([(0, 0), (1, 1), (0, 1)]),
Polygon([(0, 0), (1, 1), (1, 0), (0, 1)]), # bowtie geometry
Polygon([(0, 0), (2, 2), (2, 0)]),
None,
]
)
result = geoseries.is_valid
expected = pd.Series([True, False, True, False])
assert_series_equal(result.to_pandas(), expected)
# Check that GeoDataFrame works too
df_result = geoseries.to_geoframe().is_valid.to_pandas()
assert_series_equal(df_result, expected)
def test_is_valid_reason(self):
s = sgpd.GeoSeries(
[
Polygon([(0, 0), (1, 1), (0, 1)]),
Polygon([(0, 0), (1, 1), (1, 0), (0, 1)]), # bowtie geometry
Polygon([(0, 0), (2, 2), (2, 0)]),
Polygon(
[(0, 0), (2, 0), (1, 1), (2, 2), (0, 2), (1, 1), (0, 0)]
), # ring intersection
None,
]
)
result = s.is_valid_reason().to_pandas()
expected = pd.Series(
[
"Valid Geometry",
"Self-intersection at or near point (0.5, 0.5, NaN)",
"Valid Geometry",
"Ring Self-intersection at or near point (1.0, 1.0)",
None,
]
)
assert_series_equal(result, expected)
# Check that GeoDataFrame works too
df_result = s.to_geoframe().is_valid_reason().to_pandas()
assert_series_equal(df_result, expected)
def test_is_empty(self):
geoseries = sgpd.GeoSeries(
[Point(), Point(2, 1), Polygon([(0, 0), (1, 1), (0, 1)]), None],
)
result = geoseries.is_empty
expected = pd.Series([True, False, False, False])
assert_series_equal(result.to_pandas(), expected)
# Check that GeoDataFrame works too
df_result = geoseries.to_geoframe().is_empty.to_pandas()
assert_series_equal(df_result, expected)
def test_count_coordinates(self):
pass
def test_count_geometries(self):
pass
def test_count_interior_rings(self):
pass
def test_dwithin(self):
s = GeoSeries(
[
Polygon([(0, 0), (1, 1), (0, 1)]),
LineString([(0, 0), (0, 2)]),
LineString([(0, 0), (0, 1)]),
Point(0, 1),
],
index=range(0, 4),
)
s2 = GeoSeries(
[
Polygon([(1, 0), (4, 2), (2, 2)]),
Polygon([(2, 0), (3, 2), (2, 2)]),
LineString([(2, 0), (2, 2)]),
Point(1, 1),
],
index=range(1, 5),
)
result = s2.dwithin(Point(0, 1), 1.8)
expected = pd.Series([True, False, False, True], index=range(1, 5))
assert_series_equal(result.to_pandas(), expected)
result = s.dwithin(s2, distance=1, align=True)
expected = pd.Series([False, True, False, False, False])
result = s.dwithin(s2, distance=1, align=False)
expected = pd.Series([True, False, False, True])
assert_series_equal(result.to_pandas(), expected)
# Check that GeoDataFrame works too
df_result = s.to_geoframe().dwithin(s2, distance=1, align=False).to_pandas()
assert_series_equal(df_result, expected)
def test_difference(self):
s = GeoSeries(
[
Polygon([(0, 0), (2, 2), (0, 2)]),
Polygon([(0, 0), (2, 2), (0, 2)]),
LineString([(0, 0), (2, 2)]),
LineString([(2, 0), (0, 2)]),
Point(0, 1),
],
)
s2 = GeoSeries(
[
Polygon([(0, 0), (1, 1), (0, 1)]),
LineString([(1, 0), (1, 3)]),
LineString([(2, 0), (0, 2)]),
Point(1, 1),
Point(0, 1),
],
index=range(1, 6),
)
result = s.difference(Polygon([(0, 0), (1, 1), (0, 1)]))
expected = gpd.GeoSeries(
[
Polygon([(0, 2), (2, 2), (1, 1), (0, 1), (0, 2)]),
Polygon([(0, 2), (2, 2), (1, 1), (0, 1), (0, 2)]),
LineString([(1, 1), (2, 2)]),
MultiLineString(
[LineString([(2, 0), (1, 1)]), LineString([(1, 1), (0, 2)])]
),
Point(),
]
)
self.check_sgpd_equals_gpd(result, expected)
result = s.difference(s2, align=True)
expected = gpd.GeoSeries(
[
None,
Polygon([(0, 2), (2, 2), (1, 1), (0, 1), (0, 2)]),
MultiLineString(
[LineString([(0, 0), (1, 1)]), LineString([(1, 1), (2, 2)])]
),
LineString(),
Point(0, 1),
None,
]
)
self.check_sgpd_equals_gpd(result, expected)
result = s.difference(s2, align=False)
expected = gpd.GeoSeries(
[
Polygon([(0, 2), (2, 2), (1, 1), (0, 1), (0, 2)]),
Polygon([(0, 0), (0, 2), (1, 2), (2, 2), (1, 1), (0, 0)]),
MultiLineString(
[LineString([(0, 0), (1, 1)]), LineString([(1, 1), (2, 2)])]
),
LineString([(2, 0), (0, 2)]),
Point(),
]
)
self.check_sgpd_equals_gpd(result, expected)
# Check that GeoDataFrame works too
df_result = s.to_geoframe().difference(s2, align=False)
self.check_sgpd_equals_gpd(df_result, expected)
def test_symmetric_difference(self):
s = GeoSeries(
[
Polygon([(0, 0), (2, 2), (0, 2)]),
Polygon([(0, 0), (2, 2), (0, 2)]),
LineString([(0, 0), (2, 2)]),
LineString([(2, 0), (0, 2)]),
Point(0, 1),
],
)
s2 = GeoSeries(
[
Polygon([(0, 0), (1, 1), (0, 1)]),
LineString([(1, 0), (1, 3)]),
LineString([(2, 0), (0, 2)]),
Point(1, 1),
Point(0, 1),
],
index=range(1, 6),
)
# Test with single geometry
result = s.symmetric_difference(Polygon([(0, 0), (1, 1), (0, 1)]))
expected = gpd.GeoSeries(
[
Polygon([(0, 2), (2, 2), (1, 1), (0, 1), (0, 2)]),
Polygon([(0, 2), (2, 2), (1, 1), (0, 1), (0, 2)]),
GeometryCollection(
[
Polygon([(0, 0), (0, 1), (1, 1), (0, 0)]),
LineString([(1, 1), (2, 2)]),
]
),
GeometryCollection(
[
Polygon([(0, 0), (0, 1), (1, 1), (0, 0)]),
LineString([(2, 0), (1, 1)]),
LineString([(1, 1), (0, 2)]),
]
),
Polygon([(0, 1), (1, 1), (0, 0), (0, 1)]),
]
)
self.check_sgpd_equals_gpd(result, expected)
# Test with align=True
result = s.symmetric_difference(s2, align=True)
expected = gpd.GeoSeries(
[
None,
Polygon([(0, 2), (2, 2), (1, 1), (0, 1), (0, 2)]),
MultiLineString(
[
LineString([(0, 0), (1, 1)]),
LineString([(1, 1), (2, 2)]),
LineString([(1, 0), (1, 1)]),
LineString([(1, 1), (1, 3)]),
]
),
LineString(),
MultiPoint([Point(0, 1), Point(1, 1)]),
None,
]
)
self.check_sgpd_equals_gpd(result, expected)
# Test with align=False
result = s.symmetric_difference(s2, align=False)
expected = gpd.GeoSeries(
[
Polygon([(0, 2), (2, 2), (1, 1), (0, 1), (0, 2)]),
GeometryCollection(
[
Polygon([(0, 0), (0, 2), (1, 2), (2, 2), (1, 1), (0, 0)]),
LineString([(1, 0), (1, 1)]),
LineString([(1, 1), (1, 3)]),
]
),
MultiLineString(
[
LineString([(0, 0), (1, 1)]),
LineString([(1, 1), (2, 2)]),
LineString([(2, 0), (1, 1)]),
LineString([(1, 1), (0, 2)]),
]
),
LineString([(2, 0), (0, 2)]),
Point(),
]
)
self.check_sgpd_equals_gpd(result, expected)
# Check that GeoDataFrame works too
df_result = s.to_geoframe().symmetric_difference(s2, align=False)
self.check_sgpd_equals_gpd(df_result, expected)
def test_union(self):
s = GeoSeries(
[
Polygon([(0, 0), (2, 2), (0, 2)]),
Polygon([(0, 0), (2, 2), (0, 2)]),
LineString([(0, 0), (2, 2)]),
LineString([(2, 0), (0, 2)]),
Point(0, 1),
],
)
s2 = GeoSeries(
[
Polygon([(0, 0), (1, 1), (0, 1)]),
LineString([(1, 0), (1, 3)]),
LineString([(2, 0), (0, 2)]),
Point(1, 1),
Point(0, 1),
],
index=range(1, 6),
)
# Test with single geometry
result = s.union(Polygon([(0, 0), (1, 1), (0, 1)]))
expected = gpd.GeoSeries(
[
Polygon([(0, 0), (0, 1), (0, 2), (2, 2), (1, 1), (0, 0)]),
Polygon([(0, 0), (0, 1), (0, 2), (2, 2), (1, 1), (0, 0)]),
GeometryCollection(
[
Polygon([(0, 0), (0, 1), (1, 1), (0, 0)]),
LineString([(0, 0), (2, 2)]),
]
),
GeometryCollection(
[
Polygon([(0, 0), (0, 1), (1, 1), (0, 0)]),
LineString([(2, 0), (0, 2)]),
]
),
Polygon([(0, 1), (1, 1), (0, 0), (0, 1)]),
]
)
self.check_sgpd_equals_gpd(result, expected)
# Test with align=True
result = s.union(s2, align=True)
expected = gpd.GeoSeries(
[
None,
Polygon([(0, 0), (0, 1), (0, 2), (2, 2), (1, 1), (0, 0)]),
MultiLineString(
[
LineString([(0, 0), (1, 1)]),
LineString([(1, 1), (2, 2)]),
LineString([(1, 0), (1, 1)]),
LineString([(1, 1), (1, 3)]),
]
),
LineString([(2, 0), (0, 2)]),
MultiPoint([Point(0, 1), Point(1, 1)]),
None,
]
)
self.check_sgpd_equals_gpd(result, expected)
# Test with align=False
result = s.union(s2, align=False)
expected = gpd.GeoSeries(
[
Polygon([(0, 0), (0, 1), (0, 2), (2, 2), (1, 1), (0, 0)]),
GeometryCollection(
[
Polygon([(0, 0), (0, 2), (1, 2), (2, 2), (1, 1), (0, 0)]),
LineString([(1, 0), (1, 1)]),
LineString([(1, 1), (1, 3)]),
]
),
MultiLineString(
[
LineString([(0, 0), (1, 1)]),
LineString([(1, 1), (2, 2)]),
LineString([(2, 0), (1, 1)]),
LineString([(1, 1), (0, 2)]),
]
),
LineString([(2, 0), (0, 2)]),
Point(0, 1),
]
)
self.check_sgpd_equals_gpd(result, expected)
# Check that GeoDataFrame works too
df_result = s.to_geoframe().union(s2, align=False)
self.check_sgpd_equals_gpd(df_result, expected)
def test_is_simple(self):
s = sgpd.GeoSeries(
[
LineString([(0, 0), (1, 1), (1, -1), (0, 1)]),
LineString([(0, 0), (1, 1), (1, -1)]),
LinearRing([(0, 0), (1, 1), (1, -1), (0, 1)]),
LinearRing([(0, 0), (-1, 1), (-1, -1), (1, -1)]),
]
)
result = s.is_simple
expected = pd.Series([False, True, False, True])
assert_series_equal(result.to_pandas(), expected)
# Check that GeoDataFrame works too
df_result = s.to_geoframe().is_simple.to_pandas()
assert_series_equal(df_result, expected)
def test_is_ring(self):
s = GeoSeries(
[
LineString([(0, 0), (1, 1), (1, -1)]),
LineString([(0, 0), (1, 1), (1, -1), (0, 0)]),
LinearRing([(0, 0), (1, 1), (1, -1)]),
]
)
result = s.is_ring
expected = pd.Series([False, True, True])
self.check_pd_series_equal(result, expected)
# Check that GeoDataFrame works too
result = s.to_geoframe().is_ring
self.check_pd_series_equal(result, expected)
def test_is_ccw(self):
pass
def test_is_closed(self):
s = GeoSeries(
[
LineString([(0, 0), (1, 1), (1, -1)]),
LineString([(0, 0), (1, 1), (1, -1), (0, 0)]),
LinearRing([(0, 0), (1, 1), (1, -1)]),
]
)
result = s.is_closed
expected = pd.Series([False, True, True])
self.check_pd_series_equal(result, expected)
# Check that GeoDataFrame works too
result = s.to_geoframe().is_closed
self.check_pd_series_equal(result, expected)
def test_has_z(self):
s = sgpd.GeoSeries(
[
Point(0, 1),
Point(0, 1, 2),
Polygon([(0, 0, 1), (0, 1, 2), (1, 1, 3), (0, 0, 1)]),
Polygon([(0, 0), (0, 1), (1, 1), (0, 0)]),
]
)
result = s.has_z
expected = pd.Series([False, True, True, False])
assert_series_equal(result.to_pandas(), expected)
# Check that GeoDataFrame works too
df_result = s.to_geoframe().has_z.to_pandas()
assert_series_equal(df_result, expected)
def test_get_precision(self):
pass
def test_get_geometry(self):
# Shapely 1 seems to have a bug where Polygon() is incorrectly interpreted as a GeometryCollection
if shapely.__version__ < "2.0.0":
return
from shapely.geometry import MultiPoint
s = GeoSeries(
[
Point(0, 0),
MultiPoint([(0, 0), (1, 1), (0, 1), (1, 0)]),
GeometryCollection(
[MultiPoint([(0, 0), (1, 1), (0, 1), (1, 0)]), Point(0, 1)]
),
Polygon(),
GeometryCollection(),
]
)
result = s.get_geometry(0)
expected = gpd.GeoSeries(
[
Point(0, 0),
Point(0, 0),
MultiPoint([(0, 0), (1, 1), (0, 1), (1, 0)]),
Polygon(),
None,
]
)
self.check_sgpd_equals_gpd(result, expected)
result = s.get_geometry(1)
expected = gpd.GeoSeries([None, Point(1, 1), Point(0, 1), None, None])
self.check_sgpd_equals_gpd(result, expected)
result = s.get_geometry(-1)
expected = gpd.GeoSeries(
[Point(0, 0), Point(1, 0), Point(0, 1), Polygon(), None]
)
self.check_sgpd_equals_gpd(result, expected)
result = s.get_geometry(2)
expected = gpd.GeoSeries([None, Point(0, 1), None, None, None])
self.check_sgpd_equals_gpd(result, expected)
# Check that GeoDataFrame works too
df_result = s.to_geoframe().get_geometry(2)
self.check_sgpd_equals_gpd(df_result, expected)
def test_boundary(self):
s = sgpd.GeoSeries(
[
Polygon([(0, 0), (1, 1), (0, 1)]),
LineString([(0, 0), (1, 1), (1, 0)]),
Point(0, 0),
GeometryCollection([Point(0, 0)]),
]
)
result = s.boundary
expected = gpd.GeoSeries(
[
LineString([(0, 0), (1, 1), (0, 1), (0, 0)]),
MultiPoint([(0, 0), (1, 0)]),
GeometryCollection([]),
None,
]
)
self.check_sgpd_equals_gpd(result, expected)
# Check that GeoDataFrame works too
df_result = s.to_geoframe().boundary
self.check_sgpd_equals_gpd(df_result, expected)
def test_centroid(self):
s = sgpd.GeoSeries(
[
Polygon([(0, 0), (1, 1), (0, 1)]),
LineString([(0, 0), (1, 1), (1, 0)]),
Point(0, 0),
]
)
result = s.centroid
expected = gpd.GeoSeries(
[
Point(0.3333333333333333, 0.6666666666666666),
Point(0.7071067811865476, 0.5),
Point(0, 0),
]
)
self.check_sgpd_equals_gpd(result, expected)
def test_concave_hull(self):
pass
def test_convex_hull(self):
pass
def test_delaunay_triangles(self):
pass
def test_voronoi_polygons(self):
pass
def test_envelope(self):
s = sgpd.GeoSeries(
[
Polygon([(0, 0), (1, 1), (0, 1)]),
LineString([(0, 0), (1, 1), (1, 0)]),
MultiPoint([(0, 0), (1, 1)]),
Point(0, 0),
]
)
result = s.envelope
expected = gpd.GeoSeries(
[
Polygon([(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)]),
Polygon([(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)]),
Polygon([(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)]),
Point(0, 0),
]
)
self.check_sgpd_equals_gpd(result, expected)
# Check that GeoDataFrame works too
df_result = s.to_geoframe().envelope
self.check_sgpd_equals_gpd(df_result, expected)
def test_minimum_rotated_rectangle(self):
pass
def test_exterior(self):
pass
def test_extract_unique_points(self):
pass
def test_offset_curve(self):
pass
def test_interiors(self):
pass
def test_remove_repeated_points(self):
pass
def test_set_precision(self):
pass
def test_representative_point(self):
pass
def test_minimum_bounding_circle(self):
pass
def test_minimum_bounding_radius(self):
pass
def test_minimum_clearance(self):
pass
def test_normalize(self):
pass
def test_make_valid(self):
s = sgpd.GeoSeries(
[
Polygon([(0, 0), (0, 2), (1, 1), (2, 2), (2, 0), (1, 1), (0, 0)]),
Polygon([(0, 2), (0, 1), (2, 0), (0, 0), (0, 2)]),
LineString([(0, 0), (1, 1), (1, 0)]),
],
)
result = s.make_valid(method="structure")
expected = gpd.GeoSeries(
[
MultiPolygon(
[
Polygon([(1, 1), (0, 0), (0, 2), (1, 1)]),
Polygon([(2, 0), (1, 1), (2, 2), (2, 0)]),
]
),
Polygon([(0, 1), (2, 0), (0, 0), (0, 1)]),
LineString([(0, 0), (1, 1), (1, 0)]),
]
)
self.check_sgpd_equals_gpd(result, expected)
result = s.make_valid(method="structure", keep_collapsed=False)
expected = gpd.GeoSeries(
[
MultiPolygon(
[
Polygon([(1, 1), (0, 0), (0, 2), (1, 1)]),
Polygon([(2, 0), (1, 1), (2, 2), (2, 0)]),
]
),
Polygon([(0, 1), (2, 0), (0, 0), (0, 1)]),
LineString([(0, 0), (1, 1), (1, 0)]),
]
)
self.check_sgpd_equals_gpd(result, expected)
s = GeoSeries([Polygon([(0, 0), (1, 1), (1, 2), (1, 1), (0, 0)])])
result = s.make_valid(method="structure", keep_collapsed=True)
expected = gpd.GeoSeries([LineString([(0, 0), (1, 1), (1, 2), (1, 1), (0, 0)])])
self.check_sgpd_equals_gpd(result, expected)
result = s.make_valid(method="structure", keep_collapsed=False)
expected = gpd.GeoSeries([Polygon()])
self.check_sgpd_equals_gpd(result, expected)
# Check that GeoDataFrame works too
df_result = s.to_geoframe().make_valid(method="structure", keep_collapsed=False)
self.check_sgpd_equals_gpd(df_result, expected)
def test_reverse(self):
pass
def test_segmentize(self):
s = GeoSeries(
[
LineString([(0, 0), (0, 10)]),
Polygon([(0, 0), (10, 0), (10, 10), (0, 10), (0, 0)]),
],
)
result = s.segmentize(5)
expected = gpd.GeoSeries(
[
LineString([(0, 0), (0, 5), (0, 10)]),
Polygon(
[
(0, 0),
(5, 0),
(10, 0),
(10, 5),
(10, 10),
(5, 10),
(0, 10),
(0, 5),
(0, 0),
]
),
],
)
self.check_sgpd_equals_gpd(result, expected)
df_result = s.to_geoframe().segmentize(5)
self.check_sgpd_equals_gpd(df_result, expected)
def test_transform(self):
pass
def test_force_2d(self):
pass
def test_force_3d(self):
pass
def test_line_merge(self):
pass
def test_unary_union(self):
pass
def test_union_all(self):
s = GeoSeries([box(0, 0, 1, 1), box(0, 0, 2, 2)])
result = s.union_all()
expected = Polygon([(0, 1), (0, 2), (2, 2), (2, 0), (1, 0), (0, 0), (0, 1)])
self.check_geom_equals(result, expected)
# Check that GeoDataFrame works too
df_result = s.to_geoframe().union_all()
self.check_geom_equals(df_result, expected)
# Empty GeoSeries
s = sgpd.GeoSeries([])
result = s.union_all()
expected = GeometryCollection()
self.check_geom_equals(result, expected)
def test_row_wise_dataframe(self):
s = GeoSeries(
[
Polygon([(0, 0), (1, 1), (0, 1)]),
Polygon([(0, 0), (1, 1), (0, 1)]),
Polygon([(0, 0), (1, 1), (0, 1)]),
]
)
s2 = GeoSeries([Point(-5.5, 1), Point(1, 2), Point(3, 1)])
# self: GeoSeries, other: GeoDataFrame
expected = pd.Series([5.5, 1, 2])
result = s.distance(s2.to_geoframe())
self.check_pd_series_equal(result, expected)
# self: GeoDataFrame, other: GeoDataFrame
result = s.to_geoframe().distance(s2.to_geoframe())
assert_series_equal(result.to_pandas(), expected)
# Same but for overlay
expected = gpd.GeoSeries(
[
Polygon([(0, 0), (1, 1), (0, 1), (0, 0)]),
Polygon([(0, 0), (1, 1), (0, 1), (0, 0)]),
Polygon([(0, 0), (1, 1), (0, 1), (0, 0)]),
]
)
result = s.difference(s2.to_geoframe())
self.check_sgpd_equals_gpd(result, expected)
result = s.to_geoframe().difference(s2.to_geoframe())
self.check_sgpd_equals_gpd(result, expected)
def test_crosses(self):
s = GeoSeries(
[
Polygon([(0, 0), (2, 2), (0, 2)]),
LineString([(0, 0), (2, 2)]),
LineString([(2, 0), (0, 2)]),
Point(0, 1),
],
)
s2 = GeoSeries(
[
LineString([(1, 0), (1, 3)]),
LineString([(2, 0), (0, 2)]),
Point(1, 1),
Point(0, 1),
],
index=range(1, 5),
)
line = LineString([(-1, 1), (3, 1)])
result = s.crosses(line)
expected = pd.Series([True, True, True, False])
assert_series_equal(result.to_pandas(), expected)
result = s.crosses(s2, align=True)
expected = pd.Series([False, True, False, False, False])
assert_series_equal(result.to_pandas(), expected)
result = s.crosses(s2, align=False)
expected = pd.Series([True, True, False, False])
assert_series_equal(result.to_pandas(), expected)
# Check that GeoDataFrame works too
df_result = s.to_geoframe().crosses(s2, align=False).to_pandas()
assert_series_equal(df_result, expected)
def test_disjoint(self):
pass
def test_intersects(self):
s = sgpd.GeoSeries(
[
Polygon([(0, 0), (2, 2), (0, 2)]),
LineString([(0, 0), (2, 2)]),
LineString([(2, 0), (0, 2)]),
Point(0, 1),
],
)
s2 = sgpd.GeoSeries(
[
LineString([(1, 0), (1, 3)]),
LineString([(2, 0), (0, 2)]),
Point(1, 1),
Point(-100, -100),
],
)
result = s.intersects(s2)
expected = pd.Series([True, True, True, False])
assert_series_equal(result.to_pandas(), expected)
line = LineString([(-1, 1), (3, 1)])
result = s.intersects(line)
expected = pd.Series([True, True, True, True])
assert_series_equal(result.to_pandas(), expected)
# from the original doc string
s2 = sgpd.GeoSeries(
[
LineString([(1, 0), (1, 3)]),
LineString([(2, 0), (0, 2)]),
Point(1, 1),
Point(0, 1),
],
index=range(1, 5),
)
result = s.intersects(s2, align=True)
expected = pd.Series([False, True, True, False, False])
result = s.intersects(s2, align=False)
expected = pd.Series([True, True, True, True])
# Check that GeoDataFrame works too
df_result = s.to_geoframe().intersects(s2, align=False).to_pandas()
assert_series_equal(df_result, expected)
def test_overlaps(self):
s = GeoSeries(
[
Polygon([(0, 0), (2, 2), (0, 2)]),
Polygon([(0, 0), (2, 2), (0, 2)]),
LineString([(0, 0), (2, 2)]),
MultiPoint([(0, 0), (0, 1)]),
],
)
s2 = GeoSeries(
[
Polygon([(0, 0), (2, 0), (0, 2)]),
LineString([(0, 1), (1, 1)]),
LineString([(1, 1), (3, 3)]),
Point(0, 1),
],
index=range(1, 5),
)
polygon = Polygon([(0, 0), (1, 0), (1, 1), (0, 1)])
result = s.overlaps(polygon)
expected = pd.Series([True, True, False, False])
assert_series_equal(result.to_pandas(), expected)
result = s.overlaps(s2, align=True)
expected = pd.Series([False, True, False, False, False])
assert_series_equal(result.to_pandas(), expected)
result = s.overlaps(s2, align=False)
expected = pd.Series([True, False, True, False])
assert_series_equal(result.to_pandas(), expected)
# Check that GeoDataFrame works too
df_result = s.to_geoframe().overlaps(s2, align=False)
assert_series_equal(df_result.to_pandas(), expected)
def test_touches(self):
s = GeoSeries(
[
Polygon([(0, 0), (2, 2), (0, 2)]),
Polygon([(0, 0), (2, 2), (0, 2)]),
LineString([(0, 0), (2, 2)]),
MultiPoint([(0, 0), (0, 1)]),
],
)
s2 = GeoSeries(
[
Polygon([(0, 0), (-2, 0), (0, -2)]),
LineString([(0, 1), (1, 1)]),
LineString([(1, 1), (3, 0)]),
Point(0, 1),
],
index=range(1, 5),
)
line = LineString([(0, 0), (-1, -2)])
result = s.touches(line)
expected = pd.Series([True, True, True, True])
assert_series_equal(result.to_pandas(), expected)
result = s.touches(s2, align=True)
expected = pd.Series([False, True, True, False, False])
assert_series_equal(result.to_pandas(), expected)
result = s.touches(s2, align=False)
expected = pd.Series([True, False, True, False])
assert_series_equal(result.to_pandas(), expected)
# Check that GeoDataFrame works too
df_result = s.to_geoframe().touches(s2, align=False)
assert_series_equal(df_result.to_pandas(), expected)
def test_within(self):
s = GeoSeries(
[
Polygon([(0, 0), (2, 2), (0, 2)]),
Polygon([(0, 0), (1, 2), (0, 2)]),
LineString([(0, 0), (0, 2)]),
Point(0, 1),
],
)
s2 = GeoSeries(
[
Polygon([(0, 0), (1, 1), (0, 1)]),
LineString([(0, 0), (0, 2)]),
LineString([(0, 0), (0, 1)]),
Point(0, 1),
],
index=range(1, 5),
)
polygon = Polygon([(0, 0), (2, 2), (0, 2)])
result = s.within(polygon)
expected = pd.Series([True, True, False, False])
assert_series_equal(result.to_pandas(), expected)
result = s2.within(s, align=True)
expected = pd.Series([False, False, True, False, False])
assert_series_equal(result.to_pandas(), expected)
result = s2.within(s, align=False)
expected = pd.Series([True, False, True, True], index=range(1, 5))
assert_series_equal(result.to_pandas(), expected)
# Ensure we return False if either geometries are empty
s = GeoSeries([Point(), Point(), Polygon(), Point(0, 1)])
result = s.within(s2, align=False)
expected = pd.Series([False, False, False, True])
assert_series_equal(result.to_pandas(), expected)
# Check that GeoDataFrame works too
df_result = s.to_geoframe().within(s2, align=False)
assert_series_equal(df_result.to_pandas(), expected)
def test_covers(self):
s = GeoSeries(
[
Polygon([(0, 0), (2, 0), (2, 2), (0, 2)]),
Polygon([(0, 0), (2, 2), (0, 2)]),
LineString([(0, 0), (2, 2)]),
Point(0, 0),
],
)
s2 = GeoSeries(
[
Polygon([(0.5, 0.5), (1.5, 0.5), (1.5, 1.5), (0.5, 1.5)]),
Polygon([(0, 0), (2, 0), (2, 2), (0, 2)]),
LineString([(1, 1), (1.5, 1.5)]),
Point(0, 0),
],
index=range(1, 5),
)
poly = Polygon([(0, 0), (2, 0), (2, 2), (0, 2)])
result = s.covers(poly)
expected = pd.Series([True, False, False, False])
assert_series_equal(result.to_pandas(), expected)
result = s.covers(s2, align=True)
expected = pd.Series([False, False, False, False, False])
assert_series_equal(result.to_pandas(), expected)
result = s.covers(s2, align=False)
expected = pd.Series([True, False, True, True])
assert_series_equal(result.to_pandas(), expected)
# Ensure we return False if either geometries are empty
s = GeoSeries([Point(), Point(), Polygon(), Point(0, 0)])
result = s.covers(s2, align=False)
expected = pd.Series([False, False, False, True])
assert_series_equal(result.to_pandas(), expected)
# Check that GeoDataFrame works too
df_result = s.to_geoframe().covers(s2, align=False)
assert_series_equal(df_result.to_pandas(), expected)
def test_covered_by(self):
s = GeoSeries(
[
Polygon([(0.5, 0.5), (1.5, 0.5), (1.5, 1.5), (0.5, 1.5)]),
Polygon([(0, 0), (2, 0), (2, 2), (0, 2)]),
LineString([(1, 1), (1.5, 1.5)]),
Point(0, 0),
],
)
s2 = GeoSeries(
[
Polygon([(0, 0), (2, 0), (2, 2), (0, 2)]),
Polygon([(0, 0), (2, 2), (0, 2)]),
LineString([(0, 0), (2, 2)]),
Point(0, 0),
],
index=range(1, 5),
)
poly = Polygon([(0, 0), (2, 0), (2, 2), (0, 2)])
result = s.covered_by(poly)
expected = pd.Series([True, True, True, True])
assert_series_equal(result.to_pandas(), expected)
result = s.covered_by(s2, align=True)
expected = pd.Series([False, True, True, True, False])
assert_series_equal(result.to_pandas(), expected)
result = s.covered_by(s2, align=False)
expected = pd.Series([True, False, True, True])
assert_series_equal(result.to_pandas(), expected)
# Check that GeoDataFrame works too
df_result = s.to_geoframe().covered_by(s2, align=False)
assert_series_equal(df_result.to_pandas(), expected)
def test_distance(self):
s = GeoSeries(
[
Polygon([(0, 0), (1, 0), (1, 1)]),
Polygon([(0, 0), (-1, 0), (-1, 1)]),
LineString([(1, 1), (0, 0)]),
Point(0, 0),
],
)
s2 = GeoSeries(
[
Polygon([(0.5, 0.5), (1.5, 0.5), (1.5, 1.5), (0.5, 1.5)]),
Point(3, 1),
LineString([(1, 0), (2, 0)]),
Point(0, 1),
],
index=range(1, 5),
)
point = Point(-1, 0)
result = s.distance(point)
expected = pd.Series([1.0, 0.0, 1.0, 1.0])
assert_series_equal(result.to_pandas(), expected)
result = s.distance(s2, align=True)
expected = pd.Series([np.nan, 0.707107, 2.000000, 1.000000, np.nan])
assert_series_equal(result.to_pandas(), expected)
result = s.distance(s2, align=False)
expected = pd.Series([0.000000, 3.162278, 0.707107, 1.000000])
assert_series_equal(result.to_pandas(), expected)
# Check that GeoDataFrame works too
df_result = s.to_geoframe().distance(s2, align=False)
assert_series_equal(df_result.to_pandas(), expected)
def test_intersection(self):
s = sgpd.GeoSeries(
[
Polygon([(0, 0), (2, 2), (0, 2)]),
Polygon([(0, 0), (2, 2), (0, 2)]),
LineString([(0, 0), (2, 2)]),
LineString([(2, 0), (0, 2)]),
Point(0, 1),
],
)
geom = Polygon(
[(-0.5, -0.5), (-0.5, 2.5), (2.5, 2.5), (2.5, -0.5), (-0.5, -0.5)]
)
result = s.intersection(geom)
result.sort_index(inplace=True)
expected = gpd.GeoSeries(
[
Polygon([(0, 0), (2, 2), (0, 2)]),
Polygon([(0, 0), (2, 2), (0, 2)]),
LineString([(0, 0), (2, 2)]),
LineString([(2, 0), (0, 2)]),
Point(0, 1),
]
)
self.check_sgpd_equals_gpd(result, expected)
s2 = sgpd.GeoSeries(
[
Polygon([(0, 0), (1, 1), (0, 1)]),
LineString([(1, 0), (1, 3)]),
LineString([(2, 0), (0, 2)]),
Point(1, 1),
Point(-100, -100),
],
)
result = s.intersection(s2)
result.sort_index(inplace=True)
expected = gpd.GeoSeries(
[
Polygon([(0, 0), (0, 1), (1, 1), (0, 0)]),
LineString([(1, 1), (1, 2)]),
Point(1, 1),
Point(1, 1),
Point(),
]
)
self.check_sgpd_equals_gpd(result, expected)
# from the original doc string
s = sgpd.GeoSeries(
[
Polygon([(0, 0), (2, 2), (0, 2)]),
Polygon([(0, 0), (2, 2), (0, 2)]),
LineString([(0, 0), (2, 2)]),
LineString([(2, 0), (0, 2)]),
Point(0, 1),
],
)
s2 = sgpd.GeoSeries(
[
Polygon([(0, 0), (1, 1), (0, 1)]),
LineString([(1, 0), (1, 3)]),
LineString([(2, 0), (0, 2)]),
Point(1, 1),
Point(0, 1),
],
index=range(1, 6),
crs=4326,
)
# Ensure the index is preserved when crs is set (previously an issue)
expected_index = ps.Index(range(1, 6))
with ps.option_context("compute.ops_on_diff_frames", True):
assert s2.index.equals(expected_index)
result = s.intersection(s2, align=True)
result.sort_index(inplace=True)
expected = gpd.GeoSeries(
[
None,
Polygon([(0, 0), (0, 1), (1, 1), (0, 0)]),
Point(1, 1),
LineString([(2, 0), (0, 2)]),
Point(),
None,
]
)
self.check_sgpd_equals_gpd(result, expected)
# Check that GeoDataFrame works too
df_result = s.to_geoframe().intersection(s2, align=True)
df_result.sort_index(inplace=True)
self.check_sgpd_equals_gpd(df_result, expected)
result = s2.intersection(s, align=False)
result.sort_index(inplace=True)
expected = gpd.GeoSeries(
[
Polygon([(0, 0), (0, 1), (1, 1), (0, 0)]),
LineString([(1, 1), (1, 2)]),
Point(1, 1),
Point(1, 1),
Point(0, 1),
],
index=range(1, 6), # left's index
)
self.check_sgpd_equals_gpd(result, expected)
# Ensure result of align=False retains the left's index
assert result.index.to_pandas().equals(expected.index)
# Check that GeoDataFrame works too
df_result = s2.to_geoframe().intersection(s, align=False)
df_result.sort_index(inplace=True)
self.check_sgpd_equals_gpd(df_result, expected)
def test_snap(self):
s = GeoSeries(
[
Point(0.5, 2.5),
LineString([(0.1, 0.1), (0.49, 0.51), (1.01, 0.89)]),
Polygon([(0, 0), (0, 10), (10, 10), (10, 0), (0, 0)]),
],
)
s2 = GeoSeries(
[
Point(0, 2),
LineString([(0, 0), (0.5, 0.5), (1.0, 1.0)]),
Point(8, 10),
],
index=range(1, 4),
)
result = s.snap(Point(0, 2), tolerance=1)
expected = gpd.GeoSeries(
[
Point(0, 2),
LineString([(0.1, 0.1), (0.49, 0.51), (1.01, 0.89)]),
Polygon([(0, 0), (0, 2), (0, 10), (10, 10), (10, 0), (0, 0)]),
]
)
self.check_sgpd_equals_gpd(result, expected)
# Note: This test result slightly differs from the original geopandas's result,
# which doesn't include the Point(0, 0) in the Polygon below.
result = s.snap(s2, tolerance=1, align=True)
expected = gpd.GeoSeries(
[
None,
LineString([(0.1, 0.1), (0.49, 0.51), (1.01, 0.89)]),
Polygon(
[(0, 0), (0.5, 0.5), (1, 1), (0, 10), (10, 10), (10, 0), (0, 0)]
),
None,
]
)
self.check_sgpd_equals_gpd(result, expected)
result = s.snap(s2, tolerance=1, align=False)
expected = gpd.GeoSeries(
[
Point(0, 2),
LineString([(0, 0), (0.5, 0.5), (1, 1)]),
Polygon([(0, 0), (0, 10), (8, 10), (10, 10), (10, 0), (0, 0)]),
]
)
self.check_sgpd_equals_gpd(result, expected)
# Check that GeoDataFrame works too
df_result = s.to_geoframe().snap(s2, tolerance=1, align=False)
self.check_sgpd_equals_gpd(df_result, expected)
def test_intersection_all(self):
pass
def test_contains(self):
s = GeoSeries(
[
Polygon([(0, 0), (1, 1), (0, 1)]),
LineString([(0, 0), (0, 2)]),
LineString([(0, 0), (0, 1)]),
Point(0, 1),
],
index=range(0, 4),
)
s2 = GeoSeries(
[
Polygon([(0, 0), (2, 2), (0, 2)]),
Polygon([(0, 0), (1, 2), (0, 2)]),
LineString([(0, 0), (0, 2)]),
Point(0, 1),
],
index=range(1, 5),
)
point = Point(0, 1)
result = s.contains(point)
expected = pd.Series([False, True, False, True])
assert_series_equal(result.to_pandas(), expected)
result = s2.contains(s, align=True)
expected = pd.Series([False, False, False, True, False])
assert_series_equal(result.to_pandas(), expected)
result = s2.contains(s, align=False)
expected = pd.Series([True, False, True, True], index=range(1, 5))
assert_series_equal(result.to_pandas(), expected)
# Check that GeoDataFrame works too
df_result = s2.to_geoframe().contains(s, align=False)
assert_series_equal(df_result.to_pandas(), expected)
def test_contains_properly(self):
pass
def test_relate(self):
s = GeoSeries(
[
Point(0, 0),
Point(0, 0),
LineString([(0, 0), (1, 1)]),
]
)
s2 = GeoSeries(
[
Point(0, 0),
Point(1, 1),
LineString([(0, 0), (1, 1)]),
]
)
# "ABCDEFGHI" DE-9 Format
# A Dimension of intersection
# B Dimension of interior intersection
# C Dimension of boundary intersection
# D Interior of first geometry intersects exterior of second
# E Exterior of first geometry intersects interior of second
# F Boundary of first geometry intersects exterior of second
# G Exterior of first geometry intersects boundary of second
# H Exterior of first geometry intersects exterior of second
# I Dimension of intersection for interiors
# 0 = false, 1 = point, 2 = line, F = area
# 1. Test with single geometry
point = Point(0, 0)
result = s.relate(point)
expected = pd.Series(["0FFFFFFF2", "0FFFFFFF2", "FF10F0FF2"])
self.check_pd_series_equal(result, expected)
result = s.relate(s2)
expected = pd.Series(["0FFFFFFF2", "FF0FFF0F2", "1FFF0FFF2"])
self.check_pd_series_equal(result, expected)
# 2. Test with align=True (different indices)
s3 = GeoSeries(
[
Point(0, 0),
Point(1, 1),
],
index=range(1, 3),
)
s4 = GeoSeries(
[
Point(0, 0),
Point(1, 1),
],
index=range(0, 2),
)
result = s3.relate(s4, align=True)
expected = pd.Series([None, "FF0FFF0F2", None], index=[0, 1, 2])
self.check_pd_series_equal(result, expected)
# 3. Test with align=False
result = s3.relate(s4, align=False)
expected = pd.Series(["0FFFFFFF2", "0FFFFFFF2"], index=range(1, 3))
self.check_pd_series_equal(result, expected)
# 4. Check that GeoDataFrame works too
df_result = s.to_geoframe().relate(s2, align=False)
expected = pd.Series(["0FFFFFFF2", "FF0FFF0F2", "1FFF0FFF2"])
self.check_pd_series_equal(df_result, expected)
# 5. touching_polygons and overlapping polygon case
touching_poly_a = Polygon(((0, 0), (1, 0), (1, 1), (0, 1), (0, 0)))
touching_poly_b = Polygon(((1, 0), (2, 0), (2, 1), (1, 1), (1, 0)))
overlapping_poly_a = Polygon(((0, 0), (2, 0), (2, 2), (0, 2), (0, 0)))
overlapping_poly_b = Polygon(((1, 1), (3, 1), (3, 3), (1, 3), (1, 1)))
s5 = GeoSeries([touching_poly_a, overlapping_poly_a])
s6 = GeoSeries([touching_poly_b, overlapping_poly_b])
result = s5.relate(s6)
expected = pd.Series(["FF2F11212", "212101212"])
self.check_pd_series_equal(result, expected)
def test_set_crs(self):
geo_series = sgpd.GeoSeries([Point(0, 0), Point(1, 1)], name="geometry")
assert geo_series.crs == None
geo_series = geo_series.set_crs(epsg=4326)
assert geo_series.crs.to_epsg() == 4326
with pytest.raises(ValueError):
geo_series.set_crs(4328, allow_override=False)
with pytest.raises(ValueError):
geo_series.set_crs(None, allow_override=False)
geo_series = geo_series.set_crs(None, allow_override=True)
assert geo_series.crs == None
# Check that the name is preserved for set_crs
geo_series.name = "geometry"
geo_series.set_crs(4326, inplace=True)
assert geo_series.crs.to_epsg() == 4326
# Check that the name is preserved for set_crs after inplace=True
geo_series.name = "geometry"
geo_series = sgpd.GeoSeries(self.geoseries, crs=4326)
assert geo_series.crs.to_epsg() == 4326
# This test errors due to a bug in pyspark.
# We can uncomment it once the fix is https://github.com/apache/spark/pull/51475 is merged
# It was tested locally by using the fixed version of pyspark
# # First element null
# geo_series = sgpd.GeoSeries([None, None, Point(1, 1)], crs=4326)
# assert geo_series.crs.to_epsg() == 4326