0

I'm doing a tkinter GUI for my program and I have to display some real time data. I made a simple program (below) to demonstrate my problem on a simple case. I'm actually plotting some data every iteration of my for loop so I can observe data while the program in still calculating. Note that the real program si calculating a bit slower and have more iterations.

Now I would like to add 2 buttons (one to pause the program and one to continue) and a label (diplay variable k so i know where my program is), but I am unable to do it.

I've already lost a lot of time on it so if anyone have a hint or a solution i would love to see it.

import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
import matplotlib.pyplot as plt
from matplotlib import style

def func_A(a, x):
    import numpy
    data_x = numpy.arange(0, x)
    data_y = a * numpy.sin(data_x/5)
    return data_x, data_y

a = 1

root = tk.Tk()
root.title("Graph")
root.geometry("800x400")

fig = plt.figure(figsize=(5, 5), dpi=100)
canvas = FigureCanvasTkAgg(fig, master=root)  # A tk.DrawingArea.
canvas.draw()
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)

toolbar = NavigationToolbar2Tk(canvas, root)
toolbar.update()
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)

plt.grid("both")
style.use("ggplot")
for k in range(0, 100):
    data_x, data_y = func_A(a, k)
    print("iteration", k)
    print("data_x", data_x)
    print("data_y", data_y)
    if k == 0:
        ax1 = plt.subplot(111)
        line1, = ax1.plot([0], [0])
    else:
        line1.set_xdata(data_x)
        line1.set_ydata(data_y)

    ax1.set_ylim([-1, 1])
    ax1.set_xlim([0, 100])
    plt.grid("both")
    canvas.draw()
    canvas.flush_events()
root.mainloop()

2 Answers 2

1

To add pause/resume function:

  • create a frame to hold the progress label and the two buttons: pause and resume
  • create a tkinter BooleanVar() to store the pause/resume state
  • move the update plot code inside a function, e.g. update_plot()
  • use .after() to replace the for loop to call update_plot() periodically
  • inside update_plot(), check the pause/resume state to determine whether to update the plot or not

Below is a modified example based on your code:

import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
import matplotlib.pyplot as plt
from matplotlib import style
import matplotlib
matplotlib.use("Agg")

root = tk.Tk()
root.title("Graph")
#root.geometry("800x400")

# progress label, pause and resume buttons
frame = tk.Frame(root)
frame.pack(fill="x", side=tk.TOP)

progress = tk.Label(frame)
progress.pack(side="left")

is_paused = tk.BooleanVar()  # variable to hold the pause/resume state
tk.Button(frame, text="Pause", command=lambda: is_paused.set(True)).pack(side="right")
tk.Button(frame, text="Resume", command=lambda: is_paused.set(False)).pack(side="right")

# the plot

fig = plt.figure(figsize=(10, 5), dpi=100)

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

plt.grid("both")
style.use("ggplot")

a = 1
ax1 = plt.subplot(111)
line1, = ax1.plot([0], [0])

def func_A(a, x):
    import numpy
    data_x = numpy.arange(0, x)
    data_y = a * numpy.sin(data_x/5)
    return data_x, data_y

# function to update ploat
def update_plot(k=0):
    if not is_paused.get():
        progress["text"] = f"iteration: {k}"

        data_x, data_y = func_A(a, k)
        #print("iteration", k)
        #print("data_x", data_x)
        #print("data_y", data_y)

        line1.set_xdata(data_x)
        line1.set_ydata(data_y)

        ax1.set_ylim([-1, 1])
        ax1.set_xlim([0, 100])
        plt.grid("both")
        canvas.draw()
        canvas.flush_events()
        k += 1
    if k <= 100:
        # update plot again after 10ms. You can change the delay to whatever you want
        root.after(10, update_plot, k)

update_plot() # start updating plot
root.mainloop()
Sign up to request clarification or add additional context in comments.

2 Comments

Oh you're a savior. I'll try to embed it to my code. Altho a have a quick question. Since we replaced for loop, we are now looping within the root.mainloop(), right? But does that loop the entire code or just the part from line: "root = tk.Tk()" down to root.mainloop(). The reason for this question is that I load some precalculated values from a pickle file and I only wanna do it once. @acw1668
No, it will only execute update_plot() 100 times.
0

add a check box to enable streaming

import customtkinter as ct
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

import numpy as np
import subprocess
import time



ct.set_appearance_mode('dark')
ct.set_default_color_theme('green')
root = ct.CTk()
width=int(0.9*root.winfo_screenwidth())
height=int(0.75*root.winfo_screenheight())
root.geometry(f'{width}x{height}')
#root.geometry('1500x1200')
frame=ct.CTkFrame(master=root)
frame.pack(pady=10,padx=5,fill='both', expand=True)


def plot():
    plotButton.configure(text=f'{np.random.randint(0,100)}')
    ax[1].clear()
    ax[1].scatter(x=np.random.randint(0,10,10),y=np.random.randint(0,10,10))
    canvas.draw()
    canvas.flush_events()

    
def streamSpec():
    while streamStop.get():
        plotButton.configure(text=f'{np.random.randint(0,100)}')
        ax[1].clear()
        ax[1].scatter(x=np.random.randint(0,10,10),y=np.random.randint(0,10,10))
        canvas.draw()
        canvas.flush_events()
        root.after(10,plot)

plotButton=ct.CTkButton(master=frame,text='plot',command=plot)
plotButton.grid(pady=10)

stream=ct.CTkButton(master=frame,text='stream',command=streamSpec)
stream.grid(pady=10)

streamStop=ct.CTkCheckBox(master=frame,text='Enable Stream')
streamStop.grid(pady=10)



fig,ax=plt.subplots(2,1)
plt.close(fig)
canvas=FigureCanvasTkAgg(fig,master=frame)
canvas.get_tk_widget().grid(padx=10,pady=10,row=0,column=5,columnspan=4,rowspan=6)



root.mainloop()

1 Comment

Answer needs supporting information Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.