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

Matplotlib封装Particle类后补丁动画失效问题排查

问题:将plt.Circle封装到Particle类后,Matplotlib动画无法正常运行的原因

原始可运行代码

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

fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(7, 6.5)

ax = plt.axes(xlim=(0, 10), ylim=(0, 10))
patch = plt.Circle((5, -5), 0.75, fc='y')

def init():
    patch.center = (5, 5)
    ax.add_patch(patch)
    return patch,

def animate(i):
    x, y = patch.center
    x = 5 + 3 * np.sin(np.radians(i))
    y = 5 + 3 * np.cos(np.radians(i))
    patch.center = (x, y)
    return patch,

anim = animation.FuncAnimation(fig, animate, 
                               init_func=init, 
                               frames=36, 
                               interval=20,
                               blit=True)

HTML(anim.to_jshtml())

修改后的问题代码

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

fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(7, 6.5)

ax = plt.axes(xlim=(0, 10), ylim=(0, 10))

class Particle:
    def __init__(self,x,y):
        self.x = x
        self.y = y
    def show(self):
        return plt.Circle((self.x, self.y), 0.75, fc='y')

p = Particle(5, -5)

def init():
    ax.add_patch(p.show())
    return p.show(),

def animate(i):
    p.x = 5 + 3 * np.sin(np.radians(i))
    p.y = 5 + 3 * np.cos(np.radians(i))
    return p.show(),

anim = animation.FuncAnimation(fig, animate, 
                               init_func=init, 
                               frames=36, 
                               interval=20,
                               blit=True)

HTML(anim.to_jshtml())

问题原因及解决方法

核心问题

每次调用p.show()都会创建一个全新的plt.Circle对象,而不是修改已经添加到坐标轴上的那个圆:

  • 在init()里,你调用p.show()添加了一个圆到坐标轴,但返回的是另一个新创建的圆对象,和坐标轴上的不是同一个。
  • 在animate()里,每次又创建新的圆返回,Matplotlib的blitting机制需要跟踪同一个图形元素的变化,而不是不断创建新元素,这就导致动画无法正确更新已有的圆,反而可能不断叠加新圆(但blitting模式下不会正确渲染)。

修复方案

修改Particle类,让它内部保存一个plt.Circle实例,而不是每次创建新的:

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

fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(7, 6.5)

ax = plt.axes(xlim=(0, 10), ylim=(0, 10))

class Particle:
    def __init__(self,x,y):
        self.circle = plt.Circle((x, y), 0.75, fc='y')  # 初始化时创建一次圆实例
    def get_circle(self):
        return self.circle
    def update_pos(self, x, y):
        self.circle.center = (x, y)  # 直接修改已有圆的中心

p = Particle(5, 5)

def init():
    ax.add_patch(p.get_circle())
    return p.get_circle(),

def animate(i):
    x = 5 + 3 * np.sin(np.radians(i))
    y = 5 + 3 * np.cos(np.radians(i))
    p.update_pos(x, y)
    return p.get_circle(),

anim = animation.FuncAnimation(fig, animate, 
                               init_func=init, 
                               frames=36, 
                               interval=20,
                               blit=True)

HTML(anim.to_jshtml())

关键改动说明

  • Particle类初始化时就创建一个plt.Circle实例并保存为属性,后续不再创建新的。
  • 通过update_pos方法直接修改已有圆的中心坐标,而不是重新创建圆。
  • get_circle方法始终返回同一个圆实例,保证Matplotlib的动画机制能跟踪到同一个图形元素的变化。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 11:40:02