2017-09-15 23 views
5

Niektóre metody seaborn, takie jak create new figures on each call. Dzięki temu niemożliwe jest utworzenie prostej animacji, takiej jak w przypadku matplotlib, w której wielokrotne wywołania do plt.cla() lub plt.clf() umożliwiają aktualizowanie zawartości figury bez zamykania/otwierania okna za każdym razem.Przerysowywanie liczb Seaborn dla animacji

Jedynym rozwiązaniem Obecnie widzę to:

for t in range(iterations): 
    # .. update your data .. 

    if 'jp' in locals(): 
     plt.close(jp.fig) 

    jp = sns.jointplot(x=data[0], y=data[1]) 
    plt.pause(0.01) 

To działa, ponieważ zamykamy poprzedniego okna tuż przed utworzeniem nowego. Ale oczywiście nie jest to idealne.

Czy istnieje lepszy sposób? Czy działka może zostać wykonana bezpośrednio na wcześniej wygenerowanym obiekcie Figure? A może istnieje sposób, aby zapobiec tym metodom generowania nowych liczb przy każdym wywołaniu?

Odpowiedz

4

Niestety, sns.jointplot tworzy samodzielnie liczbę. Aby ożywić plan połączenia, można zatem ponownie użyć tej utworzonej figury, zamiast odtwarzać nową w każdej interakcji.

jointplot wewnętrznie tworzy JointGrid, więc ma sens bezpośrednie użycie tego i wykreślić osie wspólne i marginesy indywidualnie. Na każdym etapie animacji można zaktualizować dane, wyczyścić osie i ustawić je tak samo, jak podczas tworzenia siatki. Niestety ten ostatni krok obejmuje wiele linii kodu.

Ostateczny kod może wtedy wyglądać następująco:

import matplotlib.pyplot as plt 
import matplotlib.animation 
import seaborn as sns 
import numpy as np 

def get_data(i=0): 
    x,y = np.random.normal(loc=i,scale=3,size=(2, 260)) 
    return x,y 

x,y = get_data() 
g = sns.JointGrid(x=x, y=y, size=4) 
lim = (-10,10) 

def prep_axes(g, xlim, ylim): 
    g.ax_joint.clear() 
    g.ax_joint.set_xlim(xlim) 
    g.ax_joint.set_ylim(ylim) 
    g.ax_marg_x.clear() 
    g.ax_marg_x.set_xlim(xlim) 
    g.ax_marg_y.clear() 
    g.ax_marg_y.set_ylim(ylim) 
    plt.setp(g.ax_marg_x.get_xticklabels(), visible=False) 
    plt.setp(g.ax_marg_y.get_yticklabels(), visible=False) 
    plt.setp(g.ax_marg_x.yaxis.get_majorticklines(), visible=False) 
    plt.setp(g.ax_marg_x.yaxis.get_minorticklines(), visible=False) 
    plt.setp(g.ax_marg_y.xaxis.get_majorticklines(), visible=False) 
    plt.setp(g.ax_marg_y.xaxis.get_minorticklines(), visible=False) 
    plt.setp(g.ax_marg_x.get_yticklabels(), visible=False) 
    plt.setp(g.ax_marg_y.get_xticklabels(), visible=False) 


def animate(i): 
    g.x, g.y = get_data(i) 
    prep_axes(g, lim, lim) 
    g.plot_joint(sns.kdeplot, cmap="Purples_d") 
    g.plot_marginals(sns.kdeplot, color="m", shade=True) 

frames=np.sin(np.linspace(0,2*np.pi,17))*5 
ani = matplotlib.animation.FuncAnimation(g.fig, animate, frames=frames, repeat=True) 

plt.show() 

enter image description here

+0

ja podejrzewać coś takiego. Chciałbym, żeby było to bardziej proste, ale to ładnie wykonuje pracę, więc dziękuję bardzo. – runDOSrun

+0

Z kodu źródłowego seaborn widać, że wyraźnie nie został napisany z myślą o animowaniu wątków. W zależności od tego, jaki jest ostateczny cel, oczywiście można dokonać pewnych optymalizacji; Zastanawiam się nad podklasą JointGrid, aby była ona bardziej podatna na aktualizacje, umieszczając to w nowym module i wywołując go w razie potrzeby - jednak miałoby to sens tylko wtedy, gdyby trzeba było częściej wykonywać takie animacje. Należy również pamiętać, że seaborn w większości owija matplotlib, tak że rozwiązaniem może być replikacja tego, co jointplot robi wyłącznie z matplotlib. – ImportanceOfBeingErnest

Powiązane problemy