From: <ef...@us...> - 2008-02-03 21:27:04
|
Revision: 4934 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4934&view=rev Author: efiring Date: 2008-02-03 13:26:42 -0800 (Sun, 03 Feb 2008) Log Message: ----------- Modified BoundaryNorm, examples, colorbar support Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/examples/colorbar_only.py trunk/matplotlib/examples/image_masked.py trunk/matplotlib/lib/matplotlib/colorbar.py trunk/matplotlib/lib/matplotlib/colors.py Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2008-02-03 21:10:22 UTC (rev 4933) +++ trunk/matplotlib/CHANGELOG 2008-02-03 21:26:42 UTC (rev 4934) @@ -1,3 +1,6 @@ +2008-02-03 Added BoundaryNorm, with examples in colorbar_only.py + and image_masked.py. - EF + 2008-02-03 Force dpi=72 in pdf backend to fix picture size bug. - JKS 2008-02-01 Fix reference leak in ft2font Glyph objects. - MGD Modified: trunk/matplotlib/examples/colorbar_only.py =================================================================== --- trunk/matplotlib/examples/colorbar_only.py 2008-02-03 21:10:22 UTC (rev 4933) +++ trunk/matplotlib/examples/colorbar_only.py 2008-02-03 21:26:42 UTC (rev 4934) @@ -35,7 +35,7 @@ # one greater than the length of the color list. The bounds must be # monotonically increasing. bounds = [1, 2, 4, 7, 8] -norm = mpl.colors.BoundaryNorm(bounds) +norm = mpl.colors.BoundaryNorm(bounds, cmap.N) cb2 = mpl.colorbar.ColorbarBase(ax2, cmap=cmap, norm=norm, # to use 'extend', you must Modified: trunk/matplotlib/examples/image_masked.py =================================================================== --- trunk/matplotlib/examples/image_masked.py 2008-02-03 21:10:22 UTC (rev 4933) +++ trunk/matplotlib/examples/image_masked.py 2008-02-03 21:26:42 UTC (rev 4934) @@ -1,6 +1,8 @@ #!/usr/bin/env python '''imshow with masked array input and out-of-range colors. + The second subplot illustrates the use of BoundaryNorm to + get a filled contour effect. ''' from pylab import * @@ -31,10 +33,23 @@ # range to which the regular palette color scale is applied. # Anything above that range is colored based on palette.set_over, etc. +subplot(1,2,1) im = imshow(Zm, interpolation='bilinear', cmap=palette, norm = colors.Normalize(vmin = -1.0, vmax = 1.0, clip = False), origin='lower', extent=[-3,3,-3,3]) title('Green=low, Red=high, Blue=bad') -colorbar(im, extend='both', shrink=0.8) +colorbar(im, extend='both', orientation='horizontal', shrink=0.8) + +subplot(1,2,2) +im = imshow(Zm, interpolation='nearest', + cmap=palette, + norm = colors.BoundaryNorm([-1, -0.5, -0.2, 0, 0.2, 0.5, 1], + ncolors=256, clip = False), + origin='lower', extent=[-3,3,-3,3]) +title('With BoundaryNorm') +colorbar(im, extend='both', spacing='proportional', + orientation='horizontal', shrink=0.8) + show() + Modified: trunk/matplotlib/lib/matplotlib/colorbar.py =================================================================== --- trunk/matplotlib/lib/matplotlib/colorbar.py 2008-02-03 21:10:22 UTC (rev 4933) +++ trunk/matplotlib/lib/matplotlib/colorbar.py 2008-02-03 21:26:42 UTC (rev 4934) @@ -323,6 +323,9 @@ nv = len(self._values) base = 1 + int(nv/10) locator = ticker.IndexLocator(base=base, offset=0) + elif isinstance(self.norm, colors.BoundaryNorm): + b = self.norm.boundaries + locator = ticker.FixedLocator(b, nbins=10) elif isinstance(self.norm, colors.LogNorm): locator = ticker.LogLocator() else: @@ -389,6 +392,23 @@ self._boundaries = b self._values = v return + elif isinstance(self.norm, colors.BoundaryNorm): + b = list(self.norm.boundaries) + if self.extend in ('both', 'min'): + b = [b[0]-1] + b + if self.extend in ('both', 'max'): + b = b + [b[-1] + 1] + b = npy.array(b) + v = npy.zeros((len(b)-1,), dtype=float) + bi = self.norm.boundaries + v[self._inside] = 0.5*(bi[:-1] + bi[1:]) + if self.extend in ('both', 'min'): + v[0] = b[0] - 1 + if self.extend in ('both', 'max'): + v[-1] = b[-1] + 1 + self._boundaries = b + self._values = v + return else: if not self.norm.scaled(): self.norm.vmin = 0 Modified: trunk/matplotlib/lib/matplotlib/colors.py =================================================================== --- trunk/matplotlib/lib/matplotlib/colors.py 2008-02-03 21:10:22 UTC (rev 4933) +++ trunk/matplotlib/lib/matplotlib/colors.py 2008-02-03 21:26:42 UTC (rev 4934) @@ -685,13 +685,41 @@ return vmin * pow((vmax/vmin), value) class BoundaryNorm(Normalize): - def __init__(self, boundaries, clip=False): + ''' + Generate a colormap index based on discrete intervals. + + Unlike Normalize or LogNorm, BoundaryNorm maps values + to integers instead of to the interval 0-1. + + Mapping to the 0-1 interval could have been done via + piece-wise linear interpolation, but using integers seems + simpler, and reduces the number of conversions back and forth + between integer and floating point. + ''' + def __init__(self, boundaries, ncolors, clip=False): + ''' + args: + boundaries: a monotonically increasing sequence + ncolors: number of colors in the colormap to be used + + If b[i] <= v < b[i+1] then v is mapped to color j; + as i varies from 0 to len(boundaries)-2, + j goes from 0 to ncolors-1. + + Out-of-range values are mapped to -1 if low and ncolors + if high; these are converted to valid indices by + Colormap.__call__. + ''' self.clip = clip self.vmin = boundaries[0] self.vmax = boundaries[-1] self.boundaries = npy.asarray(boundaries) - self.midpoints = 0.5 *(self.boundaries[:-1] + self.boundaries[1:]) self.N = len(self.boundaries) + self.Ncmap = ncolors + if self.N-1 == self.Ncmap: + self._interp = False + else: + self._interp = True def __call__(self, x, clip=None): if clip is None: @@ -704,15 +732,17 @@ iret = npy.zeros(x.shape, dtype=npy.int16) for i, b in enumerate(self.boundaries): iret[xx>=b] = i + if self._interp: + iret = (iret * (float(self.Ncmap-1)/(self.N-2))).astype(npy.int16) iret[xx<self.vmin] = -1 - iret[xx>=self.vmax] = self.N - ret = ma.array(iret / float(self.N-1), mask=mask) + iret[xx>=self.vmax] = self.Ncmap + ret = ma.array(iret, mask=mask) if ret.shape == () and not mask: - ret = float(ret) # assume python scalar + ret = int(ret) # assume python scalar return ret def inverse(self, value): - return self.midpoints[int(value*(self.N-1))] + return ValueError("BoundaryNorm is not invertible") class NoNorm(Normalize): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |