0

(Python 3.9 on Big Sur.) I have sequence of 100 square, 6-by-6 random matrices stored in the list M_list. I wish to create an animation of the corresponding heatmaps that appears on a tkinter canvas, along with an animation player.

I modified the approach at

Managing dynamic plotting in matplotlib Animation module

to get something that works (almost). The animation appears on the canvas along with five buttons (stop, forward play, backward play, forward single frame, backward single frame). While the forward/backward single frame buttons work fine, the forward/backward play buttons do not. Nothing happens when I click on either, and there is no error message. Looking at how the functions are defined, I don't see the source of the error. Here's my code:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import mpl_toolkits.axes_grid1
import matplotlib.widgets
from matplotlib.figure import Figure

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from tkinter import Tk,TOP,BOTH


class Player(FuncAnimation):
    def __init__(self, fig, func, frames=None, init_func=None, fargs=None, 
    save_count=None, 
    mini=0, maxi=100, pos=(0.125, 0.92), **kwargs):
        self.i = 0
        self.min=mini
        self.max=maxi
        self.runs = True
        self.forwards = True
        self.fig = fig
        self.func = func
        self.setup(pos)
        FuncAnimation.__init__(self,self.fig, self.func, frames=self.play(),
                                       init_func=init_func, fargs=fargs,
                                       save_count=save_count, **kwargs )

    # Player class functions
    def play(self):
        while self.runs:
            self.i = self.i+self.forwards-(not self.forwards)
            if self.i > self.min and self.i < self.max:
                yield self.i
            else:
                self.stop()
                yield self.i

    def start(self):
        self.runs=True
        self.event_source.start()

    def stop(self, event=None):
        self.runs = False
        self.event_source.stop()

    def forward(self, event=None):
        self.forwards = True
        self.start()
    def backward(self, event=None):
        self.forwards = False
        self.start()
    def oneforward(self, event=None):
        self.forwards = True
        self.onestep()
    def onebackward(self, event=None):
        self.forwards = False
        self.onestep()

    def onestep(self):
        if self.i > self.min and self.i < self.max:
            self.i = self.i+self.forwards-(not self.forwards)
        elif self.i == self.min and self.forwards:
            self.i+=1
        elif self.i == self.max and not self.forwards:
            self.i-=1
        self.func(self.i)
        self.fig.canvas.draw_idle()

    # Buttons
    def setup(self, pos):
        playerax = self.fig.add_axes([pos[0],pos[1], 0.22, 0.04])
        divider = mpl_toolkits.axes_grid1.make_axes_locatable(playerax)
        bax = divider.append_axes("right", size="80%", pad=0.05)
        sax = divider.append_axes("right", size="80%", pad=0.05)
        fax = divider.append_axes("right", size="80%", pad=0.05)
        ofax = divider.append_axes("right", size="100%", pad=0.05)
        self.button_oneback = matplotlib.widgets.Button(playerax , label=u'$\u29CF$')
        self.button_back = matplotlib.widgets.Button(bax, label=u'$\u25C0$')
        self.button_stop = matplotlib.widgets.Button(sax, label=u'$\u25A0$')
        self.button_forward = matplotlib.widgets.Button(fax, label=u'$\u25B6$')
        self.button_oneforward = matplotlib.widgets.Button(ofax, label=u'$\u29D0$')
        self.button_oneback.on_clicked(self.onebackward)
        self.button_back.on_clicked(self.backward)
        self.button_stop.on_clicked(self.stop)
        self.button_forward.on_clicked(self.forward)
        self.button_oneforward.on_clicked(self.oneforward)



# Create matrices
num_times=100
M_list=[]
for t in range(num_times):
    M_list.append(np.random.rand(6,6))

fig=plt.Figure()

def update(i):
    ax=fig.add_subplot(111)
    ax.imshow(M_list[i],aspect='auto',cmap='jet')
    fig.suptitle('Frame: '+str(i), fontsize=16)

ani = Player(fig, update, maxi=num_times) #len(y)-1)

# tkinter root window and canvas
root=Tk()
root.geometry('1000x1000')

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


root.mainloop()
fishbacp
  • 865
  • 8
  • 20

0 Answers0