User1234098
User1234098

Reputation: 49

Add data label to grouped bar chart

I managed to find and customize some matplotlib code to create grouped bar charts. However, the code doesn't have labels at the top. I have tried several approaches, but I'm just not getting it right.

My end goal will be:

  1. Add data labels to the top of each bar
  2. Get rid of the black border around the outside and the y-axis labels

Any help (especially with #1) is greatly appreciated!

The code:

#Code adapted from:  
#https://chrisalbon.com/python/matplotlib_grouped_bar_plot.html
#matplotlib online

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


raw_data = {'plan_type': ['A1', 'A2', 'A3', 'A4', 'A5', 'A6'],
        'Group A':     [100, 0, 0, 0, 0, 0],
        'Group B':     [48, 16, 9, 22, 5, 0],
        'Group C':     [18, 28, 84, 34, 11, 0],
        'Group D': [49, 13, 7, 23, 6, 0],
        'Group E':          [57, 16, 9, 26, 3, 0]

    }
df = pd.DataFrame(raw_data, columns = ['plan_type', 'Group B', 'Group C', 'Group D', 'Group E'])


df2 =pd.DataFrame(raw_data, columns = ['plan_type', 'Group A'])



# Setting the positions and width for the bars
pos = list(range(len(df['Group B'])))
width = 0.2

# Plotting the bars
fig, ax = plt.subplots(figsize=(7, 2))


#This creates another y-axis that shares the same x-axis


# Create a bar with Group A data,
# in position pos + some width buffer,
plt.bar(pos,
    #using df['Group E'] data,
    df2['Group A'],
    # of width
    width*8,
    # with alpha 0.5
    alpha=1,
    # with color
    color='#E6E9ED',
    # with label the fourth value in plan_type
    label=df2['plan_type'][0])


# Create a bar with Group B data,
# in position pos,
plt.bar(pos,
    #using df['Group B'] data,
    df['Group B'],
    # of width
    width,
    # with alpha 1  
    alpha=1,
    # with color
    color='#900C3F',
    # with label the first value in plan_type
    label=df['plan_type'][0])

# Create a bar with Group C data,
# in position pos + some width buffer,
plt.bar([p + width for p in pos],
    #using df['Group C'] data,
    df['Group C'],
    # of width
    width,
    # with alpha 1
    alpha=1.0,
    # with color
    color='#C70039',
    # with label the second value in plan_type
    label=df['plan_type'][1])

# Create a bar with Group D data,
# in position pos + some width buffer,
plt.bar([p + width*2 for p in pos],
    #using df['Group D'] data,
    df['Group D'],
    # of width
    width,
    # with alpha 1
    alpha=1,
    # with color
    color='#FF5733',
    # with label the third value in plan_type
    label=df['plan_type'][2])

# Create a bar with Group E data,
# in position pos + some width buffer,
plt.bar([p + width*3 for p in pos],
    #using df['Group E'] data,
    df['Group E'],
    # of width
    width,
    # with alpha 1
    alpha=1,
    # with color
    color='#FFC300',
    # with label the fourth value in plan_type
    label=df['plan_type'][3])


# Set the y axis label
ax.set_ylabel('Percent')

# Set the chart's title
ax.set_title('A GRAPH - YAY!', fontweight = "bold")

# Set the position of the x ticks
ax.set_xticks([p + 1.5 * width for p in pos])

# Set the labels for the x ticks
ax.set_xticklabels(df['plan_type'])

# Setting the x-axis and y-axis limits
plt.xlim(min(pos)-width, max(pos)+width*5)
plt.ylim([0, 100] )
#plt.ylim([0, max(df['Group B'] + df['Group C'] + df['Group D'] + df['Group E'])] )

# Adding the legend and showing the plot.  Upper center location, 5 columns, 
Expanded to fit on one line.
plt.legend(['Group A','Group B', 'Group C', 'Group D', 'Group E'], loc='upper center', ncol=5, mode='expand', fontsize  ='x-small')

#plt.grid()  --> This would add a Grid, but I don't want that.

plt.show()
plt.savefig("PlanOffered.jpg")

Upvotes: 1

Views: 9564

Answers (1)

ImportanceOfBeingErnest
ImportanceOfBeingErnest

Reputation: 339220

The solution is similar to the one in this question: Adding value labels on a matplotlib bar chart

However I provide you with an example which uses your own type of plot, and thus makes it easier to understand.

The general idea in order to obtain labels on top of bars, is to iterate over the patches within the axes and annotate them with their respecticve heights.

enter image description here

I simplified the code a bit.

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

raw_data = {'plan_type': ['A1', 'A2', 'A3', 'A4', 'A5', 'A6'],
        'Group A':     [100, 0, 0, 0, 0, 0],
        'Group B':     [48, 16, 9, 22, 5, 0],
        'Group C':     [18, 28, 84, 34, 11, 0],
        'Group D': [49, 13, 7, 23, 6, 0],
        'Group E':          [57, 16, 9, 26, 3, 0]

    }
df2 =pd.DataFrame(raw_data, columns = ['plan_type', 'Group A'])
df = pd.DataFrame(raw_data, 
                  columns = ['plan_type', 'Group B', 'Group C', 'Group D', 'Group E'])

ax = df2.plot.bar(rot=0,color='#E6E9ED',width=1)
ax = df.plot.bar(rot=0, ax=ax, color=["#900C3F", '#C70039', '#FF5733', '#FFC300'], 
                 width = 0.8 )

for p in ax.patches[1:]:
    h = p.get_height()
    x = p.get_x()+p.get_width()/2.
    if h != 0:
        ax.annotate("%g" % p.get_height(), xy=(x,h), xytext=(0,4), rotation=90, 
                   textcoords="offset points", ha="center", va="bottom")

ax.set_xlim(-0.5, None)
ax.margins(y=0)
ax.legend(ncol=len(df.columns), loc="lower left", bbox_to_anchor=(0,1.02,1,0.08), 
          borderaxespad=0, mode="expand")
ax.set_xticklabels(df["plan_type"])
plt.show()

Upvotes: 3

Related Questions