pythonoopuser-interfacetkinterclassification

I am struggliing spilting the classifers catagory and displaying then in 2 rows. I am using python and tkinter to build this GUI


This my code.

import tkinter as tk
from tkinter import ttk, filedialog

class ClassifierSelectionApp:
    def __init__(self, root):
        self.root = root
        style = ttk.Style()
        style.configure("TButton", font=("Arial", 11), padding=5)
        style.configure("TLabel", font=("Arial", 11))

        # Main frame
        main_frame = ttk.Frame(root, padding="10 10 10 10")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))

        # Configure grid
        for i in range(8):  # Number of columns
            main_frame.columnconfigure(i, weight=1)
        for i in range(8):  # Increased number of rows
            main_frame.rowconfigure(i, weight=1)

        # Training Data
        self.label_train = ttk.Label(main_frame, text="Select Training Data:", style="TLabel")
        self.label_train.grid(row=0, column=0, sticky='w', padx=5, pady=5)
        self.button_train = ttk.Button(main_frame, text="Browse", command=self.browse_train, style="TButton")
        self.button_train.grid(row=1, column=0, padx=5, pady=5)

        # Testing Data
        self.label_test = ttk.Label(main_frame, text="Select Testing Data:", style="TLabel")
        self.label_test.grid(row=0, column=1, sticky='w', padx=5, pady=5)
        self.button_test = ttk.Button(main_frame, text="Browse", command=self.browse_test, style="TButton")
        self.button_test.grid(row=1, column=1, padx=5, pady=5)

        # Category Labels
        categories = ["Convolution based", "Deep learning", "Dictionary based", 
                      "Distance based", "Feature based", "Interval based", 
                      "Shapelet based", "Hybrid"]
        for i, category in enumerate(categories):
            label = ttk.Label(main_frame, text=category, font=("Arial", 11, "bold"))
            label.grid(row=2, column=i, padx=5, pady=5, sticky='w')  # Align to the left

        # Row Labels and Checkbuttons
        self.check_vars = []
        rows_top = [
            ["Rocket Classifier", "CNN ", "MUSE", "K-NN", "Catch22", "Canonical Interval Forest", "Random Forest", "HIVECOTEV2"],
            ["Arsenal", "", "WEASEL", "Elastic Ensemble", "Fresh PRINCE", "DrCIF", "", ""],
            ["", "", "BOSS Ensemble", "", "", "RandomIntervalSpectralEnsemble", "", ""]
        ]
        rows_bottom = [
            ["", "", "Contractable BOSS", "", "", "SupervisedTimeSeriesForest", "", ""],
            ["", "", "Individual BOSS", "", "", "TimeSeriesForestClassifier", "", ""],
            ["", "", "Temporal Dictionary Ensemble", "", "", "", "", ""]
        ]

        # Determine the maximum width for each column
        max_widths = [max(len(row[i]) for row in rows_top + rows_bottom if i < len(row) and row[i]) for i in range(len(categories))]

        # Place the top half of the rows in the grid
        for r, row in enumerate(rows_top):
            row_vars = []
            for c, item in enumerate(row):
                if item:
                    var = tk.BooleanVar()
                    checkbutton = ttk.Checkbutton(main_frame, text=item, variable=var, width=max_widths[c])
                    checkbutton.grid(row=r+3, column=c, padx=5, pady=5, sticky='w')  # Align to the left
                    row_vars.append(var)
                else:
                    row_vars.append(None)
            self.check_vars.append(row_vars)

        # Place the bottom half of the rows in the grid, offset by the number of rows in rows_top
        for r, row in enumerate(rows_bottom):
            row_vars = []
            for c, item in enumerate(row):
                if item:
                    var = tk.BooleanVar()
                    checkbutton = ttk.Checkbutton(main_frame, text=item, variable=var, width=max_widths[c])
                    checkbutton.grid(row=r+3+len(rows_top), column=c, padx=5, pady=5, sticky='w')  # Align to the left
                    row_vars.append(var)
                else:
                    row_vars.append(None)
            self.check_vars.append(row_vars)

    def browse_train(self):
        file_path = filedialog.askopenfilename()
        print(f"Training data selected: {file_path}")
        
    def browse_test(self):
        file_path = filedialog.askopenfilename()
        print(f"Testing data selected: {file_path}")

if __name__ == "__main__":
    root = tk.Tk()
    app = ClassifierSelectionApp(root)
    root.mainloop()

Here is an image of what my GUI look like right now, I want to make it look more presentable. I don't want it to be so wide but I want also keep all of the option. Tried using chatgpt but it was useless.

Image of my GUI

I want to build an application that can classify time sereis data. To do this I have a libary called AEON toolkit and I have important all of the classifers I wanted.

All the classifers I am going to be using are neetly catagoried in their catagiores but the application looks too wide. And I dont want that.

Insted I want 4 classifers catagory displayed in one row and the other 4 displayed in the row right after. I tried multiple thing but could not find a way to do this.

Any help would be greatly appreciated.

Please note, if there is a better way of displaying this in tkinter I am open to suggestions.


Solution

  • It is more easier to layout those checkbuttons by putting related ones in frames:

    ...
    
    class ClassifierSelectionApp:
        def __init__(self, root):
            self.root = root
            style = ttk.Style()
            style.configure("TButton", font=("Arial", 11), padding=5)
            style.configure("TLabel", font=("Arial", 11))
    
            # Main frame
            main_frame = ttk.Frame(root, padding="10 10 10 10")
            main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
    
            # Training Data
            self.label_train = ttk.Label(main_frame, text="Select Training Data:", style="TLabel")
            self.label_train.grid(row=0, column=0, sticky='w', padx=5, pady=5)
            self.button_train = ttk.Button(main_frame, text="Browse", command=self.browse_train, style="TButton")
            self.button_train.grid(row=1, column=0, padx=5, pady=5, sticky='w')
    
            # Testing Data
            self.label_test = ttk.Label(main_frame, text="Select Testing Data:", style="TLabel")
            self.label_test.grid(row=0, column=1, sticky='w', padx=5, pady=5)
            self.button_test = ttk.Button(main_frame, text="Browse", command=self.browse_test, style="TButton")
            self.button_test.grid(row=1, column=1, padx=5, pady=5, sticky='w')
    
            # Category frame
            category_frame = ttk.Frame(root)
            category_frame.grid(row=1, column=0)
    
            # better use a dictionary to store the category data
            categories = {
                "Convolution based": ["Rocket Classifier", "Arsenal"],
                "Deep learning": ["CNN"],
                "Dictionary based": ["MUSE", "WEASEL", "BOSS Ensemble", "Contractable BOSS", "Individual BOSS", "Temporal Dictionary Ensemble"],
                "Distance based": ["K-NN", "Elastic Ensemble"],
                "Feature based": ["Catch22", "Fresh PRINCE"],
                "Interval based": ["Canonical Interval Forest", "DrCIF", "Random Interval Spectral Ensemble", "Supervised Time Series Forest", "Time Series Forest Classifier"],
                "Shapelet based": ["Random Forest"],
                "Hybrid": ["TIVECOTEV2"],
            }
            # calculate number of columns for two rows
            columns = int(len(categories) / 2 + 0.5)
            self.check_vars = {}
            for i, (category, items) in enumerate(categories.items()):
                self.check_vars[category] = []
                # determine the row and column
                row, col = divmod(i, columns)
                # create a frame for this category
                frame = ttk.Frame(category_frame)
                frame.grid(row=row, column=col, sticky='nsew', padx=5, pady=5)
                ttk.Label(frame, text=category, font=('Arial', 11, 'bold')).pack(padx=5, pady=5, anchor='w')
                for item in items:
                    var = tk.BooleanVar()
                    ttk.Checkbutton(frame, text=item, variable=var).pack(anchor='w', padx=5, pady=5)
                    self.check_vars[category].append(var)
    
        ...
    

    Result:

    enter image description here