`matplotlib`:`self.__chachedRenderer`失败`sabtert self._cached



基于 John Hunter对在此处使用动画中使用补丁的问题的回答,我的印象是:

  1. 我可以创建一个 patch对象,其动画说为 True
  2. 使用add_patch方法将其添加到现有的axis(例如,axis对象称为ax)。
  3. 然后,当我想绘制patch时,我会:ax.draw_artist(patch)

这样做,我面临以下错误:

  File "environment.py", line 254, in animation_function
    ax.draw_artist(patches[index])
  File "A:Anacondalibsite-packagesmatplotlibaxes_base.py", line 2121, in draw_artist
    assert self._cachedRenderer is not None
AssertionError

最高级代码的组织如下:

  • 一个函数从数据创建修补程序,然后将它们添加到axis对象中 - 基本上,我从patches中获取了一个补丁对象的列表,其中每个补丁都添加到ax中;我认为问题可能在这里,因为patches中的补丁对象不是真正连接到 ax ...,它们被添加到其中,但通过复制而传递,而不是引用?

  • 动画函数使用从FuncAnimation接收到的数字(例如n)来引用相关的补丁对象,然后调用ax.draw_artist(patches[n])

起初我正在做以下操作:

patches = []
...
patch = mpatches.PathPatch(...)
patch.set_animated(True)
ax.add_patch(patch)
patches.append(patch)
...
ax.draw_artist(patches[n])

然后,在阅读文档后,这表明返回一个补丁对象(可能已连接到轴对象?),我尝试了以下内容:

patches = []
...
patch = mpatches.PathPatch(...)
patch.set_animated(True)
ax_patch = ax.add_patch(patch)
patches.append(ax_patch)
...
ax.draw_artist(patches[n])

但是,问题仍然相同。

您可以评论您认为问题的内容,或者我可能需要提供其他信息才能找出问题?

编辑:错误来自误差的顶级函数。

def create_animation_from_data(self, vertex_marker_radius=0.25, labels = ['a', 'a', 'b', 'b'], unit_line=0.5, colours=['red', 'blue', 'green', 'orange']):
    fig = plt.figure()
    ax = fig.add_subplot(111, aspect='equal', autoscale_on=False, xlim=(-2, 100), ylim=(-2, 100))
    ax.grid()
    print "Initializing patches..."
    patches, patch_indices_per_timestep, num_polys, num_timesteps = self.make_patches_from_environment(ax, vertex_marker_radius, labels, unit_line, colours)
    def animation_function(n):
        relevant_patch_indices = patch_indices_per_timestep[n]
        for polygon_based_index_group in relevant_patch_indices:
            for index in polygon_based_index_group:
                patches[index].draw(fig.canvas.get_renderer())
        return patches,
    print "Beginning animation..."       
    ani = animation.FuncAnimation(fig, animation_function, blit=True)
    plt.show()

您正确理解了所有内容,但缺少几个较低级别的步骤。renderer尚未初始化,您会遇到反映这一点的错误。

简而言之,在第一次绘制绘图之前,您不能使用draw_artist。您需要至少一次致电fig.canvas.draw()(在某些情况下,只需使用fig.canvas.get_renderer())才能使用draw_artist


如果您遇到了这个问题,这通常是因为您试图"反对谷物",并且做最好不要直接处理的事情。

您到底想做什么?处理此问题的方法可能会更简单(例如,如果您要抓住背景,请将代码的此部分放在draw事件的回调中)。


让我备份并解释发生了什么。Matplotlib Artist S使用Renderer的实例(例如fig.canvas.renderer)绘制FigureCanvas(例如fig.canvas)。renderer是特定于后端的和低级的。通常您不会直接触摸它。

ax.draw_artist是比fig.canvas.draw低级别的功能。更具体地说,这是artist.draw(renderer)的速记。

初始化renderer的初始化相对较慢,因此除非图形的大小或DPI更改,否则将其缓存和重复使用。这就是您所说的错误:canvas还没有渲染器。


您有一些不同的选择。您可以手动初始化渲染器(简单的方法是调用fig.canvas.get_renderer())。但是,有时您想获得一些直到绘制后才定义的东西(例如文本对象的大小)。在这种情况下,您需要一个"完整" fig.canvas.draw()

通常,遇到这样的事情是一个更简单的方法来做到这一点。通常,最好将需要抽签的代码变成对抽奖活动的回调。(尤其是如果这取决于图的确切大小 - 例如,打击的背景)。


基于代码样本

更新

如果您使用的是matplotlib.animation框架,则无需在更新功能的内部绘制艺术家。动画框架将为您处理这一步骤。

听起来您只想在每个时间步中展示您绘制的一部分艺术家?

如果是这样,您可以考虑切换其可见性。作为一个快速示例:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation

def main():
    fig, ax = plt.subplots()
    p = Plotter(ax)
    # Note: We need to save a referce to the animation object, otherwise it
    # will be garbage collected and never properly animate.
    anim = matplotlib.animation.FuncAnimation(fig, p.update,
                                              init_func=p.anim_init)
    plt.show()
class Plotter(object):
    def __init__(self, ax):
        self.ax = ax
    def anim_init(self):
        self.triangles = [self.random_triangle() for _ in range(10)]
        # Initially, show a blank plot...
        for tri in self.triangles:
            tri.set_visible(False)
        return self.triangles
    def update(self, i):
        """Animation step."""
        # Hide all triangles
        for tri in self.triangles:
            tri.set(visible=False)
        # pick 2 at random to show (e.g. your  patch_indices_per_timestep)
        for tri in np.random.choice(self.triangles, size=2):
            tri.set(visible=True)
        return self.triangles
    def random_triangle(self):
        x, y = np.random.random((2,3))
        x += 10 * np.random.random(1)
        y += 10 * np.random.random(1)
        return self.ax.fill(x, y)[0]
main()

最新更新