Matplotlib保存图像出现重叠覆盖,是机制问题还是操作疏漏?
问题:Matplotlib生成的图像出现叠加
我写了两个生成并保存图像的函数,但第二个函数生成的graph.png总是叠加了第一个函数生成的dendo.png的内容,复现代码如下:
from scipy.cluster.hierarchy import linkage, dendrogram import numpy as np import pandas as pd import matplotlib.pyplot as plt import statsmodels.api as sm def dendo(): # Create an array x = np.array([100., 200., 300., 400., 500., 250., 450., 280., 450., 750.]) Z=linkage(x,'ward') dendrogram(Z, leaf_rotation=45., leaf_font_size=12.) plt.title('Hierarchical Clustering Dendrogram') plt.xlabel('Cluster Size') plt.ylabel('Distance') plt.rcParams["figure.figsize"] = (9,8) plt.savefig('dendo.png') def stats(): df = pd.DataFrame({'gmat':[ 580.0, 660.0, 740.0, 590.0, 660.0, 540.0, 690.0, 550.0, 580.0, 620.0, 710.0, 660.0, 780.0, 680.0, 680.0, 550.0, 580.0, 650.0, 620.0, 750.0, 730.0, 690.0, 570.0, 660.0, 690.0, 650.0, 670.0, 690.0, 690.0, 590.0], 'gpa': [2.7, 3.3, 3.3, 1.7, 4.0, 2.7, 2.3, 2.7, 2.3, 2.7, 3.7, 3.3, 4.0, 3.3, 3.9, 2.3, 3.3, 3.7, 3.3, 3.9, 3.7, 1.7, 3.0, 3.7, 3.3, 3.7, 3.3, 3.7, 3.7, 2.3], 'work_experience': [4.0, 6.0, 5.0, 4.0, 4.0, 2.0, 1.0, 1.0, 2.0, 2.0, 5.0, 5.0, 3.0, 4.0, 4.0, 4.0, 1.0, 6.0, 2.0, 4.0, 6.0, 1.0, 2.0, 4.0, 3.0, 6.0, 6.0, 5.0, 5.0, 3.0], 'admitted': [0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0]}) Xtrain = df[['gmat', 'gpa', 'work_experience']] ytrain = df[['admitted']] log_reg = sm.Logit(ytrain, Xtrain).fit() stats1=log_reg.summary() plt.rc('figure', figsize=(12, 7)) plt.text(0.01, 0.05, str(stats1), {'fontsize': 10}, fontproperties = 'monospace') plt.axis('off') plt.tight_layout() plt.savefig('graph.png') dendo() stats()
请问这是Matplotlib的默认工作机制,还是我存在操作疏漏?
原因分析
这是Matplotlib默认的状态机工作机制导致的问题。Matplotlib默认会在当前活跃的Figure(画布)和Axes(坐标轴)上绘制内容。你在dendo()函数中完成绘图并保存后,没有清理或关闭当前画布,调用stats()时,所有绘图操作会继续在同一个画布上执行,最终造成内容叠加。
解决方法
有三种常用方案可以避免这类叠加问题:
1. 每个函数中创建新画布
在每个绘图函数开头调用plt.figure(),显式创建新画布,确保后续绘图操作在独立画布上进行:
def dendo(): plt.figure() # 创建新画布 # 原绘图代码不变 plt.savefig('dendo.png') def stats(): plt.figure() # 创建新画布 # 原绘图代码不变 plt.savefig('graph.png')
2. 保存图像后关闭当前画布
在每个函数的plt.savefig()之后调用plt.close(),关闭当前画布,让下一个函数自动创建新画布:
def dendo(): # 原绘图代码不变 plt.savefig('dendo.png') plt.close() # 关闭当前画布 def stats(): # 原绘图代码不变 plt.savefig('graph.png') plt.close() # 关闭当前画布
3. 使用面向对象API(推荐)
Matplotlib的面向对象API能明确控制每个画布和坐标轴,避免状态机带来的隐式问题:
def dendo(): fig, ax = plt.subplots(figsize=(9,8)) # 创建画布和坐标轴 x = np.array([100., 200., 300., 400., 500., 250., 450., 280., 450., 750.]) Z=linkage(x,'ward') dendrogram(Z, leaf_rotation=45., leaf_font_size=12., ax=ax) # 指定绘图坐标轴 ax.set_title('Hierarchical Clustering Dendrogram') ax.set_xlabel('Cluster Size') ax.set_ylabel('Distance') fig.savefig('dendo.png') def stats(): fig, ax = plt.subplots(figsize=(12,7)) # 创建画布和坐标轴 df = pd.DataFrame(...) # 原数据部分省略 log_reg = sm.Logit(ytrain, Xtrain).fit() stats1=log_reg.summary() ax.text(0.01, 0.05, str(stats1), {'fontsize': 10}, fontproperties = 'monospace') ax.axis('off') fig.tight_layout() fig.savefig('graph.png')
内容的提问来源于stack exchange,提问作者Allen
相关产品推荐
相关产品推荐

