1

The problem is that I want to draw a plot by clicking on a button but it doesn't work. However, when I call draw from __init__, the plot appears on the screen.

Plotter.py

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure

class Plotter(FigureCanvasTkAgg):

    def __init__(self, master):

        self.figure = Figure(dpi=100)
        super().__init__(self.figure, master=master)
        self.axes = self.figure.add_subplot(111)
        self.get_tk_widget().grid(column=0, row=0, sticky='nsew')

    def draw(self):

        self.axes.clear()
        x_list = [x for x in range(0, 100)]
        y_list = [x^3 for x in x_list]
        self.axes.plot(x_list, y_list, color='y')

MainApplication.py

from tkinter import ttk 
import tkinter as tk
import plotter

class MainApplication(ttk.Frame):

    def __init__(self, master, *args, **kwargs):

        super().__init__(root)
        self.grid(column=0, row=0, sticky='nsew')

        frame = ttk.Frame(self, borderwidth=8)
        frame.grid(column=0, row=0, sticky='nsew')
        frame.rowconfigure(0, weight=1)

        notes = ttk.Notebook(frame)
        notes.grid(column=0, row=0, sticky='nsew')
        notes.rowconfigure(0, weight=1)

        page = ttk.Frame(notes)
        notes.add(page, text='Picture')


        plot = plotter.Plotter(page)
        # plot.draw() # This call updates the plot

        input_frame = ttk.Frame(self)
        input_frame.grid(column=1, row=0, sticky='nsew')

        # this binding doesn't update the plot
        button = ttk.Button(input_frame, text='Plot', \
                            command=lambda: plot.draw())
        button.grid(column=0, row=4, columnspan=2, sticky='ew')


root = tk.Tk() 
MainApplication(root)
root.mainloop()

2 Answers 2

2

Personally I would write this up in a single class so that we can use class attributes and methods to control everything with ease. Also you do not need a lambda here. Just save the reference to the command button and not a lambda call. That said you were also overwriting the draw method of FigureCanvasTkAgg so change the draw() method to something else.

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
from tkinter import ttk 
import tkinter as tk


class MainApplication(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        notes = ttk.Notebook(self)
        notes.grid(column=0, row=0, sticky='nsew')
        notes.rowconfigure(0, weight=1)
        self.page = ttk.Frame(notes)
        notes.add(self.page, text='Picture')
        self.plotter()
        input_frame = ttk.Frame(self)
        input_frame.grid(column=1, row=0, sticky='nsew')

        button = ttk.Button(input_frame, text='Plot', command=self.new_draw)
        button.grid(column=0, row=4, columnspan=2, sticky='ew')

    def plotter(self):
        self.figure = Figure(dpi=100)
        self.plot_canvas = FigureCanvasTkAgg(self.figure, self.page)
        self.axes = self.figure.add_subplot(111)
        self.plot_canvas.get_tk_widget().grid(column=0, row=0, sticky='nsew')

    def new_draw(self):
        self.axes.clear()
        x_list = [x for x in range(0, 100)]
        y_list = [x^3 for x in x_list]
        self.axes.plot(x_list, y_list, color='y')
        self.plot_canvas.draw_idle()

MainApplication().mainloop()
Sign up to request clarification or add additional context in comments.

Comments

2

You overwrote the canvas' draw method without reimplementing it. But since you do not want to update your plot on every draw-event anyways, I'd suggest to call the method to update the plot differently, e.g. draw_lists. Inside draw_lists you would then need to call the draw method of the canvas (or in this case better draw_idle).

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure

class Plotter(FigureCanvasTkAgg):

    def __init__(self, master):

        self.figure = Figure(dpi=100)
        super().__init__(self.figure, master=master)
        self.axes = self.figure.add_subplot(111)
        self.get_tk_widget().grid(column=0, row=0, sticky='nsew')

    def draw_lists(self):

        self.axes.clear()
        x_list = [x for x in range(0, 100)]
        y_list = [x^3 for x in x_list]
        self.axes.plot(x_list, y_list, color='y')
        self.draw_idle()



from tkinter import ttk 
import tkinter as tk


class MainApplication(ttk.Frame):

    def __init__(self, master, *args, **kwargs):

        super().__init__(root)
        self.grid(column=0, row=0, sticky='nsew')

        frame = ttk.Frame(self, borderwidth=8)
        frame.grid(column=0, row=0, sticky='nsew')
        frame.rowconfigure(0, weight=1)

        notes = ttk.Notebook(frame)
        notes.grid(column=0, row=0, sticky='nsew')
        notes.rowconfigure(0, weight=1)

        page = ttk.Frame(notes)
        notes.add(page, text='Picture')


        plot = Plotter(page)

        input_frame = ttk.Frame(self)
        input_frame.grid(column=1, row=0, sticky='nsew')

        # this binding doesn't update the plot
        button = ttk.Button(input_frame, text='Plot', \
                            command=lambda: plot.draw_lists())
        button.grid(column=0, row=4, columnspan=2, sticky='ew')


root = tk.Tk() 
MainApplication(root)
root.mainloop()

1 Comment

I would change command=lambda: plot.draw_lists() to command= plot.draw_lists.

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.