2013-10-05 74 views
2

我是一名氣候學家,經常繪製例如溫度場使用「藍到白到紅」色彩圖。爲了使繪圖更具可讀性,我使用我在互聯網中找到的功能(但我不是很瞭解它)在一定數量的級別(bin)中離散化colormap:修改離散LinearSegmentedColormap

類似這樣:

import matplotlib.pyplot as plt 
import numpy as np 
from matplotlib import cm 
import matplotlib.colors as cols 
from numpy.random import randn 

def cmap_discretize(cmap, N): 
    colors_i = np.concatenate((np.linspace(0, 1., N), (0.,0.,0.,0.))) 
    colors_rgba = cmap(colors_i) 
    indices = np.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) ] 
    # Return colormap object. 
    return cols.LinearSegmentedColormap(cmap.name + "_%d"%N, cdict, 1024) 



cmap_disc= cmap_discretize(cm.RdBu_r,12) 


fig, ax = plt.subplots() 
data = np.clip(randn(250, 250), -1, 1) 

cax = ax.pcolor(data, cmap=cmap_disc) 
plt.colorbar(cax) 

plt.show() 

這導致

enter image description here

現在我想設置兩個中間最段(即這兩個接近於0),以白色,因爲我不想表現出非常小偏差。

我的目標是用類似這樣的東西來結束:

enter image description here

我真的有一個很難弄清楚如何將這些LinearSegmentedColormap進行相應修改。有人可以幫助我嗎?

+0

請閱讀:http://matplotlib.org/api/colors_api.html#matplotlib.colors。LinearSegmentedColormap,它具有顏色映射工作方式的清晰描述。 – tacaswell

+0

而且您可能會使用http://stackoverflow.com/questions/15399095/stacking-colormaps/15399564#15399564上的代碼並傳入兩個descritized彩色貼圖。 – tacaswell

回答

3

讓我們通過遍歷代碼開始您有

# get some uniformly sampled data, padded out a bit 
colors_i = np.concatenate((np.linspace(0, 1., N), (0.,0.,0.,0.))) 
# sample the input colormap at our sample points 
colors_rgba = cmap(colors_i) 
# indices for color map 
indices = np.linspace(0, 1., N+1) 
# dict to pass to the LinearSegmentedColormap 
cdict = {} 
# loop over the colors 
for ki,key in enumerate(('red','green','blue')): 
    # in each color assemble a list that looks like 
    #[..., 
    # (indices[2], colors_rgba[1,ki], colors_rgba[2,ki]), 
    # (indices[3], colors_rgba[2,ki], colors_rgba[3,ki]), 
    # ....] 
    cdict[key] = [ (indices[i], colors_rgba[i-1,ki], colors_rgba[i,ki]) for i in xrange(N+1) ] 
    # The color for a number between [indices[2], indices[3]] are interpolated 
    # between colors_rgba[2,ki] and colors_rgba[2,ki] which are the same 
    # which is what gives you the discrete blocks. 
# Construct and return colormap object. 
return cols.LinearSegmentedColormap(cmap.name + "_%d"%N, cdict, 1024) 

所以,現在的問題是,如何創建一個彩色地圖,在一個「翻番」白色帶中間。我想改變功能位有它採取兩種顏色圖(頂部和底部)

import matplotlib.pyplot as plt 
import numpy as np 
from matplotlib import cm 
import matplotlib.colors as cols 
from numpy.random import randn 

def cmap_double_discretize(cmap_bottom, cmap_top, N, split=.5): 
    """ 
    Generates a descritized color map using two existing color maps 

    Parameters 
    ---------- 
    cmap_bottom : cmap 
     The bottom cmap 

    cmap_top : cmap 
     The top cmap 

    N : int 
     The number of bins in each color map 

    split : float, optional 
     Where to join the maps, must be in [0, 1] 
    """ 
    # sanity check 
    assert split < 1 and split > 0 
    # set up the data structure 
    cdict = {lab: [] for lab in ('red','green','blue')} 
    # do this in a fancy loop to a) save typing, b) make it easy to 
    # retrofit to do arbitrary splits 
    for cmap, ends in zip((cmap_bottom, cmap_top), ((0, split), (split, 1))): 

     # run over the _whole_ range for each color map 
     colors_i = np.concatenate((np.linspace(0, 1., N), (0.,0.,0.,0.))) 
     # map the color 
     colors_rgba = cmap(colors_i) 
     # get the values 
     indices = np.linspace(ends[0], ends[1], N+1, endpoint=True) 

     for ki,key in enumerate(('red','green','blue')): 
      cdict[key].extend((indices[i], colors_rgba[i-1,ki], colors_rgba[i,ki]) for i in xrange(N+1)) 
      # print cdict 
    # Return colormap object. 
    return cols.LinearSegmentedColormap(cmap.name + "_%d"%N, cdict, 1024) 

red_cdict = {'red': [(0, 0, 1), 
        (1, 1, 0)], 
      'blue': [(0, 0, 0), 
        (1, 1, 0)], 
      'green': [(0, 0, 0), 
        (1, 1, 0)]} 

blue_cdict = {'blue': [(0, 0, 1), 
         (1, 1, 0),], 
      'red': [(0, 0, 1), 
        (1, 0, 0)], 
      'green': [(0, 0, 1), 
        (1, 0, 0)]} 
red_cmap = cols.LinearSegmentedColormap('red', red_cdict, 1024) 
blue_cmap = cols.LinearSegmentedColormap('blue', blue_cdict, 1024) 

test_cmap = cmap_double_discretize(red_cmap, blue_cmap, 6) 
# these don't actually go to white! 
# test_cmap = cmap_double_discretize(cm.get_cmap('Reds_r'), cm.get_cmap('Blues'), 6) 


fig, ax = plt.subplots() 
data = np.clip(randn(250, 250), -1, 1) 

cax = ax.pcolor(data, cmap=test_cmap) 
plt.colorbar(cax) 

plt.show() 

enter image description here

您可以輕鬆地修改這個橫跨兩個以上的彩色地圖分割。

+0

這也適用,但不支持中間有白色的預定義色彩地圖(如bwr,seismic,RdBu,RdGy ...)。非常感謝您的努力 –

5

你發現這個函數建立用於定義與不執行任何內插段一個LinearSegmentedColormap的數據結構(在cdict)(即,在y1i總是相同y0i+1行,並且這給出了恆定的或離散的顏色「帶」)。

cdict是一個奇怪的數據結構,包含密鑰'red','green''blue'的字典。每個這些鍵的值都是一個包含(x, y0, y1)形式的元組的列表結構。 x是彩色地圖座標,它是0到1之間的浮點數。y0x「左」側的顏色值,而y1x「右側」的顏色值。顏色在連續值x;如果第一個元組由(0, A, B)給出,第二個元組由(X, C, D)給出,那麼在0X之間的點t的顏色將由(t - 0)/(X - 0) * (C - B) + B給出。

出於您的目的,您的功能工作得很好,但需要將顏色貼圖中間附近的「條帶」替換爲白色。你可以嘗試類似以下內容:

def cmap_discretize(cmap, N): 
    colors_i = np.concatenate((np.linspace(0, 1., N), (0.,0.,0.,0.))) 
    colors_rgba = cmap(colors_i) 
    indices = np.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) ] 
    # "white out" the bands closest to the middle 
    num_middle_bands = 2 - (N % 2) 
    middle_band_start_idx = (N - num_middle_bands) // 2 
    for middle_band_idx in range(middle_band_start_idx, 
           middle_band_start_idx + num_middle_bands): 
     for key in cdict.keys(): 
      old = cdict[key][middle_band_idx] 
      cdict[key][middle_band_idx] = old[:2] + (1.,) 
      old = cdict[key][middle_band_idx + 1] 
      cdict[key][middle_band_idx + 1] = old[:1] + (1.,) + old[2:] 
    # Return colormap object. 
    return cols.LinearSegmentedColormap(cmap.name + "_%d"%N, cdict, 1024) 
+0

這是偉大的,但我仍然需要通過它來了解它 –

+0

我有點擔心達到擠壓像這樣的顏色,因爲你是在一個非常透明的方式使彩色地圖非線性。 – tacaswell