Stacked Bar Chart with Centered Labels
- The following method is more succinct, and more easily scales with more columns.
- Putting the data into a
pandas.DataFrame
is the easiest way to plot a stacked bar plot. - Using
pandas.DataFrame.plot.bar(stacked=True)
is the easiest way to plot a stacked bar plot.- This method returns a
matplotlib.axes.Axes
or anumpy.ndarray
of them.
- This method returns a
- Since
seaborn
is just a high-level API formatplotlib
, these solutions also work withseaborn
plots, as shown in How to annotate a seaborn barplot with the aggregated value
Imports & Test DataFrame
import pandas as pdimport matplotlib.pyplot as pltA = [45, 17, 47]B = [91, 70, 72]C = [68, 43, 13]# pandas dataframedf = pd.DataFrame(data={'A': A, 'B': B, 'C': C})df.index = ['C1', 'C2', 'C3'] A B CC1 45 91 68C2 17 70 43C3 47 72 13
Updated for matplotlib v3.4.2
- Use
matplotlib.pyplot.bar_label
- Will automatically center the values in the bar.
- See this answer for additional details about
.bar_label()
- See the matplotlib: Bar Label Demo page for additional formatting options.
- Tested with
pandas v1.2.4
, which is usingmatplotlib
as the plot engine. - If some sections of the bar plot will be zero, see my answer, which shows how to customize the
labels
for.bar_label()
. ax.bar_label(c, fmt='%0.0f', label_type='center')
will change the number format to show no decimal places, if needed.
ax = df.plot(kind='bar', stacked=True, figsize=(8, 6), rot=0, xlabel='Class', ylabel='Count')for c in ax.containers: # Optional: if the segment is small or 0, customize the labels labels = [v.get_height() if v.get_height() > 0 else '' for v in c] # remove the labels parameter if it's not needed for customized labels ax.bar_label(c, labels=labels, label_type='center')
Annotation Resources - from matplotlib v3.4.2
- Adding value labels on a matplotlib bar chart
- How to annotate each segment of a stacked bar chart
- How to plot and annotate multiple data columns in a seaborn barplot
- How to annotate a seaborn barplot with the aggregated value
- stack bar plot in matplotlib and add label to each section
- How to add multiple annotations to a barplot
- How to plot and annotate a grouped bar chart
Original Answer
- Using the
.patches
method unpacks a list ofmatplotlib.patches.Rectangle
objects, one for each of the sections of the stacked bar.- Each
.Rectangle
has methods for extracting the various values that define the rectangle. - Each
.Rectangle
is in order from left to right, and bottom to top, so all the.Rectangle
objects, for each level, appear in order, when iterating through.patches
.
- Each
- The labels are made using an f-string,
label_text = f'{height}'
, so any additional text can be added as needed, such aslabel_text = f'{height}%'
label_text = f'{height:0.0f}'
will display numbers with no decimal places.
Plot
plt.style.use('ggplot')ax = df.plot(stacked=True, kind='bar', figsize=(12, 8), rot='horizontal')# .patches is everything inside of the chartfor rect in ax.patches: # Find where everything is located height = rect.get_height() width = rect.get_width() x = rect.get_x() y = rect.get_y() # The height of the bar is the data value and can be used as the label label_text = f'{height}' # f'{height:.2f}' to format decimal values # ax.text(x, y, text) label_x = x + width / 2 label_y = y + height / 2 # plot only when height is greater than specified value if height > 0: ax.text(label_x, label_y, label_text, ha='center', va='center', fontsize=8) ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0.) ax.set_ylabel("Count", fontsize=18)ax.set_xlabel("Class", fontsize=18)plt.show()
- To plot a horizontal bar:
kind='barh'
label_text = f'{width}'
if width > 0:
- Attribution: jsoma/chart.py