2

I have a subplot bar chart coded as:

axes = df.plot.bar(yerr=df1, figsize=(10,8), legend=False,
             title='Bar chart',grid=1, subplots=True, layout (5,1),xticks=None)

enter image description here

Is there an easy way to modify the code so that to see numerical values from dataframe df on the top of each bar?

UPDATE: with the code below still no values:

df = DataFrame(np.zeros((5, 3)))
df.index=['[1,3)','[3, 4)','[4, 5)','[5, 6)','[7]']
df.columns=['cat1','cat2','cat3']
df.iloc[0,:]= np.array( [0.4, 0.3, 0.2])
df.iloc[1,:]= np.array( [0, 0.1, 0.9])
df.iloc[2,:]= np.array( [0.3, 0.1, 0.3])
df.iloc[3,:]= np.array( [0, 0, 0.2])
df.iloc[4,:]= np.array( [0.0, 0, 0.9])

se_df = DataFrame(np.zeros((5, 3)))
se_df.index=['[1,3)','[3, 4)','[4, 5)','[5, 6)','[7]']
se_df.columns=['cat1','cat2','cat3']
se_df.iloc[0,:]= np.array( [0.1, 0.2, 0.002])
se_df.iloc[1,:]= np.array( [0.003, 0.02, 0.008])
se_df.iloc[2,:]= np.array( [0.006, 0.03, 0.0002])
se_df.iloc[3,:]= np.array( [0.001, 0, 0.0001])
se_df.iloc[4,:]= np.array( [0.0001, 0, 0.0002])

df1=df.transpose()
se_df1=se_df.transpose()
axes = df1.plot.bar(yerr=se_df1, figsize=(10,8), legend=False,
             title='Title',grid=1, subplots=True, layout=(5,1),xticks=None)
for n,i in enumerate(axes, 1):
            for rec, label in zip(i.patches,df.loc[:, n].astype(str)):
                height = rec.get_height()
                i.text(rec.get_x() + rec.get_width() / 2, height - 5, label,
                ha = 'center', va='bottom', color='w', weight='bold')
plt.tight_layout()

Could you please indicate what am I doing wrong?

Ekaterina
  • 189
  • 1
  • 10
  • Possible duplicate of [Annotate bars with values on Pandas bar plots](https://stackoverflow.com/questions/25447700/annotate-bars-with-values-on-pandas-bar-plots) – Andrey Portnoy Sep 10 '18 at 16:30
  • I don't think that procedure is the same for subplots? Or could you maybe give me some hints of how to apply the answer from the link? – Ekaterina Sep 10 '18 at 16:32

1 Answers1

2

Update with your new code:

df = pd.DataFrame(np.zeros((5, 3)))
df.index=['[1,3)','[3, 4)','[4, 5)','[5, 6)','[7]']
df.columns=['cat1','cat2','cat3']
df.iloc[0,:]= np.array( [0.4, 0.3, 0.2])
df.iloc[1,:]= np.array( [0, 0.1, 0.9])
df.iloc[2,:]= np.array( [0.3, 0.1, 0.3])
df.iloc[3,:]= np.array( [0, 0, 0.2])
df.iloc[4,:]= np.array( [0.0, 0, 0.9])

se_df = pd.DataFrame(np.zeros((5, 3)))
se_df.index=['[1,3)','[3, 4)','[4, 5)','[5, 6)','[7]']
se_df.columns=['cat1','cat2','cat3']
se_df.iloc[0,:]= np.array( [0.1, 0.2, 0.002])
se_df.iloc[1,:]= np.array( [0.003, 0.02, 0.008])
se_df.iloc[2,:]= np.array( [0.006, 0.03, 0.0002])
se_df.iloc[3,:]= np.array( [0.001, 0, 0.0001])
se_df.iloc[4,:]= np.array( [0.0001, 0, 0.0002])

df1=df.transpose()
se_df1=se_df.transpose()
naxes = df1.plot.bar(yerr=se_df1, figsize=(10,8), legend=False,
             title='Title',grid=1, subplots=True, layout=(5,1),xticks=None)

for n,i in enumerate(naxes, 1):
            for rec, label in zip(i[0].patches,df1.iloc[:, n-1].astype(str)):
                height = rec.get_height()
                i[0].text(rec.get_x() + rec.get_width() / 2, height * .8, label,
                ha = 'center', va='bottom', color='w', weight='bold')
plt.tight_layout()

Let's use:

np.random.seed(20)
df = pd.DataFrame({'Chart':[1,2,3,4]*3,'x':[1,2,3]*4,'y':np.random.randint(0,50,12)})

df_chart = df.set_index(['x','Chart'])['y'].unstack()
naxes = df_chart.plot.bar(subplots=True, figsize=(15,10), grid=1, yerr=df.groupby(['Chart'])['y'].transform('std'))

for n,i in enumerate(naxes, 1):
    for rec, label in zip(i.patches,df_chart.loc[:, n].astype(str)):
        height = rec.get_height()
        i.text(rec.get_x() + rec.get_width() / 2, height - 5, label,
                ha = 'center', va='bottom', color='w', weight='bold')

plt.tight_layout()

Output:

enter image description here

Scott Boston
  • 147,308
  • 15
  • 139
  • 187
  • I tried to apply your code, but still do not see the values. Could you please have a look at my code in the modified version of my question? – Ekaterina Sep 10 '18 at 19:46
  • @Ekaterina Two problems with orginal code, hardcoding for y value text placement, and hard coding for column header labelling. Managed to use iloc instead of loc and use (height * .80) instead of blindly subtracting 5. – Scott Boston Sep 10 '18 at 20:22
  • @Ekaterina Oh... and the other issue was using layout, df.plot.bar returns a 2-D array, so we have to index our selection from axes with [0] to get the first (only) element from that list inside the for loop. – Scott Boston Sep 10 '18 at 20:29
  • Great. Thanks so much! – Ekaterina Sep 10 '18 at 21:02