'Tkinter Moving Graph created through GUI - not from the start
Why isn't this graph moving? Or even being created? I've gotten graphs to move in tkinter before, but they would always open up immediately as the GUI opens, but I need the user to be able to choose their own dataset from a file within the GUI.
Thus, I have a function that chooses a file and creates the lists which matplotlib uses, but if I create the
import tkinter
import tkinter.ttk as ttk
from tkinter import filedialog
import time
import math
import serial
from numpy import arrange, sin, pi
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import numpy as np
import matplotlib.pyplot at plt
import matplotlib.animation as animation
global x
global y
def open_file():
file = filedialog.askopenfile(mode = 'r', filetypes=[('CSV Files', '*.csv'), ('Text Files', '*.txt'), ('All Files', '*.*')])
if file != None:
unprocessed_content = file.read()
unprocessed_content = unprocessed_content.split('\n')
unprocessed_content.remove('')
for line in unprocessed_content:
x.append(float(line.split(',')[0]))
y.append(float(line.split(',')[1]))
tkTop = tkinter.Tk()
fileOpener = tkinter.Button(tkTop, text = "Open File", command = open_file, height = 4, fg = 'black', bg = 'red', width = 8, bd = 5)
fileOpener.pack()
try:
x #just to pass over this section and not start the graph if the user hasn't chosen a file yet
fig = plt.Figure()
x_current = x[:10] #I want to only show part of the window at a time, so I thought I would do it in segments of 10 arbitrarily
def animate(i):
line.set_ydata(y[i:i+10])
return line,
canvas = FigureCanvasTkAgg(fig, master = tkTop)
canvas.get_tk_widget().pack()
ax = fig.add_subplot(111)
line, = ax.plot(x, y[:10])
ani = animation.FuncAnimation(fig, animate, np.arange(1,200), interval = 25, blit = False)
except NameError:
pass
tkTop.mainloop()
I think that's all the relevant code for my problem... so basically what happens is that I open up the GUI, and there's no graph (which is what I want) but then I click on the button to open a file and still nothing happens with the graph?
I kind of assumed that tkTop.mainloop() would run continuously again and again, so that it would continue to update the animation? Is that not right?
Solution 1:[1]
You may have problem for two reasons:
First
You do the worst thing - you use pass in except.
except NameError:
pass
This way you don't see that you have other mistake which makes all problem.
You should at least display error
except NameError as ex:
print('ex:', ex)
and you would know what makes all problem.
Second:
global is not for creating global variables. All variables created outside functions/classes are globla. And global is used inside function to inform function that it has to use external/global variable instead of local variable.
Problem is that your graph raise error because x,y don't exist. And you should create them by assigning default value
x = []
y = []
And now it should show graph
EDIT:
Minimal working code.
At start it displays empty plot and run animation (but it has nothing to display).
I added button to generate some fake data - so everyone can test it.
I didn't make one thing: restart animation after loading/generating new data and start at first frame i - so now it uses new y but old x (using old i in animate).
Frankly, it could be good to create animation only when data are loaded/generate, and replace previous animation.
import tkinter as tk
from tkinter import filedialog
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import csv
import random
# --- functions --- # PEP8: `lower_case_names`
def open_file():
global x
global y
file = filedialog.askopenfile(filetypes=[('CSV Files', '*.csv'),
('Text Files', '*.txt'),
('All Files', '*.*')])
if file:
print('read file')
x = []
y = []
reader_csv = csv.reader(file)
for row in reader_csv:
x.append(float(row[0]))
y.append(float(row[1]))
if x:
ax.set_xlim(0, 10)
if y:
ax.set_ylim(min(y), max(y))
def generate_data():
global x
global y
print('generate data')
# fake values
x = list(range(250))
y = [random.randint(0, 10) for _ in range(250)]
#
if x:
ax.set_xlim(0, 10)
if y:
ax.set_ylim(min(y), max(y))
def animate(i):
print('i:', i, x[i:i+10], y[i:i+10])
current_x = x[i:i+10]
current_y = y[i:i+10]
line.set_xdata(current_x)
line.set_ydata(current_y)
if current_x:
ax.set_xlim(min(current_x), max(current_x))
#canvas.draw()
return line,
# --- main ---
# default values at start
x = []
y = []
# - GUI -
tk_top = tk.Tk()
file_opener = tk.Button(tk_top, text="Open File", command=open_file)
file_opener.pack()
data_generator = tk.Button(tk_top, text="Generate Data", command=generate_data)
data_generator.pack()
# - empty plot -
try:
fig = plt.Figure()
canvas = FigureCanvasTkAgg(fig, master=tk_top)
canvas.get_tk_widget().pack()
ax = fig.add_subplot(111)
line, = ax.plot([], [])
ani = animation.FuncAnimation(fig, animate, 250, interval=250, blit=False)
except NameError as ex:
print(ex)
print('mainloop')
tk_top.mainloop()
EDIT:
Version which doesn't create animation at start (when there is no data) but it create animation after loading/generating data.
I also used this to create buttons STOP, START.
import tkinter as tk
from tkinter import filedialog
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import csv
import random
# --- functions --- # PEP8: `lower_case_names`
def open_file():
global x
global y
file = filedialog.askopenfile(filetypes=[('CSV Files', '*.csv'),
('Text Files', '*.txt'),
('All Files', '*.*')])
if file:
print('read file')
x = []
y = []
reader_csv = csv.reader(file)
for row in reader_csv:
x.append(float(row[0]))
y.append(float(row[1]))
if x:
ax.set_xlim(0, 10)
if y:
ax.set_ylim(min(y), max(y))
# stop previous animation
if ani:
ani._stop()
#del ani
# create new animation
ani = animation.FuncAnimation(fig, animate, 250, interval=250, blit=False)
ani._start()
def generate_data():
global x
global y
global ani
print('generate data')
# fake values
x = list(range(250))
y = [random.randint(0, 10) for _ in range(250)]
#
if x:
ax.set_xlim(0, 10)
if y:
ax.set_ylim(min(y), max(y))
# stop previous animation
if ani:
ani._stop()
#del ani
# create new animation
ani = animation.FuncAnimation(fig, animate, 250, interval=250, blit=False)
ani._start()
def animate(i):
print('i:', i, x[i:i+10], y[i:i+10])
current_x = x[i:i+10]
current_y = y[i:i+10]
line.set_xdata(current_x)
line.set_ydata(current_y)
if current_x:
ax.set_xlim(min(current_x), max(current_x))
#canvas.draw()
return line,
def stop_animation():
if ani:
# matplotlib 3.4.0+ # https://matplotlib.org/3.4.0/gallery/animation/pause_resume.html
#ani.pause()
# older matplotlib
ani.event_source.stop()
if ani._blit:
for artist in ani._drawn_artists:
artist.set_animated(False)
def start_animation():
if ani:
# matplotlib 3.4.0+ # https://matplotlib.org/3.4.0/gallery/animation/pause_resume.html
#ani.resume()
# older matplotlib
ani.event_source.start()
if ani._blit:
for artist in ani._drawn_artists:
artist.set_animated(True)
# --- main ---
# default values at start
x = []
y = []
ani = None
# - GUI -
tk_top = tk.Tk()
file_opener = tk.Button(tk_top, text="Open File", command=open_file)
file_opener.pack()
data_generator = tk.Button(tk_top, text="Generate Data", command=generate_data)
data_generator.pack()
# - empty plot -
try:
fig = plt.Figure()
canvas = FigureCanvasTkAgg(fig, master=tk_top)
canvas.get_tk_widget().pack()
ax = fig.add_subplot(111)
line, = ax.plot([], [])
# don't create animation at start
#ani = animation.FuncAnimation(fig, animate, 250, interval=250, blit=False)
#ani.pause() # it needs newer matplotlib
except NameError as ex:
print(ex)
stop = tk.Button(tk_top, text="Stop", command=stop_animation)
stop.pack()
start = tk.Button(tk_top, text="Start", command=start_animation)
start.pack()
print('mainloop')
tk_top.mainloop()
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |

