0

Python 3.9, matplotlib 3.4, Mac OS 11.6.1

I have a slider on a tkinter Toplevel containing a figure convas showing two sets of axes. As the slider advances, the axes illustrate the heatplots over time for two sequences of 4-by-300 matrices. Each increment of the slider value increases the number of depicted columns for each matrix by 10. The problem I encounter is that the slider becomes unresponsive after a couple frames.

import numpy as np
import matplotlib.pyplot as plt
import random
from matplotlib.widgets import Slider
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from tkinter import Tk,TOP,BOTH,Toplevel
import matplotlib
matplotlib.use('TkAgg',force=True)

def scrolling_matrix_viewer(M,channels,win_size):    
    plot_window = Toplevel(bg="lightgray") 
    plot_window.geometry('1000x900')
    plot_window.attributes('-topmost', 'true')

    fig, ax = plt.subplots(2,sharex=True)

    canvas = FigureCanvasTkAgg(fig, master=plot_window)
    canvas.draw()
    canvas.get_tk_widget().pack(side=TOP,fill=BOTH,expand=1)
    
    ax[0].invert_yaxis

    fig.subplots_adjust(left=.09, bottom=.2, right=None, top=.9, wspace=.2, 
    hspace=.2)
    ax_time=fig.add_axes([0.15, 0.1, 0.65, 0.03]) # axis for slider
    spos = Slider(ax_time, '',valinit=0,valmin=0,valmax=M.shape[1]- 
    win_size,valstep=win_size)

    def update_graph(val):
            start=spos.val #starting column index of M used for this frame
            stop=spos.val+win_size #ending column index of M used for this frame
            if stop<=M.shape[1]:
               ax[0].cla
               ax[1].cla
               heatmap0=ax[0].imshow(M[:,start:stop],vmin=0, vmax=1, cmap='coolwarm', 
               aspect='auto',extent=[0,win_size,M.shape[0],0])
               heatmap1=ax[1].imshow(N[:,start:stop],vmin=0, vmax=1, cmap='coolwarm', 
               aspect='auto',extent=[0,win_size,N.shape[0],0])
               ax_time.set_xlabel('time (sec)',fontsize=12)
               ax[0].set_ylabel('channel',fontsize=12)
               ticks=ax[0].get_xticks()
               x_labels=[str(start+ticks[i]) for i in range(len(ticks))] 
               ax[0].set_yticks(range(len(channels)))
               ax[0].set_yticklabels(channels,fontsize=12)

               ax[1].set_ylabel('channel',fontsize=12)
               ax[1].set_yticks(range(len(channels)))
               ax[1].set_yticklabels(channels,fontsize=12)
           
    spos.on_changed(update_graph)
    spos.set_val(0)

# Example
root=Tk()

M=np.random.rand(4,300)
N=np.random.rand(4,300)
channels=['A','B','C','D']
win_size=10 # the number of columns of M we advance by from frame to frame

scrolling_matrix_viewer(M,channels,win_size)

root.mainloop()

The image below shows the result. The slider becomes unresponsive when spos.valis 20

enter image description here

I have noticed that when only one matrix is used, hence only one set of axes, then everything works fine. Also, the animation for both matrices works fine when I'm simply creating the animation using matplotlib and not placing the result on a figure canvas.

ALSO: The fact that all the animation takes place inside a function could be the source of the problem. Specifically, when the matrices M and N are entered at the start of the file and all commands are executed outside a function, with the exception of the update, everything works fine.

fishbacp
  • 1,123
  • 3
  • 14
  • 29

1 Answers1

0

The problem can be resolved by changing ax.cla to ax.cla() for each axis and by having the function return spos. Thus, in the example, we call the function as spos=scrolling_matrix_viewer(M,channels,win_size)

fishbacp
  • 1,123
  • 3
  • 14
  • 29