TL;DR: How to plot the result of np.histogram(..., density=True) correctly with Numpy?
Using density=True should help to match the histogram of the sample, and the density function of the underlying random variable, but it doesn't:
import numpy as np
import scipy.stats
import matplotlib.pyplot as plt
y = np.random.randn(10000)
h, bins = np.histogram(y, bins=1000, density=True)
plt.bar(bins[:-1], h)
x = np.linspace(-10, 10, 100)
f = scipy.stats.norm.pdf(x)
plt.plot(x, f, color="green")
plt.show()
Why aren't the histogram and probability density functions scaled accordingly?
In this case, an observation shows that a 1.6 scaling would be better:
plt.plot(x, 1.6 * f, color="green")
Also, this works normally:
plt.hist(y, bins=100, density=True)
Why?


TL;DR:
.bar()is too big (.hist()adjusts width internally).In
Axes.hist, bar widths are computed bynp.diff(bins)(source code). Since it allows a multi-dimensional array, there are a whole lot of validation and reshaping done behind the scenes but if we set all that aside, for a 1D array,Axes.histis just a wrapper aroundnp.histogramandAxes.barwhose (abridged) code looks like the following:On the other hand,
Axes.bariteratively addsmatplotlib.patches.Rectangleobjects to an Axes using a default width of 0.8, (source implementation), so if a bar is particularly tall and subsequent bars are short, the short ones will be hidden behind the tall ones.The following code (kind of) illustrates the points made above. The histograms are the same; for example the tallest bars are the same. Note that, in the figure below the figsize is 12"x5" and each Axes is roughly 3" wide), so given that the default dpi is 100, it can only show roughly 300 dots horizontally which means it cannot show all 1000 bars correctly. We need an appropriately wide figure to show all bars correctly.
For example, if we plot the same figure with
figsize=(60,5)(everything else the same), we get the following figure where the bars are correctly shown (in particularAxes.histandAxes.barwith adjusted widths are the same).