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

循环更新Matplotlib Pyplot子图图像时的set_data属性错误问题

解决AttributeError: 'AxesSubplot' object has no attribute 'set_data'问题

我一眼就看出问题的核心了——你在代码里犯了两个容易踩的小坑:错误覆盖了坐标轴数组,还有遍历子图的方式不对!

问题根源拆解

  1. 坐标轴与图像对象混淆:
    plt.subplots()返回的self.a是AxesSubplot对象的二维数组,每个元素代表子图的坐标轴。但你在__init__的循环里做了self.a[row, col] = plt.imshow(...),这会把原本的坐标轴对象替换成imshow返回的AxesImage(图像数据对象)。

  2. 遍历范围错误:
    你用zip(range(self.nrows), range(self.ncols))遍历子图,这只会遍历对角线位置的子图(比如nrows=4、ncols=4时,只会处理(0,0)、(1,1)、(2,2)、(3,3))。剩下的子图位置还是原始的AxesSubplot对象,自然没有set_data方法——这就是为什么你单独看tp.a[0,0]有set_data,但运行update时会报错!

修正后的代码

我们需要把坐标轴对象和图像数据对象分开存储,同时用正确的方式遍历所有子图:

import matplotlib.pyplot as plt
import numpy as np

class tensor_plot:
    def __init__(self, tensor_shape, nrows=1):
        self.img_height, self.img_width, self.num_imgs = tensor_shape
        self.nrows = nrows
        self.ncols = self.num_imgs // nrows
        assert(self.ncols*self.nrows == self.num_imgs), "num_imgs必须能被nrows整除"
        
        # 创建子图坐标轴数组,保留原始的AxesSubplot对象
        self.fig, self.a = plt.subplots(self.nrows, self.ncols, sharex='col', sharey='row')
        # 单独存储每个imshow返回的图像数据对象(AxesImage)
        self.imgs = []
        
        # 用嵌套循环遍历所有子图,确保每个子图都被初始化
        for row in range(self.nrows):
            for col in range(self.ncols):
                # 在当前坐标轴上绘制初始图像,并保存图像对象
                img = self.a[row, col].imshow(np.zeros([self.img_height, self.img_width]))
                self.imgs.append(img)
        
        # 调整子图间距,优化显示效果
        self.fig.tight_layout()
        # 非阻塞式显示窗口,方便后续循环更新
        plt.show(block=False)

    def update(self, tensor):
        n = 0
        # 遍历所有图像对象,直接更新数据
        for img in self.imgs:
            img.set_data(tensor[:,:,n].squeeze())
            n += 1
        
        # 刷新画布而不是重复调用plt.show(),避免创建新窗口或阻塞程序
        self.fig.canvas.draw()
        self.fig.canvas.flush_events()

关键修改说明

  • 新增self.imgs列表专门存储图像数据对象,不再覆盖坐标轴数组self.a;
  • 用嵌套循环替代zip,确保所有子图都被初始化;
  • 初始化时用plt.show(block=False),让窗口不阻塞后续代码执行;
  • 更新时调用fig.canvas.draw()和fig.canvas.flush_events()刷新画面,避免重复弹出窗口。

测试示例

# 创建测试用的16张10x10随机图像张量
tensor_shape = (10, 10, 16)
l10 = np.random.rand(*tensor_shape)

# 初始化绘图类(4行4列)
tp = tensor_plot(tensor_shape, nrows=4)

# 模拟循环更新:每0.5秒刷新一次随机图像
import time
for _ in range(10):
    new_tensor = np.random.rand(*tensor_shape)
    tp.update(new_tensor)
    time.sleep(0.5)

内容的提问来源于stack exchange,提问作者jdbrody

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:06:34