Matplotlib 多列箱线图绘制:全面指南与实例
参考:matplotlib boxplot multiple columns
Matplotlib 是 Python 中最流行的数据可视化库之一,它提供了强大的工具来创建各种类型的图表,包括箱线图。箱线图是一种用于显示数据分布的统计图形,特别适合比较多个数据集的分布情况。本文将深入探讨如何使用 Matplotlib 绘制多列箱线图,并通过丰富的示例代码来展示其各种功能和技巧。
1. 箱线图基础
箱线图,也称为盒须图,是一种用于描述数据分布的统计图表。它显示了数据的五个关键统计量:最小值、第一四分位数(Q1)、中位数、第三四分位数(Q3)和最大值。箱线图还可以显示异常值,这使得它成为比较多个数据集分布的有力工具。
让我们从一个简单的单列箱线图开始:
import matplotlib.pyplot as plt
import numpy as np
# 生成示例数据
data = np.random.randn(100)
# 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(8, 6))
# 绘制箱线图
ax.boxplot(data)
# 设置标题和标签
ax.set_title('Single Column Boxplot - how2matplotlib.com')
ax.set_xlabel('Data')
ax.set_ylabel('Values')
plt.show()
Output:
这个示例创建了一个简单的单列箱线图。我们首先导入必要的库,然后生成随机数据。使用 plt.subplots()
创建图形和坐标轴,然后调用 ax.boxplot()
方法绘制箱线图。最后,我们设置标题和标签,并显示图形。
2. 多列箱线图基础
现在,让我们扩展到多列箱线图。多列箱线图允许我们在同一图表中比较多个数据集的分布。
import matplotlib.pyplot as plt
import numpy as np
# 生成多列数据
data1 = np.random.randn(100)
data2 = np.random.randn(100) + 1
data3 = np.random.randn(100) - 1
# 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(10, 6))
# 绘制多列箱线图
ax.boxplot([data1, data2, data3])
# 设置标题和标签
ax.set_title('Multiple Column Boxplot - how2matplotlib.com')
ax.set_xlabel('Datasets')
ax.set_ylabel('Values')
ax.set_xticklabels(['Data 1', 'Data 2', 'Data 3'])
plt.show()
Output:
在这个例子中,我们创建了三个不同的数据集,并将它们作为列表传递给 boxplot()
函数。我们还使用 set_xticklabels()
为每个箱线图设置了标签。
3. 自定义箱线图样式
Matplotlib 提供了多种方式来自定义箱线图的外观。我们可以更改箱体颜色、边框样式、须线样式等。
import matplotlib.pyplot as plt
import numpy as np
# 生成数据
data = [np.random.randn(100) for _ in range(3)]
# 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(10, 6))
# 自定义箱线图样式
boxprops = dict(facecolor='lightblue', edgecolor='navy')
whiskerprops = dict(color='green', linestyle='--')
medianprops = dict(color='red', linewidth=2)
# 绘制自定义样式的箱线图
ax.boxplot(data, boxprops=boxprops, whiskerprops=whiskerprops, medianprops=medianprops)
# 设置标题和标签
ax.set_title('Customized Boxplot - how2matplotlib.com')
ax.set_xlabel('Datasets')
ax.set_ylabel('Values')
ax.set_xticklabels(['Data 1', 'Data 2', 'Data 3'])
plt.show()
在这个例子中,我们使用字典来定义箱体、须线和中位数线的样式。这些字典被传递给 boxplot()
函数的相应参数,从而自定义箱线图的外观。
4. 添加数据点
有时,我们可能希望在箱线图上显示原始数据点。Matplotlib 允许我们轻松地添加这些点。
import matplotlib.pyplot as plt
import numpy as np
# 生成数据
data = [np.random.randn(30) for _ in range(3)]
# 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(10, 6))
# 绘制箱线图和数据点
bp = ax.boxplot(data)
for i, d in enumerate(data):
y = d
x = np.random.normal(i + 1, 0.04, len(y))
ax.plot(x, y, 'r.', alpha=0.4)
# 设置标题和标签
ax.set_title('Boxplot with Data Points - how2matplotlib.com')
ax.set_xlabel('Datasets')
ax.set_ylabel('Values')
ax.set_xticklabels(['Data 1', 'Data 2', 'Data 3'])
plt.show()
Output:
在这个例子中,我们首先绘制箱线图,然后使用循环为每个数据集添加散点。我们使用 np.random.normal()
来稍微扰动 x 坐标,以避免点重叠。
5. 水平箱线图
默认情况下,Matplotlib 绘制垂直的箱线图。但有时,水平箱线图可能更适合某些数据或布局。
import matplotlib.pyplot as plt
import numpy as np
# 生成数据
data = [np.random.randn(100) for _ in range(5)]
# 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(10, 8))
# 绘制水平箱线图
ax.boxplot(data, vert=False)
# 设置标题和标签
ax.set_title('Horizontal Boxplot - how2matplotlib.com')
ax.set_xlabel('Values')
ax.set_ylabel('Datasets')
ax.set_yticklabels(['Data 1', 'Data 2', 'Data 3', 'Data 4', 'Data 5'])
plt.show()
Output:
通过将 vert=False
参数传递给 boxplot()
函数,我们可以创建水平箱线图。注意,在这种情况下,我们需要交换 x 轴和 y 轴的标签。
6. 带缺口的箱线图
缺口箱线图可以帮助我们快速判断两个中位数之间是否存在显著差异。
import matplotlib.pyplot as plt
import numpy as np
# 生成数据
data = [np.random.randn(100) for _ in range(3)]
# 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(10, 6))
# 绘制带缺口的箱线图
ax.boxplot(data, notch=True)
# 设置标题和标签
ax.set_title('Notched Boxplot - how2matplotlib.com')
ax.set_xlabel('Datasets')
ax.set_ylabel('Values')
ax.set_xticklabels(['Data 1', 'Data 2', 'Data 3'])
plt.show()
Output:
通过设置 notch=True
,我们可以创建带缺口的箱线图。缺口表示中位数的置信区间,如果两个箱子的缺口不重叠,通常表示它们的中位数有显著差异。
7. 箱线图与小提琴图结合
小提琴图是箱线图的一个变体,它显示了数据的概率密度。我们可以将箱线图和小提琴图结合起来,以提供更丰富的数据分布信息。
import matplotlib.pyplot as plt
import numpy as np
# 生成数据
data = [np.random.randn(100) for _ in range(3)]
# 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(10, 6))
# 绘制小提琴图
parts = ax.violinplot(data, showmeans=False, showmedians=False, showextrema=False)
# 自定义小提琴图样式
for pc in parts['bodies']:
pc.set_facecolor('#D43F3A')
pc.set_edgecolor('black')
pc.set_alpha(0.7)
# 添加箱线图
ax.boxplot(data, positions=range(1, 4), widths=0.15, patch_artist=True,
boxprops=dict(facecolor='white', color='black'),
capprops=dict(color='black'),
whiskerprops=dict(color='black'),
flierprops=dict(color='black', markeredgecolor='black'),
medianprops=dict(color='black'))
# 设置标题和标签
ax.set_title('Boxplot with Violin Plot - how2matplotlib.com')
ax.set_xlabel('Datasets')
ax.set_ylabel('Values')
ax.set_xticks(range(1, 4))
ax.set_xticklabels(['Data 1', 'Data 2', 'Data 3'])
plt.show()
Output:
这个例子展示了如何将箱线图叠加在小提琴图上。小提琴图显示了数据的概率密度,而箱线图提供了关键的统计信息。这种组合可以提供更全面的数据分布视图。
8. 分组箱线图
当我们有多个类别和每个类别内的多个组时,分组箱线图非常有用。
import matplotlib.pyplot as plt
import numpy as np
# 生成数据
np.random.seed(42)
data = {
'Group A': [np.random.normal(0, std, 100) for std in range(1, 4)],
'Group B': [np.random.normal(0, std, 100) for std in range(1, 4)],
'Group C': [np.random.normal(0, std, 100) for std in range(1, 4)]
}
# 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(12, 6))
# 设置位置和宽度
positions = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
width = 0.5
# 绘制分组箱线图
for i, (group, group_data) in enumerate(data.items()):
bp = ax.boxplot(group_data, positions=positions[i], widths=width)
# 自定义每组的颜色
color = plt.cm.Set3(i / float(len(data)))
plt.setp(bp['boxes'], color=color)
plt.setp(bp['whiskers'], color=color)
plt.setp(bp['caps'], color=color)
# 设置标题和标签
ax.set_title('Grouped Boxplot - how2matplotlib.com')
ax.set_xlabel('Groups')
ax.set_ylabel('Values')
ax.set_xticks([2, 5, 8])
ax.set_xticklabels(['Group A', 'Group B', 'Group C'])
# 添加图例
for i, group in enumerate(data.keys()):
ax.plot([], [], color=plt.cm.Set3(i / float(len(data))), label=group)
ax.legend()
plt.show()
Output:
这个例子展示了如何创建分组箱线图。我们为每个组创建了三个箱线图,并使用不同的颜色来区分不同的组。我们还添加了图例来帮助识别每个组。
9. 带异常值标记的箱线图
箱线图通常用于识别异常值。我们可以自定义异常值的显示方式,使它们更加突出。
import matplotlib.pyplot as plt
import numpy as np
# 生成数据
np.random.seed(42)
data = [np.random.normal(0, std, 100) for std in range(1, 4)]
# 添加一些异常值
data[0] = np.append(data[0], [10, -10])
data[1] = np.append(data[1], [15, -15])
data[2] = np.append(data[2], [20, -20])
# 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(10, 6))
# 绘制带自定义异常值的箱线图
bp = ax.boxplot(data, patch_artist=True)
# 自定义箱体颜色
colors = ['lightblue', 'lightgreen', 'lightpink']
for patch, color in zip(bp['boxes'], colors):
patch.set_facecolor(color)
# 自定义异常值标记
for flier in bp['fliers']:
flier.set(marker='D', color='red', alpha=0.5)
# 设置标题和标签
ax.set_title('Boxplot with Custom Outliers - how2matplotlib.com')
ax.set_xlabel('Datasets')
ax.set_ylabel('Values')
ax.set_xticklabels(['Data 1', 'Data 2', 'Data 3'])
plt.show()
Output:
在这个例子中,我们添加了一些异常值到数据集中,并自定义了异常值的标记样式。我们使用菱形标记和红色来突出显示异常值。
10. 带统计注释的箱线图
有时,我们可能想在箱线图上添加一些统计信息,如均值或标准差。
import```python
import matplotlib.pyplot as plt
import numpy as np
# 生成数据
np.random.seed(42)
data = [np.random.normal(0, std, 100) for std in range(1, 4)]
# 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(10, 6))
# 绘制箱线图
bp = ax.boxplot(data)
# 计算并添加均值
means = [np.mean(d) for d in data]
ax.scatter(range(1, len(data) + 1), means, marker='o', color='red', s=30, zorder=3)
# 添加统计注释
for i, d in enumerate(data):
mean = np.mean(d)
std = np.std(d)
ax.annotate(f'Mean: {mean:.2f}\nStd: {std:.2f}',
xy=(i + 1, mean),
xytext=(5, 5),
textcoords='offset points',
ha='left', va='bottom')
# 设置标题和标签
ax.set_title('Boxplot with Statistical Annotations - how2matplotlib.com')
ax.set_xlabel('Datasets')
ax.set_ylabel('Values')
ax.set_xticklabels(['Data 1', 'Data 2', 'Data 3'])
plt.show()
这个例子展示了如何在箱线图上添加统计注释。我们计算了每个数据集的均值和标准差,并将这些信息添加到图表上。红点表示均值,文本注释显示具体的均值和标准差值。
11. 带颜色渐变的箱线图
我们可以使用颜色渐变来增强箱线图的视觉效果,特别是当我们有多个数据集时。
import matplotlib.pyplot as plt
import numpy as np
# 生成数据
np.random.seed(42)
data = [np.random.normal(0, std, 100) for std in range(1, 6)]
# 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(12, 6))
# 创建颜色渐变
colors = plt.cm.viridis(np.linspace(0, 1, len(data)))
# 绘制带颜色渐变的箱线图
bp = ax.boxplot(data, patch_artist=True)
# 应用颜色渐变
for patch, color in zip(bp['boxes'], colors):
patch.set_facecolor(color)
# 设置标题和标签
ax.set_title('Boxplot with Color Gradient - how2matplotlib.com')
ax.set_xlabel('Datasets')
ax.set_ylabel('Values')
ax.set_xticklabels([f'Data {i+1}' for i in range(len(data))])
plt.show()
Output:
在这个例子中,我们使用 Matplotlib 的 viridis
颜色映射创建了一个颜色渐变,并将其应用到箱线图的箱体上。这种方法可以帮助观察者更容易地区分不同的数据集。
12. 带误差条的箱线图
有时,我们可能想在箱线图上添加误差条来显示额外的统计信息,如置信区间。
import matplotlib.pyplot as plt
import numpy as np
from scipy import stats
# 生成数据
np.random.seed(42)
data = [np.random.normal(0, std, 100) for std in range(1, 4)]
# 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(10, 6))
# 绘制箱线图
bp = ax.boxplot(data)
# 计算并添加95%置信区间
for i, d in enumerate(data):
mean = np.mean(d)
ci = stats.t.interval(alpha=0.95, df=len(d)-1, loc=mean, scale=stats.sem(d))
ci_range = ci[1] - ci[0]
ax.errorbar(i + 1, mean, yerr=ci_range/2, fmt='o', color='red', capsize=5)
# 设置标题和标签
ax.set_title('Boxplot with Error Bars - how2matplotlib.com')
ax.set_xlabel('Datasets')
ax.set_ylabel('Values')
ax.set_xticklabels(['Data 1', 'Data 2', 'Data 3'])
plt.show()
这个例子展示了如何在箱线图上添加误差条。我们使用 SciPy 的 stats
模块计算了 95% 置信区间,并使用 errorbar
函数将其添加到图表上。红点表示均值,误差条表示置信区间。
13. 带子图的多列箱线图
当我们有多个相关但独立的数据集时,使用子图可以帮助我们在一个图形中组织多个箱线图。
import matplotlib.pyplot as plt
import numpy as np
# 生成数据
np.random.seed(42)
data1 = [np.random.normal(0, std, 100) for std in range(1, 4)]
data2 = [np.random.normal(0, std, 100) for std in range(2, 5)]
# 创建图形和子图
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))
# 绘制第一个子图的箱线图
bp1 = ax1.boxplot(data1)
ax1.set_title('Dataset 1 - how2matplotlib.com')
ax1.set_xlabel('Groups')
ax1.set_ylabel('Values')
ax1.set_xticklabels(['Group A', 'Group B', 'Group C'])
# 绘制第二个子图的箱线图
bp2 = ax2.boxplot(data2)
ax2.set_title('Dataset 2 - how2matplotlib.com')
ax2.set_xlabel('Groups')
ax2.set_ylabel('Values')
ax2.set_xticklabels(['Group X', 'Group Y', 'Group Z'])
# 调整子图布局
plt.tight_layout()
plt.show()
Output:
这个例子创建了两个并排的子图,每个子图包含一个独立的箱线图。这种布局允许我们直观地比较两个相关但独立的数据集。
14. 带轴缩放的箱线图
有时,我们的数据可能包含极端值,这可能会使箱线图的主要部分变得难以辨认。在这种情况下,我们可以使用对数刻度或其他轴缩放技术。
import matplotlib.pyplot as plt
import numpy as np
# 生成数据,包括一些极端值
np.random.seed(42)
data = [np.random.lognormal(0, 1, 1000) for _ in range(3)]
# 创建图形和坐标轴
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))
# 绘制普通刻度的箱线图
bp1 = ax1.boxplot(data)
ax1.set_title('Normal Scale - how2matplotlib.com')
ax1.set_xlabel('Groups')
ax1.set_ylabel('Values')
ax1.set_xticklabels(['Group A', 'Group B', 'Group C'])
# 绘制对数刻度的箱线图
bp2 = ax2.boxplot(data)
ax2.set_yscale('log')
ax2.set_title('Log Scale - how2matplotlib.com')
ax2.set_xlabel('Groups')
ax2.set_ylabel('Values (log scale)')
ax2.set_xticklabels(['Group A', 'Group B', 'Group C'])
# 调整子图布局
plt.tight_layout()
plt.show()
Output:
这个例子创建了两个箱线图:一个使用普通刻度,另一个使用对数刻度。对数刻度可以帮助我们更好地可视化包含极端值的数据分布。
15. 带颜色编码的箱线图
我们可以使用颜色编码来强调箱线图的某些特征,例如基于数据的某些属性。
import matplotlib.pyplot as plt
import numpy as np
# 生成数据
np.random.seed(42)
data = [np.random.normal(0, std, 100) for std in range(1, 6)]
# 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(12, 6))
# 定义颜色映射
color_map = plt.cm.get_cmap('RdYlGn')
# 计算每个数据集的中位数
medians = [np.median(d) for d in data]
norm = plt.Normalize(min(medians), max(medians))
# 绘制带颜色编码的箱线图
bp = ax.boxplot(data, patch_artist=True)
for median, box in zip(medians, bp['boxes']):
color = color_map(norm(median))
box.set_facecolor(color)
# 设置标题和标签
ax.set_title('Color-coded Boxplot - how2matplotlib.com')
ax.set_xlabel('Datasets')
ax.set_ylabel('Values')
ax.set_xticklabels([f'Data {i+1}' for i in range(len(data))])
# 添加颜色条
sm = plt.cm.ScalarMappable(cmap=color_map, norm=norm)
sm.set_array([])
cbar = plt.colorbar(sm)
cbar.set_label('Median Value')
plt.show()
在这个例子中,我们基于每个数据集的中位数值来为箱体着色。我们使用了 ‘RdYlGn’ 颜色映射,其中红色表示较低的中位数,绿色表示较高的中位数。我们还添加了一个颜色条来解释颜色编码。
结论
Matplotlib 提供了丰富的工具和选项来创建和自定义多列箱线图。通过本文介绍的各种技术,你可以创建信息丰富、视觉吸引力强的箱线图,以有效地展示和比较多个数据集的分布情况。从基本的多列箱线图到高度自定义的版本,这些技术可以帮助你根据特定需求和数据特征来优化你的数据可视化。
记住,好的数据可视化不仅仅是about美观,更重要的是要能够有效地传达数据中的关键信息。因此,在选择和应用这些技术时,始终要考虑你的目标受众和你想要传达的主要信息。通过实践和实验,你将能够掌握使用 Matplotlib 创建富有洞察力的多列箱线图的艺术。