2017-03-07 133 views
2

我有3組值的數組:0和1(綠色梯度) Matplotlib:如何在2個或更多的顏色中切割一個顏色條?

  • 值等於2(紅色)之間

    • 值等於3(灰)

    多虧了這個帖子(Define a colormap for each set of values in an array)我能得到這個代碼:

    from random import random 
    import numpy as np 
    import matplotlib.pyplot as plt 
    import matplotlib.colors as mcolors 
    from matplotlib import cm 
    
    n=11 
    tab = np.array([[random() for i in range(n)] for j in range(n)]) 
    tab[1,2] = 2. 
    tab[3,4] = 2. 
    tab[5,6] = 3. 
    tab[7,8] = 3. 
    
    values1 = np.ma.masked_array(tab, tab > 1.) 
    values2 = np.ma.masked_array(tab, tab != 2.) 
    values3 = np.ma.masked_array(tab, tab != 3.) 
    
    # 50 values for later use from 0 to 1 
    greens = cm.Greens(np.linspace(0,1, num=50)) 
    # 25 values for later use from 1 to 1.5 
    greensfill = cm.Greens(np.ones(25)) 
    # 50 values red for later use from 1.5 to 2.5 
    red = [(1,0,0,1)]*len(greens) 
    # 50 values gray for later use from 2.5 to 3.5 
    gray = [(.5,.5,.5,1)]*len(greens) 
    
    colors = np.vstack((greens, greensfill, red, gray)) 
    # in total we now have 175 colors in the colormap 
    mycmap = mcolors.LinearSegmentedColormap.from_list('my_colormap', colors) 
    
    #we now map those 175 colors to the range between 0 and 3.5 
    im = plt.imshow(tab, cmap = mycmap, interpolation="none", vmin=0, vmax=3.5) 
    cb = plt.colorbar(im) 
    cb.set_ticks([0,1,2,3]) 
    
    plt.show() 
    

    下面是結果:

    enter image description here

    我的問題是:可以matplotlib獲得通過削減現有的顏色映射成3個獨立的顏色表或者相近的東西像下面的圖片(編輯用Photoshop做)?

    enter image description here

    編輯:

    greens = cm.Greens(np.linspace(0,1, num=75)) 
    red = [(1,0,0,1)]*(len(greens)/2) 
    white = [(1,1,1,1)]*3 
    black = [(0,0,0,1)]*1 
    gray = [(.5,.5,.5,1)]*(len(greens)/2) 
    
    colors = np.vstack((greens, black, white, black, red, black, white, black, gray)) 
    mycmap = mcolors.LinearSegmentedColormap.from_list('my_colormap', colors) 
    

    我修改了代碼,並獲得內容,但它並不好看和索引是在錯誤的地方:

    enter image description here

  • +0

    偉大的想法(因爲我沒有在互聯網上看到任何類似的東西,所以我覺得它會有點困難)!我該如何移動我想要的索引? –

    +0

    @LoïcPoncin您可以通過'set_ticks'指定勾號位置並通過'set_ticklabels'勾選標籤。所以你可以通過'cb.set_ticks([0,1.5,2,3])來獲得右手繪圖的刻度+標籤; cb.set_ticklabels(['0','1','2','3'])'。然而,它將標籤'1'設置在位置1.5,因此實際上使顏色條無效。同樣在你的右手繪圖中(紅色區域),紅色區域從1到2.5,灰色區域從2.5到3.5,但是它們的大小相同。綠色跨越一個類似的區域,如灰色和小於紅色的區域,但是它們是三者中最大的一個。 –

    +0

    謝謝。 @a_guest是的,我知道它並不真正對應於彩條的原理。事實上,我在一個關於森林火災的學校項目中工作,在我的動畫中,綠色漸變(0和1之間)對應於像素中包含的植被的能力,紅色像素對應於燃燒的樹木,灰色對應於已經燃燒並在灰燼中的樹木。所以紅色和灰色的顏色就是傳說中的動畫。 –

    回答

    3

    首先:不要更改顏色表!這是用於指定數據的映射,因此如果更改它,數據表示形式與您最初的目標不同。

    你可以做的是創建3個不同的顏色條,如下所示。注意區別:我們有一個單一的色彩映射,但有三個色彩條,它們都顯示了一個色彩映射的一部分。

    enter image description here

    from random import random 
    import numpy as np 
    import matplotlib.pyplot as plt 
    import matplotlib.colors as mcolors 
    from matplotlib import cm 
    
    n=11 
    tab = np.array([[random() for i in range(n)] for j in range(n)]) 
    tab[1,2] = 2. 
    tab[3,4] = 2. 
    tab[5,6] = 3. 
    tab[7,8] = 3. 
    
    values1 = np.ma.masked_array(tab, tab > 1.) 
    values2 = np.ma.masked_array(tab, tab != 2.) 
    values3 = np.ma.masked_array(tab, tab != 3.) 
    
    # 50 values for later use from 0 to 1 
    greens = cm.Greens(np.linspace(0,1, num=50)) 
    # 25 values for later use from 1 to 1.5 
    greensfill = cm.Greens(np.ones(25)) 
    # 50 values red for later use from 1.5 to 2.5 
    red = [(1,0,0,1)]*len(greens) 
    # 50 values gray for later use from 2.5 to 3.5 
    gray = [(.5,.5,.5,1)]*len(greens) 
    
    colors = np.vstack((greens, greensfill, red, gray)) 
    # in total we now have 175 colors in the colormap 
    mycmap = mcolors.LinearSegmentedColormap.from_list('my_colormap', colors) 
    
    #we now map those 175 colors to the range between 0 and 3.5 
    im = plt.imshow(tab, cmap = mycmap, interpolation="none", vmin=0, vmax=3.5) 
    
    plt.subplots_adjust(top=0.90, bottom=0.1) 
    cb1ax = plt.gcf().add_axes([0.85, 0.8, 0.035, 0.1]) 
    cb2ax = plt.gcf().add_axes([0.85, 0.67, 0.035, 0.1]) 
    cb3ax = plt.gcf().add_axes([0.85, 0.1, 0.035, 0.54]) 
    
    plt.gcf().colorbar(im, cax=cb1ax, boundaries=[2.5,3.5], ticks=[3]) 
    plt.gcf().colorbar(im, cax=cb2ax, boundaries=[1.5,2.5], ticks=[2]) 
    plt.gcf().colorbar(im, cax=cb3ax, boundaries=np.linspace(0,1, num=100), ticks=[0,1]) 
    
    plt.show() 
    


    編輯:現在,它可能發生在彩條不坐間隔緊密的圖像,甚至重疊的。也可能發生這樣的情況,三個條的高度大於圖像的高度。爲了防止這種情況發生,我們可以調整欄杆大小並調整它們的位置,使它們始終看起來不錯。因此腳本的下半部分可能會被下面的代碼替代。

    plt.subplots_adjust(top=0.90, bottom=0.1) 
    plt.gcf().canvas.draw() 
    ax = plt.gca() 
    
    plt.subplots_adjust(top=0.90, bottom=0.1) 
    cb1ax = plt.gcf().add_axes([0.85, 0.8, 0.035, 0.1]) 
    cb2ax = plt.gcf().add_axes([0.85, 0.67, 0.035, 0.1]) 
    cb3ax = plt.gcf().add_axes([0.85, 0.1, 0.035, 0.54]) 
    
    plt.gcf().colorbar(im, cax=cb1ax, boundaries=[2.5,3.5], ticks=[3]) 
    plt.gcf().colorbar(im, cax=cb2ax, boundaries=[1.5,2.5], ticks=[2]) 
    plt.gcf().colorbar(im, cax=cb3ax, boundaries=np.linspace(0,1, num=100), ticks=[0,1]) 
    
    def resize(event=None): 
        s = 0.03 
        pos = ax.get_position() 
        smh = pos.height/8.; loh = pos.height*0.675 
        w = 0.06*pos.width; 
        x0 = pos.x1+0.065*pos.width 
        cb1ax.set_position([x0, pos.y0+loh+smh+2*s, w, smh]) 
        cb2ax.set_position([x0, pos.y0+loh+s,  w, smh]) 
        cb3ax.set_position([x0, pos.y0,    w, loh]) 
    
    resize() 
    plt.connect("resize_event", resize) 
    
    plt.show() 
    
    +0

    非常感謝!看看我得到:https://i.stack.imgur.com/PQAvH.png。如何正確地將3個顏色條對齊到我的身材右側並且尺寸相同?我知道對於單個顏色條,它必須是'divider = make_axes_locatable(axes)',然後'cax = divider.append_axes(「right」,size =「5%」,pad = 0.2)''。以及如何將這些小特性放在數字之外,而不是內部? –

    +0

    你想要完整的數字向外指出蜱嗎?然後在腳本頂部的'plt.rcParams [「xtick.direction」] =「out」'會有所幫助。分隔線不適用於3個顏色條。 「具有相同尺寸」是什麼意思?他們都應該是圖像高度的三分之一? – ImportanceOfBeingErnest

    +0

    我的意思是我想讓這套着色器的頂部和底部與陣列的頂部和底部對齊。例如,在你的帖子中,顏色條與數組的頂部和底部正確對齊,但在我發給你的鏈接中卻不是。感謝蜱,這正是我想要的。 –