2

I would like to properly interrupt an animation.

Background:

  • I have a matplotlib figure (an animation) encapsulated into a tkinter instance. I want that when the user presses a tkinter button, the animation must stop, be deleted and be restarted. I am interrupting the old animation, by using del fig at the beginning of the call back function (called by the button) which deletes the old instance of the figure class and after creates a new one.

Problem:

  • I think that the old animations are still somehow running in the background, as I noticed that when I click the button like 5 times, the animation gets slow and moves jerkily.

Code:

import matplotlib
import matplotlib.backends.backend_tkagg as tkagg
import matplotlib.animation as animation 
import numpy as np
import tkinter as tk

fig = matplotlib.figure.Figure() 
ani = []
#callback function
def solve():
    #I want the old animation to disappear, every time the button is pushed
    global fig,  ani
    del  fig,  ani
    #Creating an instance of the figure class
    fig = matplotlib.figure.Figure() 
    #Create a Canvas containing fig into win
    aCanvas =tkagg.FigureCanvasTkAgg(fig, master=win)
    #Making the canvas a tkinter widget
    aFigureWidget=aCanvas.get_tk_widget()
    #Showing the figure into win as if it was a normal tkinter widget
    aFigureWidget.grid(row=0, column=3,  rowspan=10)
    # create a time array
    ti, tf, dt,  delay=0, 10, 0.01, 15
    N=(tf-ti)/dt
    t = np.arange(ti, tf, dt)
    x1=np.sin(t)
    N=len(t)
    #Creating a sub plot
    ax2 = fig.add_subplot(xlim=(0, t[N-1]), ylim=(min(x1), max(x1)))
    #Printing a legend with time info
    time_template = 'time = %.1fs'
    time_text = ax2.text(0.05, 0.95, '', transform=ax2.transAxes,  bbox=dict(facecolor='white', edgecolor='black', boxstyle='round,pad=1'))
    #I want to create a live plot for x(t). I am using place-holders where the t and x will be 
    massmotion, = ax2.plot([], [],  '-')
    CumulativeX1,   CumulativeT=[], []
    #I am defining what is going to go into the brackets above (I am filling the placeholders)
    def animate(i):
        CumulativeX1.append(x1[i]),  CumulativeT.append(i*dt)       
        time_text.set_text(time_template % (i*dt))
        massmotion.set_data(CumulativeT, CumulativeX1 ) #Update the placeholders for the live plot
        return time_text, massmotion
    ani = animation.FuncAnimation(fig, animate, np.arange(1, N), interval=delay, blit=True)
    fig.canvas.draw()

#Creating the GUI
#Creating an instance of the Tk class
win = tk.Tk()

#Creating an instance of the Button class
#run the solve function when I click the button
aButton=tk.Button(win, text='Start Animation', command=solve)
#Placing the Button instance
aButton.grid(column=0, row=10, columnspan=2)

#Starting the event loop
win.mainloop()
medium-dimensional
  • 1,974
  • 10
  • 19
Francesco
  • 111
  • 9
  • I let the code plot 7 times the sine-like curve till ~ 9s, but I didn't see any particular lag in the plotting. But when I press *start animation* button very quickly for few times, plotting completely stops: is this the issue? – medium-dimensional Oct 24 '22 at 07:31
  • If I let it run up to 2s, 6 or 7 times then it becomes very slow. This is a simplified code. In my original code, where the background calculations are heavier, this problem occurs only after 2 or 3 times I click the button. – Francesco Oct 24 '22 at 08:16
  • It's the possible that the animation itself is not causing any lag, but computations to get the data is affecting it. You might want to take an objective look at such computations, looking at the memory utilised and time spent in computations. Please see if [this](https://stackoverflow.com/a/21972666/7789963) helps and the linked questions there. – medium-dimensional Oct 24 '22 at 08:19

0 Answers0