matplotlib 中的自定义直方图归一化
Custom Histogram Normalization in matplotlib
我正在尝试在 matplotlib 中制作归一化直方图,但我希望它归一化,使总面积为 1000。有办法做到这一点吗?
我知道要将它归一化为 1,您只需在 plt.hist()
的参数中包含 density=True,stacked=True
。一个等效的解决方案是这样做并将每列的高度乘以 1000,如果这比更改直方图标准化的内容更可行的话。
非常感谢您!
以下方法使用 np.histogram
来计算每个直方图 bin 的计数。使用 1000 / total_count / bin_width
作为归一化因子,总面积将为 1000。相反,要使所有条形高度的总和为 1000,需要 1000 / total_count
的因子。
plt.bar
用于显示最终结果。
示例代码计算与 density=True,
相同的组合直方图,以将其与总和为 1000 的新直方图进行比较。
import matplotlib.pyplot as plt
import numpy as np
data = [np.random.randn(100) * 5 + 10, np.random.randn(300) * 4 + 14, np.random.randn(100) * 3 + 17]
fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(12, 4))
ax1.hist(data, stacked=True, density=True)
ax1.set_title('Histogram with density=True')
xmin = min([min(d) for d in data])
xmax = max([max(d) for d in data])
bins = np.linspace(xmin, xmax, 11)
bin_width = bins[1] - bins[0]
counts = [np.histogram(d, bins=bins)[0] for d in data]
total_count = sum([sum(c) for c in counts])
# factor = 1000 / total_count # to sum to 1000
factor = 1000 / total_count / bin_width # for an area of 1000
thousands = [c * factor for c in counts]
bottom = 0
for t in thousands:
ax2.bar(bins[:-1], t, bottom=bottom, width=bin_width, align='edge')
bottom += t
ax2.set_title('Histogram with total area of 1000')
plt.show()
一个简单的方法是设置第二个 y 轴,其刻度标签是原始轴乘以 1000,然后隐藏原始轴的刻度:
import matplotlib.pyplot as plt
import numpy as np
data = [np.random.randn(5000)]
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
#hist returns a tuple that contains a list of y values at its 0 index:
y,_,_ = ax1.hist(data, density=True, bins=10, edgecolor = 'black')
#find max y value of histogram and multiply by 1000:
max_y = np.round(y.max(),1)*1000
#set up the second y-axis ticks as increments of max_y:
ax2.set_ylim(0,max_y)
ax2.set_yticks(np.linspace(0, max_y, 9))
#hide original y-axis ticks:
ax1.axes.yaxis.set_ticks([])
plt.show()
我正在尝试在 matplotlib 中制作归一化直方图,但我希望它归一化,使总面积为 1000。有办法做到这一点吗?
我知道要将它归一化为 1,您只需在 plt.hist()
的参数中包含 density=True,stacked=True
。一个等效的解决方案是这样做并将每列的高度乘以 1000,如果这比更改直方图标准化的内容更可行的话。
非常感谢您!
以下方法使用 np.histogram
来计算每个直方图 bin 的计数。使用 1000 / total_count / bin_width
作为归一化因子,总面积将为 1000。相反,要使所有条形高度的总和为 1000,需要 1000 / total_count
的因子。
plt.bar
用于显示最终结果。
示例代码计算与 density=True,
相同的组合直方图,以将其与总和为 1000 的新直方图进行比较。
import matplotlib.pyplot as plt
import numpy as np
data = [np.random.randn(100) * 5 + 10, np.random.randn(300) * 4 + 14, np.random.randn(100) * 3 + 17]
fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(12, 4))
ax1.hist(data, stacked=True, density=True)
ax1.set_title('Histogram with density=True')
xmin = min([min(d) for d in data])
xmax = max([max(d) for d in data])
bins = np.linspace(xmin, xmax, 11)
bin_width = bins[1] - bins[0]
counts = [np.histogram(d, bins=bins)[0] for d in data]
total_count = sum([sum(c) for c in counts])
# factor = 1000 / total_count # to sum to 1000
factor = 1000 / total_count / bin_width # for an area of 1000
thousands = [c * factor for c in counts]
bottom = 0
for t in thousands:
ax2.bar(bins[:-1], t, bottom=bottom, width=bin_width, align='edge')
bottom += t
ax2.set_title('Histogram with total area of 1000')
plt.show()
一个简单的方法是设置第二个 y 轴,其刻度标签是原始轴乘以 1000,然后隐藏原始轴的刻度:
import matplotlib.pyplot as plt
import numpy as np
data = [np.random.randn(5000)]
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
#hist returns a tuple that contains a list of y values at its 0 index:
y,_,_ = ax1.hist(data, density=True, bins=10, edgecolor = 'black')
#find max y value of histogram and multiply by 1000:
max_y = np.round(y.max(),1)*1000
#set up the second y-axis ticks as increments of max_y:
ax2.set_ylim(0,max_y)
ax2.set_yticks(np.linspace(0, max_y, 9))
#hide original y-axis ticks:
ax1.axes.yaxis.set_ticks([])
plt.show()