Skip to content

Commit 76882b3

Browse files
authored
Merge pull request #1904 from QuLogic/backport-0.20
Backport PRs for 0.20.1
2 parents 851199b + 70d6f6e commit 76882b3

File tree

14 files changed

+103
-43
lines changed

14 files changed

+103
-43
lines changed

lib/cartopy/mpl/geoaxes.py

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1793,7 +1793,7 @@ def pcolormesh(self, *args, **kwargs):
17931793
"""
17941794
# Add in an argument checker to handle Matplotlib's potential
17951795
# interpolation when coordinate wraps are involved
1796-
args = self._wrap_args(*args, **kwargs)
1796+
args, kwargs = self._wrap_args(*args, **kwargs)
17971797
result = matplotlib.axes.Axes.pcolormesh(self, *args, **kwargs)
17981798
# Wrap the quadrilaterals if necessary
17991799
result = self._wrap_quadmesh(result, **kwargs)
@@ -1815,8 +1815,11 @@ def _wrap_args(self, *args, **kwargs):
18151815
if not (kwargs.get('shading', default_shading) in
18161816
('nearest', 'auto') and len(args) == 3 and
18171817
getattr(kwargs.get('transform'), '_wrappable', False)):
1818-
return args
1818+
return args, kwargs
18191819

1820+
# We have changed the shading from nearest/auto to flat
1821+
# due to the addition of an extra coordinate
1822+
kwargs['shading'] = 'flat'
18201823
X = np.asanyarray(args[0])
18211824
Y = np.asanyarray(args[1])
18221825
nrows, ncols = np.asanyarray(args[2]).shape
@@ -1852,7 +1855,7 @@ def _interp_grid(X, wrap=0):
18521855
X = _interp_grid(X.T, wrap=xwrap).T
18531856
Y = _interp_grid(Y.T).T
18541857

1855-
return (X, Y, args[2])
1858+
return (X, Y, args[2]), kwargs
18561859

18571860
def _wrap_quadmesh(self, collection, **kwargs):
18581861
"""
@@ -1868,8 +1871,13 @@ def _wrap_quadmesh(self, collection, **kwargs):
18681871
# Get the quadmesh data coordinates
18691872
coords = collection._coordinates
18701873
Ny, Nx, _ = coords.shape
1874+
if kwargs.get('shading') == 'gouraud':
1875+
# Gouraud shading has the same shape for coords and data
1876+
data_shape = Ny, Nx
1877+
else:
1878+
data_shape = Ny - 1, Nx - 1
18711879
# data array
1872-
C = collection.get_array().reshape((Ny - 1, Nx - 1))
1880+
C = collection.get_array().reshape(data_shape)
18731881

18741882
transformed_pts = self.projection.transform_points(
18751883
t, coords[..., 0], coords[..., 1])
@@ -1898,6 +1906,23 @@ def _wrap_quadmesh(self, collection, **kwargs):
18981906
# No wrapping needed
18991907
return collection
19001908

1909+
# Wrapping with gouraud shading is error-prone. We will do our best,
1910+
# but pcolor does not handle gouraud shading, so there needs to be
1911+
# another way to handle the wrapped cells.
1912+
if kwargs.get('shading') == 'gouraud':
1913+
warnings.warn("Handling wrapped coordinates with gouraud "
1914+
"shading is likely to introduce artifacts. "
1915+
"It is recommended to remove the wrap manually "
1916+
"before calling pcolormesh.")
1917+
# With gouraud shading, we actually want an (Ny, Nx) shaped mask
1918+
gmask = np.zeros(data_shape, dtype=bool)
1919+
# If any of the cells were wrapped, apply it to all 4 corners
1920+
gmask[:-1, :-1] |= mask
1921+
gmask[1:, :-1] |= mask
1922+
gmask[1:, 1:] |= mask
1923+
gmask[:-1, 1:] |= mask
1924+
mask = gmask
1925+
19011926
# We have quadrilaterals that cross the wrap boundary
19021927
# Now, we need to update the original collection with
19031928
# a mask over those cells and use pcolor to draw those
@@ -1978,7 +2003,11 @@ def pcolor(self, *args, **kwargs):
19782003
"""
19792004
# Add in an argument checker to handle Matplotlib's potential
19802005
# interpolation when coordinate wraps are involved
1981-
args = self._wrap_args(*args, **kwargs)
2006+
args, kwargs = self._wrap_args(*args, **kwargs)
2007+
if matplotlib.__version__ < "3.3":
2008+
# MPL 3.3 introduced the shading option, and it isn't
2009+
# handled before that for pcolor calls.
2010+
kwargs.pop('shading', None)
19822011
result = matplotlib.axes.Axes.pcolor(self, *args, **kwargs)
19832012

19842013
# Update the datalim for this pcolor.

lib/cartopy/mpl/gridliner.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -796,8 +796,6 @@ def update_artist(artist, renderer):
796796
# Cache a few things so they aren't re-calculated in the loops.
797797
crs_transform = self._crs_transform().transform
798798
inverse_data_transform = self.axes.transData.inverted().transform_point
799-
if self.x_inline or self.y_inline:
800-
pc_transform = PlateCarree()
801799

802800
for xylabel, lines, line_ticks, formatter, label_style in (
803801
('x', lon_lines, lon_ticks,
@@ -899,7 +897,7 @@ def update_artist(artist, renderer):
899897
# Initial text specs
900898
x0, y0 = pt0
901899
if x_inline or y_inline:
902-
kw = {'rotation': 0, 'transform': pc_transform,
900+
kw = {'rotation': 0, 'transform': self.crs,
903901
'ha': 'center', 'va': 'center'}
904902
loc = 'inline'
905903
else:
824 Bytes
Loading
166 Bytes
Loading
367 Bytes
Loading
1.32 KB
Loading
874 Bytes
Loading
262 Bytes
Loading

lib/cartopy/tests/mpl/test_mpl_integration.py

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,7 @@ def test_pcolormesh_diagonal_wrap():
583583
# and the bottom edge on the other gets wrapped properly
584584
xs = [[160, 170], [190, 200]]
585585
ys = [[-10, -10], [10, 10]]
586-
zs = [[0, 1], [0, 1]]
586+
zs = [[0]]
587587

588588
ax = plt.axes(projection=ccrs.PlateCarree())
589589
mesh = ax.pcolormesh(xs, ys, zs)
@@ -652,6 +652,31 @@ def test_pcolormesh_wrap_set_array():
652652
coll.set_array(Z.ravel())
653653

654654

655+
@pytest.mark.parametrize('shading, input_size, expected', [
656+
pytest.param('auto', 3, 4, id='auto same size'),
657+
pytest.param('auto', 4, 4, id='auto input larger'),
658+
pytest.param('nearest', 3, 4, id='nearest same size'),
659+
pytest.param('nearest', 4, 4, id='nearest input larger'),
660+
pytest.param('flat', 4, 4, id='flat input larger'),
661+
pytest.param('gouraud', 3, 3, id='gouraud same size')
662+
])
663+
def test_pcolormesh_shading(shading, input_size, expected):
664+
# Testing that the coordinates are all broadcast as expected with
665+
# the various shading options
666+
# The data shape is (3, 3) and we are changing the input shape
667+
# based upon that
668+
ax = plt.axes(projection=ccrs.PlateCarree())
669+
670+
x = np.arange(input_size)
671+
y = np.arange(input_size)
672+
d = np.zeros((3, 3))
673+
674+
coll = ax.pcolormesh(x, y, d, shading=shading)
675+
# We can use coll.get_coordinates() once MPL >= 3.5 is required
676+
# For now, we use the private variable for testing
677+
assert coll._coordinates.shape == (expected, expected, 2)
678+
679+
655680
@pytest.mark.natural_earth
656681
@ImageTesting(['quiver_plate_carree'])
657682
def test_quiver_plate_carree():
@@ -830,8 +855,10 @@ def test_barbs_1d_transformed():
830855

831856

832857
@pytest.mark.natural_earth
833-
@ImageTesting(['streamplot'], style='mpl20',
834-
tolerance=42 if MPL_VERSION < parse_version('3.2') else 0.54)
858+
@ImageTesting(
859+
['streamplot'], style='mpl20',
860+
tolerance=(42 if MPL_VERSION.release[:2] < (3, 2) else
861+
9.77 if MPL_VERSION.release[:2] < (3, 5) else 0.5))
835862
def test_streamplot():
836863
x = np.arange(-60, 42.5, 2.5)
837864
y = np.arange(30, 72.5, 2.5)

lib/cartopy/tests/mpl/test_pseudo_color.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515

1616
def test_pcolormesh_partially_masked():
17-
data = np.ma.masked_all((40, 30))
17+
data = np.ma.masked_all((39, 29))
1818
data[0:100] = 10
1919

2020
# Check that a partially masked data array does trigger a pcolor call.
@@ -27,7 +27,7 @@ def test_pcolormesh_partially_masked():
2727

2828

2929
def test_pcolormesh_invisible():
30-
data = np.zeros((3, 3))
30+
data = np.zeros((2, 2))
3131

3232
# Check that a fully invisible mesh doesn't fail.
3333
with mock.patch('cartopy.mpl.geoaxes.GeoAxes.pcolor') as pcolor:

0 commit comments

Comments
 (0)