2014-10-06 69 views
12

我有一個數組的值,我想創建它的直方圖。我主要對低端數據感興趣,並希望在一個垃圾箱中收集每個300以上的數字。這個垃圾箱應該和其他所有垃圾箱一樣寬。我怎樣才能做到這一點?Matplotlib直方圖與高值收集箱

注:這個問題涉及到這樣一個問題:Defining bin width/x-axis scale in Matplotlib histogram

這是我試過到目前爲止:

import matplotlib.pyplot as plt 
import numpy as np 

def plot_histogram_01(): 
    np.random.seed(1) 
    values_A = np.random.choice(np.arange(600), size=200, replace=True).tolist() 
    values_B = np.random.choice(np.arange(600), size=200, replace=True).tolist() 

    bins = [0, 25, 50, 75, 100, 125, 150, 175, 200, 225, 250, 275, 300, 600] 

    fig, ax = plt.subplots(figsize=(9, 5)) 
    _, bins, patches = plt.hist([values_A, values_B], normed=1, # normed is deprecated and will be replaced by density 
           bins=bins, 
           color=['#3782CC', '#AFD5FA'], 
           label=['A', 'B']) 

    xlabels = np.array(bins[1:], dtype='|S4') 
    xlabels[-1] = '300+' 

    N_labels = len(xlabels) 
    plt.xlim([0, 600]) 
    plt.xticks(25 * np.arange(N_labels) + 12.5) 
    ax.set_xticklabels(xlabels) 

    plt.yticks([]) 
    plt.title('') 
    plt.setp(patches, linewidth=0) 
    plt.legend() 

    fig.tight_layout() 
    plt.savefig('my_plot_01.png') 
    plt.close() 

這是結果,這並不好看: enter image description here

然後我用xlim改了一行:

plt.xlim([0, 325]) 

結果如下: enter image description here

它看起來或多或少我所想要的,但最後斌現在是不可見的。我錯過了哪個技巧來以25的寬度形象化這最後一個bin?

回答

18

numpy的具有處理這個方便的功能:np.clip。儘管名稱可能聽起來像,但它不會刪除值,它只會將它們限制在您指定的範圍內。基本上,它是Artem的「骯髒的黑客」內聯。您可以保留值,因爲他們,但在hist通話,只是包裝在np.clip調用數組,像這樣

plt.hist(np.clip(values_A, bins[0], bins[-1]), bins=bins) 

這是有很多原因更好:

  1. 這是的方式更快 - 至少對於大量的元素。 Numpy在C級別上工作。在Python列表上運行(如Artem的列表理解)對每個元素都有很大的開銷。基本上,如果你有選擇使用numpy,你應該。

  2. 你可以在需要的地方做到這一點,從而減少在代碼中出錯的機率。

  3. 您不需要保留數組的第二個副本,這樣可以減少內存使用量(除了在這一行內)並進一步減少出錯的機率。

  4. 使用bins[0], bins[-1]而不是對值進行硬編碼可以減少再犯錯誤的機率,因爲您可以在定義bins的位置更改容器;您無需記得在致電clip或其他任何地方時更改它們。

因此要將其放到一起作爲OP:

import matplotlib.pyplot as plt 
import numpy as np 

def plot_histogram_01(): 
    np.random.seed(1) 
    values_A = np.random.choice(np.arange(600), size=200, replace=True).tolist() 
    values_B = np.random.choice(np.arange(600), size=200, replace=True).tolist() 

    bins = np.arange(0,350,25) 

    fig, ax = plt.subplots(figsize=(9, 5)) 
    _, bins, patches = plt.hist([np.clip(values_A, bins[0], bins[-1]), 
           np.clip(values_B, bins[0], bins[-1])], 
           normed=1, # normed is deprecated and will be replaced by density 
           bins=bins, color=['#3782CC', '#AFD5FA'], label=['A', 'B']) 

    xlabels = [str(b) for b in bins[1:]] 
    xlabels[-1] = '300+' 

    N_labels = len(xlabels) 
    plt.xlim([0, 325]) 
    plt.xticks(25 * np.arange(N_labels) + 12.5) 
    ax.set_xticklabels(xlabels) 

    plt.yticks([]) 
    plt.title('') 
    plt.setp(patches, linewidth=0) 
    plt.legend(loc='upper left') 

    fig.tight_layout() 
plot_histogram_01() 

result of code above

4

對不起,我不熟悉matplotlib。所以我對你有一個骯髒的黑客。我只是將所有大於300的值放在一個bin中,並更改了bin的大小。

問題的根源在於matplotlib試圖把所有的箱子放在圖上。在R我會把我的箱子轉換爲因子變量,所以他們不被視爲實數。

import matplotlib.pyplot as plt 
import numpy as np 

def plot_histogram_01(): 
    np.random.seed(1) 
    values_A = np.random.choice(np.arange(600), size=200, replace=True).tolist() 
    values_B = np.random.choice(np.arange(600), size=200, replace=True).tolist() 
    values_A_to_plot = [301 if i > 300 else i for i in values_A] 
    values_B_to_plot = [301 if i > 300 else i for i in values_B] 

    bins = [0, 25, 50, 75, 100, 125, 150, 175, 200, 225, 250, 275, 300, 325] 

    fig, ax = plt.subplots(figsize=(9, 5)) 
    _, bins, patches = plt.hist([values_A_to_plot, values_B_to_plot], normed=1, # normed is deprecated and will be replaced by density 
           bins=bins, 
           color=['#3782CC', '#AFD5FA'], 
           label=['A', 'B']) 

    xlabels = np.array(bins[1:], dtype='|S4') 
    xlabels[-1] = '300+' 

    N_labels = len(xlabels) 

    plt.xticks(25 * np.arange(N_labels) + 12.5) 
    ax.set_xticklabels(xlabels) 

    plt.yticks([]) 
    plt.title('') 
    plt.setp(patches, linewidth=0) 
    plt.legend() 

    fig.tight_layout() 
    plt.savefig('my_plot_01.png') 
    plt.close() 

plot_histogram_01() 

enter image description here

+0

這是一個骯髒的黑客,但它的工程!我接受這個答案,直到有更好的答案出現。 – physicalattraction 2014-10-06 15:13:04