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

如何完全移除子箱线图图例并消除残留空白?附代码优化需求

问题描述

使用matplotlib和seaborn绘制子箱线图时,执行.legend_.remove()后每个子图仍残留图例空白区域,同时希望简化现有重复代码。

原始代码:

fig, axes = plt.subplots(nrows=1, ncols=4, figsize=(18,6))   
a = sns.boxplot(data = df, ax=axes[0], x='Building', y='CDL-08', hue = 'Week', palette="Set3")
b = sns.boxplot(data = df, ax=axes[1], x='Building', y='CDL-09', hue = 'Week', palette="Set3")
c = sns.boxplot(data = df, ax=axes[2], x='Building', y='CDL-10', hue = 'Week', palette="Set3")
d = sns.boxplot(data = df, ax=axes[3], x='Building', y='CDL-11', hue = 'Week', palette="Set3")

a.legend_.remove()
b.legend_.remove()
c.legend_.remove()
d.legend_.remove()


#placing legend outside
plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)


plt.subplots_adjust(left= 0.11, bottom=0.11, right=0.9, top=0.85, wspace=0.3, hspace=0.3)

a.xaxis.label.set_visible(False)
b.xaxis.label.set_visible(False)
c.xaxis.label.set_visible(False)
d.xaxis.label.set_visible(False)

a.yaxis.label.set_visible(False)
b.yaxis.label.set_visible(False)
c.yaxis.label.set_visible(False)
d.yaxis.label.set_visible(False)

fig.text(0.5, 0.04, 'Building', ha='center', va='center', fontsize = 14)
fig.text(0.06, 0.5, 'CO2 concentration (ppm)', ha='center', va='center', rotation='vertical', fontsize = 14)

#threshold
a.axhline(y=1000, color='red', linestyle='--', linewidth = 1.5)
a.axhline(y=800, color='#8B2323', linestyle='--', linewidth = 1.5)

b.axhline(y=1000, color='red', linestyle='--', linewidth = 1.5)
b.axhline(y=800, color='#8B2323', linestyle='--', linewidth = 1.5)

c.axhline(y=1000, color='red', linestyle='--', linewidth = 1.5)
c.axhline(y=800, color='#8B2323', linestyle='--', linewidth = 1.5)

d.axhline(y=1000, color='red', linestyle='--', linewidth = 1.5)
d.axhline(y=800, color='#8B2323', linestyle='--', linewidth = 1.5)

#common title
fig.suptitle('CO2 exposures', fontsize = 18)

#title for subplots
a.set_title("Subject 01", fontsize=14)
b.set_title("Subject 02", fontsize=14)
c.set_title("Subject 03", fontsize=14)
d.set_title("Subject 04", fontsize=14)


plt.rcParams['xtick.labelsize'] = 14

min([], default="EMPTY")
# returns EMPTY

# Defining custom 'xlim' and 'ylim' values.
custom_ylim = (300, 1500)

# Setting the values for all axes.
plt.setp(axes, ylim=custom_ylim, yticks=[300, 600, 900, 1200, 1500])
a.set_yticklabels([300, 600, 900, 1200, 1500], fontsize=15)
b.set_yticklabels([300, 600, 900, 1200, 1500], fontsize=15)
c.set_yticklabels([300, 600, 900, 1200, 1500], fontsize=15)
d.set_yticklabels([300, 600, 900, 1200, 1500], fontsize=15)

plt.show()

附图:
图例残留空白

问题原因
  1. 使用sns.boxplot时指定hue参数,seaborn会自动为每个子图预留图例布局空间,仅调用.legend_.remove()只能删除图例元素,无法收回预留的空白区域。
  2. 后续执行plt.legend()创建全局图例,但未解决子图预留空间的问题,导致空白依然存在。
  3. 原始代码存在大量重复操作,如重复绘制水平线、重复设置轴标签可见性等,代码冗余且不易维护。
解决方案与简化代码

核心优化措施

  • 绘制箱线图时直接通过legend=False禁用图例创建,从根源避免子图预留空白空间
  • 采用循环批量处理所有子图,消除重复代码
  • 提取公共配置(如水平线、轴范围、刻度样式)统一设置
  • 基于子图的图例手柄和标签创建全局图例,保证样式与箱线图一致

简化后的代码:

import matplotlib.pyplot as plt
import seaborn as sns

# 初始化画布
fig, axes = plt.subplots(nrows=1, ncols=4, figsize=(18, 6))

# 定义子图相关配置参数
y_columns = ['CDL-08', 'CDL-09', 'CDL-10', 'CDL-11']
subplot_titles = ["Subject 01", "Subject 02", "Subject 03", "Subject 04"]
custom_ylim = (300, 1500)
ytick_values = [300, 600, 900, 1200, 1500]

# 循环批量绘制子图
for ax, y_col, title in zip(axes, y_columns, subplot_titles):
    # 绘制箱线图时禁用图例,避免预留空间
    sns.boxplot(data=df, ax=ax, x='Building', y=y_col, hue='Week', palette="Set3", legend=False)
    # 添加阈值水平线
    ax.axhline(y=1000, color='red', linestyle='--', linewidth=1.5)
    ax.axhline(y=800, color='#8B2323', linestyle='--', linewidth=1.5)
    # 设置子图标题
    ax.set_title(title, fontsize=14)
    # 隐藏子图自身的轴标签
    ax.set_xlabel('')
    ax.set_ylabel('')
    # 统一设置y轴范围和刻度
    ax.set_ylim(custom_ylim)
    ax.set_yticks(ytick_values)
    ax.set_yticklabels(ytick_values, fontsize=15)

# 创建全局图例(基于第一个子图的图例数据,保证样式匹配)
handles, labels = axes[0].get_legend_handles_labels()
fig.legend(handles, labels, bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)

# 设置全局标题和轴标签
fig.suptitle('CO2 exposures', fontsize=18)
fig.text(0.5, 0.04, 'Building', ha='center', va='center', fontsize=14)
fig.text(0.06, 0.5, 'CO2 concentration (ppm)', ha='center', va='center', rotation='vertical', fontsize=14)

# 调整全局样式和子图间距
plt.rcParams['xtick.labelsize'] = 14
plt.subplots_adjust(left=0.11, bottom=0.11, right=0.85, top=0.85, wspace=0.3)

plt.show()

效果说明

  • 彻底消除子图中的图例空白区域,布局更紧凑合理
  • 代码结构清晰,重复操作全部通过循环批量处理,便于后续修改和扩展
  • 全局图例样式与箱线图保持一致,视觉效果统一

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 05:50:50