How to plot a histogram with unequal bin widths in Matplotlib (with Code)
The Short Answer (TL;DR)
Pass increasing bin edges to hist and use density=True when bar areas should represent proportions. With unequal widths, compare areas rather than interpreting bar heights as probabilities.
import matplotlib.pyplot as plt
values = [0.2, 0.8, 1.2, 1.7, 2.4, 3.6]; edges = [0, 1, 2, 4]
plt.hist(values, bins=edges, density=True, edgecolor="white")
Detailed Implementation
This example uses synthetic data and does not need a network connection. Install the recorded package versions in a separate Python environment before running it.
python -m pip install numpy==2.5.4 pandas==3.0.6 matplotlib==3.11.2 seaborn==0.13.2
import numpy as np
import matplotlib.pyplot as plt
values = np.array([0.2, 0.8, 1.2, 1.7, 2.4, 3.6])
edges = np.array([0.0, 1.0, 2.0, 4.0])
fig, ax = plt.subplots(figsize=(5.8, 3.6), layout="constrained")
density, used_edges, bars = ax.hist(values, bins=edges, density=True,
color="#176b87", edgecolor="white")
widths = np.diff(used_edges)
areas = density * widths
for bar, area in zip(bars, areas):
ax.text(bar.get_x() + bar.get_width() / 2, bar.get_height(),
f"area = {area:.3f}", ha="center", va="bottom")
ax.set(xlabel="Synthetic measurement", ylabel="Probability density",
title="Unequal bin widths; equal probability areas", ylim=(0, 0.42))
fig.savefig("unequal-bin-histogram.png", dpi=160)
plt.show()
The three bars have equal areas of one third. The last bar spans twice the width and has half the height of either of the first two bars.
Why is the widest bar shorter?
Each bin contains two of the six observations. The last bin is twice as wide, so its density is half as high while its area remains one third.
How are bin boundaries handled?
Bins include the left edge and exclude the right edge, except the last bin, which includes both endpoints. Supply strictly increasing edges and inspect missing or nonfinite values before plotting.
What if the edges exclude observations?
Values outside the supplied edges are not counted. Density normalization then uses the observations inside the plotted range. Report any exclusions; the resulting areas describe the retained observations.
Mathematical Context
For an unweighted histogram, let c_j be a bin count, N the total count inside the chosen edges and w_j its width. The density height is h_j = c_j/(N w_j), so its area h_j w_j = c_j/N. Here N=6 and each count is 2: widths 1, 1 and 2 give heights 1/3, 1/3 and 1/6. Density heights do not generally sum to one.
\[ h_j=\frac{c_j}{Nw_j},\qquad \sum_j h_jw_j=1 \]
Reproducibility
Executed with Python 3.12.14; numpy 2.5.4, pandas 3.0.6, matplotlib 3.11.2, seaborn 0.13.2. Automated checks confirm the stated output properties.