How to Animate multiple columns as dots with matpl

2019-08-20 08:53发布

I have a question that maybe is asked before, but I couldn't find any post describing my problem.

I have two pandas dataframes, each with the same index, representing x coordinates in one dataframe and y coordinates in the other. Each colum represent a car that started a specific timestep, logged every step until it arrived, and then stopped logging.

Everytime a car starts on its route, a column is added to each dataframe and the coordinates of each step are added to each frame (every step it moves trough space therefor has new x,y coordinates), (see example for the x coordinates dataframe)

enter image description here

But I am trying to animate the tracks of each car by plotting the coordinates in an animated graph, but I cannot seem to get it worked. My code:

    %matplotlib notebook
from matplotlib import animation
from JSAnimation import IPython_display
from IPython.display import HTML

fig = plt.figure(figsize=(10,10))
#ax = plt.axes()


#nx.draw_networkx_edges(w_G,nx.get_node_attributes(w_G, 'pos'))
n_steps = simulation.x_df.index

def init():
    graph, = plt.plot([],[],'o')
    return graph,

def get_data_x(i):
    return simulation.x_df.loc[i]

def get_data_y(i):
    return simulation.y_df.loc[i]


def animate(i):
    x = get_data_x(i)
    y= get_data_y(i)
    graph.set_data(x,y)
    return graph,


animation.FuncAnimation(fig, animate, frames=100, init_func = init, repeat=True)

plt.show()

It does not plot anything, so any help would be very much appreciated.


EDIT: Minimal, Complete, and Verifiable example!

So two simple examples of the x and y dataframes that I have. Each has the same index.

import random
import geopandas as gpd
import networkx as nx
import matplotlib.pyplot as plt
import numpy as np
import math
import pandas as pd
from shapely.geometry import Point
from matplotlib import animation
from JSAnimation import IPython_display
%matplotlib inline



[IN]:   df_x = pd.DataFrame(data=np.array([[np.NaN, np.NaN, np.NaN, np.NaN], [4, np.nan, np.NaN,np.NaN], [7, 12, np.NaN,np.NaN], [6, 18, 12,9]]), index= [1, 2, 3, 4], columns=[1, 2, 3, 4])

gives:

[OUT]

         1     2     3    4
    1  NaN   NaN   NaN  NaN
    2  4.0   NaN   NaN  NaN
    3  7.0  12.0   NaN  NaN
    4  6.0  18.0  12.0  9.0

And the y coordinate dataframe:

[IN] df_y = pd.DataFrame(data=np.array([[np.NaN, np.NaN, np.NaN, np.NaN], [6, np.nan, np.NaN,np.NaN], [19, 2, np.NaN,np.NaN], [4, 3, 1,12]]), index= [1, 2, 3, 4], columns=[1, 2, 3, 4])'

gives:

[OUT]
          1    2    3     4
    1   NaN  NaN  NaN   NaN
    2   6.0  NaN  NaN   NaN
    3  19.0  2.0  NaN   NaN
    4   4.0  3.0  1.0  12.0

Now I want to create an animation, by creating a frame by plotting the x coordinate and the y coordinate of each column per each row of both dataframes. In this example, frame 1 should not contain any plot. Frame 2 should plot point (4.0 , 6.0) (of column 1). Frame 3 should plot point (7.0,19.0) (column1) and point (12.0,2.0) (column 2). Frame 4 should plot point (6.0, 4.0) (column 1), point (18.0,3.0) (column 2), point (12.0,1.0) (column 3) and (9.0, 12.0) column 4. Therefore I wrote the following code:

I tried writing the following code to animate this:

  [IN] %matplotlib notebook
from matplotlib import animation
from JSAnimation import IPython_display
from IPython.display import HTML

fig = plt.figure(figsize=(10,10))
#ax = plt.axes()

graph, = plt.plot([],[],'o')

def get_data_x(i):
    return df_x.loc[i]

def get_data_y(i):
    return df_y.loc[i]


def animate(i):
    x = get_data_x(i)
    y= get_data_y(i)
    graph.set_data(x,y)
    return graph,

animation.FuncAnimation(fig, animate, frames=4, repeat=True)
plt.show()

But this does not give any output. Any suggestions?

1条回答
我欲成王,谁敢阻挡
2楼-- · 2019-08-20 09:32

I've reformatted your code, but I think your main issue was that your dataframes start with a index of 1, but when you're calling your animation with frames=4, it's calling update() with i=[0,1,2,3]. Therefore when you do get_data_x(0) you raise a KeyError: 'the label [0] is not in the [index]'

As per the documentation, frames= can be passed an iterable instead of an int. Here, I simply pass the index of your dataframe, and the function will iterate and call update() with each value. Actually, I decided to pass the intersection of your two dataframe indexes, that way, if there is one index present in one dataframe but not the other, it will not raise an Error. If you are garanteed that your two indexes are the same, then you could just do frames=df_x.index

x_ = """        1     2     3    4
    1  NaN   NaN   NaN  NaN
    2  4.0   NaN   NaN  NaN
    3  7.0  12.0   NaN  NaN
    4  6.0  18.0  12.0  9.0
"""
y_ = """1    2    3     4
    1   NaN  NaN  NaN   NaN
    2   6.0  NaN  NaN   NaN
    3  19.0  2.0  NaN   NaN
    4   4.0  3.0  1.0  12.0"""
df_x = pd.read_table(StringIO(x_), sep='\s+')
df_y = pd.read_table(StringIO(y_), sep='\s+')


fig, ax = plt.subplots(figsize=(5, 5))
graph, = ax.plot([],[], 'o')
# either set up sensible limits here that won't change during the animation
# or see the comment in function `update()`
ax.set_xlim(0,20)
ax.set_ylim(0,20)


def get_data_x(i):
    return df_x.loc[i]

def get_data_y(i):
    return df_y.loc[i]

def update(i):
    x = get_data_x(i)
    y = get_data_y(i)
    graph.set_data(x,y)
    # if you don't know the range of your data, you can use the following
    # instructions to rescale the axes.
    #ax.relim()
    #ax.autoscale_view()
    return graph,


# Creating the Animation object
ani = animation.FuncAnimation(fig, update,  
                              frames=pd.Index.intersection(df_x.index,df_y.index),
                              interval=500, blit=False)
plt.show()

enter image description here

查看更多
登录 后发表回答