From b3cf153989ea154725601dc3d42f0386087df359 Mon Sep 17 00:00:00 2001 From: simonpf Date: Fri, 27 Oct 2017 08:26:29 +0200 Subject: [PATCH 1/7] Extended pcolormesh to support X and Y grids that are larger than the color grid also for gouraud shading. --- lib/matplotlib/axes/_axes.py | 54 +++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index c730eba4fd6d..51e569b8b1d4 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -5156,17 +5156,26 @@ def imshow(self, X, cmap=None, norm=None, aspect=None, @staticmethod def _pcolorargs(funcname, *args, **kw): - # This takes one kwarg, allmatch. - # If allmatch is True, then the incoming X, Y, C must - # have matching dimensions, taking into account that - # X and Y can be 1-D rather than 2-D. This perfect - # match is required for Gouroud shading. For flat - # shading, X and Y specify boundaries, so we need - # one more boundary than color in each direction. - # For convenience, and consistent with Matlab, we - # discard the last row and/or column of C if necessary - # to meet this condition. This is done if allmatch - # is False. + # This function takes care of resizing the grids X and Y + # to match the size of the color grid C. + # + # If only a color grid is given dummy grids for X and Y are + # created, matching the dimensions of C. + # + # If given, the X and Y grids must have the same size or + # one more row and column than C. + # + # If the keyword allmatch is given and True the returned X, Y and + # C grids will have the same dimensions. If this is not the case + # on input, this is achieved by linearly interpolating the grids + # to obtain their midpoints. This is what is required for gouraud + # shading. + # + # If the keyword allmatch is not given or False the returned + # X, Y will have one more row and column than the C grid, which + # is achieved by potentially dropping the last row and column of + # X and Y. This is consistent with Matlab behaviour. This is + # required for flat shading. allmatch = kw.pop("allmatch", False) @@ -5200,16 +5209,23 @@ def _pcolorargs(funcname, *args, **kw): raise TypeError( 'Incompatible X, Y inputs to %s; see help(%s)' % ( funcname, funcname)) + + if not (numCols in (Nx, Nx - 1) and numRows in (Ny, Ny - 1)): + raise TypeError('Dimensions of C %s are incompatible with' + ' X (%d) and/or Y (%d); see help(%s)' % ( + C.shape, Nx, Ny, funcname)) + if allmatch: - if not (Nx == numCols and Ny == numRows): - raise TypeError('Dimensions of C %s are incompatible with' - ' X (%d) and/or Y (%d); see help(%s)' % ( - C.shape, Nx, Ny, funcname)) + if numRows == Ny - 1: + Y_new = 0.5 * Y[:numRows, :numCols] + Y_new += 0.5 * Y[1:, 1:] + Y = Y_new + + if numCols == Nx - 1: + X_new = 0.5 * X[:numRows, :numCols] + X_new += 0.5 * X[1:, 1:] + X = X_new else: - if not (numCols in (Nx, Nx - 1) and numRows in (Ny, Ny - 1)): - raise TypeError('Dimensions of C %s are incompatible with' - ' X (%d) and/or Y (%d); see help(%s)' % ( - C.shape, Nx, Ny, funcname)) C = C[:Ny - 1, :Nx - 1] C = cbook.safe_masked_invalid(C) return X, Y, C From 135bf7f4ed4fc62767030b944d7042098b1357c7 Mon Sep 17 00:00:00 2001 From: simonpf Date: Fri, 27 Oct 2017 08:40:35 +0200 Subject: [PATCH 2/7] Adapted pcolormesh test. --- lib/matplotlib/tests/test_axes.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 12c219215024..c82705ffc719 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -1186,10 +1186,6 @@ def test_pcolorargs(): ax.pcolormesh(y, x, Z) with pytest.raises(TypeError): ax.pcolormesh(X, Y, Z.T) - with pytest.raises(TypeError): - ax.pcolormesh(x, y, Z[:-1, :-1], shading="gouraud") - with pytest.raises(TypeError): - ax.pcolormesh(X, Y, Z[:-1, :-1], shading="gouraud") @image_comparison(baseline_images=['canonical']) From dc30842ff37dbe213cd2fd346225ef3d394a8e8d Mon Sep 17 00:00:00 2001 From: simonpf Date: Sat, 28 Oct 2017 23:58:33 +0200 Subject: [PATCH 3/7] Added interpolate_boundaries to pcolormesh to allow for interpolation of X and Y for Gouraud shading in case of dimension mismatch. --- lib/matplotlib/axes/_axes.py | 64 ++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index 51e569b8b1d4..156304c1de01 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -5178,6 +5178,7 @@ def _pcolorargs(funcname, *args, **kw): # required for flat shading. allmatch = kw.pop("allmatch", False) + interpolate_grids = kw.pop("interpolate_grids", False) if len(args) == 1: C = np.asanyarray(args[0]) @@ -5216,15 +5217,25 @@ def _pcolorargs(funcname, *args, **kw): C.shape, Nx, Ny, funcname)) if allmatch: - if numRows == Ny - 1: - Y_new = 0.5 * Y[:numRows, :numCols] - Y_new += 0.5 * Y[1:, 1:] - Y = Y_new - - if numCols == Nx - 1: - X_new = 0.5 * X[:numRows, :numCols] - X_new += 0.5 * X[1:, 1:] - X = X_new + if numRows != Ny or numCols != Nx: + if interpolate_grids: + + if numRows == Ny - 1: + Y_new = 0.5 * Y[:numRows, :numCols] + Y_new += 0.5 * Y[1:, 1:] + Y = Y_new + + if numCols == Nx - 1: + X_new = 0.5 * X[:numRows, :numCols] + X_new += 0.5 * X[1:, 1:] + X = X_new + + else: + + raise TypeError('Dimensions of C %s are incompatible with' + ' X (%d) and/or Y (%d); see help(%s)' % ( + C.shape, Nx, Ny, funcname)) + else: C = C[:Ny - 1, :Nx - 1] C = cbook.safe_masked_invalid(C) @@ -5514,6 +5525,22 @@ def pcolormesh(self, *args, **kwargs): contrast, :func:`~matplotlib.pyplot.pcolor` simply does not draw quadrilaterals with masked colors or vertices. + If flat shading is used, the arrays *X* and *Y* are assumed to + specify the boundary points of quadrilaterals. They should thus + each have one more column and row than the *C* array. For compatibility + with Matlab as well as convenience, the case in which *X*, *Y*, *C* + have the same dimension is also accepted and handled by dropping the + last row and column of *C*. + + If Gouraud shading is used, the arrays *X* and *Y* are assumed to + specify the centers of the quadrilaterals and thus should have the + same dimensions as *C*. If this is not the case an error will be + thrown. However, for compatibility with the flat shading case, the + ``interpolate_grids`` keyword argument is provided. When set to + ``True`` and *X* and *Y* have one row and column more then *C*, + *X* and *Y* will be linearly interpolated to obtain the corresponding + centerpoints. + Keyword arguments: *cmap*: [ *None* | Colormap ] @@ -5552,6 +5579,19 @@ def pcolormesh(self, *args, **kwargs): *alpha*: ``0 <= scalar <= 1`` or *None* the alpha blending value + *interpolate_grids*: [``True`` | ``False``] + + When set to ``True`` and Gouraud shading is used with *X* and + *Y* with one more row and column than *C*, *X* and *Y* will be + linearly interpolated to obtain the centers of the quadrilaterals + described by *X* and *Y*. + + When set to ``False`` the above case with cause an error to be + thrown. + + Ignored when ``shading = flat``. + + Return value is a :class:`matplotlib.collections.QuadMesh` object. @@ -5577,11 +5617,15 @@ def pcolormesh(self, *args, **kwargs): vmax = kwargs.pop('vmax', None) shading = kwargs.pop('shading', 'flat').lower() antialiased = kwargs.pop('antialiased', False) + interpolate_grids = kwargs.pop('interpolate_grids', False) kwargs.setdefault('edgecolors', 'None') allmatch = (shading == 'gouraud') - X, Y, C = self._pcolorargs('pcolormesh', *args, allmatch=allmatch) + X, Y, C = self._pcolorargs('pcolormesh', + *args, + allmatch=allmatch, + interpolate_grids=interpolate_grids) Ny, Nx = X.shape X = X.ravel() Y = Y.ravel() From 86704aa94d2e386e823fec58402c9a34684377a0 Mon Sep 17 00:00:00 2001 From: simonpf Date: Sun, 29 Oct 2017 08:53:58 +0100 Subject: [PATCH 4/7] Adapted tests of pcolormesh. --- lib/matplotlib/tests/test_axes.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index c82705ffc719..8b303ac2729a 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -1180,12 +1180,22 @@ def test_pcolorargs(): y = np.linspace(-1.5, 1.5, n*2) X, Y = np.meshgrid(x, y) Z = np.sqrt(X**2 + Y**2)/5 + Z_1 = Z[:-1, :-1] _, ax = plt.subplots() with pytest.raises(TypeError): ax.pcolormesh(y, x, Z) with pytest.raises(TypeError): ax.pcolormesh(X, Y, Z.T) + with pytest.raises(TypeError): + ax.pcolormesh(y, x, Z, shading="gouraud") + with pytest.raises(TypeError): + ax.pcolormesh(X, Y, Z.T, shading="gouraud") + with pytest.raises(TypeError): + ax.pcolormesh(X, Y, Z_1, shading="gouraud") + + ax.pcolormesh(X, Y, Z_1) + ax.pcolormesh(x, y, Z_1, shading="gouraud", interpolate_grids=True) @image_comparison(baseline_images=['canonical']) From f4763ba6426faa8a1fbe07db65752a295a846ff9 Mon Sep 17 00:00:00 2001 From: simonpf Date: Wed, 1 Nov 2017 08:12:21 +0100 Subject: [PATCH 5/7] Fixed indentation in docstring of pcolormesh. --- lib/matplotlib/axes/_axes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index 156304c1de01..c6651b496cb4 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -5538,7 +5538,7 @@ def pcolormesh(self, *args, **kwargs): thrown. However, for compatibility with the flat shading case, the ``interpolate_grids`` keyword argument is provided. When set to ``True`` and *X* and *Y* have one row and column more then *C*, - *X* and *Y* will be linearly interpolated to obtain the corresponding + *X* and *Y* will be linearly interpolated to obtain the corresponding centerpoints. Keyword arguments: From c731c20f4ab5fae87a4dd4c1055b4fabd738e1ef Mon Sep 17 00:00:00 2001 From: simonpf Date: Wed, 1 Nov 2017 08:21:31 +0100 Subject: [PATCH 6/7] Added whatsnew entry. --- doc/users/whats_new.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index 362384db8c94..7f05f59cdbc9 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -246,6 +246,14 @@ volumetric model. Improvements ++++++++++++ +New ``interpolate_grids`` keyword arg to `pcolormesh` +----------------------------------------------------- + +`pcolormesh` now has a keyword argument ``interpolate_grids`` that will allow +interpolation of the boundary grids ``X``, ``Y`` to match the dimension of +``C`` if Gouraud shading is used. This will simplify changing between flat +and Gouraud shading. + CheckButtons widget ``get_status`` function ------------------------------------------- From 2d2aae80235612c56c21de24d882831da41551b8 Mon Sep 17 00:00:00 2001 From: simonpf Date: Thu, 2 Nov 2017 07:56:08 +0100 Subject: [PATCH 7/7] Fixed documentation and added mention of interpolate_dimensions keyword in error message. --- lib/matplotlib/axes/_axes.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index c6651b496cb4..ff4c3a068ffc 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -5159,8 +5159,8 @@ def _pcolorargs(funcname, *args, **kw): # This function takes care of resizing the grids X and Y # to match the size of the color grid C. # - # If only a color grid is given dummy grids for X and Y are - # created, matching the dimensions of C. + # If only a color grid is given uniform grids with step size 1.0 + # are created for X and Y are, matching the dimensions of C. # # If given, the X and Y grids must have the same size or # one more row and column than C. @@ -5233,8 +5233,10 @@ def _pcolorargs(funcname, *args, **kw): else: raise TypeError('Dimensions of C %s are incompatible with' - ' X (%d) and/or Y (%d); see help(%s)' % ( - C.shape, Nx, Ny, funcname)) + ' X (%d) and/or Y (%d); To allow linear ' + ' interpolation of the grids to match C ' + ' set the keyword interpolate_grids to ' + ' True' % (C.shape, Nx, Ny, funcname)) else: C = C[:Ny - 1, :Nx - 1]