Reputation: 417
I am trying to plot 100% stacked bar chart but i am getting wrong output. The aligned and the percentages are all messed up.
x = ["A","B","C","D"]
data1 = {'Price':[12,44,23,21]}
data2 = {'Cost':[15,40,10,15]}
data3 = {'Units':[22,12,23,15]}
y1 = pd.DataFrame(data1)
y2 = pd.DataFrame(data2)
y3 = pd.DataFrame(data3)
snum = y1['Price']+y2['Cost']+y3['Units']
y11 = y1['Price']/snum*100
y22 = y2['Cost']/snum*100
y33 = y3['Units']/snum*100
plt.figure(figsize=(4,3))
# stack bars
plt.bar(x, y11, label='y1')
plt.bar(x, y22 ,bottom=y11 ,label='y2')
plt.bar(x, y33 ,bottom=y11+y22+y33,label='y3')
for xpos, ypos, yval in zip(x, y11/2, y11):
plt.text(xpos, ypos, "%.1f"%yval, ha="center", va="center")
for xpos, ypos, yval in zip(x, y11+y22/2, y22):
plt.text(xpos, ypos, "%.1f"%yval, ha="center", va="center")
for xpos, ypos, yval in zip(x, y11+y22+y33/2, y33):
plt.text(xpos, ypos, "%.1f"%yval, ha="center", va="center")
Upvotes: 0
Views: 2597
Reputation: 80509
By bottom=y11+y22+y33
, the third bar will start at 100% and stick out. Just remove the +y33
to get the desired result.
Here is the adapted code, also with slightly different colors. If you give the edge the same color as the bar, you avoid some possible white line between them.(I also imported the libraries and added show()
.)
import pandas as pd
from matplotlib import pyplot as plt
x = ["A","B","C","D"]
data1 = {'Price':[12,44,23,21]}
data2 = {'Cost':[15,40,10,15]}
data3 = {'Units':[22,12,23,15]}
y1 = pd.DataFrame(data1)
y2 = pd.DataFrame(data2)
y3 = pd.DataFrame(data3)
snum = y1['Price']+y2['Cost']+y3['Units']
y11 = y1['Price']/snum*100
y22 = y2['Cost']/snum*100
y33 = y3['Units']/snum*100
plt.figure(figsize=(4,3))
# stack bars
plt.bar(x, y11, label='y1', color='#fbb4ae', edgecolor='#fbb4ae')
plt.bar(x, y22, bottom=y11, label='y2', color='#b3cde3', edgecolor='#b3cde3')
plt.bar(x, y33, bottom=y11+y22, label='y3', color='#ccebc5', edgecolor='#ccebc5')
for xpos, ypos, yval in zip(x, y11/2, y11):
plt.text(xpos, ypos, "%.1f"%yval, ha="center", va="center")
for xpos, ypos, yval in zip(x, y11+y22/2, y22):
plt.text(xpos, ypos, "%.1f"%yval, ha="center", va="center")
for xpos, ypos, yval in zip(x, y11+y22+y33/2, y33):
plt.text(xpos, ypos, "%.1f"%yval, ha="center", va="center")
plt.show()
Upvotes: 1