Python Matplotlib绘制多子图详解:图例合并与间距调整

一颗松果
一颗松果
发布时间:2026-10-12| 2人浏览过
原创

本文详解Python Matplotlib中多子图的绘制方法,重点讲解如何通过遍历子图句柄合并分散的图例,以及利用subplots_adjust函数精确控制子图间的水平与垂直间距,帮助读者优化图表布局与可读性。

在绘制包含多个子图的图表时,我们通常希望将各个子图中的图例合并为一个统一的图例,以便更清晰地展示数据。这可以通过获取每个子图的标签(label)和线条样式(line style),然后将它们整合到一个总图例中来实现。

实现这一功能的关键在于,在创建每个子图的曲线时,必须显式地添加label参数。只有设置了label,后续才能通过get_legend_handles_labels()方法提取出对应的图例元素。

#导入数据(读者可忽略)
pre_lp=total_res#组合模型
true=diff1[-pre_day:]#真实值
pre_ph=results_data["yhat"]#prophet
pre_lstm=reslut#lstm
pre_ari=data_ari['data_pre']#arima
#设置中文字体
rcParams['font.sans-serif'] = 'kaiti'

# 生成一个时间序列 (读者可根据情况进行修改或删除)
time =pd.to_datetime(np.arange(0,21), unit='D',
                    origin=pd.Timestamp('2021-10-19'))
#创建画布
fig=plt.figure(figsize=(20,16))#figsize为画布大小
# 1 
ax1=fig.add_subplot(221)
ax1.plot(time,pre_lp,color='#1bb9f6',marker='^',linestyle='-',label='1')
# ax1.plot(time,true,color='#fd5749',marker='s',linestyle='-',label='true')
ax1.set_title('1',fontsize=15)#设置标题
ax1.set_xlabel('日期/天',fontsize=15)#设置横坐标名称
ax1.set_ylabel('感染人数/人',fontsize=15)#设置纵坐标名称
ax1.xaxis.set_major_formatter(mdate.DateFormatter('%m-%d'))#设置横坐标刻度(读者可忽略)
plt.xticks(pd.date_range(time[0],time[-1],freq='D'),rotation=45)#设置横坐标刻度(读者可忽略)

# 2 
ax2=fig.add_subplot(222)
ax2.plot(time,pre_ph,color='#739b06',marker='o',linestyle='-',label='2')
# ax2.plot(time,true,color='#fd5749',marker='s',linestyle='-',label='true')
ax2.set_title('2',fontsize=15)
ax2.set_xlabel('日期/天',fontsize=15)
ax2.set_ylabel('感染人数/人',fontsize=15)
ax2.xaxis.set_major_formatter(mdate.DateFormatter('%m-%d'))
plt.xticks(pd.date_range(time[0],time[-1],freq='D'),rotation=45)
# 3 
ax3=fig.add_subplot(223)
ax3.plot(time,pre_lstm,color='#38d9a9',marker='*',linestyle='-',label='3')
# ax3.plot(time,true,color='#fd5749',marker='s',linestyle='-',label='true')
ax3.set_title('3',fontsize=15)
ax3.set_xlabel('日期/天',fontsize=15)
ax3.set_ylabel('感染人数/人',fontsize=15)
ax3.xaxis.set_major_formatter(mdate.DateFormatter('%m-%d'))
plt.xticks(pd.date_range(time[0],time[-1],freq='D'),rotation=45)

# 4 
ax4=fig.add_subplot(224)
ax4.plot(time,pre_ari,color='#e666ff',marker='x',linestyle='-',label='4')
ax4.plot(time,true,color='#fd5749',marker='s',linestyle='-',label='true')
ax4.set_title('4',fontsize=15)
ax4.set_xlabel('日期/天',fontsize=15)
ax4.set_ylabel('感染人数/人',fontsize=15)
ax4.xaxis.set_major_formatter(mdate.DateFormatter('%m-%d'))
plt.xticks(pd.date_range(time[0],time[-1],freq='D'),rotation=45)

#初始化labels和线型数组
lines=[]
labels=[]
#通过循环获取线型和labels
for ax in fig.axes:
    axLine, axLabel = ax.get_legend_handles_labels()
    lines.extend(axLine)
    labels.extend(axLabel)
#设置图例和调整图例位置
fig.legend(lines, labels,loc='lower center',
           ncol=5,framealpha=False,fontsize=25)

执行上述合并图例的代码后,生成的图表效果如下图所示。此时,所有子图的图例元素被集中展示在图表的指定位置,避免了图例重复或分散的问题。

为了对比效果,我们将之前代码中用于循环获取label和线型以合并图例的部分注释掉。修改后的代码如下所示,此时不再通过循环收集各子图的图例句柄和标签。

#导入数据(读者可忽略)
pre_lp=total_res#组合模型
true=diff1[-pre_day:]#真实值
pre_ph=results_data["yhat"]#prophet
pre_lstm=reslut#lstm
pre_ari=data_ari['data_pre']#arima
#设置中文字体
rcParams['font.sans-serif'] = 'kaiti'

# 生成一个时间序列 (读者可根据情况进行修改或删除)
time =pd.to_datetime(np.arange(0,21), unit='D',
                    origin=pd.Timestamp('2021-10-19'))
#创建画布
fig=plt.figure(figsize=(20,16))#figsize为画布大小
# 1 
ax1=fig.add_subplot(221)
ax1.plot(time,pre_lp,color='#1bb9f6',marker='^',linestyle='-',label='1')
ax1.plot(time,true,color='#fd5749',marker='s',linestyle='-',label='true')
ax1.set_title('1',fontsize=15)#设置标题
ax1.set_xlabel('日期/天',fontsize=15)#设置横坐标名称
ax1.set_ylabel('感染人数/人',fontsize=15)#设置纵坐标名称
ax1.xaxis.set_major_formatter(mdate.DateFormatter('%m-%d'))#设置横坐标刻度(读者可忽略)
plt.xticks(pd.date_range(time[0],time[-1],freq='D'),rotation=45)#设置横坐标刻度(读者可忽略)

# 2 
ax2=fig.add_subplot(222)
ax2.plot(time,pre_ph,color='#739b06',marker='o',linestyle='-',label='2')
ax2.plot(time,true,color='#fd5749',marker='s',linestyle='-',label='true')
ax2.set_title('2',fontsize=15)
ax2.set_xlabel('日期/天',fontsize=15)
ax2.set_ylabel('感染人数/人',fontsize=15)
ax2.xaxis.set_major_formatter(mdate.DateFormatter('%m-%d'))
plt.xticks(pd.date_range(time[0],time[-1],freq='D'),rotation=45)
# 3 
ax3=fig.add_subplot(223)
ax3.plot(time,pre_lstm,color='#38d9a9',marker='*',linestyle='-',label='3')
ax3.plot(time,true,color='#fd5749',marker='s',linestyle='-',label='true')
ax3.set_title('3',fontsize=15)
ax3.set_xlabel('日期/天',fontsize=15)
ax3.set_ylabel('感染人数/人',fontsize=15)
ax3.xaxis.set_major_formatter(mdate.DateFormatter('%m-%d'))
plt.xticks(pd.date_range(time[0],time[-1],freq='D'),rotation=45)

# 4 
ax4=fig.add_subplot(224)
ax4.plot(time,pre_ari,color='#e666ff',marker='x',linestyle='-',label='4')
ax4.plot(time,true,color='#fd5749',marker='s',linestyle='-',label='true')
ax4.set_title('4',fontsize=15)
ax4.set_xlabel('日期/天',fontsize=15)
ax4.set_ylabel('感染人数/人',fontsize=15)
ax4.xaxis.set_major_formatter(mdate.DateFormatter('%m-%d'))
plt.xticks(pd.date_range(time[0],time[-1],freq='D'),rotation=45)

#初始化labels和线型数组
# lines=[]
# labels=[]
#通过循环获取线型和labels
# for ax in fig.axes:
#  	 axLine, axLabel = ax.get_legend_handles_labels()
#    lines.extend(axLine)
#    labels.extend(axLabel)
#设置图例和调整图例位置
fig.legend(lines, labels,loc='lower center',
           ncol=5,framealpha=False,fontsize=25)

注释掉合并逻辑后,重新运行代码得到的结果如下图所示。可以看到,每个子图各自保留了其独立的图例,或者如果没有显式设置图例位置,可能会显示为默认状态,这有助于理解合并前后的差异。

除了图例处理,调整子图之间的间距也是优化多子图布局的重要环节。Matplotlib提供了专门的函数来调整子图之间的宽度和高度间距,使图表更加美观易读。

plt.subplots_adjust(wspace=0.4,hspace=0.4)

具体而言,wspace参数用于控制子图之间的水平间距(width space),而hspace参数用于控制子图之间的垂直间距(height space)。通过调整这两个参数,可以精确控制子图的排列紧密程度。

下图展示了应用了间距调整后的对比效果。通过合理设置wspace和hspace,子图之间的留白更加协调,视觉上的层次感更强。

当设置了合适的间距参数(如wspace=0.4, hspace=0.4)后,图像呈现出良好的布局,子图之间有足够的呼吸空间,避免了元素重叠或过于拥挤。

相比之下,如果没有设置间距参数,图像中的子图会紧密排列,甚至可能出现标签或图形元素相互遮挡的情况,影响阅读体验。

至此,关于Python Matplotlib绘制多子图的详细教程已介绍完毕。更多相关Python Matplotlib多子图内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。