0

I have data displayed in the following format:

values = np.array([10, 12,13, 5,20], [30, 7, 10, 25,2], [10, 12,13, 5,20]])

And I want to create a straight-up stacked bar chart like the following figure. Each element in the array belongs to a stacked bar.

enter image description here

I have searched to see how can I do this with matplotlib, but unfortunately, I still haven't found a way to do it. How can I do this?

xeon123
  • 819
  • 1
  • 10
  • 25
  • Does this answer your question? [How to annotate a stacked bar chart with word count and column name?](https://stackoverflow.com/questions/62239435/how-to-annotate-a-stacked-bar-chart-with-word-count-and-column-name) – Trenton McKinney Aug 29 '20 at 01:24
  • [Stacked Bar Chart with Centered Labels](https://stackoverflow.com/questions/41296313) & [How to annotate a pandas stacked bar, with more than 2 stacks?](https://stackoverflow.com/questions/60875468) – Trenton McKinney Aug 29 '20 at 01:26

2 Answers2

0

AFAIK, there is now straightforward way to do it. You need to calculate exact position of bars yourself and then normalize it.

import numpy as np
import matplotlib.pyplot as plt

values = np.array([[10, 12,13, 5,20], [30, 7, 10, 25,2], [10, 12,13, 5,20]])
values_normalized = values/np.sum(values, axis=0)
bottom_values = np.cumsum(values_normalized, axis=0)
bottom_values = np.vstack([np.zeros(values_normalized[0].size), bottom_values])
text_positions = (bottom_values[1:] + bottom_values[:-1])/2
r = [0, 1, 2, 3, 4] # position of the bars on the x-axis
names = ['A', 'B', 'C', 'D', 'E'] # names of groups
colors = ['lightblue', 'orange', 'lightgreen']
for i in range(3):
    plt.bar(r, values_normalized[i], bottom=bottom_values[i], color=colors[i], edgecolor='white', width=1, tick_label=['a','b','c','d','e'])
    for xpos, ypos, yval in zip(r, text_positions[i], values[i]):
        plt.text(xpos, ypos, "N=%d"%yval, ha="center", va="center")
    # Custom X axis
plt.xticks(r, names, fontweight='bold')
plt.xlabel("group")
plt.show()

There is a source that tells how to add text on top of bars. I'm a bit in a hurry right now so I hope this is useful and I'll update my answer next day if needed.

I've updated my answer. Adding text on top of the bars is tricky, it requires some calculations of their vertical positions.

Btw, I have refactored the most of code that is in a link I shared.

enter image description here

mathfux
  • 5,759
  • 1
  • 14
  • 34
0
  • Python 3.8
  • matplotlib 3.3.1
  • numpy 1.19.1

Chat Result

import matplotlib.pyplot as plt
import numpy as np

values = np.array([[10, 12, 13, 5, 20], [30, 7, 10, 25, 2], [10, 12, 13, 5, 20]])
row, column = values.shape  # (3, 5)

x_type = [x+1 for x in range(column)]
ind = [x for x, _ in enumerate(x_type)]

values_normalized = values/np.sum(values, axis=0)
value1, value2, value3 = values_normalized[0,:], values_normalized[1,:], values_normalized[2,:]

# Create figure
plt.figure(figsize=(8, 6))
plt.bar(ind, value1, width=0.8, label='Searies1', color='#5B9BD5')
plt.bar(ind, value2, width=0.8, label='Searies2', color='#C00000', bottom=value1)
plt.bar(ind, value3, width=0.8, label='Searies3', color='#70AD47', bottom=value1 + value2)

# Show text
bottom_values = np.cumsum(values_normalized, axis=0)
bottom_values = np.vstack([np.zeros(values_normalized[0].size), bottom_values])
text_positions = (bottom_values[1:] + bottom_values[:-1])/2
c = list(range(column))
for i in range(3):
    for xpos, ypos, yval in zip(c, text_positions[i], values[i]):
        plt.text(xpos, ypos, yval, horizontalalignment='center', verticalalignment='center', color='white')

plt.xticks(ind, x_type)
plt.legend(loc='center', bbox_to_anchor=(0, 1.02, 1, 0.1), handlelength=1, handleheight=1, ncol=row)
plt.title('CHART TITLE', fontdict = {'fontsize': 16,'fontweight': 'bold', 'family': 'serif'}, y=1.1)

# Hide y-axis
plt.gca().axes.yaxis.set_visible(False)

plt.show()
Leo
  • 1
  • 1