在matplotlib

时间:2018-02-14 18:33:58

标签: python matplotlib

我试图动画一组遵循x,y和z轨迹的粒子。每个对象都有一个与轴单位相关的特定半径,这就是为什么我希望每个对象都由一个圆形补丁表示,我可以在其中指定补丁的大小(而不是散点图,我必须转换)轴单位的大小)。

另一个限制是我希望根据色图对色块进行着色,色块的颜色由z的值决定。

我发现使用色彩图绘制一组贴片的唯一方法是将它们放在一个集合中。所以,这成功地产生了一个框架

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as anm
import matplotlib.collections as clt

fig, ax = plt.subplots(1,1,figsize=(7,7))

ax.set_xlim(-1,1)
ax.set_ylim(-1,1)

n_of_particles = 3
frames = 10

radius = 0.05
x = 0.5*np.random.randn(frames,n_of_particles)
y = 0.5*np.random.randn(frames,n_of_particles)
z = 0.5*np.random.randn(frames,n_of_particles)

patches = []
for p in range(n_of_particles):
    circle = plt.Circle((x[0,p], y[0,p]), radius)
    patches.append(circle)

collection = clt.PatchCollection(patches, cmap=plt.cm.jet, alpha=0.4)
collection.set_array(z[0,:])
collection.set_clim([-1, 1])
plt.colorbar(collection)

ax.add_collection(collection)

但我该如何制作动画?

我试图在最后添加(而不是ax.add_collection(collection)

def animate(frame):
    patches = []
    for p in range(n_of_particles):
        circle = plt.Circle((x[frame,p], y[frame,p]), radius)
        patches.append(circle)

    collection = clt.PatchCollection(patches, cmap=plt.cm.jet, alpha=0.4)
    collection.set_array(z[0,:])

    ax.add_collection(collection)
    return collection,

然后:

anim = anm.FuncAnimation(fig, animate,
                               frames=10, interval=100, blit=True)
HTML(anim.to_html5_video())

但它并没有删除前一帧。

理想情况下,我更愿意更改补丁的位置,而不是重新定义补丁。但我不知道如何修改集合。

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

这个想法当然只是将集合添加到轴上一次。然后通过collection.set_paths更改集合中的艺术家。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as anm
import matplotlib.collections as clt

fig, ax = plt.subplots(1,1,figsize=(7,7))

ax.set_xlim(-1,1)
ax.set_ylim(-1,1)

n_of_particles = 3
frames = 10

radius = 0.05
x = 0.5*np.random.randn(frames,n_of_particles)
y = 0.5*np.random.randn(frames,n_of_particles)
z = 0.5*np.random.randn(frames,n_of_particles)

patches = []
for p in range(n_of_particles):
    circle = plt.Circle((x[0,p], y[0,p]), radius)
    patches.append(circle)

collection = clt.PatchCollection(patches, cmap=plt.cm.jet, alpha=0.4)
collection.set_array(z[0,:])
collection.set_clim([-1, 1])
fig.colorbar(collection)

ax.add_collection(collection)

def animate(frame):
    patches = []
    for p in range(n_of_particles):
        circle = plt.Circle((x[frame,p], y[frame,p]), radius)
        patches.append(circle)

    collection.set_paths(patches)
    collection.set_array(z[frame,:])

anim = anm.FuncAnimation(fig, animate,
                               frames=10, interval=1000, blit=False)
plt.show()

另一种选择可能是使用此答案中提供的解决方案:matplotlib change a Patch in PatchCollection
并创建一个UpdatablePatchCollection。这样就可以只更新循环内原始补丁的属性。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as anm
import matplotlib.collections as clt

fig, ax = plt.subplots(1,1,figsize=(7,7))

ax.set_xlim(-1,1)
ax.set_ylim(-1,1)

n_of_particles = 3
frames = 10

radius = 0.05
x = 0.5*np.random.randn(frames,n_of_particles)
y = 0.5*np.random.randn(frames,n_of_particles)
z = 0.5*np.random.randn(frames,n_of_particles)

patches = []
for p in range(n_of_particles):
    circle = plt.Circle((x[0,p], y[0,p]), radius)
    patches.append(circle)

class UpdatablePatchCollection(clt.PatchCollection):
    def __init__(self, patches, *args, **kwargs):
        self.patches = patches
        clt.PatchCollection.__init__(self, patches, *args, **kwargs)

    def get_paths(self):
        self.set_paths(self.patches)
        return self._paths

collection = UpdatablePatchCollection(patches, cmap=plt.cm.jet, alpha=0.4)
collection.set_array(z[0,:])
collection.set_clim([-1, 1])
fig.colorbar(collection)

ax.add_collection(collection)

def animate(frame):
    for p in range(n_of_particles):
        patches[p].center = x[frame,p], y[frame,p]   
    collection.set_array(z[frame,:])

anim = anm.FuncAnimation(fig, animate,
                               frames=10, interval=1000, blit=False)

plt.show()