Python 设置散布和等高线图的动画

Python 设置散布和等高线图的动画,python,pandas,matplotlib,animation,plot,Python,Pandas,Matplotlib,Animation,Plot,我正试图在正常运行的动画轮廓内生成动画散点绘图。我可以让他们分开工作,但不能一起工作 下面的代码根据df中的坐标A和B生成轮廓。我尝试使用C坐标在示例绘图中包含一个单独的动画散点。此尝试当前已被注释掉 因此,我基本上想使用C_X和C_Y包含另一个动画散点。我尝试将它们应用到行\u c import numpy as np import pandas as pd import matplotlib.pyplot as plt import scipy.stats as sts import mat

我正试图在正常运行的
动画
轮廓内生成
动画
散点
绘图
。我可以让他们分开工作,但不能一起工作

下面的代码根据
df
中的坐标
A
B
生成
轮廓。我尝试使用
C
坐标在示例
绘图中包含一个单独的动画
散点
。此尝试当前已被注释掉

因此,我基本上想使用
C_X
C_Y
包含另一个
动画
散点
。我尝试将它们应用到
行\u c

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import scipy.stats as sts
import matplotlib.animation as animation
import matplotlib.transforms as transforms

''' Section 1 '''

DATA_LIMITS = [-85, 85]

def datalimits(*data):
    return DATA_LIMITS  # dmin - spad, dmax + spad

def mvpdf(x, y, xlim, ylim, radius=1, velocity=0, scale=0, theta=0):
    X,Y = np.meshgrid(np.linspace(*xlim), np.linspace(*ylim))
    XY = np.stack([X, Y], 2)
    PDF = sts.multivariate_normal([x, y]).pdf(XY)
    return X, Y, PDF

def mvpdfs(xs, ys, xlim, ylim, radius=None, velocity=None, scale=None, theta=None):
    PDFs = []
    for i,(x,y) in enumerate(zip(xs,ys)):
        X, Y, PDF = mvpdf(x, y, xlim, ylim)
        PDFs.append(PDF)

    return X, Y, np.sum(PDFs, axis=0)

''' Animate Plot '''

fig, ax = plt.subplots(figsize = (10,6))
ax.set_xlim(DATA_LIMITS)
ax.set_ylim(DATA_LIMITS)

#Animated coordinates for group A,B
line_a, = ax.plot([], [], '.', c='red', alpha = 0.5, markersize=5, animated=True)
line_b, = ax.plot([], [], '.', c='blue', alpha = 0.5, markersize=5, animated=True)

#Attempt to incorporate scatter for C 
line_c, = ax.plot([], [], '.', c='white', alpha = 0.5, markersize=2.5, animated=True)

cfs = None

def plotmvs(tdf, xlim=None, ylim=None, fig=fig, ax=ax):
    global cfs  
    if cfs:
        for tp in cfs.collections:
            # Remove the existing contours
            tp.remove()

    # Get the data frame for time t
    df = tdf[1]

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

    PDFs = []

    for (group, gdf), group_line in zip(df.groupby('group'), (line_a, line_b)):
        group_line.set_data(*gdf[['X','Y']].values.T)
        X, Y, PDF = mvpdfs(gdf['X'].values, gdf['Y'].values, xlim, ylim)
        PDFs.append(PDF)

    normPDF = PDF - PDF.min()
    normPDF = normPDF / normPDF.max()
    cfs = ax.contourf(X, Y, normPDF, cmap='viridis', alpha = 1, levels=np.linspace(-1,1,10))

#Create offset scatter for Group C
#    for (group, g2df), group_line in zip(df.groupby('group'), (line_c)):    
#        group_line.set_data(*g2df[['XX','YY']].values.T)

#        offset = lambda p: transforms.ScaledTranslation(p/82.,0, plt.gcf().dpi_scale_trans)
#        trans = plt.gca().transData
#        ax.scatter(line_c,transform=trans+offset(+2))


    return cfs.collections + [line_a, line_b]#, line_c] 

n = 10
time = range(n)  

d = ({
     'A1_X' :    [13.3,13.16,12.99,12.9,12.79,12.56,12.32,12.15,11.93,11.72],
     'A1_Y' :    [26.12,26.44,26.81,27.18,27.48,27.82,28.13,28.37,28.63,28.93],
     'A2_X' :    [6.97,6.96,7.03,6.98,6.86,6.76,6.55,6.26,6.09,5.9],
     'A2_Y' :    [10.92,10.83,10.71,10.52,10.22,10.02,9.86,9.7,9.54,9.37],
     'B1_X' :    [38.35,38.1,37.78,37.55,37.36,37.02,36.78,36.46,36.21,35.79],
     'B1_Y' :    [12.55,12.58,12.58,12.55,12.5,12.47,12.43,12.48,12.44,12.44],
     'B2_X' :    [14.6,14.38,14.16,13.8,13.45,13.11,12.71,12.3,12.06,11.61],
     'B2_Y' :    [4.66,4.44,4.24,4.1,4.01,3.84,3.67,3.56,3.44,3.47],
#    'C_X' :    [10,15,18,20,30,33,35,42,34,20],
#    'C_Y' :    [10,16,20,10,20,13,15,12,14,10],                 
     })

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 = 200
delay_ms = 1000
ani = animation.FuncAnimation(fig, plotmvs, frames=df.groupby('time'),
            blit=True, interval=interval_ms, repeat_delay=delay_ms)

plt.show()

好的,所以我不得不改变一些事情:

  • 最重要的是,我在
    行a
    行b
    的定义中关闭了
    blit=True
    (主要是因为我在Mac电脑上,这不完全受支持,因此您的里程可能会有所不同)和
    animated=True
  • 您在代码注释中创建的组“C”缺少一个整数,因此
    元组=[…]
    代码无法工作(它希望找到一个
    int(k.split(“”“)[0][1://code>)
  • 散点图应该是
    .scatter()
    ,因为在
    FuncAnimation
    中没有使用
    init\u func=init
    调用,所以我们可以在动画函数本身中“动态”创建它
  • 我为
循环添加了第二个
,带有一个
if group=='C'
案例——尽管你可以更优雅地解决这个问题——它创建了散点图
scat
  • 我将
    ax.tourtf()中的级别设置为间隔[0,1],但从我的角度来看,这完全是迂腐的;-)
  • 我在所有打印项目中添加了
    zorder=
    ,以控制它们在哪个z平面上打印(可选,但很有用),并稍微调整了打印线的外观(可选,仅用于强调)
  • 最后,您需要确保返回的是一个iterable列表,因此可能是“奇数外观”
    return cfs.collections+[scat]+[line_a,line_b]
  • 绘图结果:

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import scipy.stats as sts
    import matplotlib.animation as animation
    import matplotlib.transforms as transforms
    from matplotlib.lines import Line2D
    
    ''' Section 1 '''
    
    DATA_LIMITS = [-85, 85]
    
    def datalimits(*data):
        return DATA_LIMITS  # dmin - spad, dmax + spad
    
    def mvpdf(x, y, xlim, ylim, radius=1, velocity=0, scale=0, theta=0):
        X,Y = np.meshgrid(np.linspace(*xlim), np.linspace(*ylim))
        XY = np.stack([X, Y], 2)
        PDF = sts.multivariate_normal([x, y]).pdf(XY)
        return X, Y, PDF
    
    def mvpdfs(xs, ys, xlim, ylim, radius=None, velocity=None, scale=None, theta=None):
        PDFs = []
        for i,(x,y) in enumerate(zip(xs,ys)):
            X, Y, PDF = mvpdf(x, y, xlim, ylim)
            PDFs.append(PDF)
    
        return X, Y, np.sum(PDFs, axis=0)
    
    ''' Animate Plot '''
    
    fig, ax = plt.subplots(figsize = (10,6))
    ax.set_xlim(DATA_LIMITS)
    ax.set_ylim(DATA_LIMITS)
    
    #Animated coordinates for group A,B
    line_a, = ax.plot([], [], '-o', c='red', alpha = 0.5, markersize=5,zorder=3)
    line_b, = ax.plot([], [], '-o', c='blue', alpha = 0.5, markersize=5,zorder=3)
    
    cfs = None
    
    def plotmvs(tdf, xlim=None, ylim=None, fig=fig, ax=ax):    
        global cfs  
        if cfs:
            for tp in cfs.collections:
                # Remove the existing contours
                tp.remove()
    
        # Get the data frame for time t
        df = tdf[1]
    
        if xlim is None: xlim = datalimits(df['X'])
        if ylim is None: ylim = datalimits(df['Y'])
    
        PDFs = []
    
        for (group, gdf), group_line in zip(df.groupby('group'), (line_a, line_b)):
            group_line.set_data(*gdf[['X','Y']].values.T)
            X, Y, PDF = mvpdfs(gdf['X'].values, gdf['Y'].values, xlim, ylim)
            PDFs.append(PDF)
    
        for (group, gdf) in df.groupby('group'):
            if group=='C':
                offset = lambda p: transforms.ScaledTranslation(p/82.,0, plt.gcf().dpi_scale_trans)
                trans = plt.gca().transData
                scat=ax.scatter(gdf['X'].values, gdf['Y'].values, 
                        marker='o', c='white', alpha = 0.5,zorder=3,
                        transform=trans+offset(+2) )#markersize=2,zorder=3)
    
    
        normPDF = PDF - PDF.min()
        normPDF = normPDF / normPDF.max()
    
        cfs = ax.contourf(X, Y, normPDF, cmap='viridis', alpha = 1, levels=np.linspace(0,1,10),zorder=1)
    
        return  cfs.collections + [scat] + [line_a,line_b] # make sure that these are iterable!
    
    n = 10
    time = range(n)  
    
    d = ({
        'A1_X' :    [13.3,13.16,12.99,12.9,12.79,12.56,12.32,12.15,11.93,11.72],
        'A1_Y' :    [26.12,26.44,26.81,27.18,27.48,27.82,28.13,28.37,28.63,28.93],
        'A2_X' :    [6.97,6.96,7.03,6.98,6.86,6.76,6.55,6.26,6.09,5.9],
        'A2_Y' :    [10.92,10.83,10.71,10.52,10.22,10.02,9.86,9.7,9.54,9.37],
        'B1_X' :    [38.35,38.1,37.78,37.55,37.36,37.02,36.78,36.46,36.21,35.79],
        'B1_Y' :    [12.55,12.58,12.58,12.55,12.5,12.47,12.43,12.48,12.44,12.44],
        'B2_X' :    [14.6,14.38,14.16,13.8,13.45,13.11,12.71,12.3,12.06,11.61],
        'B2_Y' :    [4.66,4.44,4.24,4.1,4.01,3.84,3.67,3.56,3.44,3.47],
        'C1_X' :    [10.,15.,18.,20.,30.,33.,35.,42.,34.,20.],## name contains an int so that tuples=... list works!
        'C1_Y' :    [10.,16.,20.,10.,20.,13.,15.,12.,14.,10.],
    })
    
    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 = 200
    delay_ms = 1000
    ani = animation.FuncAnimation(fig, plotmvs,  frames=df.groupby('time'), interval=interval_ms, repeat_delay=delay_ms,)
    
    plt.show()
    

    完整代码:

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import scipy.stats as sts
    import matplotlib.animation as animation
    import matplotlib.transforms as transforms
    from matplotlib.lines import Line2D
    
    ''' Section 1 '''
    
    DATA_LIMITS = [-85, 85]
    
    def datalimits(*data):
        return DATA_LIMITS  # dmin - spad, dmax + spad
    
    def mvpdf(x, y, xlim, ylim, radius=1, velocity=0, scale=0, theta=0):
        X,Y = np.meshgrid(np.linspace(*xlim), np.linspace(*ylim))
        XY = np.stack([X, Y], 2)
        PDF = sts.multivariate_normal([x, y]).pdf(XY)
        return X, Y, PDF
    
    def mvpdfs(xs, ys, xlim, ylim, radius=None, velocity=None, scale=None, theta=None):
        PDFs = []
        for i,(x,y) in enumerate(zip(xs,ys)):
            X, Y, PDF = mvpdf(x, y, xlim, ylim)
            PDFs.append(PDF)
    
        return X, Y, np.sum(PDFs, axis=0)
    
    ''' Animate Plot '''
    
    fig, ax = plt.subplots(figsize = (10,6))
    ax.set_xlim(DATA_LIMITS)
    ax.set_ylim(DATA_LIMITS)
    
    #Animated coordinates for group A,B
    line_a, = ax.plot([], [], '-o', c='red', alpha = 0.5, markersize=5,zorder=3)
    line_b, = ax.plot([], [], '-o', c='blue', alpha = 0.5, markersize=5,zorder=3)
    
    cfs = None
    
    def plotmvs(tdf, xlim=None, ylim=None, fig=fig, ax=ax):    
        global cfs  
        if cfs:
            for tp in cfs.collections:
                # Remove the existing contours
                tp.remove()
    
        # Get the data frame for time t
        df = tdf[1]
    
        if xlim is None: xlim = datalimits(df['X'])
        if ylim is None: ylim = datalimits(df['Y'])
    
        PDFs = []
    
        for (group, gdf), group_line in zip(df.groupby('group'), (line_a, line_b)):
            group_line.set_data(*gdf[['X','Y']].values.T)
            X, Y, PDF = mvpdfs(gdf['X'].values, gdf['Y'].values, xlim, ylim)
            PDFs.append(PDF)
    
        for (group, gdf) in df.groupby('group'):
            if group=='C':
                offset = lambda p: transforms.ScaledTranslation(p/82.,0, plt.gcf().dpi_scale_trans)
                trans = plt.gca().transData
                scat=ax.scatter(gdf['X'].values, gdf['Y'].values, 
                        marker='o', c='white', alpha = 0.5,zorder=3,
                        transform=trans+offset(+2) )#markersize=2,zorder=3)
    
    
        normPDF = PDF - PDF.min()
        normPDF = normPDF / normPDF.max()
    
        cfs = ax.contourf(X, Y, normPDF, cmap='viridis', alpha = 1, levels=np.linspace(0,1,10),zorder=1)
    
        return  cfs.collections + [scat] + [line_a,line_b] # make sure that these are iterable!
    
    n = 10
    time = range(n)  
    
    d = ({
        'A1_X' :    [13.3,13.16,12.99,12.9,12.79,12.56,12.32,12.15,11.93,11.72],
        'A1_Y' :    [26.12,26.44,26.81,27.18,27.48,27.82,28.13,28.37,28.63,28.93],
        'A2_X' :    [6.97,6.96,7.03,6.98,6.86,6.76,6.55,6.26,6.09,5.9],
        'A2_Y' :    [10.92,10.83,10.71,10.52,10.22,10.02,9.86,9.7,9.54,9.37],
        'B1_X' :    [38.35,38.1,37.78,37.55,37.36,37.02,36.78,36.46,36.21,35.79],
        'B1_Y' :    [12.55,12.58,12.58,12.55,12.5,12.47,12.43,12.48,12.44,12.44],
        'B2_X' :    [14.6,14.38,14.16,13.8,13.45,13.11,12.71,12.3,12.06,11.61],
        'B2_Y' :    [4.66,4.44,4.24,4.1,4.01,3.84,3.67,3.56,3.44,3.47],
        'C1_X' :    [10.,15.,18.,20.,30.,33.,35.,42.,34.,20.],## name contains an int so that tuples=... list works!
        'C1_Y' :    [10.,16.,20.,10.,20.,13.,15.,12.,14.,10.],
    })
    
    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 = 200
    delay_ms = 1000
    ani = animation.FuncAnimation(fig, plotmvs,  frames=df.groupby('time'), interval=interval_ms, repeat_delay=delay_ms,)
    
    plt.show()
    

    更新

    如果您希望有一个单一的移动点,同时最小化/简化代码行,您还可以通过以下方式启动绘图元素:

    line_a, = ax.plot([], [], '-o', c='red', alpha = 0.5, markersize=5,zorder=3)
    line_b, = ax.plot([], [], '-o', c='blue', alpha = 0.5, markersize=5,zorder=3)
    lines=[line_a,line_b] ## this is iterable!
    
    offset = lambda p: transforms.ScaledTranslation(p/82.,0, plt.gcf().dpi_scale_trans)
    trans = plt.gca().transData
    
    scat = ax.scatter([], [], s=5**2,marker='o', c='white', alpha = 0.5,zorder=3,transform=trans+offset(+2) )
    scats=[scat] ## this is iterable, too!
    
    然后在plotmvs()中:

    请注意,更新散点图和直线图使用不同的函数和坐标列表

    最后更新返回值:

    return  cfs.collections + scats + lines # make sure that these are iterable!
    
    这将生成以下动画:


    谢谢阿斯莫斯。我已经更改了
    行a,=ax.plot([],[],'o',c='red',alpha=0.5,markersize=5,zorder=3)
    。但我希望能有一个类似于其他小组的动画分散。不是为每一帧创建一个新的散射点。“我希望能有一个类似于其他组的动画散射”这太棒了。谢谢@Asmus。我在下面添加了第二种方法,它只对一个散点进行动画制作,语法与线形图中的类似。