Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a colormap with white centered around zero

I must admit, understanding how to create or manipulate matplotlib's colormaps is not an easy thing. Therefore I'm seeking a little help in explaining and setting up a colormap that goes from blue (negative) to red (positive) and has white centered tightly around zero. I would then like to use this cmap in contourf:

  1. This works but the colors are reversed

    cs = plt.contourf(longrid, latgrid,
                      ar[window-1]-bkgrd, levels,
                      cmap = cm.get_cmap('BuRd', len(levels)-1))
    
  2. The problem here is that BuRd_r takes away the white around zero

    cs = plt.contourf(longrid, latgrid,
                      ar[window-1]-bkgrd, levels,
                      cmap = cm.get_cmap('BuRd_r', len(levels)-1))
    

I would appreciate any help with this.

Here's the function and data to test the colormap:

def PlotAnomalyCF(ar,hgrid,latgrid,longrid,outfile,levels,units):                        
    window = 1                                                                           
    tsize = 8                                                                            
    plt.close()                                                                          
    plt.figure(figsize=(11.7,4.3) )                                                      
    plt.clf()                                                                            
    plt.cla()                                                                            

    bkgrd = bn.nanmean(ar[:],0)

    for v in hgrid:OA                                                                    
        plt.subplot(1,len(hgrid),window)                                                 
        plt.title(v,fontsize=tsize)                                                      
        plt.subplots_adjust(left=0.07,bottom=0.75,                                       
                            right=0.98, top=0.92,                                        
                            wspace=0.12,hspace=0.98)                                     
        cs = plt.contourf(longrid,latgrid,                                               
                          ar[window-1]-bkgrd,levels,                                     
                          cmap=cm.get_cmap('BuRd_r',len(levels)-1))                      
        cs.cmap.set_over('r')                                                            
        plt.grid(True)                                                                   
        plt.axis('off')                                                                  
        window += 1                                                                      
    ax = plt.gca()                                                                       
    pos = ax.get_position()                                                              
    l,b,w,h = pos.bounds                                                                 
    print l,b,w,h                                                                        
    cax = plt.axes([l-0.848,b-0.05,0.91,0.02]) # setup colorbar axes                     
    cbar = plt.colorbar(cs,cax=cax,orientation='horizontal')                             
    cl = plt.getp(cbar.ax, 'xticklabels')                                                
    plt.setp(cl, fontsize=8)
    # Add units text                                                                     
    plt.figtext(0.012,0.83,units,fontsize=tsize+1)                                       
    print 'outfile.',outfile                                                             
    plt.savefig(outfile,dpi=900,orientation='landscape',format='pdf')                    
    plt.show()

# Data
hgrid = array([-18, -15, -12,  -9,  -6,  -3,   0,   3,   6,   9,  12,  15,  18])
latgrid = array([ 5.61402391,  4.91227095,  4.21051798,  3.508765  ,  2.80701201,
                  2.10525902,  1.40350602,  0.70175301,  0.        , -0.70175302,
                 -1.40350604, -2.10525907, -2.8070121 , -3.50876514, -4.21051818,
                 -4.91227122, -5.61402427])
longrid = array([-5.625   , -4.921875, -4.21875 , -3.515625, -2.8125  , -2.109375,
                 -1.40625 , -0.703125,  0.      ,  0.703125,  1.40625 ,  2.109375,
                 2.8125  ,  3.515625,  4.21875 ,  4.921875,  5.625   ])
levels = array([-20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10,  -9,  -8,
                -7,  -6,  -5,  -4,  -3,  -2,  -1,   0,   1,   2,   3,   4,   5,
                 6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,
                 19,  20])
units ='$\mathrm{CC_{200}\,[\%]}$'
ar = shape is (13, 17, 17) with max = 82.4 and min = 45.5. It would be easier to just
     generate some random data within these intervals. Alternatively just copy one of the 
     array:
ar[1] = array([[ 46.91224792,  46.21374984,  46.86130719,  47.01021234,
     46.72626813,  46.2288305 ,  46.43835451,  45.79325437,
     45.58271668,  46.35872217,  48.08725987,  48.44553638,
     47.76519316,  47.6366742 ,  48.40425078,  48.77756577,
     49.33566712],
   [ 46.83599932,  46.84286989,  47.33453309,  46.55030976,
     46.80566458,  46.53292035,  47.02261763,  47.41084421,
     47.38724565,  47.91122826,  49.21117552,  49.45223641,
     49.97629913,  50.44165439,  51.08080398,  50.79600723,  49.968034  ],
   [ 47.42288313,  47.07674124,  46.7167639 ,  46.11959218,
     46.95814111,  46.88763807,  47.79510368,  48.50213272,
     49.14340301,  50.0550682 ,  50.96554707,  51.70960776,
     52.76304827,  53.13428506,  53.01955687,  52.57951586,
     51.91245273],
   [ 47.71067291,  47.48154219,  47.40131211,  47.45929857,
     48.46118424,  48.65199823,  49.38156691,  49.86137507,
     50.55394084,  51.96604309,  52.60579898,  53.69096203,
     54.22750101,  54.37757099,  54.31517398,  53.47697773,
     53.41809044],
   [ 48.20779565,  48.58856851,  48.75880829,  49.40822878,
     50.03355014,  51.44922083,  52.00567831,  52.99485667,
     53.69339127,  53.58208129,  53.88588998,  55.24096208,
     55.24137628,  55.38338399,  55.30856415,  55.0329081 ,
     54.58041914],
   [ 49.20063728,  49.81223264,  50.2145489 ,  50.54749112,
     51.44252761,  53.1708726 ,  54.48141824,  55.1337493 ,
     55.86338227,  55.80719304,  56.1060897 ,  56.15050406,
     56.10404113,  56.82550383,  57.12370494,  56.79250814,
     57.21656741],
   [ 50.17222332,  50.78494993,  51.47036476,  51.78513471,
     54.07329312,  55.12136894,  56.63202678,  56.77587861,
     57.60688855,  57.31874243,  57.86532727,  58.38753463,
     58.52204736,  58.8451274 ,  59.17282185,  58.93137673,
     58.90977463],
   [ 51.50642331,  51.51055372,  52.44746806,  53.37696513,
     54.86775802,  56.68992167,  57.90624404,  58.76394172,
     59.64662899,  59.80540837,  59.98355254,  60.05761821,
     59.95848562,  60.54540623,  60.4776266 ,  60.11749116,
     59.74209418],
   [ 51.40396463,  51.48043239,  52.89530187,  53.73500868,
     55.39612502,  56.70178532,  58.07064267,  59.56644298,
     60.47288049,  60.59095081,  61.26474813,  61.20278944,
     61.43807574,  61.1942828 ,  60.40014922,  59.78371327,
     59.50410992],
   [ 51.89656984,  52.18725649,  52.57764233,  54.39502415,
     55.61672911,  57.04180061,  58.54357871,  59.76354498,
     60.24155861,  60.59473182,  60.65985503,  60.92762915,
     60.76726905,  60.47166256,  60.42044548,  60.04043031,
     60.06031171],
   [ 51.69698671,  52.39494994,  52.71685017,  53.65488505,
     54.52480831,  56.33091376,  57.87811829,  58.36719736,
     59.31479758,  59.61329074,  59.81807224,  59.44053305,
     59.25522337,  59.5309563 ,  59.68850776,  59.54046914,
     58.60604327],
   [ 50.81523448,  51.5690217 ,  51.81382216,  52.88514118,
     53.27394887,  54.6941369 ,  55.81938471,  56.85401174,
     57.10874072,  58.55074569,  58.45869901,  57.67496274,
     57.3895956 ,  58.05319653,  58.83009123,  57.90678384,
     56.97717781],
   [ 49.61355365,  49.92298625,  50.56281781,  51.22117266,
     51.98020374,  53.0328832 ,  53.76602714,  54.94396421,
     55.16849545,  55.83033544,  56.19720112,  56.9382048 ,
     57.20669361,  56.76351885,  56.93632305,  56.16428665,  54.7570241 ],
   [ 49.17250426,  49.14663096,  49.86504335,  50.24394193,
     50.84671744,  51.21785439,  51.72667942,  52.8287256 ,
     53.65550669,  53.81801262,  54.62490542,  54.88045696,
     55.27367041,  54.89234901,  54.51005786,  53.57284022,
     52.53966996],
   [ 48.55125023,  48.99467099,  49.80237362,  49.67943854,
     49.45569362,  49.3387854 ,  50.129718  ,  49.94784906,
     51.03357894,  51.73021167,  52.0211617 ,  52.55805334,
     52.22956095,  51.88844202,  50.87410618,  50.39506101,
     49.72117909],
   [ 48.37551433,  48.30812683,  48.45300884,  48.50818535,
     47.76798967,  47.21965588,  47.60764424,  48.21327283,
     48.52370448,  49.95221655,  49.7608777 ,  50.1178807 ,
     50.15020093,  49.4369175 ,  49.16839811,  49.31254753,
     48.03208233],
   [ 46.91675497,  46.45280928,  46.37122283,  46.69881125,
     45.95493853,  46.33296801,  46.15091804,  46.09862998,
     46.31676066,  46.6199912 ,  47.60040926,  48.34096053,
     47.78005438,  48.0951173 ,  48.15291404,  47.21140107,
     46.28884057]]) 
like image 322
Shejo284 Avatar asked Jul 25 '12 10:07

Shejo284


People also ask

What is a sequential colormap?

Sequential colormaps (that are perceptually uniform of course) are basic colormaps that start at a reasonably low lightness value and uniformly increase to a higher value. They are commonly used to represent information that is ordered.

How do you define a colormap?

A colormap is a matrix of values that define the colors for graphics objects such as surface, image, and patch objects. MATLAB® draws the objects by mapping data values to colors in the colormap. Colormaps can be any length, but must be three columns wide. Each row in the matrix defines one color using an RGB triplet.


1 Answers

Rather than using a stock cmap, I will walk thorough the production of your own.

As you have already spotted, in order to have absolute control of the colors (without passing a colors array) when using cmaps, the number of colors in a cmap should be equal to the number of levels - 1.

We can easily demonstrate this with the following example. Lets make a colormap with the three primary colors in:

import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import numpy


data = numpy.arange(12).reshape(3, 4)

cmap = mcolors.ListedColormap([(0, 0, 1), 
                               (0, 1, 0), 
                               (1, 0, 0)])

However, when we come to use this with anything other than 3+1 levels, we will get results that you may not expect:

plt.subplot(121)
plt.contourf(data, cmap=cmap, levels=[1, 4, 8, 10])

plt.subplot(122)
plt.contourf(data, cmap=cmap, levels=[1, 4, 8])

plt.show()

enter image description here

So I have shown that your levels must be of length n_colors-1, but because we want to have 3 colors, and the middle color always shown, we must also have an even number of levels.

Good, now we have some ground rules, lets make a LinearSegmentedColormap which is essentially just a ListedColormap with interpolation to N colors:

levs = range(12)
assert len(levs) % 2 == 0, 'N levels must be even.'

cmap = mcolors.LinearSegmentedColormap.from_list(name='red_white_blue', 
                                                 colors =[(0, 0, 1), 
                                                          (1, 1., 1), 
                                                          (1, 0, 0)],
                                                 N=len(levs)-1,
                                                 )
plt.contourf(data, cmap=cmap, levels=levs)
plt.show()

enter image description here

We can verify that the normailzed cmap has white as the middle color programatically:

>>> print cmap(0.5)
(1.0, 1.0, 1.0, 1.0)

Hopefully this will give you all the information you need to be able to make any colormap you like and to use it successfully in contouring.

like image 174
pelson Avatar answered Sep 23 '22 18:09

pelson