Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Annotate values for stacked horizontal bar in pandas

I'm trying to annotate the values for a stacked horizontal bar graph created using pandas. Current code is below

import pandas as pd 
import matplotlib.pyplot as plt
import numpy as np

d = {'group 1': [1, 2, 5, 7, 4, 5, 10],
     'group 2': [5, 6, 1, 8, 2, 6, 2],
     'group 3': [12, 2, 2, 4, 4, 8, 4]}
df = pd.DataFrame(d)

ax = df.plot.barh(stacked=True, figsize=(10,12))

for p in ax.patches:
    ax.annotate(str(p.get_x()), xy=(p.get_x(), p.get_y()+0.2))

plt.legend(bbox_to_anchor=(0, -0.15), loc=3, prop={'size': 14}, frameon=False)

The problem is the annotation method I used gives the x starting points and not the values of each segment. I'd like to be able to annotate values of each segment in the center of each segment for each of the bars.

example

edit: for clarity, what I would like to achieve is something like this where the values are centered horizontally (and vertically) for each segment:

enter image description here

like image 972
at1623 Avatar asked Dec 24 '18 03:12

at1623


2 Answers

You can use the patches bbox to get the information you want.

ax = df.plot.barh(stacked=True, figsize=(10, 12))
for p in ax.patches:
    left, bottom, width, height = p.get_bbox().bounds
    ax.annotate(str(width), xy=(left+width/2, bottom+height/2), 
                ha='center', va='center')

enter image description here

like image 108
James Avatar answered Nov 05 '22 01:11

James


Another possible solution is to get your df.values to a flatten array via values = df.values.flatten("F")

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

d = {'group 1': [1, 2, 5, 7, 4, 5, 10],
     'group 2': [5, 6, 1, 8, 2, 6, 2],
     'group 3': [12, 2, 2, 4, 4, 8, 4]}
df = pd.DataFrame(d)

ax = df.plot.barh(stacked=True, figsize=(10,12))

values = df.values.flatten("F")

for i, p in enumerate(ax.patches):
    ax.annotate(str(values[i]), xy=(p.get_x()+ values[i]/2, p.get_y()+0.2))

plt.legend(bbox_to_anchor=(0, -0.15), loc=3, prop={'size': 14}, frameon=False);

enter image description here

like image 39
rpanai Avatar answered Nov 05 '22 01:11

rpanai