有没有办法用 Matplotlib 绘制具有给定 bin 宽度的直方图?

Is there a way to plot a histogram with given bin widths with Mathplotlib?

我有两个列表。 一个名为“bin_edge”,用 25 个值表示 24 个 bin 的下边界和上边界。第二个名为“counts”,表示每个 bin 的相应计数(=值)。

我的目标是,如果可能的话,得到一个 Matplotlib 直方图,它应该看起来有点像:

所以,我面临的第一个困难是第一个bin是位于bin_edge的前两个值之间的部分,第二个bin是[=11的第二个和第三个元素之间的部分=] 等等... 表示 counts 的一个值连接到 bin_edge 列表的两个边界(下限和上限)。

第二个症结:我想画对数的 x 轴和 y 轴。

我尝试的代码:

bin_edge = [0.36, 0.46, 0.66, 1.00, 1.30, 1.70, 2.20, 3.00, 4.00, 
            5.20, 6.50, 8.00, 10.00, 12.00, 14.00, 16.00, 18.00, 
            20.00, 22.00, 25.00, 28.00, 31.00, 34.00, 37.00, 40.00]

counts = [159746491, 9316595, 855578, 166092, 151198, 41293, 51051, 
          26098, 38536, 1172, 2.872e-12, 24598, 3.27097e-12, 3.86874e-12, 
          4.46613e-12, 5.06328e-12, 5.6602754e-12, 6.2571442e-12, 4.6652e-12, 
          5.26229e-12, 5.8592429e-12, 0, 7.052837e-12, 0] 

plt.hist([counts], bins=bin_edge)
plt.xscale('log')
plt.yscale('log')
plt.xlabel('Size / µm')
plt.ylabel('counts')
plt.title('Histogram')
plt.show()

这会导致一个空的情节。

当然也欢迎除 Matplotlib 之外的任何其他解决方案,包括散景:-)

因为您已经有了每个 bin 的高度,所以您应该创建一个条形图。

x-values 应该是 bin 边缘,除了最后一个。默认情况下,条形图居中;您需要 align='edge' 将它们与垃圾箱边缘对齐。条形的宽度是 bin 边缘的差异。

from matplotlib import pyplot as plt
from matplotlib.ticker import FormatStrFormatter
import numpy as np

bin_edge = [0.36, 0.46, 0.66, 1.00, 1.30, 1.70, 2.20, 3.00, 4.00,
            5.20, 6.50, 8.00, 10.00, 12.00, 14.00, 16.00, 18.00,
            20.00, 22.00, 25.00, 28.00, 31.00, 34.00, 37.00, 40.00]
counts = [159746491, 9316595, 855578, 166092, 151198, 41293, 51051,
          26098, 38536, 1172, 2.872e-12, 24598, 3.27097e-12, 3.86874e-12,
          4.46613e-12, 5.06328e-12, 5.6602754e-12, 6.2571442e-12, 4.6652e-12,
          5.26229e-12, 5.8592429e-12, 0, 7.052837e-12, 0]
fig, ax = plt.subplots(figsize=(12, 5))
ax.bar(x=bin_edge[:-1], height=counts, width=np.diff(bin_edge), align='edge', fc='MediumOrchid', ec='black')
ax.set_xscale('log')
ax.set_yscale('log')
ax.set_xlabel('Size / µm')
ax.set_ylabel('counts')
ax.set_title('Histogram')
ax.margins(x=0.01)  # less margin left and right

ax.xaxis.set_major_formatter(FormatStrFormatter('%g'))
ax.xaxis.set_minor_formatter(FormatStrFormatter('%g'))
# "length" is the length of the tick mark, it also changes the text offset
# "labelsize" is the fontsize of the tick label
ax.tick_params(axis='x', which='minor', length=5, labelsize=8)
ax.tick_params(axis='x', which='major', length=10, labelsize=12)
plt.tight_layout()
plt.show()