Skip to content
Advertisement

Animation issue in Python

I want the green rectangle to not disappear as it moves from one value to another in matrix b. For example, the rectangle is around 0.24671953. Then the rectangle stays on this value. Then another rectangle appears onto the next value which is 0.25959473. Then another rectangle appears on 0.41092171, with the previous two rectangles not disappearing.

import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
import seaborn as sns
import numpy as np
from celluloid import Camera

a = np.array([[0.24671953, 0.25959473, 0.85494718],
       [0.60553861, 0.76276659, 0.41092171],
       [0.37356358, 0.69378785, 0.46988614]])

b = np.array([[0.24671953,0.25959473],
 [0.41092171,0.46988614],
 [0.37356358,0.60553861]])

annot=True
fig, ax1 = plt.subplots(1)  
camera = Camera(fig)
sns.set_style('white')
ax1 = sns.heatmap(a, linewidth=0.5,ax=ax1,annot=annot)
for bb in b.flatten():
    ax1.add_patch(plt.Rectangle((np.where(a == bb)[1][0], 
    np.where(a == bb)[0][0]), 1, 1, fc='none', ec='green', lw=5, clip_on=False))
    camera.snap()


animation = camera.animate(interval=800)
animation.save('animation2.gif')
plt.show()

enter image description here

Advertisement

Answer

It looks like celluloid clears the existing plot at each snap. You can recreate the plot from scratch at each step. The rectangles can be stored in a list.

To avoid that new colorbar positions are set at each step, you can use sns.heatmap‘s cbar_ax= parameter to always use the same colorbar ax:

import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from celluloid import Camera

a = np.array([[0.24671953, 0.25959473, 0.85494718],
              [0.60553861, 0.76276659, 0.41092171],
              [0.37356358, 0.69378785, 0.46988614]])
b = np.array([[0.24671953, 0.25959473],
              [0.41092171, 0.46988614],
              [0.37356358, 0.60553861]])

fig, (ax1, cbar_ax) = plt.subplots(ncols=2, gridspec_kw={'width_ratios': [20, 1]})
camera = Camera(fig)
sns.set_style('white')
rectangles = []
for bb in b.flatten():
    sns.heatmap(a, linewidth=0.5, ax=ax1, annot=True, cbar_ax=cbar_ax)
    rectangles.append(plt.Rectangle((np.where(a == bb)[1][0], np.where(a == bb)[0][0]), 1, 1,
                                    fc='none', ec='green', lw=5, clip_on=False))
    for rect in rectangles:
        ax1.add_patch(rect)
    camera.snap()

animation = camera.animate(interval=800)
animation.save('animation2.gif')
plt.show()

heatmap with rectangles animation

An alternative could be to directly use matplotlib’s animation framework. Then, the code could look like:

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

a = np.array([[0.24671953, 0.25959473, 0.85494718],
              [0.60553861, 0.76276659, 0.41092171],
              [0.37356358, 0.69378785, 0.46988614]])
b = np.array([[0.24671953, 0.25959473],
              [0.41092171, 0.46988614],
              [0.37356358, 0.60553861]])

fig, ax1 = plt.subplots()
sns.set_style('white')
sns.heatmap(a, linewidth=0.5, ax=ax1, annot=True)

def animate(i):
    bb = b.flatten()[i]
    patch = ax1.add_patch(plt.Rectangle((np.where(a == bb)[1][0], np.where(a == bb)[0][0]), 1, 1,
                                        fc='none', ec='green', lw=5, clip_on=False))
    return patch,

animation = FuncAnimation(fig, animate, frames=range(0, b.size), interval=800, repeat=False)
animation.save('animation2.gif')
plt.show()
User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement