英文:
How to annotate grouped bars with percent for each index
问题
ax = df.plot(kind='bar', ylabel='Number of Messages\nw/ <= 128 Characters',
             xlabel='Username', title='Discord Sentiment Analysis',
             color=['coral', 'khaki', 'skyblue'])
for p in ax.patches:
    width = p.get_width()
    height = p.get_height()
    x, y = p.get_xy() 
    ax.annotate(f'{height:.0%}', (x + width/2, y + height*1.02), ha='center')
plt.tight_layout()
plt.show()
英文:
I have created a bar plot with the following code. I would like to label the percentages adding up to ~100% for each user, as I've done in MSpaint for user1 and user2 below:

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
users = ['user1', 'user2', 'user3', 'user4', 'user5', 'user6', 'user7',\
         'user8', 'user9', 'user10', 'user11', 'user12']
NEG = [433, 1469, 1348, 2311, 522, 924, 54, 720, 317, 135, 388, 9]
NEU = [2529, 4599, 4617, 4297, 1782, 2742, 61, 2640, 1031, 404, 1723, 76]
POS = [611, 1149, 1262, 1378, 411, 382, 29, 513, 421, 101, 584, 49]
data = {'Negative': NEG, 'Neutral': NEU, 'Positive': POS}
df = pd.DataFrame(data, index=users)
ax = df.plot(kind='bar', ylabel='Number of Messages\nw/ <= 128 Characters',\
             xlabel='Username', title='Discord Sentiment Analysis',\
             color=['coral', 'khaki', 'skyblue'])
plt.tight_layout()
plt.show()
Following the advice from this thread, I've made the following attempts:
Attempt 1
ax = df.plot(kind='bar', ylabel='Number of Messages\nw/ <= 128 Characters',\
             xlabel='Username', title='Discord Sentiment Analysis',\
             color=['coral', 'khaki', 'skyblue'])
for p in ax.containers:
    ax.bar_label(p, fmt='%.1f%%', label_type='edge')`
plt.tight_layout()
plt.show()

Attempt 2
ax = df.plot(kind='bar', ylabel='Number of Messages\nw/ <= 128 Characters',\
             xlabel='Username', title='Discord Sentiment Analysis',\
             color=['coral', 'khaki', 'skyblue'])
for p in ax.patches:
    width = p.get_width()
    height = p.get_height()
    x, y = p.get_xy() 
    ax.annotate(f'{height:.0%}', (x + width/2, y + height*1.02), ha='center')
plt.tight_layout()
plt.show()

Attempt 3
ax = df.plot(kind='bar', ylabel='Number of Messages\nw/ <= 128 Characters',\
             xlabel='Username', title='Discord Sentiment Analysis',\
             color=['coral', 'khaki', 'skyblue'])
for p in ax.containers:
    ax.bar_label(p, fmt='%.1f%%', label_type='edge')
    
plt.tight_layout()
plt.show()

答案1
得分: 4
- 创建一个百分比的数据框,可用作
.bar_label的自定义标签。 - 详细说明以及
.bar_label的其他示例,请参阅如何在条形图上添加值标签。 
# 创建百分比数据框
percent = df.div(df.sum(axis=1), axis=0).mul(100).round(1)
# 绘图
ax = df.plot(kind='bar', ylabel='消息数\n(<= 128字符)',
             xlabel='用户名', title='Discord情感分析',
             color=['coral', 'khaki', 'skyblue'], width=0.9, figsize=(10, 8))
# 添加注释
for p in ax.containers:
    # 获取当前图例标签,即列名
    label = p.get_label()
    # 使用列名从百分比中访问正确的标签
    labels = percent[label].astype(str).add('%')
    # 添加条形标签
    ax.bar_label(p, labels=labels, label_type='edge', rotation=90, fontsize=10, padding=3)
# 增加数字与图表边缘之间的间距
ax.margins(y=0.1)
plt.tight_layout()
plt.show()
用于注释分组水平条形图kind='barh'的代码完全相同。
# 创建百分比数据框
percent = df.div(df.sum(axis=1), axis=0).mul(100).round(1)
# 绘图
ax = df.plot(kind='barh', ylabel='消息数\n(<= 128字符)',
             xlabel='用户名', title='Discord情感分析',
             color=['coral', 'khaki', 'skyblue'], width=0.9, figsize=(10, 8))
# 添加注释
for p in ax.containers:
    label = p.get_label()
    labels = percent[label].astype(str).add('%')
    ax.bar_label(p, labels=labels, label_type='edge', rotation=0, fontsize=10, padding=3)
# 增加数字与图表边缘之间的间距
ax.margins(x=0.1)
plt.tight_layout()
plt.show()
df
        负面情感  中性情感  正面情感
user1     433    2529    611
user2    1469    4599   1149
user3    1348    4617   1262
user4    2311    4297   1378
user5     522    1782    411
user6     924    2742    382
user7      54      61     29
user8     720    2640    513
user9     317    1031    421
user10    135     404    101
user11    388    1723    584
user12      9      76     49
percent
        负面情感  中性情感  正面情感
user1    12.1   70.8  17.1
user2    20.4   63.7  15.9
user3    18.7   63.9  17.5
user4    28.9   53.8  17.3
user5    19.2   65.6  15.1
user6    22.8   67.7   9.4
user7    37.5   42.4  20.1
user8    18.6   68.2  13.2
user9    17.9   58.3  23.8
user10   21.1   63.1  15.8
user11   14.4   63.9  21.7
user12    6.7   56.7  36.6
英文:
- Plot 
df, but create a dataframe of the percents, which can be used as customlabelsfor.bar_label. - See How to add value labels on a bar chart for a thorough explanation, and additional examples, of 
.bar_label. 
# create a dataframe of percents
percent = df.div(df.sum(axis=1), axis=0).mul(100).round(1)
# plot
ax = df.plot(kind='bar', ylabel='Number of Messages\nw/ <= 128 Characters',\
             xlabel='Username', title='Discord Sentiment Analysis',\
             color=['coral', 'khaki', 'skyblue'], width=0.9, figsize=(10, 8))
# add annotations
for p in ax.containers:
    # get the current legend label, which is the column name
    label = p.get_label()
    # use the column name to access the correct labels from percent 
    labels = percent[label].astype(str).add('%')
    # add the bar labels
    ax.bar_label(p, labels=labels, label_type='edge', rotation=90, fontsize=10, padding=3)
    
# pad the spacing between the number and the edge of the figure
ax.margins(y=0.1)
plt.tight_layout()
plt.show()
The code for annotating a grouped horizontal bar chart, kind='barh', is exactly the same.
# create a dataframe of percents
percent = df.div(df.sum(axis=1), axis=0).mul(100).round(1)
# plot
ax = df.plot(kind='barh', ylabel='Number of Messages\nw/ <= 128 Characters',\
             xlabel='Username', title='Discord Sentiment Analysis',\
             color=['coral', 'khaki', 'skyblue'], width=0.9, figsize=(10, 8))
# add annotations
for p in ax.containers:
    label = p.get_label()
    labels = percent[label].astype(str).add('%')
    ax.bar_label(p, labels=labels, label_type='edge', rotation=0, fontsize=10, padding=3)
    
# pad the spacing between the number and the edge of the figure
ax.margins(x=0.1)
plt.tight_layout()
plt.show()
df
        Negative  Neutral  Positive
user1        433     2529       611
user2       1469     4599      1149
user3       1348     4617      1262
user4       2311     4297      1378
user5        522     1782       411
user6        924     2742       382
user7         54       61        29
user8        720     2640       513
user9        317     1031       421
user10       135      404       101
user11       388     1723       584
user12         9       76        49
percent
        Negative  Neutral  Positive
user1       12.1     70.8      17.1
user2       20.4     63.7      15.9
user3       18.7     63.9      17.5
user4       28.9     53.8      17.3
user5       19.2     65.6      15.1
user6       22.8     67.7       9.4
user7       37.5     42.4      20.1
user8       18.6     68.2      13.2
user9       17.9     58.3      23.8
user10      21.1     63.1      15.8
user11      14.4     63.9      21.7
user12       6.7     56.7      36.6
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。




评论