that's too much!

This commit is contained in:
2024-12-19 20:22:56 -08:00
parent 0020a609dd
commit 32cd60e92b
8443 changed files with 1446950 additions and 42 deletions

View File

@@ -0,0 +1,986 @@
import random
import numpy as np
import pandas as pd
from pyproj import CRS
import shapely
import shapely.affinity
import shapely.geometry
from shapely.geometry.base import CAP_STYLE, JOIN_STYLE, BaseGeometry
import shapely.wkb
import shapely.wkt
try:
from shapely import geos_version
except ImportError:
from shapely._buildcfg import geos_version
import geopandas
from geopandas.array import (
GeometryArray,
from_shapely,
from_wkb,
from_wkt,
points_from_xy,
to_wkb,
to_wkt,
_check_crs,
_crs_mismatch_warn,
)
import geopandas._compat as compat
import pytest
triangle_no_missing = [
shapely.geometry.Polygon([(random.random(), random.random()) for i in range(3)])
for _ in range(10)
]
triangles = triangle_no_missing + [shapely.wkt.loads("POLYGON EMPTY"), None]
T = from_shapely(triangles)
points_no_missing = [
shapely.geometry.Point(random.random(), random.random()) for _ in range(20)
]
points = points_no_missing + [None]
P = from_shapely(points)
def equal_geometries(result, expected):
for r, e in zip(result, expected):
if r is None or e is None:
if not (r is None and e is None):
return False
elif not r.equals(e):
return False
return True
def test_points():
x = np.arange(10).astype(np.float64)
y = np.arange(10).astype(np.float64) ** 2
points = points_from_xy(x, y)
assert isinstance(points, GeometryArray)
for i in range(10):
assert isinstance(points[i], shapely.geometry.Point)
assert points[i].x == x[i]
assert points[i].y == y[i]
def test_points_from_xy():
# testing the top-level interface
# using DataFrame column
df = pd.DataFrame([{"x": x, "y": x, "z": x} for x in range(10)])
gs = [shapely.geometry.Point(x, x) for x in range(10)]
gsz = [shapely.geometry.Point(x, x, x) for x in range(10)]
geometry1 = geopandas.points_from_xy(df["x"], df["y"])
geometry2 = geopandas.points_from_xy(df["x"], df["y"], df["z"])
assert isinstance(geometry1, GeometryArray)
assert isinstance(geometry2, GeometryArray)
assert list(geometry1) == gs
assert list(geometry2) == gsz
# using Series or numpy arrays or lists
for s in [pd.Series(range(10)), np.arange(10), list(range(10))]:
geometry1 = geopandas.points_from_xy(s, s)
geometry2 = geopandas.points_from_xy(s, s, s)
assert isinstance(geometry1, GeometryArray)
assert isinstance(geometry2, GeometryArray)
assert list(geometry1) == gs
assert list(geometry2) == gsz
# using different lengths should throw error
arr_10 = np.arange(10)
arr_20 = np.arange(20)
with pytest.raises(ValueError):
geopandas.points_from_xy(x=arr_10, y=arr_20)
geopandas.points_from_xy(x=arr_10, y=arr_10, z=arr_20)
# Using incomplete arguments should throw error
with pytest.raises(TypeError):
geopandas.points_from_xy(x=s)
geopandas.points_from_xy(y=s)
geopandas.points_from_xy(z=s)
def test_from_shapely():
assert isinstance(T, GeometryArray)
assert equal_geometries(T, triangles)
def test_from_shapely_geo_interface():
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
@property
def __geo_interface__(self):
return {"type": "Point", "coordinates": (self.x, self.y)}
result = from_shapely([Point(1.0, 2.0), Point(3.0, 4.0)])
expected = from_shapely(
[shapely.geometry.Point(1.0, 2.0), shapely.geometry.Point(3.0, 4.0)]
)
assert all(v.equals(t) for v, t in zip(result, expected))
def test_from_wkb():
# list
L_wkb = [p.wkb for p in points_no_missing]
res = from_wkb(L_wkb)
assert isinstance(res, GeometryArray)
assert all(v.equals(t) for v, t in zip(res, points_no_missing))
# array
res = from_wkb(np.array(L_wkb, dtype=object))
assert isinstance(res, GeometryArray)
assert all(v.equals(t) for v, t in zip(res, points_no_missing))
# missing values
# TODO(pygeos) does not support empty strings, np.nan, or pd.NA
missing_values = [None]
if not (compat.USE_SHAPELY_20 or compat.USE_PYGEOS):
missing_values.extend([b"", np.nan])
missing_values.append(pd.NA)
res = from_wkb(missing_values)
np.testing.assert_array_equal(res, np.full(len(missing_values), None))
# single MultiPolygon
multi_poly = shapely.geometry.MultiPolygon(
[shapely.geometry.box(0, 0, 1, 1), shapely.geometry.box(3, 3, 4, 4)]
)
res = from_wkb([multi_poly.wkb])
assert res[0] == multi_poly
def test_from_wkb_hex():
geometry_hex = ["0101000000CDCCCCCCCCCC1440CDCCCCCCCC0C4A40"]
res = from_wkb(geometry_hex)
assert isinstance(res, GeometryArray)
# array
res = from_wkb(np.array(geometry_hex, dtype=object))
assert isinstance(res, GeometryArray)
def test_to_wkb():
P = from_shapely(points_no_missing)
res = to_wkb(P)
exp = np.array([p.wkb for p in points_no_missing], dtype=object)
assert isinstance(res, np.ndarray)
np.testing.assert_array_equal(res, exp)
res = to_wkb(P, hex=True)
exp = np.array([p.wkb_hex for p in points_no_missing], dtype=object)
assert isinstance(res, np.ndarray)
np.testing.assert_array_equal(res, exp)
# missing values
a = from_shapely([None, points_no_missing[0]])
res = to_wkb(a)
assert res[0] is None
@pytest.mark.parametrize("string_type", ["str", "bytes"])
def test_from_wkt(string_type):
if string_type == "str":
f = str
else:
def f(x):
return bytes(x, "utf8")
# list
L_wkt = [f(p.wkt) for p in points_no_missing]
res = from_wkt(L_wkt)
assert isinstance(res, GeometryArray)
tol = 0.5 * 10 ** (-6)
assert all(v.equals_exact(t, tolerance=tol) for v, t in zip(res, points_no_missing))
assert all(v.equals_exact(t, tolerance=tol) for v, t in zip(res, points_no_missing))
# array
res = from_wkt(np.array(L_wkt, dtype=object))
assert isinstance(res, GeometryArray)
assert all(v.equals_exact(t, tolerance=tol) for v, t in zip(res, points_no_missing))
# missing values
# TODO(pygeos) does not support empty strings, np.nan, or pd.NA
missing_values = [None]
if not (compat.USE_SHAPELY_20 or compat.USE_PYGEOS):
missing_values.extend([f(""), np.nan])
missing_values.append(pd.NA)
res = from_wkb(missing_values)
np.testing.assert_array_equal(res, np.full(len(missing_values), None))
# single MultiPolygon
multi_poly = shapely.geometry.MultiPolygon(
[shapely.geometry.box(0, 0, 1, 1), shapely.geometry.box(3, 3, 4, 4)]
)
res = from_wkt([f(multi_poly.wkt)])
assert res[0] == multi_poly
def test_to_wkt():
P = from_shapely(points_no_missing)
res = to_wkt(P, rounding_precision=-1)
exp = np.array([p.wkt for p in points_no_missing], dtype=object)
assert isinstance(res, np.ndarray)
np.testing.assert_array_equal(res, exp)
# missing values
a = from_shapely([None, points_no_missing[0]])
res = to_wkt(a)
assert res[0] is None
def test_data():
arr = from_shapely(points_no_missing)
with pytest.warns(DeprecationWarning):
np_arr = arr.data
assert isinstance(np_arr, np.ndarray)
if compat.USE_PYGEOS:
np_arr2 = arr.to_numpy()
assert isinstance(np_arr2[0], BaseGeometry)
np_arr3 = np.asarray(arr)
assert isinstance(np_arr3[0], BaseGeometry)
else:
assert arr.to_numpy() is np_arr
assert np.asarray(arr) is np_arr
def test_as_array():
arr = from_shapely(points_no_missing)
np_arr1 = np.asarray(arr)
np_arr2 = arr.to_numpy()
assert np_arr1[0] == arr[0]
np.testing.assert_array_equal(np_arr1, np_arr2)
@pytest.mark.parametrize(
"attr,args",
[
("contains", ()),
("covers", ()),
("crosses", ()),
("disjoint", ()),
("geom_equals", ()),
("intersects", ()),
("overlaps", ()),
("touches", ()),
("within", ()),
("geom_equals_exact", (0.1,)),
("geom_almost_equals", (3,)),
],
)
def test_predicates_vector_scalar(attr, args):
na_value = False
point = points[0]
tri = triangles[0]
for other in [point, tri, shapely.geometry.Polygon()]:
result = getattr(T, attr)(other, *args)
assert isinstance(result, np.ndarray)
assert result.dtype == bool
expected = [
getattr(tri, attr if "geom" not in attr else attr[5:])(other, *args)
if tri is not None
else na_value
for tri in triangles
]
assert result.tolist() == expected
# TODO other is missing
@pytest.mark.parametrize(
"attr,args",
[
("contains", ()),
("covers", ()),
("crosses", ()),
("disjoint", ()),
("geom_equals", ()),
("intersects", ()),
("overlaps", ()),
("touches", ()),
("within", ()),
("geom_equals_exact", (0.1,)),
("geom_almost_equals", (3,)),
],
)
def test_predicates_vector_vector(attr, args):
na_value = False
empty_value = True if attr == "disjoint" else False
A = (
[shapely.geometry.Polygon(), None]
+ [
shapely.geometry.Polygon(
[(random.random(), random.random()) for i in range(3)]
)
for _ in range(100)
]
+ [None]
)
B = [
shapely.geometry.Polygon([(random.random(), random.random()) for i in range(3)])
for _ in range(100)
] + [shapely.geometry.Polygon(), None, None]
vec_A = from_shapely(A)
vec_B = from_shapely(B)
result = getattr(vec_A, attr)(vec_B, *args)
assert isinstance(result, np.ndarray)
assert result.dtype == bool
expected = []
for a, b in zip(A, B):
if a is None or b is None:
expected.append(na_value)
elif a.is_empty or b.is_empty:
expected.append(empty_value)
else:
expected.append(
getattr(a, attr if "geom" not in attr else attr[5:])(b, *args)
)
assert result.tolist() == expected
@pytest.mark.parametrize(
"attr",
[
"boundary",
"centroid",
"convex_hull",
"envelope",
"exterior",
# 'interiors',
],
)
def test_unary_geo(attr):
na_value = None
result = getattr(T, attr)
expected = [getattr(t, attr) if t is not None else na_value for t in triangles]
assert equal_geometries(result, expected)
@pytest.mark.parametrize("attr", ["representative_point"])
def test_unary_geo_callable(attr):
na_value = None
result = getattr(T, attr)()
expected = [getattr(t, attr)() if t is not None else na_value for t in triangles]
assert equal_geometries(result, expected)
@pytest.mark.parametrize(
"attr", ["difference", "symmetric_difference", "union", "intersection"]
)
def test_binary_geo_vector(attr):
na_value = None
quads = [shapely.geometry.Polygon(), None]
while len(quads) < 12:
geom = shapely.geometry.Polygon(
[(random.random(), random.random()) for i in range(4)]
)
if geom.is_valid:
quads.append(geom)
Q = from_shapely(quads)
result = getattr(T, attr)(Q)
expected = [
getattr(t, attr)(q) if t is not None and q is not None else na_value
for t, q in zip(triangles, quads)
]
assert equal_geometries(result, expected)
@pytest.mark.parametrize(
"attr", ["difference", "symmetric_difference", "union", "intersection"]
)
def test_binary_geo_scalar(attr):
na_value = None
quads = []
while len(quads) < 1:
geom = shapely.geometry.Polygon(
[(random.random(), random.random()) for i in range(4)]
)
if geom.is_valid:
quads.append(geom)
q = quads[0]
for other in [q, shapely.geometry.Polygon()]:
result = getattr(T, attr)(other)
expected = [
getattr(t, attr)(other) if t is not None else na_value for t in triangles
]
assert equal_geometries(result, expected)
@pytest.mark.parametrize(
"attr",
[
"is_closed",
"is_valid",
"is_empty",
"is_simple",
"has_z",
# for is_ring we raise a warning about the value for Polygon changing
pytest.param(
"is_ring",
marks=[
pytest.mark.filterwarnings("ignore:is_ring:FutureWarning"),
],
),
],
)
def test_unary_predicates(attr):
na_value = False
if attr == "is_simple" and geos_version < (3, 8) and not compat.USE_PYGEOS:
# poly.is_simple raises an error for empty polygon for GEOS < 3.8
with pytest.raises(Exception): # noqa: B017
T.is_simple
vals = triangle_no_missing
V = from_shapely(vals)
else:
vals = triangles
V = T
result = getattr(V, attr)
if attr == "is_simple" and geos_version < (3, 8):
# poly.is_simple raises an error for empty polygon for GEOS < 3.8
# with shapely, pygeos always returns False for all GEOS versions
expected = [
getattr(t, attr) if t is not None and not t.is_empty else na_value
for t in vals
]
elif attr == "is_ring":
expected = [
getattr(t.exterior, attr)
if t is not None and t.exterior is not None
else na_value
for t in vals
]
# empty Linearring.is_ring gives False with Shapely < 2.0
if compat.USE_PYGEOS and not compat.SHAPELY_GE_20:
expected[-2] = True
elif (
attr == "is_closed"
and compat.USE_PYGEOS
and compat.SHAPELY_GE_182
and not compat.SHAPELY_GE_20
):
# In shapely 1.8.2, is_closed was changed to return always True for
# Polygon/MultiPolygon, while PyGEOS returns always False
expected = [False] * len(vals)
else:
expected = [getattr(t, attr) if t is not None else na_value for t in vals]
assert result.tolist() == expected
# for is_ring we raise a warning about the value for Polygon changing
@pytest.mark.filterwarnings("ignore:is_ring:FutureWarning")
def test_is_ring():
g = [
shapely.geometry.LinearRing([(0, 0), (1, 1), (1, -1)]),
shapely.geometry.LineString([(0, 0), (1, 1), (1, -1)]),
shapely.geometry.LineString([(0, 0), (1, 1), (1, -1), (0, 0)]),
shapely.geometry.Polygon([(0, 0), (1, 1), (1, -1)]),
shapely.wkt.loads("POLYGON EMPTY"),
None,
]
expected = [True, False, True, True, True, False]
if not compat.USE_PYGEOS and not compat.SHAPELY_GE_20:
# empty polygon is_ring gives False with Shapely < 2.0
expected[-2] = False
result = from_shapely(g).is_ring
assert result.tolist() == expected
@pytest.mark.parametrize("attr", ["area", "length"])
def test_unary_float(attr):
na_value = np.nan
result = getattr(T, attr)
assert isinstance(result, np.ndarray)
assert result.dtype == np.dtype("float64")
expected = [getattr(t, attr) if t is not None else na_value for t in triangles]
np.testing.assert_allclose(result, expected)
def test_geom_types():
cat = T.geom_type
# empty polygon has GeometryCollection type
assert list(cat) == ["Polygon"] * (len(T) - 1) + [None]
def test_geom_types_null_mixed():
geoms = [
shapely.geometry.Polygon([(0, 0), (0, 1), (1, 1)]),
None,
shapely.geometry.Point(0, 1),
]
G = from_shapely(geoms)
cat = G.geom_type
assert list(cat) == ["Polygon", None, "Point"]
def test_binary_distance():
attr = "distance"
na_value = np.nan
# also use nan for empty
# vector - vector
result = P[: len(T)].distance(T[::-1])
expected = [
getattr(p, attr)(t)
if not ((t is None or t.is_empty) or (p is None or p.is_empty))
else na_value
for t, p in zip(triangles[::-1], points)
]
np.testing.assert_allclose(result, expected)
# vector - scalar
p = points[0]
result = T.distance(p)
expected = [
getattr(t, attr)(p) if not (t is None or t.is_empty) else na_value
for t in triangles
]
np.testing.assert_allclose(result, expected)
# other is empty
result = T.distance(shapely.geometry.Polygon())
expected = [na_value] * len(T)
np.testing.assert_allclose(result, expected)
# TODO other is None
def test_binary_relate():
attr = "relate"
na_value = None
# vector - vector
result = getattr(P[: len(T)], attr)(T[::-1])
expected = [
getattr(p, attr)(t) if t is not None and p is not None else na_value
for t, p in zip(triangles[::-1], points)
]
assert list(result) == expected
# vector - scalar
p = points[0]
result = getattr(T, attr)(p)
expected = [getattr(t, attr)(p) if t is not None else na_value for t in triangles]
assert list(result) == expected
@pytest.mark.parametrize("normalized", [True, False])
def test_binary_project(normalized):
na_value = np.nan
lines = (
[None]
+ [
shapely.geometry.LineString(
[(random.random(), random.random()) for _ in range(2)]
)
for _ in range(len(P) - 2)
]
+ [None]
)
L = from_shapely(lines)
result = L.project(P, normalized=normalized)
expected = [
line.project(p, normalized=normalized)
if line is not None and p is not None
else na_value
for p, line in zip(points, lines)
]
np.testing.assert_allclose(result, expected)
@pytest.mark.parametrize("cap_style", [CAP_STYLE.round, CAP_STYLE.square])
@pytest.mark.parametrize("join_style", [JOIN_STYLE.round, JOIN_STYLE.bevel])
@pytest.mark.parametrize("resolution", [16, 25])
def test_buffer(resolution, cap_style, join_style):
if compat.USE_PYGEOS:
# TODO(pygeos) need to further investigate why this test fails
if cap_style == 1 and join_style == 3:
pytest.skip("failing TODO")
na_value = None
expected = [
p.buffer(0.1, resolution=resolution, cap_style=cap_style, join_style=join_style)
if p is not None
else na_value
for p in points
]
result = P.buffer(
0.1, resolution=resolution, cap_style=cap_style, join_style=join_style
)
assert equal_geometries(expected, result)
dist = np.array([0.1] * len(P))
result = P.buffer(
dist, resolution=resolution, cap_style=cap_style, join_style=join_style
)
assert equal_geometries(expected, result)
def test_simplify():
triangles = [
shapely.geometry.Polygon(
[(random.random(), random.random()) for i in range(3)]
).buffer(10)
for _ in range(10)
]
T = from_shapely(triangles)
result = T.simplify(1)
expected = [t.simplify(1) for t in triangles]
assert all(a.equals(b) for a, b in zip(expected, result))
def test_unary_union():
geoms = [
shapely.geometry.Polygon([(0, 0), (0, 1), (1, 1)]),
shapely.geometry.Polygon([(0, 0), (1, 0), (1, 1)]),
]
G = from_shapely(geoms)
u = G.unary_union()
expected = shapely.geometry.Polygon([(0, 0), (1, 0), (1, 1), (0, 1)])
assert u.equals(expected)
@pytest.mark.parametrize(
"attr, arg",
[
("affine_transform", ([0, 1, 1, 0, 0, 0],)),
("translate", ()),
("rotate", (10,)),
("scale", ()),
("skew", ()),
],
)
def test_affinity_methods(attr, arg):
result = getattr(T, attr)(*arg)
expected = [
getattr(shapely.affinity, attr)(t, *arg) if not (t is None or t.is_empty) else t
for t in triangles
]
assert equal_geometries(result, expected)
# def test_coords():
# L = T.exterior.coords
# assert L == [tuple(t.exterior.coords) for t in triangles]
def test_coords_x_y():
na_value = np.nan
result = P.x
expected = [p.x if p is not None else na_value for p in points]
np.testing.assert_allclose(result, expected)
result = P.y
expected = [p.y if p is not None else na_value for p in points]
np.testing.assert_allclose(result, expected)
def test_bounds():
result = T.bounds
expected = [
t.bounds if not (t is None or t.is_empty) else [np.nan] * 4 for t in triangles
]
np.testing.assert_allclose(result, expected)
# additional check for one empty / missing
for geom in [None, shapely.geometry.Polygon()]:
E = from_shapely([geom])
result = E.bounds
assert result.ndim == 2
assert result.dtype == "float64"
np.testing.assert_allclose(result, np.array([[np.nan] * 4]))
# empty array (https://github.com/geopandas/geopandas/issues/1195)
E = from_shapely([])
result = E.bounds
assert result.shape == (0, 4)
assert result.dtype == "float64"
def test_total_bounds():
result = T.total_bounds
bounds = np.array(
[t.bounds if not (t is None or t.is_empty) else [np.nan] * 4 for t in triangles]
)
expected = np.array(
[
np.nanmin(bounds[:, 0]), # minx
np.nanmin(bounds[:, 1]), # miny
np.nanmax(bounds[:, 2]), # maxx
np.nanmax(bounds[:, 3]), # maxy
]
)
np.testing.assert_allclose(result, expected)
# additional check for empty array or one empty / missing
for geoms in [[], [None], [shapely.geometry.Polygon()]]:
E = from_shapely(geoms)
result = E.total_bounds
assert result.ndim == 1
assert result.dtype == "float64"
np.testing.assert_allclose(result, np.array([np.nan] * 4))
def test_getitem():
points = [shapely.geometry.Point(i, i) for i in range(10)]
P = from_shapely(points)
P2 = P[P.area > 0.3]
assert isinstance(P2, GeometryArray)
P3 = P[[1, 3, 5]]
assert len(P3) == 3
assert isinstance(P3, GeometryArray)
assert [p.x for p in P3] == [1, 3, 5]
P4 = P[1::2]
assert len(P4) == 5
assert isinstance(P3, GeometryArray)
assert [p.x for p in P4] == [1, 3, 5, 7, 9]
P5 = P[1]
assert isinstance(P5, shapely.geometry.Point)
assert P5.equals(points[1])
@pytest.mark.parametrize(
"item",
[
geopandas.GeoDataFrame(
geometry=[shapely.geometry.Polygon([(0, 0), (2, 0), (2, 2), (0, 2)])]
),
geopandas.GeoSeries(
[shapely.geometry.Polygon([(0, 0), (2, 0), (2, 2), (0, 2)])]
),
np.array([shapely.geometry.Polygon([(0, 0), (2, 0), (2, 2), (0, 2)])]),
[shapely.geometry.Polygon([(0, 0), (2, 0), (2, 2), (0, 2)])],
shapely.geometry.Polygon([(0, 0), (2, 0), (2, 2), (0, 2)]),
],
)
def test_setitem(item):
points = [shapely.geometry.Point(i, i) for i in range(10)]
P = from_shapely(points)
P[[0]] = item
assert isinstance(P[0], shapely.geometry.Polygon)
def test_equality_ops():
with pytest.raises(ValueError):
P[:5] == P[:7]
a1 = from_shapely([points[1], points[2], points[3]])
a2 = from_shapely([points[1], points[0], points[3]])
res = a1 == a2
assert res.tolist() == [True, False, True]
res = a1 != a2
assert res.tolist() == [False, True, False]
# check the correct expansion of list-like geometry
multi_poly = shapely.geometry.MultiPolygon(
[shapely.geometry.box(0, 0, 1, 1), shapely.geometry.box(3, 3, 4, 4)]
)
a3 = from_shapely([points[1], points[2], points[3], multi_poly])
res = a3 == multi_poly
assert res.tolist() == [False, False, False, True]
def test_dir():
assert "contains" in dir(P)
assert "data" in dir(P)
def test_chaining():
# contains will give False for empty / missing
T = from_shapely(triangle_no_missing)
assert T.contains(T.centroid).all()
def test_pickle():
import pickle
T2 = pickle.loads(pickle.dumps(T))
# assert (T.data != T2.data).all()
assert T2[-1] is None
assert T2[-2].is_empty
assert T[:-2].geom_equals(T2[:-2]).all()
def test_raise_on_bad_sizes():
with pytest.raises(ValueError) as info:
T.contains(P)
assert "lengths" in str(info.value).lower()
assert "12" in str(info.value)
assert "21" in str(info.value)
def test_buffer_single_multipolygon():
# https://github.com/geopandas/geopandas/issues/1130
multi_poly = shapely.geometry.MultiPolygon(
[shapely.geometry.box(0, 0, 1, 1), shapely.geometry.box(3, 3, 4, 4)]
)
arr = from_shapely([multi_poly])
result = arr.buffer(1)
expected = [multi_poly.buffer(1)]
equal_geometries(result, expected)
result = arr.buffer(np.array([1]))
equal_geometries(result, expected)
def test_astype_multipolygon():
# https://github.com/geopandas/geopandas/issues/1145
multi_poly = shapely.geometry.MultiPolygon(
[shapely.geometry.box(0, 0, 1, 1), shapely.geometry.box(3, 3, 4, 4)]
)
arr = from_shapely([multi_poly])
result = arr.astype(str)
assert isinstance(result[0], str)
assert result[0] == multi_poly.wkt
# astype(object) does not convert to string
result = arr.astype(object)
assert isinstance(result[0], shapely.geometry.base.BaseGeometry)
# astype(np_dtype) honors the dtype
result = arr.astype(np.dtype("U10"))
assert result.dtype == np.dtype("U10")
assert result[0] == multi_poly.wkt[:10]
def test_check_crs():
t1 = T.copy()
t1.crs = 4326
assert _check_crs(t1, T) is False
assert _check_crs(t1, t1) is True
assert _check_crs(t1, T, allow_none=True) is True
def test_crs_mismatch_warn():
t1 = T.copy()
t2 = T.copy()
t1.crs = 4326
t2.crs = 3857
# two different CRS
with pytest.warns(UserWarning, match="CRS mismatch between the CRS"):
_crs_mismatch_warn(t1, t2)
# left None
with pytest.warns(UserWarning, match="CRS mismatch between the CRS"):
_crs_mismatch_warn(T, t2)
# right None
with pytest.warns(UserWarning, match="CRS mismatch between the CRS"):
_crs_mismatch_warn(t1, T)
@pytest.mark.parametrize("NA", [None, np.nan])
def test_isna(NA):
t1 = T.copy()
t1[0] = NA
assert t1[0] is None
def test_isna_pdNA():
t1 = T.copy()
t1[0] = pd.NA
assert t1[0] is None
def test_shift_has_crs():
t = T.copy()
t.crs = 4326
assert t.shift(1).crs == t.crs
assert t.shift(0).crs == t.crs
assert t.shift(-1).crs == t.crs
def test_unique_has_crs():
t = T.copy()
t.crs = 4326
assert t.unique().crs == t.crs
class TestEstimateUtmCrs:
def setup_method(self):
self.esb = shapely.geometry.Point(-73.9847, 40.7484)
self.sol = shapely.geometry.Point(-74.0446, 40.6893)
self.landmarks = from_shapely([self.esb, self.sol], crs="epsg:4326")
def test_estimate_utm_crs__geographic(self):
assert self.landmarks.estimate_utm_crs() == CRS("EPSG:32618")
assert self.landmarks.estimate_utm_crs("NAD83") == CRS("EPSG:26918")
def test_estimate_utm_crs__projected(self):
assert self.landmarks.to_crs("EPSG:3857").estimate_utm_crs() == CRS(
"EPSG:32618"
)
def test_estimate_utm_crs__antimeridian(self):
antimeridian = from_shapely(
[
shapely.geometry.Point(1722483.900174921, 5228058.6143420935),
shapely.geometry.Point(4624385.494808555, 8692574.544944234),
],
crs="EPSG:3851",
)
assert antimeridian.estimate_utm_crs() == CRS("EPSG:32760")
def test_estimate_utm_crs__out_of_bounds(self):
with pytest.raises(RuntimeError, match="Unable to determine UTM CRS"):
from_shapely(
[shapely.geometry.Polygon([(0, 90), (1, 90), (2, 90)])], crs="EPSG:4326"
).estimate_utm_crs()
def test_estimate_utm_crs__missing_crs(self):
with pytest.raises(RuntimeError, match="crs must be set"):
from_shapely(
[shapely.geometry.Polygon([(0, 90), (1, 90), (2, 90)])]
).estimate_utm_crs()