Matplotlib绘制总高度为1的直方图:完整教程与实例
参考:Plotting a Histogram with Total Height Equal to 1
在数据可视化中,直方图是一种常用的图表类型,用于展示数据的分布情况。通过将总高度设置为1,我们可以更直观地比较不同数据集的分布特征。本文将详细介绍如何使用Matplotlib绘制总高度为1的直方图,包括基本概念、实现方法、常见问题及解决方案等。
1. 直方图基础
直方图是一种用于显示数据分布的图形表示。它将数据分成若干个区间(称为”箱”或”bin”),并显示每个区间内数据点的数量或频率。当我们将直方图的总高度设置为1时,实际上是在绘制一个概率密度直方图,这种图形可以更好地比较不同样本量的数据集。
以下是一个基本的直方图示例:
import matplotlib.pyplot as plt
import numpy as np
# 生成示例数据
data = np.random.normal(0, 1, 1000)
# 绘制直方图
plt.figure(figsize=(10, 6))
plt.hist(data, bins=30, density=True)
plt.title('How2matplotlib.com: Basic Histogram with Total Height = 1')
plt.xlabel('Value')
plt.ylabel('Density')
plt.show()
Output:
在这个例子中,我们使用numpy
生成了1000个服从标准正态分布的随机数,然后使用plt.hist()
函数绘制直方图。通过设置density=True
参数,我们确保了直方图的总面积为1。
2. 自定义箱数和范围
调整箱的数量和范围可以帮助我们更好地展示数据的分布特征。以下是一个自定义箱数和范围的示例:
import matplotlib.pyplot as plt
import numpy as np
# 生成示例数据
data = np.random.exponential(2, 1000)
# 自定义箱数和范围
plt.figure(figsize=(10, 6))
plt.hist(data, bins=20, range=(0, 10), density=True)
plt.title('How2matplotlib.com: Histogram with Custom Bins and Range')
plt.xlabel('Value')
plt.ylabel('Density')
plt.show()
Output:
在这个例子中,我们生成了服从指数分布的数据,并通过设置bins=20
和range=(0, 10)
来自定义箱数和数据范围。这样可以更精确地控制直方图的显示效果。
3. 多数据集比较
当我们需要比较多个数据集的分布时,将总高度设置为1的直方图特别有用。以下是一个比较两个数据集的示例:
import matplotlib.pyplot as plt
import numpy as np
# 生成两组示例数据
data1 = np.random.normal(0, 1, 1000)
data2 = np.random.normal(2, 1.5, 1500)
# 绘制两个数据集的直方图
plt.figure(figsize=(12, 6))
plt.hist(data1, bins=30, density=True, alpha=0.7, label='Dataset 1')
plt.hist(data2, bins=30, density=True, alpha=0.7, label='Dataset 2')
plt.title('How2matplotlib.com: Comparing Two Datasets')
plt.xlabel('Value')
plt.ylabel('Density')
plt.legend()
plt.show()
Output:
在这个例子中,我们生成了两组不同参数的正态分布数据,并在同一张图上绘制它们的直方图。通过设置alpha
参数,我们可以使两个直方图部分透明,以便更好地观察重叠部分。
4. 堆叠直方图
堆叠直方图可以用来展示多个类别的数据分布,同时保持总高度为1。以下是一个堆叠直方图的示例:
import matplotlib.pyplot as plt
import numpy as np
# 生成示例数据
data1 = np.random.normal(0, 1, 1000)
data2 = np.random.normal(2, 1, 1000)
data3 = np.random.normal(4, 1, 1000)
# 绘制堆叠直方图
plt.figure(figsize=(12, 6))
plt.hist([data1, data2, data3], bins=30, density=True, stacked=True, label=['Group 1', 'Group 2', 'Group 3'])
plt.title('How2matplotlib.com: Stacked Histogram with Total Height = 1')
plt.xlabel('Value')
plt.ylabel('Density')
plt.legend()
plt.show()
Output:
在这个例子中,我们生成了三组正态分布数据,并使用stacked=True
参数创建了一个堆叠直方图。这种方式可以清晰地展示各组数据在不同值范围内的相对比例。
5. 自定义样式
Matplotlib提供了丰富的样式选项,允许我们自定义直方图的外观。以下是一个使用自定义样式的示例:
import matplotlib.pyplot as plt
import numpy as np
# 生成示例数据
data = np.random.gamma(2, 2, 1000)
# 自定义样式
plt.figure(figsize=(10, 6))
plt.hist(data, bins=30, density=True, edgecolor='black', color='skyblue', linewidth=1.2)
plt.title('How2matplotlib.com: Histogram with Custom Style', fontsize=16)
plt.xlabel('Value', fontsize=12)
plt.ylabel('Density', fontsize=12)
plt.grid(True, linestyle='--', alpha=0.7)
plt.show()
Output:
在这个例子中,我们使用了伽马分布的数据,并通过设置edgecolor
、color
、linewidth
等参数来自定义直方图的外观。同时,我们还调整了标题和轴标签的字体大小,并添加了网格线。
6. 添加核密度估计曲线
核密度估计(KDE)曲线可以帮助我们更好地理解数据的连续分布。以下是一个在直方图上添加KDE曲线的示例:
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import gaussian_kde
# 生成示例数据
data = np.random.lognormal(0, 0.5, 1000)
# 计算KDE
kde = gaussian_kde(data)
x_range = np.linspace(data.min(), data.max(), 100)
# 绘制直方图和KDE曲线
plt.figure(figsize=(10, 6))
plt.hist(data, bins=30, density=True, alpha=0.7, label='Histogram')
plt.plot(x_range, kde(x_range), 'r-', label='KDE')
plt.title('How2matplotlib.com: Histogram with KDE Curve')
plt.xlabel('Value')
plt.ylabel('Density')
plt.legend()
plt.show()
Output:
在这个例子中,我们使用对数正态分布的数据,并使用scipy.stats.gaussian_kde
函数计算KDE。然后,我们在直方图上叠加了KDE曲线,以提供更平滑的分布估计。
7. 双坐标轴直方图
有时我们可能需要同时显示频数和密度。以下是一个使用双坐标轴的直方图示例:
import matplotlib.pyplot as plt
import numpy as np
# 生成示例数据
data = np.random.poisson(5, 1000)
# 创建图形和坐标轴
fig, ax1 = plt.subplots(figsize=(10, 6))
ax2 = ax1.twinx()
# 绘制频数直方图
n, bins, patches = ax1.hist(data, bins=30, color='skyblue', edgecolor='black')
ax1.set_ylabel('Frequency', color='blue')
# 计算和绘制密度
density = n / (sum(n) * np.diff(bins))
ax2.plot(bins[:-1], density, 'r-', linewidth=2)
ax2.set_ylabel('Density', color='red')
plt.title('How2matplotlib.com: Histogram with Dual Y-axes')
plt.xlabel('Value')
plt.show()
Output:
在这个例子中,我们使用泊松分布的数据,创建了一个主坐标轴用于显示频数,和一个次坐标轴用于显示密度。这种方式可以同时展示数据的绝对数量和相对分布。
8. 3D直方图
对于二维数据,我们可以创建3D直方图来展示其分布。以下是一个3D直方图的示例:
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
# 生成二维示例数据
x = np.random.normal(0, 1, 1000)
y = np.random.normal(0, 1, 1000)
# 创建3D图形
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
# 计算直方图数据
hist, xedges, yedges = np.histogram2d(x, y, bins=20, density=True)
xpos, ypos = np.meshgrid(xedges[:-1] + 0.25, yedges[:-1] + 0.25, indexing="ij")
xpos = xpos.ravel()
ypos = ypos.ravel()
zpos = 0
# 绘制3D直方图
dx = dy = 0.5 * np.ones_like(zpos)
dz = hist.ravel()
ax.bar3d(xpos, ypos, zpos, dx, dy, dz, zsort='average')
plt.title('How2matplotlib.com: 3D Histogram')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Density')
plt.show()
Output:
在这个例子中,我们生成了二维正态分布的数据,并使用np.histogram2d
函数计算二维直方图数据。然后,我们使用ax.bar3d
函数创建了一个3D直方图,展示了二维数据的分布情况。
9. 极坐标直方图
对于周期性数据或角度数据,极坐标直方图可能更适合。以下是一个极坐标直方图的示例:
import matplotlib.pyplot as plt
import numpy as np
# 生成示例数据(角度)
data = np.random.vonmises(0, 2, 1000)
# 创建极坐标图
fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(111, projection='polar')
# 绘制极坐标直方图
n, bins, _ = ax.hist(data, bins=30, density=True)
# 调整显示范围
ax.set_ylim(0, max(n) * 1.1)
plt.title('How2matplotlib.com: Polar Histogram')
plt.show()
Output:
在这个例子中,我们使用von Mises分布生成了角度数据,并使用极坐标系统创建了直方图。这种方式特别适合展示方向或时间等周期性数据的分布。
10. 累积分布直方图
累积分布直方图可以帮助我们理解数据的累积特性。以下是一个累积分布直方图的示例:
import matplotlib.pyplot as plt
import numpy as np
# 生成示例数据
data = np.random.weibull(1.5, 1000)
# 绘制累积分布直方图
plt.figure(figsize=(10, 6))
plt.hist(data, bins=30, density=True, cumulative=True, histtype='step', linewidth=2)
plt.title('How2matplotlib.com: Cumulative Distribution Histogram')
plt.xlabel('Value')
plt.ylabel('Cumulative Density')
plt.grid(True, linestyle='--', alpha=0.7)
plt.show()
Output:
在这个例子中,我们使用Weibull分布生成数据,并通过设置cumulative=True
参数创建了一个累积分布直方图。这种图形可以帮助我们了解数据在不同值以下的累积概率。
11. 多面板直方图
当我们需要比较多个相关数据集时,多面板直方图是一个很好的选择。以下是一个多面板直方图的示例:
import matplotlib.pyplot as plt
import numpy as np
# 生成示例数据
data1 = np.random.normal(0, 1, 1000)
data2 = np.random.gamma(2, 2, 1000)
data3 = np.random.exponential(2, 1000)
data4 = np.random.lognormal(0, 0.5, 1000)
# 创建多面板图
fig, axs = plt.subplots(2, 2, figsize=(12, 10))
fig.suptitle('How2matplotlib.com: Multi-panel Histograms', fontsize=16)
# 绘制四个直方图
axs[0, 0].hist(data1, bins=30, density=True)
axs[0, 0].set_title('Normal Distribution')
axs[0, 1].hist(data2, bins=30, density=True)
axs[0, 1].set_title('Gamma Distribution')
axs[1, 0].hist(data3, bins=30, density=True)
axs[1, 0].set_title('Exponential Distribution')
axs[1, 1].hist(data4, bins=30, density=True)
axs[1, 1].set_title('Lognormal Distribution')
# 调整子图间距
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们创建了一个2×2的子图网格,并在每个子图中绘制了不同分布的直方图。这种方式可以方便地比较多个数据集的分布特征。
12. 带误差条的直方图
在某些情况下,我们可能需要在直方图上显示误差范围。以下是一个带误差条的直方图示例:
import matplotlib.pyplot as plt
import numpy as np
# 生成示例数据
data = np.random.normal(0, 1, 1000)
# 计算直方图数据
counts, bins, _ = plt.hist(data, bins=20, density=True)
# 计算误差(这里使用简单的平方根估计)
errors = np.sqrt(counts) / np.sum(counts) * (bins[1] - bins[0])
# 绘制带误差条的直方图
plt.figure(figsize=(10, 6))
plt.bar(bins[:-1], counts, width=bins[1] - bins[0], alpha=0.7, yerr=errors, capsize=5)
plt.title('How2matplotlib.com: Histogram with Error Bars')
plt.xlabel('Value')
plt.ylabel('Density')
plt.show()
Output:
在这个例子中,我们首先计算了直方图数据,然后估算了每个箱的误差。使用plt.bar()
函数绘制直方图,并通过yerr
参数添加了误差条。这种方式可以帮助我们更好地理解数据的不确定性。
13. 对数刻度直方图
对于跨越多个数量级的数据,使用对数刻度可能更合适。以下是一个对数刻度直方图的示例:
import matplotlib.pyplot as plt
import numpy as np
# 生成示例数据(使用对数正态分布)
data = np.random.lognormal(0, 1, 10000)
# 绘制对数刻度直方图
plt.figure(figsize=(10, 6))
plt.hist(data, bins=50, density=True)
plt.xscale('log')
plt.yscale('log')
plt.title('How2matplotlib.com: Histogram with Logarithmic Scales')
plt.xlabel('Value (log scale)')
plt.ylabel('Density (log scale)')
plt.grid(True, which="both", ls="-", alpha=0.2)
plt.show()
Output:
在这个例子中,我们使用对数正态分布生成了数据,并通过设置plt.xscale('log')
和plt.yscale('log')
将x轴和y轴都设置为对数刻度。这种方式可以更好地展示跨越多个数量级的数据分布。
14. 带标注的直方图
有时我们可能需要在直方图上添加一些标注来突出某些特征。以下是一个带标注的直方图示例:
import matplotlib.pyplot as plt
import numpy as np
# 生成示例数据
data = np.random.normal(0, 1, 1000)
# 绘制直方图
plt.figure(figsize=(10, 6))
n, bins, patches = plt.hist(data, bins=30, density=True)
# 找到最高的箱
max_bin = bins[np.argmax(n)]
# 添加标注
plt.annotate(f'Peak at {max_bin:.2f}', xy=(max_bin, max(n)), xytext=(max_bin+1, max(n)),
arrowprops=dict(facecolor='black', shrink=0.05),
fontsize=12, ha='left', va='center')
plt.title('How2matplotlib.com: Histogram with Annotation')
plt.xlabel('Value')
plt.ylabel('Density')
plt.show()
Output:
在这个例子中,我们找到了直方图中最高的箱,并使用plt.annotate()
函数添加了一个指向该箱的标注。这种方式可以帮助我们强调数据分布中的重要特征。
15. 条形直方图
虽然通常我们使用连续的矩形来表示直方图,但有时使用分离的条形可能更清晰。以下是一个条形直方图的示例:
import matplotlib.pyplot as plt
import numpy as np
# 生成示例数据
data = np.random.poisson(5, 1000)
# 计算直方图数据
counts, bins, _ = plt.hist(data, bins=range(0, 15), density=True)
plt.clf() # 清除之前的图形
# 绘制条形直方图
plt.figure(figsize=(10, 6))
plt.bar(bins[:-1], counts, width=0.8, align='center', edgecolor='black')
plt.title('How2matplotlib.com: Bar-style Histogram')
plt.xlabel('Value')
plt.ylabel('Density')
plt.xticks(range(0, 15))
plt.show()
Output:
在这个例子中,我们使用泊松分布生成数据,并使用plt.bar()
函数创建了一个条形样式的直方图。这种方式特别适合离散数据或者当我们想要强调每个箱之间的区别时。
16. 2D直方图
对于二维数据,我们可以创建2D直方图来展示其联合分布。以下是一个2D直方图的示例:
import matplotlib.pyplot as plt
import numpy as np
# 生成二维示例数据
x = np.random.normal(0, 1, 10000)
y = x + np.random.normal(0, 1, 10000)
# 绘制2D直方图
plt.figure(figsize=(10, 8))
plt.hist2d(x, y, bins=50, density=True, cmap='viridis')
plt.colorbar(label='Density')
plt.title('How2matplotlib.com: 2D Histogram')
plt.xlabel('X')
plt.ylabel('Y')
plt.show()
Output:
在这个例子中,我们生成了相关的二维数据,并使用plt.hist2d()
函数创建了一个2D直方图。颜色表示每个箱中的密度,我们还添加了一个颜色条来帮助解释密度值。
17. 边缘直方图
边缘直方图是一种组合图,它在主图的边缘显示单变量分布。以下是一个边缘直方图的示例:
import matplotlib.pyplot as plt
import numpy as np
# 生成示例数据
x = np.random.normal(0, 1, 1000)
y = x + np.random.normal(0, 1, 1000)
# 创建图形和子图
fig = plt.figure(figsize=(10, 10))
gs = fig.add_gridspec(3, 3)
ax_main = fig.add_subplot(gs[1:, :-1])
ax_right = fig.add_subplot(gs[1:, -1], sharey=ax_main)
ax_top = fig.add_subplot(gs[0, :-1], sharex=ax_main)
# 绘制散点图
ax_main.scatter(x, y, alpha=0.5)
# 绘制边缘直方图
ax_right.hist(y, bins=30, orientation='horizontal', density=True)
ax_top.hist(x, bins=30, density=True)
# 隐藏部分刻度标签
ax_right.tick_params(axis="y", labelleft=False)
ax_top.tick_params(axis="x", labelbottom=False)
plt.suptitle('How2matplotlib.com: Marginal Histogram', fontsize=16)
plt.tight_layout()
plt.show()
Output:
在这个例子中,我们创建了一个主散点图和两个边缘直方图。这种方式可以同时展示二维数据的联合分布和每个变量的单独分布。
总结
本文详细介绍了如何使用Matplotlib绘制总高度为1的直方图,涵盖了从基础概念到高级技巧的多个方面。我们探讨了直方图的基本原理,学习了如何自定义箱数和范围,比较多个数据集,创建堆叠直方图,以及如何添加核密度估计曲线等。此外,我们还介绍了3D直方图、极坐标直方图、累积分布直方图等特殊类型的直方图,以及如何创建多面板直方图和带误差条的直方图。
通过这些示例,我们可以看到Matplotlib提供了丰富的工具和选项,使我们能够创建各种类型的直方图,以最佳方式展示和分析数据分布。无论是单变量还是多变量数据,无论是连续数据还是离散数据,我们都可以找到合适的直方图表示方法。
在实际应用中,选择合适的直方图类型和样式取决于数据的性质和我们想要传达的信息。通过调整箱数、范围、颜色、标签等参数,我们可以创建既美观又信息丰富的直方图。
最后,值得注意的是,虽然本文主要关注总高度为1的直方图(即概率密度直方图),但这些技巧和方法同样适用于其他类型的直方图。通过灵活运用这些技巧,我们可以更好地理解和展示数据,为数据分析和决策提供有力支持。