Matplotlib中为多个箱线图添加图例的详细指南
参考:Adding Legend to Boxplot with Multiple Plots
在数据可视化中,箱线图是一种非常有用的工具,用于展示数据的分布情况。当我们需要在同一张图中比较多个数据集时,为每个箱线图添加图例就变得尤为重要。本文将详细介绍如何在Matplotlib中为多个箱线图添加图例,包括基本概念、不同的实现方法以及一些进阶技巧。
1. 箱线图基础
在开始为多个箱线图添加图例之前,我们先来回顾一下箱线图的基本概念和创建方法。
箱线图(Box Plot)也称为盒须图,是一种用作显示一组数据分散情况资料的统计图。它能显示出一组数据的最大值、最小值、中位数、下四分位数及上四分位数。
1.1 创建简单的箱线图
让我们从一个简单的箱线图开始:
import matplotlib.pyplot as plt
import numpy as np
# 生成示例数据
data = np.random.randn(100)
# 创建图形和坐标轴
fig, ax = plt.subplots()
# 绘制箱线图
ax.boxplot(data)
# 设置标题
ax.set_title('Simple Boxplot - how2matplotlib.com')
# 显示图形
plt.show()
Output:
这段代码创建了一个简单的箱线图。我们使用numpy
生成了随机数据,然后使用matplotlib.pyplot.boxplot()
函数绘制箱线图。
1.2 箱线图的组成部分
箱线图由以下几个部分组成:
- 箱体:表示数据的四分位数范围
- 中位线:表示数据的中位数
- 须:延伸到最小和最大值(不包括异常值)
- 异常值:通常用点表示,超出四分位范围的1.5倍
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()
# 绘制多个箱线图
ax.boxplot([data1, data2, data3])
# 设置标题和标签
ax.set_title('Multiple Boxplots - how2matplotlib.com')
ax.set_xticklabels(['Data 1', 'Data 2', 'Data 3'])
# 显示图形
plt.show()
Output:
在这个例子中,我们创建了三个数据集,并将它们作为一个列表传递给boxplot()
函数。这样就可以在同一张图上绘制多个箱线图。
3. 为多个箱线图添加图例
现在我们来到了本文的核心内容:如何为多个箱线图添加图例。有几种不同的方法可以实现这一目标,我们将逐一介绍。
3.1 使用自定义图例
一种常用的方法是创建自定义的图例,而不是使用箱线图的内置图例。
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()
# 绘制多个箱线图
bplot = ax.boxplot([data1, data2, data3], patch_artist=True)
# 设置箱体颜色
colors = ['pink', 'lightblue', 'lightgreen']
for patch, color in zip(bplot['boxes'], colors):
patch.set_facecolor(color)
# 添加自定义图例
ax.legend([bplot["boxes"][0], bplot["boxes"][1], bplot["boxes"][2]],
['Data 1', 'Data 2', 'Data 3'],
loc='upper right')
# 设置标题
ax.set_title('Boxplots with Custom Legend - how2matplotlib.com')
# 显示图形
plt.show()
Output:
在这个例子中,我们使用patch_artist=True
参数来允许自定义箱体的颜色。然后,我们为每个箱体设置不同的颜色,并使用这些箱体作为图例的句柄。
3.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()
# 绘制多个箱线图
bplot = ax.boxplot([data1, data2, data3], patch_artist=True)
# 设置箱体颜色
colors = ['pink', 'lightblue', 'lightgreen']
for patch, color in zip(bplot['boxes'], colors):
patch.set_facecolor(color)
# 创建虚拟线条用于图例
dummy_lines = [plt.Line2D([0], [0], color=color, lw=4) for color in colors]
# 添加图例
ax.legend(dummy_lines, ['Data 1', 'Data 2', 'Data 3'], loc='upper right')
# 设置标题
ax.set_title('Boxplots with Legend Using Dummy Lines - how2matplotlib.com')
# 显示图形
plt.show()
Output:
在这个例子中,我们创建了虚拟的Line2D
对象,这些对象只用于图例,不会在实际的图表中显示。这种方法可以让我们更灵活地控制图例的外观。
3.3 使用标记符号创建图例
如果你想在图例中使用更简洁的标记,可以考虑使用标记符号来创建图例。
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()
# 绘制多个箱线图
bplot = ax.boxplot([data1, data2, data3], patch_artist=True)
# 设置箱体颜色
colors = ['pink', 'lightblue', 'lightgreen']
for patch, color in zip(bplot['boxes'], colors):
patch.set_facecolor(color)
# 创建标记符号用于图例
dummy_markers = [plt.scatter([], [], c=color, marker='s', s=50) for color in colors]
# 添加图例
ax.legend(dummy_markers, ['Data 1', 'Data 2', 'Data 3'], loc='upper right')
# 设置标题
ax.set_title('Boxplots with Legend Using Markers - how2matplotlib.com')
# 显示图形
plt.show()
Output:
在这个例子中,我们使用scatter()
函数创建了小方块作为图例的标记。这种方法可以让图例看起来更加简洁。
4. 高级技巧
现在我们已经掌握了为多个箱线图添加图例的基本方法,让我们来看一些更高级的技巧。
4.1 组合箱线图和散点图
有时,我们可能想要在箱线图旁边显示原始数据点。这可以通过组合箱线图和散点图来实现。
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()
# 绘制箱线图
bplot = ax.boxplot([data1, data2, data3], patch_artist=True, positions=[1, 2, 3])
# 设置箱体颜色
colors = ['pink', 'lightblue', 'lightgreen']
for patch, color in zip(bplot['boxes'], colors):
patch.set_facecolor(color)
# 添加散点图
for i, data in enumerate([data1, data2, data3], start=1):
x = np.random.normal(i, 0.04, len(data))
ax.scatter(x, data, alpha=0.3)
# 添加图例
ax.legend([bplot["boxes"][0], bplot["boxes"][1], bplot["boxes"][2]],
['Data 1', 'Data 2', 'Data 3'],
loc='upper right')
# 设置标题和坐标轴标签
ax.set_title('Boxplots with Scatter Points - how2matplotlib.com')
ax.set_xlabel('Data Sets')
ax.set_ylabel('Values')
# 显示图形
plt.show()
Output:
在这个例子中,我们不仅绘制了箱线图,还在每个箱线图旁边添加了对应的散点图。这样可以同时展示数据的分布和个体数据点。
4.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()
# 绘制箱线图
bplot = ax.boxplot([data1, data2, data3], patch_artist=True)
# 设置箱体颜色
colors = ['pink', 'lightblue', 'lightgreen']
for patch, color in zip(bplot['boxes'], colors):
patch.set_facecolor(color)
# 计算均值
means = [np.mean(data) for data in [data1, data2, data3]]
# 添加图例(包含均值信息)
legend_labels = [f'Data {i+1} (Mean: {mean:.2f})' for i, mean in enumerate(means)]
ax.legend([bplot["boxes"][0], bplot["boxes"][1], bplot["boxes"][2]],
legend_labels,
loc='upper right')
# 设置标题
ax.set_title('Boxplots with Mean in Legend - how2matplotlib.com')
# 显示图形
plt.show()
Output:
在这个例子中,我们计算了每个数据集的均值,并将这些信息包含在图例标签中。这样可以在图例中提供更多有用的统计信息。
4.3 自定义箱线图样式
我们可以进一步自定义箱线图的样式,以使其更加美观或更符合特定的设计需求。
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()
# 自定义箱线图样式
boxprops = dict(linestyle='--', linewidth=2, color='black')
flierprops = dict(marker='o', markerfacecolor='red', markersize=8,
linestyle='none')
medianprops = dict(linestyle='-', linewidth=2.5, color='white')
meanpointprops = dict(marker='D', markeredgecolor='black',
markerfacecolor='firebrick')
# 绘制箱线图
bplot = ax.boxplot([data1, data2, data3], patch_artist=True,
boxprops=boxprops, flierprops=flierprops,
medianprops=medianprops, meanprops=meanpointprops,
showmeans=True)
# 设置箱体颜色
colors = ['pink', 'lightblue', 'lightgreen']
for patch, color in zip(bplot['boxes'], colors):
patch.set_facecolor(color)
# 添加图例
ax.legend([bplot["boxes"][0], bplot["boxes"][1], bplot["boxes"][2]],
['Data 1', 'Data 2', 'Data 3'],
loc='upper right')
# 设置标题
ax.set_title('Customized Boxplots - how2matplotlib.com')
# 显示图形
plt.show()
Output:
在这个例子中,我们自定义了箱线图的多个元素,包括箱体、异常值、中位数线和均值点的样式。这种高度自定义的方法可以让你的箱线图更加独特和富有表现力。
4.4 添加水平箱线图
有时,水平方向的箱线图可能更适合某些数据的展示。我们可以轻松地将垂直箱线图转换为水平箱线图。
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()
# 绘制水平箱线图
bplot = ax.boxplot([data1, data2, data3], patch_artist=True, vert=False)
# 设置箱体颜色
colors = ['pink', 'lightblue', 'lightgreen']
for patch, color in zip(bplot['boxes'], colors):
patch.set_facecolor(color)
# 添加图例
ax.legend([bplot["boxes"][0], bplot["boxes"][1], bplot["boxes"][2]],
['Data 1', 'Data 2', 'Data 3'],
loc='lower right')
# 设置标题和标签
ax.set_title('Horizontal Boxplots - how2matplotlib.com')
ax.set_xlabel('Values')
ax.set_yticklabels(['Data 1', 'Data 2', 'Data 3'])
# 显示图形
plt.show()
Output:
在这个例子中,我们通过设置vert=False
参数来创建水平方向的箱线图。这种布局在某些情况下可能更适合数据的展示,特别是当你有较长的标签或者想要强调数值范围时。
4.5 添加子图
当我们需要比较多组数据时,可以考虑使用子图来组织多个箱线图。
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
data4 = np.random.randn(100) * 2
# 创建2x2的子图
fig, axs = plt.subplots(2, 2, figsize=(12, 10))
# 在每个子图中绘制箱线图
for ax, data in zip(axs.flat, [data1, data2, data3, data4]):
bplot = ax.boxplot(data, patch_artist=True)
bplot['boxes'][0].set_facecolor('lightblue')
ax.set_title(f'Subplot - how2matplotlib.com')
# 添加总标题
fig.suptitle('Multiple Boxplots in Subplots', fontsize=16)
# 调整子图之间的间距
plt.tight_layout()
# 显示图形
plt.show()
Output:
这个例子展示了如何在2×2的网格中创建多个子图,每个子图包含一个箱线图。这种方法适用于需要同时比较多个独立数据集的情况。
4.6 添加violin图
Violin图是箱线图的一种变体,它可以更详细地显示数据分布。我们可以将箱线图和violin图结合起来。
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()
# 绘制violin图
vplot = ax.violinplot([data1, data2, data3], showmeans=False, showmedians=False)
# 设置violin图颜色
colors = ['pink', 'lightblue', 'lightgreen']
for body, color in zip(vplot['bodies'], colors):
body.set_facecolor(color)
body.set_edgecolor('black')
body.set_alpha(0.7)
# 绘制箱线图
bplot = ax.boxplot([data1, data2, data3], patch_artist=True, widths=0.1)
# 设置箱体颜色
for patch, color in zip(bplot['boxes'], colors):
patch.set_facecolor(color)
patch.set_alpha(0.8)
# 添加图例
ax.legend([vplot['bodies'][0], vplot['bodies'][1], vplot['bodies'][2]],
['Data 1', 'Data 2', 'Data 3'],
loc='upper right')
# 设置标题和标签
ax.set_title('Violin Plots with Boxplots - how2matplotlib.com')
ax.set_xlabel('Data Sets')
ax.set_ylabel('Values')
# 显示图形
plt.show()
Output:
这个例子展示了如何将violin图和箱线图结合在一起。Violin图可以显示数据的概率密度,而箱线图则提供了关键统计信息的快速概览。
5. 处理大量数据集
当我们需要处理大量数据集时,手动创建每个箱线图可能会变得繁琐。在这种情况下,我们可以使用循环来自动化这个过程。
import matplotlib.pyplot as plt
import numpy as np
# 生成多个数据集
num_datasets = 10
all_data = [np.random.randn(100) + i for i in range(num_datasets)]
# 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(12, 6))
# 绘制多个箱线图
bplot = ax.boxplot(all_data, patch_artist=True)
# 设置箱体颜色
colors = plt.cm.rainbow(np.linspace(0, 1, num_datasets))
for patch, color in zip(bplot['boxes'], colors):
patch.set_facecolor(color)
# 创建图例
legend_elements = [plt.Rectangle((0,0),1,1, facecolor=color, edgecolor='black')
for color in colors]
ax.legend(legend_elements, [f'Data {i+1}' for i in range(num_datasets)],
loc='upper right', ncol=2)
# 设置标题和标签
ax.set_title('Multiple Boxplots - how2matplotlib.com')
ax.set_xlabel('Data Sets')
ax.set_ylabel('Values')
# 显示图形
plt.show()
Output:
这个例子展示了如何处理大量数据集。我们使用循环生成多个数据集,并使用颜色映射来为每个箱线图分配不同的颜色。图例被分成两列以节省空间。
6. 自定义图例
有时,默认的图例可能不能满足我们的需求。我们可以进一步自定义图例的外观和位置。
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()
# 绘制箱线图
bplot = ax.boxplot([data1, data2, data3], patch_artist=True)
# 设置箱体颜色
colors = ['pink', 'lightblue', 'lightgreen']
for patch, color in zip(bplot['boxes'], colors):
patch.set_facecolor(color)
# 创建自定义图例
legend_elements = [plt.Rectangle((0,0),1,1, facecolor=color, edgecolor='black') for color in colors]
legend = ax.legend(legend_elements, ['Data 1', 'Data 2', 'Data 3'],
loc='upper right', title='Data Sets',
fancybox=True, shadow=True)
# 自定义图例标题
legend.get_title().set_fontweight('bold')
# 设置标题
ax.set_title('Boxplots with Custom Legend - how2matplotlib.com')
# 显示图形
plt.show()
Output:
在这个例子中,我们创建了一个带有阴影和圆角的自定义图例,并为图例添加了粗体标题。这种自定义可以让图例更加突出和美观。
7. 添加统计注释
有时,我们可能想要在图表上直接显示一些统计信息,比如均值或中位数。
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()
# 绘制箱线图
bplot = ax.boxplot([data1, data2, data3], patch_artist=True)
# 设置箱体颜色
colors = ['pink', 'lightblue', 'lightgreen']
for patch, color in zip(bplot['boxes'], colors):
patch.set_facecolor(color)
# 添加图例
ax.legend([bplot["boxes"][0], bplot["boxes"][1], bplot["boxes"][2]],
['Data 1', 'Data 2', 'Data 3'],
loc='upper right')
# 添加统计注释
for i, data in enumerate([data1, data2, data3], start=1):
mean = np.mean(data)
median = np.median(data)
ax.text(i, ax.get_ylim()[1], f'Mean: {mean:.2f}\nMedian: {median:.2f}',
horizontalalignment='center', verticalalignment='bottom')
# 设置标题
ax.set_title('Boxplots with Statistical Annotations - how2matplotlib.com')
# 显示图形
plt.show()
Output:
这个例子展示了如何在每个箱线图上方添加均值和中位数的注释。这种方法可以直接在图表上提供重要的统计信息,而不需要查看单独的图例或数据表。
8. 结合其他图表类型
有时,将箱线图与其他类型的图表结合可以提供更全面的数据视图。
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()
# 绘制箱线图
bplot = ax.boxplot([data1, data2, data3], patch_artist=True, positions=[1, 2, 3])
# 设置箱体颜色
colors = ['pink', 'lightblue', 'lightgreen']
for patch, color in zip(bplot['boxes'], colors):
patch.set_facecolor(color)
# 添加散点图
for i, data in enumerate([data1, data2, data3], start=1):
x = np.random.normal(i, 0.04, len(data))
ax.scatter(x, data, alpha=0.3)
# 添加均值点
means = [np.mean(data) for data in [data1, data2, data3]]
ax.plot([1, 2, 3], means, 'ro-', linewidth=2, markersize=8, label='Mean')
# 添加图例
ax.legend([bplot["boxes"][0], bplot["boxes"][1], bplot["boxes"][2], ax.get_lines()[-1]],
['Data 1', 'Data 2', 'Data 3', 'Mean'],
loc='upper right')
# 设置标题和标签
ax.set_title('Boxplots with Scatter and Mean - how2matplotlib.com')
ax.set_xlabel('Data Sets')
ax.set_ylabel('Values')
# 显示图形
plt.show()
Output:
这个例子展示了如何将箱线图、散点图和均值线结合在一起。这种组合可以同时显示数据的分布、个体数据点和中心趋势,提供了数据的全面视图。
9. 结论
在本文中,我们详细探讨了如何在Matplotlib中为多个箱线图添加图例。我们从基本的箱线图开始,逐步深入到更复杂的可视化技术。我们学习了如何创建自定义图例、使用不同的图例样式、组合多种图表类型,以及处理大量数据集。
通过这些技巧,你可以创建更加信息丰富、视觉上更具吸引力的箱线图。记住,好的数据可视化不仅仅是展示数据,还要讲述数据背后的故事。通过适当地使用图例和其他视觉元素,你可以使你的箱线图更加清晰、易懂,并更有效地传达你的数据洞察。
在实际应用中,请根据你的具体需求和数据特性来选择最合适的方法。不要忘记考虑你的目标受众,确保你的可视化既美观又易于理解。随着练习和经验的积累,你将能够创建出既专业又富有洞察力的数据可视化作品。