2012-07-22 298 views
10

我想在matplotlib中按照圖庫中的示例製作分組條形圖。我用的是以下幾點:matplotlib中分組條形圖之間的設置間隔

import matplotlib.pyplot as plt 
plt.figure(figsize=(7,7), dpi=300) 
xticks = [0.1, 1.1] 
groups = [[1.04, 0.96], 
      [1.69, 4.02]] 
group_labels = ["G1", "G2"] 
num_items = len(group_labels) 
ind = arange(num_items) 
width = 0.1 
s = plt.subplot(1,1,1) 
for num, vals in enumerate(groups): 
    print "plotting: ", vals 
    group_len = len(vals) 
    gene_rects = plt.bar(ind, vals, width, 
         align="center") 
    ind = ind + width 
num_groups = len(group_labels) 
# Make label centered with respect to group of bars 
# Is there a less complicated way? 
offset = (num_groups/2.) * width 
xticks = arange(num_groups) + offset 
s.set_xticks(xticks) 
print "xticks: ", xticks 
plt.xlim([0 - width, max(xticks) + (num_groups * width)]) 
s.set_xticklabels(group_labels) 

enter image description here

我的問題是:

  1. 如何控制酒吧的羣體之間的空間?現在間距很大,看起來很愚蠢。請注意,我不想讓這些條更寬 - 我希望它們具有相同的寬度,但要靠得更近。

  2. 我怎樣才能讓標籤在棒組下面居中?我試圖想出一些算術計算來將xlabels放置在正確的位置(參見上面的代碼),但它仍然略微偏離......這有點像寫一個繪圖庫而不是使用一個。這怎麼解決? (是否有包裝或內置實用工具matplotlib哪裏,這是默認的行爲?)

編輯:回覆@mlgill:感謝您的回答。你的代碼當然更優雅,但仍然存在相同的問題,即條形的寬度和組之間的間距不能單獨控制。你的圖看起來是正確的,但是酒吧太寬 - 看起來像一個Excel圖 - 我想讓酒吧變得更薄。

寬度和利潤率現在鏈接,所以如果我嘗試:

margin = 0.60 
width = (1.-2.*margin)/num_items 

這使得巴瘦,但帶來的組相距甚遠,所以情節再次看起來不正確的。

如何製作一個帶有兩個參數的分組條形圖函數:每個條形的寬度以及條形組之間的間距,並像代碼一樣正確地繪製它,即以x軸標籤爲中心團體?

我覺得,既然用戶有來計算具體的低層次的佈局數量一樣保證金和寬度,我們仍然基本上可以寫一個繪圖庫:)

回答

15

訣竅您的兩個問題是理解的是條形圖在Matplotlib中,預計每個系列(G1,G2)的總寬度爲「1.0」,計算任一側的邊距。因此,可能最容易設置邊距,然後計算每個小節的寬度,具體取決於每個小節有多少個小節。在你的情況下,每個系列有兩個小節。

假設您左對齊每個橫條,而不是像您所做的那樣對齊它們,則此設置將導致在x軸上跨越0.0到1.0,1.0到2.0等的系列。因此,每個系列的確切中心(您希望標籤出現的位置)將爲0.5,1.5等。

由於存在大量無關變量,因此我清理了代碼。見內的評論。

import matplotlib.pyplot as plt 
import numpy as np 

plt.figure(figsize=(7,7), dpi=300) 

groups = [[1.04, 0.96], 
      [1.69, 4.02]] 
group_labels = ["G1", "G2"] 
num_items = len(group_labels) 
# This needs to be a numpy range for xdata calculations 
# to work. 
ind = np.arange(num_items) 

# Bar graphs expect a total width of "1.0" per group 
# Thus, you should make the sum of the two margins 
# plus the sum of the width for each entry equal 1.0. 
# One way of doing that is shown below. You can make 
# The margins smaller if they're still too big. 
margin = 0.05 
width = (1.-2.*margin)/num_items 

s = plt.subplot(1,1,1) 
for num, vals in enumerate(groups): 
    print "plotting: ", vals 
    # The position of the xdata must be calculated for each of the two data series 
    xdata = ind+margin+(num*width) 
    # Removing the "align=center" feature will left align graphs, which is what 
    # this method of calculating positions assumes 
    gene_rects = plt.bar(xdata, vals, width) 


# You should no longer need to manually set the plot limit since everything 
# is scaled to one. 
# Also the ticks should be much simpler now that each group of bars extends from 
# 0.0 to 1.0, 1.0 to 2.0, and so forth and, thus, are centered at 0.5, 1.5, etc. 
s.set_xticks(ind+0.5) 
s.set_xticklabels(group_labels) 

Output from my code.

+0

另外,請注意一旦我的註釋被刪除,大大減少的命令數量。雖然我認爲Matplotlib的繪圖功能可以在某些方面使用較小的改進,但這當然不再像寫一個繪圖庫。 :) – 2012-07-22 20:43:00

+0

感謝您的評論,我在編輯回覆我的主要帖子。 – user248237dfsf 2012-07-22 21:20:53

+0

從上面所寫的內容來看,聽起來好像您要麼讓整個圖形的寬度更小(這可以在創建圖形的行中設置),或者希望邊距本身更大,這將保持寬高比相同。您還可以調整寬度和xdata計算,以便在每個小節之間留有餘量。完成這個只需要基本的代數。除了這三個想法之外,我不知道你在問什麼。 – 2012-07-22 21:42:56

2

我看了一個答案,保羅·伊萬諾夫張貼在Nabble可能與更低的複雜性解決這個問題。只需設置索引如下。這將增加分組列之間的間距。

ind = np.arange(0,12,2) 
9

其實我覺得這個問題是通過調整figsizewidth最好的解決;這是我與figsize=(2,7)width=0.3輸出:

enter image description here

順便說一句,如果你使用pandas包裝(我也進口seaborn,沒有必要爲解決這一類的事情就變得很多簡單但讓劇情有很多漂亮和更現代的看着在我看來):

import pandas as pd   
import seaborn 
seaborn.set() 

df = pd.DataFrame(groups, index = group_labels) 
df.plot(kind='bar', legend = False, width = .8, figsize = (2,5)) 
plt.show() 

enter image description here

相關問題