Repository: SciTools/cartopy

Issue:
Contour labelling image test failing against Matplotlib `main`
### Description
<!-- Please provide a general introduction to the issue/proposal. -->
I just ran the tests against Matplotlib main, and got an image comparison failure because of the contour labels:

Expected
![baseline](https://github.com/SciTools/cartopy/assets/10599679/84c6ae6a-21af-45be-a746-6643745f3fc4)

Actual
![result](https://github.com/SciTools/cartopy/assets/10599679/5307ccea-ea84-41e9-ad86-605f76ebe9d4)

The test:

https://github.com/SciTools/cartopy/blob/c4858e4963fd8a11fe227700a4b97043f69986ab/lib/cartopy/tests/mpl/test_examples.py#L33-L72

I have two questions

1.  Does anyone have a theory why `inline=True` does not seem to work any more?  I cannot reproduce the problem with Matplotlib's [Contour Label Demo](https://matplotlib.org/devdocs/gallery/images_contours_and_fields/contour_label_demo.html).

2. How would you handle a genuine difference caused by different Matplotlib versions, so that both the main tests and the "minimum package versions" tests still pass?

<!--
If you are reporting a bug, attach the *entire* traceback from Python.

If you are proposing an enhancement/new feature, provide links to related articles, reference examples, etc.

If you are asking a question, please ask on StackOverflow and use the cartopy tag. All cartopy
questions on StackOverflow can be found at https://stackoverflow.com/questions/tagged/cartopy
-->

<details>
 <summary>Full environment definition</summary>

<!-- fill in the following information as appropriate -->

### Operating system

RHEL7

### Cartopy version

`main`

### conda list

```

# Name                    Version                   Build  Channel
_libgcc_mutex             0.1                 conda_forge    conda-forge
_openmp_mutex             4.5                       2_gnu    conda-forge
alsa-lib                  1.2.8                h166bdaf_0    conda-forge
asttokens                 2.2.1              pyhd8ed1ab_0    conda-forge
atk-1.0                   2.38.0               hd4edc92_1    conda-forge
attr                      2.5.1                h166bdaf_1    conda-forge
attrs                     22.2.0             pyh71513ae_0    conda-forge
backcall                  0.2.0              pyh9f0ad1d_0    conda-forge
backports                 1.0                pyhd8ed1ab_3    conda-forge
backports.functools_lru_cache 1.6.4              pyhd8ed1ab_0    conda-forge
beautifulsoup4            4.12.2             pyha770c72_0    conda-forge
black                     23.3.0          py311h38be061_0    conda-forge
bleach                    6.0.0              pyhd8ed1ab_0    conda-forge
brotli                    1.0.9                h166bdaf_8    conda-forge
brotli-bin                1.0.9                h166bdaf_8    conda-forge
brotlipy                  0.7.0           py311hd4cff14_1005    conda-forge
bzip2                     1.0.8                h7f98852_4    conda-forge
c-ares                    1.18.1               h7f98852_0    conda-forge
ca-certificates           2022.12.7            ha878542_0    conda-forge
cairo                     1.16.0            h35add3b_1015    conda-forge
cairocffi                 1.4.0              pyhd8ed1ab_0    conda-forge
cartopy                   0.21.1.dev109+g08ee0828.d20230414          pypi_0    pypi
certifi                   2022.12.7          pyhd8ed1ab_0    conda-forge
cffi                      1.15.1          py311h409f033_3    conda-forge
cfgv                      3.3.1              pyhd8ed1ab_0    conda-forge
charset-normalizer        3.1.0              pyhd8ed1ab_0    conda-forge
click                     8.1.3           unix_pyhd8ed1ab_2    conda-forge
colorama                  0.4.6              pyhd8ed1ab_0    conda-forge
comm                      0.1.3              pyhd8ed1ab_0    conda-forge
contourpy                 1.0.7           py311ha3edf6b_0    conda-forge
coverage                  7.2.3           py311h2582759_0    conda-forge
cryptography              40.0.1          py311h9b4c7bb_0    conda-forge
cycler                    0.11.0             pyhd8ed1ab_0    conda-forge
cython                    0.29.34         py311hcafe171_0    conda-forge
dataclasses               0.8                pyhc8e2a94_3    conda-forge
dbus                      1.13.6               h5008d03_3    conda-forge
debugpy                   1.6.7           py311hcafe171_0    conda-forge
decorator                 5.1.1              pyhd8ed1ab_0    conda-forge
defusedxml                0.7.1              pyhd8ed1ab_0    conda-forge
distlib                   0.3.6              pyhd8ed1ab_0    conda-forge
entrypoints               0.4                pyhd8ed1ab_0    conda-forge
epoxy                     1.5.10               h166bdaf_1    conda-forge
exceptiongroup            1.1.1              pyhd8ed1ab_0    conda-forge
execnet                   1.9.0              pyhd8ed1ab_0    conda-forge
executing                 1.2.0              pyhd8ed1ab_0    conda-forge
expat                     2.5.0                hcb278e6_1    conda-forge
filelock                  3.11.0             pyhd8ed1ab_0    conda-forge
flake8                    6.0.0              pyhd8ed1ab_0    conda-forge
flake8-docstrings         1.7.0              pyhd8ed1ab_0    conda-forge
font-ttf-dejavu-sans-mono 2.37                 hab24e00_0    conda-forge
font-ttf-inconsolata      3.000                h77eed37_0    conda-forge
font-ttf-source-code-pro  2.038                h77eed37_0    conda-forge
font-ttf-ubuntu           0.83                 hab24e00_0    conda-forge
fontconfig                2.14.2               h14ed4e7_0    conda-forge
fonts-conda-ecosystem     1                             0    conda-forge
fonts-conda-forge         1                             0    conda-forge
fonttools                 4.39.3          py311h2582759_0    conda-forge
freetype                  2.12.1               hca18f0e_1    conda-forge
fribidi                   1.0.10               h36c2ea0_0    conda-forge
gdk-pixbuf                2.42.10              h6b639ba_2    conda-forge
geos                      3.11.2               hcb278e6_0    conda-forge
gettext                   0.21.1               h27087fc_0    conda-forge
glib                      2.74.1               h6239696_1    conda-forge
glib-tools                2.74.1               h6239696_1    conda-forge
graphite2                 1.3.13            h58526e2_1001    conda-forge
gst-plugins-base          1.22.0               h4243ec0_2    conda-forge
gstreamer                 1.22.0               h25f0c4b_2    conda-forge
gtk2                      2.24.33              h90689f9_2    conda-forge
gtk4                      4.10.1               hb50841d_0    conda-forge
harfbuzz                  6.0.0                h3ff4399_1    conda-forge
hicolor-icon-theme        0.17                 ha770c72_2    conda-forge
icu                       72.1                 hcb278e6_0    conda-forge
identify                  2.5.22             pyhd8ed1ab_0    conda-forge
idna                      3.4                pyhd8ed1ab_0    conda-forge
importlib-metadata        6.3.0              pyha770c72_0    conda-forge
importlib-resources       5.12.0             pyhd8ed1ab_0    conda-forge
importlib_metadata        6.3.0                hd8ed1ab_0    conda-forge
importlib_resources       5.12.0             pyhd8ed1ab_0    conda-forge
iniconfig                 2.0.0              pyhd8ed1ab_0    conda-forge
ipykernel                 6.22.0             pyh210e3f2_0    conda-forge
ipython                   8.12.0             pyh41d4057_0    conda-forge
jedi                      0.18.2             pyhd8ed1ab_0    conda-forge
jinja2                    3.1.2              pyhd8ed1ab_1    conda-forge
jsonschema                4.17.3             pyhd8ed1ab_0    conda-forge
jupyter_client            8.2.0              pyhd8ed1ab_0    conda-forge
jupyter_core              5.3.0           py311h38be061_0    conda-forge
jupyterlab_pygments       0.2.2              pyhd8ed1ab_0    conda-forge
keyutils                  1.6.1                h166bdaf_0    conda-forge
kiwisolver                1.4.4           py311h4dd048b_1    conda-forge
krb5                      1.20.1               h81ceb04_0    conda-forge
lame                      3.100             h166bdaf_1003    conda-forge
lcms2                     2.15                 haa2dc70_1    conda-forge
ld_impl_linux-64          2.40                 h41732ed_0    conda-forge
lerc                      4.0.0                h27087fc_0    conda-forge
libblas                   3.9.0           16_linux64_openblas    conda-forge
libbrotlicommon           1.0.9                h166bdaf_8    conda-forge
libbrotlidec              1.0.9                h166bdaf_8    conda-forge
libbrotlienc              1.0.9                h166bdaf_8    conda-forge
libcap                    2.67                 he9d0100_0    conda-forge
libcblas                  3.9.0           16_linux64_openblas    conda-forge
libclang                  16.0.1          default_h62803fd_0    conda-forge
libclang13                16.0.1          default_h9b593c0_0    conda-forge
libcups                   2.3.3                h36d4200_3    conda-forge
libcurl                   8.0.1                h588be90_0    conda-forge
libdeflate                1.18                 h0b41bf4_0    conda-forge
libedit                   3.1.20191231         he28a2e2_2    conda-forge
libev                     4.33                 h516909a_1    conda-forge
libevent                  2.1.10               h28343ad_4    conda-forge
libexpat                  2.5.0                hcb278e6_1    conda-forge
libffi                    3.4.2                h7f98852_5    conda-forge
libflac                   1.4.2                h27087fc_0    conda-forge
libgcc-ng                 12.2.0              h65d4601_19    conda-forge
libgcrypt                 1.10.1               h166bdaf_0    conda-forge
libgfortran-ng            12.2.0              h69a702a_19    conda-forge
libgfortran5              12.2.0              h337968e_19    conda-forge
libgirepository           1.74.0               ha2a38d2_1    conda-forge
libglib                   2.74.1               h606061b_1    conda-forge
libglu                    9.0.0             he1b5a44_1001    conda-forge
libgomp                   12.2.0              h65d4601_19    conda-forge
libgpg-error              1.46                 h620e276_0    conda-forge
libgraphene               1.10.6               h76c114f_0    conda-forge
libiconv                  1.17                 h166bdaf_0    conda-forge
libjpeg-turbo             2.1.5.1              h0b41bf4_0    conda-forge
liblapack                 3.9.0           16_linux64_openblas    conda-forge
libllvm16                 16.0.1               hadd5161_0    conda-forge
libnghttp2                1.52.0               h61bc06f_0    conda-forge
libnsl                    2.0.0                h7f98852_0    conda-forge
libogg                    1.3.4                h7f98852_1    conda-forge
libopenblas               0.3.21          pthreads_h78a6416_3    conda-forge
libopus                   1.3.1                h7f98852_1    conda-forge
libpng                    1.6.39               h753d276_0    conda-forge
libpq                     15.2                 hb675445_0    conda-forge
libsndfile                1.2.0                hb75c966_0    conda-forge
libsodium                 1.0.18               h36c2ea0_1    conda-forge
libsqlite                 3.40.0               h753d276_0    conda-forge
libssh2                   1.10.0               hf14f497_3    conda-forge
libstdcxx-ng              12.2.0              h46fd767_19    conda-forge
libsystemd0               253                  h8c4010b_1    conda-forge
libtiff                   4.5.0                ha587672_6    conda-forge
libuuid                   2.38.1               h0b41bf4_0    conda-forge
libvorbis                 1.3.7                h9c3ff4c_0    conda-forge
libwebp-base              1.3.0                h0b41bf4_0    conda-forge
libxcb                    1.13              h7f98852_1004    conda-forge
libxkbcommon              1.5.0                h79f4944_1    conda-forge
libxml2                   2.10.4               hfdac1af_0    conda-forge
libxslt                   1.1.37               h873f0b0_0    conda-forge
libzlib                   1.2.13               h166bdaf_4    conda-forge
lxml                      4.9.2           py311h14a6109_0    conda-forge
lz4-c                     1.9.4                hcb278e6_0    conda-forge
markupsafe                2.1.2           py311h2582759_0    conda-forge
matplotlib                3.8.0.dev1194+g26224d9606          pypi_0    pypi
matplotlib-inline         0.1.6              pyhd8ed1ab_0    conda-forge
mccabe                    0.7.0              pyhd8ed1ab_0    conda-forge
mistune                   2.0.5              pyhd8ed1ab_0    conda-forge
mpg123                    1.31.3               hcb278e6_0    conda-forge
munkres                   1.1.4              pyh9f0ad1d_0    conda-forge
mypy_extensions           1.0.0              pyha770c72_0    conda-forge
mysql-common              8.0.32               ha901b37_1    conda-forge
mysql-libs                8.0.32               hd7da12d_1    conda-forge
nbclient                  0.7.3              pyhd8ed1ab_0    conda-forge
nbconvert                 7.2.10             pyhd8ed1ab_1    conda-forge
nbconvert-core            7.2.10             pyhd8ed1ab_1    conda-forge
nbconvert-pandoc          7.2.10             pyhd8ed1ab_1    conda-forge
nbformat                  5.8.0              pyhd8ed1ab_0    conda-forge
ncurses                   6.3                  h27087fc_1    conda-forge
nest-asyncio              1.5.6              pyhd8ed1ab_0    conda-forge
nodeenv                   1.7.0              pyhd8ed1ab_0    conda-forge
nspr                      4.35                 h27087fc_0    conda-forge
nss                       3.89                 he45b914_0    conda-forge
numpy                     1.24.2          py311h8e6699e_0    conda-forge
openjpeg                  2.5.0                hfec8fc6_2    conda-forge
openssl                   3.1.0                h0b41bf4_0    conda-forge
owslib                    0.29.1             pyhd8ed1ab_0    conda-forge
packaging                 23.1               pyhd8ed1ab_0    conda-forge
pandas                    2.0.0           py311h2872171_0    conda-forge
pandoc                    2.19.2               h32600fe_2    conda-forge
pandocfilters             1.5.0              pyhd8ed1ab_0    conda-forge
pango                     1.50.14              hd33c08f_0    conda-forge
parso                     0.8.3              pyhd8ed1ab_0    conda-forge
pathlib2                  2.3.7.post1     py311h38be061_2    conda-forge
pathspec                  0.11.1             pyhd8ed1ab_0    conda-forge
pcre2                     10.40                hc3806b6_0    conda-forge
pexpect                   4.8.0              pyh1a96a4e_2    conda-forge
pickleshare               0.7.5                   py_1003    conda-forge
pillow                    9.5.0           py311h573f0d3_0    conda-forge
pip                       23.0.1             pyhd8ed1ab_0    conda-forge
pixman                    0.40.0               h36c2ea0_0    conda-forge
pkgutil-resolve-name      1.3.10             pyhd8ed1ab_0    conda-forge
platformdirs              3.2.0              pyhd8ed1ab_0    conda-forge
pluggy                    1.0.0              pyhd8ed1ab_5    conda-forge
ply                       3.11                       py_1    conda-forge
pooch                     1.7.0              pyha770c72_3    conda-forge
pre-commit                3.2.2              pyha770c72_0    conda-forge
proj                      9.2.0                h8ffa02c_0    conda-forge
prompt-toolkit            3.0.38             pyha770c72_0    conda-forge
prompt_toolkit            3.0.38               hd8ed1ab_0    conda-forge
psutil                    5.9.4           py311hd4cff14_0    conda-forge
pthread-stubs             0.4               h36c2ea0_1001    conda-forge
ptyprocess                0.7.0              pyhd3deb0d_0    conda-forge
pulseaudio-client         16.1                 h5195f5e_3    conda-forge
pure_eval                 0.2.2              pyhd8ed1ab_0    conda-forge
pybind11                  2.10.4          py311ha3edf6b_0    conda-forge
pybind11-global           2.10.4          py311ha3edf6b_0    conda-forge
pycairo                   1.23.0          py311hdece40b_0    conda-forge
pycodestyle               2.10.0             pyhd8ed1ab_0    conda-forge
pycparser                 2.21               pyhd8ed1ab_0    conda-forge
pydocstyle                6.3.0              pyhd8ed1ab_0    conda-forge
pyflakes                  3.0.1              pyhd8ed1ab_0    conda-forge
pygments                  2.15.0             pyhd8ed1ab_0    conda-forge
pygobject                 3.44.1          py311he2aa4b6_0    conda-forge
pykdtree                  1.3.7.post0     py311hcb2cf0a_0    conda-forge
pyopenssl                 23.1.1             pyhd8ed1ab_0    conda-forge
pyparsing                 3.0.9              pyhd8ed1ab_0    conda-forge
pyproj                    3.5.0           py311h1850bce_1    conda-forge
pyqt                      5.15.7          py311ha74522f_3    conda-forge
pyqt5-sip                 12.11.0         py311hcafe171_3    conda-forge
pyrsistent                0.19.3          py311h2582759_0    conda-forge
pyshp                     2.3.1              pyhd8ed1ab_0    conda-forge
pysocks                   1.7.1              pyha2e5f31_6    conda-forge
pytest                    7.3.0              pyhd8ed1ab_0    conda-forge
pytest-cov                4.0.0              pyhd8ed1ab_0    conda-forge
pytest-mpl                0.16.1             pyhd8ed1ab_0    conda-forge
pytest-rerunfailures      11.1.2             pyhd8ed1ab_0    conda-forge
pytest-timeout            2.1.0              pyhd8ed1ab_0    conda-forge
pytest-xdist              3.2.1              pyhd8ed1ab_0    conda-forge
python                    3.11.3          h2755cc3_0_cpython    conda-forge
python-dateutil           2.8.2              pyhd8ed1ab_0    conda-forge
python-fastjsonschema     2.16.3             pyhd8ed1ab_0    conda-forge
python-tzdata             2023.3             pyhd8ed1ab_0    conda-forge
python_abi                3.11                    3_cp311    conda-forge
pytz                      2023.3             pyhd8ed1ab_0    conda-forge
pyyaml                    6.0             py311hd4cff14_5    conda-forge
pyzmq                     25.0.2          py311hd6ccaeb_0    conda-forge
qt-main                   5.15.8               h5c52f38_9    conda-forge
readline                  8.2                  h8228510_1    conda-forge
requests                  2.28.2             pyhd8ed1ab_1    conda-forge
scipy                     1.10.1          py311h8e6699e_0    conda-forge
setuptools                67.6.1             pyhd8ed1ab_0    conda-forge
setuptools-scm            7.1.0              pyhd8ed1ab_0    conda-forge
setuptools_scm            7.1.0                hd8ed1ab_0    conda-forge
shapely                   2.0.1           py311h54d622a_1    conda-forge
sip                       6.7.8           py311hcafe171_0    conda-forge
six                       1.16.0             pyh6c4a22f_0    conda-forge
snowballstemmer           2.2.0              pyhd8ed1ab_0    conda-forge
soupsieve                 2.3.2.post1        pyhd8ed1ab_0    conda-forge
sqlite                    3.40.0               h4ff8645_0    conda-forge
stack_data                0.6.2              pyhd8ed1ab_0    conda-forge
tinycss2                  1.2.1              pyhd8ed1ab_0    conda-forge
tk                        8.6.12               h27826a3_0    conda-forge
toml                      0.10.2             pyhd8ed1ab_0    conda-forge
tomli                     2.0.1              pyhd8ed1ab_0    conda-forge
tornado                   6.2             py311hd4cff14_1    conda-forge
traitlets                 5.9.0              pyhd8ed1ab_0    conda-forge
typing-extensions         4.5.0                hd8ed1ab_0    conda-forge
typing_extensions         4.5.0              pyha770c72_0    conda-forge
tzdata                    2023c                h71feb2d_0    conda-forge
ukkonen                   1.0.1           py311h4dd048b_3    conda-forge
urllib3                   1.26.15            pyhd8ed1ab_0    conda-forge
virtualenv                20.21.0            pyhd8ed1ab_0    conda-forge
wcwidth                   0.2.6              pyhd8ed1ab_0    conda-forge
webencodings              0.5.1                      py_1    conda-forge
wheel                     0.40.0             pyhd8ed1ab_0    conda-forge
wxpython                  4.2.0           py311h0cf6651_6    conda-forge
xcb-util                  0.4.0                h166bdaf_0    conda-forge
xcb-util-image            0.4.0                h166bdaf_0    conda-forge
xcb-util-keysyms          0.4.0                h166bdaf_0    conda-forge
xcb-util-renderutil       0.3.9                h166bdaf_0    conda-forge
xcb-util-wm               0.4.1                h166bdaf_0    conda-forge
xkeyboard-config          2.38                 h0b41bf4_0    conda-forge
xorg-compositeproto       0.4.2             h7f98852_1001    conda-forge
xorg-damageproto          1.2.1             h7f98852_1002    conda-forge
xorg-fixesproto           5.0               h7f98852_1002    conda-forge
xorg-inputproto           2.3.2             h7f98852_1002    conda-forge
xorg-kbproto              1.0.7             h7f98852_1002    conda-forge
xorg-libice               1.0.10               h7f98852_0    conda-forge
xorg-libsm                1.2.3             hd9c2040_1000    conda-forge
xorg-libx11               1.8.4                h0b41bf4_0    conda-forge
xorg-libxau               1.0.9                h7f98852_0    conda-forge
xorg-libxcomposite        0.4.6                h0b41bf4_1    conda-forge
xorg-libxcursor           1.2.0                h0b41bf4_1    conda-forge
xorg-libxdamage           1.1.5                h7f98852_1    conda-forge
xorg-libxdmcp             1.1.3                h7f98852_0    conda-forge
xorg-libxext              1.3.4                h0b41bf4_2    conda-forge
xorg-libxfixes            5.0.3             h7f98852_1004    conda-forge
xorg-libxi                1.7.10               h7f98852_0    conda-forge
xorg-libxinerama          1.1.5                h27087fc_0    conda-forge
xorg-libxrandr            1.5.2                h7f98852_1    conda-forge
xorg-libxrender           0.9.10            h7f98852_1003    conda-forge
xorg-randrproto           1.5.0             h7f98852_1001    conda-forge
xorg-renderproto          0.11.1            h7f98852_1002    conda-forge
xorg-util-macros          1.19.3               h7f98852_0    conda-forge
xorg-xextproto            7.3.0             h0b41bf4_1003    conda-forge
xorg-xf86vidmodeproto     2.3.1             h7f98852_1002    conda-forge
xorg-xineramaproto        1.2.1             h7f98852_1001    conda-forge
xorg-xproto               7.0.31            h7f98852_1007    conda-forge
xz                        5.2.6                h166bdaf_0    conda-forge
yaml                      0.2.5                h7f98852_2    conda-forge
zeromq                    4.3.4                h9c3ff4c_1    conda-forge
zipp                      3.15.0             pyhd8ed1ab_0    conda-forge
zlib                      1.2.13               h166bdaf_4    conda-forge
zstd                      1.5.2                h3eb15da_6    conda-forge
```

</details>



Discussion:
The behaviour change comes from https://github.com/matplotlib/matplotlib/pull/25247.
Just realised that @greglucas already has a plan for this: https://github.com/matplotlib/matplotlib/pull/25247#issuecomment-1490367788
> Just realised that @greglucas already has a plan for this: https://github.com/matplotlib/matplotlib/pull/25247#issuecomment-1490367788

I can't say I actually had a plan for this ;) just that I looked at the code within Cartopy and noticed that there was a lot of path manipulation with the clabel subclass, so at first glance it seems like we should address it here rather than in MPL. I wonder if we can get rid of the GeoContourSet altogether now that it is a single PathCollection in MPL?

Resolving patch:
diff --git a/lib/cartopy/crs.py b/lib/cartopy/crs.py
--- a/lib/cartopy/crs.py
+++ b/lib/cartopy/crs.py
@@ -1247,7 +1247,8 @@ def quick_vertices_transform(self, vertices, src_crs):
             is required (see :meth:`cartopy.crs.Projection.project_geometry`).
 
         """
-        return_value = None
+        if vertices.size == 0:
+            return vertices
 
         if self == src_crs:
             x = vertices[:, 0]
@@ -1258,9 +1259,7 @@ def quick_vertices_transform(self, vertices, src_crs):
             y_limits = (self.y_limits[0] - epsilon, self.y_limits[1] + epsilon)
             if (x.min() >= x_limits[0] and x.max() <= x_limits[1] and
                     y.min() >= y_limits[0] and y.max() <= y_limits[1]):
-                return_value = vertices
-
-        return return_value
+                return vertices
 
 
 class _RectangularProjection(Projection, metaclass=ABCMeta):
diff --git a/lib/cartopy/mpl/contour.py b/lib/cartopy/mpl/contour.py
--- a/lib/cartopy/mpl/contour.py
+++ b/lib/cartopy/mpl/contour.py
@@ -4,10 +4,11 @@
 # See COPYING and COPYING.LESSER in the root of the repository for full
 # licensing details.
 
-
+import matplotlib as mpl
 from matplotlib.contour import QuadContourSet
 import matplotlib.path as mpath
 import numpy as np
+import packaging
 
 
 class GeoContourSet(QuadContourSet):
@@ -20,66 +21,91 @@ class GeoContourSet(QuadContourSet):
     # fiddling with instance.__class__.
 
     def clabel(self, *args, **kwargs):
-        # nb: contour labelling does not work very well for filled
-        # contours - it is recommended to only label line contours.
-        # This is especially true when inline=True.
-
-        # This wrapper exist because mpl does not properly transform
-        # paths. Instead it simply assumes one path represents one polygon
-        # (not necessarily the case), and it assumes that
-        # transform(path.verts) is equivalent to transform_path(path).
-        # Unfortunately there is no way to easily correct this error,
-        # so we are forced to pre-transform the ContourSet's paths from
-        # the source coordinate system to the axes' projection.
-        # The existing mpl code then has a much simpler job of handling
-        # pre-projected paths (which can now effectively be transformed
-        # naively).
-
-        for col in self.collections:
-            # Snaffle the collection's path list. We will change the
-            # list in-place (as the contour label code does in mpl).
-            paths = col.get_paths()
+        if packaging.version.parse(mpl.__version__).release[:2] < (3, 8):
+            # nb: contour labelling does not work very well for filled
+            # contours - it is recommended to only label line contours.
+            # This is especially true when inline=True.
+
+            # This wrapper exist because mpl does not properly transform
+            # paths. Instead it simply assumes one path represents one polygon
+            # (not necessarily the case), and it assumes that
+            # transform(path.verts) is equivalent to transform_path(path).
+            # Unfortunately there is no way to easily correct this error,
+            # so we are forced to pre-transform the ContourSet's paths from
+            # the source coordinate system to the axes' projection.
+            # The existing mpl code then has a much simpler job of handling
+            # pre-projected paths (which can now effectively be transformed
+            # naively).
+
+            for col in self.collections:
+                # Snaffle the collection's path list. We will change the
+                # list in-place (as the contour label code does in mpl).
+                paths = col.get_paths()
+
+                # Define the transform that will take us from collection
+                # coordinates through to axes projection coordinates.
+                data_t = self.axes.transData
+                col_to_data = col.get_transform() - data_t
+
+                # Now that we have the transform, project all of this
+                # collection's paths.
+                new_paths = [col_to_data.transform_path(path)
+                             for path in paths]
+                new_paths = [path for path in new_paths
+                             if path.vertices.size >= 1]
+
+                # The collection will now be referenced in axes projection
+                # coordinates.
+                col.set_transform(data_t)
+
+                # Clear the now incorrectly referenced paths.
+                del paths[:]
+
+                for path in new_paths:
+                    if path.vertices.size == 0:
+                        # Don't persist empty paths. Let's get rid of them.
+                        continue
+
+                    # Split the path if it has multiple MOVETO statements.
+                    codes = np.array(
+                        path.codes if path.codes is not None else [0])
+                    moveto = codes == mpath.Path.MOVETO
+                    if moveto.sum() <= 1:
+                        # This is only one path, so add it to the collection.
+                        paths.append(path)
+                    else:
+                        # The first MOVETO doesn't need cutting-out.
+                        moveto[0] = False
+                        split_locs = np.flatnonzero(moveto)
+
+                        split_verts = np.split(path.vertices, split_locs)
+                        split_codes = np.split(path.codes, split_locs)
+
+                        for verts, codes in zip(split_verts, split_codes):
+                            # Add this path to the collection's list of paths.
+                            paths.append(mpath.Path(verts, codes))
+
+        else:
+            # Where contour paths exist at the edge of the globe, sometimes a
+            # complete path in data space will become multiple paths when
+            # transformed into axes or screen space.  Matplotlib's contour
+            # labelling does not account for this so we need to give it the
+            # pre-transformed paths to work with.
 
             # Define the transform that will take us from collection
             # coordinates through to axes projection coordinates.
             data_t = self.axes.transData
-            col_to_data = col.get_transform() - data_t
+            col_to_data = self.get_transform() - data_t
 
             # Now that we have the transform, project all of this
             # collection's paths.
+            paths = self.get_paths()
             new_paths = [col_to_data.transform_path(path) for path in paths]
-            new_paths = [path for path in new_paths if path.vertices.size >= 1]
+            paths[:] = new_paths
 
             # The collection will now be referenced in axes projection
             # coordinates.
-            col.set_transform(data_t)
-
-            # Clear the now incorrectly referenced paths.
-            del paths[:]
-
-            for path in new_paths:
-                if path.vertices.size == 0:
-                    # Don't persist empty paths. Let's get rid of them.
-                    continue
-
-                # Split the path if it has multiple MOVETO statements.
-                codes = np.array(
-                    path.codes if path.codes is not None else [0])
-                moveto = codes == mpath.Path.MOVETO
-                if moveto.sum() <= 1:
-                    # This is only one path, so add it to the collection.
-                    paths.append(path)
-                else:
-                    # The first MOVETO doesn't need cutting-out.
-                    moveto[0] = False
-                    split_locs = np.flatnonzero(moveto)
-
-                    split_verts = np.split(path.vertices, split_locs)
-                    split_codes = np.split(path.codes, split_locs)
-
-                    for verts, codes in zip(split_verts, split_codes):
-                        # Add this path to the collection's list of paths.
-                        paths.append(mpath.Path(verts, codes))
+            self.set_transform(data_t)
 
         # Now that we have prepared the collection paths, call on
         # through to the underlying implementation.
diff --git a/lib/cartopy/mpl/geoaxes.py b/lib/cartopy/mpl/geoaxes.py
--- a/lib/cartopy/mpl/geoaxes.py
+++ b/lib/cartopy/mpl/geoaxes.py
@@ -45,7 +45,8 @@
 from cartopy.mpl.slippy_image_artist import SlippyImageArtist
 
 
-assert packaging.version.parse(mpl.__version__).release[:2] >= (3, 4), \
+_MPL_VERSION = packaging.version.parse(mpl.__version__)
+assert _MPL_VERSION.release >= (3, 4), \
     'Cartopy is only supported with Matplotlib 3.4 or greater.'
 
 # A nested mapping from path, source CRS, and target projection to the
@@ -1602,12 +1603,15 @@ def contour(self, *args, **kwargs):
         result = super().contour(*args, **kwargs)
 
         # We need to compute the dataLim correctly for contours.
-        bboxes = [col.get_datalim(self.transData)
-                  for col in result.collections
-                  if col.get_paths()]
-        if bboxes:
-            extent = mtransforms.Bbox.union(bboxes)
-            self.update_datalim(extent.get_points())
+        if _MPL_VERSION.release[:2] < (3, 8):
+            bboxes = [col.get_datalim(self.transData)
+                      for col in result.collections
+                      if col.get_paths()]
+            if bboxes:
+                extent = mtransforms.Bbox.union(bboxes)
+                self.update_datalim(extent.get_points())
+        else:
+            self.update_datalim(result.get_datalim(self.transData))
 
         self.autoscale_view()
 
@@ -1650,12 +1654,15 @@ def contourf(self, *args, **kwargs):
         result = super().contourf(*args, **kwargs)
 
         # We need to compute the dataLim correctly for contours.
-        bboxes = [col.get_datalim(self.transData)
-                  for col in result.collections
-                  if col.get_paths()]
-        if bboxes:
-            extent = mtransforms.Bbox.union(bboxes)
-            self.update_datalim(extent.get_points())
+        if _MPL_VERSION.release[:2] < (3, 8):
+            bboxes = [col.get_datalim(self.transData)
+                      for col in result.collections
+                      if col.get_paths()]
+            if bboxes:
+                extent = mtransforms.Bbox.union(bboxes)
+                self.update_datalim(extent.get_points())
+        else:
+            self.update_datalim(result.get_datalim(self.transData))
 
         self.autoscale_view()
 


Test patch:
diff --git a/lib/cartopy/tests/mpl/test_examples.py b/lib/cartopy/tests/mpl/test_examples.py
--- a/lib/cartopy/tests/mpl/test_examples.py
+++ b/lib/cartopy/tests/mpl/test_examples.py
@@ -8,6 +8,7 @@
 import pytest
 
 import cartopy.crs as ccrs
+from cartopy.tests.mpl import MPL_VERSION
 
 
 @pytest.mark.natural_earth
@@ -31,7 +32,9 @@ def test_global_map():
 
 
 @pytest.mark.natural_earth
-@pytest.mark.mpl_image_compare(filename='contour_label.png', tolerance=0.5)
+@pytest.mark.mpl_image_compare(
+    filename='contour_label.png',
+    tolerance=3.9 if MPL_VERSION.release[:2] >= (3, 8) else 0.5)
 def test_contour_label():
     from cartopy.tests.mpl.test_caching import sample_data
     fig = plt.figure()