Mar-12-2024, 02:09 PM
(This post was last modified: Mar-12-2024, 02:09 PM by deanhystad.)
The likely problem is that there is no variable referencing the animation. "anim" is a local variable that disappears as soon as the price_graph() method ends. You need to make this an instance variable.
I stripped out everything that isn't absolutely necessary to focus on what is.
It probably makes more sense making animate() a method instead of an enclosed function, This would require changing ax to an instance variable so it could be used in both __init__() and animate().
I till thing using funcanimation is the wrong way to do this. In this post I used tkinter.after to update th graph.
https://python-forum.io/thread-39130-pos...#pid166027
I was wrong about funcanimation blocking, but I still think there are advantages to having the program do the updates with a timer event. For example, it would be simple to tie the animation to a scrollbar for scrolling forward and backward in time. Starting and stopping the animation is simpler when you don't have to work around funcanimation.
For an apples to apples comparison, here's the same program written using funcanimation and using after().
Using funcanimation:
I stripped out everything that isn't absolutely necessary to focus on what is.
import pandas as pd import tkinter as tk import matplotlib.pyplot as plt from matplotlib.animation import FuncAnimation from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg class Graph(tk.Tk): def __init__(self, *args, **kwargs): def animate(_): df = pd.read_csv('data.csv', names=("x", "y"), skiprows=1) # Does first row have a bad header? ax.clear() ax.plot(df.x, df.y) # Should not need to call float or int to convert dataframe values. super().__init__(*args, **kwargs) fig = plt.Figure() ax = fig.add_subplot() canvas = FigureCanvasTkAgg(fig, master=self) canvas.get_tk_widget().pack() self.anim = FuncAnimation(fig, animate, interval=1000) # self.anim makes this an instance variable instead of local variable. Graph().mainloop()A lot of things could be different. Instead of subclassing Tk to make a Graph top level window, you could subclass Frame and put the graph in the frame. This would allow multiple plots in one window.
It probably makes more sense making animate() a method instead of an enclosed function, This would require changing ax to an instance variable so it could be used in both __init__() and animate().
I till thing using funcanimation is the wrong way to do this. In this post I used tkinter.after to update th graph.
https://python-forum.io/thread-39130-pos...#pid166027
I was wrong about funcanimation blocking, but I still think there are advantages to having the program do the updates with a timer event. For example, it would be simple to tie the animation to a scrollbar for scrolling forward and backward in time. Starting and stopping the animation is simpler when you don't have to work around funcanimation.
For an apples to apples comparison, here's the same program written using funcanimation and using after().
Using funcanimation:
import tkinter as tk from matplotlib.figure import Figure from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from matplotlib.animation import FuncAnimation import math class Graph(tk.Tk): """Tkinter window that displays matplotlib plot.""" def __init__(self, *args, **kwargs): def animate(i): self.x.append(self.x[-1] + 0.1) self.y.append(math.sin(self.x[-1])) plt.clear() plt.plot(self.x[-100:], self.y[-100:]) super().__init__(*args, **kwargs) fig = Figure() plt = fig.add_subplot() canvas = FigureCanvasTkAgg(fig, master=self) canvas.get_tk_widget().pack() self.x = [0] self.y = [0] self.anim = FuncAnimation(fig, animate, interval=10) Graph().mainloop()Using after()
import tkinter as tk from matplotlib.figure import Figure from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg import math class Graph(tk.Tk): """Tkinter window that displays matplotlib plot.""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.figure = Figure() self.plt = self.figure.add_subplot() canvas = FigureCanvasTkAgg(self.figure, self) canvas.get_tk_widget().pack() self.x = [0] self.y = [0] self.animate() def animate(self): self.x.append(self.x[-1] + 0.1) self.y.append(math.sin(self.x[-1])) self.plt.clear() self.plt.plot(self.x[-100:], self.y[-100:]) self.figure.canvas.draw() self.after(10, self.animate) Graph().mainloop()