A Matplotlib stacked bar chart problem usually comes from one of three causes: the upper layers have no correct bottom value, the arrays passed to bar() do not line up, or the data contains gaps, negative numbers, or pandas index issues. Each cause looks different on screen, so identify the symptom first and then apply the matching fix below.
How Matplotlib stacks bars
Matplotlib has no built-in “stacked” option in matplotlib.pyplot.bar. Instead, you draw each layer as its own call and tell it where the bottom edge of each bar sits. The bottom parameter is documented as the y coordinate of the bottom side of each bar, and its default is zero. A stack therefore works only when every layer after the first starts at the running total of the layers beneath it. The matplotlib.pyplot.bar API reference describes these parameters, including the fact that x, height, and bottom can be scalars or sequences with one value per bar.
As an Amazon Associate I earn from qualifying purchases.
The official two-layer example in the Matplotlib 3.6.2 “Stacked bar chart” gallery page shows the core idea: the second series uses the first series’ values as its bottom. With three or more layers, the bottom must be the sum of all earlier layers, computed bar by bar.
Identify which problem you have
The table below maps common symptoms to their likely causes. The exact exception text differs between Matplotlib versions, so treat the symptom column as the more reliable guide.
#1 Best Overall
| Symptom | Likely cause | Where to go |
|---|---|---|
| Code runs, but bars sit side by side or overlap at the baseline | Later layers have no bottom, or a repeated zero baseline |
Fix 1 |
| Code runs, but upper layers are too tall or misplaced | Bottom uses the individual values of the previous layer instead of the running total | Fix 1 |
| Exception mentioning shape, sizes, or broadcasting | An array length differs from x or from the other layers |
Fix 2 |
| Missing segments, gaps, or segments in the wrong category | NaN values, pandas index alignment, or categories in a different order | Fix 3 |
| Bars extend below zero in an unexpected way | Negative values are stacked with the positive running total | Fix 4 |
Fix 1: Bars overlap or the stack height is wrong
This is the most common “stacked bar chart error,” and it does not raise an exception. If every call uses the default bottom, each series is drawn from zero and the bars overlap. If you pass the previous layer’s values but not the sum of all earlier layers, the third and later layers will look too short.
The corrected three-layer version looks like this:
import matplotlib.pyplot as plt
labels = ["A", "B", "C"]
first = [2, 3, 4]
second = [1, 2, 1]
third = [3, 1, 2]
fig, ax = plt.subplots()
ax.bar(labels, first, label="First")
ax.bar(labels, second, bottom=first, label="Second")
ax.bar(labels, third,
bottom=[a + b for a, b in zip(first, second)],
label="Third")
ax.legend()
plt.show()
The first two layers follow the official pattern. The third layer applies the same rule: its bottom is the element-by-element sum of the layers below it.
Rank #2
Fix 2: Shape or length mismatch
When a call raises an exception, the message usually refers to shapes, sizes, or broadcasting. The wording changes between versions, but the cause is almost always that one array does not match the number of bars. Work through these checks in order:
- Read the full traceback and note which
ax.bar()line raised the error. - Print the length of
xand of everyheightandbottomarray used in that call. They must all be the same length, or be scalars. - Confirm the order. Each layer must list its values in the same category order as
x. A list sorted differently from the labels will stack in the wrong place without raising an error. - If you build bottoms with
zip(), remember thatzip()silently stops at the shortest input. A mismatched list is truncated rather than reported, so compare the lengths explicitly before zipping.
A reusable loop that avoids most shape errors
Accumulating the bottom in a loop keeps the running total in one place and makes length checks easy to add:
import numpy as np
import matplotlib.pyplot as plt
labels = ["A", "B", "C"]
layers = {
"First": [2, 3, 4],
"Second": [1, 2, 1],
"Third": [3, 1, 2],
}
n = len(labels)
for name, values in layers.items():
if len(values) != n:
raise ValueError(f"{name} has {len(values)} values; expected {n}")
fig, ax = plt.subplots()
bottom = np.zeros(n)
for name, values in layers.items():
values = np.asarray(values, dtype=float)
ax.bar(labels, values, bottom=bottom, label=name)
bottom = bottom + values # new array, so earlier bars are not affected
ax.legend()
plt.show()
The explicit length check fails with a clear message at the layer that is wrong, rather than a generic error from inside bar().
Fix 3: Gaps, NaN values, and pandas data
If your data comes from a DataFrame, several issues can produce a chart that looks stacked but is wrong.
- NaN values: A missing value in a layer leaves a gap, and any bottom computed from it becomes NaN, which can hide the bars above it. Decide whether missing values should be zero with
fillna(0), or whether the chart should skip them, and handle them before building the bottoms. - Index alignment: Matplotlib works with the numbers you pass in by position. If you pass a pandas Series as
bottomwhose index is in a different order from the category labels, the bars will not match the labels. Convert with.to_numpy()after sorting both the labels and the data into the same order. - Numeric versus string categories: If some labels are numbers and others are strings, Matplotlib may place them on different axes. Convert all category labels to strings before plotting.
If you only need a stacked chart from a DataFrame, pandas’ own DataFrame.plot(kind="bar", stacked=True) computes the bottoms for you. It is a reasonable alternative when your data is already in wide format, but the manual approach above gives you finer control over each layer.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Fix 4: Negative values
A simple running sum mixes positive and negative numbers. A negative value in an early layer lowers the bottom of the layers above it, so a positive segment can appear to sit below zero. To keep positive and negative stacks separate, track two running totals: one that adds only positive values, and one that adds only negative values. Each positive segment starts at the positive total, and each negative segment starts at the negative total.
Best Value
import numpy as np
import matplotlib.pyplot as plt
labels = ["A", "B", "C"]
layers = {
"Gain": np.array([2.0, 3.0, 1.0]),
"Loss": np.array([-1.0, -2.0, -0.5]),
}
pos_bottom = np.zeros(len(labels))
neg_bottom = np.zeros(len(labels))
fig, ax = plt.subplots()
for name, values in layers.items():
pos = np.where(values >= 0, values, 0.0)
neg = np.where(values < 0, values, 0.0)
ax.bar(labels, pos, bottom=pos_bottom, label=name)
ax.bar(labels, neg, bottom=neg_bottom, label=name)
pos_bottom = pos_bottom + pos
neg_bottom = neg_bottom + neg
ax.axhline(0, color="black", linewidth=0.8)
ax.legend()
plt.show()
The second bar() call for each layer is drawn in the same colour and label, so the legend may show the name twice. Remove the duplicate with ax.legend() after deduplicating the handles, or assign a separate label to the negative call and accept two legend entries.
When asking for help, include these details
If none of the fixes above matches your situation, a question on a forum or issue tracker will get a faster answer when it includes:
- The full traceback, copied as text rather than as a screenshot.
- The
bar()call that raised the error, plus the lengths ofx, eachheight, and eachbottom. - A small data example, five or fewer categories, that reproduces the problem.
- Your Matplotlib version, printed with
python -c "import matplotlib; print(matplotlib.__version__)". - Whether the chart is built with
pyplotor with the object-orientedfig, axinterface, because the two can behave differently when multiple figures are open.
Matplotlib's stacking behaviour is stable across the versions covered by the documentation linked above. The version number matters most when you are reading error text, since messages about array shapes change wording between releases.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




