Skip to content

Commit

Permalink
Merge pull request #1930 from akrherz/shapely
Browse files Browse the repository at this point in the history
Address Shapely 2.0 Deprecations
  • Loading branch information
greglucas authored Nov 13, 2021
2 parents 76882b3 + 88edc5e commit 5cfb76b
Show file tree
Hide file tree
Showing 10 changed files with 107 additions and 96 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci-testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ jobs:
if: matrix.python-version == '3.7' && matrix.os == 'macos-latest'
id: minimum-packages
run: |
echo "PACKAGES=cython=0.28.5 matplotlib=3.1 numpy=1.18 owslib=0.17 pyproj=3.0 proj=8.0 scipy=1.2.0" >> $GITHUB_ENV
echo "PACKAGES=cython=0.28.5 matplotlib=3.1 numpy=1.18 owslib=0.17 pyproj=3.0 proj=8.0 scipy=1.2.0 shapely=1.6.4" >> $GITHUB_ENV
echo "CFLAGS=-stdlib=libc++" >> $GITHUB_ENV
- name: Latest packages
if: steps.minimum-packages.conclusion == 'skipped'
run: |
echo "PACKAGES=cython fiona matplotlib-base numpy pyproj pykdtree scipy" >> $GITHUB_ENV
echo "PACKAGES=cython fiona matplotlib-base numpy pyproj pykdtree scipy shapely" >> $GITHUB_ENV
- name: Coverage packages
id: coverage
Expand Down
10 changes: 5 additions & 5 deletions lib/cartopy/crs.py
Original file line number Diff line number Diff line change
Expand Up @@ -822,7 +822,7 @@ def _project_linear_ring(self, linear_ring, src_crs):
threshold = max(np.abs(self.x_limits + self.y_limits)) * 1e-5

# 2) Simplify the segments where appropriate.
if len(multi_line_string) > 1:
if len(multi_line_string.geoms) > 1:
# Stitch together segments which are close to continuous.
# This is important when:
# 1) The first source point projects into the map and the
Expand All @@ -833,7 +833,7 @@ def _project_linear_ring(self, linear_ring, src_crs):
# 2) The cut ends of segments are too close to reliably
# place into an order along the boundary.

line_strings = list(multi_line_string)
line_strings = list(multi_line_string.geoms)
any_modified = False
i = 0
if debug:
Expand Down Expand Up @@ -874,7 +874,7 @@ def _project_linear_ring(self, linear_ring, src_crs):
# 3) Check for rings that have been created by the projection stage.
rings = []
line_strings = []
for line in multi_line_string:
for line in multi_line_string.geoms:
if len(line.coords) > 3 and np.allclose(line.coords[0],
line.coords[-1],
atol=threshold):
Expand Down Expand Up @@ -941,7 +941,7 @@ def _project_polygon(self, polygon, src_crs):
p_rings, p_mline = self._project_linear_ring(src_ring, src_crs)
if p_rings:
rings.extend(p_rings)
if len(p_mline) > 0:
if len(p_mline.geoms) > 0:
multi_lines.append(p_mline)

# Convert any lines to rings by attaching them to the boundary.
Expand Down Expand Up @@ -979,7 +979,7 @@ def boundary_distance(xy):
# Squash all the LineStrings into a single list.
line_strings = []
for multi_line_string in multi_line_strings:
line_strings.extend(multi_line_string)
line_strings.extend(multi_line_string.geoms)

# Record the positions of all the segment ends
for i, line_string in enumerate(line_strings):
Expand Down
2 changes: 1 addition & 1 deletion lib/cartopy/io/ogc_clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ def _target_extents(extent, requested_projection, available_projection):

# Return the polygons' rectangular bounds as extent tuples.
target_extents = []
for poly in polys:
for poly in polys.geoms:
min_x, min_y, max_x, max_y = poly.bounds
if fudge_mode:
# If we shrunk the request area before, then here we
Expand Down
11 changes: 8 additions & 3 deletions lib/cartopy/mpl/gridliner.py
Original file line number Diff line number Diff line change
Expand Up @@ -839,15 +839,20 @@ def update_artist(artist, renderer):
sgeom.MultiLineString)):
if isinstance(intersection, sgeom.LineString):
intersection = [intersection]
elif len(intersection) > 4:
elif len(intersection.geoms) > 4:
# Gridline and map boundary are parallel and they
# intersect themselves too much it results in a
# multiline string that must be converted to a single
# linestring. This is an empirical workaround for a
# problem that can probably be solved in a cleaner way.
xy = np.append(intersection[0], intersection[-1],
axis=0)
xy = np.append(
intersection.geoms[0].coords,
intersection.geoms[-1].coords,
axis=0,
)
intersection = [sgeom.LineString(xy)]
else:
intersection = intersection.geoms
tails = []
heads = []
for inter in intersection:
Expand Down
7 changes: 5 additions & 2 deletions lib/cartopy/tests/crs/test_albers_equal_area.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,11 @@ def test_central_longitude(self, lon):
'x_0=0.0', 'y_0=0.0', 'lat_1=20.0', 'lat_2=50.0'}
check_proj_params('aea', aea_offset, other_args)

assert_array_almost_equal(aea_offset.boundary, aea.boundary,
decimal=0)
assert_array_almost_equal(
aea_offset.boundary.coords,
aea.boundary.coords,
decimal=0,
)

def test_standard_parallels(self):
aea = ccrs.AlbersEqualArea(standard_parallels=(13, 37))
Expand Down
7 changes: 5 additions & 2 deletions lib/cartopy/tests/crs/test_equidistant_conic.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,11 @@ def test_central_longitude(self, lon):
'x_0=0.0', 'y_0=0.0', 'lat_1=20.0', 'lat_2=50.0'}
check_proj_params('eqdc', eqdc_offset, other_args)

assert_array_almost_equal(eqdc_offset.boundary, eqdc.boundary,
decimal=0)
assert_array_almost_equal(
eqdc_offset.boundary.coords,
eqdc.boundary.coords,
decimal=0,
)

def test_standard_parallels(self):
eqdc = ccrs.EquidistantConic(standard_parallels=(13, 37))
Expand Down
6 changes: 3 additions & 3 deletions lib/cartopy/tests/test_crs.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,9 @@ def test_project_point(self):

result = pc_rotated.project_geometry(multi_point, pc)
assert isinstance(result, sgeom.MultiPoint)
assert len(result) == 2
assert_arr_almost_eq(result[0].xy, [[-180.], [45.]])
assert_arr_almost_eq(result[1].xy, [[0], [45.]])
assert len(result.geoms) == 2
assert_arr_almost_eq(result.geoms[0].xy, [[-180.], [45.]])
assert_arr_almost_eq(result.geoms[1].xy, [[0], [45.]])

def test_utm(self):
utm30n = ccrs.UTM(30)
Expand Down
72 changes: 36 additions & 36 deletions lib/cartopy/tests/test_line_string.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def test_out_of_bounds(self):
expected = 0
else:
expected = 1
assert len(multi_line_string) == expected, \
assert len(multi_line_string.geoms) == expected, \
f'Unexpected line when working from {start} to {end}'

def test_simple_fragment_count(self):
Expand All @@ -51,15 +51,15 @@ def test_simple_fragment_count(self):
multi_line_string = projection.project_geometry(line_string)
# from cartopy.tests.mpl import show
# show(projection, multi_line_string)
assert len(multi_line_string) == pieces
assert len(multi_line_string.geoms) == pieces

def test_split(self):
projection = ccrs.Robinson(170.5)
line_string = sgeom.LineString([(-10, 30), (10, 60)])
multi_line_string = projection.project_geometry(line_string)
# from cartopy.tests.mpl import show
# show(projection, multi_line_string)
assert len(multi_line_string) == 2
assert len(multi_line_string.geoms) == 2

def test_out_of_domain_efficiency(self):
# Check we're efficiently dealing with lines that project
Expand Down Expand Up @@ -103,80 +103,80 @@ def test_repeated_point(self):
projection = FakeProjection()
line_string = sgeom.LineString([(10, 0), (10, 0)])
multi_line_string = projection.project_geometry(line_string)
assert len(multi_line_string) == 1
assert len(multi_line_string[0].coords) == 2
assert len(multi_line_string.geoms) == 1
assert len(multi_line_string.geoms[0].coords) == 2

def test_interior_repeated_point(self):
projection = FakeProjection()
line_string = sgeom.LineString([(0, 0), (10, 0), (10, 0), (20, 0)])
multi_line_string = projection.project_geometry(line_string)
assert len(multi_line_string) == 1
assert len(multi_line_string[0].coords) == 4
assert len(multi_line_string.geoms) == 1
assert len(multi_line_string.geoms[0].coords) == 4

def test_circular_repeated_point(self):
projection = FakeProjection()
line_string = sgeom.LineString([(0, 0), (360, 0)])
multi_line_string = projection.project_geometry(line_string)
assert len(multi_line_string) == 1
assert len(multi_line_string[0].coords) == 2
assert len(multi_line_string.geoms) == 1
assert len(multi_line_string.geoms[0].coords) == 2

def test_short(self):
projection = FakeProjection()
line_string = sgeom.LineString([(0, 0), (1e-12, 0)])
multi_line_string = projection.project_geometry(line_string)
assert len(multi_line_string) == 1
assert len(multi_line_string[0].coords) == 2
assert len(multi_line_string.geoms) == 1
assert len(multi_line_string.geoms[0].coords) == 2

def test_empty(self):
projection = FakeProjection(right_offset=10)
line_string = sgeom.LineString([(175, 0), (175, 10)])
multi_line_string = projection.project_geometry(line_string)
assert len(multi_line_string) == 0
assert len(multi_line_string.geoms) == 0

def test_simple_run_in(self):
projection = FakeProjection(right_offset=10)
line_string = sgeom.LineString([(160, 0), (175, 0)])
multi_line_string = projection.project_geometry(line_string)
assert len(multi_line_string) == 1
assert len(multi_line_string[0].coords) == 2
assert len(multi_line_string.geoms) == 1
assert len(multi_line_string.geoms[0].coords) == 2

def test_simple_wrap(self):
projection = FakeProjection()
line_string = sgeom.LineString([(160, 0), (-160, 0)])
multi_line_string = projection.project_geometry(line_string)
assert len(multi_line_string) == 2
assert len(multi_line_string[0].coords) == 2
assert len(multi_line_string[1].coords) == 2
assert len(multi_line_string.geoms) == 2
assert len(multi_line_string.geoms[0].coords) == 2
assert len(multi_line_string.geoms[1].coords) == 2

def test_simple_run_out(self):
projection = FakeProjection(left_offset=10)
line_string = sgeom.LineString([(-175, 0), (-160, 0)])
multi_line_string = projection.project_geometry(line_string)
assert len(multi_line_string) == 1
assert len(multi_line_string[0].coords) == 2
assert len(multi_line_string.geoms) == 1
assert len(multi_line_string.geoms[0].coords) == 2

def test_point_on_boundary(self):
projection = FakeProjection()
line_string = sgeom.LineString([(180, 0), (-160, 0)])
multi_line_string = projection.project_geometry(line_string)
assert len(multi_line_string) == 1
assert len(multi_line_string[0].coords) == 2
assert len(multi_line_string.geoms) == 1
assert len(multi_line_string.geoms[0].coords) == 2

# Add a small offset to the left-hand boundary to make things
# even more pathological.
projection = FakeProjection(left_offset=5)
line_string = sgeom.LineString([(180, 0), (-160, 0)])
multi_line_string = projection.project_geometry(line_string)
assert len(multi_line_string) == 1
assert len(multi_line_string[0].coords) == 2
assert len(multi_line_string.geoms) == 1
assert len(multi_line_string.geoms[0].coords) == 2

def test_nan_start(self):
projection = ccrs.TransverseMercator(central_longitude=-90,
approx=False)
line_string = sgeom.LineString([(10, 50), (-10, 30)])
multi_line_string = projection.project_geometry(line_string)
assert len(multi_line_string) == 1
for line_string in multi_line_string:
assert len(multi_line_string.geoms) == 1
for line_string in multi_line_string.geoms:
for coord in line_string.coords:
assert not any(np.isnan(coord)), \
'Unexpected NaN in projected coords.'
Expand All @@ -188,8 +188,8 @@ def test_nan_end(self):
multi_line_string = projection.project_geometry(line_string)
# from cartopy.tests.mpl import show
# show(projection, multi_line_string)
assert len(multi_line_string) == 1
for line_string in multi_line_string:
assert len(multi_line_string.geoms) == 1
for line_string in multi_line_string.geoms:
for coord in line_string.coords:
assert not any(np.isnan(coord)), \
'Unexpected NaN in projected coords.'
Expand All @@ -203,7 +203,7 @@ def test_misc(self):
multi_line_string = projection.project_geometry(line_string)
# from cartopy.tests.mpl import show
# show(projection, multi_line_string)
for line_string in multi_line_string:
for line_string in multi_line_string.geoms:
for coord in line_string.coords:
assert not any(np.isnan(coord)), \
'Unexpected NaN in projected coords.'
Expand All @@ -213,20 +213,20 @@ def test_something(self):
pole_latitude=37.5)
line_string = sgeom.LineString([(0, 0), (1e-14, 0)])
multi_line_string = projection.project_geometry(line_string)
assert len(multi_line_string) == 1
assert len(multi_line_string[0].coords) == 2
assert len(multi_line_string.geoms) == 1
assert len(multi_line_string.geoms[0].coords) == 2

def test_global_boundary(self):
linear_ring = sgeom.LineString([(-180, -180), (-180, 180),
(180, 180), (180, -180)])
pc = ccrs.PlateCarree()
merc = ccrs.Mercator()
multi_line_string = pc.project_geometry(linear_ring, merc)
assert len(multi_line_string) > 0
assert len(multi_line_string.geoms) > 0

# check the identity transform
multi_line_string = merc.project_geometry(linear_ring, merc)
assert len(multi_line_string) > 0
assert len(multi_line_string.geoms) > 0


class TestSymmetry:
Expand All @@ -244,9 +244,9 @@ def test_curve(self):

# Make sure that they generated the same points.
# (Although obviously they will be in the opposite order!)
assert len(multi_line_string) == 1
assert len(multi_line_string2) == 1
coords = multi_line_string[0].coords
coords2 = multi_line_string2[0].coords
assert len(multi_line_string.geoms) == 1
assert len(multi_line_string2.geoms) == 1
coords = multi_line_string.geoms[0].coords
coords2 = multi_line_string2.geoms[0].coords
np.testing.assert_allclose(coords, coords2[::-1],
err_msg='Asymmetric curve generation')
14 changes: 7 additions & 7 deletions lib/cartopy/tests/test_linear_ring.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def test_cuts(self):
rings, multi_line_string = projection.project_geometry(linear_ring)

# The original ring should have been split into multiple pieces.
assert len(multi_line_string) > 1
assert len(multi_line_string.geoms) > 1
assert not rings

def assert_intersection_with_boundary(segment_coords):
Expand All @@ -37,7 +37,7 @@ def assert_intersection_with_boundary(segment_coords):
# segment that crosses the boundary when extended to double length.
# (This is important when considering polygon rings which need to be
# attached to the boundary.)
for line_string in multi_line_string:
for line_string in multi_line_string.geoms:
coords = list(line_string.coords)
assert len(coords) >= 2
assert_intersection_with_boundary(coords[1::-1])
Expand Down Expand Up @@ -68,7 +68,7 @@ def test_out_of_bounds(self):
assert rings
assert not mlinestr
else:
assert len(mlinestr) == expected_n_lines
assert len(mlinestr.geoms) == expected_n_lines
if expected_n_lines == 0:
assert mlinestr.is_empty

Expand All @@ -86,7 +86,7 @@ def test_small(self):
rings, multi_line_string = projection.project_geometry(linear_ring)
# There should be one, and only one, returned ring.
assert isinstance(multi_line_string, sgeom.MultiLineString)
assert len(multi_line_string) == 0
assert len(multi_line_string.geoms) == 0
assert len(rings) == 1

# from cartopy.tests.mpl import show
Expand Down Expand Up @@ -135,13 +135,13 @@ def test_stitch(self):

linear_ring = sgeom.LinearRing(coords)
rings, mlinestr = target_proj.project_geometry(linear_ring, src_proj)
assert len(mlinestr) == 1
assert len(mlinestr.geoms) == 1
assert len(rings) == 0

# Check the stitch works in either direction.
linear_ring = sgeom.LinearRing(coords[::-1])
rings, mlinestr = target_proj.project_geometry(linear_ring, src_proj)
assert len(mlinestr) == 1
assert len(mlinestr.geoms) == 1
assert len(rings) == 0

def test_at_boundary(self):
Expand Down Expand Up @@ -170,7 +170,7 @@ def test_at_boundary(self):
rings, mlinestr = tcrs._project_linear_ring(tring, scrs)

# Number of linearstrings
assert len(mlinestr) == 4
assert len(mlinestr.geoms) == 4
assert not rings

# Test area of smallest Polygon that contains all the points in the
Expand Down
Loading

0 comments on commit 5cfb76b

Please sign in to comment.