Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
matplotlib.pyplot.hist() creates a one-dimensional histogram: it groups numeric observations into intervals called bins and plots the count or weighted amount in each interval. The simplest example is:
import matplotlib.pyplot as plt
plt.hist(data)
plt.show()
For reusable or multi-panel code, prefer the equivalent object-oriented form, Axes.hist():
fig, ax = plt.subplots()
ax.hist(data, bins=20)
plt.show()
The most important choices are statistical rather than cosmetic: choose meaningful bin edges, decide whether the y-axis should show counts or density, and use the same edges when comparing datasets.
What a histogram shows
A histogram groups numeric observations into contiguous intervals and displays how much data falls into each interval. With ordinary unweighted data, each bar represents the number of observations in its bin.
#1 Best Overall
A histogram is not the same as a bar chart. Histogram bars represent numeric ranges, such as 0–10 or 10–20; a bar chart represents discrete categories, such as product names or departments. The apparent shape of a histogram also depends on its bin width and boundaries, so bins is part of the analysis—not merely a styling option.
pyplot.hist() delegates the numerical binning to NumPy’s histogram machinery and renders the result with Matplotlib artists. The current API is documented at Matplotlib’s hist() reference.
Install Matplotlib and verify the environment
Install or upgrade Matplotlib with pip:
python -m pip install -U matplotlib
With conda, use:
conda install -c conda-forge matplotlib
Check which version the active Python environment is using:
import matplotlib
print(matplotlib.__version__)
The stable documentation snapshot used for this guide is labeled Matplotlib 3.11.1. Matplotlib’s Python and NumPy requirements are release-specific, so check the current documentation and official installation guide for the version you install.
Create a basic histogram
import numpy as np
import matplotlib.pyplot as plt
rng = np.random.default_rng(42)
data = rng.normal(loc=0, scale=1, size=1_000)
plt.hist(data, bins=30, edgecolor="black")
plt.xlabel("Value")
plt.ylabel("Count")
plt.title("Distribution of values")
plt.show()
datasupplies the observations.bins=30requests 30 equal-width bins across the relevant range.edgecolor="black"separates adjacent bars visually.- The labels explain what the horizontal and vertical axes mean.
plt.show()explicitly displays the figure in scripts and many noninteractive environments. Jupyter commonly displays plots automatically, but usingshow()remains portable.
Understand the function signature
matplotlib.pyplot.hist(
x,
bins=None,
*,
range=None,
density=False,
weights=None,
cumulative=False,
bottom=None,
histtype="bar",
align="mid",
orientation="vertical",
rwidth=None,
log=False,
color=None,
label=None,
stacked=False,
data=None,
**kwargs
)
The **kwargs styling arguments are passed to the underlying bar or polygon artists. The properties accepted therefore depend partly on histtype.
Inspect the return values
hist() returns a three-item tuple:
counts, edges, artists = plt.hist(data, bins=5)
print(counts)
print(edges)
print(len(edges) - 1) # number of bins
countscontains the values plotted for each bin. These are normally counts, butdensityandweightschange their meaning.edgescontains the bin boundaries. It has one more element than the number of bins.artistscontains the Matplotlib objects used to draw the histogram.
Even ordinary unweighted counts are returned as floating-point values. With multiple datasets, the first and third return values become lists—one entry per dataset—while the bin-edge array remains shared.
Choose bins carefully
Integer bin counts
plt.hist(data, bins=10)
An integer requests that many equal-width bins over the selected range. More bins do not automatically make a histogram more accurate: too few can hide structure, while too many can make random noise look like meaningful peaks.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsExplicit bin edges
plt.hist(data, bins=[0, 1, 2, 5, 10])
A sequence supplies the edges directly and can create unequal-width bins. For edges [1, 2, 3, 4], the intervals are generally [1, 2), [2, 3), and [3, 4]: the final bin includes both endpoints.
Use domain-specific edges when thresholds have real meaning—for example, age bands, temperature ranges, or quality-control limits. For exploratory analysis, compare a few reasonable bin choices rather than trusting one setting blindly.
Rank #2
Automatic strategies
plt.hist(data, bins="auto")
Documented automatic strategies include auto, fd, doane, scott, stone, rice, sturges, and sqrt. These are useful starting points, not universal answers. The best choice depends on sample size, skew, outliers, and the question the chart must answer.
Use the same edges for comparisons
When comparing groups, independently chosen automatic bins can make the plots look different for reasons unrelated to the data. Create one edge array and pass it to every dataset:
import numpy as np
lower = min(data_a.min(), data_b.min())
upper = max(data_a.max(), data_b.max())
common_edges = np.linspace(lower, upper, 31)
plt.hist(data_a, bins=common_edges, alpha=0.5, label="Group A")
plt.hist(data_b, bins=common_edges, alpha=0.5, label="Group B")
plt.legend()
Control the plotted range
plt.hist(data, bins=20, range=(0, 100))
range sets the lower and upper limits used for binning. Values outside the interval are ignored; it is not merely a visual zoom. If outliers matter, inspect or report how many observations were excluded.
If bins is an explicit sequence, range has no effect. In either case, make sure your edges cover the observations you intend to analyze.
Counts versus density
Counts
plt.hist(data, bins=20)
plt.ylabel("Count")
Counts answer: “How many observations fall in each interval?” They are useful when the sample size itself matters.
Probability density
plt.hist(data, bins=20, density=True)
plt.ylabel("Density")
With density=True, each bin height is proportional to:
count / (total_count * bin_width)
The area of the bars integrates to approximately 1. The heights do not necessarily sum to 1, particularly when bins have unequal widths:
density_values, edges = np.histogram(data, bins=20, density=True)
area = np.sum(density_values * np.diff(edges))
print(area) # approximately 1
Use density when comparing distribution shapes or groups with different sample sizes. Never label a density axis “Count,” and do not interpret a density height as the probability of an entire bin without accounting for its width.
Density with unequal-width bins
edges = [0, 1, 2, 5, 10, 20]
fig, ax = plt.subplots()
ax.hist(data, bins=edges, density=True, edgecolor="black")
ax.set_xlabel("Value")
ax.set_ylabel("Density")
plt.show()
Unequal widths make raw bar heights especially easy to misread. For a probability-density histogram, compare areas, not just heights.
Use weights
weights = np.array([...])
plt.hist(data, bins=20, weights=weights)
Each observation contributes its corresponding weight rather than exactly one count. weights must have the same shape as x. This is useful when observations represent different amounts, such as survey weights or exposure time.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11For a weighted density histogram, the weights are normalized so the density integrates to 1 over the plotted range. Label the y-axis according to what the weights represent if the result is not an ordinary count.
Compare multiple datasets
Overlay distributions
fig, ax = plt.subplots()
ax.hist(
data_a,
bins=common_edges,
density=True,
histtype="step",
linewidth=2,
label="Group A"
)
ax.hist(
data_b,
bins=common_edges,
density=True,
histtype="step",
linewidth=2,
label="Group B"
)
ax.set_xlabel("Value")
ax.set_ylabel("Density")
ax.legend()
plt.show()
An outline histogram makes overlap easier to see than opaque bars. For filled bars, use transparency with alpha, but be cautious: overlapping colors can obscure which group is responsible for a region.
Stack or separate
plt.hist(
[data_a, data_b],
bins=common_edges,
label=["Group A", "Group B"],
stacked=True
)
plt.legend()
- Use an overlay to compare shapes.
- Use
stacked=Trueto show composition and total volume. - Use side-by-side bars for a small number of groups when direct bin-by-bin comparison is useful.
- Use separate subplots when groups have very different scales or sample sizes.
A sequence of arrays may contain datasets with different lengths. A two-dimensional NumPy array is interpreted by columns, so do not casually assume that a list of arrays and every two-dimensional representation have identical behavior.
Create cumulative histograms
plt.hist(data, bins=20, cumulative=True)
The final bin represents the total count. For a normalized cumulative distribution:
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →fig, ax = plt.subplots()
ax.hist(
data,
bins=40,
density=True,
cumulative=True,
histtype="step",
linewidth=2
)
ax.set_xlabel("Value")
ax.set_ylabel("Cumulative proportion")
ax.set_ylim(0, 1)
plt.show()
Use cumulative=-1 to accumulate from high values toward low values:
plt.hist(data, bins=20, density=True, cumulative=-1)
For this reverse-normalized form, the first bin is normalized to 1. A cumulative histogram remains affected by bin boundaries. If you want a distribution display without binning artifacts, consider Matplotlib’s current ECDF functionality.
Customize the appearance and axes
fig, ax = plt.subplots(figsize=(8, 5))
ax.hist(
data,
bins=25,
color="cornflowerblue",
edgecolor="white",
alpha=0.8,
rwidth=0.9,
label="Sample"
)
ax.set(
title="Distribution of measurements",
xlabel="Measurement",
ylabel="Frequency"
)
ax.legend()
fig.tight_layout()
plt.show()
colorsets the bar or line color.edgecolorseparates neighboring bars.alphacontrols transparency.rwidthsets the bar width as a fraction of the bin width. It is ignored forstepandstepfilled.labelsupplies legend text; calllegend()to display it.
Histogram types
plt.hist(data, histtype="bar") # ordinary bars
plt.hist(data, histtype="barstacked") # stacked bars for multiple datasets
plt.hist(data, histtype="step") # unfilled outline
plt.hist(data, histtype="stepfilled") # filled outline
bar is a good default, step is often clearest for overlays, and barstacked emphasizes composition. stepfilled can be effective for one distribution but may obscure overlaps.
Alignment and orientation
plt.hist(data, bins=10, align="left")
plt.hist(data, bins=10, align="mid")
plt.hist(data, bins=10, align="right")
The default alignment is mid. Alignment changes how bars are positioned relative to their bins, but selecting correct explicit edges is more important for statistical interpretation.
Recommended Free Tools
plt.hist(data, orientation="horizontal")
orientation="horizontal" draws a horizontal histogram, changing which axis carries the bin values and which carries the counts.
Logarithmic axes are not logarithmic data
plt.hist(data, bins=30, log=True)
log=True makes the histogram axis logarithmic; it does not transform the observations. These are different operations:
plt.hist(data, log=True) # logarithmic plotted count axis
plt.hist(np.log10(data)) # bin the log-transformed values
If you use a logarithmic x-axis or logarithmically transformed data, zero and negative values cannot be represented by the logarithm. Validate and explain how nonpositive observations are handled.
Prefer Axes.hist() for maintainable code
pyplot.hist() uses the current axes implicitly. That is convenient for quick scripts, but explicit axes are easier to manage in reusable code, dashboards, and multi-panel figures:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
import matplotlib.pyplot as plt
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))
ax1.hist(data_a, bins=20, color="steelblue")
ax1.set_title("Group A")
ax2.hist(data_b, bins=20, color="darkorange")
ax2.set_title("Group B")
fig.tight_layout()
plt.show()
The pyplot and axes methods use the same histogram concepts and parameters; the object-oriented form simply makes the destination explicit.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Plot precomputed histograms with NumPy and stairs()
Use numpy.histogram() when you need numerical counts and edges without drawing a chart:
counts, edges = np.histogram(data, bins=100)
Render those values with stairs():
fig, ax = plt.subplots()
ax.stairs(counts, edges)
ax.set_xlabel("Value")
ax.set_ylabel("Count")
plt.show()
This separates calculation from presentation and is often clearer for already-binned data. It can also be more efficient than rendering thousands of individual rectangles. Matplotlib recommends stairs() or a step-style histogram for very large bin counts; exact performance depends on the backend and plotting environment.
If you must use hist() with precomputed counts, use bin edges as the positions and counts as weights:
Free tools Windows power users keep installed
One-click scans. No signup required.
counts, edges = np.histogram(data, bins=20)
plt.hist(
edges[:-1],
bins=edges,
weights=counts
)
Do not pass bin centers as though they were raw observations without explaining the weighting. For precomputed values, stairs(counts, edges) is usually the more direct expression.
Best Value
Troubleshoot common problems
Nothing appears
- Confirm Matplotlib is installed in the same Python environment that runs the script.
- Print
matplotlib.__version__to verify the active installation. - Call
plt.show()in scripts. - Try a standalone script instead of relying on an IDE’s plotting integration.
- On a headless machine, use a noninteractive backend such as
Aggand save the output:
plt.savefig("histogram.png", dpi=150, bbox_inches="tight")
See Matplotlib’s installation and backend documentation for environment-specific issues.
The histogram has the wrong number of bins
Remember that an edge array has one more value than the number of bins. For example, five bins require six edges. Also check whether you supplied an integer, an explicit edge sequence, or an automatic strategy.
Outliers disappeared
Check range and explicit bin edges. Values outside the selected interval are excluded from the histogram, not merely hidden by the display. Compare the number of finite input values with the number represented by the bins.
The density looks wrong
Verify that the y-axis says “Density,” not “Count,” and remember that density is normalized by bin width. Check the area:
values, edges = np.histogram(data, bins=edges, density=True)
print(np.sum(values * np.diff(edges))) # approximately 1
Groups do not line up
Use one shared edge array for every dataset. Avoid plotting one group with bins="auto" and another with a separate automatic choice when the purpose is visual comparison.
The input is empty or nonfinite
Clean data explicitly when appropriate:
clean = np.asarray(data)
clean = clean[np.isfinite(clean)]
if clean.size == 0:
raise ValueError("No finite observations to plot")
plt.hist(clean, bins=20)
This is general NumPy data-cleaning practice, not a guarantee that every invalid input will produce the same behavior across Matplotlib versions. Also note that the current API documentation does not support masked arrays for hist().
The logarithmic plot fails
Check for zero or negative values before using logarithmic data or x-axis scaling. A logarithmic y-axis also cannot display zero-height bins in the same way as a linear axis, so choose the scale and treatment of empty bins deliberately.
Alternatives to pyplot.hist()
numpy.histogram(): calculate counts and edges without creating a chart.plt.stairs(): draw precomputed histograms, especially with many bins.bar(): display category counts. For labels such as product types, first count categories rather than using a numeric histogram:
categories, counts = np.unique(labels, return_counts=True)
ax.bar(categories, counts)
hist2d(): show the joint distribution of two numeric variables:
ax.hist2d(x, y, bins=30)
hexbin(): another option for dense two-dimensional numeric data:
ax.hexbin(x, y, gridsize=30)
Do not force two-dimensional data into repeated one-dimensional histograms when the relationship between variables is the question.
Quick decision guide
| Question | Recommended choice |
|---|---|
| How many observations fall in each interval? | Default counts with meaningful bins |
| How do distributions compare across unequal sample sizes? | density=True, with a clearly labeled density axis |
| How should groups be compared fairly? | One shared edge array for all groups |
| Are there meaningful domain thresholds? | Explicit, documented bin edges |
| Are there many precomputed bins? | np.histogram() followed by stairs() |
| Are the values categorical? | A counted bar chart instead of hist() |
| Do you need a cumulative distribution without bin artifacts? | Consider an ECDF |
Use pyplot.hist() for quick one-dimensional plots, but treat binning, normalization, weighting, and range selection as analytical decisions. In current code, use density rather than the obsolete historical normed parameter.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

