Tutorials

Stacked Bar Plots in Matplotlib

Stacked bar plots are useful when you want to show both the total value for each category and how that total is divided across multiple components. In Matplotlib, you can build stacked bars by plotting one series at a time and using the `bottom` argument to place each new layer on top of the previous one.

This tutorial walks through basic stacked bar charts, stacking multiple series, styling the plot, and using stacked bars for a practical reporting example.

### Basic Stacked Bar Plot

Let's start with a simple stacked bar plot using two series.

import matplotlib.pyplot as plt

# Sample data
categories = ["A", "B", "C", "D", "E"]
values1 = [10, 15, 7, 12, 9]
values2 = [5, 8, 3, 6, 4]

plt.bar(categories, values1, label="Value 1")
plt.bar(categories, values2, bottom=values1, label="Value 2")

plt.xlabel("Categories")
plt.ylabel("Values")
plt.title("Basic Stacked Bar Plot")
plt.legend()
plt.show()
- **`plt.bar(categories, values1, label="Value 1")`** draws the first layer of bars.
- **`plt.bar(categories, values2, bottom=values1, label="Value 2")`** places the second layer on top of the first one.
- **`bottom=values1`** controls where each bar segment starts.

### Stacking More Than Two Series

You can extend the same idea to stack three or more groups by keeping track of the cumulative height.

import matplotlib.pyplot as plt
import numpy as np

# Sample data
categories = ["Q1", "Q2", "Q3", "Q4"]
product_a = np.array([12, 15, 14, 18])
product_b = np.array([8, 10, 9, 11])
product_c = np.array([5, 6, 7, 6])

plt.bar(categories, product_a, label="Product A")
plt.bar(categories, product_b, bottom=product_a, label="Product B")
plt.bar(categories, product_c, bottom=product_a + product_b, label="Product C")

plt.xlabel("Quarter")
plt.ylabel("Revenue")
plt.title("Stacking Multiple Series")
plt.legend()
plt.show()
- **`bottom=product_a + product_b`** stacks the third series above the combined height of the first two.
- NumPy arrays are convenient here because element-wise addition gives the cumulative totals directly.

### Customizing Colors and Labels

Color choices and labels make stacked bar charts much easier to read, especially when several groups are involved.

import matplotlib.pyplot as plt
import numpy as np

# Sample data
months = ["Jan", "Feb", "Mar", "Apr"]
online = np.array([20, 24, 22, 26])
retail = np.array([14, 12, 16, 15])
wholesale = np.array([8, 10, 9, 11])

plt.bar(months, online, color="#4E79A7", label="Online")
plt.bar(months, retail, bottom=online, color="#F28E2B", label="Retail")
plt.bar(
    months,
    wholesale,
    bottom=online + retail,
    color="#59A14F",
    label="Wholesale",
)

plt.xlabel("Month")
plt.ylabel("Sales")
plt.title("Monthly Sales by Channel")
plt.legend(loc="upper left")
plt.grid(axis="y", linestyle="--", alpha=0.4)
plt.show()
- Distinct colors help viewers separate each segment of the stack.
- **`plt.grid(axis="y", linestyle="--", alpha=0.4)`** adds light horizontal guides so totals are easier to estimate.

### Adding Totals Above Each Stack

Stacked bars show composition well, but total values can be harder to read at a glance. Adding total labels solves that problem.

import matplotlib.pyplot as plt
import numpy as np

# Sample data
departments = ["Engineering", "Sales", "Support", "Marketing"]
men = np.array([18, 12, 9, 7])
women = np.array([14, 10, 11, 9])

totals = men + women

plt.bar(departments, men, label="Men")
plt.bar(departments, women, bottom=men, label="Women")

for i, total in enumerate(totals):
    plt.text(i, total + 0.5, str(total), ha="center")

plt.xlabel("Department")
plt.ylabel("Employees")
plt.title("Team Composition by Department")
plt.legend()
plt.show()
- **`plt.text(i, total + 0.5, str(total), ha="center")`** writes the total just above each bar.
- This is useful when you want to show both the breakdown and the final combined value.

### Practical Example: Monthly Project Hours

Here is a practical example using stacked bars to compare how project time is split across different types of work each month.

import matplotlib.pyplot as plt
import numpy as np

# Sample data
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
feature_work = np.array([42, 38, 45, 50, 47, 53])
bug_fixes = np.array([16, 18, 14, 12, 15, 11])
maintenance = np.array([10, 9, 11, 10, 9, 8])

totals = feature_work + bug_fixes + maintenance

fig, ax = plt.subplots(figsize=(9, 5))

ax.bar(months, feature_work, color="#4E79A7", label="Feature work")
ax.bar(months, bug_fixes, bottom=feature_work, color="#E15759", label="Bug fixes")
ax.bar(
    months,
    maintenance,
    bottom=feature_work + bug_fixes,
    color="#76B7B2",
    label="Maintenance",
)

for i, total in enumerate(totals):
    ax.text(i, total + 0.8, f"{total}h", ha="center")

ax.set_xlabel("Month")
ax.set_ylabel("Hours")
ax.set_title("Project Hours by Work Type")
ax.legend(loc="upper left")
ax.set_axisbelow(True)
ax.grid(axis="y", linestyle=":", alpha=0.5)

plt.show()
- This chart makes it easy to compare both the total hours per month and the share of time spent on each type of work.
- A stacked bar plot works well here because the monthly totals matter, but the composition matters too.

### Conclusion

Stacked bar plots in Matplotlib are a practical way to show totals and composition in the same chart. By combining the `bottom` parameter with good labels, legends, and optional total annotations, you can create plots that are both compact and informative.