matplotlib 如何按行计算百分比并注解100%堆积条形图

jei2mxaa  于 2023-03-09  发布在  其他
关注(0)|答案(2)|浏览(185)

我需要帮助添加的百分比分布的总数(没有小数)在每一部分的堆叠条形图在Pandas创建的交叉表在一个 Dataframe 。
以下是示例数据:

data = {
    'Name':['Alisa','Bobby','Bobby','Alisa','Bobby','Alisa',
            'Alisa','Bobby','Bobby','Alisa','Bobby','Alisa'],
    'Exam':['Semester 1','Semester 1','Semester 1','Semester 1','Semester 1','Semester 1',
            'Semester 2','Semester 2','Semester 2','Semester 2','Semester 2','Semester 2'],
     
    'Subject':['Mathematics','Mathematics','English','English','Science','Science',
               'Mathematics','Mathematics','English','English','Science','Science'],
   'Result':['Pass','Pass','Fail','Pass','Fail','Pass','Pass','Fail','Fail','Pass','Pass','Fail']}
df = pd.DataFrame(data)

# display(df)
     Name        Exam      Subject Result
0   Alisa  Semester 1  Mathematics   Pass
1   Bobby  Semester 1  Mathematics   Pass
2   Bobby  Semester 1      English   Fail
3   Alisa  Semester 1      English   Pass
4   Bobby  Semester 1      Science   Fail
5   Alisa  Semester 1      Science   Pass
6   Alisa  Semester 2  Mathematics   Pass
7   Bobby  Semester 2  Mathematics   Fail
8   Bobby  Semester 2      English   Fail
9   Alisa  Semester 2      English   Pass
10  Bobby  Semester 2      Science   Pass
11  Alisa  Semester 2      Science   Fail

下面是我的代码:

#crosstab
pal = ["royalblue", "dodgerblue", "lightskyblue", "lightblue"]
ax= pd.crosstab(df['Name'], df['Subject']).apply(lambda r: r/r.sum()*100, axis=1)
ax.plot.bar(figsize=(10,10),stacked=True, rot=0, color=pal)
display(ax)
    
plt.legend(loc='best', bbox_to_anchor=(0.1, 1.0),title="Subject",)

plt.xlabel('Name')
plt.ylabel('Percent Distribution')

plt.show()

我知道我需要添加一个plt.text,但是我不知道该怎么做。我想把总数的百分比嵌入到堆叠的条形图中。

pgky5nke

pgky5nke1#

我们试试看:

# crosstab
pal = ["royalblue", "dodgerblue", "lightskyblue", "lightblue"]
ax= pd.crosstab(df['Name'], df['Subject']).apply(lambda r: r/r.sum()*100, axis=1)
ax_1 = ax.plot.bar(figsize=(10,10), stacked=True, rot=0, color=pal)
display(ax)

plt.legend(loc='upper center', bbox_to_anchor=(0.1, 1.0), title="Subject")

plt.xlabel('Name')
plt.ylabel('Percent Distribution')

for rec in ax_1.patches:
    height = rec.get_height()
    ax_1.text(rec.get_x() + rec.get_width() / 2, 
              rec.get_y() + height / 2,
              "{:.0f}%".format(height),
              ha='center', 
              va='bottom')
    
plt.show()

输出:

Subject English Mathematics Science
Name            
Alisa   33.333333   33.333333   33.333333
Bobby   33.333333   33.333333   33.333333

ctrmrzij

ctrmrzij2#

  • matplotlib 3.4.2使用matplotlib.pyplot.bar_label
  • 有关使用该方法的详细说明和其他示例,请参见answer
  • 使用label_type='center'将使用每个段的值进行注解,而label_type='edge'将使用段的累积和进行注解。
  • 使用pandas.DataFrame.plotkind='bar'stacked=True绘制堆叠条形图最简单
    *要以矢量化方式获取百分比(无.apply):

1.使用pd.crosstab获取频率计数

  • ct沿着axis=0除以ct.sum(axis=1)
  • 使用.div.sum指定正确的轴非常重要。
  • 乘以100,四舍五入。
  • 这最好使用.crosstab来完成,因为它会产生一个具有正确形状的 Dataframe ,用于绘制堆叠的条形图。.groupby将需要对 Dataframe 进行进一步的整形。
    *python 3.10pandas 1.3.4matplotlib 3.5.0中测试
import pandas as pd
import matplotlib.pyplot as plt

# calculate the normalize value by row
ct = pd.crosstab(df['Name'], df['Subject'], normalize='index').mul(100).round(2)

# specify custom colors
pal = ["royalblue", "dodgerblue", "lightskyblue", "lightblue"]

# plot
ax = ct.plot(kind='bar', figsize=(10, 10), stacked=True, rot=0, color=pal, xlabel='Name', ylabel='Percent Distribution')

# move the legend
ax.legend(title='Subject', bbox_to_anchor=(1, 1.02), loc='upper left')

# iterate through each bar container
for c in ax.containers:

    # add the annotations
    ax.bar_label(c, fmt='%0.0f%%', label_type='center')

plt.show()

  • 使用label_type='edge'注记累积和

一米二十分

Subject  English  Mathematics  Science
Name                                  
Alisa      33.33        33.33    33.33
Bobby      33.33        33.33    33.33

相关问题