Grouped & Stacked Bar Charts
Grouped and stacked bar charts plot several data series in one figure — grouped bars sit side by side to compare series within each category, while stacked bars sit on top of each other to show how a total breaks into parts.
Learn Grouped & Stacked Bar Charts in our free Matplotlib course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a…
Part of the free Matplotlib course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
In this lesson you'll offset bar positions with numpy, stack series with the bottom argument, add a legend, and label every bar using ax.bar_label().
To place two series side by side, you can't reuse the same x positions — the bars would land on top of each other. Instead, build a numeric position array with np.arange() , then shift one series left and the other right by half the bar width . The category labels are added afterward with ax.set_xticks() and ax.set_xticklabels() .
What you'll see: four pairs of bars, one pair per quarter. The Online bar sits just left of center and In-Store just right, both growing toward Q4. The legend in the corner maps each color to a sales channel so you can compare them quarter by quarter.
Stacked bars share the same x position but sit on top of one another. The trick is the bottom argument: it tells each layer where to start. Draw the first series normally, then draw the second with bottom=first . For a third layer, set bottom to the running total. Because numpy arrays add element-wise, first + second gives you that total in one line.
What you'll see: four tall bars, one per month, each split into three colored segments. Rent forms a steady base, Food sits on top of it, and Fun caps each bar. The full height shows total spending, while the colored bands reveal how that total splits across categories.
Modern Matplotlib makes labeling painless. Capture the bars returned by ax.bar() , then pass that object to ax.bar_label() . It writes each bar's height just above it. For stacked charts, add label_type="center" to drop the number inside each segment.
What you'll see: three stacked bars showing wins and losses per team. The win count sits centered in the lower segment, the loss count centered in the upper one, and the season total floats just above each bar — no manual text positioning required.
Replace each ___ to draw two series side by side and label one of them.
You drew both series at the same x. Offset them: x - width/2 and x + width/2 with a width below 0.5.
You forgot bottom= . Each higher layer needs bottom set to the running total below it.
Plain lists concatenate, not add. Wrap your data in np.array(...) so a + b adds element-wise.
Plot survey results for three answers across four products as grouped bars, label every bar, and add a legend.
Lesson complete — you can plot multiple series in one chart!
You offset positions with numpy to draw grouped bars, stacked series with the bottom argument, added legends, and labeled every bar automatically with ax.bar_label().
🚀 Up next: Error Bars & Bands — show uncertainty around your values.
Practice quiz
To draw two series side by side, you first build numeric positions with...
- np.zeros()
- np.arange(len(categories))
- range(0)
- np.fill()
Answer: np.arange(len(categories)). np.arange(len(categories)) gives positions 0, 1, 2, ... to offset bars from.
How do you offset two grouped bars around each position x with width w?
- x and x
- x - w/2 and x + w/2
- x*2 and x/2
- x + w and x + w
Answer: x - w/2 and x + w/2. Draw one series at x - width/2 and the other at x + width/2 so they sit side by side.
Which argument stacks one bar series on top of another?
- stack=True
- top=
- bottom=
- base=
Answer: bottom=. bottom= tells each layer where to start, stacking it on the series below.
For a third stacked layer, what should bottom be set to?
- 0
- Just the first layer
- The running total of the layers below
- The largest value
Answer: The running total of the layers below. Set bottom to the running total (layer1 + layer2) so the third layer sits on top.
Why use np.array instead of plain lists for stacked data?
- Lists are slower to plot
- Arrays add element-wise; lists would concatenate
- Arrays are required by ax.bar()
- Lists cannot hold numbers
Answer: Arrays add element-wise; lists would concatenate. np.array lets rent + food add element-wise; plain lists would concatenate instead.
Which method automatically labels each bar with its value?
- ax.bar_label(bars)
- ax.annotate_all()
- ax.label_bars()
- ax.text_bars()
Answer: ax.bar_label(bars). ax.bar_label(bars) writes each bar's height just above it.
What does label_type='center' do in ax.bar_label()?
- Centers the chart
- Puts the label inside the bar
- Centers the legend
- Removes the label
Answer: Puts the label inside the bar. label_type='center' drops the value inside each bar, handy for stacked charts.
After offsetting grouped bars, how do you restore the category names on the x-axis?
- ax.set_xticks(x) then ax.set_xticklabels(categories)
- ax.rename(categories)
- ax.categories = ...
- ax.set_labels()
Answer: ax.set_xticks(x) then ax.set_xticklabels(categories). Set the ticks to x, then set their labels to the category names.
Which keeps grouped bars from touching for two bars per group?
- width above 1.0
- width of 0.4 (group total under 1.0)
- width of 1.5
- width of 0
Answer: width of 0.4 (group total under 1.0). Keep the group's total width under 1.0; for two bars a width of 0.4 leaves a clean gap.
When should you choose STACKED bars over grouped bars?
- To compare series against each other in each category
- To show a total and how it breaks into parts
- To plot a single series
- To show uncertainty
Answer: To show a total and how it breaks into parts. Stacked bars show each category's total and its breakdown; grouped bars compare series.