Redrawing Seaborn Figures for Animations
sns.jointplot
creates a figure by itself. In order to animate the jointplot, one might therefore reuse this created figure instead of recreating a new one in each iteration.
jointplot
internally creates a JointGrid
, so it makes sense to directly use this and plot the joint axes and the marginals individually. In each step of the animation one would then update the data, clear the axes and set them up just as during creation of the grid. Unfortunately, this last step involves a lot of code lines.
The final code may then look like:
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()
using the celluloid
package (https://github.com/jwkvam/celluloid) I was able to animate seaborn plots without much hassle:
import numpy as np
from celluloid import Camera
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
fig = plt.figure()
camera = Camera(fig)
# animation draws one data point at a time
for i in range(0, data.shape[0]):
plot = sns.scatterplot(x=data.x[:i], y=data.y[:i])
camera.snap()
anim = camera.animate(blit=False)
anim.save('animation.mp4')
I'm sure similar code could be written for jointplots