簡體   English   中英

Seaborn 條形圖:條形圖的異構組

[英]Seaborn Barplot: Heterogeneous groups of bars

我正在使用 seaborn 到 plot 不同算法的結果。 我想區分不同的算法以及它們的分類(“組”)。 問題是並非所有算法都在所有組中,所以當我使用 group 作為hue時,我會得到很多空白:

import seaborn as sns
group = ['Simple', 'Simple', 'Complex', 'Complex', 'Cool']
alg = ['Alg 1', 'Alg 2', 'Alg 3', 'Alg 4', 'Alg 2']
results = [i+1 for i in range(len(group))]
sns.barplot(group, results, hue=alg)

條形圖

如您所見,seaborn 為來自所有算法的條形留出了空間,使其位於所有組中,從而導致大量空白。 我怎樣才能避免這種情況? 我確實想在 x 軸上顯示不同的組,並通過顏色/樣式區分不同的算法。 算法可能出現在多個但不是所有組中。 但我只想要“簡單”和“復雜”中的 2 個小節的空間,而“酷”中的 1 個小節。 也歡迎任何純matplotlib的解決方案; 它不需要是 seaborn。 不過,我想保留 seaborn 調色板。

似乎沒有創建這種類型的分組條形圖的標准方法。 以下代碼為條形創建一個位置列表,它們的 colors,以及標簽及其位置的列表。

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from matplotlib.patches import Patch

group = ['Simple', 'Simple', 'Complex', 'Complex', 'Cool']
alg = ['Alg 1', 'Alg 2', 'Alg 3', 'Alg 4', 'Alg 2']
colors = plt.cm.tab10.colors
alg_cat = pd.Categorical(alg)
alg_colors = [colors[c] for c in alg_cat.codes]

results = [i + 1 for i in range(len(group))]

dist_groups = 0.4 # distance between successive groups
pos = (np.array([0] + [g1 != g2 for g1, g2 in zip(group[:-1], group[1:])]) * dist_groups + 1).cumsum()
labels = [g1 for g1, g2 in zip(group[:-1], group[1:]) if g1 != g2] + group[-1:]
label_pos = [sum([p for g, p in zip(group, pos) if g == label]) / len([1 for g in group if g == label])
             for label in labels]
plt.bar(pos, results, color=alg_colors)
plt.xticks(label_pos, labels)
handles = [Patch(color=colors[c], label=lab) for c, lab in enumerate(alg_cat.categories)]
plt.legend(handles=handles)
plt.show()

結果圖

雖然可以在matplotlibnumpy中完全處理這種情況,但我已經通過pandas解決了它。 原因是您需要找出一種正確進行分類分組的方法,這是pandas的主要優勢之一。

所以我所做的,基本上,是從您的數據中創建一個 DataFrame,然后按 - 顯然 - group類別進行分組。 在遍歷索引為i=0,1,2,..的每個枚舉類別時,我們創建了一組ax.bar()圖,每個圖都限制在區間[i-0.5, i+0,5]內。 根據要求,顏色取自 seaborn 顏色圖,最后也用於創建自定義圖例。

import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import pandas as pd
import numpy as np

group = ['Simple', 'Simple', 'Complex', 'Complex', 'Cool']
alg = ['Alg 1', 'Alg 2', 'Alg 3', 'Alg 4', 'Alg 2']
results = [i+1 for i in range(len(group))]

df = pd.DataFrame({'group':group, 'alg':alg, 'results':results})

## this next line is only required if you have a specific order in mind;
#  else, the .groupby() method will sort alphabetically!
df['group'] = pd.Categorical(df['group'], ["Simple", "Complex", "Cool"])

## choose the desired seaborn color palette here:
palette = sns.color_palette("Paired", len(alg))
labels, levels = pd.factorize(df['alg'])
df['color'] = [palette[l] for l in labels]

gdf = df.groupby('group')

fig,ax=plt.subplots(figsize=(5,3))  

xt = []
xtl = []

min_width = 1/max([len(item) for (key,item) in gdf])


for i,(key,item) in enumerate(gdf):
    xt.append(i)
    xtl.append(key)

    ## for each enumerated group, we need to create the proper x-scale placement
    #  such that each bar plot is centered around " i "
    #  i.e. two bars near " i = 0 " will be placed at [-0.25, 0.25] with widths of 0.5
    #  so that they won't collide with bars near " i = 1 "
    #  which themselves are placed at [0.75 1.25] 
    rel = np.linspace(0,1,len(item)+1)[:-1]
    rel -= rel.mean() 
    rel +=i

    w = 1/(len(item))
    ## note that the entire interval width (i.e. from i-0.5 to i+0.5) will be filled with the bars,
    #  meaning that the individual bar widths will vary depending on the number of bars.
    #  either adjust the bar width like this to add some whitespace:
    # w *= 0.9 
    ## or alternatively, you could use a fixed width instead:
    # w = 0.4
    ## or, by pre-evaluating the minimal required bar width:
    # w = min_width

    ax.bar(rel,item['results'].values,alpha=1,width=w,color=item['color'])

leg = []
for i,l in enumerate(levels):
    p = mpatches.Patch(color=palette[i], label=l)
    leg.append(p)
ax.legend(handles=leg)

ax.set_xticks(xt)
ax.set_xticklabels(xtl)
ax.grid()
plt.show()

結果(使用sns.color_palette("Paired")w=1/len(item) )如下所示:

漂亮的條形圖

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM