Matplotlib中如何在同一坐标轴上绘制两个箱线图

Matplotlib中如何在同一坐标轴上绘制两个箱线图

参考:Combining Two Boxplots With the Same Axes

箱线图是一种用于展示数据分布情况的统计图表,它可以直观地显示出一组数据的中位数、四分位数范围、异常值等重要统计信息。在数据分析和可视化中,我们经常需要比较不同组或条件下的数据分布。Matplotlib作为Python中最流行的绘图库之一,提供了强大的功能来创建和自定义箱线图。本文将详细介绍如何在Matplotlib中在同一坐标轴上绘制两个箱线图,以便进行直观的数据比较和分析。

1. 箱线图的基本概念

在深入探讨如何在同一坐标轴上绘制两个箱线图之前,我们先来回顾一下箱线图的基本概念。

箱线图,也称为盒须图,是一种用作显示一组数据分散情况资料的统计图。它能显示出一组数据的最大值、最小值、中位数、下四分位数及上四分位数。

箱线图的主要组成部分包括:

  1. 箱体:表示数据的四分位范围,即从第一四分位数(Q1)到第三四分位数(Q3)。
  2. 中位线:表示数据的中位数。
  3. 须线:从箱体延伸出去,通常延伸到最小和最大的非异常值。
  4. 异常值:位于须线之外的数据点,通常用单独的标记表示。

下面是一个简单的示例,展示如何使用Matplotlib创建一个基本的箱线图:

import matplotlib.pyplot as plt
import numpy as np

# 生成示例数据
np.random.seed(42)
data = np.random.normal(100, 20, 200)

# 创建箱线图
plt.figure(figsize=(8, 6))
plt.boxplot(data)
plt.title('Basic Boxplot Example - how2matplotlib.com')
plt.ylabel('Values')
plt.show()

Output:

Matplotlib中如何在同一坐标轴上绘制两个箱线图

在这个例子中,我们首先导入了必要的库(Matplotlib和NumPy)。然后,我们生成了一组随机数据,并使用plt.boxplot()函数创建了一个简单的箱线图。plt.title()plt.ylabel()函数用于添加标题和Y轴标签。

2. 在同一坐标轴上绘制两个箱线图的基本方法

现在,让我们来看看如何在同一坐标轴上绘制两个箱线图。这种方法通常用于比较两组数据的分布情况。

以下是一个基本示例:

import matplotlib.pyplot as plt
import numpy as np

# 生成两组示例数据
np.random.seed(42)
data1 = np.random.normal(100, 20, 200)
data2 = np.random.normal(90, 25, 200)

# 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(10, 6))

# 在同一坐标轴上绘制两个箱线图
bp1 = ax.boxplot(data1, positions=[1], widths=0.6)
bp2 = ax.boxplot(data2, positions=[2], widths=0.6)

# 设置坐标轴标签和标题
ax.set_ylabel('Values')
ax.set_title('Two Boxplots on the Same Axes - how2matplotlib.com')
ax.set_xticks([1, 2])
ax.set_xticklabels(['Data 1', 'Data 2'])

plt.show()

Output:

Matplotlib中如何在同一坐标轴上绘制两个箱线图

在这个例子中,我们首先生成了两组随机数据。然后,我们使用plt.subplots()创建了一个图形和坐标轴对象。接下来,我们使用ax.boxplot()函数分别绘制两个箱线图,通过设置positions参数来控制每个箱线图的位置。最后,我们设置了坐标轴标签和标题,并自定义了X轴刻度标签。

3. 自定义箱线图的样式

Matplotlib提供了多种方式来自定义箱线图的样式,使其更具可读性和美观性。以下是一些常用的自定义选项:

3.1 更改箱体颜色

我们可以通过设置patch_artist参数和boxprops来更改箱体的颜色:

import matplotlib.pyplot as plt
import numpy as np

np.random.seed(42)
data1 = np.random.normal(100, 20, 200)
data2 = np.random.normal(90, 25, 200)

fig, ax = plt.subplots(figsize=(10, 6))

bp1 = ax.boxplot(data1, positions=[1], widths=0.6, patch_artist=True,
                 boxprops=dict(facecolor="lightblue", color="blue"))
bp2 = ax.boxplot(data2, positions=[2], widths=0.6, patch_artist=True,
                 boxprops=dict(facecolor="lightgreen", color="green"))

ax.set_ylabel('Values')
ax.set_title('Customized Boxplots - how2matplotlib.com')
ax.set_xticks([1, 2])
ax.set_xticklabels(['Data 1', 'Data 2'])

plt.show()

Output:

Matplotlib中如何在同一坐标轴上绘制两个箱线图

在这个例子中,我们设置了patch_artist=True,并使用boxprops参数来指定箱体的填充颜色(facecolor)和边框颜色(color)。

3.2 自定义须线样式

我们可以通过设置whiskerprops来自定义须线的样式:

import matplotlib.pyplot as plt
import numpy as np

np.random.seed(42)
data1 = np.random.normal(100, 20, 200)
data2 = np.random.normal(90, 25, 200)

fig, ax = plt.subplots(figsize=(10, 6))

bp1 = ax.boxplot(data1, positions=[1], widths=0.6,
                 whiskerprops=dict(linestyle="--", color="blue"))
bp2 = ax.boxplot(data2, positions=[2], widths=0.6,
                 whiskerprops=dict(linestyle="-.", color="green"))

ax.set_ylabel('Values')
ax.set_title('Customized Whiskers - how2matplotlib.com')
ax.set_xticks([1, 2])
ax.set_xticklabels(['Data 1', 'Data 2'])

plt.show()

Output:

Matplotlib中如何在同一坐标轴上绘制两个箱线图

在这个例子中,我们使用whiskerprops参数来设置须线的样式(linestyle)和颜色(color)。

3.3 自定义中位线样式

我们可以通过设置medianprops来自定义中位线的样式:

import matplotlib.pyplot as plt
import numpy as np

np.random.seed(42)
data1 = np.random.normal(100, 20, 200)
data2 = np.random.normal(90, 25, 200)

fig, ax = plt.subplots(figsize=(10, 6))

bp1 = ax.boxplot(data1, positions=[1], widths=0.6,
                 medianprops=dict(color="red", linewidth=2))
bp2 = ax.boxplot(data2, positions=[2], widths=0.6,
                 medianprops=dict(color="purple", linewidth=2))

ax.set_ylabel('Values')
ax.set_title('Customized Median Lines - how2matplotlib.com')
ax.set_xticks([1, 2])
ax.set_xticklabels(['Data 1', 'Data 2'])

plt.show()

Output:

Matplotlib中如何在同一坐标轴上绘制两个箱线图

在这个例子中,我们使用medianprops参数来设置中位线的颜色(color)和线宽(linewidth)。

4. 添加数据点和统计信息

除了基本的箱线图,我们还可以添加额外的信息来增强数据的可视化效果。

4.1 在箱线图上叠加数据点

我们可以使用ax.scatter()函数在箱线图上叠加原始数据点:

import matplotlib.pyplot as plt
import numpy as np

np.random.seed(42)
data1 = np.random.normal(100, 20, 200)
data2 = np.random.normal(90, 25, 200)

fig, ax = plt.subplots(figsize=(10, 6))

bp1 = ax.boxplot(data1, positions=[1], widths=0.6)
bp2 = ax.boxplot(data2, positions=[2], widths=0.6)

# 添加数据点
ax.scatter(np.random.normal(1, 0.04, len(data1)), data1, alpha=0.4)
ax.scatter(np.random.normal(2, 0.04, len(data2)), data2, alpha=0.4)

ax.set_ylabel('Values')
ax.set_title('Boxplots with Data Points - how2matplotlib.com')
ax.set_xticks([1, 2])
ax.set_xticklabels(['Data 1', 'Data 2'])

plt.show()

Output:

Matplotlib中如何在同一坐标轴上绘制两个箱线图

在这个例子中,我们使用ax.scatter()函数来添加数据点。我们稍微调整了点的X坐标,使其在箱线图周围随机分布,以避免重叠。

4.2 添加均值点

我们可以在箱线图上添加均值点来提供额外的统计信息:

import matplotlib.pyplot as plt
import numpy as np

np.random.seed(42)
data1 = np.random.normal(100, 20, 200)
data2 = np.random.normal(90, 25, 200)

fig, ax = plt.subplots(figsize=(10, 6))

bp1 = ax.boxplot(data1, positions=[1], widths=0.6)
bp2 = ax.boxplot(data2, positions=[2], widths=0.6)

# 添加均值点
ax.scatter(1, np.mean(data1), marker='D', color='red', s=100, label='Mean')
ax.scatter(2, np.mean(data2), marker='D', color='red', s=100)

ax.set_ylabel('Values')
ax.set_title('Boxplots with Mean Points - how2matplotlib.com')
ax.set_xticks([1, 2])
ax.set_xticklabels(['Data 1', 'Data 2'])
ax.legend()

plt.show()

Output:

Matplotlib中如何在同一坐标轴上绘制两个箱线图

在这个例子中,我们使用ax.scatter()函数添加了均值点,并使用不同的标记和颜色使其突出显示。

5. 处理多组数据

当我们需要比较多于两组的数据时,可以使用以下方法:

5.1 使用循环创建多个箱线图

import matplotlib.pyplot as plt
import numpy as np

np.random.seed(42)
data = [np.random.normal(100, 20, 200),
        np.random.normal(90, 25, 200),
        np.random.normal(110, 15, 200),
        np.random.normal(95, 30, 200)]

fig, ax = plt.subplots(figsize=(12, 6))

positions = range(1, len(data) + 1)
bp = ax.boxplot(data, positions=positions, widths=0.6)

ax.set_ylabel('Values')
ax.set_title('Multiple Boxplots - how2matplotlib.com')
ax.set_xticks(positions)
ax.set_xticklabels([f'Data {i}' for i in positions])

plt.show()

Output:

Matplotlib中如何在同一坐标轴上绘制两个箱线图

在这个例子中,我们创建了一个包含多组数据的列表,然后使用单个boxplot()调用来创建多个箱线图。

5.2 使用pandas创建分组箱线图

如果我们的数据存储在pandas DataFrame中,我们可以使用pandas的绘图功能来创建分组箱线图:

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

np.random.seed(42)
df = pd.DataFrame({
    'group': np.repeat(['A', 'B', 'C', 'D'], 200),
    'values': np.concatenate([
        np.random.normal(100, 20, 200),
        np.random.normal(90, 25, 200),
        np.random.normal(110, 15, 200),
        np.random.normal(95, 30, 200)
    ])
})

fig, ax = plt.subplots(figsize=(12, 6))
df.boxplot(column='values', by='group', ax=ax)

ax.set_ylabel('Values')
ax.set_title('Grouped Boxplot using Pandas - how2matplotlib.com')

plt.show()

Output:

Matplotlib中如何在同一坐标轴上绘制两个箱线图

在这个例子中,我们首先创建了一个包含分组信息和值的DataFrame,然后使用pandas的boxplot()方法来创建分组箱线图。

6. 高级定制技巧

6.1 添加标注

我们可以在箱线图上添加文本标注来突出显示重要信息:

import matplotlib.pyplot as plt
import numpy as np

np.random.seed(42)
data1 = np.random.normal(100, 20, 200)
data2 = np.random.normal(90, 25, 200)

fig, ax = plt.subplots(figsize=(10, 6))

bp1 = ax.boxplot(data1, positions=[1], widths=0.6)
bp2 = ax.boxplot(data2, positions=[2], widths=0.6)

# 添加标注
ax.annotate(f'Median: {np.median(data1):.2f}', xy=(1, np.median(data1)),
            xytext=(1.2, np.median(data1) + 10),
            arrowprops=dict(facecolor='black', shrink=0.05))

ax.annotate(f'Median: {np.median(data2):.2f}', xy=(2, np.median(data2)),
            xytext=(2.2, np.median(data2) - 10),
            arrowprops=dict(facecolor='black', shrink=0.05))

ax.set_ylabel('Values')
ax.set_title('Boxplots with Annotations - how2matplotlib.com')
ax.set_xticks([1, 2])
ax.set_xticklabels(['Data 1', 'Data 2'])

plt.show()

Output:

Matplotlib中如何在同一坐标轴上绘制两个箱线图

在这个例子中,我们使用ax.annotate()函数为每个箱线图添加了中位数的标注。我们指定了标注的位置、文本内容和箭头样式。

6.2 自定义异常值标记

我们可以自定义异常值的标记样式:

import matplotlib.pyplot as plt
import numpy as np

np.random.seed(42)
data1 = np.random.normal(100, 20, 200)
data2 = np.random.normal(90, 25, 200)

fig, ax = plt.subplots(figsize=(10, 6))

bp1 = ax.boxplot(data1, positions=[1], widths=0.6,
                 flierprops=dict(marker='o', markerfacecolor='red', markersize=8,
                                 linestyle='none'))
bp2 = ax.boxplot(data2, positions=[2], widths=0.6,
                 flierprops=dict(marker='s', markerfacecolor='green', markersize=8,
                                 linestyle='none'))

ax.set_ylabel('Values')
ax.set_title('Customized Outlier Markers - how2matplotlib.com')
ax.set_xticks([1, 2])
ax.set_xticklabels(['Data 1', 'Data 2'])

plt.show()

Output:

Matplotlib中如何在同一坐标轴上绘制两个箱线图

在这个例子中,我们使用flierprops参数来自定义异常值的标记样式,包括标记形状、颜色和大小。

6.3 添加水平参考线

我们可以添加水平参考线来帮助比较不同组的数据:

import matplotlib.pyplot as plt
import numpy as np

np.random.seed(42)
data1 = np.random.normal(100, 20, 200)
data2 = np.random.normal(90, 25, 200)

fig, ax = plt.subplots(figsize=(10, 6))

bp1 = ax.boxplot(data1, positions=[1], widths=0.6)
bp2 = ax.boxplot(data2, positions=[2], widths=0.6)

# 添加水平参考线
ax.axhline(y=np.mean([np.mean(data1), np.mean(data2)]), color='r', linestyle='--', label='Overall Mean')

ax.set_ylabel('Values')
ax.set_title('Boxplots with Reference Line - how2matplotlib.com')
ax.set_xticks([1, 2])
ax.set_xticklabels(['Data 1', 'Data 2'])
ax.legend()

plt.show()

Output:

Matplotlib中如何在同一坐标轴上绘制两个箱线图

在这个例子中,我们使用ax.axhline()函数添加了一条表示总体平均值的水平参考线。

7. 处理特殊情况

7.1 处理空数据或异常数据

在实际应用中,我们可能会遇到空数据或异常数据的情况。以下是一个处理这些情况的示例:

import matplotlib.pyplot as plt
import numpy as np

np.random.seed(42)
data1 = np.random.normal(100, 20, 200)
data2 = []  # 空数据
data3 = [np.nan, 1, 2, 3, np.inf, -np.inf]  # 包含异常值的数据

fig, ax = plt.subplots(figsize=(12, 6))

bp1 = ax.boxplot(data1, positions=[1], widths=0.6)
bp2 = ax.boxplot(data2, positions=[2], widths=0.6)
bp3 = ax.boxplot(data3, positions=[3], widths=0.6)

ax.set_ylabel('Values')
ax.set_title('Handling Special Cases - how2matplotlib.com')
ax.set_xticks([1, 2, 3])
ax.set_xticklabels(['Normal Data', 'Empty Data', 'Abnormal Data'])

plt.show()

Output:

Matplotlib中如何在同一坐标轴上绘制两个箱线图

在这个例子中,我们展示了如何处理正常数据、空数据和包含异常值的数据。Matplotlib会自动处理这些特殊情况,对于空数据会显示一个空的箱线图,对于包含异常值的数据会忽略无效值。

7.2 处理不同尺度的数据

当我们需要比较不同尺度的数据时,可以使用对数刻度或双Y轴:

import matplotlib.pyplot as plt
import numpy as np

np.random.seed(42)
data1 = np.random.normal(100, 20, 200)
data2 = np.random.normal(1000000, 200000, 200)

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))

# 使用对数刻度
bp1 = ax1.boxplot([data1, data2], positions=[1, 2], widths=0.6)
ax1.set_yscale('log')
ax1.set_title('Using Log Scale - how2matplotlib.com')
ax1.set_xticks([1, 2])
ax1.set_xticklabels(['Data 1', 'Data 2'])

# 使用双Y轴
bp2_1 = ax2.boxplot(data1, positions=[1], widths=0.6)
ax2.set_ylabel('Data 1 Values')
ax2.set_title('Using Twin Axes - how2matplotlib.com')

ax2_twin = ax2.twinx()
bp2_2 = ax2_twin.boxplot(data2, positions=[2], widths=0.6)
ax2_twin.set_ylabel('Data 2 Values')

ax2.set_xticks([1, 2])
ax2.set_xticklabels(['Data 1', 'Data 2'])

plt.tight_layout()
plt.show()

Output:

Matplotlib中如何在同一坐标轴上绘制两个箱线图

在这个例子中,我们展示了两种处理不同尺度数据的方法:使用对数刻度和使用双Y轴。

8. 结合其他图表类型

我们可以将箱线图与其他类型的图表结合,以提供更全面的数据可视化:

8.1 箱线图与小提琴图结合

import matplotlib.pyplot as plt
import numpy as np

np.random.seed(42)
data1 = np.random.normal(100, 20, 200)
data2 = np.random.normal(90, 25, 200)

fig, ax = plt.subplots(figsize=(10, 6))

parts1 = ax.violinplot(data1, positions=[1], showmeans=False, showmedians=False, showextrema=False)
parts2 = ax.violinplot(data2, positions=[2], showmeans=False, showmedians=False, showextrema=False)

for pc in parts1['bodies']:
    pc.set_facecolor('lightblue')
    pc.set_edgecolor('blue')
    pc.set_alpha(0.7)

for pc in parts2['bodies']:
    pc.set_facecolor('lightgreen')
    pc.set_edgecolor('green')
    pc.set_alpha(0.7)

bp1 = ax.boxplot(data1, positions=[1], widths=0.15, patch_artist=True,
                 boxprops=dict(facecolor="white", edgecolor="blue"))
bp2 = ax.boxplot(data2, positions=[2], widths=0.15, patch_artist=True,
                 boxprops=dict(facecolor="white", edgecolor="green"))

ax.set_ylabel('Values')
ax.set_title('Boxplots with Violin Plots - how2matplotlib.com')
ax.set_xticks([1, 2])
ax.set_xticklabels(['Data 1', 'Data 2'])

plt.show()

Output:

Matplotlib中如何在同一坐标轴上绘制两个箱线图

在这个例子中,我们将箱线图和小提琴图结合在一起,提供了更丰富的数据分布信息。

8.2 箱线图与散点图结合

import matplotlib.pyplot as plt
import numpy as np

np.random.seed(42)
data1 = np.random.normal(100, 20, 200)
data2 = np.random.normal(90, 25, 200)

fig, ax = plt.subplots(figsize=(10, 6))

bp1 = ax.boxplot(data1, positions=[1], widths=0.6)
bp2 = ax.boxplot(data2, positions=[2], widths=0.6)

# 添加散点图
ax.scatter(np.random.normal(1, 0.04, len(data1)), data1, alpha=0.4, color='blue')
ax.scatter(np.random.normal(2, 0.04, len(data2)), data2, alpha=0.4, color='green')

ax.set_ylabel('Values')
ax.set_title('Boxplots with Scatter Plot - how2matplotlib.com')
ax.set_xticks([1, 2])
ax.set_xticklabels(['Data 1', 'Data 2'])

plt.show()

Output:

Matplotlib中如何在同一坐标轴上绘制两个箱线图

在这个例子中,我们将箱线图与散点图结合,既显示了数据的统计特征,又展示了原始数据点的分布。

9. 保存和导出图表

最后,让我们看看如何保存和导出我们创建的图表:

import matplotlib.pyplot as plt
import numpy as np

np.random.seed(42)
data1 = np.random.normal(100, 20, 200)
data2 = np.random.normal(90, 25, 200)

fig, ax = plt.subplots(figsize=(10, 6))

bp1 = ax.boxplot(data1, positions=[1], widths=0.6)
bp2 = ax.boxplot(data2, positions=[2], widths=0.6)

ax.set_ylabel('Values')
ax.set_title('Saving Boxplots - how2matplotlib.com')
ax.set_xticks([1, 2])
ax.set_xticklabels(['Data 1', 'Data 2'])

# 保存为PNG文件
plt.savefig('boxplots.png', dpi=300, bbox_inches='tight')

# 保存为SVG文件(矢量图)
plt.savefig('boxplots.svg', format='svg', bbox_inches='tight')

plt.show()

Output:

Matplotlib中如何在同一坐标轴上绘制两个箱线图

在这个例子中,我们使用plt.savefig()函数将图表保存为PNG和SVG格式。dpi参数控制图像的分辨率,bbox_inches='tight'参数确保图表的所有部分都包含在保存的文件中。

总结

在本文中,我们详细探讨了如何在Matplotlib中在同一坐标轴上绘制两个箱线图。我们介绍了箱线图的基本概念,展示了创建和自定义箱线图的各种方法,包括更改颜色、样式,添加数据点和统计信息,处理多组数据,以及结合其他图表类型。我们还讨论了如何处理特殊情况,如空数据和不同尺度的数据。最后,我们介绍了如何保存和导出创建的图表。

通过掌握这些技巧,你可以创建出既信息丰富又视觉吸引的箱线图,有效地比较和分析不同组的数据分布。记住,好的数据可视化不仅要准确呈现数据,还要让观众能够轻松理解和解释结果。因此,在创建箱线图时,要根据你的具体需求和目标受众来选择合适的自定义选项和附加信息。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程