如何有效地为列表列表中的多个补丁制作动画

How to efficiently animate multiple patches from a list of lists

我试图在从列表中读取数据时尽可能高效地为多个补丁制作动画?

下面的代码显示了散点图的动画,但没有显示补丁。散点图中的每个点都包含各种大小的圆圈。此示例将需要 6 个不同的圆圈在每个时间点 2 个对象处进行动画处理。但是如果有 20 个对象,每个对象周围有 3 个圆圈呢?

为每一帧制作所有 60 个圆圈的最有效方法是什么?

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

x_data = np.random.randint(80, size=(400, 4))
y_data = np.random.randint(80, size=(400, 4))

fig, ax = plt.subplots(figsize = (8,6))
ax.set_xlim(0,80)
ax.set_ylim(0,80)

scatter = ax.scatter(x_data[0], y_data[0], zorder = 5) #Scatter plot

Player_1 = x_data[0][0], y_data[0][0]
Player_2 = x_data[0][1], y_data[0][1]

Player_1_IR = mpl.patches.Circle(Player_1, radius = 2, color = 'black', lw = 1, alpha = 0.8, zorder = 4)
Player_1_MR = mpl.patches.Circle(Player_1, radius = 4, color = 'gray', lw = 1, alpha = 0.8, zorder = 3)
Player_1_OR = mpl.patches.Circle(Player_1, radius = 6, color = 'lightgrey', lw = 1, alpha = 0.8, zorder = 2)

Player_2_IR = mpl.patches.Circle(Player_2, radius = 2, color = 'black', lw = 1, alpha = 0.8, zorder = 4)
Player_2_MR = mpl.patches.Circle(Player_2, radius = 4, color = 'gray', lw = 1, alpha = 0.8, zorder = 3)
Player_2_OR = mpl.patches.Circle(Player_2, radius = 6, color = 'lightgrey', lw = 1, alpha = 0.8, zorder = 2)

ax.add_patch(Player_1_IR)
ax.add_patch(Player_1_MR)
ax.add_patch(Player_1_OR)

ax.add_patch(Player_2_IR)
ax.add_patch(Player_2_MR)
ax.add_patch(Player_2_OR)

def animate(i) : 
    scatter.set_offsets(np.c_[x_data[i,:], y_data[i,:]])

ani = animation.FuncAnimation(fig, animate, frames=len(x_data), 
                              interval = 700, blit = False)

plt.show()

您可以将要更新的所有补丁存储在一个列表中,然后通过该列表遍历每个迭代步骤。请注意,Circle 补丁的大小以数据 units/coordinates 为单位,而散点图点以点为单位(一个点 = 1/72 英寸),这意味着散点和圆之间的相对大小取决于在图形大小和轴限制上,并且会在您重新缩放图形时发生变化。

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

x_data = np.random.randint(80, size=(400, 20))
y_data = np.random.randint(80, size=(400, 20))

fig, ax = plt.subplots(figsize = (8,6))
ax.set_xlim(0,80)
ax.set_ylim(0,80)

scatter = ax.scatter(x_data[0], y_data[0], zorder = 5) #Scatter plot

##creating list of patches
players = []
for n in range(10):
    ##as there are always 3 circles, append all three patches as a list at once
    players.append([
        mpl.patches.Circle((x_data[0,n],y_data[0,n]), radius = 2, color = 'black', lw = 1, alpha = 0.8, zorder = 4),
        mpl.patches.Circle((x_data[0,n],y_data[0,n]), radius = 4, color = 'gray', lw = 1, alpha = 0.8, zorder = 3),
        mpl.patches.Circle((x_data[0,n],y_data[0,n]), radius = 6, color = 'lightgrey', lw = 1, alpha = 0.8, zorder = 2)
    ])

##adding patches to axes
for player in players:
    for circle in player:
        ax.add_patch(circle)


def animate(i):
    scatter.set_offsets(np.c_[x_data[i,:], y_data[i,:]])
    ##updating players:
    for n,player in enumerate(players):
        for circle in player:
            circle.center = (x_data[i,n],y_data[i,n])

ani = animation.FuncAnimation(fig, animate, frames=len(x_data), 
                              interval = 700, blit = False)

plt.show()

旧答案(视觉效果略有不同,但可以调整为看起来相同):

如果你真的只想在你的散点周围画圈,你实际上可以忘记 Circle 补丁,只覆盖几个具有不同标记大小的散点图。

在下面的示例中,我只是通过对随机数数组进行切片来用圆圈标记部分散点。还请记住,在散点图中,标记大小以平方点给出,因此如果您想将圆半径从 5 增加到 6,给定的标记大小应从 25 更改为 36。

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

x_data = np.random.randint(80, size=(400, 20))
y_data = np.random.randint(80, size=(400, 20))

fig, ax = plt.subplots(figsize = (8,6))
ax.set_xlim(0,80)
ax.set_ylim(0,80)

scatter = ax.scatter(x_data[0], y_data[0], zorder = 5) #Scatter plot
scatter_IR = ax.scatter(
    x_data[0,:10], y_data[0,:10], zorder = 4,
    facecolor='black', edgecolor = 'black',
    alpha = 0.8, s = 100
)
scatter_MR = ax.scatter(
    x_data[0,:10], y_data[0,:10], zorder = 3,
    facecolor='grey', edgecolor = 'grey',
    alpha = 0.8, s = 225
)
scatter_OR = ax.scatter(
    x_data[0,:10], y_data[0,:10], zorder = 2,
    facecolor='lightgrey', edgecolor = 'lightgrey',
    alpha = 0.8, s = 400
)

def animate(i) : 
    scatter.set_offsets(np.c_[x_data[i,:], y_data[i,:]])
    scatter_IR.set_offsets(np.c_[x_data[i,:10], y_data[i,:10]])
    scatter_MR.set_offsets(np.c_[x_data[i,:10], y_data[i,:10]])
    scatter_OR.set_offsets(np.c_[x_data[i,:10], y_data[i,:10]])


ani = animation.FuncAnimation(fig, animate, frames=len(x_data), 
                              interval = 700, blit = False)

plt.show()