此问题与其他动画问题不同,因为我正在尝试为点之间的交替线设置动画。例如,可能在3点或50点之间。
使用下面的数据框,这些点在Item
中标记。前两个时间戳记包含4点,但是对于最后两个时间戳记则下降到3点。我正在尝试找到一种有效的方法,将每个时间戳起作用的所有潜在行组合到一个动画调用函数中。
我遇到的问题是我正在手动绘制每条线。因此,当前每个点之间的线都是硬编码的,这不能说明线数的变化。
我需要一些东西,这些东西首先要合并可用的行,然后再将其传递给动画。
例如,A, B, C, D
当前是前两个时间点中的标记点。但这在最近两个时间点下降到A, B, C
。
以下内容不考虑行数的交替变化。
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
import pandas as pd
df1 = pd.DataFrame({
'Time' : [1,1,1,1,2,2,2,2,3,3,3,4,4,4],
'Item' : ['A', 'B', 'C', 'D','A', 'B', 'C', 'D', 'A', 'B', 'C', 'A', 'B', 'C'],
'GroupA_X' : [3, 4, 5, 1, 2, 5, 6, 2, 1, 6, 7, 2, 7, 8],
'GroupA_Y' : [2, 4, 5, 1, 2, 5, 5, 2, 2, 6, 5, 1, 5, 4],
})
GA_X = np.array(df.groupby('Time')['GroupA_X'].apply(list).tolist())
GA_Y = np.array(df.groupby('Time')['GroupA_Y'].apply(list).tolist())
fig, ax = plt.subplots(figsize = (6,6))
ax.grid(False)
ax.set_xlim(0,10)
ax.set_ylim(0,10)
data = np.stack([GA_X, GA_Y], axis = 2)
vector1 = ax.annotate('', xy = data[0][0],
xytext = data[0][1],
arrowprops={'arrowstyle': "-", 'color': 'black'},
ha='center')
vector2 = ax.annotate('', xy = data[0][0],
xytext = data[0][2],
arrowprops={'arrowstyle': "-", 'color': 'black'},
ha='center')
vector3 = ax.annotate('', xy = data[0][1],
xytext = data[0][2],
arrowprops={'arrowstyle': "-", 'color': 'black'},
ha='center')
def animate(i):
start1 = np.r_[data[i, 0]]
end1 = np.r_[data[i, 1]]
vector1.set_position(start1)
vector1.xy = end1
start2 = np.r_[data[i, 0]]
end2 = np.r_[data[i, 2]]
vector2.set_position(start2)
vector2.xy = end2
start3 = np.r_[data[i, 1]]
end3 = np.r_[data[i, 2]]
vector3.set_position(start3)
vector3.xy = end3
return
ani = animation.FuncAnimation(fig, animate, interval = 100, blit = False)
出局:
data = np.stack([GA_X, GA_Y], axis = 2)
axis = normalize_axis_index(axis, result_ndim)
AxisError: axis 2 is out of bounds for array of dimension 2
答案 0 :(得分:4)
根据我的理解,您想绘制每个项目的每个时间步ia线,其中每行的两个点首先是时间步i的(x,y),其次是点(x,y)在时间步长i + 1中。
(因此,如果该项目未出现在时间步骤i + 1中,我们将不会在步骤i中显示该项目的行)
假设我建议:
1)使用数据框本身,而不是将其更改为np.array
2)在动画功能内移动线条的创建
import matplotlib.pyplot as plt
from matplotlib import animation
from numpy import random
import random
import pandas as pd
import numpy as np
df1 = pd.DataFrame({
'Time' : [1,1,1,1,2,2,2,2,3,3,3,4,4,4],
'Item' : ['A', 'B', 'C', 'D','A', 'B', 'C', 'D', 'A', 'B', 'C', 'A', 'B', 'C'],
'GroupA_X' : [3, 4, 5, 1, 2, 5, 6, 2, 1, 6, 7, 2, 7, 8],
'GroupA_Y' : [2, 4, 5, 1, 2, 5, 5, 2, 2, 6, 5, 1, 5, 4],
})
# generating the figure configs
frame_num = len(df1['Time'].unique())
fig = plt.figure()
ax1 = plt.axes(xlim=(0, 10), ylim=(0, 10))
line, = ax1.plot([], [], lw=2)
plt.xlabel('X')
plt.ylabel('Y')
plotlays, itemColors = [2], {'A':"black",
'B':"red",
'C':"blue",
'D':"purple"}
def animate(i):
lines = []
# filtering items per time step
for (row_idx, row) in df1[df1["Time"] == i+1].iterrows():
nextTimestep_item = df1[(df1["Time"] == i+2) & (df1["Item"] ==row["Item"])]
if nextTimestep_item.empty:
# no plot if item is not on next timestep
continue
else:
x = [row['GroupA_X'],nextTimestep_item['GroupA_X']]
y = [row['GroupA_Y'],nextTimestep_item['GroupA_Y']]
color = itemColors[row["Item"]]
lobj = ax1.plot([],[],lw=2,color=color)[0]
lobj.set_data(x, y)
lines.append(lobj)
return lines
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate,
frames=frame_num, interval=500, blit=True)
plt.show()