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
- Histogram in Excel: Built-in chart, Analysis ToolPak and FREQUENCY.
- Histogram in Google Sheets: Chart editor, bucket size and outliers.
- Histogram on a TI-84: STAT PLOT, Xscl and ZoomStat.
- Histogram in Desmos: histogram(), bin width, box and dot plots.