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?

Jailbone
  • 167
  • 1
  • 9
  • Does this answer your question? [how-do-i-create-multiple-checkboxes-from-a-list-in-a-for-loop-in-python-tkinter](https://stackoverflow.com/questions/8536518) – stovfl Jun 23 '20 at 12:43
  • not really somehow, sorry... I've wrote a code which does what I want but it is really unautomatic and I don't know how to do it better. I'll show it beneath. – Jailbone Jun 23 '20 at 13:58

2 Answers2

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()
stovfl
  • 14,998
  • 7
  • 24
  • 51
  • 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 Jun 24 '20 at 12:16
  • 1
    @Jailbone ***Parent is then just convention?***: Yes. Are the `**kwargs` thing clear? – stovfl Jun 24 '20 at 15:02
  • 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. – Jailbone Jun 24 '20 at 16:22
  • ***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*. – stovfl Jun 24 '20 at 16:35
  • ***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**. – stovfl Jun 24 '20 at 16:39
  • ***two class variables (subplot and variable). Why is it not necessary to designate them in the innit method?*** They are in `__init__` ? ***what this class does.***: Basicly extends the `Tkinter.Checkbutton` class to aggregate all whats needed to work. – stovfl Jun 24 '20 at 16:43
  • I learned it like that for example: `class Shirt: def __init__(self, brand, size, color): self.brand = .... ` So i was wondering why there is no `subplot` and `variable` in the `innit` method. – Jailbone Jun 24 '20 at 16:49
  • ***wondering why there is no subplot and variable***: They are passed as `**kwargs` using `subplot=...` but `variable` don't habe to be passed it is defined inside `__init__` to exetend the object to know the checked status. – stovfl Jun 24 '20 at 16:56
  • I am sorry but I don't get it. So `subplot = ...` is a `**kwarg` and `variable` is already known from the parent class, i.e. `tk.Checkbutton` ? – Jailbone Jun 24 '20 at 17:05
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/216580/discussion-between-stovfl-and-jailbone). – stovfl Jun 24 '20 at 17:24
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()
stovfl
  • 14,998
  • 7
  • 24
  • 51
Jailbone
  • 167
  • 1
  • 9
  • 1
    ***but it does not work***: Should read: `if varChannels[i].get() == 1:` – stovfl Jun 23 '20 at 15:54
  • 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. – Jailbone Jun 23 '20 at 17:43