Home > Software design >  How to label bars with multiple custom values
How to label bars with multiple custom values

Time:07-19

I have this dataframe

rules count    percentage    groups   weight

A      15      24%            1       10
B      5       2%             2       30
C      25      50%            3       50

I have the following code:

sns.set(rc={'figure.figsize':(18,9.5)})
plots = sns.barplot(x="rules", y="count", data=df, hue=df['groups'], dodge=False)
percentage = df['percentage'].tolist()
weight = df['weight'].tolist()
patches = plots.patches
for i in range(len(patches)):
   x = patches[i].get_x()   patches[i].get_width()/2
   y = patches[i].get_height() .09
   plots.annotate('{:.1f}%'.format(percentage[i]), (x, y), ha='center',  va='bottom', size=14)
   plots.annotate('{:.0f}'.format(weight[i]), (x, y), ha='center', va='top', color='white', size=15, fontweight="bold")

and I get the following error when trying to annotate the barchart with the percentage.

Inside the barchart is another number corresponding to the weight column in the df.

IndexError                                Traceback (most recent call last)
<ipython-input-120-0ef14f891711> in <module>()
      7    x = patches[i].get_x()   patches[i].get_width()/2
      8    y = patches[i].get_height() .09
----> 9    plots.annotate('{:.1f}%'.format(percentage[i]), (x, y), ha='center',  va='bottom', size=14)
     10    plots.annotate('{:.0f}'.format(weight[i]), (x, y), ha='center', va='top', color='white', size=15, fontweight="bold")
     11 plots.set_xticklabels(plots.get_xticklabels(), rotation=90, fontsize=15)

IndexError: list index out of range

CodePudding user response:

  • As of enter image description here


    • Annotation with two custom labels ('weight' and 'percentage').
    ax = sns.barplot(x="rules", y="count", data=df, hue='groups', dodge=False)
    
    # since you are using hue, there are multiple containers
    for c in ax.containers:
        # add an annotations with custom labels
        ax.bar_label(c, labels=df.weight, label_type='center')
        # add an annotations with custom labels
        ax.bar_label(c, labels=df.percentage, label_type='edge', padding=1)
        
    ax.margins(y=0.1)
    

    enter image description here


    • The issue with the existing code is there are 9 patches, as can be seen with print(patches) or list(patches), which can be resolved by selecting only the patches with a height greater than 0.
      • This occurs because hue is being used, but there is only one value in 'groups' for each value in 'rules'.
    plots = sns.barplot(x="rules", y="count", data=df, hue=df['groups'], dodge=False)
    percentage = df['percentage'].tolist()
    weight = df['weight'].tolist()
    patches = plots.patches
    
    # select patches with a height > 0
    patches = [p for p in patches if p.get_height() > 0]
    
    for i, p in enumerate(patches):
        
        x = p.get_x()   patches[i].get_width()/2
        y = p.get_height() .09
        
        plots.annotate(f'{percentage[i]}', (x, y), ha='center',  va='bottom', size=14)
        plots.annotate(f'{weight[i]:.0f}', (x, y), ha='center', va='top', color='white', size=15, fontweight="bold")
    

    enter image description here

  • Related