2

I am plotting data on a tkinter app, using matplotlib.

As long as I start the plot with a dataset, it is just fine, but when I try to change the dataset, instead of getting a new plot in place of the old one, a new plot get add on the application, so they end up stacked.

How do I update the matplotlib figure, with new dataset? I use a button to trigger the plot, passing the data to the function. This is the relevant part of the app:

class Application(Frame):

    def __init__(self, master=None):

        Frame.__init__(self, master)
        matplotlib.rcParams["figure.figsize"] = [2,6]
        self.data_set = [1,2,3,4,5,6]
        self.initUI()


    def initUI(self):
        self.pack(fill=BOTH, expand=1)
        self.style = Style()
        self.style.theme_use("default")

        plotbutton = Button(self, text="Plot Data", command=lambda: self.create_plot(self.data_set))
        calculatebutton.place(x=300, y=600)

        quitbutton = Button(self, text="Quit", command=self.quit)
        quitbutton.place(x=400, y=600)

    def create_plot(self, dataset):

        plt = Figure(figsize=(4, 4), dpi=100)
        a = plt.add_subplot(211)
        a.plot(dataset, '-o', label="Main response(ms)")
        a.set_ylabel("milliseconds")
        a.set_title("plot")
        canvas = FigureCanvasTkAgg(plt, self)
        canvas.show()
        canvas.get_tk_widget().pack(fill=BOTH)
        toolbar = NavigationToolbar2TkAgg(canvas, self)
        toolbar.update()
        canvas._tkcanvas.pack(fill=BOTH)
        # generate a random list of 6 numbers for sake of simplicity, for the next plot
        data_set = random.sample(range(30), 6)
        return


def main():

    root = Tk()
    root.wm_title("generic app")
    root.geometry("800x700+100+100")

    app = Application(master=root)
    app.mainloop()

    return 0
5
  • matplotlib has function clear() which remove old plot Commented Jan 4, 2017 at 7:55
  • When should I use it? in my create_plot function, before the add_subplot call? Commented Jan 4, 2017 at 8:00
  • you didn' create working example so it is hard to say. But I made own version and now I see that you problem is different than I was thinking. Commented Jan 4, 2017 at 8:07
  • problem is that every time you click button, you create new Figure, plot and canvas - so clear() make no sence - and you use pack() to add it but you don't remove old one. pack() is used to add new element below other elements - it doesn't replace elements. You have to use pack_forget() to remove old canvas. (Or maybe better use destroy()) Commented Jan 4, 2017 at 8:11
  • I see; so the issue is in the way that I add the plot to the app. I did grab this approach from an example on the matplotlib site and a youtube tutorial. I can try with forget or destroy and see what happens; although I do not save the reference to the previous canvas, so I am not sure how do I retrieve the reference to destroy it Commented Jan 4, 2017 at 8:21

1 Answer 1

2

You have to remove/destroy old plot before you create new one.

It works for me - maybe it is what you need

I use

    self.widget = None
    self.toolbar = None

to keep access to widgets

I commented some lines of code because it works for me without them.

import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import Figure, FigureCanvasTkAgg, NavigationToolbar2TkAgg
from tkinter import *
import random

class Application(Frame):

    def __init__(self, master=None):

        Frame.__init__(self, master)
        matplotlib.rcParams["figure.figsize"] = [2,6]
        self.data_set = [1,2,3,4,5,6]
        self.initUI()

        # to assign widgets
        self.widget = None
        self.toolbar = None

    def initUI(self):
        self.pack(fill=BOTH, expand=1)

        plotbutton = Button(self, text="Plot Data", command=lambda: self.create_plot(self.data_set))
        plotbutton.place(x=300, y=600)

        quitbutton = Button(self, text="Quit", command=self.quit)
        quitbutton.place(x=400, y=600)


    def create_plot(self, dataset):

        # remove old widgets
        if self.widget:
            self.widget.destroy()

        if self.toolbar:
            self.toolbar.destroy()

        # create new elements

        plt = Figure(figsize=(4, 4), dpi=100)

        a = plt.add_subplot(211)
        a.plot(dataset, '-o', label="Main response(ms)")
        a.set_ylabel("milliseconds")
        a.set_title("plot")

        canvas = FigureCanvasTkAgg(plt, self)

        self.toolbar = NavigationToolbar2TkAgg(canvas, self)
        #toolbar.update()

        self.widget = canvas.get_tk_widget()
        self.widget.pack(fill=BOTH)

        #self.toolbars = canvas._tkcanvas
        #self.toolbars.pack(fill=BOTH)

        # generate a random list of 6 numbers for sake of simplicity, for the next plot
        self.data_set = random.sample(range(30), 6)


def main():

    root = Tk()
    root.wm_title("generic app")
    root.geometry("800x700+100+100")

    app = Application(master=root)
    app.mainloop()

main()

Or maybe you should create Figure/canvas/etc. only once and replace data in plot using clear() and set_data()

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.