如何有效地为列表列表中的多个补丁设置动画
Posted
技术标签:
【中文标题】如何有效地为列表列表中的多个补丁设置动画【英文标题】:How to efficiently animate multiple patches from a list of lists 【发布时间】:2018-02-13 05:23:19 【问题描述】:在从列表中读取数据时,我试图尽可能高效地为多个补丁设置动画?
下面的代码显示了散点图的动画,但不显示补丁。散点图中的每个点都包含各种大小的圆圈。此示例需要在每个时间点为 2 个对象设置 6 个不同的圆圈。但是,如果有 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()
【问题讨论】:
我在您的代码中经常看到player
这个词。如果您正在尝试创建游戏,我认为 matplotlib 不是正确的平台——您看过 pygame 吗?
如果这真的只是更新大量补丁,我会将它们收集在一个列表中,然后通过迭代该列表进行更新。例如,如果您有Circle
补丁列表,例如circle_list
和相应的要更新的坐标列表,例如coord_list
,则只需执行for circ,coord in zip(circle_list,coord_list): circ.center=coord
。另请参阅this。
我应该换个主题。但不,我不是。我使用的 XY 坐标来自体育比赛中测量的球员跟踪单位。我只是使用这些坐标来可视化它们的运动。所以当我说Player
我的意思是一个主题的XY坐标
我明白了,那就把它清除了:)
感谢您为此提供的所有帮助。我会将@ThomasKühn 放在致谢中。可能是合著者!
【参考方案1】:
您可以将要更新的所有补丁存储在一个列表中,然后通过该列表迭代每个迭代步骤。请注意,Circle
补丁的大小以数据单位/坐标为单位,而散点图点以点为单位(一点 = 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()
【讨论】:
没想到。好主意! 只是一个快速的@ThomasKuhn。我的数据集略有不同。x_data
是 x 坐标的 list
,标记为 x_data[0]
。所以如果我想要第一行,那就是x_data [0][0]
。使用上述代码时,我收到一条错误消息,指出 TypeError: list indices must be integers or slices, not tuple
。我将如何更改数据的读取方式,使其不是元组?
@JPA0888 你有两个选择,要么将 x_data
转换为数组 (x_data=np.array(x_data)
),要么将每个位置的索引从 numpy 样式更改为 python 样式 (x_data[0,start:end]
-- >x_data[0][start:end]
)。无论哪种方式都可以解决问题。我个人会选择第一个选项。以上是关于如何有效地为列表列表中的多个补丁设置动画的主要内容,如果未能解决你的问题,请参考以下文章
css 这是使用css3的动画列表。通过添加.animated类和。{animation-name}类轻松地为元素设置动画。
如何正确地为隐藏在 UITableViewCell 中的 UIStackView 设置动画?