3

Using the following code, I've added value labels to the horizontal stacked bar plot in Matplotlib:

import pandas
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline

def sumzip(*items):
    return [sum(values) for values in zip(*items)]

fig, ax = plt.subplots(figsize=(10,6))

N = 5
values1 = [130, 120, 170, 164, 155]
values2 = [120, 185, 162, 150, 153]
values3 = [100, 170, 160, 145, 150]

ind = np.arange(N) + .15
width = 0.3

rects1 = plt.barh(ind, values1, width, color='blue') 
rects2 = plt.barh(ind, values2, width, left = sumzip(values1), color='green') 
rects3 = plt.barh(ind, values3, width, left = sumzip(values1, values2), color='red')

extra_space = 0.15
ax.set_yticks(ind+width-extra_space)
ax.set_yticklabels( ('Label1', 'Label2', 'Label3', 'Label4', 'Label5') )
ax.yaxis.set_tick_params(length=0,labelbottom=True)

for i, v in enumerate(values1):
    plt.text(v * 0.45, i + .145, str(v), color='white', fontweight='bold', fontsize=10, 
             ha='center', va='center')

for i, v in enumerate(values2):
    plt.text(v * 1.45, i + .145, str(v), color='white', fontweight='bold', fontsize=10, 
             ha='center', va='center')

for i, v in enumerate(values3):
    plt.text(v * 2.45, i + .145, str(v), color='white', fontweight='bold', fontsize=10, 
             ha='center', va='center')

ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)

plt.show()

And the code gives me the following result: enter image description here

As you can see, the labels in green and red sections are not aligned properly. What to I need to do to correct this issue?

wes_potter
  • 67
  • 5

3 Answers3

6

The factors 1.45 and 2.45 will give the desired result only when the numbers in values1, values2, values3 are all equal.

You need to do the following:

For the second bar, x = first bar value + 0.45 * second bar value

For the third bar, x = first bar value + second bar value + 0.45 * third bar value


Following is how you can do it.

# Use values1[i] + v * 0.45 as the x-coordinate
for i, v in enumerate(values2):
    plt.text(values1[i] + v * 0.45, i + .145, str(v), color='white', fontweight='bold', fontsize=10, 
             ha='center', va='center')

# Use values1[i] + values2[i] + v * 0.45 as the x-coordinate
for i, v in enumerate(values3):
    plt.text(values1[i] + values2[i] + v * 0.45, i + .145, str(v), color='white', fontweight='bold', fontsize=10, 
             ha='center', va='center')

enter image description here

Sheldore
  • 37,862
  • 7
  • 57
  • 71
4

Simply add the value from each of the previous lists with the corresponding index, like this:

for i, v in enumerate(values1):
    plt.text(v * 0.45, i + .145, str(v), color='white', fontweight='bold', fontsize=10, 
             ha='center', va='center')

for i, v in enumerate(values2):
    plt.text(v * 0.45 + values1[i], i + .145, str(v), color='white', fontweight='bold', fontsize=10, 
             ha='center', va='center')


for i, v in enumerate(values2):
    plt.text(v * 0.45 + values1[i] + values2[i], i + .145, str(v), color='white', fontweight='bold', fontsize=10, 
             ha='center', va='center')

Result:

Image

Red
  • 26,798
  • 7
  • 36
  • 58
3

I would replace all three for i,v loops with this:

for patch in ax.patches:
    x,y = patch.get_xy()
    w, h = patch.get_width(), patch.get_height()
    ax.text(x+w/2, y+h/2, str(w), 
            ha='center', va='center', 
            color='white', fontweight='bold', fontsize=10, 
           )

Output:

enter image description here

Quang Hoang
  • 146,074
  • 10
  • 56
  • 74