Matplotlib自定义axes图表保存丢失标题坐标轴的问题解决
问题根本原因
- 散点图保存后缺失元素的问题,核心来自
fig.add_axes([0,0,1,1])的参数设置:add_axes传入的四个数值是[左起始位置, 下起始位置, 轴宽度, 轴高度],以0-1的归一化坐标相对于整张画布计算尺寸。传入[0,0,1,1]会让绘图轴从画布最左下角开始,完全占满整个画布的全部宽高,原本预留用来放置标题、坐标轴标签、图例的一圈边距会被绘图轴完全覆盖。 - Spyder IDE内显示图表时,Matplotlib交互式渲染后端会自动触发布局适配,动态将绘图轴向内收缩,为外围的标签、标题元素腾出显示空间,因此界面中能看到完整的图表内容;但调用
savefig保存文件时,会严格按照手动设置的轴位置存储画布内容,不会自动调整边距,因此位于画布边界外的标签、标题、图例元素会被完全排除在保存范围外。 - 折线图没有出现同类问题,是因为它全程使用Matplotlib的pyplot全局接口绘制,没有手动创建全铺满的自定义轴,pyplot默认会预留合理边距,保存逻辑和显示逻辑保持一致。
对应修改方案
- 移除全铺满的轴设置:将原代码中
ax=fig.add_axes([0,0,1,1])替换为默认带合理边距的子图创建方式,比如ax = fig.add_subplot(111);如果确实需要自定义轴的大小和位置,可将参数调整为[0.1, 0.1, 0.8, 0.8],主动预留10%的画布边距给外围元素。 - 保存时自动适配元素边界:在
plt.savefig()中增加参数bbox_inches='tight',该参数会在保存时自动计算所有绘图元素(含标签、标题、图例)的实际范围,避免元素被裁切。 - 统一绘图接口逻辑:代码中存在遍历多组实验设置循环绘图的场景,尽量不要混用pyplot全局接口和手动创建的面向对象接口,将
plt.title()、plt.xlabel()等全局调用替换为对应轴对象的方法(如ax.set_title()、ax.set_xlabel()),避免循环过程中出现全局状态串扰、元素错位的问题。 - 循环绘制多图时,每次保存完成后调用
plt.close(fig)关闭当前画布,避免内存泄漏和残留状态干扰下一次绘图。
修改后的可正常使用的代码
def plot_cluster_datapoints_graph(self, directory): fig = plt.figure() # 替换铺满全画布的自定义轴为默认带边距的子图 ax = fig.add_subplot(111) ax.scatter( self.svd_data[:,0], self.svd_data[:,1], color='b', s=0.2, label='Datapoints' ) ax.scatter( self.cluster_centers[:,0], self.cluster_centers[:,1], s=8, color='r', label='Cluster centers' ) # 用轴对象的方法设置图表属性,避免全局状态串扰 ax.set_title('Data point and clusters for 2 factors' + self.setting) ax.set_xlabel('Dimension 0') ax.set_ylabel('Dimension 1') ax.legend() ax.grid() # 保存时自动适配元素范围,避免裁切 plt.savefig( directory + self.setting + '-CD.png', bbox_inches='tight' ) plt.show() # 关闭当前画布,避免循环时状态残留 plt.close(fig) return
内容的提问来源于stack exchange,提问作者Emil
相关产品推荐
相关产品推荐

