diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index fd4d8d514..6ef1be700 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -24,18 +24,17 @@ jobs: channels: conda-forge/label/testing,conda-forge - name: Minimum packages - # Only run on macos for now + # Only run on Linux for now # Conda's linux packages don't grab the testing label of matplotlib causing failures due to freetype differences - if: matrix.python-version == '3.7' && matrix.os == 'macos-latest' + if: matrix.python-version == '3.7' && matrix.os == 'ubuntu-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 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 shapely" >> $GITHUB_ENV + echo "PACKAGES=cython fiona matplotlib-base numpy pyproj 'proj>=8' pykdtree scipy shapely" >> $GITHUB_ENV - name: Coverage packages id: coverage @@ -51,6 +50,10 @@ jobs: PACKAGES="$PACKAGES flufl.lock owslib pep8 pillow pyshp pytest" PACKAGES="$PACKAGES pytest-xdist requests setuptools_scm" PACKAGES="$PACKAGES setuptools_scm_git_archive shapely" + # openssl 3.0 updated the legacy renegotiation default, which causes + # failures in NASA's WMTS server. They will need to update their + # server before we can use a newer openssl. + PACKAGES="$PACKAGES openssl<3" conda install $PACKAGES conda info -a conda list diff --git a/lib/cartopy/mpl/geoaxes.py b/lib/cartopy/mpl/geoaxes.py index 4f73e8032..fcedf2f30 100644 --- a/lib/cartopy/mpl/geoaxes.py +++ b/lib/cartopy/mpl/geoaxes.py @@ -1863,10 +1863,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 @@ -1902,8 +1898,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 index e66bc7d89..77e916d2e 100644 --- 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 diff --git a/lib/cartopy/tests/mpl/baseline_images/mpl/test_features/natural_earth.png b/lib/cartopy/tests/mpl/baseline_images/mpl/test_features/natural_earth.png index 9ac86af51..cedc5cabb 100644 Binary files a/lib/cartopy/tests/mpl/baseline_images/mpl/test_features/natural_earth.png and b/lib/cartopy/tests/mpl/baseline_images/mpl/test_features/natural_earth.png differ diff --git a/lib/cartopy/tests/mpl/test_features.py b/lib/cartopy/tests/mpl/test_features.py index 024775851..28cf5431b 100644 --- a/lib/cartopy/tests/mpl/test_features.py +++ b/lib/cartopy/tests/mpl/test_features.py @@ -16,7 +16,7 @@ @pytest.mark.filterwarnings("ignore:Downloading") @pytest.mark.natural_earth -@ImageTesting(['natural_earth']) +@ImageTesting(['natural_earth'], tolerance=0.97) def test_natural_earth(): ax = plt.axes(projection=ccrs.PlateCarree()) ax.add_feature(cfeature.LAND) diff --git a/lib/cartopy/tests/mpl/test_mpl_integration.py b/lib/cartopy/tests/mpl/test_mpl_integration.py index 3315d0b7b..a76652e06 100644 --- a/lib/cartopy/tests/mpl/test_mpl_integration.py +++ b/lib/cartopy/tests/mpl/test_mpl_integration.py @@ -19,7 +19,7 @@ # This is due to a change in MPL 3.5 contour line paths changing # ever so slightly. -contour_tol = 2.24 +contour_tol = 2.25 @pytest.mark.natural_earth @ImageTesting(['global_contour_wrap'], style='mpl20', tolerance=contour_tol) @@ -257,7 +257,7 @@ def test_cursor_values(): @pytest.mark.natural_earth -@ImageTesting(['natural_earth_interface'], tolerance=0.21) +@ImageTesting(['natural_earth_interface'], tolerance=1.21) def test_axes_natural_earth_interface(): rob = ccrs.Robinson() diff --git a/lib/cartopy/tests/mpl/test_pseudo_color.py b/lib/cartopy/tests/mpl/test_pseudo_color.py index c3a822f29..8e97d128a 100644 --- a/lib/cartopy/tests/mpl/test_pseudo_color.py +++ b/lib/cartopy/tests/mpl/test_pseudo_color.py @@ -84,3 +84,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)