Skip to content

Commit

Permalink
FIX: add shading='nearest' and warn on mis-sized shading='flat'
Browse files Browse the repository at this point in the history
  • Loading branch information
jklymak committed Feb 9, 2020
1 parent 63cbb60 commit 404fe52
Show file tree
Hide file tree
Showing 13 changed files with 459 additions and 103 deletions.
25 changes: 25 additions & 0 deletions doc/users/next_whats_new/2020-01-18-pcolorshadingoptions.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Pcolor and Pcolormesh now accept shading='nearest' and 'auto'
-------------------------------------------------------------

Previously `.axes.Axes.pcolor` and `.axes.Axes.pcolormesh` handled
the situation where *x* and *y* have the same (respective) size as *C* by
dropping the last row and column of *C*, and *x* and *y* are regarded as the
edges of the remaining rows and columns in *C*. However, many users want
*x* and *y* centered on the rows and columns of *C*.

To accommodate this, ``shading='nearest'`` and ``shading='auto'`` are
new allowed strings for the ``shading`` kwarg. ``'nearest'`` will center the
color on *x* and *y* if *x* and *y* have the same dimensions as *C*
(otherwise an error will be thrown). ``shading='auto'`` will choose 'flat'
or 'nearest' based on the size of *X*, *Y*, *C*.

If ``shading='flat'`` then *X*, and *Y* should have dimensions one larger
than *C*. If *X* and *Y* have the same dimensions as *C*, then the previous
behavior is used and the last row and column of *C* are dropped, and a
DeprecationWarning is emitted.

Users can also specify this by the new :rc:`pcolor.shading` in their
``.matplotlibrc`` or via `.rcParams`.

See :doc:`pcolormesh </gallery/images_contours_and_fields/pcolormesh_grids>`
for examples.
132 changes: 132 additions & 0 deletions examples/images_contours_and_fields/pcolormesh_grids.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
"""
============================
pcolormesh grids and shading
============================
`.axes.Axes.pcolormesh` and `~.axes.Axes.pcolor` have a few options for
how grids are laid out and the shading between the grid points.
Generally, if *Z* has shape *(M, N)* then the grid *X* and *Y* can be
specified with either shape *(M+1, N+1)* or *(M, N)*, depending on the
argument for the ``shading`` keyword argument. Note that below we specify
vectors *x* as either length N or N+1 and *y* as length M or M+1, and
`~.axes.Axes.pcolormesh` internally makes the mesh matrices *X* and *Y* from
the input vectors.
"""

import matplotlib
import matplotlib.pyplot as plt
import numpy as np

###############################################################################
# Flat Shading
# ------------
#
# The grid specification with the least assumptions is ``shading='flat'``
# and if the grid is one larger than the data in each dimesion, i.e. has shape
# *(M+1, N+1)*. In that case *X* and *Y* sepcify the corners of quadrilaterals
# that are colored with the values in *Z*. Here we specify the edges of the
# *(3, 5)* quadrilaterals with *X* and *Y* that are *(4, 6)*.

nrows = 3
ncols = 5
Z = np.arange(nrows * ncols).reshape(nrows, ncols)
x = np.arange(ncols + 1)
y = np.arange(nrows + 1)

fig, ax = plt.subplots()
ax.pcolormesh(x, y, Z, shading='flat', vmin=Z.min(), vmax=Z.max())


def _annotate(ax, x, y, title):
# this all gets repeated below:
X, Y = np.meshgrid(x, y)
ax.plot(X.flat, Y.flat, 'o', color='m')
ax.set_xlim(-0.7, 5.2)
ax.set_ylim(-0.7, 3.2)
ax.set_title(title)

_annotate(ax, x, y, "shading='flat'")


###############################################################################
# Flat Shading, same shape grid
# -----------------------------
#
# Often, however, data is provided where *X* and *Y* match the shape of *Z*.
# As of Matplotlib v3.3, ``shading='flat'`` is deprecated when this is the
# case, a warning is raised, and the last row and column of *Z* are dropped.
# This dropping of the last row and column is what Matplotlib did silently
# previous to v3.3, and is compatible with what Matlab does.

x = np.arange(ncols) # note *not* ncols + 1 as before
y = np.arange(nrows)
fig, ax = plt.subplots()
ax.pcolormesh(x, y, Z, shading='flat', vmin=Z.min(), vmax=Z.max())
_annotate(ax, x, y, "shading='flat': X, Y, C same shape")

###############################################################################
# Nearest Shading, same shape grid
# --------------------------------
#
# Usually, dropping a row and column of data is not what the user means when
# the make *X*, *Y* and *Z* all the same shape. For this case, Matplotlib
# allows ``shading='nearest'`` and centers the colored qudrilaterals on the
# grid points.
#
# If a grid that is not the correct shape is passed with ``shading='nearest'``
# an error is raised.

fig, ax = plt.subplots()
ax.pcolormesh(x, y, Z, shading='nearest', vmin=Z.min(), vmax=Z.max())
_annotate(ax, x, y, "shading='nearest'")

###############################################################################
# Auto Shading
# ------------
#
# Its possible that the user would like the code to automatically choose
# which to use, in which case ``shading='auto'`` will decide whether to
# use 'flat' or 'nearest' shading based on the shapes of *X*, *Y* and *Z*.

fig, axs = plt.subplots(2, 1, constrained_layout=True)
ax = axs[0]
x = np.arange(ncols)
y = np.arange(nrows)
ax.pcolormesh(x, y, Z, shading='auto', vmin=Z.min(), vmax=Z.max())
_annotate(ax, x, y, "shading='auto'; X, Y, Z: same shape (nearest)")

ax = axs[1]
x = np.arange(ncols + 1)
y = np.arange(nrows + 1)
ax.pcolormesh(x, y, Z, shading='auto', vmin=Z.min(), vmax=Z.max())
_annotate(ax, x, y, "shading='auto'; X, Y one larger than Z (flat)")

###############################################################################
# Gouraud Shading
# ---------------
#
# `Gouraud shading <https://en.wikipedia.org/wiki/Gouraud_shading>`_ can also
# be specified, where the colour in the quadrilaterals is linearly
# interpolated between the grid points. The shapes of *X*, *Y*, *Z* must
# be the same.

fig, ax = plt.subplots(constrained_layout=True)
x = np.arange(ncols)
y = np.arange(nrows)
ax.pcolormesh(x, y, Z, shading='gouraud', vmin=Z.min(), vmax=Z.max())
_annotate(ax, x, y, "shading='gouraud'; X, Y same shape as Z")

plt.show()
#############################################################################
#
# ------------
#
# References
# """"""""""
#
# The use of the following functions and methods is shown in this example:

matplotlib.axes.Axes.pcolormesh
matplotlib.pyplot.pcolormesh
67 changes: 64 additions & 3 deletions examples/images_contours_and_fields/pcolormesh_levels.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
pcolormesh
==========
Shows how to combine Normalization and Colormap instances to draw "levels" in
`~.axes.Axes.pcolor`, `~.axes.Axes.pcolormesh` and `~.axes.Axes.imshow` type
plots in a similar way to the levels keyword argument to contour/contourf.
`.axes.Axes.pcolormesh` allows you to generate 2-D image-style plots. Note it
is faster than the similar `~.axes.Axes.pcolor`.
"""

import matplotlib
Expand All @@ -14,6 +14,67 @@
from matplotlib.ticker import MaxNLocator
import numpy as np

###############################################################################
# Basic pcolormesh
# ----------------
#
# We usually specify a pcolormesh by defining the edge of quadrilaterals and
# the value of the quadrilateral. Note that here *x* and *y* each have one
# extra element than Z in the respective dimension.

np.random.seed(19680801)
Z = np.random.rand(6, 10)
x = np.arange(-0.5, 10, 1) # len = 11
y = np.arange(4.5, 11, 1) # len = 7

fig, ax = plt.subplots()
ax.pcolormesh(x, y, Z)

###############################################################################
# Non-rectilinear pcolormesh
# --------------------------
#
# Note that we can also specify matrices for *X* and *Y* and have
# non-rectilinear quadrilaterals.

x = np.arange(-0.5, 10, 1) # len = 11
y = np.arange(4.5, 11, 1) # len = 7
X, Y = np.meshgrid(x, y)
X = X + 0.2 * Y # tilt the coordinates.
Y = Y + 0.3 * X

fig, ax = plt.subplots()
ax.pcolormesh(X, Y, Z)

###############################################################################
# Centered Coordinates
# ---------------------
#
# Often a user wants to pass *X* and *Y* with the same sizes as *Z* to
# `.axes.Axes.pcolormesh`. This is also allowed if ``shading='auto'`` is
# passed (default set by :rc:`pcolor.shading`). Pre Matplotlib 3.3,
# ``shading='flat'`` would drop the last column and row of *Z*; while that
# is still allowed for back compatibility purposes, a DeprecationWarning is
# raised.

x = np.arange(10) # len = 10
y = np.arange(6) # len = 6
X, Y = np.meshgrid(x, y)

fig, axs = plt.subplots(2, 1, sharex=True, sharey=True)
axs[0].pcolormesh(X, Y, Z, vmin=np.min(Z), vmax=np.max(Z), shading='auto')
axs[0].set_title("shading='auto' = 'nearest'")
axs[1].pcolormesh(X, Y, Z, vmin=np.min(Z), vmax=np.max(Z), shading='flat')
axs[1].set_title("shading='flat'")

###############################################################################
# Making levels using Norms
# -------------------------
#
# Shows how to combine Normalization and Colormap instances to draw
# "levels" in `.axes.Axes.pcolor`, `.axes.Axes.pcolormesh`
# and `.axes.Axes.imshow` type plots in a similar
# way to the levels keyword argument to contour/contourf.

# make these smaller to increase the resolution
dx, dy = 0.05, 0.05
Expand Down
Loading

0 comments on commit 404fe52

Please sign in to comment.