Animate a annotation from a list of XY Coordinates

2019-08-26 09:52发布

问题:

I am trying to animate annotations from a list of xy coordinates. The code below animates the annotation line but I cannot get the arrow function to animate using the same code.

The example dataset is a representation of the data I'm using. It is horizontally formatted. With this, I make a list from all the X-Coordinates and all the Y-Coordiantes from each subject. I then make a list pertaining to each time point, which is each row of data. From that I can plot a scatter and annotations.

However, when trying to plot an arrow between two separate coordinates I run into the error as stated by @ImportanceOfBeingErnest. The function should be a tuple of two elements but I'm having trouble with the arrow animation function as I think I need to provide 4 elements. The X and Y coordinate for the first point and X and Y coordinate for the second point.

Will I have to re-format that data or is there a way to animate the arrow function were 4 tuples are required?

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

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

lists = [[],[]]
lists[0] = x_data
lists[1] = y_data 

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

scatter = ax.scatter(lists[0][0], lists[1][0], zorder = 5) #Scatter plot

annotation = ax.annotate('  Subject 1', xy=(lists[0][0][2],lists[1][0][2]))

arrow = ax.annotate('', xy = (lists[0][0][0], lists[1][0][0]), xytext = (lists[0][0][1],lists[1][0][1]), arrowprops = {'arrowstyle': "<->"})

def animate(i) : 
    scatter.set_offsets([[[[[lists[0][0+i][0], lists[1][0+i][0]], [lists[0][0+i][1], lists[1][0+i][1]], [lists[0][0+i][2], lists[1][0+i][2]], [lists[0][0+i][3], lists[1][0+i][3]]]]]])
    Subject_x = lists[0][0+i][2]
    Subject_y = lists[1][0+i][2]
    annotation.set_position((Subject_x, Subject_y))
    annotation.xy = (Subject_x, Subject_y)
    Arrow1 = (lists[0][0+i][0], lists[1][0+i][0]) #Code for arrow animation doesn't work. Produces a blank screen after the 1st frame
    Arrow2 = (lists[0][0+i][1], lists[1][0+i][1])
    arrow.set_position((Arrow1, Arrow2))
    arrow.xy = (Arrow1, Arrow2)

ani = animation.FuncAnimation(fig, animate,
                          interval = 50, blit = False)

plt.show()

回答1:

The solution to this is still given in this question: Animate points with labels with mathplotlib

As said several times in the comments, each position is determined by a tuple of two values (x,y). Hence you cannot provide a tuple of tuples to those positions. Also the start and end of the arrow should of course be at different positions.

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

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

annotation = ax.annotate('  Subject 1', xy=(x_data[0,2],y_data[0,2]))

arrow = ax.annotate('', xy = (x_data[0,0], y_data[0,0]), 
                        xytext = (x_data[0,1],y_data[0,1]), 
                        arrowprops = {'arrowstyle': "<->"})

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

    annotation.set_position((x_data[i,2], y_data[i,2]))

    start = (x_data[i,0], y_data[i,0]) 
    end   = (x_data[i,1], y_data[i,1])
    arrow.set_position(start)
    arrow.xy = end

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

plt.show()