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

如何通过两个变量设置Seaborn箱线图的颜色与填充样式

如何通过两个变量设置Seaborn箱线图的颜色与填充样式

我完全懂你想要的效果——用G变量控制箱线图的主题颜色,C变量控制箱体是实心还是空心,对吧?其实这个需求不难实现,核心思路是先把数据按G和C的组合拆分,再手动调整每个箱体的样式。结合你给的示例数据,我给你整理了一套可直接运行的方案:


第一步:准备数据与基础配置

先把你提供的示例数据和基础配置写好,和你原来的代码保持一致:

import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
from matplotlib.patches import Patch

# 你的示例数据
data1 = {'Trial': [1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2],
         'level': [20, 25, 23, 22, 7, 6, 5, 8, 46, 43, 40, 45, 11, 14, 10, 15],
         'G': ['G1', 'G1', 'G1', 'G1', 'G2', 'G2', 'G2', 'G2', 'G1', 'G1', 'G1', 'G1', 'G2', 'G2', 'G2', 'G2'],
         'C': ['C1', 'C1', 'C2', 'C2', 'C1', 'C1', 'C2', 'C2', 'C1', 'C1', 'C2', 'C2', 'C1', 'C1', 'C2', 'C2']}
df1 = pd.DataFrame(data1)

data2 = {'Trial': [1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2],
         'level': [22, 24, 23, 21, 3, 2, 4, 1, 30, 31, 29, 26, 7, 5, 9, 10],
         'G': ['G1', 'G1', 'G1', 'G1', 'G2', 'G2', 'G2', 'G2', 'G1', 'G1', 'G1', 'G1', 'G2', 'G2', 'G2', 'G2'],
         'C': ['C1', 'C1', 'C2', 'C2', 'C1', 'C1', 'C2', 'C2', 'C1', 'C1', 'C2', 'C2', 'C1', 'C1', 'C2', 'C2']}
df2 = pd.DataFrame(data2)

# 定义颜色映射和绘图风格
colors = {"G1": '#7fb5b0', "G2": '#d86fad'}
sns.set_style("ticks")

第二步:编写自定义箱线图绘制函数

为了避免重复代码(你要画两个子图),我把绘图逻辑封装成一个函数,核心做了这几件事:

  1. 给数据新增group列,把G和C的组合作为独立分组,这样Seaborn会为每个组合生成一个箱体
  2. 用这个新分组绘制箱线图,确保同一G的箱体颜色一致
  3. 遍历每个箱体,根据C的值设置填充样式(C1实心,C2空心)
  4. 自定义图例,把颜色(对应G)和填充样式(对应C)分开展示,避免冗余
def plot_custom_boxplot(ax, data, color_map):
    # 生成G和C的组合分组
    data['group'] = data['G'] + '_' + data['C']
    
    # 绘制基础箱线图:同一G的不同C组合用相同颜色
    sns.boxplot(
        x='Trial', 
        y='level', 
        hue='group', 
        data=data, 
        palette={
            'G1_C1': color_map['G1'],
            'G1_C2': color_map['G1'],
            'G2_C1': color_map['G2'],
            'G2_C2': color_map['G2']
        }, 
        ax=ax, 
        dodge=True, 
        showcaps=True
    )
    
    # 遍历每个箱体,设置填充样式
    handles, labels = ax.get_legend_handles_labels()
    for patch, label in zip(ax.patches, labels):
        g, c = label.split('_')
        if c == 'C2':
            # C2设置为空心:填充色透明,保留边框颜色并加粗
            patch.set_facecolor('none')
            patch.set_edgecolor(color_map[g])
            patch.set_linewidth(2)
        else:
            # C1设置为实心:填充色和边框色一致
            patch.set_facecolor(color_map[g])
            patch.set_edgecolor(color_map[g])
    
    # 替换默认图例,让展示更清晰
    ax.legend_.remove()
    # 颜色图例(对应G变量)
    color_legends = [
        Patch(facecolor=color_map['G1'], label='G1'),
        Patch(facecolor=color_map['G2'], label='G2')
    ]
    # 填充样式图例(对应C变量)
    fill_legends = [
        Patch(facecolor='gray', edgecolor='black', label='C1 (实心)'),
        Patch(facecolor='none', edgecolor='black', label='C2 (空心)', linewidth=2)
    ]
    # 添加两个独立图例
    leg1 = ax.legend(handles=color_legends, loc='upper left', bbox_to_anchor=(1, 1))
    ax.add_artist(leg1)
    ax.legend(handles=fill_legends, loc='upper left', bbox_to_anchor=(1, 0.8))

第三步:绘制并展示图形

最后调用函数绘制两个子图,调整布局后展示:

# 创建子图
fig, axes = plt.subplots(1, 2, figsize=(16, 6))

# 绘制两个子图
plot_custom_boxplot(axes[0], df1, colors)
plot_custom_boxplot(axes[1], df2, colors)

# 调整子图间距,避免图例和图形重叠
plt.tight_layout()
plt.show()

效果说明

运行这段代码后,你就能得到想要的效果:

  • G1的箱体都是绿色,其中C1是实心,C2是空心
  • G2的箱体都是粉色,其中C1是实心,C2是空心
  • 图例清晰区分了颜色和填充样式对应的变量

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 09:58:05