Repository: SciTools/cartopy

Issue:
Update pcolormesh with new matplotlib versions
### Description
<!-- Please provide a general introduction to the issue/proposal. -->
The current master of matplotlib has changed the keyword arguments for `pcolor*`. See: https://github.com/matplotlib/matplotlib/pull/16258

We will need to change the `_pcolormesh_patched` function. Specifically, the call to `_pcolor_args` and the `shading` option and get rid of `allmatch` when that update from mpl is released.

Note: I didn't find any version checks and if statements to handle cases like this for MPL_VERSION in the code, only in the tests, so I'm also not sure how we want to handle this.


Discussion:
Just to add that this is slated for release with matplotlib 3.3.

Resolving patch:
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
@@ -1,4 +1,4 @@
-# (C) British Crown Copyright 2011 - 2019, Met Office
+# (C) British Crown Copyright 2011 - 2020, Met Office
 #
 # This file is part of cartopy.
 #
@@ -52,7 +52,14 @@ def clabel(self, *args, **kwargs):
             # list in-place (as the contour label code does in mpl).
             paths = col.get_paths()
 
-            data_t = self.ax.transData
+            # The ax attribute is deprecated in MPL 3.3 in favor of
+            # axes. So, here we test if axes is present and fall back
+            # on the old self.ax to support MPL versions less than 3.3
+            if hasattr(self, "axes"):
+                data_t = self.axes.transData
+            else:
+                data_t = self.ax.transData
+
             # Define the transform that will take us from collection
             # coordinates through to axes projection coordinates.
             col_to_data = col.get_transform() - data_t
@@ -64,7 +71,7 @@ def clabel(self, *args, **kwargs):
 
             # The collection will now be referenced in axes projection
             # coordinates.
-            col.set_transform(self.ax.transData)
+            col.set_transform(data_t)
 
             # Clear the now incorrectly referenced paths.
             del paths[:]
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
@@ -441,7 +441,7 @@ def hold_limits(self, hold=True):
                     self._autoscaleXon, self._autoscaleYon) = other
 
     @matplotlib.artist.allow_rasterization
-    def draw(self, renderer=None, inframe=False):
+    def draw(self, renderer=None, **kwargs):
         """
         Extend the standard behaviour of :func:`matplotlib.axes.Axes.draw`.
 
@@ -475,8 +475,8 @@ def draw(self, renderer=None, inframe=False):
                 self.imshow(img, extent=extent, origin=origin,
                             transform=factory.crs, *args[1:], **kwargs)
         self._done_img_factory = True
-        return matplotlib.axes.Axes.draw(self, renderer=renderer,
-                                         inframe=inframe)
+
+        return matplotlib.axes.Axes.draw(self, renderer=renderer, **kwargs)
 
     def _update_title_position(self, renderer):
         matplotlib.axes.Axes._update_title_position(self, renderer)
@@ -1583,13 +1583,20 @@ def _pcolormesh_patched(self, *args, **kwargs):
         cmap = kwargs.pop('cmap', None)
         vmin = kwargs.pop('vmin', None)
         vmax = kwargs.pop('vmax', None)
-        shading = kwargs.pop('shading', 'flat').lower()
         antialiased = kwargs.pop('antialiased', False)
         kwargs.setdefault('edgecolors', 'None')
 
-        allmatch = (shading == 'gouraud')
+        if matplotlib.__version__ < "3.3":
+            shading = kwargs.pop('shading', 'flat')
+            allmatch = (shading == 'gouraud')
+            X, Y, C = self._pcolorargs('pcolormesh', *args, allmatch=allmatch)
+        else:
+            shading = kwargs.pop('shading', 'auto')
+            if shading is None:
+                shading = 'auto'
+            X, Y, C, shading = self._pcolorargs('pcolormesh', *args,
+                                                shading=shading)
 
-        X, Y, C = self._pcolorargs('pcolormesh', *args, allmatch=allmatch)
         Ny, Nx = X.shape
 
         # convert to one dimensional arrays


Test patch:
diff --git a/lib/cartopy/tests/mpl/test_caching.py b/lib/cartopy/tests/mpl/test_caching.py
--- a/lib/cartopy/tests/mpl/test_caching.py
+++ b/lib/cartopy/tests/mpl/test_caching.py
@@ -1,4 +1,4 @@
-# (C) British Crown Copyright 2011 - 2019, Met Office
+# (C) British Crown Copyright 2011 - 2020, Met Office
 #
 # This file is part of cartopy.
 #
@@ -151,8 +151,9 @@ def test_shapefile_transform_cache():
 
 
 def test_contourf_transform_path_counting():
+    fig = plt.figure()
     ax = plt.axes(projection=ccrs.Robinson())
-    ax.figure.canvas.draw()
+    fig.canvas.draw()
 
     # Capture the size of the cache before our test.
     gc.collect()
diff --git a/lib/cartopy/tests/mpl/test_gridliner.py b/lib/cartopy/tests/mpl/test_gridliner.py
--- a/lib/cartopy/tests/mpl/test_gridliner.py
+++ b/lib/cartopy/tests/mpl/test_gridliner.py
@@ -315,6 +315,7 @@ def test_grid_labels_inline_usa():
      ])
 def test_gridliner_default_fmtloc(
         proj, gcrs, xloc, xfmt, xloc_expected, xfmt_expected):
+    plt.figure()
     ax = plt.subplot(111, projection=proj)
     gl = ax.gridlines(crs=gcrs, draw_labels=False, xlocs=xloc, xformatter=xfmt)
     plt.close()
diff --git a/lib/cartopy/tests/mpl/test_mpl_integration.py b/lib/cartopy/tests/mpl/test_mpl_integration.py
--- a/lib/cartopy/tests/mpl/test_mpl_integration.py
+++ b/lib/cartopy/tests/mpl/test_mpl_integration.py
@@ -93,7 +93,7 @@ def test_global_pcolor_wrap_new_transform():
     ax = plt.axes(projection=ccrs.PlateCarree())
     ax.coastlines()
     x, y = np.meshgrid(np.linspace(0, 360), np.linspace(-90, 90))
-    data = np.sin(np.sqrt(x ** 2 + y ** 2))
+    data = np.sin(np.sqrt(x ** 2 + y ** 2))[:-1, :-1]
     plt.pcolor(x, y, data, transform=ccrs.PlateCarree())
 
 
@@ -103,7 +103,7 @@ def test_global_pcolor_wrap_no_transform():
     ax = plt.axes(projection=ccrs.PlateCarree())
     ax.coastlines()
     x, y = np.meshgrid(np.linspace(0, 360), np.linspace(-90, 90))
-    data = np.sin(np.sqrt(x ** 2 + y ** 2))
+    data = np.sin(np.sqrt(x ** 2 + y ** 2))[:-1, :-1]
     plt.pcolor(x, y, data)
 
 
@@ -148,6 +148,7 @@ def test_global_map():
              transform=ccrs.Geodetic())
 
 
+@pytest.mark.filterwarnings("ignore:Unable to determine extent")
 @pytest.mark.natural_earth
 @ImageTesting(['simple_global'])
 def test_simple_global():
@@ -156,6 +157,7 @@ def test_simple_global():
     # produces a global map, despite not having needed to set the limits
 
 
+@pytest.mark.filterwarnings("ignore:Unable to determine extent")
 @pytest.mark.natural_earth
 @ImageTesting(['multiple_projections4' if ccrs.PROJ4_VERSION < (5, 0, 0)
                else 'multiple_projections5'],
@@ -187,7 +189,7 @@ def test_multiple_projections():
                    ccrs.EckertVI(),
                    ]
 
-    rows = np.ceil(len(projections) / 5)
+    rows = np.ceil(len(projections) / 5).astype(int)
 
     fig = plt.figure(figsize=(10, 2 * rows))
     for i, prj in enumerate(projections, 1):