如何通过两个变量设置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")
第二步:编写自定义箱线图绘制函数
为了避免重复代码(你要画两个子图),我把绘图逻辑封装成一个函数,核心做了这几件事:
- 给数据新增
group列,把G和C的组合作为独立分组,这样Seaborn会为每个组合生成一个箱体 - 用这个新分组绘制箱线图,确保同一
G的箱体颜色一致 - 遍历每个箱体,根据
C的值设置填充样式(C1实心,C2空心) - 自定义图例,把颜色(对应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
相关产品推荐
相关产品推荐

