0

I'm plotting streamed data with tkinter but my app opens the current plot in an additional window:

My App looks something like this:

import tkinter as tk
from tkinter import ttk
from random import randint
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg


class App(tk.Tk):

    def __init__(self):
        super().__init__()
        self.button_run = tk.Button(master=self, text='run', bg='grey', command=self.run)
        self.button_run.pack()
        self.fig = plt.Figure()
        self.fig, self.axes_dict = plt.subplot_mosaic([['o', 'o'], ['_', '__']])
        self.canvas = FigureCanvasTkAgg(figure=self.fig, master=self)
        self.canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)
        self.canvas.draw_idle()
        self.fig.canvas.flush_events()

    def run(self):
        S = Streamer(parent=self)
        S.start()

And I stream data like this:

class Streamer:  

    def __init__(self, parent):
        self.parent = parent

    def start(self):
    # plot random data
        for x in range(6):
            self.parent.axes_dict['o'].add_patch(Rectangle((x, randint(x, x*2)), height=0.4, width=0.4))
            self.parent.axes_dict['o'].relim()
            self.parent.axes_dict['o'].autoscale_view(True, True, True)
            self.parent.fig.canvas.draw_idle()
            self.parent.fig.canvas.flush_events()
            plt.pause(0.4)

Starting the app:

if __name__ == '__main__':
    A = App()
    A.mainloop()

How can I close this matplotlib window and why does it appear?

2
  • As I understood:-- If you want only one main window then you just need to remove the plt.pause(0.4) from the Streamer class ...And you are missing one = in starting the app it should be like if __name__ == '__main__': Commented Jan 19, 2023 at 4:45
  • This didn't solve it in my case the matplotlib window is still appearing but thank you. Commented Jan 19, 2023 at 4:54

1 Answer 1

1

You should not call plt.pause() because it will block the event loop of the tkinter.

Do like this using the after().

class Streamer:
    ...
    def start(self):
        xs = list(range(6))
        def update():
            if xs:
                x = xs.pop(0)
                parent = self.parent
                parent.axes_dict['o'].add_patch(Rectangle((x, randint(x, x*2)), height=0.4, width=0.4))
                parent.axes_dict['o'].relim()
                parent.axes_dict['o'].autoscale_view(True, True, True)
                parent.fig.canvas.draw()
                parent.after(400, update)
        update()

If you do a time consuming work in the update(), you are better to use a worker thread or process.

Sign up to request clarification or add additional context in comments.

Comments

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.