`matplotlib`:`self._chachedRenderer`失败`断言self._cachedRenderer不是None`,在补丁上调用`draw_artist`时?

时间:2015-05-10 17:32:39

标签: python animation matplotlib

基于 John Hunter的answer to a question regarding using patches in animations here,我的印象是:

  1. 我可以使用its animated stated being True创建patch个对象。
  2. 使用axis方法将其添加到现有axis(假设ax对象称为add_patch)。
  3. 然后,当我想绘制patch时,我会:ax.draw_artist(patch)
  4. 这样做,我遇到以下错误:

      File "environment.py", line 254, in animation_function
        ax.draw_artist(patches[index])
      File "A:\Anaconda\lib\site-packages\matplotlib\axes\_base.py", line 2121, in draw_artist
        assert self._cachedRenderer is not None
    AssertionError
    

    顶级代码的组织如下:

    • 一个函数从数据创建补丁,然后将它们添加到axis对象 - 基本上,我得到一个补丁对象列表,patches,其中每个补丁都已添加到ax; 我认为这个问题可能就在这里,因为patches中的补丁对象

      } {...}}通过复制,而不是参考?

    • 动画功能使用从ax收到的号码(让我们说n)来引用相关的补丁对象,然后调用FuncAnimation

    起初我正在做以下事情:

    ax.draw_artist(patches[n])

    然后,在reading the documentation之后,表示返回了一个补丁对象(可能现在连接到一个轴对象?),我尝试了以下内容:

    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])
    

1 个答案:

答案 0 :(得分:2)

您正确理解了所有内容,但遗漏了几个较低级别的步骤。 renderer尚未初始化,并且您收到反映该错误的错误。

简而言之,在第一次绘制情节之前,您无法使用draw_artist。在使用fig.canvas.draw()之前,您需要至少召唤一次fig.canvas.get_renderer()(在某些情况下,您只能使用draw_artist)。Artist

如果你遇到这个问题,通常是因为你正试图去对抗谷物"做一些最好不要直接处理的事情。

你到底想要做什么?可能有一种更简单的方法来解决这个问题(例如,如果您尝试获取背景,请将此部分代码放入回调事件的回调中)。

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

fig.canvas.draw是比artist.draw(renderer)更低级别的功能。更具体地说,它是renderer的简写。

初始化canvas相对较慢,因此除非图形的大小或dpi发生变化,否则它会被缓存并重复使用。这就是你所得到的错误:fig.canvas.get_renderer()还没有渲染器。

您有几种不同的选择。您可以手动初始化渲染器(简单的方法是调用fig.canvas.draw())。但是,有时候您需要获取某些内容(例如文本对象的大小),直到它被绘制之后才能定义。在这种情况下,你需要一个完整的" matplotlib.animation

但是,通常情况下,遇到这样的事情表明这是一种更简单的方法。通常,最好将需要绘制的代码放入到draw事件的回调中。 (特别是如果它取决于图形的确切大小 - 例如blitting的背景)。

基于代码示例的更新

如果您正在使用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() 框架,那么您不需要在更新功能中绘制艺术家。动画框架将为您完成这一步骤。

听起来你只是试图只展示你在每个时间步都画出的艺术家的一部分?

如果是这样,您可以考虑切换其可见性。作为一个简单的例子:

union all