Bar charts and histograms

Matplotlib · Essentials · 10 min

Bars and histograms answer the two most common questions about data: how do groups compare, and how are values spread?

A bar chart compares a number across categories. ax.bar(categories, heights) accepts strings directly as x positions, and ax.barh draws horizontal bars, which are easier to read when category names are long. Useful options: width=, color=, edgecolor=, and bottom= to stack one series on top of another.

Grouped bars need a little arithmetic: plot each series at x - w/2 and x + w/2 where x = np.arange(n), then set the tick labels to the category names.

A histogram is different: it takes raw values, cuts their range into bins and counts how many fall in each. ax.hist(values, bins=30) returns three things: the counts, the bin edges (one more than the counts) and the bar patches.

  • bins can be an integer, an explicit list of edges, or a rule such as "auto".
  • density=True rescales so the bars' total area is 1, which lets you compare samples of different sizes.
  • histtype="step" draws outlines, good for overlaying two distributions.

The number of bins changes the story a histogram tells: too few hides structure, too many shows noise. Try a few values before drawing conclusions.

Bars encode values by length, so the value axis of a bar chart should start at zero; a truncated axis exaggerates differences. Matplotlib does this by default for bars.

Example

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(9, 3.5))

langs = ["Python", "Go", "Rust"]
ax1.bar(langs, [42, 18, 12], color="tab:blue")
ax1.set_ylabel("Projects")

rng = np.random.default_rng(1)
values = rng.normal(loc=170, scale=8, size=1000)
counts, edges, patches = ax2.hist(values, bins=20, edgecolor="white")

print(len(counts), len(edges))       # 20 21
print(int(counts.sum()))             # 1000
print(ax1.get_ylim()[0])             # 0.0 (bars start at zero)
fig.savefig("bars.png")

Remember

  • bar/barh compare categories; strings work as x positions
  • hist bins raw values and returns counts, edges and patches
  • Try several bin counts; use density=True to compare different-sized samples

Watch out for

  • Passing already-counted data to hist; use bar for counts you computed yourself.

Check yourself

  1. `counts, edges, _ = ax.hist(data, bins=10)`. How many values does `edges` hold?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.hist.html