You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python中使用Matplotlib/Seaborn绘制双变量箱线图

用Matplotlib实现双向箱线图(带可变宽度水平箱线)

要实现你需要的同时包含水平/垂直须、且X轴方向箱线组件大小随数据调整的图形,本质是创建双向箱线图。Seaborn没有直接对应的函数,但可以用Matplotlib手动绘制元素,灵活控制每个组件的位置和尺寸。

以下是完整实现代码,用鸢尾花数据集做示例:

import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from matplotlib.patches import Rectangle

# 加载示例数据,按分组准备数据
df = sns.load_dataset("iris")
groups = df["species"].unique()
x_var = "sepal_length"  # X轴变量
y_var = "sepal_width"   # Y轴变量

# 预计算每个分组的箱线统计量(四分位数、极值)及X方向箱线宽度
group_stats = {}
for group in groups:
    subset = df[df["species"] == group]
    # Y方向(垂直箱线)统计:[最小值, Q1, 中位数, Q3, 最大值]
    y_percentiles = np.percentile(subset[y_var], [0, 25, 50, 75, 100])
    # X方向(水平箱线)统计
    x_percentiles = np.percentile(subset[x_var], [0, 25, 50, 75, 100])
    # 用X变量的四分位距(IQR)计算箱线宽度,缩放系数调整视觉效果
    x_iqr = x_percentiles[3] - x_percentiles[1]
    group_stats[group] = {
        "y_stats": y_percentiles,
        "x_stats": x_percentiles,
        "x_box_width": x_iqr * 0.3  # 可根据需求调整缩放比例
    }

# 创建画布
fig, ax = plt.subplots(figsize=(9, 6))
pos = np.arange(len(groups))  # 每个分组在Y轴上的位置

# 绘制垂直箱线(对应Y变量分布)
for idx, group in enumerate(groups):
    stats = group_stats[group]
    y_min, y_q1, y_med, y_q3, y_max = stats["y_stats"]
    
    # 绘制箱体
    ax.add_patch(Rectangle(
        (pos[idx] - 0.2, y_q1), 0.4, y_q3 - y_q1,
        fill=False, edgecolor="#2c3e50", linewidth=1.2
    ))
    # 中位数线
    ax.plot([pos[idx]-0.2, pos[idx]+0.2], [y_med, y_med], color="#2c3e50", linewidth=1.5)
    # 须和端点
    ax.plot([pos[idx], pos[idx]], [y_min, y_q1], color="#2c3e50")
    ax.plot([pos[idx], pos[idx]], [y_q3, y_max], color="#2c3e50")
    ax.plot([pos[idx]-0.1, pos[idx]+0.1], [y_min, y_min], color="#2c3e50")
    ax.plot([pos[idx]-0.1, pos[idx]+0.1], [y_max, y_max], color="#2c3e50")

# 绘制水平箱线(对应X变量分布,宽度随数据调整)
for idx, group in enumerate(groups):
    stats = group_stats[group]
    x_min, x_q1, x_med, x_q3, x_max = stats["x_stats"]
    box_height = stats["x_box_width"]
    
    # 绘制箱体
    ax.add_patch(Rectangle(
        (x_q1, pos[idx] - box_height), x_q3 - x_q1, box_height * 2,
        fill=False, edgecolor="#e74c3c", linewidth=1.2
    ))
    # 中位数线
    ax.plot([x_med, x_med], [pos[idx]-box_height, pos[idx]+box_height], color="#e74c3c", linewidth=1.5)
    # 须和端点
    ax.plot([x_min, x_q1], [pos[idx], pos[idx]], color="#e74c3c")
    ax.plot([x_q3, x_max], [pos[idx], pos[idx]], color="#e74c3c")
    ax.plot([x_min, x_min], [pos[idx]-0.1, pos[idx]+0.1], color="#e74c3c")
    ax.plot([x_max, x_max], [pos[idx]-0.1, pos[idx]+0.1], color="#e74c3c")

# 添加原始数据散点(带微小偏移避免重叠)
for idx, group in enumerate(groups):
    subset = df[df["species"] == group]
    # X方向散点
    ax.scatter(
        subset[x_var], pos[idx] + np.random.normal(0, 0.05, len(subset)),
        alpha=0.5, color="#95a5a6", s=20
    )
    # Y方向散点
    ax.scatter(
        pos[idx] + np.random.normal(0, 0.05, len(subset)), subset[y_var],
        alpha=0.5, color="#95a5a6", s=20
    )

# 调整坐标轴样式
ax.set_xlabel(x_var, fontsize=12)
ax.set_ylabel("Species", fontsize=12)
ax.set_yticks(pos)
ax.set_yticklabels(groups, fontsize=10)
ax.set_xlim(df[x_var].min() - 0.5, df[x_var].max() + 0.5)
ax.set_ylim(-0.5, len(groups) - 0.5)
ax.grid(axis="y", linestyle="-", alpha=0.3)
plt.tight_layout()
plt.show()

关键实现细节:

  1. 手动绘制箱体:用matplotlib.patches.Rectangle分别绘制垂直(Y变量)和水平(X变量)的箱体,避开Seaborn单方向箱线图的限制。
  2. 可变宽度控制:通过计算每个分组X变量的四分位距(IQR)来设置水平箱线的高度(对应Y轴方向的尺寸),实现“根据数据调整大小”的需求。
  3. 元素对齐:将每个分组的垂直/水平箱线对齐到同一Y轴位置,保证视觉上的对应关系。
  4. 散点偏移:给散点添加微小的随机偏移,避免数据点完全重叠,提升可读性。

内容的提问来源于stack exchange,提问作者Liam Wilson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 12:07:09