如何在分组条形图顶部添加百分比

2025-02-25 09:07:00
admin
原创
19
摘要:问题描述:给定以下计数图,我该如何将百分比放在条形图的顶部?import seaborn as sns sns.set(style="darkgrid") titanic = sns.load_dataset("titanic") ax = sns.countplot(...

问题描述:

给定以下计数图,我该如何将百分比放在条形图的顶部?

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

在此处输入图片描述

例如,对于“第一”,我希望在各自的栏目顶部显示男性第一名总数/第一名总数、女性第一名总数/第一名总数以及儿童第一名总数/第一名总数。


解决方案 1:

组织seaborn.catplot函数返回一个 FacetGrid,它允许您访问无花果、斧头及其补丁。如果您在没有绘制其他任何内容时添加标签,您就会知道哪些条形补丁来自哪些变​​量。从@LordZsolt 的回答中,我选择了order以下论点catplot:我喜欢明确这一点,因为现在我们不依赖于使用我们认为是默认的顺序的 barplot 函数。

import seaborn as sns
from itertools import product

titanic = sns.load_dataset("titanic")

class_order = ['First','Second','Third'] 
hue_order = ['child', 'man', 'woman']
bar_order = product(class_order, hue_order)

catp = sns.catplot(data=titanic, kind='count', 
                   x='class', hue='who',
                   order = class_order, 
                   hue_order = hue_order )

# As long as we haven't plotted anything else into this axis,
# we know the rectangles in it are our barplot bars
# and we know the order, so we can match up graphic and calculations:

spots = zip(catp.ax.patches, bar_order)
for spot in spots:
    class_total = len(titanic[titanic['class']==spot[1][0]])
    class_who_total = len(titanic[(titanic['class']==spot[1][0]) & 
        (titanic['who']==spot[1][1])])
    height = spot[0].get_height() 
    catp.ax.text(spot[0].get_x(), height+3, '{:1.2f}'.format(class_who_total/class_total))

    #checking the patch order, not for final:
    #catp.ax.text(spot[0].get_x(), -3, spot[1][0][0]+spot[1][1][0])

生产

3×3 变量值的条形图,以子集计算结果作为文本标签

另一种方法是明确地进行子求和,例如使用优秀的pandas,并使用绘制,并自己进行样式设置。(尽管即使在使用绘图函数时也matplotlib可以从上下文中获得相当多的样式。试试看——)sns`matplotlib`

解决方案 2:

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

如果您有一个普通的图, without_hue函数将在条形图上绘制百分比。它以实际的图形和特征作为参数。

def with_hue(ax, feature, Number_of_categories, hue_categories):
    a = [p.get_height() for p in ax.patches]
    patch = [p for p in ax.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)

def without_hue(ax, feature):
    total = len(feature)
    for p in ax.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)

在此处输入图片描述

在此处输入图片描述

解决方案 3:

答案受到上述 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()

用百分比计数图

解决方案 4:

  • 最简单的开始方式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

导入和示例 DataFrame

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

轴水平图

  • 适用于seaborn.countplotseaborn.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()

在此处输入图片描述

图形层次图

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()

在此处输入图片描述

解决方案 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")

在此处输入图片描述

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

由于Axes.patches它们的排序方式很奇怪(首先是所有蓝色条,然后是所有绿色条,然后是所有红色条),您必须将它们分开,然后将它们重新压缩在一起。

解决方案 6:

如果有超过 2 个色调类别,我就无法使这些方法发挥作用。

我使用了@Lord Zsolt 的方法,增强了任意数量的色调类别。

def barPerc(df,xVar,ax):
    '''
    barPerc(): Add percentage for hues to bar plots
    args:
        df: pandas dataframe
        xVar: (string) X variable 
        ax: Axes object (for Seaborn Countplot/Bar plot or
                         pandas bar plot)
    '''
    # 1. how many X categories
    ##   check for NaN and remove
    numX=len([x for x in df[xVar].unique() if x==x])

    # 2. The bars are created in hue order, organize them
    bars = ax.patches
    ## 2a. For each X variable
    for ind in range(numX):
        ## 2b. Get every hue bar
        ##     ex. 8 X categories, 4 hues =>
        ##    [0, 8, 16, 24] are hue bars for 1st X category
        hueBars=bars[ind:][::numX]
        ## 2c. Get the total height (for percentages)
        total = sum([x.get_height() for x in hueBars])

        # 3. Print the percentage on the bars
        for bar in hueBars:
            ax.text(bar.get_x() + bar.get_width()/2.,
                    bar.get_height(),
                    f'{bar.get_height()/total:.0%}',
                    ha="center",va="bottom")

在此处输入图片描述

正如您所见,这种方法满足了原始发帖者的要求:

我想要总计第一名男性/总计第一名、总计第一名女性/总计第一名以及总计第一名儿童/总计第一名,并将它们显示在各自的栏目顶部。

也就是说,添加的值是每个色调的百分比(对于每个 X 类别) - 因此对于每个 X 类别,百分比加起来为 100%


(这也适用于 Seaborn 的 .barplot())

在此处输入图片描述


相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1343  
  信创产业的蓬勃发展推动着各行业数字化转型加速,数据库迁移作为其中关键一环,面临诸多挑战。信创数据库迁移旨在将传统数据库平稳过渡到信创环境,以满足自主可控、安全可靠的需求。这一过程涉及技术、业务等多方面因素,稍有不慎就可能出现各种问题,影响业务的正常运行。深入探讨信创数据库迁移过程中的常见问题及解决方案,对于保障迁移工作...
2027年信创国产化   41  
  随着信息技术的飞速发展,信创国产化成为了国家战略的重要组成部分。国产化信创产品名录涵盖了众多领域,其在各个关键应用场景中发挥着重要作用。而信创国产化操作系统作为其中的核心环节,具备五大核心优势,为我国信息技术产业的自主可控发展提供了坚实支撑。关键应用场景之办公领域在办公领域,国产化信创产品有着广泛且深入的应用。如今,越...
国产信创系统   37  
  随着信息技术的飞速发展,信创国产化操作系统在政府部门的推广应用具有重要的战略意义。它不仅关乎国家信息安全,更是推动国内信息技术产业自主创新、实现科技自立自强的关键举措。在当前复杂的国际形势下,政府部门积极推广信创国产化操作系统,对于保障国家政务信息的安全稳定运行,提升信息技术的自主可控能力,具有不可替代的重要作用。推广...
信创产品有哪些   28  
  在企业数字化转型的进程中,信创数据库解决方案的选择至关重要。它不仅关乎企业数据的安全存储与管理,更影响着企业业务的稳定运行与未来发展。合适的信创数据库能够助力企业在复杂多变的市场环境中提升竞争力,保障数据主权与安全。然而,面对市场上众多的信创数据库产品和解决方案,企业往往感到困惑,不知如何做出正确的选择。接下来,我们将...
信创电脑   24  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用