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

Skip to content

Commit 41822d5

Browse files
committed
Merge pull request #1057 from efiring/contour_norm_scaling
Contour norm scaling
2 parents 50ae794 + 0890246 commit 41822d5

12 files changed

Lines changed: 20367 additions & 170 deletions

File tree

CHANGELOG

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
1+
2012-08-05 When a norm is passed to contourf, either or both of the
2+
vmin, vmax attributes of that norm are now respected.
3+
Formerly they were respected only if both were
4+
specified. In addition, vmin and/or vmax can now
5+
be passed to contourf directly as kwargs. - EF
6+
17
2012-07-24 Contourf handles the extend kwarg by mapping the extended
28
ranges outside the normed 0-1 range so that they are
39
handled by colormap colors determined by the set_under
410
and set_over methods. Previously the extended ranges
511
were mapped to 0 or 1 so that the "under" and "over"
6-
colormap colors were ignored. - EF
12+
colormap colors were ignored. This change also increases
13+
slightly the color contrast for a given set of contour
14+
levels. - EF
715

816
2012-06-24 Make use of mathtext in tick labels configurable - DSD
917

lib/matplotlib/axes.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3754,7 +3754,7 @@ def vlines(self, x, ymin, ymax, colors='k', linestyles='solid',
37543754
linestyles=linestyles, label=label)
37553755
self.add_collection(coll)
37563756
coll.update(kwargs)
3757-
3757+
37583758
if len(x) > 0:
37593759
minx = min( x )
37603760
maxx = max( x )
@@ -6955,16 +6955,18 @@ def pcolor(self, *args, **kwargs):
69556955
A :class:`matplotlib.colors.Colormap` instance. If *None*, use
69566956
rc settings.
69576957
6958-
norm: [ *None* | Normalize ]
6958+
*norm*: [ *None* | Normalize ]
69596959
An :class:`matplotlib.colors.Normalize` instance is used
69606960
to scale luminance data to 0,1. If *None*, defaults to
69616961
:func:`normalize`.
69626962
69636963
*vmin*/*vmax*: [ *None* | scalar ]
69646964
*vmin* and *vmax* are used in conjunction with *norm* to
6965-
normalize luminance data. If either are *None*, the min
6966-
and max of the color array *C* is used. If you pass a
6967-
*norm* instance, *vmin* and *vmax* will be ignored.
6965+
normalize luminance data. If either is *None*, it
6966+
is autoscaled to the respective min or max
6967+
of the color array *C*. If not *None*, *vmin* or
6968+
*vmax* passed in here override any pre-existing values
6969+
supplied in the *norm* instance.
69686970
69696971
*shading*: [ 'flat' | 'faceted' ]
69706972
If 'faceted', a black grid is drawn around each rectangle; if
@@ -7121,10 +7123,8 @@ def pcolor(self, *args, **kwargs):
71217123
if norm is not None: assert(isinstance(norm, mcolors.Normalize))
71227124
collection.set_cmap(cmap)
71237125
collection.set_norm(norm)
7124-
if vmin is not None or vmax is not None:
7125-
collection.set_clim(vmin, vmax)
7126-
else:
7127-
collection.autoscale_None()
7126+
collection.set_clim(vmin, vmax)
7127+
collection.autoscale_None()
71287128
self.grid(False)
71297129

71307130
x = X.compressed()
@@ -7167,9 +7167,11 @@ def pcolormesh(self, *args, **kwargs):
71677167
71687168
*vmin*/*vmax*: [ *None* | scalar ]
71697169
*vmin* and *vmax* are used in conjunction with *norm* to
7170-
normalize luminance data. If either are *None*, the min
7171-
and max of the color array *C* is used. If you pass a
7172-
*norm* instance, *vmin* and *vmax* will be ignored.
7170+
normalize luminance data. If either is *None*, it
7171+
is autoscaled to the respective min or max
7172+
of the color array *C*. If not *None*, *vmin* or
7173+
*vmax* passed in here override any pre-existing values
7174+
supplied in the *norm* instance.
71737175
71747176
*shading*: [ 'flat' | 'gouraud' ]
71757177
'flat' indicates a solid color for each quad. When
@@ -7235,10 +7237,8 @@ def pcolormesh(self, *args, **kwargs):
72357237
if norm is not None: assert(isinstance(norm, mcolors.Normalize))
72367238
collection.set_cmap(cmap)
72377239
collection.set_norm(norm)
7238-
if vmin is not None or vmax is not None:
7239-
collection.set_clim(vmin, vmax)
7240-
else:
7241-
collection.autoscale_None()
7240+
collection.set_clim(vmin, vmax)
7241+
collection.autoscale_None()
72427242

72437243
self.grid(False)
72447244

lib/matplotlib/colorbar.py

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ def __init__(self, ax, cmap=None,
255255
self.filled = filled
256256
self.extendfrac = extendfrac
257257
self.solids = None
258-
self.lines = None
258+
self.lines = list()
259259
self.outline = None
260260
self.patch = None
261261
self.dividers = None
@@ -467,14 +467,25 @@ def _add_solids(self, X, Y, C):
467467
)
468468
self.ax.add_collection(self.dividers)
469469

470-
def add_lines(self, levels, colors, linewidths):
470+
def add_lines(self, levels, colors, linewidths, erase=True):
471471
'''
472472
Draw lines on the colorbar.
473+
474+
*colors* and *linewidths* must be scalars or
475+
sequences the same length as *levels*.
476+
477+
Set *erase* to False to add lines without first
478+
removing any previously added lines.
473479
'''
474-
N = len(levels)
475-
dummy, y = self._locate(levels)
476-
if len(y) != N:
477-
raise ValueError("levels are outside colorbar range")
480+
y = self._locate(levels)
481+
nlevs = len(levels)
482+
igood = (y < 1.001) & (y > -0.001)
483+
y = y[igood]
484+
if cbook.iterable(colors):
485+
colors = np.asarray(colors)[igood]
486+
if cbook.iterable(linewidths):
487+
linewidths = np.asarray(linewidths)[igood]
488+
N = len(y)
478489
x = np.array([0.0, 1.0])
479490
X, Y = np.meshgrid(x,y)
480491
if self.orientation == 'vertical':
@@ -483,9 +494,10 @@ def add_lines(self, levels, colors, linewidths):
483494
xy = [zip(Y[i], X[i]) for i in xrange(N)]
484495
col = collections.LineCollection(xy, linewidths=linewidths)
485496

486-
if self.lines:
487-
self.lines.remove()
488-
self.lines = col
497+
if erase and self.lines:
498+
for lc in self.lines.pop():
499+
lc.remove()
500+
self.lines.append(col)
489501
col.set_color(colors)
490502
self.ax.add_collection(col)
491503

@@ -528,7 +540,10 @@ def _ticker(self):
528540
locator.axis.get_minpos = lambda : intv[0]
529541
formatter.axis.get_minpos = lambda : intv[0]
530542
b = np.array(locator())
531-
b, ticks = self._locate(b)
543+
ticks = self._locate(b)
544+
inrange = (ticks > -0.001) & (ticks < 1.001)
545+
ticks = ticks[inrange]
546+
b = b[inrange]
532547
formatter.set_locs(b)
533548
ticklabels = [formatter(t, i) for i, t in enumerate(b)]
534549
offset_string = formatter.get_offset()
@@ -746,37 +761,36 @@ def _mesh(self):
746761

747762
def _locate(self, x):
748763
'''
749-
Given a possible set of color data values, return the ones
750-
within range, together with their corresponding colorbar
751-
data coordinates.
764+
Given a set of color data values, return their
765+
corresponding colorbar data coordinates.
752766
'''
753767
if isinstance(self.norm, (colors.NoNorm, colors.BoundaryNorm)):
754768
b = self._boundaries
755769
xn = x
756-
xout = x
757770
else:
758771
# Do calculations using normalized coordinates so
759772
# as to make the interpolation more accurate.
760773
b = self.norm(self._boundaries, clip=False).filled()
761-
# We do our own clipping so that we can allow a tiny
762-
# bit of slop in the end point ticks to allow for
763-
# floating point errors.
764774
xn = self.norm(x, clip=False).filled()
765-
in_cond = (xn > -0.001) & (xn < 1.001)
766-
xn = np.compress(in_cond, xn)
767-
xout = np.compress(in_cond, x)
768-
# The rest is linear interpolation with clipping.
775+
# The rest is linear interpolation with extrapolation at ends.
769776
y = self._y
770777
N = len(b)
771-
ii = np.minimum(np.searchsorted(b, xn), N-1)
772-
i0 = np.maximum(ii - 1, 0)
778+
ii = np.searchsorted(b, xn)
779+
i0 = ii - 1
780+
itop = (ii == N)
781+
ibot = (ii == 0)
782+
i0[itop] -= 1
783+
ii[itop] -= 1
784+
i0[ibot] += 1
785+
ii[ibot] += 1
786+
773787
#db = b[ii] - b[i0]
774788
db = np.take(b, ii) - np.take(b, i0)
775-
db = np.where(i0==ii, 1.0, db)
776789
#dy = y[ii] - y[i0]
777790
dy = np.take(y, ii) - np.take(y, i0)
778791
z = np.take(y, i0) + (xn-np.take(b,i0))*dy/db
779-
return xout, z
792+
793+
return z
780794

781795
def set_alpha(self, alpha):
782796
self.alpha = alpha
@@ -834,10 +848,13 @@ def on_mappable_changed(self, mappable):
834848
self.set_clim(mappable.get_clim())
835849
self.update_normal(mappable)
836850

837-
def add_lines(self, CS):
851+
def add_lines(self, CS, erase=True):
838852
'''
839853
Add the lines from a non-filled
840854
:class:`~matplotlib.contour.ContourSet` to the colorbar.
855+
856+
Set *erase* to False if these lines should be added to
857+
any pre-existing lines.
841858
'''
842859
if not isinstance(CS, contour.ContourSet) or CS.filled:
843860
raise ValueError('add_lines is only for a ContourSet of lines')
@@ -851,7 +868,8 @@ def add_lines(self, CS):
851868
#tcolors = [col.get_colors()[0] for col in CS.collections]
852869
#tlinewidths = [col.get_linewidth()[0] for lw in CS.collections]
853870
#print 'tlinewidths:', tlinewidths
854-
ColorbarBase.add_lines(self, CS.levels, tcolors, tlinewidths)
871+
ColorbarBase.add_lines(self, CS.levels, tcolors, tlinewidths,
872+
erase=erase)
855873

856874
def update_normal(self, mappable):
857875
'''
@@ -884,7 +902,7 @@ def update_bruteforce(self, mappable):
884902
self.outline = None
885903
self.patch = None
886904
self.solids = None
887-
self.lines = None
905+
self.lines = list()
888906
self.dividers = None
889907
self.set_alpha(mappable.get_alpha())
890908
self.cmap = mappable.cmap

lib/matplotlib/colors.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -510,11 +510,10 @@ def __call__(self, X, alpha=None, bytes=False):
510510
xa = np.array([X])
511511
else:
512512
vtype = 'array'
513-
xma = ma.array(X, copy=False)
514-
mask_bad = xma.mask
515-
xa = xma.data.copy() # Copy here to avoid side effects.
513+
xma = ma.array(X, copy=True) # Copy here to avoid side effects.
514+
mask_bad = xma.mask # Mask will be used below.
515+
xa = xma.filled() # Fill to avoid infs, etc.
516516
del xma
517-
# masked values are substituted below; no need to fill them here
518517

519518
if xa.dtype.char in np.typecodes['Float']:
520519
# Treat 1.0 as slightly less than 1.

0 commit comments

Comments
 (0)