如何在seaborn的酒吧顶部添加百分比?

I a*_*rge 25 python matplotlib seaborn

鉴于以下计数图,我如何将百分比放在栏杆上?

import seaborn as sns
sns.set(style="darkgrid")
titanic = sns.load_dataset("titanic")
ax = sns.countplot(x="class", hue="who", data=titanic)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

例如,对于"第一",我想要总的第一人/总第一,总第一女人/总第一,总第一个孩子/总第一个在他们各自的酒吧之上.

如果我的解释不清楚,请告诉我.

谢谢!

cph*_*wis 48

sns.barplot没有明确地返回条形图值的方式matplotlib.pyplot.bar(参见最后一段),但如果你没有绘制任何其他内容,你可以冒险假设patches轴中的所有值都是你的值.然后,您可以使用barplot函数为您计算的小计:

from matplotlib.pyplot import show
import seaborn as sns
sns.set(style="darkgrid")
titanic = sns.load_dataset("titanic")
total = float(len(titanic)) # one person per row 
#ax = sns.barplot(x="class", hue="who", data=titanic)
ax = sns.countplot(x="class", hue="who", data=titanic) # for Seaborn version 0.7 and more
for p in ax.patches:
    height = p.get_height()
    ax.text(p.get_x()+p.get_width()/2.,
            height + 3,
            '{:1.2f}'.format(height/total),
            ha="center") 
show()
Run Code Online (Sandbox Code Playgroud)

产生

Countplot

另一种方法是明确地进行子求和,例如,使用优秀的pandas,与情节一起绘制matplotlib,并且自己也做样式.(尽管sns即使使用matplotlib绘图功能,您也可以从上下文中获得相当多的样式.尝试一下 - )

  • 这只是一个不同的等式 - 你看到`高度/总数'在哪里?带着它去城里. (2认同)

小智 9

如果您的图中有“色调”参数,with_hue函数将在条形图上绘制百分比。它以实际图形、特征、特征中的 Number_of_categories 和hue_categories(色调特征中的类别数)作为参数。

如果您有正常绘图,without_hue函数将在条形图上绘制百分比。它以实际图形和特征为参数。

def with_hue(plot, feature, Number_of_categories, hue_categories):
    a = [p.get_height() for p in plot.patches]
    patch = [p for p in plot.patches]
    for i in range(Number_of_categories):
        total = feature.value_counts().values[i]
        for j in range(hue_categories):
            percentage = '{:.1f}%'.format(100 * a[(j*Number_of_categories + i)]/total)
            x = patch[(j*Number_of_categories + i)].get_x() + patch[(j*Number_of_categories + i)].get_width() / 2 - 0.15
            y = patch[(j*Number_of_categories + i)].get_y() + patch[(j*Number_of_categories + i)].get_height() 
            ax.annotate(percentage, (x, y), size = 12)
    plt.show()

def without_hue(plot, feature):
    total = len(feature)
    for p in plot.patches:
        percentage = '{:.1f}%'.format(100 * p.get_height()/total)
        x = p.get_x() + p.get_width() / 2 - 0.05
        y = p.get_y() + p.get_height()
        ax.annotate(percentage, (x, y), size = 12)
    plt.show()
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

在此处输入图片说明


Vij*_*rya 7

答案是受到 jrjc 和 cphlewis 答案的启发,如上所述,但更简单易懂

sns.set(style="whitegrid")
plt.figure(figsize=(8,5))
total = float(len(train_df))
ax = sns.countplot(x="event", hue="event", data=train_df)
plt.title('Data provided for each event', fontsize=20)
for p in ax.patches:
    percentage = '{:.1f}%'.format(100 * p.get_height()/total)
    x = p.get_x() + p.get_width()
    y = p.get_height()
    ax.annotate(percentage, (x, y),ha='center')
plt.show()
Run Code Online (Sandbox Code Playgroud)

用百分比计数图


Tre*_*ney 7

  • 以 开头的最简单的选项matplotlib 3.4.2是使用matplotlib.pyplot.bar_label.
  • 有关使用的更多选项和信息,请参阅此答案.bar_label
  • 的列表理解labels使用赋值表达式 ( :=),这需要python >= 3.8. 这可以重写为标准的 for 循环。
    • labels = [f'{v.get_height()/data.who.count()*100:0.1f}' for v in c]无需赋值表达式即可工作。
    • 水平条的注释应使用v.get_width().
  • 示例中的注释占总数的百分比。要根据组的总数添加注释,请参阅此答案
  • 另请参阅如何使用 seaborn distplot / histplot / displot 绘制百分比
  • 测试于python 3.10, pandas 1.4.2, matplotlib 3.5.1,seaborn 0.11.2

导入和示例数据框

import matplotlib.pyplot as plt
import seaborn as sns

# load the data
data = sns.load_dataset('titanic')[['survived', 'class', 'who']]

   survived  class    who
0         0  Third    man
1         1  First  woman
2         1  Third  woman
Run Code Online (Sandbox Code Playgroud)

轴水平图

  • seaborn.countplot与或 一起使用seaborn.barplot
# plot
ax = sns.countplot(x="class", hue="who", data=data)
ax.set(ylabel='Bar Count', title='Bar Count and Percent of Total')

# add annotations
for c in ax.containers:
    
    # custom label calculates percent and add an empty string so 0 value bars don't have a number
    labels = [f'{h/data.who.count()*100:0.1f}%' if (h := v.get_height()) > 0 else '' for v in c]
    
    ax.bar_label(c, labels=labels, label_type='edge')

plt.show()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

图级图

fg = sns.catplot(data=data, kind='count', x='class', hue='who', col='survived')
fg.fig.subplots_adjust(top=0.9)
fg.fig.suptitle('Bar Count and Percent of Total')

for ax in fg.axes.ravel():
    
    # add annotations
    for c in ax.containers:

        # custom label calculates percent and add an empty string so 0 value bars don't have a number
        labels = [f'{h/data.who.count()*100:0.1f}%' if (h := v.get_height()) > 0 else '' for v in c]

        ax.bar_label(c, labels=labels, label_type='edge')

plt.show()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


Lor*_*olt 5

cphlewis 的解决方案的帮助下,我设法将正确的百分比放在图表的顶部,因此这些类的总和为 1。

for index, category in enumerate(categorical):
    plt.subplot(plot_count, 1, index + 1)

    order = sorted(data[category].unique())
    ax = sns.countplot(category, data=data, hue="churn", order=order)
    ax.set_ylabel('')

    bars = ax.patches
    half = int(len(bars)/2)
    left_bars = bars[:half]
    right_bars = bars[half:]

    for left, right in zip(left_bars, right_bars):
        height_l = left.get_height()
        height_r = right.get_height()
        total = height_l + height_r

        ax.text(left.get_x() + left.get_width()/2., height_l + 40, '{0:.0%}'.format(height_l/total), ha="center")
        ax.text(right.get_x() + right.get_width()/2., height_r + 40, '{0:.0%}'.format(height_r/total), ha="center")
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

但是,该解决方案假设有 2 个选项(男人、女人)而不是 3 个(男人、女人、孩子)。

由于Axes.patches以奇怪的方式排序(首先是所有蓝色条,然后是所有绿色条,然后是所有红色条),因此您必须将它们分开并相应地将它们拉回一起。