From: Eric Firing <efiring@ha...>  20100528 00:44:22

On 05/27/2010 01:58 PM, T J wrote: > On Thu, May 27, 2010 at 3:23 PM, Eric Firing<efiring@...> wrote: >> >> I'm not sure I understand the problem; could you provide a tiny example >> to illustrate? >> > > Sure, let me focus just on the interpolation and I'll leave the > filtering issue out. > > In the script below, I plot a 3x3 array with the center element having > an "over" value. In the default case, because its value is over, the > colormap will assign it the maximum color. I also plot the case when > the "over" color is explicitly set to the minimum color and also to > white. What I want is this: > > The center element should be an equal mixture of the 4 elements around it. You can't do this via any manipulation of the colormap, or any fancier colormap specificationinstead, you have to manipulate the data value. For example, you could identify the "over" values in your data, and then use 2D interpolation to replace them with the values you want. Basemap includes a 2D interpolation routine: from mpl_toolkits.basemap import interp > > This is partially achieved with "white" (and I suppose I could pick > "grey" or "black"), but I think it might be nicer if it were a pure > mixture, rather than a mixture of the surrounding colors and the > "over" color. > > The script is attached below. Sorry it is a bit long, but I needed a > discrete colormap. Can we get cmap_discrete() into matplotlib? No, because it doesn't make much sense, given the mpl paradigm in which a colormap and a norm work together. If you want 4 colors, make a colormap with 4 colors, and use a norm that maps your data to those 4 colors. For example: cm4 = get_cmap('jet', 4) cm4a = mpl.colors.ListedColormap(get_cmap('jet', 256)([20, 70, 150, 200])) You can select any discrete set of colors you want using ListedColormap. Then you can use the default Normalize, or a custom BoundaryNorm, to map data ranges to the colors. You just don't need a lookup table with 1024 entries to specify 4 colorsit doesn't gain you anything. Eric > >  > > import matplotlib.pyplot as plt > import matplotlib.colors > > import numpy as np > from scipy import interpolate > > #### http://www.scipy.org/Cookbook/Matplotlib/ColormapTransformations > #### Can this be added to matplotlib? > def cmap_discretize(cmap, N): > """Return a discrete colormap from the continuous colormap cmap. > > cmap: colormap instance, eg. cm.jet. > N: Number of colors. > > Example > x = resize(arange(100), (5,100)) > djet = cmap_discretize(cm.jet, 5) > imshow(x, cmap=djet) > """ > > cdict = cmap._segmentdata.copy() > # N colors > colors_i = np.linspace(0,1.,N) > # N+1 indices > indices = np.linspace(0,1.,N+1) > for key in ('red','green','blue'): > # Find the N colors > D = np.array(cdict[key]) > I = interpolate.interp1d(D[:,0], D[:,1]) > colors = I(colors_i) > # Place these colors at the correct indices. > A = np.zeros((N+1,3), float) > A[:,0] = indices > A[1:,1] = colors > A[:1,2] = colors > # Create a tuple for the dictionary. > L = [] > for l in A: > L.append(tuple(l)) > cdict[key] = tuple(L) > # Return colormap object. > return matplotlib.colors.LinearSegmentedColormap('colormap',cdict,1024) > > def draw(m, cm, norm, ncolors): > ax = plt.gca() > ai = ax.imshow(m, cmap=cm, norm=norm, interpolation='gaussian') > cb = ax.figure.colorbar(ai) > cb.set_ticks(np.linspace(.5, ncolors.5, ncolors)) > cb.set_ticklabels(['$%s$' % (i,) for i in np.arange(ncolors)]) > return ai, cb > > if __name__ == '__main__': > ncolors = 4 > norm = plt.Normalize(vmax=ncolors) > m = np.array([[0, 0, 1], > [3, 10, 1], > [3, 2, 2]]) > > for over in [None, 'min', (1,1,1,1)]: > f = plt.figure() > cm = cmap_discretize(plt.cm.jet, ncolors) > if over == 'min': > cm.set_over(cm(0.0)) > elif over is not None: > cm.set_over(over) > ai, cb = draw(m, cm, norm, ncolors) > > plt.show() 