Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d96916f

Browse files
committed
ENH: allow pcolor to plot all data is x, y not N+1
1 parent 29a1afe commit d96916f

File tree

7 files changed

+201
-25
lines changed

7 files changed

+201
-25
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
Pcolor and Pcolormesh now have *dropdata* kwarg and rcParam
2+
-----------------------------------------------------------
3+
4+
Previously `.axes.Axes.pcolor` and `.axes.Axes.pcolormesh` handled
5+
the situation where *x* and *y* have the same (respective) size as *Z* by
6+
dropping the last row and column of *Z*, and *x* and *y* are regarded as the
7+
edges of the remaining rows and columns in *Z*. However, most users probably
8+
really want *x* and *y* centered on the rows and columns of *Z*, so if
9+
they specify *dropdata* as True, both methods will now linearly interpolate to
10+
get the edges of the bins, and *x* and *y* will specify the (linear) center of
11+
each gridcell in the pseudocolor plot.
12+
13+
Users can also specify this by the new :rc:`pcolor.dropdata` in their
14+
``.matplotlibrc`` or via `.rcParams`.
15+
16+
See :doc:`pcolormesh </gallery/images_contours_and_fields/pcolormesh_levels>`
17+
for an example.

examples/images_contours_and_fields/pcolormesh_levels.py

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
"""
22
==========
3-
pcolormesh
3+
Pcolormesh
44
==========
55
6-
Shows how to combine Normalization and Colormap instances to draw "levels" in
7-
`~.axes.Axes.pcolor`, `~.axes.Axes.pcolormesh` and `~.axes.Axes.imshow` type
8-
plots in a similar way to the levels keyword argument to contour/contourf.
6+
`.axes.Axes.pcolormesh` allows you to generate 2-D image-style plots. Note it
7+
is somewhat faster than `~.axes.Axes.pcolor`.
8+
99
"""
1010

1111
import matplotlib
@@ -14,6 +14,66 @@
1414
from matplotlib.ticker import MaxNLocator
1515
import numpy as np
1616

17+
###############################################################################
18+
# Basic Pcolormesh
19+
# ----------------
20+
#
21+
# We usually specify a pcolormesh by defining the edge of quadrilaterals and
22+
# the value of the quadrilateral. Note that here *x* and *y* each have one
23+
# extra element than Z in the respective dimension.
24+
25+
np.random.seed(19680801)
26+
Z = np.random.rand(6, 10)
27+
x = np.arange(-0.5, 10, 1) # len = 11
28+
y = np.arange(4.5, 11, 1) # len = 7
29+
30+
fig, ax = plt.subplots()
31+
ax.pcolormesh(x, y, Z)
32+
33+
###############################################################################
34+
# Non-rectilinear Pcolormesh
35+
# --------------------------
36+
#
37+
# Note that we can also specify matrices for *X* and *Y* and have
38+
# non-rectilinear quadrilaterals.
39+
40+
x = np.arange(-0.5, 10, 1) # len = 11
41+
y = np.arange(4.5, 11, 1) # len = 7
42+
X, Y = np.meshgrid(x, y)
43+
X = X + 0.2 * Y # tilt the co-ordinates.
44+
Y = Y + 0.3 * X
45+
46+
fig, ax = plt.subplots()
47+
ax.pcolormesh(X, Y, Z)
48+
49+
###############################################################################
50+
# Centered Co-ordinates
51+
# ---------------------
52+
#
53+
# Often a user wants to pass *X* and *Y* with the same sizes as *Z* to
54+
# `.axes.Axes.pcolormesh`. Matplotlib will either drop the last row and
55+
# column of *Z* (default, h=istorically compatible with Matlab), or if
56+
# ``dropdata=True`` assume the user wanted *X* and *Y* centered on the
57+
# quadrilateral and linearly interpolate to get the edges.
58+
59+
x = np.arange(10) # len = 10
60+
y = np.arange(6) # len = 6
61+
X, Y = np.meshgrid(x, y)
62+
63+
fig, axs = plt.subplots(2, 1, sharex=True, sharey=True)
64+
axs[0].pcolormesh(X, Y, Z, vmin=np.min(Z), vmax=np.max(Z))
65+
axs[0].set_title('dropdata=True (default)')
66+
axs[1].pcolormesh(X, Y, Z, vmin=np.min(Z), vmax=np.max(Z), dropdata=False)
67+
axs[1].set_title('dropdata=False')
68+
69+
###############################################################################
70+
# Making levels using Norms
71+
# -------------------------
72+
#
73+
# Shows how to combine Normalization and Colormap instances to draw
74+
# "levels" in `.axes.Axes.pcolor`, `.axes.Axes.pcolormesh`
75+
# and `.axes.Axes.imshow` type plots in a similar
76+
# way to the levels keyword argument to contour/contourf.
1777

1878
# make these smaller to increase the resolution
1979
dx, dy = 0.05, 0.05
@@ -54,8 +114,6 @@
54114
# don't overlap
55115
fig.tight_layout()
56116

57-
plt.show()
58-
59117
#############################################################################
60118
#
61119
# ------------

lib/matplotlib/axes/_axes.py

Lines changed: 63 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5603,7 +5603,7 @@ def imshow(self, X, cmap=None, norm=None, aspect=None,
56035603
return im
56045604

56055605
@staticmethod
5606-
def _pcolorargs(funcname, *args, allmatch=False):
5606+
def _pcolorargs(funcname, *args, allmatch=False, dropdata=True):
56075607
# If allmatch is True, then the incoming X, Y, C must have matching
56085608
# dimensions, taking into account that X and Y can be 1-D rather than
56095609
# 2-D. This perfect match is required for Gouraud shading. For flat
@@ -5665,14 +5665,34 @@ def _pcolorargs(funcname, *args, allmatch=False):
56655665
raise TypeError('Dimensions of C %s are incompatible with'
56665666
' X (%d) and/or Y (%d); see help(%s)' % (
56675667
C.shape, Nx, Ny, funcname))
5668-
C = C[:Ny - 1, :Nx - 1]
5668+
5669+
if dropdata:
5670+
C = C[:Ny - 1, :Nx - 1]
5671+
else:
5672+
def _interp_grid(X):
5673+
# helper for below
5674+
dX = np.diff(X, axis=1)/2.
5675+
X = np.hstack((X[:, [0]] - dX[:, [0]],
5676+
X[:, :-1] + dX,
5677+
X[:, [-1]] + dX[:, [-1]])
5678+
)
5679+
return X
5680+
5681+
if ncols == Nx:
5682+
X = _interp_grid(X)
5683+
Y = _interp_grid(Y)
5684+
5685+
if nrows == Ny:
5686+
X = _interp_grid(X.T).T
5687+
Y = _interp_grid(Y.T).T
5688+
56695689
C = cbook.safe_masked_invalid(C)
56705690
return X, Y, C
56715691

56725692
@_preprocess_data()
56735693
@docstring.dedent_interpd
56745694
def pcolor(self, *args, alpha=None, norm=None, cmap=None, vmin=None,
5675-
vmax=None, **kwargs):
5695+
vmax=None, dropdata=None, **kwargs):
56765696
r"""
56775697
Create a pseudocolor plot with a non-regular rectangular grid.
56785698
@@ -5686,7 +5706,9 @@ def pcolor(self, *args, alpha=None, norm=None, cmap=None, vmin=None,
56865706
56875707
``pcolor()`` can be very slow for large arrays. In most
56885708
cases you should use the similar but much faster
5689-
`~.Axes.pcolormesh` instead. See there for a discussion of the
5709+
`~.Axes.pcolormesh` instead. See
5710+
:ref:`Differences between pcolor() and pcolormesh()
5711+
<differences-pcolor-pcolormesh>` for a discussion of the
56905712
differences.
56915713
56925714
Parameters
@@ -5711,7 +5733,8 @@ def pcolor(self, *args, alpha=None, norm=None, cmap=None, vmin=None,
57115733
57125734
The dimensions of *X* and *Y* should be one greater than those of
57135735
*C*. Alternatively, *X*, *Y* and *C* may have equal dimensions, in
5714-
which case the last row and column of *C* will be ignored.
5736+
which case the last row and column of *C* will be ignored if
5737+
*dropdata* is True (see below).
57155738
57165739
If *X* and/or *Y* are 1-D arrays or column vectors they will be
57175740
expanded as needed into the appropriate 2-D arrays, making a
@@ -5751,6 +5774,13 @@ def pcolor(self, *args, alpha=None, norm=None, cmap=None, vmin=None,
57515774
snap : bool, default: False
57525775
Whether to snap the mesh to pixel boundaries.
57535776
5777+
dropdata : bool, default: :rc:`pcolor.dropdata`
5778+
If True (default), and *X* and *Y* are the same size as C in their
5779+
respective dimensions, drop the last element of C in both
5780+
dimensions. If False, *X* and *Y* are assumed to be the midpoints
5781+
of the quadrilaterals, and their edges calculated by linear
5782+
interpolation.
5783+
57545784
Returns
57555785
-------
57565786
collection : `matplotlib.collections.Collection`
@@ -5801,12 +5831,19 @@ def pcolor(self, *args, alpha=None, norm=None, cmap=None, vmin=None,
58015831
``pcolor()`` displays all columns of *C* if *X* and *Y* are not
58025832
specified, or if *X* and *Y* have one more column than *C*.
58035833
If *X* and *Y* have the same number of columns as *C* then the last
5804-
column of *C* is dropped. Similarly for the rows.
5834+
column of *C* is dropped if *dropdata* is True. Similarly for the rows.
5835+
If *dropdata* is False, then *X* and *Y* are assumed to be at the
5836+
middle of the quadrilaterals, and the edges of the quadrilaterals are
5837+
linearly interpolated.
58055838
5806-
Note: This behavior is different from MATLAB's ``pcolor()``, which
5839+
This behavior is different from MATLAB's ``pcolor()``, which
58075840
always discards the last row and column of *C*.
58085841
"""
5809-
X, Y, C = self._pcolorargs('pcolor', *args, allmatch=False)
5842+
if dropdata is None:
5843+
dropdata = rcParams['pcolor.dropdata']
5844+
5845+
X, Y, C = self._pcolorargs('pcolor', *args, dropdata=dropdata,
5846+
allmatch=False)
58105847
Ny, Nx = X.shape
58115848

58125849
# unit conversion allows e.g. datetime objects as axis values
@@ -5903,7 +5940,8 @@ def pcolor(self, *args, alpha=None, norm=None, cmap=None, vmin=None,
59035940
@_preprocess_data()
59045941
@docstring.dedent_interpd
59055942
def pcolormesh(self, *args, alpha=None, norm=None, cmap=None, vmin=None,
5906-
vmax=None, shading='flat', antialiased=False, **kwargs):
5943+
vmax=None, shading='flat', antialiased=False,
5944+
dropdata=None, **kwargs):
59075945
"""
59085946
Create a pseudocolor plot with a non-regular rectangular grid.
59095947
@@ -5913,9 +5951,9 @@ def pcolormesh(self, *args, alpha=None, norm=None, cmap=None, vmin=None,
59135951
59145952
*X* and *Y* can be used to specify the corners of the quadrilaterals.
59155953
5916-
.. note::
5954+
.. hint::
59175955
5918-
`~Axes.pcolormesh` is similar to `~Axes.pcolor`. It's much faster
5956+
`~Axes.pcolormesh` is similar to `~Axes.pcolor`. It is much faster
59195957
and preferred in most cases. For a detailed discussion on the
59205958
differences see :ref:`Differences between pcolor() and pcolormesh()
59215959
<differences-pcolor-pcolormesh>`.
@@ -5942,7 +5980,8 @@ def pcolormesh(self, *args, alpha=None, norm=None, cmap=None, vmin=None,
59425980
59435981
The dimensions of *X* and *Y* should be one greater than those of
59445982
*C*. Alternatively, *X*, *Y* and *C* may have equal dimensions, in
5945-
which case the last row and column of *C* will be ignored.
5983+
which case the last row and column of *C* will be ignored, unless
5984+
*dropdata* is *False* (see below).
59465985
59475986
If *X* and/or *Y* are 1-D arrays or column vectors they will be
59485987
expanded as needed into the appropriate 2-D arrays, making a
@@ -5991,6 +6030,13 @@ def pcolormesh(self, *args, alpha=None, norm=None, cmap=None, vmin=None,
59916030
snap : bool, default: False
59926031
Whether to snap the mesh to pixel boundaries.
59936032
6033+
dropdata : bool, default: :rc:`pcolor.dropdata`
6034+
If True (default), and *X* and *Y* are the same size as C in their
6035+
respective dimensions, drop the last element of C in both
6036+
dimensions. If False, *X* and *Y* are assumed to be the midpoints
6037+
of the quadrilaterals, and their edges calculated by linear
6038+
interpolation.
6039+
59946040
Returns
59956041
-------
59966042
mesh : `matplotlib.collections.QuadMesh`
@@ -6062,7 +6108,11 @@ def pcolormesh(self, *args, alpha=None, norm=None, cmap=None, vmin=None,
60626108

60636109
allmatch = (shading == 'gouraud')
60646110

6065-
X, Y, C = self._pcolorargs('pcolormesh', *args, allmatch=allmatch)
6111+
if dropdata is None:
6112+
dropdata = rcParams['pcolor.dropdata']
6113+
6114+
X, Y, C = self._pcolorargs('pcolormesh', *args,
6115+
allmatch=allmatch, dropdata=dropdata)
60666116
Ny, Nx = X.shape
60676117
X = X.ravel()
60686118
Y = Y.ravel()

lib/matplotlib/pyplot.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2515,11 +2515,11 @@ def minorticks_on():
25152515
@docstring.copy(Axes.pcolor)
25162516
def pcolor(
25172517
*args, alpha=None, norm=None, cmap=None, vmin=None,
2518-
vmax=None, data=None, **kwargs):
2518+
vmax=None, dropdata=None, data=None, **kwargs):
25192519
__ret = gca().pcolor(
25202520
*args, alpha=alpha, norm=norm, cmap=cmap, vmin=vmin,
2521-
vmax=vmax, **({"data": data} if data is not None else {}),
2522-
**kwargs)
2521+
vmax=vmax, dropdata=dropdata, **({"data": data} if data is not
2522+
None else {}), **kwargs)
25232523
sci(__ret)
25242524
return __ret
25252525

@@ -2528,12 +2528,13 @@ def pcolor(
25282528
@docstring.copy(Axes.pcolormesh)
25292529
def pcolormesh(
25302530
*args, alpha=None, norm=None, cmap=None, vmin=None,
2531-
vmax=None, shading='flat', antialiased=False, data=None,
2532-
**kwargs):
2531+
vmax=None, shading='flat', antialiased=False, dropdata=None,
2532+
data=None, **kwargs):
25332533
__ret = gca().pcolormesh(
25342534
*args, alpha=alpha, norm=norm, cmap=cmap, vmin=vmin,
25352535
vmax=vmax, shading=shading, antialiased=antialiased,
2536-
**({"data": data} if data is not None else {}), **kwargs)
2536+
dropdata=dropdata, **({"data": data} if data is not None else
2537+
{}), **kwargs)
25372538
sci(__ret)
25382539
return __ret
25392540

lib/matplotlib/rcsetup.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,6 +1030,9 @@ def validate_webagg_address(s):
10301030
# marker props
10311031
'markers.fillstyle': ['full', validate_fillstyle],
10321032

1033+
## pcolor(mesh) props:
1034+
'pcolor.dropdata': [True, validate_bool],
1035+
10331036
## patch props
10341037
'patch.linewidth': [1.0, validate_float], # line width in points
10351038
'patch.edgecolor': ['black', validate_color],

lib/matplotlib/tests/test_axes.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1268,6 +1268,52 @@ def test_pcolorargs():
12681268
ax.pcolormesh(x, y, Z[:-1, :-1])
12691269

12701270

1271+
@check_figures_equal(extensions=["png"])
1272+
def test_pcolornodropdata(fig_test, fig_ref):
1273+
ax = fig_test.subplots()
1274+
x = np.arange(0, 10)
1275+
y = np.arange(0, 3)
1276+
np.random.seed(19680801)
1277+
Z = np.random.randn(2, 9)
1278+
ax.pcolormesh(x, y, Z)
1279+
1280+
ax = fig_ref.subplots()
1281+
x2 = x[:-1] + np.diff(x) / 2
1282+
y2 = y[:-1] + np.diff(y) / 2
1283+
ax.pcolormesh(x2, y2, Z, dropdata=False)
1284+
1285+
1286+
@check_figures_equal(extensions=["png"])
1287+
def test_pcolornodropdatarc(fig_test, fig_ref):
1288+
matplotlib.rcParams['pcolor.dropdata'] = False
1289+
ax = fig_test.subplots()
1290+
x = np.arange(0, 10)
1291+
y = np.arange(0, 3)
1292+
np.random.seed(19680801)
1293+
Z = np.random.randn(2, 9)
1294+
ax.pcolormesh(x, y, Z)
1295+
1296+
ax = fig_ref.subplots()
1297+
x2 = x[:-1] + np.diff(x) / 2
1298+
y2 = y[:-1] + np.diff(y) / 2
1299+
ax.pcolormesh(x2, y2, Z)
1300+
1301+
1302+
@check_figures_equal(extensions=["png"])
1303+
def test_pcolordropdata(fig_test, fig_ref):
1304+
ax = fig_test.subplots()
1305+
x = np.arange(0, 10)
1306+
y = np.arange(0, 4)
1307+
np.random.seed(19680801)
1308+
Z = np.random.randn(3, 9)
1309+
ax.pcolormesh(x[:-1], y[:-1], Z[:-1, :-1])
1310+
1311+
ax = fig_ref.subplots()
1312+
x2 = x[:-1]
1313+
y2 = y[:-1]
1314+
ax.pcolormesh(x2, y2, Z)
1315+
1316+
12711317
@image_comparison(['canonical'])
12721318
def test_canonical():
12731319
fig, ax = plt.subplots()

matplotlibrc.template

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@
135135

136136
#markers.fillstyle : full ## {full, left, right, bottom, top, none}
137137

138+
# pcolor.dropdata : True
138139

139140
## ***************************************************************************
140141
## * PATCHES *

0 commit comments

Comments
 (0)