Tutorial

How to Make a Histogram in Python

Last updated: October 16, 2026

Short on time? Paste your numbers into our free histogram maker and download a finished chart in under a minute, with no software and no formulas.

Matplotlib: plt.hist

import matplotlib.pyplot as plt

scores = [52, 58, 61, 64, 64, 67, 69, 70, 71, 73, 75, 75, 76, 78, 80, 82, 85, 88, 91, 94]

plt.hist(scores, bins=8, edgecolor="white", color="#2563eb")
plt.title("Exam Scores")
plt.xlabel("Score")
plt.ylabel("Frequency")
plt.savefig("histogram.png", dpi=200, bbox_inches="tight")
plt.show()

Choosing the bins

  • bins=8: eight equal-width bins between the minimum and maximum.
  • bins=range(50, 101, 10): exact edges 50, 60, …, 100 (bin width 10).
  • bins="auto", "sturges", "fd" (Freedman–Diaconis), "scott", "sqrt", "rice": let NumPy apply a rule.

Every bin includes its left edge and excludes its right edge, except the last bin, which includes both. So with edges 50, 60, 70, a score of 60 is counted in 60–70.

Useful options

  • density=True: scale the bars so the total area is 1 (needed to overlay a probability curve).
  • cumulative=True: a cumulative histogram.
  • alpha=0.5: transparency, for overlapping histograms.
  • histtype="step": outlines only, which makes several groups easier to compare.

Comparing two groups

bins = range(40, 101, 5)
plt.hist(class_a, bins=bins, alpha=0.6, label="Class A")
plt.hist(class_b, bins=bins, alpha=0.6, label="Class B")
plt.legend()
plt.show()

Always pass the same bins to both groups, or the bars won’t line up and the comparison is misleading.

pandas

import pandas as pd

df = pd.read_csv("scores.csv")
df["score"].plot.hist(bins=10, edgecolor="white")
# or a grid of histograms, one per numeric column:
df.hist(bins=10)

seaborn: histplot with a smooth curve

import seaborn as sns

sns.histplot(data=df, x="score", bins=10, kde=True)        # add a KDE curve
sns.histplot(data=df, x="score", hue="class", stat="percent", common_norm=False)

stat can be "count", "frequency", "probability", "percent" or "density". With common_norm=False, each group is normalized separately, so groups of different sizes can be compared fairly.

NumPy: just the counts

import numpy as np

counts, edges = np.histogram(scores, bins=range(50, 101, 10))
for lo, hi, c in zip(edges[:-1], edges[1:], counts):
    print(f"{lo}-{hi}: {c}")

This gives you the frequency table without drawing anything. It’s handy for checking results or exporting to a spreadsheet.

No Python handy?

For a one-off chart, paste the same numbers into the histogram maker. It uses the same bin rules (Sturges, Scott, Freedman–Diaconis), adds a normal curve and frequency table, and exports PNG, SVG or PDF.

Other tutorials

Make your own histogram

Paste your numbers and get a histogram, frequency table and summary statistics in seconds. Free, no sign-up.

Open the Histogram Maker