Skip to content

Commit fe83c8a

Browse files
authored
Merge pull request #2623 from rcomer/bump-deps
MNT: bump minimum dependency versions
2 parents 62088f0 + cd88586 commit fe83c8a

File tree

14 files changed

+86
-263
lines changed

14 files changed

+86
-263
lines changed

.github/workflows/ci-testing.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ jobs:
1717
fail-fast: false
1818
matrix:
1919
os: [ubuntu-latest, macos-latest, windows-latest]
20-
python-version: ['3.10', '3.11', '3.12', '3.13']
20+
python-version: ['3.11', '3.12', '3.13']
2121
use-network: [true]
2222
include:
2323
- os: ubuntu-latest
24-
python-version: '3.11'
24+
python-version: '3.13'
2525
use-network: false
2626

2727
steps:
@@ -37,17 +37,17 @@ jobs:
3737

3838
- name: Minimum packages
3939
if: |
40-
matrix.python-version == '3.10' && matrix.os == 'ubuntu-latest' &&
40+
matrix.python-version == '3.11' && matrix.os == 'ubuntu-latest' &&
4141
(github.event_name == 'push' || github.event_name == 'pull_request')
4242
id: minimum-packages
4343
run: |
44-
pip install cython==0.29.28 matplotlib==3.6 numpy==1.23 owslib==0.27 pyproj==3.3.1 scipy==1.9 shapely==2.0 pyshp==2.3.1
44+
pip install cython==3.0 matplotlib==3.8 numpy==1.26 owslib==0.29 pyproj==3.6 scipy==1.11 shapely==2.0 pyshp==2.3.1
4545
4646
- name: Coverage packages
4747
id: coverage
4848
# only want the coverage to be run on the latest ubuntu and for code changes i.e. push and pr
4949
if: |
50-
matrix.python-version == '3.12' && matrix.os == 'ubuntu-latest' &&
50+
matrix.python-version == '3.13' && matrix.os == 'ubuntu-latest' &&
5151
(github.event_name == 'push' || github.event_name == 'pull_request')
5252
run: |
5353
echo "CYTHON_COVERAGE=1" >> $GITHUB_ENV

INSTALL

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,20 +59,20 @@ To use it::
5959

6060
Further information about the required dependencies can be found here:
6161

62-
**Python** 3.10 or later (https://www.python.org/)
62+
**Python** 3.11 or later (https://www.python.org/)
6363
Python 2 support was removed in v0.19.
6464

65-
**Matplotlib** 3.6 or later (https://matplotlib.org/)
65+
**Matplotlib** 3.8 or later (https://matplotlib.org/)
6666
Python package for 2D plotting. Python package required for any
6767
graphical capabilities.
6868

6969
**Shapely** 2.0 or later (https://github.com/shapely/shapely)
7070
Python package for the manipulation and analysis of planar geometric objects.
7171

72-
**pyshp** 2.3 or later (https://pypi.python.org/pypi/pyshp)
72+
**pyshp** 2.3.1 or later (https://pypi.python.org/pypi/pyshp)
7373
Pure Python read/write support for ESRI Shapefile format.
7474

75-
**pyproj** 3.3.1 or later (https://github.com/pyproj4/pyproj/)
75+
**pyproj** 3.6 or later (https://github.com/pyproj4/pyproj/)
7676
Python interface to PROJ (cartographic projections and coordinate transformations library).
7777

7878
Optional Dependencies
@@ -90,10 +90,10 @@ the optional OWS libraries.
9090
A fast kd-tree implementation that is used for faster warping
9191
of images than SciPy.
9292

93-
**SciPy** 1.9 or later (https://www.scipy.org/)
93+
**SciPy** 1.11 or later (https://www.scipy.org/)
9494
A Python package for scientific computing.
9595

96-
**OWSLib** 0.27 or later (https://pypi.python.org/pypi/OWSLib)
96+
**OWSLib** 0.29 or later (https://pypi.python.org/pypi/OWSLib)
9797
A Python package for client programming with the Open Geospatial
9898
Consortium (OGC) web service, and which gives access to Cartopy ogc
9999
clients.

environment.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,24 @@ name: cartopy-dev
88
channels:
99
- conda-forge
1010
dependencies:
11-
- cython>=0.29.28
12-
- numpy>=1.23
11+
- cython>=3.0
12+
- numpy>=1.26
1313
- shapely>=2.0
14-
- pyshp>=2.3
15-
- pyproj>=3.3.1
16-
- packaging>=21
14+
- pyshp>=2.3.1
15+
- pyproj>=3.6.0
1716
# The testing label has the proper version of freetype included
1817
- conda-forge/label/testing::matplotlib-base>=3.6
1918

2019
# OWS
21-
- owslib>=0.27
20+
- owslib>=0.29
2221
- pillow>=9.1
2322
# Plotting
24-
- scipy>=1.9
23+
- scipy>=1.11
2524
# Testing
2625
- pytest
2726
- pytest-mpl
2827
- pytest-xdist
28+
- packaging>=21
2929
# Documentation
3030
- pydata-sphinx-theme
3131
- sphinx

lib/cartopy/mpl/__init__.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,3 @@
22
#
33
# This file is part of Cartopy and is released under the BSD 3-clause license.
44
# See LICENSE in the root of the repository for full licensing details.
5-
6-
import matplotlib
7-
import packaging.version
8-
9-
10-
_MPL_VERSION = packaging.version.parse(matplotlib.__version__)
11-
_MPL_37 = _MPL_VERSION.release[:2] >= (3, 7)
12-
_MPL_38 = _MPL_VERSION.release[:2] >= (3, 8)

lib/cartopy/mpl/contour.py

Lines changed: 20 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,6 @@
44
# See LICENSE in the root of the repository for full licensing details.
55

66
from matplotlib.contour import QuadContourSet
7-
import matplotlib.path as mpath
8-
import numpy as np
9-
10-
from cartopy.mpl import _MPL_38
117

128

139
class GeoContourSet(QuadContourSet):
@@ -20,91 +16,26 @@ class GeoContourSet(QuadContourSet):
2016
# fiddling with instance.__class__.
2117

2218
def clabel(self, *args, **kwargs):
23-
if not _MPL_38:
24-
# nb: contour labelling does not work very well for filled
25-
# contours - it is recommended to only label line contours.
26-
# This is especially true when inline=True.
27-
28-
# This wrapper exist because mpl does not properly transform
29-
# paths. Instead it simply assumes one path represents one polygon
30-
# (not necessarily the case), and it assumes that
31-
# transform(path.verts) is equivalent to transform_path(path).
32-
# Unfortunately there is no way to easily correct this error,
33-
# so we are forced to pre-transform the ContourSet's paths from
34-
# the source coordinate system to the axes' projection.
35-
# The existing mpl code then has a much simpler job of handling
36-
# pre-projected paths (which can now effectively be transformed
37-
# naively).
38-
39-
for col in self.collections:
40-
# Snaffle the collection's path list. We will change the
41-
# list in-place (as the contour label code does in mpl).
42-
paths = col.get_paths()
43-
44-
# Define the transform that will take us from collection
45-
# coordinates through to axes projection coordinates.
46-
data_t = self.axes.transData
47-
col_to_data = col.get_transform() - data_t
48-
49-
# Now that we have the transform, project all of this
50-
# collection's paths.
51-
new_paths = [col_to_data.transform_path(path)
52-
for path in paths]
53-
new_paths = [path for path in new_paths
54-
if path.vertices.size >= 1]
55-
56-
# The collection will now be referenced in axes projection
57-
# coordinates.
58-
col.set_transform(data_t)
59-
60-
# Clear the now incorrectly referenced paths.
61-
del paths[:]
62-
63-
for path in new_paths:
64-
if path.vertices.size == 0:
65-
# Don't persist empty paths. Let's get rid of them.
66-
continue
67-
68-
# Split the path if it has multiple MOVETO statements.
69-
codes = np.array(
70-
path.codes if path.codes is not None else [0])
71-
moveto = codes == mpath.Path.MOVETO
72-
if moveto.sum() <= 1:
73-
# This is only one path, so add it to the collection.
74-
paths.append(path)
75-
else:
76-
# The first MOVETO doesn't need cutting-out.
77-
moveto[0] = False
78-
split_locs = np.flatnonzero(moveto)
79-
80-
split_verts = np.split(path.vertices, split_locs)
81-
split_codes = np.split(path.codes, split_locs)
82-
83-
for verts, codes in zip(split_verts, split_codes):
84-
# Add this path to the collection's list of paths.
85-
paths.append(mpath.Path(verts, codes))
86-
87-
else:
88-
# Where contour paths exist at the edge of the globe, sometimes a
89-
# complete path in data space will become multiple paths when
90-
# transformed into axes or screen space. Matplotlib's contour
91-
# labelling does not account for this so we need to give it the
92-
# pre-transformed paths to work with.
93-
94-
# Define the transform that will take us from collection
95-
# coordinates through to axes projection coordinates.
96-
data_t = self.axes.transData
97-
col_to_data = self.get_transform() - data_t
98-
99-
# Now that we have the transform, project all of this
100-
# collection's paths.
101-
paths = self.get_paths()
102-
new_paths = [col_to_data.transform_path(path) for path in paths]
103-
self.set_paths(new_paths)
104-
105-
# The collection will now be referenced in axes projection
106-
# coordinates.
107-
self.set_transform(data_t)
19+
# Where contour paths exist at the edge of the globe, sometimes a
20+
# complete path in data space will become multiple paths when
21+
# transformed into axes or screen space. Matplotlib's contour
22+
# labelling does not account for this so we need to give it the
23+
# pre-transformed paths to work with.
24+
25+
# Define the transform that will take us from collection
26+
# coordinates through to axes projection coordinates.
27+
data_t = self.axes.transData
28+
col_to_data = self.get_transform() - data_t
29+
30+
# Now that we have the transform, project all of this
31+
# collection's paths.
32+
paths = self.get_paths()
33+
new_paths = [col_to_data.transform_path(path) for path in paths]
34+
self.set_paths(new_paths)
35+
36+
# The collection will now be referenced in axes projection
37+
# coordinates.
38+
self.set_transform(data_t)
10839

10940
# Now that we have prepared the collection paths, call on
11041
# through to the underlying implementation.

lib/cartopy/mpl/feature_artist.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import numpy as np
1818

1919
import cartopy.feature as cfeature
20-
from cartopy.mpl import _MPL_38
2120
import cartopy.mpl.path as cpath
2221

2322

@@ -145,11 +144,6 @@ def set_facecolor(self, c):
145144
else:
146145
super().set_facecolor(c)
147146

148-
if not _MPL_38:
149-
# set_paths does not yet exist on Collection.
150-
def set_paths(self, paths):
151-
self._paths = paths
152-
153147
def _get_geoms_paths(self):
154148
ax = self.axes
155149
feature_crs = self._feature.crs

lib/cartopy/mpl/geoaxes.py

Lines changed: 21 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
from cartopy import config
3939
import cartopy.crs as ccrs
4040
import cartopy.feature
41-
from cartopy.mpl import _MPL_38
4241
import cartopy.mpl.contour
4342
import cartopy.mpl.feature_artist as feature_artist
4443
import cartopy.mpl.geocollection
@@ -1592,21 +1591,12 @@ def contour(self, *args, **kwargs):
15921591
"""
15931592
result = super().contour(*args, **kwargs)
15941593

1595-
if not _MPL_38:
1596-
# We need to compute the dataLim correctly for contours.
1597-
bboxes = [col.get_datalim(self.transData)
1598-
for col in result.collections
1599-
if col.get_paths()]
1600-
if bboxes:
1601-
extent = mtransforms.Bbox.union(bboxes)
1602-
self.update_datalim(extent.get_points())
1603-
else:
1604-
# We need to compute the dataLim correctly for contours and set the
1605-
# artist's sticky edges to match.
1606-
datalim = result.get_datalim(self.transData)
1607-
self.update_datalim(datalim)
1608-
result.sticky_edges.x[:] = datalim.xmin, datalim.xmax
1609-
result.sticky_edges.y[:] = datalim.ymin, datalim.ymax
1594+
# We need to compute the dataLim correctly for contours and set the
1595+
# artist's sticky edges to match.
1596+
datalim = result.get_datalim(self.transData)
1597+
self.update_datalim(datalim)
1598+
result.sticky_edges.x[:] = datalim.xmin, datalim.xmax
1599+
result.sticky_edges.y[:] = datalim.ymin, datalim.ymax
16101600

16111601
self.autoscale_view()
16121602

@@ -1638,21 +1628,12 @@ def contourf(self, *args, **kwargs):
16381628
"""
16391629
result = super().contourf(*args, **kwargs)
16401630

1641-
if not _MPL_38:
1642-
# We need to compute the dataLim correctly for contours.
1643-
bboxes = [col.get_datalim(self.transData)
1644-
for col in result.collections
1645-
if col.get_paths()]
1646-
if bboxes:
1647-
extent = mtransforms.Bbox.union(bboxes)
1648-
self.update_datalim(extent.get_points())
1649-
else:
1650-
# We need to compute the dataLim correctly for contours and set the
1651-
# artist's sticky edges to match.
1652-
datalim = result.get_datalim(self.transData)
1653-
self.update_datalim(datalim)
1654-
result.sticky_edges.x[:] = datalim.xmin, datalim.xmax
1655-
result.sticky_edges.y[:] = datalim.ymin, datalim.ymax
1631+
# We need to compute the dataLim correctly for contours and set the
1632+
# artist's sticky edges to match.
1633+
datalim = result.get_datalim(self.transData)
1634+
self.update_datalim(datalim)
1635+
result.sticky_edges.x[:] = datalim.xmin, datalim.xmax
1636+
result.sticky_edges.y[:] = datalim.ymin, datalim.ymax
16561637

16571638
self.autoscale_view()
16581639

@@ -1936,36 +1917,19 @@ def _wrap_quadmesh(self, collection, **kwargs):
19361917
vmax = kwargs.pop('vmax', None)
19371918
norm = kwargs.pop('norm', None)
19381919
cmap = kwargs.pop('cmap', None)
1920+
19391921
# Plot all of the wrapped cells.
19401922
# `pcolor` only draws polygons where the data is not
19411923
# masked, so this will only draw a limited subset of
19421924
# polygons that were actually wrapped.
1943-
1944-
if not _MPL_38:
1945-
# We will add the original data mask in later to
1946-
# make sure that set_array can work in future
1947-
# calls on the proper sized array inputs.
1948-
# NOTE: we don't use C.data here because C.data could
1949-
# contain nan's which would be masked in the
1950-
# pcolor routines, which we don't want. We will
1951-
# fill in the proper data later with set_array()
1952-
# calls.
1953-
pcolor_zeros = np.ma.array(np.zeros(C.shape), mask=pcolor_mask)
1954-
pcolor_col = self.pcolor(coords[..., 0], coords[..., 1],
1955-
pcolor_zeros, zorder=zorder,
1956-
**kwargs)
1957-
1958-
# The pcolor_col is now possibly shorter than the
1959-
# actual collection, so grab the masked cells
1960-
pcolor_col.set_array(pcolor_data[mask].ravel())
1961-
else:
1962-
pcolor_col = self.pcolor(coords[..., 0], coords[..., 1],
1963-
pcolor_data, zorder=zorder,
1964-
**kwargs)
1965-
# Currently pcolor_col.get_array() will return a compressed array
1966-
# and warn unless we explicitly set the 2D array. This should be
1967-
# unnecessary with future matplotlib versions.
1968-
pcolor_col.set_array(pcolor_data)
1925+
pcolor_col = self.pcolor(coords[..., 0], coords[..., 1],
1926+
pcolor_data, zorder=zorder,
1927+
**kwargs)
1928+
1929+
# In matplotlib v3.8 and v3.9 pcolor_col.get_array() will return a
1930+
# compressed array and warn unless we explicitly set the 2D array.
1931+
# This can be removed when we support only matplotlib v3.10+.
1932+
pcolor_col.set_array(pcolor_data)
19691933

19701934
pcolor_col.set_cmap(cmap)
19711935
pcolor_col.set_norm(norm)

0 commit comments

Comments
 (0)