Repository: SciTools/cartopy

Issue:
Global map cropped with pcolormesh when lats > 90
Here is a mwe:

```python
import matplotlib
import matplotlib.pyplot as plt
import numpy as np 
import cartopy
import cartopy.crs as ccrs  

print('matplotlib', matplotlib.__version__)
print('cartopy', cartopy.__version__)

lon = np.linspace(-179.625, 179.625, 480)
lat = np.linspace(90, -90, 241)
data, _ = np.meshgrid(lon, lat)

plt.figure()
ax = plt.axes(projection=ccrs.EqualEarth())
plt.pcolormesh(lon, lat, data, transform=ccrs.PlateCarree(), shading='nearest')
ax.coastlines(); ax.gridlines();
```

Which produces:
![image](https://user-images.githubusercontent.com/10050469/143658015-03b38361-98ed-451c-9ff8-ff9f26e446a7.png)

Strangely enough, this does not occur with other coordinates (here in steps of 1):

```python
lon = np.linspace(-180, 180, 361)
lat = np.linspace(90, -90, 181)
data, _ = np.meshgrid(lon, lat)

plt.figure()
ax = plt.axes(projection=ccrs.EqualEarth())
plt.pcolormesh(lon, lat, data, transform=ccrs.PlateCarree(), shading='nearest')
ax.coastlines(); ax.gridlines();
```

![image](https://user-images.githubusercontent.com/10050469/143658094-ea177c60-7e62-4915-9d48-4c9c875e7f40.png)

This is:

```
matplotlib 3.4.3
cartopy 0.20.1
```




Discussion:
Ok yes, this happens when the bounds [-180, 180] are not included in the coordinates. In my first example above however, if `shading='nearest'` is correctly interpreted, the bounds are actually correct. (note that I come from xarray, where plots that used to work before - previous version unknown -  now have this issue with the latest stable versions) 
I think I have found that the problem reliably occurs when the latitudes are > 90°, which happens in the case above and auto shading. See e.g. with `shading='flat'`: 

```python
lon = np.linspace(-179.625, 179.625, 480)
lat = np.linspace(90.1, -90.1, 241)
data, _ = np.meshgrid(lon[1:], lat[1:])

plt.figure()
ax = plt.axes(projection=ccrs.EqualEarth())
plt.pcolormesh(lon, lat, data, transform=ccrs.PlateCarree(), shading='flat')
ax.coastlines(); ax.gridlines();
```

![image](https://user-images.githubusercontent.com/10050469/143683987-78b6652f-f21d-4bda-9750-8902ad0b60fd.png)

**This problem does not occur with cartopy 0.18.0**.


Resolving patch:
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
@@ -1794,10 +1794,6 @@ def _wrap_quadmesh(self, collection, **kwargs):
         cross the boundary of the projection.
         """
         t = kwargs.get('transform', None)
-        if not (getattr(t, '_wrappable', False) and
-                getattr(self.projection, '_wrappable', False)):
-            # Nothing to do
-            return collection
 
         # Get the quadmesh data coordinates
         coords = collection._coordinates
@@ -1833,8 +1829,25 @@ def _wrap_quadmesh(self, collection, **kwargs):
                     np.isnan(diagonal1_lengths) |
                     (diagonal1_lengths > size_limit))
 
-        if not np.any(mask):
-            # No wrapping needed
+        # Update the data limits based on the corners of the mesh
+        # in transformed coordinates, ignoring nan values
+        with warnings.catch_warnings():
+            warnings.filterwarnings('ignore', 'All-NaN slice encountered')
+            # If we have all nans, that is OK and will be handled by the
+            # Bbox calculations later, so suppress that warning from the user
+            corners = ((np.nanmin(xs), np.nanmin(ys)),
+                       (np.nanmax(xs), np.nanmax(ys)))
+        collection._corners = mtransforms.Bbox(corners)
+        self.update_datalim(collection._corners)
+
+        # We need to keep the transform/projection check after
+        # update_datalim to make sure we are getting the proper
+        # datalims on the returned collection
+        if (not (getattr(t, '_wrappable', False) and
+                 getattr(self.projection, '_wrappable', False)) or
+                not np.any(mask)):
+            # If both projections are unwrappable
+            # or if there aren't any points to wrap
             return collection
 
         # Wrapping with gouraud shading is error-prone. We will do our best,
diff --git a/lib/cartopy/mpl/geocollection.py b/lib/cartopy/mpl/geocollection.py
--- a/lib/cartopy/mpl/geocollection.py
+++ b/lib/cartopy/mpl/geocollection.py
@@ -52,3 +52,8 @@ def set_clim(self, vmin=None, vmax=None):
 
         # Update color limits for the rest of the cells.
         super().set_clim(vmin, vmax)
+
+    def get_datalim(self, transData):
+        # Return the corners that were calculated in
+        # the pcolormesh routine.
+        return self._corners


Test patch:
diff --git a/lib/cartopy/tests/mpl/test_pseudo_color.py b/lib/cartopy/tests/mpl/test_pseudo_color.py
--- a/lib/cartopy/tests/mpl/test_pseudo_color.py
+++ b/lib/cartopy/tests/mpl/test_pseudo_color.py
@@ -81,3 +81,46 @@ def test_pcolormesh_arg_interpolation():
                           [2, 20],
                           [4, 20]]])
     np.testing.assert_array_almost_equal(expected, coll._coordinates)
+
+
+def test_pcolormesh_datalim():
+    # Test that wrapping the coordinates still produces proper data limits
+    x = [359, 1, 3]
+    y = [-10, 10]
+
+    xs, ys = np.meshgrid(x, y)
+    # Z with the same shape as X/Y to force the interpolation
+    z = np.zeros(xs.shape)
+
+    ax = plt.subplot(2, 1, 1, projection=ccrs.PlateCarree())
+    coll = ax.pcolormesh(xs, ys, z, shading='auto',
+                         transform=ccrs.PlateCarree())
+
+    coll_bbox = coll.get_datalim(ax.transData)
+    np.testing.assert_array_equal(coll_bbox, [[-2, -20], [4, 20]])
+
+    # Non-wrapped coordinates
+    x = [-80, 0, 80]
+    y = [-10, 10]
+
+    xs, ys = np.meshgrid(x, y)
+    ax = plt.subplot(2, 1, 1, projection=ccrs.PlateCarree())
+    coll = ax.pcolormesh(xs, ys, z, shading='auto',
+                         transform=ccrs.PlateCarree())
+
+    coll_bbox = coll.get_datalim(ax.transData)
+    np.testing.assert_array_equal(coll_bbox, [[-120, -20], [120, 20]])
+
+    # A projection that doesn't support wrapping
+    x = [-10, 0, 10]
+    y = [-10, 10]
+
+    xs, ys = np.meshgrid(x, y)
+    ax = plt.subplot(2, 1, 1, projection=ccrs.Orthographic())
+    coll = ax.pcolormesh(xs, ys, z, shading='auto',
+                         transform=ccrs.PlateCarree())
+
+    coll_bbox = coll.get_datalim(ax.transData)
+    expected = [[-1650783.327873, -2181451.330891],
+                [1650783.327873, 2181451.330891]]
+    np.testing.assert_array_almost_equal(coll_bbox, expected)