apfhd dnwls
apfhd dnwls

Reputation: 27

python percentage label with groupby and barchart

enter image description here

enter image description here

percentage_df = df.groupby(['customer service calls', 'churn']).size().groupby(level=0).apply(
    lambda x: np.round(x * 100 / len(df), 2))

ax = percentage_df.unstack().plot(kind='bar', stacked=True, figsize=(10,10)) 
for c in ax.containers:
    ax.bar_label(c, label_type='center',color='black')

outcome :

enter image description here

Hi, I am new to python, and the below image is what I am planning to code.

  1. the bar should be the same, but percentage indicates the percentage of the certain group

  2. add % sign

  3. only shows the percentage of orange parts

#1 is the main problem I am having with.

Would you please help me on this problem? Many thanks in advance.

enter image description here

Upvotes: 1

Views: 131

Answers (1)

mrCopiCat
mrCopiCat

Reputation: 919

Is that what you want ? (I used bar containers to edit the bars data and a little of list comprehension) :

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import random

# init df:
df = pd.DataFrame({'calls':[np.random.randint(0,10) for _ in range(40)],
                   'churn': [random.choice([True, False]) for _ in range(40)]})

# preprocess the dataframe:
# true and false values calculation
true_perc = df.groupby('calls')['churn'].mean()*100
true_count = df.groupby('calls')['churn'].sum()
false_count = df.groupby('calls')['churn'].count() - df.groupby('calls')['churn'].sum()

# final df
df = pd.concat([false_count, true_count], axis=1)
df.columns = ['false_count', 'true_count']

# create plot
ax = df.plot( kind='bar', stacked=True, figsize=(10,10))

# getting the  containers values
container_t = ax.containers[1]

# create custom labels 
labels = [f'{round(val, 2)} %' if  (val != 0) else '' for val in true_perc]

# annotate with the previous custom labels
ax.bar_label(container_t, labels=labels, label_type='center', fontsize=7)

# pad the spacing between the number and the edge of the figure
ax.margins(y=0.1)

# show plot
plt.show()

output:

enter image description here

Upvotes: 1

Related Questions