1

I have a sequence of 100, four-by-four coherence matrices, whose heatmaps I wish to animate using seaborn. The four rows/columns correspond to channels 'a', 'b', 'c', 'd', and the animation sequence will be embedded on a tkinter figure canvas appearing in a Toplevel window.

I'm using the handy Player class defined Managing dynamic plotting in matplotlib Animation module, which creates the animation with play buttons.

All of this I wish to combine into a function, which takes as its inputs the main tkinter window name, the channel labels, and the list of matrices and whose output is the desired animation. The relevant code:

M_list=[np.random.rand(4,4) for i in range(50)]
channels=['a','b','c','d']

root=Tk()
root.geometry('1000x1000')

def animate_coherence_matrices(root,channels,M_list):
    num_times=len(M_list)-1
    fig=Figure()
    plot_window = Toplevel(bg="lightgray")
    plot_window.geometry('700x700')

    canvas = FigureCanvasTkAgg(fig, master=plot_window)
    canvas.draw()
    canvas.get_tk_widget().pack(side=TOP,fill=BOTH,expand=1)


    def update_matrix(i):
        # clear current axes
        ax.cla()
        sns.heatmap(ax = ax, data = M_list[i], cmap = "coolwarm", cbar_ax = 
        cbar_ax,vmin=0,vmax=1)


    ax=fig.add_subplot(111)
    # set up axes labels OUTSIDE update function so we don't need to re-create for 
    # each frame. 
    ax.set_xticks(range(len(channels)))
    ax.set_xticklabels(channels,fontsize=10)
    ax.set_yticks(range(len(channels)))
    ax.set_yticklabels(channels,fontsize=10)

    # create heatmap color bar
    divider = make_axes_locatable(ax)
    cbar_ax = divider.append_axes("right", size="5%", pad=0.05)

    # Create animation with buttons as described at URL above.
    ani = Player(fig, update_matrix, maxi=num_times)


animate_coherence_matrices(root,channels,M_list)

root.mainloop()

This all works fine and dandy, except the axis labels in each frame are 0, 1, 2, 3 and not the channel labels 'a', 'b', 'c', 'd'.

Obviously I'm overlooking something that's easy to correct.

Zephyr
  • 11,891
  • 53
  • 45
  • 80
fishbacp
  • 1,123
  • 3
  • 14
  • 29

1 Answers1

1

Just move the lines:

ax.set_xticks(range(len(channels)))
ax.set_xticklabels(channels, fontsize = 10)
ax.set_yticks(range(len(channels)))
ax.set_yticklabels(channels, fontsize = 10)

within the function update_matrix:

def update_matrix(i):
    # clear current axes
    ax.cla()
    sns.heatmap(ax = ax, data = M_list[i], cmap = "coolwarm", cbar_ax = 
    cbar_ax,vmin=0,vmax=1)
    ax.set_xticks(range(len(channels)))
    ax.set_xticklabels(channels, fontsize = 10)
    ax.set_yticks(range(len(channels)))
    ax.set_yticklabels(channels, fontsize = 10)

enter image description here


If you to center labels with respect to heatmap cells, just comment ax.set_xticks and ax.set_yticks lines:

def update_matrix(i):
    # clear current axes
    ax.cla()
    sns.heatmap(ax = ax, data = M_list[i], cmap = "coolwarm", cbar_ax = 
    cbar_ax,vmin=0,vmax=1)
    # ax.set_xticks(range(len(channels)))
    ax.set_xticklabels(channels, fontsize = 10)
    # ax.set_yticks(range(len(channels)))
    ax.set_yticklabels(channels, fontsize = 10)

enter image description here

Zephyr
  • 11,891
  • 53
  • 45
  • 80
  • Thanks I had tried your suggestion above, but somehow my labels are "blinking" from frame to frame and don't appear fixed as they do in your animation. (Python 3.9 on Mac running Big Sur.) – fishbacp Aug 27 '21 at 14:45