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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 00:07:59