|
| 1 | +""" |
| 2 | +.. _plot_gridded: |
| 3 | +
|
| 4 | +Gridded plots |
| 5 | +============= |
| 6 | +
|
| 7 | +This section discusses data that mapped onto a two-dimensional grid. The data |
| 8 | +usually has structured coordinates defined by arrays of x and y values, and data |
| 9 | +mapped onto those coordinates :math:`Data(x, y)` in a two-dimensional array. The grid |
| 10 | +can either be regular, in which case the x and y arrays are 1D and the Data is 2D, |
| 11 | +or the grid can be irregular, and X, Y, and Data are all 2D arrays. |
| 12 | +
|
| 13 | +""" |
| 14 | + |
| 15 | +import matplotlib.pyplot as plt |
| 16 | +import numpy as np |
| 17 | + |
| 18 | +import warnings |
| 19 | + |
| 20 | +plt.rcParams['figure.constrained_layout.use'] = True |
| 21 | +plt.rcParams['figure.figsize'] = (5, 4) |
| 22 | + |
| 23 | +# %% |
| 24 | +# imshow |
| 25 | +# ------ |
| 26 | +# |
| 27 | +# `~.axes.Axes.imshow` is a simple way to plot a 2D array as an image. By |
| 28 | +# default, the aspect ratio is set to be equal, so the pixels are square, and |
| 29 | +# the origin of the data is the upper-left corner. The values of the array are |
| 30 | +# mapped to colors using a colormap. |
| 31 | + |
| 32 | +# create a square matrix of data: |
| 33 | +X, Y = np.meshgrid(np.linspace(-3, 3, 128), np.linspace(-3, 3, 128)) |
| 34 | +Z = (1 - X/2 + X**5 + Y**3) * np.exp(-X**2 - Y**2) |
| 35 | + |
| 36 | +fig, ax = plt.subplots() |
| 37 | +im = ax.imshow(Z) |
| 38 | +fig.colorbar(im, ax=ax) |
| 39 | +ax.set_xlabel('pixels in x') |
| 40 | +ax.set_ylabel('pixels in y') |
| 41 | + |
| 42 | +# %% |
| 43 | +# |
| 44 | +# Note how the origin is in the upper left and the x and y axises are in units |
| 45 | +# of pixels. These behaviors can be changed with the *origin* and *extent* |
| 46 | +# arguments. This is discussed in detail in :ref:`imshow_extent`. |
| 47 | +# |
| 48 | +# Other colormaps can be chosen through the *cmap* argument (see |
| 49 | +# :ref:`colormaps`), and the color limits can be set with the *vmin* and *vmax* |
| 50 | +# arguments, or by using the *norm* parameter (see :ref:`colormapnorms`). An example |
| 51 | +# of using *vmin* and *vmax* is shown below: |
| 52 | + |
| 53 | +fig, ax = plt.subplots() |
| 54 | +im = ax.imshow(Z, cmap='RdBu_r', vmin=-1, vmax=1) |
| 55 | +fig.colorbar(im, ax=ax) |
| 56 | +ax.set_xlabel('pixels in x') |
| 57 | +ax.set_ylabel('pixels in y') |
| 58 | + |
| 59 | +# %% |
| 60 | +# |
| 61 | +# There are many options for resampling the data when it is displayed. See |
| 62 | +# :ref:`image_antialiasing` for more information, but note the the default attempts |
| 63 | +# to remove aliasing artifacts from data that is "downsampled" (i.e., when the |
| 64 | +# number of pixels in the data array is greater than the number of pixels in the |
| 65 | +# displayed image). |
| 66 | +# |
| 67 | +# .. seealso:: |
| 68 | +# - :ref:`image_demo` |
| 69 | +# - :ref:`imshow_extent` |
| 70 | +# - :ref:`image_antialiasing` |
| 71 | + |
| 72 | + |
| 73 | +# %% |
| 74 | +# pcolormesh (and pcolor, pcolorfast) |
| 75 | +# ----------------------------------- |
| 76 | +# |
| 77 | +# `~.axes.Axes.pcolormesh` is more flexible than `~.axes.Axes.imshow` in that |
| 78 | +# the x and y vectors need not be equally spaced (indeed they can be skewed). |
| 79 | +# In the example below, the x values are unevenly spaced, and much less finely |
| 80 | +# sampled than the y values. The x and y data are orthogonal, so we can pass |
| 81 | +# x and y directly to `~.axes.Axes.pcolormesh`: |
| 82 | + |
| 83 | +x = np.array([-3, -2, -1.6, -1.2, -.8, -.5, -.2, .1, .3, .5, .8, 1.1, 1.5, 1.9, 2.3, 3]) |
| 84 | +y = np.linspace(-3, 3, 128) |
| 85 | +X, Y = np.meshgrid(x, y) |
| 86 | +Z = (1 - X/2 + X**5 + Y**3) * np.exp(-X**2 - Y**2) |
| 87 | + |
| 88 | +fig, ax = plt.subplots() |
| 89 | + |
| 90 | +ax.pcolormesh(x, y, Z, vmin=-0.5, vmax=1.0) |
| 91 | + |
| 92 | +ax.set_xlabel('x') |
| 93 | +ax.set_ylabel('y') |
| 94 | + |
| 95 | +# %% |
| 96 | +# As noted, `~.axes.Axes.pcolormesh` need not be on an orthogonal grid. Here |
| 97 | +# is an example with the y grid points varying with x. Note that we need to |
| 98 | +# give the grids as 2D arrays for this to work: |
| 99 | + |
| 100 | +# make a 2D array of y values that where the y dimension varies in x: |
| 101 | +Yn = Y + 0.3 * np.abs(x) |
| 102 | + |
| 103 | +fig, ax = plt.subplots() |
| 104 | +with warnings.catch_warnings(): |
| 105 | + warnings.simplefilter("ignore") |
| 106 | + ax.pcolormesh(X, Yn, Z, vmin=-0.5, vmax=1.0) |
| 107 | +ax.set_xlabel('x') |
| 108 | +ax.set_ylabel('skewed y') |
| 109 | + |
| 110 | +# %% |
| 111 | +# Note that the above returns a warning because the y grid is not strictly increasing: |
| 112 | +# |
| 113 | +# UserWarning: The input coordinates to pcolormesh are |
| 114 | +# interpreted as cell centers, but are not monotonically |
| 115 | +# increasing or decreasing. |
| 116 | +# |
| 117 | +# To avoid that warning, we can give `.Axes.pcolormesh` the cell edges rather |
| 118 | +# than the cell centers: |
| 119 | + |
| 120 | + |
| 121 | +def midpoints_plus_ends(x): |
| 122 | + """Given a 1D array, return a new array with the midpoints and the two ends.""" |
| 123 | + return np.concatenate(([x[0] - (x[1] - x[0]) / 2], |
| 124 | + x[:-1] + np.diff(x) / 2, |
| 125 | + [x[-1] - (x[-1] - x[-2]) / 2])) |
| 126 | + |
| 127 | +yn = midpoints_plus_ends(y) |
| 128 | +xn = midpoints_plus_ends(x) |
| 129 | +Xn, Yn = np.meshgrid(xn, yn) |
| 130 | +Yn = Yn + 0.3 * np.abs(xn) |
| 131 | + |
| 132 | +fig, ax = plt.subplots() |
| 133 | +ax.pcolormesh(Xn, Yn, Z, vmin=-0.5, vmax=1.0) |
| 134 | + |
| 135 | +# %% |
| 136 | +# Two similar methods are `~.axes.Axes.pcolor` and `~.axes.Axes.pcolorfast`. There are |
| 137 | +# some differences in the way they handle the data, but they are largely the same and |
| 138 | +# are not as commonly used as `~.axes.Axes.pcolormesh`. See |
| 139 | +# :ref:`Differences between pcolor() and pcolormesh() <differences-pcolor-pcolormesh>` |
| 140 | +# for a discussion of the differences. |
| 141 | +# |
| 142 | +# `~.axes.Axes.pcolorfast` is not as flexible as `~.axes.Axes.pcolormesh`, but can be |
| 143 | +# faster for large datasets. |
| 144 | + |
| 145 | +# %% |
| 146 | +# .. seealso:: |
| 147 | +# - :ref:`pcolormesh_grids` |
| 148 | +# - :ref:`pcolor_demo` |
| 149 | + |
| 150 | +# %% |
| 151 | +# contour and contourf |
| 152 | +# -------------------- |
| 153 | +# |
| 154 | +# `~.axes.Axes.contour` and `~.axes.Axes.contourf` create contour plots. They accept |
| 155 | +# a 2D array of data, and create a plot with contour lines or filled regions enclosing |
| 156 | +# data that is in the same contour level. The example below shows a simple contour |
| 157 | +# plot using the data from above. Note that as before, the x and y data are not |
| 158 | +# necessarily evenly spaced, but in this case they are orthogonal. |
| 159 | + |
| 160 | +fig, axs = plt.subplots(2, 1, figsize=(5, 5)) |
| 161 | +ax = axs[0] |
| 162 | +ax.contour(x, y, Z, levels=10) |
| 163 | +ax.set_xlabel('x') |
| 164 | +ax.set_ylabel('y') |
| 165 | +ax.set_title('contour plot') |
| 166 | + |
| 167 | +ax = axs[1] |
| 168 | +cf = ax.contourf(x, y, Z, levels=10) |
| 169 | +ax.set_xlabel('x') |
| 170 | +ax.set_ylabel('y') |
| 171 | +ax.set_title('contourf plot') |
| 172 | +fig.colorbar(cf, ax=ax) |
| 173 | + |
| 174 | +# %% |
| 175 | +# Note that like for `.Axes.pcolormesh`, the grid need not be orthogonal. In |
| 176 | +# the following example the the same data is plotted as above, but with the y |
| 177 | +# grid points varying with x. The contour *levels* are also manually specified |
| 178 | +# in this example with a list of levels, (see :ref:`contourf_log` for an |
| 179 | +# example of using a tick locator instead of a list), and the colormap set with |
| 180 | +# the *cmap* argument (see :ref:`colormaps`). |
| 181 | + |
| 182 | +Yn = Y + 0.3 * np.abs(x) |
| 183 | + |
| 184 | +fig, ax = plt.subplots() |
| 185 | + |
| 186 | +cf = ax.contourf(X, Yn, Z, levels=np.arange(-1.3, 1.31, 0.2), cmap='RdBu_r') |
| 187 | +ax.set_xlabel('x') |
| 188 | +ax.set_ylabel('y') |
| 189 | +ax.set_title('contour plot') |
| 190 | +fig.colorbar(cf, ax=ax) |
| 191 | + |
| 192 | +# %% |
| 193 | +# .. seealso:: |
| 194 | +# |
| 195 | +# - :ref:`contour_demo` |
| 196 | +# - :ref:`contourf_demo` |
| 197 | + |
| 198 | +# %% |
| 199 | +# barbs and quiver |
| 200 | +# ---------------- |
| 201 | +# `~.axes.Axes.barbs` and `~.axes.Axes.quiver` allow us to represent gridded |
| 202 | +# vector fields specified at points on an x-y grid by two-dimensional arrays U, |
| 203 | +# V. The arrays must be the same shape as x and y and the arrows are placed at |
| 204 | +# the corresponding points in the grid. The main difference between the two |
| 205 | +# functions is that `~.axes.Axes.barbs` plots barbs, which are a more |
| 206 | +# traditional representation of wind speed and direction, while |
| 207 | +# `~.axes.Axes.quiver` plots arrows with a uniform size and the direction is |
| 208 | +# given by the vector U, V. |
| 209 | + |
| 210 | +# make data |
| 211 | +x = np.linspace(-4, 4, 20) |
| 212 | +y = np.linspace(-4, 4, 20) |
| 213 | +X, Y = np.meshgrid(x, y) |
| 214 | +U = X + Y |
| 215 | +V = Y - X |
| 216 | + |
| 217 | +# plot |
| 218 | +fig, ax = plt.subplots() |
| 219 | + |
| 220 | +ax.quiver(X, Y, U, V, color="C0", angles='xy', |
| 221 | + scale_units='xy', scale=8, width=.005) |
| 222 | + |
| 223 | +ax.set_xlabel('x') |
| 224 | +ax.set_ylabel('y') |
| 225 | +ax.set_title('barbs') |
| 226 | + |
| 227 | +fig, ax = plt.subplots() |
| 228 | +ax.barbs(X, Y, U, V, color="C0", barbcolor='C0', flagcolor='C0', length=4, |
| 229 | + linewidth=1.0) |
| 230 | + |
| 231 | +ax.set_xlabel('x') |
| 232 | +ax.set_ylabel('y') |
| 233 | +ax.set_title('quiver') |
| 234 | + |
| 235 | +# %% |
| 236 | +# streamplot |
| 237 | +# ---------- |
| 238 | +# |
| 239 | +# `~.axes.Axes.streamplot` is used to plot the streamlines of a vector field. It |
| 240 | +# makes traces of where a massless particle would go if it followed the vector field |
| 241 | +# at each point. The example below shows the streamlines of the vector field from |
| 242 | +# above: |
| 243 | + |
| 244 | +fig, ax = plt.subplots() |
| 245 | +ax.streamplot(x, y, U, V) |
| 246 | + |
| 247 | +ax.set_xlabel('x') |
| 248 | +ax.set_ylabel('y') |
| 249 | +ax.set_title('streamplot') |
| 250 | + |
| 251 | +# %% |
| 252 | +# `~.axes.Axes.streamplot` performs an interpolation and the streamlines are |
| 253 | +# not guaranteed to be accurate. For more accurate streamlines, the data grid |
| 254 | +# could be refined. |
| 255 | +# |
| 256 | +# .. note:: |
| 257 | +# |
| 258 | +# `~.axes.Axes.streamplot` does not accept 2D arrays for the x and y data: |
| 259 | +# the x and y data must be 1D arrays, and the spacing between the points must |
| 260 | +# be uniform. |
| 261 | +# |
| 262 | +# .. seealso:: :ref:`Streamplot demo <plot_streamplot>` |
| 263 | +# |
| 264 | +# .. admonition:: References |
| 265 | +# |
| 266 | +# The use of the following functions, methods, classes and modules is shown |
| 267 | +# in this example: |
| 268 | +# |
| 269 | +# - `matplotlib.axes.Axes.imshow` / `matplotlib.pyplot.imshow` |
| 270 | +# - `matplotlib.axes.Axes.pcolormesh` / `matplotlib.pyplot.pcolormesh` |
| 271 | +# - `matplotlib.axes.Axes.contour` / `matplotlib.pyplot.contour` |
| 272 | +# - `matplotlib.axes.Axes.contourf` / `matplotlib.pyplot.contourf` |
| 273 | +# - `matplotlib.axes.Axes.barbs` / `matplotlib.pyplot.barbs` |
| 274 | +# - `matplotlib.axes.Axes.quiver` / `matplotlib.pyplot.quiver` |
| 275 | +# - `matplotlib.axes.Axes.streamplot` / `matplotlib.pyplot.streamplot` |
0 commit comments