How make stacked bar chart from dataframe in python

Question:

I have the following dataframe:

     Color      Level     Proportion
-------------------------------------
0     Blue          1            0.1
1     Blue          2            0.3
2     Blue          3            0.6
3      Red          1            0.2
4      Red          2            0.5
5      Red          3            0.3

Here I have 2 color categories, where each color category has 3 levels, and each entry has a proportion, which sum to 1 for each color category. I want to make a stacked bar chart from this dataframe that has 2 stacked bars, one for each color category. Within each of those stacked bars will be the proportion for each level, all summing to 1. So while the bars will be "stacked" different, the bars as complete bars will be the same length of 1.

I have tried this:

df.plot(kind='bar', stacked=True)

I then get this stacked bar chart, which is not what I want:

enter image description here

I want 2 stacked bars, and so a stacked bar for "Blue" and a stacked bar for "Red", where these bars are "stacked" by the proportions, with the colors of these stacks corresponding to each level. And so both of these bars would be of length 1 along the x-axis, which would be labelled "proportion". How can I fix my code to create this stacked bar chart?

Answers:

Make a pivot and then plot it:

df.pivot(index = 'Color', columns = 'Level', values = 'Proportion')
df.plot(kind = 'bar', stacked = True)

Edit: Cleaner legend

Answered By: Michael Cao

You could create a Seaborn sns.histplot using the proportion as weights and the level as hue:

import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd

df = pd.DataFrame({'Color': ['Blue'] * 3 + ['Red'] * 3,
                   'Level': [1, 2, 3] * 2,
                   'Proportion': [.1, .3, .6, .2, .5, .3]})
sns.set_style('white')
ax = sns.histplot(data=df, x='Color', weights='Proportion', hue='Level', multiple='stack', palette='flare', shrink=0.75)
ax.set_ylabel('Proportion')
for bars in ax.containers:
    ax.bar_label(bars, label_type='center', fmt='%.2f')
sns.move_legend(ax, loc='upper left', bbox_to_anchor=(1, 0.97))
sns.despine()
plt.tight_layout()
plt.show()

sns.histplot with weights

Answered By: JohanC