1

I've been trying to execute a command for a button to plot a matplotlib figure. I've been over this post. But it does not quite help since the example has everything in one class. I'm struggling to link the objects from different classes together. The command to execute is for button2 in class EntryButton. The plot itself is made in class CalcPlot. And finally I want the plot to appear as an instance of the class PlotWindow.

I've tried to set the command=PlotWindow.plot, but that does not work. Also I'm not sure in which class the method should be in. The inheritance could work, but I don't find how to set it up since the classes already inherit from Frameclass.

from tkinter import *
import matplotlib
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
matplotlib.use('TkAgg')


class MainWindow(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)
        self.parent = parent
        self.config(bg='blue')
        self.pack(side=TOP, fill=BOTH, expand=True)
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)

        #frames
        entry_frame = EntryButton(self)
        plot_frame = PlotWindow(self)

x1 = 1
x2 = 2
y1 = 1
y2 = 2


class EntryButton(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)
        self.config(width=600, height=400, bg='#ff6600')
        self.place(x=0, y=0)

        self.entry1 = Entry(self, width=10)
        self.entry1.insert(0, '0')
        self.entry1.place(x=110, y=40, anchor=W)

        self.entry2 = Entry(self, width=10)
        self.entry2.insert(0, '0')
        self.entry2.place(x=180, y=40, anchor=W)

        self.entry3 = Entry(self, width=10)
        self.entry3.insert(0, '0')
        self.entry3.place(x=110, y=65, anchor=W)

        self.entry4 = Entry(self, width=10)
        self.entry4.insert(0, '0')
        self.entry4.place(x=180, y=65, anchor=W)

        label1 = Label(self, text='x coord.', font='arial 10 bold', bg='#ff6600')
        label1.place(x=50, y=40, anchor=W)

        label2 = Label(self, text='y coord.', font='arial 10 bold', bg='#ff6600')
        label2.place(x=50, y=65, anchor=W)

        button1 = Button(self, text='enter', width=8, command=self.set_values)
        button1.place(x=180, y=100, anchor=W)

        button2 = Button(self, text='plot', width=8, command=PlotWindow.plot)
        button2.place(x=180, y=140, anchor=W)

    def set_values(self):
        global x1, x2, y1, y2
        x1 = int(self.entry1.get())
        x2 = int(self.entry2.get())
        y1 = int(self.entry3.get())
        y2 = int(self.entry4.get())

    def plot(self):         #possibly the function should be here
        pass


class CalcClass:
    def __init__(self, parent):
        fig = Figure(figsize=(6, 4))
        axes = fig.add_subplot(1, 1, 1)
        global x1, x2, y1, y2
        axes.plot([x1, x2], [y1, y2])

        canvas = FigureCanvasTkAgg(fig, parent)
        canvas.draw()
        canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=True)


class PlotWindow(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)
        self.config(width=600, height=400, bg='yellow')
        self.place(x=600, y=0)

    def plot(self):
        plot = CalcClass(self)


if __name__ == '__main__':
    root = Tk()
    root.title('Frost Lite')
    app = MainWindow(root)
    root.geometry('1200x400+2000+800')
    root.resizable(False, False)
    root.mainloop()
Kārlis Rieksts
  • 169
  • 1
  • 1
  • 8

2 Answers2

0

You can't just call the object in the command, you have to have the object already set up in the Class you are trying to plot in. Like in MainWindow(Frame) you already have the EntryButton and PlotWindow but PlotWindow isn't an object inside of EntryButton. So you will need to add a PlotWindow to the EntryButton class like

plot_frame= PlotWindow(self)

in your MainWindow and then call the command inside your button like

 command= plot_frame.plot()

Or you will need to find some way to make EntryButton inherit PlotWindow things from the MainWindow but that may be different than what you want out of this.

D.Sanders
  • 98
  • 6
0

You can use a controller object to link the two together. Here's a snippet from some of my old code:

class gui(tk.Tk):
    def __init__(self, char, *args, **kwargs):
        self.display_cont = display_controller( leftSide, self)
        keyboard = key_controller( rightSide, self, height=474, width=300)

class display_controller(tk.Frame):
    def bar_chart(self, x, y, xlabel, ylabel, title):
        self.frames["matplotlib_display"].bar_chart(x, y, xlabel, ylabel, title)
        self.show_frame("matplotlib_display")

class matplotlib_display(tk.Frame):
    def bar_chart(self, x, y, xlabel, ylabel, title):
        self.fig.clf()
        graph = self.fig.add_subplot(1,1,1)
        x_fill = [i for i in range(len(x))]
        graph.bar(x_fill,y)

        graph.set_title(title)
        graph.set_xlabel(xlabel)
        graph.set_ylabel(ylabel)

        graph.set_xticks(range(len(x)))
        graph.set_xticklabels(x)

class key_controller(tk.Frame):
    def show_production(self, entity):
        display_cont = self.root.get_display_cont()
        xy = entity.getProduction()
        products = [d.getMaterials()[xy[0][i]] for i in range(len(xy[0]))]
        display_cont.bar_chart(products, xy[1], "Products", "Crafted", entity.name + " Production")

Then you can make a button like so:

production = tk.Button(self, text="[c] Crafted", font=BUTTON_FONT, command=lambda: controller.show_production(self.business))

The key_controller doesn't need to know HOW graphs are made, it just passes data to the controller. The display_controller doesn't know where data comes from, it just turns it into a graph.

markemus
  • 1,702
  • 15
  • 23