通过 mpl_toolkit.basemap 绘制 pcolormesh() 动画时产生的属性错误的解决方法

64 阅读2分钟

用户在尝试使用 mpl_toolkit.basemap 为密度数据创建动画时遇到了一个属性错误。具体来说,当更新 pcolormesh() 对象的数据数组时,出现了 "AttributeError: 'list' object has no attribute 'ndim'" 的错误。

huake_00152_.jpg 2. 解决方案

问题分析:

  • 该错误是由于在初始化函数 init() 中将数据数组设置为空列表 [] 引起的。这导致了在更新数据时,没有有效的数组对象可以操作。

解决方法:

  • 将 init() 函数中的 quad.set_array([]) 改为 quad.set_array(np.array([])),这将创建一个空 NumPy 数组,并将其设置为 pcolormesh() 对象的数据数组。

另需要确保在 FuncAnimation() 调用中将 blit 参数设置为 False,并避免在 pcolormesh() 对象的艺术家属性中设置 animated 为 True。此外,在初始调用中根据要动画化的数据设置数据范围(边界),以防止出现空白动画。

如需生成成功动画,请确保使用最新版本的 matplotlib 和 basemap,并注意处理线条虚线时的变化。

对于相同的问题,还有一些额外的注意事项和解决方法:

  • 确保数据数组的维度与边界位置数据一致。pcolormesh() 需要边界数据来定位数据字段,如果数据数组大于或等于边界位置数据,则超出此边界要求的任何数据都将被排除。
  • 使用最新的 matplotlib 和 basemap 版本。旧版本的 matplotlib 可能具有较差的错误报告,导致难以诊断问题。
  • 如果遇到其他问题,请尝试搜索相关错误消息或在相关的论坛上寻求帮助。

代码示例:

def plot_pcolor(lons, lats):

    class UpdateQuad(object):

        def __init__(self, ax, map_object, lons, lats):
            self.ax = ax
            self.m  = map_object
            self.lons = lons
            self.lats = lats
            self.ydim, self.xdim = lons.shape
            self.z = np.zeros((self.ydim-1,self.xdim-1))
            levels = MaxNLocator(nbins=15).tick_values(vmin,vmax)
            cmap = plt.cm.cool
            norm = BoundaryNorm(levels, ncolors=cmap.N, clip=True)
            x, y = self.m(lons, lats)
            self.quad = self.ax.pcolormesh(x, y, self.z, alpha=0.9,
                                           norm=norm, cmap=cmap,
                                           vmin=vmin, vmax=vmax)

        def init(self):
            print('update init')
            self.quad.set_array(np.asarray([]))
            return self.quad

        def __call__(self,i):
            for i in range(self.ydim-1):
                for j in range(self.xdim-1):
                    self.z[i,j]=random.random()
            self.quad.set_array(self.z.ravel())
            return self.quad

    fig, ax = plt.subplots()

    m = Basemap(width=2000000, height=2000000,
                resolution='l', projection='laea',
                lat_ts=10., lat_0=64., lon_0=10., ax=ax)

    m.fillcontinents()

    ud = UpdateQuad(ax, m, lons, lats)

    anim = animation.FuncAnimation(fig, ud, init_func=ud.init,
                                   frames=20,  blit=False)

    fig.tight_layout()

    plt.show()

    return ud.quad

if __name__ == '__main__':
    import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    from mpl_toolkits.basemap import Basemap
    import numpy as np
    import random
    from matplotlib.colors import BoundaryNorm
    from matplotlib.ticker import MaxNLocator

    lons = np.linspace(-5.,25., num = 25)[:50]
    lats = np.linspace(56., 71., num = 25)[:50]
    lons, lats =  np.meshgrid(lons, lats)

    quad = plot_pcolor(lons, lats)