How to do a stack chart in python, order by one category in percentage?

Viewed 39

I am trying to do a bar chart with this dataset. I've accomplished that, however, I want to do the bar chart in descendent order of percentage of "m". This is my code so far.

 cars = {'Column_1': ['A','A','C','B','D','B','C','A','C','D','D','D','B','B','D','D','D'],
            'Column_2': ['m','f','m','m','f','f','m','m','f','m','f','f','m','m','m','m','m']
            }

df = pd.DataFrame(cars, columns = ['Column_1', 'Column_2'])

df3 = df.groupby(['Column_1', 'Column_2'])['Column_1'].count().unstack('Column_2')

df3[['f','m']].plot(kind='bar', stacked=True)

enter image description here

But the way I want, B should be the first one (because 75% of its total quantity (4) is "m"), followed by A or C and finally D (because 58% of its total quantity (7) is "m". How can I do this? Is it possible also have the percentage label written on each bar?

UPDATE (SOLUTION ALMOST COMPLETE)

import pandas as pd
cars = {'Column_1': ['A','A','C','B','D','B','C','A','C','D','D','D','B','B','D','D','D'],
            'Column_2': ['m','f','m','m','f','f','m','m','f','m','f','f','m','m','m','m','m']
            }

df = pd.DataFrame(cars, columns = ['Column_1', 'Column_2'])

df3 = df.groupby(['Column_1', 'Column_2'])['Column_1'].count().unstack('Column_2')

temp_df = df3[['f','m']]
temp_df["fraction_m"] = temp_df["m"]/(temp_df["m"]+temp_df["f"])
temp_df["fraction_f"] = temp_df["f"]/(temp_df["m"]+temp_df["f"])
temp_df = temp_df.sort_values(by=["fraction_m"], ascending=True)
temp_df[["fraction_f","fraction_m"]].plot(kind='bar', stacked=True)

enter image description here

Now it is only missing the percentage label written on each bar. Anyone can help?

1 Answers

I just use a temporary data frame and add some codes to your base code.

Code

# your base code
import pandas as pd
cars = {'Column_1': ['A','A','C','B','D','B','C','A','C','D','D','D','B','B','D','D','D'],
            'Column_2': ['m','f','m','m','f','f','m','m','f','m','f','f','m','m','m','m','m']
            }

df = pd.DataFrame(cars, columns = ['Column_1', 'Column_2'])

df3 = df.groupby(['Column_1', 'Column_2'])['Column_1'].count().unstack('Column_2')
# your base code finished here,

# What I add to your code:
temp_df = df3[['f','m']]
temp_df["fraction"] = temp_df["m"]/(temp_df["m"]+temp_df["f"])
temp_df = temp_df.sort_values(by=["fraction"], ascending=False)
plot = temp_df[['f','m']].plot(kind='bar', stacked=True)
i = 0
to_annotate = temp_df["f"] + temp_df["m"]

for i in range(int(len(plot.patches)/2),len(plot.patches)):
    p = plot.patches[i]
    fraction = str(round(temp_df["fraction"][i-int(len(plot.patches)/2)] * 100)) + "%"
    annotate_height = to_annotate[i-int(len(plot.patches)/2)]
    plot.annotate(fraction, (p.get_x(), annotate_height))
    

Result

enter image description here

Related