【问题标题】:Animate changing amount of lines between points - Python动画改变点之间的线条数量 - Python
【发布时间】:2020-06-24 02:34:57
【问题描述】:

这个问题与其他动画问题不同,因为我试图为点之间的交替数量的线设置动画。例如,可能在 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

【问题讨论】:

  • @Diziet Asahi。我试图适应这一点,但它略有不同。我需要动画线条
  • 有数百个关于如何animate a line plot 的示例。如果您有很多行 (>50),您可以考虑使用行集合(请参阅 this),但对于小数字或低帧率可能会过大。
  • 如果行数是动态的怎么办。例如,一帧可能是 10,另一帧可能是 100
  • 你能澄清一下你想要制作的情节吗?您想在每个时间步为每个“项目”创建一行吗?因此,即 tiimestep 2 将有 4 行(每个项目一个,但 timestep 3 应该有 3 行?)

标签: python pandas matplotlib animation


【解决方案1】:

根据我的理解,您希望在每个时间步长为每个项目绘制 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()

【讨论】:

    猜你喜欢
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-14
    • 1970-01-01
    • 2016-08-25
    相关资源
    最近更新 更多