【问题标题】:How to funcanimation seaborn's lmplot如何对 seaborn 的 lmplot 进行 funcanimation
【发布时间】:2018-07-23 06:49:45
【问题描述】:

(这是this问题的扩展)

你好

我正在尝试使用新数据更新 lmplot,但无法找到将其连接到现有图形/轴的方法,因为它们有自己的。到目前为止,我已经尝试过这样的:

%matplotlib notebook

import matplotlib.animation as animation
import numpy as np

#fig, ax = plt.subplots(1,1,figsize=(5,4))

df = get_data()
g = sns.lmplot( x='Mean', y='Variance', data=df, fit_reg=False, hue='Size', legend=False, palette=cmap)

def get_data():
    takeRandomSample(population, popSize, popVar)   
    current_elem = len(sampleStats)-1
    current_size = sampleStats[current_elem][0]
    current_mean = sampleStats[current_elem][1]
    current_var =  sampleStats[current_elem][2]

    data = {'Size' : current_size, 'Mean' : current_mean, 'Variance' : current_var}
    df = pd.DataFrame(data, index=[0])

    return df


def prep_axes(g):
    g.set(xlim=(0, 20), ylim=(0, 100), xticks=range(0,21))    

    ax = g.axes[0,0]       
    ax.axvline(x=popMean, color='#8c8ca0', ls='dashed')
    ax.axhline(y=popVar, color='#8c8ca0', ls='dashed')
    ax.set_title('Sample Statistics :{}'.format(i))
    ax.set_facecolor(backgroundColour)

def animate(i):
    df = get_data()
    g = sns.lmplot( x='Mean', y='Variance', data=df, fit_reg=False, hue='Size', legend=False, palette=cmap)
    prep_axes(g, i)


# initialize samples
sampleStats = []

plt.tight_layout()

ani = animation.FuncAnimation(g.fig, animate, frames = np.arange(1,100), interval=100)

输出:

问题:
1. 这只会产生一个静态图,因为我找不到更新现有 g 的方法,并在同一个 g 的图形 lmsplot 上重新绘制。 animate 函数正在创建新的 g
2. 我不得不进行一次不必要的初始化以让 g 对象将 g.fig 传递给 funcanimation,但由于第 1 点,这也无济于事。

我们如何使用 lmplot 制作动画?由于色调功能,我想使用它而不是常规的 matplotlib。

我也尝试直接使用 facetgrid(并在 g.map 中传递 lmplot),但这也无济于事。

【问题讨论】:

  • funcanimationlmplot 结合使用会很困难,而且可能会适得其反。但是,您似乎没有使用 lmplot 的任何功能(无回归,无方面)仅hue?自己分离色调类别会容易得多,或者考虑使用新的seaborn.scatterplot()。如果您需要更多帮助,您需要提供Minimal, Complete, and Verifiable example
  • 请找到它here 它是所有sn-ps的笔记本。我被困在最后一部分。现在我得到单独的静态图,而不是动画,因为每次都有单独的g 更新。请帮忙

标签: python matplotlib plotly seaborn


【解决方案1】:

为了记录,如果您没有任何方面并且您不关心回归,那么您可以通过以下方式为 lmplot() 设置动画:

import seaborn as sns; sns.set(color_codes=True)
tips = sns.load_dataset("tips")
g = sns.lmplot(x="total_bill", y="tip", hue="smoker", data=tips, fit_reg=False)
fig = g.fig
ax = g.axes[0,0]
scatters = [c for c in ax.collections if isinstance(c, matplotlib.collections.PathCollection)]
txt = ax.text(0.1,0.9,'frame=0', transform=ax.transAxes)

def animate(i):
    for c in scatters:
        # do whatever do get the new data to plot
        x = np.random.random(size=(50,1))*50
        y = np.random.random(size=(50,1))*10
        xy = np.hstack([x,y])
        # update PathCollection offsets
        c.set_offsets(xy)
    txt.set_text('frame={:d}'.format(i))
    return scatters+[txt]

ani = matplotlib.animation.FuncAnimation(fig, animate, frames=10, blit=True)

但是在这种情况下,您可以通过完全不使用 lmplot 以更直接的方式获得几乎完全相同的结果:

import seaborn as sns; sns.set(color_codes=True)
tips = sns.load_dataset("tips")

fig, ax = plt.subplots()
scatters = []
for g,d in tips.groupby('smoker'):
    s = ax.scatter(x="total_bill", y="tip", data=tips, label=g)
    scatters.append(s)
ax.legend(bbox_to_anchor=(1.,1.), loc=1)
txt = ax.text(0.1,0.9,'frame=0', transform=ax.transAxes)

def animate(i):
    for c in scatters:
        x = np.random.random(size=(50,1))*50
        y = np.random.random(size=(50,1))*10
        xy = np.hstack([x,y])
        c.set_offsets(xy)
    txt.set_text('frame={:d}'.format(i))
    return scatters+[txt]

ani = matplotlib.animation.FuncAnimation(fig, animate, frames=10, blit=True)

从上面的代码中,将新值附加到以前的数据中是相当简单的,而不是替换所有的点:

import seaborn as sns; sns.set(color_codes=True)
tips = sns.load_dataset("tips")

fig, ax = plt.subplots()
scatters = []
for g,d in tips.groupby('smoker'):
    s = ax.scatter([], [], label=g)
    scatters.append(s)
ax.legend(bbox_to_anchor=(1.,1.), loc=1)
txt = ax.text(0.1,0.9,'frame=0', transform=ax.transAxes)
ax.set_xlim((0,60))
ax.set_ylim((0,15))

def animate(i, df, x, y, hue):
    new_data = df.sample(20) # get new data here
    for c,(groupname,subgroup) in zip(scatters,new_data.groupby(hue)):
        xy = c.get_offsets()
        xy = np.append(xy,subgroup[[x,y]].values, axis=0)
        c.set_offsets(xy)
    txt.set_text('frame={:d}'.format(i))
    return scatters+[txt]

ani = matplotlib.animation.FuncAnimation(fig, animate, fargs=(tips, "total_bill", "tip", 'smoker'), frames=10, blit=True)

【讨论】:

  • 肯定会尝试使用 matplotlib 本身,但希望尽快完成这些。以您的 seaborn 示例为例,除了小故障外,几乎可以正常工作。 Matplotlib 似乎没有正确间隔标题,它被剪掉了。更重要的是,帧被重新绘制,因此不保留较早的帧点。我更新的代码here,输出截图here,想要的效果here
  • 据我了解,我们正在抓取当前数据点句柄,并根据每帧的新数据将其偏移到新位置。相反,我们需要保留过去帧的旧数据点,对于新帧,在相同轴上添加新数据点。一种动态散点图。
  • 我已经修改了上面的答案
  • 非常感谢。您能否在 lmplot 中提供,因为我希望有更多的用例,所以拥有 lmplot 解决方案也会非常有帮助。
猜你喜欢
  • 2014-07-17
  • 2020-11-09
  • 2021-09-06
  • 2018-02-28
  • 1970-01-01
  • 2019-06-20
  • 2022-11-17
  • 2019-02-13
  • 1970-01-01
相关资源
最近更新 更多