图例元素过多致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
相关产品推荐
相关产品推荐

