在python matplotlib中对同一图上的2条线进行动画处理

时间:2020-07-27 22:54:23

标签: python pandas dataframe matplotlib animation

我正在为同一块情节的两条线设置动画。搜索之后,我发现this post似乎使我步入正轨。当我运行此代码时,停滞图没有动画显示,给我一个错误AttributeError: 'AxesSubplot' object has no attribute 'set_data'。我抬起头来set_data,它说“接受:2D数组(行是x,y)或两个1D数组”。因为我将line1line2分配给绘图而不是2D数组,所以动画不起作用吗?我会尽力使这些线条在我的情节上产生动画效果,我已经尝试并且尝试都没有成功。谢谢!

fig, ax = plt.subplots(figsize=(16,8))

#Plot Lines
line1 = sns.lineplot('game_seconds_remaining', 'away_wp', data=game, color='#4F2683',linewidth=2)
line2 = sns.lineplot('game_seconds_remaining', 'home_wp', data=game, color='#869397',linewidth=2)
#Add Fill
ax.fill_between(game['game_seconds_remaining'], 0.5, game['away_wp'], where=game['away_wp']>.5, color = '#4F2683',alpha=0.3)
ax.fill_between(game['game_seconds_remaining'], 0.5, game['home_wp'], where=game['home_wp']>.5, color = '#869397',alpha=0.3)


#Plot Aesthetics - Can Ignore
plt.ylabel('Win Probability %', fontsize=16)
plt.xlabel('', fontsize=16)
plt.axvline(x=900, color='white', alpha=0.7)
plt.axvline(x=1800, color='white', alpha=0.7)
plt.axvline(x=2700, color='white', alpha=0.7)
plt.axhline(y=.50, color='white', alpha=0.7)
plt.suptitle('Minnesota Vikings @ Dallas Cowboys', fontsize=20, style='italic',weight='bold')
plt.title('Min 28, DAL 24 - Week 10 ', fontsize=16, style = 'italic',weight='semibold')


#Labels (And variable assignment for animation below)
x = ax.set_xticks(np.arange(0, 3601,900))
y1 = game['away_wp']
y2 = game['home_wp']
plt.gca().invert_xaxis()
x_ticks_labels = ['End','End Q3','Half','End Q1','Kickoff']
ax.set_xticklabels(x_ticks_labels, fontsize=12)


#Animation - Not working
def update(num, x, y1, y2, line1, line2):
    line1.set_data(x[:num], y1[:num])
    line2.set_data(x[:num], y2[:num])
    return [line1,line2]

ani = animation.FuncAnimation(fig, update, len(x), fargs=[x, y1, y2, line1, line2],
                  interval=295, blit=False)

1 个答案:

答案 0 :(得分:1)

似乎sns给出了AxesSublot,您必须为此line(s)获得Axes

ax1 = sns.lineplot(...)
ax2 = sns.lineplot(...)

line1 = ax1.lines[0]
line2 = ax2.lines[1]

或者(因为两行在同一Axes上)

sns.lineplot(x=x, y='away_wp', data=game)
sns.lineplot(x=x, y='home_wp', data=game)

ax = plt.gca()

line1 = ax.lines[0]
line2 = ax.lines[1]

编辑:

Google Colab需要

from matplotlib import rc
rc('animation', html='jshtml')

# code without `plt.show()`

ani   # display it

来源:Embedding Matplotlib Animations in Python (google colab notebook)


带有随机数据的最小工作代码

import random
import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import animation
from matplotlib import rc
rc('animation', html='jshtml')

game = pd.DataFrame({
    'away_wp': [random.randint(-10,10) for _ in range(100)],
    'home_wp': [random.randint(-10,10) for _ in range(100)],
    'game_seconds_remaining': list(range(100)),
})

x = range(len(game))
y1 = game['away_wp']
y2 = game['home_wp']

fig = plt.gcf()
ax = plt.gca()

sns.lineplot(x='game_seconds_remaining', y='away_wp', data=game)
sns.lineplot(x='game_seconds_remaining', y='home_wp', data=game)

line1 = ax.lines[0]
line2 = ax.lines[1]

ax.fill_between(game['game_seconds_remaining'], 0.5, game['away_wp'], where=game['away_wp']>.5, color = '#4F2683',alpha=0.3)
ax.fill_between(game['game_seconds_remaining'], 0.5, game['home_wp'], where=game['home_wp']>.5, color = '#869397',alpha=0.3)
#print(ax.collections)

def update(num, x, y1, y2, line1, line2):
    line1.set_data(x[:num], y1[:num])
    line2.set_data(x[:num], y2[:num])

    ax.collections.clear()
    ax.fill_between(game['game_seconds_remaining'][:num], 0.5, game['away_wp'][:num], where=game['away_wp'][:num]>.5, color = '#4F2683',alpha=0.3)
    ax.fill_between(game['game_seconds_remaining'][:num], 0.5, game['home_wp'][:num], where=game['home_wp'][:num]>.5, color = '#869397',alpha=0.3)

    return line1,line2

ani = animation.FuncAnimation(fig, update, len(x), fargs=[x, y1, y2, line1, line2], interval=295, blit=False)

#plt.show()

ani   # display it

编辑:

没有seaborn,只有plt.plot()的情况。

开始时,我创建空行line1, = plt.plot([], [])

import random
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import animation
from matplotlib import rc
rc('animation', html='jshtml')

game = pd.DataFrame({
    'away_wp': [random.randint(-10,10) for _ in range(100)],
    'home_wp': [random.randint(-10,10) for _ in range(100)],
    'game_seconds_remaining': list(range(100)),
})

x = range(len(game))
y1 = game['away_wp']
y2 = game['home_wp']

fig = plt.gcf()
ax = plt.gca()

# empty lines at start
line1, = plt.plot([], [])
line2, = plt.plot([], [])

# doesn't draw fill_between at start

# set limits 
ax.set_xlim(0, 100)
ax.set_ylim(-10, 10)

def update(num, x, y1, y2, line1, line2):
    line1.set_data(x[:num], y1[:num])
    line2.set_data(x[:num], y2[:num])
    # autoscale 
    #ax.relim()
    #ax.autoscale_view()

    ax.collections.clear()
    ax.fill_between(game['game_seconds_remaining'][:num], 0.5, game['away_wp'][:num], where=game['away_wp'][:num]>.5, color = '#4F2683',alpha=0.3)
    ax.fill_between(game['game_seconds_remaining'][:num], 0.5, game['home_wp'][:num], where=game['home_wp'][:num]>.5, color = '#869397',alpha=0.3)
    
    return line1,line2

ani = animation.FuncAnimation(fig, update, len(x), fargs=[x, y1, y2, line1, line2], interval=295, blit=False)

#plt.show()

ani