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

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

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

df, but create a dataframe of the percents, which can be used as custom labels for .bar_label..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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With