【问题标题】:Plot multiple subplots as animations将多个子图绘制为动画
【发布时间】:2019-05-21 04:31:00
【问题描述】:

我有两个独立的subplots,我希望将它们显示为动画。对于下面的子图,ax1 显示动画scatter 图,而ax2 现在是散点图,我希望将其更改为line plot

请注意:我已将问题简化为仅显示相关信息。但是我希望保持代码与现在相似。

以下是我的尝试:

import matplotlib.pyplot as plt
import matplotlib.animation as animation
import pandas as pd

DATA_LIMITS = [0, 15]

def datalimits(*data):
    return DATA_LIMITS 

fig = plt.figure(figsize=(10,18))
grid = plt.GridSpec(1, 3, wspace=0.4, hspace=0.3)

gridsize = (3, 2)
ax1 = plt.subplot2grid(gridsize, (0, 0), colspan=2, rowspan=2)
ax2 = plt.subplot2grid(gridsize, (2, 0), colspan=2, rowspan=2)
ax1.grid(False)
ax2.grid(False)

ax1.set_xlim(DATA_LIMITS)
ax1.set_ylim(DATA_LIMITS)

line_a, = ax1.plot([], [], 'o', c='red', alpha = 0.5, markersize=5,zorder=3)
line_b, = ax1.plot([], [], 'o', c='blue', alpha = 0.5, markersize=5,zorder=3)
lines=[line_a,line_b] 

scat = ax1.scatter([], [], s=20, marker='o', c='white', alpha = 1,zorder=3)
scats=[scat] 

line_d = ax2.plot([], [], 'o', c = 'k')

ax2.set_ylim(-6,6) 
ax2.set_xlim(0,15) 

def plots(tdf, xlim=None, ylim=None, fig=fig, ax=ax1):

    df = tdf[1]

    if xlim is None: xlim = datalimits(df['X'])
    if ylim is None: ylim = datalimits(df['Y'])

    for (group, gdf), group_line in zip(df.groupby('group'), lines+scats+line_d):
        if group in ['A','B','D']:
            group_line.set_data(*gdf[['X','Y']].values.T)
        elif group in ['C']:
            gdf['X'].values, gdf['Y'].values
            scat.set_offsets(gdf[['X','Y']].values)

    return [scat] + [line_a,line_b] + [line_d]          

n = 9
time = range(n)  

d = ({
     'A1_X' :    [13,14,12,13,11,12,13,12,11,10],
     'A1_Y' :    [6,6,7,7,7,8,8,8,9,10],
     'A2_X' :    [7,6,5,7,6,3,4,5,6,6],
     'A2_Y' :    [11,12,11,10,11,12,10,11,10,9],
     'B1_X' :    [8,9,8,7,6,7,5,6,7,6],
     'B1_Y' :    [3,4,3,2,3,4,2,1,2,3],
     'B2_X' :    [13,14,14,14,13,13,13,12,12,12],
     'B2_Y' :    [5,4,3,2,4,5,4,6,3,3],
     'C1_X' :   [5,6,7,5,6,5,6,5,6,5],
     'C1_Y' :   [10,11,10,11,12,11,10,8,7,6],
     'D1_X' :   [0,1,2,3,4,5,6,7,8,9],           
     'D1_Y' :   [0,1,2,3,4,3,2,1,0,-1],                
    })

tuples = [((t, k.split('_')[0][0], int(k.split('_')[0][1:]), k.split('_')[1]), v[i])
    for k,v in d.items() for i,t in enumerate(time) ]

df = pd.Series(dict(tuples)).unstack(-1)
df.index.names = ['time', 'group', 'id']

interval_ms = 1000
delay_ms = 2000
ani = animation.FuncAnimation(fig, plots, frames=df.groupby('time'), interval=interval_ms, repeat_delay=delay_ms,)

plt.show()

【问题讨论】:

    标签: python pandas matplotlib animation plot


    【解决方案1】:

    编辑 3:我已删除所有以前的更新以保持干净;您仍然可以在编辑历史记录中查看它们。

    查看此代码是否符合您的要求,更改通过 cmets 进行标记:

    import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    import pandas as pd
    
    import numpy as np #<< a new import is required
    
    DATA_LIMITS = [0, 15]
    
    def datalimits(*data):
        return DATA_LIMITS 
    
    fig = plt.figure(figsize=(10,18))
    grid = plt.GridSpec(1, 3, wspace=0.4, hspace=0.3)
    
    gridsize = (3, 2)
    ax1 = plt.subplot2grid(gridsize, (0, 0), colspan=2, rowspan=2)
    ax2 = plt.subplot2grid(gridsize, (2, 0), colspan=2, rowspan=2)
    ax1.grid(False)
    ax2.grid(False)
    
    ax1.set_xlim(DATA_LIMITS)
    ax1.set_ylim(DATA_LIMITS)
    
    line_a, = ax1.plot([], [], 'o', c='red', alpha = 0.5, markersize=5,zorder=3)
    line_b, = ax1.plot([], [], 'o', c='blue', alpha = 0.5, markersize=5,zorder=3)
    lines=[line_a,line_b] 
    
    scat = ax1.scatter([], [], s=20, marker='o', c='white', alpha = 1,zorder=3)
    scats=[scat] 
    
    line_d = ax2.plot([], [], '-', c = 'k') ##<< using '-' makes this a line plot
    
    ax2.set_ylim(-6,6) 
    ax2.set_xlim(0,15) 
    
    def plots(tdf, xlim=None, ylim=None, fig=fig, ax=ax1):
    
        df = tdf[1]
    
        if xlim is None: xlim = datalimits(df['X'])
        if ylim is None: ylim = datalimits(df['Y'])
    
        for (group, gdf), group_line in zip(df.groupby('group'), lines+scats+line_d):
            if group in ['A','B']: #<< 'D' is moved to a new if case
                group_line.set_data(*gdf[['X','Y']].values.T)
            elif group in ['D']:
                if tdf[0]==0: #<< use this to "reset the line" when the animation restarts
                              ## or remove the if/else part here if you want continuous (over-)plotting
                    group_line.set_data([0,0])
                else:    
                    _x,_y=group_line.get_data()
                    _x=np.append(_x,gdf['X'].values)
                    _y=np.append(_y,gdf['Y'].values)
                    group_line.set_data([_x,_y])
    
            elif group in ['C']:
                gdf['X'].values, gdf['Y'].values
                scat.set_offsets(gdf[['X','Y']].values)
    
        return [scat] + [line_a,line_b] + [line_d]          
    
    n = 9
    time = range(n)  
    
    d = ({
         'A1_X' :    [13,14,12,13,11,12,13,12,11,10],
         'A1_Y' :    [6,6,7,7,7,8,8,8,9,10],
         'A2_X' :    [7,6,5,7,6,3,4,5,6,6],
         'A2_Y' :    [11,12,11,10,11,12,10,11,10,9],
         'B1_X' :    [8,9,8,7,6,7,5,6,7,6],
         'B1_Y' :    [3,4,3,2,3,4,2,1,2,3],
         'B2_X' :    [13,14,14,14,13,13,13,12,12,12],
         'B2_Y' :    [5,4,3,2,4,5,4,6,3,3],
         'C1_X' :   [5,6,7,5,6,5,6,5,6,5],
         'C1_Y' :   [10,11,10,11,12,11,10,8,7,6],
         'D1_X' :   [0,1,2,3,4,5,6,7,8,9],           
         'D1_Y' :   [0,1,2,3,4,3,2,1,0,-1],                
        })
    
    tuples = [((t, k.split('_')[0][0], int(k.split('_')[0][1:]), k.split('_')[1]), v[i])
        for k,v in d.items() for i,t in enumerate(time) ]
    
    df = pd.Series(dict(tuples)).unstack(-1)
    df.index.names = ['time', 'group', 'id']
    
    interval_ms = 1000
    delay_ms = 2000
    ani = animation.FuncAnimation(fig, plots, frames=df.groupby('time'), interval=interval_ms, repeat_delay=delay_ms,)
    
    plt.show()
    

    【讨论】:

    • 谢谢@Asmus。道歉我应该在问题中提到它应该遵守代码。我已经为 SO 目的减少了这个问题。但我的实际代码包含更多功能,需要按原样设置代码。
    • @jonboy 比你的问题只是(a)你的 line_d 只有 一个 坐标(也许你想要一个 .scatter() 代替?)(b ) 你没有将line_d 放入lines,因此它不会在你的for (group, gdf), group_line … 循环中进行动画处理。
    • @jonboy 我已经更新了顶部的答案,向您展示了您需要添加/更改的四行。
    • 谢谢@Asmus。这很好用。我一定是混淆了线图。我确实想要一个类似于您的第一个答案答案中调用的动画。 D_X 表示它是哪一帧,D_Y 显示相对值。因此,我希望将相同的值显示为动画线图,而不是 * 动画散点图。
    • @jonboy “我确实想要一个类似于你的第一个答案答案中调用的动画”scat.set_offset 更改为 group_line.set_offset() 并可能给 scat 赋予白色以外的颜色,才能看到它。
    猜你喜欢
    • 2018-04-27
    • 2018-01-16
    • 2021-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-19
    • 1970-01-01
    • 2021-12-23
    相关资源
    最近更新 更多