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

图例元素过多致Matplotlib子图绘图区域过小,如何调整放大?

如何放大Matplotlib子图的绘图区域(解决图例占用空间导致绘图区过小问题)

问题描述

单个子图内信号过多,图例占用大量空间,导致绘图区域高度不足、显示过小,需要放大绘图区域。

当前效果:
当前绘图效果

期望效果:
期望绘图效果

现有绘图代码

cm = 1/2.54
fig, axes = plt.subplots(nrows=len(unique_signals), ncols=1, figsize=(23.5*cm, 17.2*cm))

sig_col = filtered_df.columns[1:]
plot_counter = 0
previous_label = ""
for column in sig_col:
    signal_name = column.split('_')[0] if ':' in column else column[:-1]

    if  signal_name != previous_label or plot_counter == 0:
        ax = axes[plot_counter]
        plot_counter += 1
        ax.grid(True)

    previous_label = signal_name

    ax.plot(filtered_df['time'], filtered_df[column], label=column)

    y_min, y_max = ax.get_ylim()
    more_ext = ['Ilw1_X','Ilw2_X','IvwTrf1_X','IdcP_X','IdcN_X','Vlw2_X', 'Ilw1_Y','Ilw2_Y','IvwTrf1_Y','IdcP_Y','IdcN_Y','Vlw2_Y','Ivlv','IvlvSum','Icir','Ignd']
    percentage = 0.02 if signal_name not in more_ext else 0.2

    y_min_ext = y_min*(1-percentage) if y_min > 0 else y_min*(1+percentage)
    y_max_ext = y_max*(1+percentage) if y_max > 0 else y_max*(1-percentage)
    ax.set_ylim(y_min_ext, y_max_ext)

for ax in axes:
    ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))
plt.tight_layout()
plt.savefig(group_name.split('_')[0]+'.png', dpi=300)
plt.close()

解决方案

方法1:优化图例,释放绘图空间

当前图例放置在子图右侧,挤占了绘图区域,可通过调整图例属性减少空间占用:

  • 缩小图例字体:
    ax.legend(loc='center left', bbox_to_anchor=(1, 0.5), fontsize='x-small')
    
  • 缩短图例标记长度,让布局更紧凑:
    ax.legend(loc='center left', bbox_to_anchor=(1, 0.5), fontsize='x-small', handlelength=1)
    
  • 将图例移到子图内部空白区域(如右上角),避免占用外部空间:
    ax.legend(loc='upper right', fontsize='x-small')
    

方法2:调整画布与子图布局

  • 增大画布宽度,给图例预留独立空间,保证绘图区域宽度不变:
    fig, axes = plt.subplots(nrows=len(unique_signals), ncols=1, figsize=(28*cm, 17.2*cm))
    
  • 手动调整子图右侧留白,替代tight_layout():
    # 替换plt.tight_layout()
    plt.subplots_adjust(right=0.8)  # 右侧留20%空间给图例
    

方法3:合并同类图例

从代码逻辑看,信号按signal_name分组,可只给每组显示一个分类图例,减少图例条目:

sig_col = filtered_df.columns[1:]
plot_counter = 0
previous_label = ""
for column in sig_col:
    signal_name = column.split('_')[0] if ':' in column else column[:-1]

    if  signal_name != previous_label or plot_counter == 0:
        ax = axes[plot_counter]
        plot_counter += 1
        ax.grid(True)
        show_legend = True  # 新组显示图例
    else:
        show_legend = False  # 同组不重复显示

    previous_label = signal_name
    # 仅新组的信号添加label
    ax.plot(filtered_df['time'], filtered_df[column], label=column if show_legend else '')

    # 原有ylim调整代码不变...

# 仅给有label的子图添加图例
for ax in axes:
    handles, labels = ax.get_legend_handles_labels()
    if labels:
        ax.legend(loc='center left', bbox_to_anchor=(1, 0.5), fontsize='x-small')

方法4:使用独立图例轴

创建单独的轴放置所有图例,彻底避免挤占子图空间:

cm = 1/2.54
fig, axes = plt.subplots(nrows=len(unique_signals), ncols=1, figsize=(23.5*cm, 17.2*cm))
# 预留右侧空间,创建图例轴
fig.subplots_adjust(right=0.8)
legend_ax = fig.add_axes([0.82, 0.1, 0.15, 0.8])  # [左, 下, 宽, 高]

# 原有绘图逻辑不变...

# 收集所有图例并移到独立轴
all_handles = []
all_labels = []
for ax in axes:
    handles, labels = ax.get_legend_handles_labels()
    all_handles.extend(handles)
    all_labels.extend(labels)
    if ax.get_legend():
        ax.get_legend().remove()

legend_ax.legend(all_handles, all_labels, loc='center', fontsize='x-small')
legend_ax.axis('off')  # 隐藏图例轴边框和刻度

plt.savefig(group_name.split('_')[0]+'.png', dpi=300)
plt.close()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 18:05:31