8000 Merge pull request #1022 from efiring/contourf_extend · matplotlib/matplotlib@967c15a · GitHub
[go: up one dir, main page]

Skip to content

Commit 967c15a

Browse files
committed
Merge pull request #1022 from efiring/contourf_extend
contour: map extended ranges to "under" and "over" values
2 parents 96d1814 + 0c347f3 commit 967c15a

File tree

4 files changed

+79
-38
lines changed

4 files changed

+79
-38
lines changed

CHANGELOG

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
2012-07-24 Contourf handles the extend kwarg by mapping the extended
2+
ranges outside the normed 0-1 range so that they are
3+
handled by colormap colors determined by the set_under
4+
and set_over methods. Previously the extended ranges
5+
were mapped to 0 or 1 so that the "under" and "over"
6+
colormap colors were ignored. - EF
7+
18
2012-06-24 Make use of mathtext in tick labels configurable - DSD
29

310
2012-06-05 Images loaded through PIL are now ordered correctly - CG

doc/api/api_changes.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,16 @@ For new features that were added to matplotlib, please see
1414
Changes in 1.2.x
1515
================
1616

17+
* In :meth:`~matplotlib.axes.Axes.contourf`, the handling of the *extend*
18+
kwarg has changed. Formerly, the extended ranges were mapped
19+
after to 0, 1 after being normed, so that they always corresponded
20+
to the extreme values of the colormap. Now they are mapped
21+
outside this range so that they correspond to the special
22+
colormap values determined by the
23+
:meth:`~matplotlib.colors.Colormap.set_under` and
24+
:meth:`~matplotlib.colors.Colormap.set_over` methods, which
25+
default to the colormap end points.
26+
1727
* The new rc parameter ``savefig.format`` replaces ``cairo.format`` and
1828
``savefig.extension``, and sets the default file format used by
1929
:meth:`matplotlib.figure.Figure.savefig`.
Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,70 @@
11
#!/usr/bin/env python
2-
from pylab import *
2+
import numpy as np
3+
import matplotlib.pyplot as plt
4+
35
origin = 'lower'
46
#origin = 'upper'
57

68
delta = 0.025
79

8-
x = y = arange(-3.0, 3.01, delta)
9-
X, Y = meshgrid(x, y)
10-
Z1 = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
11-
Z2 = bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
10+
x = y = np.arange(-3.0, 3.01, delta)
11+
X, Y = np.meshgrid(x, y)
12+
Z1 = plt.mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
13+
Z2 = plt.mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
1214
Z = 10 * (Z1 - Z2)
1315

1416
nr, nc = Z.shape
1517

1618
# put NaNs in one corner:
17-
Z[-nr//6:, -nc//6:] = nan
19+
Z[-nr//6:, -nc//6:] = np.nan
1820
# contourf will convert these to masked
1921

2022

21-
Z = ma.array(Z)
23+
Z = np.ma.array(Z)
2224
# mask another corner:
23-
Z[:nr//6, :nc//6] = ma.masked
25+
Z[:nr//6, :nc//6] = np.ma.masked
2426

2527
# mask a circle in the middle:
26-
interior = sqrt((X**2) + (Y**2)) < 0.5
27-
Z[interior] = ma.masked
28+
interior = np.sqrt((X**2) + (Y**2)) < 0.5
29+
Z[interior] = np.ma.masked
2830

2931

3032
# We are using automatic selection of contour levels;
3133
# this is usually not such a good idea, because they don't
3234
# occur on nice boundaries, but we do it here for purposes
3335
# of illustration.
34-
CS = contourf(X, Y, Z, 10, # [-1, -0.1, 0, 0.1],
36+
CS = plt.contourf(X, Y, Z, 10, # [-1, -0.1, 0, 0.1],
3537
#alpha=0.5,
36-
cmap=cm.bone,
38+
cmap=plt.cm.bone,
3739
origin=origin)
3840

3941
# Note that in the following, we explicitly pass in a subset of
4042
# the contour levels used for the filled contours. Alternatively,
4143
# We could pass in additional levels to provide extra resolution,
4244
# or leave out the levels kwarg to use all of the original levels.
4345

44-
CS2 = contour(CS, levels=CS.levels[::2],
46+
CS2 = plt.contour(CS, levels=CS.levels[::2],
4547
colors = 'r',
4648
origin=origin,
4749
hold='on')
4850

49-
title('Nonsense (3 masked regions)')
50-
xlabel('word length anomaly')
51-
ylabel('sentence length anomaly')
51+
plt.title('Nonsense (3 masked regions)')
52+
plt.xlabel('word length anomaly')
53+
plt.ylabel('sentence length anomaly')
5254

5355
# Make a colorbar for the ContourSet returned by the contourf call.
54-
cbar = colorbar(CS)
56+
cbar = plt.colorbar(CS)
5557
cbar.ax.set_ylabel('verbosity coefficient')
5658
# Add the contour line levels to the colorbar
5759
cbar.add_lines(CS2)
5860

59-
figure()
61+
plt.figure()
6062

6163
# Now make a contour plot with the levels specified,
6264
# and with the colormap generated automatically from a list
6365
# of colors.
6466
levels = [-1.5, -1, -0.5, 0, 0.5, 1]
65-
CS3 = contourf(X, Y, Z, levels,
67+
CS3 = plt.contourf(X, Y, Z, levels,
6668
colors = ('r', 'g', 'b'),
6769
origin=origin,
6870
extend='both')
@@ -72,16 +74,34 @@
7274
CS3.cmap.set_under('yellow')
7375
CS3.cmap.set_over('cyan')
7476

75-
CS4 = contour(X, Y, Z, levels,
77+
CS4 = plt.contour(X, Y, Z, levels,
7678
colors = ('k',),
7779
linewidths = (3,),
7880
origin = origin)
79-
title('Listed colors (3 masked regions)')
80-
clabel(CS4, fmt = '%2.1f', colors = 'w', fontsize=14)
81+
plt.title('Listed colors (3 masked regions)')
82+
plt.clabel(CS4, fmt = '%2.1f', colors = 'w', fontsize=14)
8183

8284
# Notice that the colorbar command gets all the information it
8385
# needs from the ContourSet object, CS3.
84-
colorbar(CS3)
85-
86-
show()
86+
plt.colorbar(CS3)
87+
88+
# Illustrate all 4 possible "extend" settings:
89+
extends = ["neither", "both", "min", "max"]
90+
cmap = plt.cm.get_cmap("winter")
91+
cmap.set_under("magenta")
92+
cmap.set_over("yellow")
93+
# Note: contouring simply excludes masked or nan regions, so
94+
# instead of using the "bad" colormap value for them, it draws
95+
# nothing at all in them. Therefore the following would have
96+
# no effect:
97+
#cmap.set_bad("red")
98+
99+
fig, axs = plt.subplots(2,2)
100+
for ax, extend in zip(axs.ravel(), extends):
101+
cs = ax.contourf(X, Y, Z, levels, cmap=cmap, extend=extend, origin=origin)
102+
fig.colorbar(cs, ax=ax, shrink=0.9)
103+
ax.set_title("extend = %s" % extend)
104+
ax.locator_params(nbins=4)
105+
106+
plt.show()
87107

lib/matplotlib/contour.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -870,10 +870,10 @@ def legend_elements(self, variable_name='x', str_format=str):
870870
lower = str_format(lower)
871871
upper = str_format(upper)
872872

873-
if i == 0 and self.extend in ('lower', 'both'):
874-
labels.append(r'$%s \leq %s$' % (variable_name, upper, ))
875-
elif i == n_levels-1 and self.extend in ('upper', 'both'):
876-
labels.append(r'$%s > %s$' % (variable_name, lower, ))
873+
if i == 0 and self.extend in ('min', 'both'):
874+
labels.append(r'$%s \leq %s$' % (variable_name, lower, ))
875+
elif i == n_levels-1 and self.extend in ('max', 'both'):
876+
labels.append(r'$%s > %s$' % (variable_name, upper, ))
877877
else:
878878
labels.append(r'$%s < %s \leq %s$' % (lower, variable_name, upper))
879879
else:
@@ -1029,24 +1029,25 @@ def _contour_level_args(self, z, args):
10291029
raise ValueError("Filled contours require at least 2 levels.")
10301030

10311031
def _process_levels(self):
1032+
# Color mapping range (norm vmin, vmax) is based on levels.
1033+
self.vmin = np.amin(self.levels)
1034+
self.vmax = np.amax(self.levels)
1035+
# Make a private _levels to include extended regions.
10321036
self._levels = list(self.levels)
10331037
if self.extend in ('both', 'min'):
10341038
self._levels.insert(0, min(self.levels[0],self.zmin) - 1)
10351039
if self.extend in ('both', 'max'):
10361040
self._levels.append(max(self.levels[-1],self.zmax) + 1)
10371041
self._levels = np.asarray(self._levels)
1038-
self.vmin = np.amin(self.levels) # alternative would be self.layers
1039-
self.vmax = np.amax(self.levels)
1040-
if self.extend in ('both', 'min'):
1041-
self.vmin = 2 * self.levels[0] - self.levels[1]
1042-
if self.extend in ('both', 'max'):
1043-
self.vmax = 2 * self.levels[-1] - self.levels[-2]
10441042
if self.filled:
1043+
# layer values are mid-way between levels
10451044
self.layers = 0.5 * (self._levels[:-1] + self._levels[1:])
1045+
# ...except that extended layers must be outside the
1046+
# normed range:
10461047
if self.extend in ('both', 'min'):
1047-
self.layers[0] = 0.5 * (self.vmin + self._levels[1])
1048+
self.layers[0] = -np.inf
10481049
if self.extend in ('both', 'max'):
1049-
self.layers[-1] = 0.5 * (self.vmax + self._levels[-2])
1050+
self.layers[-1] = np.inf
10501051
else:
10511052
self.layers = self.levels # contour: a line is a thin layer
10521053
# Use only original levels--no extended levels
@@ -1065,9 +1066,11 @@ def _process_colors(self):
10651066
"""
10661067
self.monochrome = self.cmap.monochrome
10671068
if self.colors is not None:
1069+
# Generate integers for direct indexing.
10681070
i0, i1 = 0, len(self.levels)
10691071
if self.filled:
10701072
i1 -= 1
1073+
# Out of range indices for over and under:
10711074
if self.extend in ('both', 'min'):
10721075
i0 = -1
10731076
if self.extend in ('both', 'max'):
@@ -1080,7 +1083,8 @@ def _process_colors(self):
10801083
self.set_clim(self.vmin, self.vmax)
10811084
if self.extend in ('both', 'max', 'min'):
10821085
self.norm.clip = False
1083-
self.set_array(self.layers)
1086+
self.set_array(self.layers) # Required by colorbar, but not
1087+
# actually used.
10841088
# self.tcolors are set by the "changed" method
10851089

10861090
def _process_linewidths(self):

0 commit comments

Comments
 (0)
0