0

Say I got a multidimensional list:

my_list = [[1,2,3,4,5], [2,3,4,5,6], [3,4,5,6,7]]

Now I want to create a GUI with Tkinter where one could check boxes to select which of these sub-lists should be plotted in a histogram. So for this example I imagine three checkboxes (labeled 0, 1, 2) and a Button "Show Histograms". Say I check boxes labeled 1 and 2 and press the "Show Histograms" Button, it should show the histograms of my_list[0]and my_list[1](preferably as subplots on one canvas). What would be the approach?

2

2 Answers 2

2

OOP Example:

Defines a class SubplotCheckbutton ..., inheriting from tk.Checkbutton.
Extends the tk.Checkbutton widget with:

  • Named argument subplot=
  • The required tk.Variable, here tk.IntVar
  • A class method checked() which returns True/False according the checked state.

Reference:


  1. What do the arguments parentand **kwargs in the init method mean?
    Every Tkinter widget needs a parent. Therefore the first argument of all Tkinterwidgets class objects take the parent argument. A parent in Tkinter specifies in which widget your widget, here Checkbutton, are layouted.
    • class App(tk.Tk): => self
    • SubplotCheckbutton(self, ...
    • def __init__(..., parent, ...
    • super().__init__(parent, ... => tk.Checkbutton(parent)

**kwargs are shorted from known word arguments and is of type dict.
Here: text=str(i) and subplot=subplot

  1. will be continued ...

import tkinter as tk


class SubplotCheckbutton(tk.Checkbutton):
    def __init__(self, parent, **kwargs):
        # Pop the 'subplot=' argument and save to class member
        self.subplot = kwargs.pop('subplot')

        # Extend this class with the required tk.Variable
        self.variable = tk.IntVar()

        # __init__ the inherited (tk.Checkbutton) class object
        # Pass the argument variable= and all other passed arguments in kwargs
        super().__init__(parent, variable=self.variable, **kwargs)

    # Extend this object with a checked() method
    def checked(self):
        # Get the value from the tk.Variable and return True/False
        return self.variable.get() == 1

Usage:

Note: No root, the class object App is the root object, therefore you have to use self as parent:

  • SubplotCheckbutton(self, ...
  • Button(self, ...
class App(tk.Tk):
    def __init__(self):
        super().__init__()

        my_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
        self.channels = []

        for i, subplot in enumerate(my_list):
            self.channels.append(SubplotCheckbutton(self, text=str(i), subplot=subplot))
            self.channels[-1].pack()

        tk.Button(self, text="Show Histograms", command=self.show).pack()

    def show(self):
        for channel in self.channels:
            if channel.checked():
                fig, ax = plt.subplots()
                y, x, _ = ax2.hist(channel.subplot, bins = 150)
                plt.show()


if __name__ == '__main__':
    App().mainloop()
Sign up to request clarification or add additional context in comments.

10 Comments

Thanks! I do not understand everything though. 1. What do the arguments parent and **kwargs in the init method mean? In beginner tutorials I learned that you put self and all class variables in the init method. What does parent mean? Does it compromise all class variables of my class I inherit from (tk.Checkbutton in this case)? 2. What does kwargs.pop() exactly do? Where is the subplot argument passed and what is beeing popped? 3. What does it mean when the super().__innit__() method has no arguments (in class App(tk.Tk)) 4. In general, what would be the benefit of OOP approach?
@Jailbone Parent is then just convention?: Yes. Are the **kwargs thing clear?
Not 100 percent. Let me explain how I understand the code. So the App() class just appends the SubplotCheckbutton classes to a list with corresponding **kwargs through enumeration of my_list and packs the Checkbuttons on the screen. If the channels are checked they get plotted. My missing link is how it is veryfied if the channels are checked. This happens in the SubplotCheckbutton class itself. As I see this class has two class variables (subplot and variable). Why is it not necessary to designate them in the innit method? So basically I don' understand what this class does.
packs the Checkbutton on the screen.: In Tkinter speaking: The widget, here SubplotCheckbutton, are layout inside the App Toplevel window as you pass self as parent using The Pack Layout Manager.
My missing link is how it is veryfied if the channels are checked.: It's done inside def checked(.... It is the same as yours: if varChannels[i].get() == 1: but Object oriented, means the Object SubplotCheckbutton knows the checked status. That's one benefit of OOP, ALL are in the same Object. Therefore it's called Object Oriented Programming.
|
0
root = Tk()

my_list = [[1,2,3,4,5], [2,3,4,5,6], [3,4,5,6,7]]

var = IntVar()
var2 = IntVar()
var3 = IntVar()

def show():
    

    if var.get() == 1: 
        fig, ax = plt.subplots()
        y, x, _ = ax.hist(my_list[0], bins = 150)
        

    if var2.get() == 1:
        fig2, ax2 = plt.subplots()
        y, x, _ = ax2.hist(my_list[1], bins = 150)
        

    if var3.get()    def checked(self):
        return self.variable.get() == 1

 == 1:
        fig3, ax3 = plt.subplots()
        y, x, _ = ax3.hist(my_list[2], bins = 150)
    
    plt.show()





button = Button(root, text = "Show Histograms", command = show).pack()

c = Checkbutton(root, text = 'first list', variable = var).pack()
c2 = Checkbutton(root, text = 'second list', variable = var2).pack()
c3 = Checkbutton(root, text = 'third list', variable = var3).pack()


root.mainloop()

UPDATE: I managed to write it more compact but it does not work like that:

my_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
varChannels = []
checkbuttonChannels = []

def show():
    for i in range(3):
        if varChannels[i] == 1:
            fig, ax = plt.subplots()
            y, x, _ = ax2.hist(my_list[i], bins = 150)
            plt.show()



for _ in range(3):
    varChannels.append(IntVar())
    checkbuttonChannels.append('0')

for i in range(3):
    checkbuttonChannels[i] = Checkbutton(root, text = str(i), variable = varChannels[i]).pack()

button = Button(root, text = "Show Histograms", command = show).pack()

root.mainloop()

2 Comments

but it does not work: Should read: if varChannels[i].get() == 1:
thanks a lot! it works now. could you maybe explain in a few words how your code works? I am really new to classes stuff. So I can learn.

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.