-1
$\begingroup$

I am trying to embed an animation using FuncAnimation from matplotlib into a tkninter GUI. In the execute button at the bottom I am calling the Execute function. If I click the execute button many times the animations either get slower or plot over one another. The way it is written now, new plots are superposed. Previously, they would not superpose but would just get slower. In either case I get a warning that says I have plotted too many figures.

GOAL: I want an empty figure within my tkinter window. Then when the execute button is clicked I want the plots to be made. If it is clicked again, I want the previous plots to be cleared and new ones made with the new parameters. I suppose I should define the figure outside of Execute() and then add something like plt.clf() inside Execute(). This does not work.

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

root = tk.Tk()
#labels entry widgets
WidthLabel = tk.StringVar()
WidthLabel.set("Enter width of well: ")
tk.Label(root, textvariable=WidthLabel, height=2).grid(row=1, column=0)

EnergyLabel = tk.StringVar()
EnergyLabel.set("Enter energy level: ")
tk.Label(root, textvariable=EnergyLabel, height=1).grid(row=2,column=0)

#entry widgets
WidthEntry = tk.Entry(root)
WidthEntry.grid(row=1, column=1)
EnergyLevelEntry = tk.Entry(root)
EnergyLevelEntry.grid(row=2, column=1)

fig = plt.figure()
fig.subplots_adjust(hspace=0.3)

# must initialize these variables to create plots. They will be changed by input 
# later.
a = 5
C = 5

# making two plots
IMAGINARY = plt.subplot(212)
plt.xlim(0, a)
plt.ylim(-1.35*C, 1.35*C)
plt.yticks(fontsize=8)
plt.text(a*.01, 1.1*C, 'Imaginary part')

REAL = plt.subplot(211, sharex=IMAGINARY)
plt.xlim(0, a)
plt.ylim(-1.35*C, 1.35*C)
plt.xticks(fontsize=8)
plt.yticks(fontsize=8)
plt.text(a*.01, 1.1*C, 'Real part')
plt.setp(REAL.get_xticklabels(), visible=False)

# This is for later animation. I do not fully understand what FuncAnimation does # but it is necessary to have these objects be iterable.
line1, = IMAGINARY.plot([], [], lw=2)
line2, = REAL.plot([],[], lw=2)
#line3, = IMAGINARY.plot([], [], lw=2)

# defining function for later defined execute button to call
def Execute():

    # this is my attempt to clear the previous figure each time new data is given 
    # in the entry widgets. It does not work and is the main source of my 
    # confusion.
    plt.clf()
    # this is here so entering something that cannot be converted into a string 
    # can eventually be communicated to the user without messing up the program.
    try:
        a = WidthEntry.get()
        a = float(a)
        n = EnergyLevelEntry.get()
        n = int(n)
    except ValueError:
        print("Bad Input")
    
    C = np.sqrt(2/a)
    # this sets up the axes and stuff based on the user input.
    plt.xlim(0, a)
    plt.ylim(-1.35*C, 1.35*C)
    plt.yticks(fontsize=8)
    plt.text(a*.01, 1.1*C, 'Imaginary part')
    
    plt.xlim(0, a)
    plt.ylim(-1.35*C, 1.35*C)
    plt.xticks(fontsize=8)
    plt.yticks(fontsize=8)
    plt.text(a*.01, 1.1*C, 'Real part')
        
    
    # this creates the x values over which y_vals will be calculated below.
    x = np.linspace(0, a, 500)
    
    def Real(x_vals,time):
        y_vals = np.cos(time)*C*np.sin(n*np.pi*x_vals/a)
        return y_vals
    
    def Imaginary(x_vals,time):
        y_vals = np.sin(time)*C*np.sin(n*np.pi*x_vals/a)
        return y_vals
        
    #animate functions will be used for animating. 
    def animate(i):
        t = 0.01*i
        y = Real(x,t)
        line1.set_data(x,y)
        return line1,
    
    def animate2(i):
        t = 0.01*i
        y = Imaginary(x, t)
        line2.set_data(x,y)
        return line2,
    
    FigureCanvasTkAgg(fig, master=root).get_tk_widget().grid(row=0,column=0)
    FuncAnimation(fig, animate, frames = 50000, interval = 2, blit = True)
    FuncAnimation(fig, animate2, frames = 50000, interval = 2, blit = True)
    #FuncAnimation(fig, animate3, frames = 50000, interval = 2, blit = True)

# this is where I make the execute button widget.
ExecuteButton = tk.Button(root, text="Execute", command=Execute).grid(row=3, column=1)

root.mainloop()
$\endgroup$
  • 1
    $\begingroup$ You need to provide more details here. You're just listing 100 lines of code with not one comment in it. Your question has no explanation of what you're trying to do, what you expect to happen, what you see happen, and what you have already tried to address the problem. $\endgroup$ – Wolfgang Bangerth 2 days ago
  • $\begingroup$ I figured people could just read it. But I guess I can explain a little. @WolfgangBangerth $\endgroup$ – Sean O'Gary yesterday
  • $\begingroup$ @SeanO'Gary I agree with Wolfgang, much more elaboration in addition to minimization of example is needed to maximize the probability of getting an answer. $\endgroup$ – Anton Menshov yesterday
  • $\begingroup$ @SeanO'Gary The people on this forum are volunteers, offering their spare time to help others with their questions. Meet them halfway by explaining what is happening, what should be happening, and what you have already tried. $\endgroup$ – Wolfgang Bangerth yesterday
  • $\begingroup$ I'll note that a statement like "Previously, they would not superpose" is not useful -- we don't know what the previous code looked like. Explain what is happening now. $\endgroup$ – Wolfgang Bangerth yesterday

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.