Home > Mobile >  Updating the matplotlib subplot figure by deleting/replacing the old values
Updating the matplotlib subplot figure by deleting/replacing the old values

Time:03-05

I have written a very simple code to have a scatter plot in matplotlib subplot. I can plot based on the values for x, y1 with the plot() function. I want to know if I got new values such as y2 through another function, how to update it in on the figure? I checked other posts in this regard and there were some suggestions to use clear(), destroy(), delete() in the update() function but none of them works. I want to keep the settings for the canvas and figure and only replace the new values with the old values.

import tkinter as tk
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)


class Data:
    def __init__(self):
        self.x = tk.IntVar()


class SampleApp(tk.Tk):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.minsize(700, 700)
        container = tk.Frame(self)
        container.pack()

        self.data = Data()

        self.frames = {}
        for F in (PageOne, ):
            frame = F(container, self.data)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky="nsew")

    def show_frame(self, c):
        frame = self.frames[c]
        frame.tkraise()


class PageOne(tk.Frame):
    def __init__(self, parent, data):
        super().__init__(parent)
        self.data = data

        self.button1 = tk.Button(self, text="Plot", command=self.plot)
        self.button1.pack()

        self.button2 = tk.Button(self, text="update", command=self.update)
        self.button2.pack()

        self.frame = tk.LabelFrame(self)
        self.frame.pack()

    def plot(self):
        global x
        x = [1,2,3,4,5,6,7,8,9]
        y1 = [1,2,3,4,5,6,7,8,9]

        self.figure = Figure(figsize=(4, 4))
        ax = self.figure.add_subplot(111)
        ax.scatter(x, y1)
        ax.set_title('Test')
        ax.set_xlabel('x')
        ax.set_ylabel('y')

        canvas = FigureCanvasTkAgg(self.figure, self.frame)
        canvas.draw()
        canvas.get_tk_widget().pack()
        toolbar = NavigationToolbar2Tk(canvas, self.frame)
        toolbar.pack()
        canvas.get_tk_widget().pack()

    def update(self):
        global x
        self.figure.clear()
        y2 = [1, 2, 3, 4, 5, 4, 3, 2, 1]

app = SampleApp()
app.mainloop()

CodePudding user response:

I got it to work by a combination of what I suggested and something I found in another post.

Here's how I did it, modifying only your update function.

    def update(self):
        global x
        self.figure.clear()
        ax = self.figure.add_subplot(111)
        ax.set_title('Test')
        ax.set_xlabel('x')
        ax.set_ylabel('y')
        x = [1,2,3,4,5,6,7,8,9]
        y2 = [1, 2, 3, 4, 5, 4, 3, 2, 1]
        ax.scatter(x, y2)
        self.figure.canvas.draw()

Here's how I did it using the set_data method.


import tkinter as tk
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)


class Data:
    def __init__(self):
        self.x = tk.IntVar()


class SampleApp(tk.Tk):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.minsize(700, 700)
        container = tk.Frame(self)
        container.pack()

        self.data = Data()

        self.frames = {}
        for F in (PageOne, ):
            frame = F(container, self.data)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky="nsew")

    def show_frame(self, c):
        frame = self.frames[c]
        frame.tkraise()


class PageOne(tk.Frame):
    def __init__(self, parent, data):
        super().__init__(parent)
        self.data = data

        self.button1 = tk.Button(self, text="Plot", command=self.plot)
        self.button1.pack()

        self.button2 = tk.Button(self, text="update", command=self.update)
        self.button2.pack()

        self.frame = tk.LabelFrame(self)
        self.frame.pack()


    def plot(self):
        global x
        x = [1,2,3,4,5,6,7,8,9]
        y1 = [1,2,3,4,5,6,7,8,9]

        self.figure = Figure(figsize=(4, 4))
        ax = self.figure.add_subplot(111)
        l = ax.plot(x, y1, lw=0, marker='o') # Changed here
        self.line1 = l[0] # Changed here
        ax.set_title('Test')
        ax.set_xlabel('x')
        ax.set_ylabel('y')

        canvas = FigureCanvasTkAgg(self.figure, self.frame)
        canvas.draw()
        canvas.get_tk_widget().pack()
        toolbar = NavigationToolbar2Tk(canvas, self.frame)
        toolbar.pack()
        canvas.get_tk_widget().pack()

    def update(self):
        global x
        y2 = [1, 2, 3, 4, 5, 4, 3, 2, 1]
        self.line1.set_data(x, y2) # Changed here
        self.figure.canvas.draw()  # Changed here <-- without this, won't redraw

app = SampleApp()
app.mainloop()

There's a few weird things in your code like global x that's unused, but that's stuff for another time.

  • Related