Differences between revisions 11 and 12

Deletions are marked like this. Additions are marked like this.
Line 79: Line 79:
        N: Number of colors.         N: number of colors.
Line 87: Line 87:
    cdict = cmap._segmentdata.copy()
    # N colors
    colors_i = linspace(0,1.,N)
    # N+1 indices
    indices = linspace(0,1.,N+1)
    for key in ('red','green','blue'):
        # Find the N colors
        D = array(cdict[key])
        I = interpolate.interp1d(D[:,0], D[:,1])
        colors = I(colors_i)
        # Place these colors at the correct indices.
        A = 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)
    if type(cmap) == str:
        cmap = get_cmap(cmap)
    colors_i = concatenate((linspace(0, 1., N), (0.,0.,0.,0.)))
    colors_rgba = cmap(colors_i)
    indices = linspace(0, 1., N+1)
    cdict = {}
    for ki,key in enumerate(('red','green','blue')):
        cdict[key] = [ (indices[i], colors_rgba[i-1,ki], colors_rgba[i,ki]) for i in xrange(N+1) ]
Line 108: Line 96:
    return matplotlib.colors.LinearSegmentedColormap('colormap',cdict,1024)     return matplotlib.colors.LinearSegmentedColormap(cmap.name + "_%d"%N, cdict, 1024)

Operating on color vectors

Ever wanted to reverse a colormap, or to desaturate one ? Here is a routine to apply a function to the look up table of a colormap:

   1 def cmap_map(function,cmap):
   2     """ Applies function (which should operate on vectors of shape 3:
   3     [r, g, b], on colormap cmap. This routine will break any discontinuous     points in a colormap.
   4     """
   5     cdict = cmap._segmentdata
   6     step_dict = {}
   7     # Firt get the list of points where the segments start or end
   8     for key in ('red','green','blue'):         step_dict[key] = map(lambda x: x[0], cdict[key])
   9     step_list = sum(step_dict.values(), [])
  10     step_list = array(list(set(step_list)))
  11     # Then compute the LUT, and apply the function to the LUT
  12     reduced_cmap = lambda step : array(cmap(step)[0:3])
  13     old_LUT = array(map( reduced_cmap, step_list))
  14     new_LUT = array(map( function, old_LUT))
  15     # Now try to make a minimal segment definition of the new LUT
  16     cdict = {}
  17     for i,key in enumerate(('red','green','blue')):
  18         this_cdict = {}
  19         for j,step in enumerate(step_list):
  20             if step in step_dict[key]:
  21                 this_cdict[step] = new_LUT[j,i]
  22             elif new_LUT[j,i]!=old_LUT[j,i]:
  23                 this_cdict[step] = new_LUT[j,i]
  24         colorvector=  map(lambda x: x + (x[1], ), this_cdict.items())
  25         colorvector.sort()
  26         cdict[key] = colorvector
  27 
  28     return matplotlib.colors.LinearSegmentedColormap('colormap',cdict,1024)

Lets try it out: I want a jet colormap, but lighter, so that I can plot things on top of it:

light_jet = cmap_map(lambda x: x/2+0.5, cm.jet)
x,y=mgrid[1:2,1:10:0.1]
imshow(y, cmap=light_jet)

As a comparison, this is what the original jet looks like:

Operating on indices

OK, but what if you want to change the indices of a colormap, but not its colors.

   1 def cmap_xmap(function,cmap):
   2     """ Applies function, on the indices of colormap cmap. Beware, function
   3     should map the [0, 1] segment to itself, or you are in for surprises.
   4 
   5     See also cmap_xmap.
   6     """
   7     cdict = cmap._segmentdata
   8     function_to_map = lambda x : (function(x[0]), x[1], x[2])
   9     for key in ('red','green','blue'):         cdict[key] = map(function_to_map, cdict[key])
  10         cdict[key].sort()
  11         assert (cdict[key][0]<0 or cdict[key][-1]>1), "Resulting indices extend out of the [0, 1] segment."
  12 
  13 
  14     return matplotlib.colors.LinearSegmentedColormap('colormap',cdict,1024)

Discrete colormap

Here is how you can discretize a continuous colormap.

   1 def cmap_discretize(cmap, N):
   2     """Return a discrete colormap from the continuous colormap cmap.
   3     
   4         cmap: colormap instance, eg. cm.jet. 
   5         N: number of colors.
   6     
   7     Example
   8         x = resize(arange(100), (5,100))
   9         djet = cmap_discretize(cm.jet, 5)
  10         imshow(x, cmap=djet)
  11     """
  12 
  13     if type(cmap) == str:
  14         cmap = get_cmap(cmap)
  15     colors_i = concatenate((linspace(0, 1., N), (0.,0.,0.,0.)))
  16     colors_rgba = cmap(colors_i)
  17     indices = linspace(0, 1., N+1)
  18     cdict = {}
  19     for ki,key in enumerate(('red','green','blue')):
  20         cdict[key] = [ (indices[i], colors_rgba[i-1,ki], colors_rgba[i,ki]) for i in xrange(N+1) ]
  21     # Return colormap object.
  22     return matplotlib.colors.LinearSegmentedColormap(cmap.name + "_%d"%N, cdict, 1024)

So for instance, this is what you would get by doing cmap_discretize(cm.jet, 6).

Cookbook/Matplotlib/ColormapTransformations (last edited 2012-10-23 13:58:42 by macdems)