0

I am very new to using TKinter. I am making a TKinter window that displays the descriptive statistics of the wine quality data sets. The problem I am having is with the positioning. Even using pack(side=BOTTOM), the button for the histogram shows up next to the column option buttons I have, like so: enter image description here

Ideally, what I would like the window to look like, is similar to this: enter image description here

I tried making the button in the same place I made the label "Descriptive statistics", and then configuring it later, but while that keeps the button where I would like it to be, the histogram ends up in the same place.

Edit: I was originally using grid() to manually place everything, but, for aesthetic reasons, I didn't like how the spaces in between the buttons would adjust as more objects were added to the window. I was also getting a "can't use pack() and grid()" warning even though I had changed all pack()s to grid()s, specifically only because of my plot function, and I couldn't figure it out. So in the end I just made the switch from grid() to pack() to avoid continually getting that error.

My code:

import tkinter as tk
from matplotlib.figure import Figure 
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)

#the main window
root = tk.Tk()

root.title('Descriptive statistics for vinho verde datasets') 

#generate some labels    
lbl1 = tk.Label(root, text = "Wine choice:")
lbl1.pack(side=TOP)

lbl2 = tk.Label(root, text = "Descriptive statistics:")
lbl2.pack(side=BOTTOM)

def wine_choice(opt):
    #functions determining for which columns to output descriptive statistics
    def describe(colm):
        if opt == 'white':
            res = white[colm].describe()
        else:
            res = red[colm].describe()
        txt = "\nDescriptive statistics for {0} wine, {1}:\n\n{2}"
        lbl2.config(text = txt.format(opt,colm,res)) 
    
        def b_plot(): 
            #figure that will contain the plot 
            fig = Figure(figsize = (5, 5), dpi = 75) 
            p1 = fig.add_subplot() 
        
            if opt == 'white':
                p1.hist(white[colm])
            else:
                p1.hist(red[colm])
        
            #creating the canvas containing figure and placing on the window 
            canvas = FigureCanvasTkAgg(fig, root)   
            canvas.draw() 
            canvas.get_tk_widget().pack(side=BOTTOM)
        
        btn_p = tk.Button(root, command = b_plot, width=10, height=3, text = "Histogram").pack(side=BOTTOM)
    
    lbl3 = tk.Label(root, text = "Pick an attribute to investigate:")
    lbl3.pack(side=TOP)

    #spawn attribute buttons after user chooses a wine
    #generate buttons
    btn3 = tk.Button(root, text='fixed acidity', width=10, height=3)
    btn3.pack(side=LEFT)
    btn3.bind('<Button-1>', lambda e: describe('fixed acidity'))

    btn4 = tk.Button(root, text='volatile\nacidity', width=10, height=3)
    btn4.pack(side=LEFT)
    btn4.bind('<Button-1>', lambda e: describe('volatile acidity'))

    btn5 = tk.Button(root, text='citric\nacid', width=10, height=3)
    btn5.pack(side=LEFT)
    btn5.bind('<Button-1>', lambda e: describe('citric acid'))

    btn6 = tk.Button(root, text='residual\nsugar', width=10, height=3)
    btn6.pack(side=LEFT)
    btn6.bind('<Button-1>', lambda e: describe('residual sugar'))

    btn7 = tk.Button(root, text='chlorides', width=10, height=3)
    btn7.pack(side=LEFT)
    btn7.bind('<Button-1>', lambda e: describe('chlorides'))

    btn8 = tk.Button(root, text='free\nsulfur\ndioxide', width=10, height=3)
    btn8.pack(side=LEFT)
    btn8.bind('<Button-1>', lambda e: describe('free sulfur dioxide'))

    btn9 = tk.Button(root, text='total\nsulfur\ndioxide', width=10, height=3)
    btn9.pack(side=LEFT)
    btn9.bind('<Button-1>', lambda e: describe('total sulfur dioxide'))

    btn10 = tk.Button(root, text='density', width=10, height=3)
    btn10.pack(side=LEFT)
    btn10.bind('<Button-1>', lambda e: describe('density'))

    btn11 = tk.Button(root, text='pH', width=10, height=3)
    btn11.pack(side=LEFT)
    btn11.bind('<Button-1>', lambda e: describe('pH'))

    btn12 = tk.Button(root, text='sulphates', width=10, height=3)
    btn12.pack(side=LEFT)
    btn12.bind('<Button-1>', lambda e: describe('sulphates'))

    btn13 = tk.Button(root, text='alcohol', width=10, height=3)
    btn13.pack(side=LEFT)
    btn13.bind('<Button-1>', lambda e: describe('alcohol'))

    btn14 = tk.Button(root, text='quality', width=10, height=3)
    btn14.pack(side=LEFT)
    btn14.bind('<Button-1>', lambda e: describe('quality'))

#buttons for wine choices
btn1 = tk.Button(root, text = "white", width=10, height=2)
btn1.pack(side=TOP)
#remember which button user picks
btn1.bind('<Button-1>', lambda e: wine_choice('white'))

btn2 = tk.Button(root, text = "red", width=10, height=2)
btn2.pack(side=TOP)
btn2.bind('<Button-1>', lambda e: wine_choice('red'))

#must be called for window to be drawn and events to be processed
root.mainloop()
Illari
  • 183
  • 1
  • 12
  • try using `.place(x, y)` but it wont work well with expanding window other option is to use `.grid(row, column)` and put everything in grid but be careful – Matiiss Oct 28 '20 at 19:18
  • Yes, I was running into some issues with `.grid()`. I'll look into `.place(x,y)`! Thanks for mentioning it. – Illari Oct 29 '20 at 01:42

1 Answers1

1

The solution is to break your UI into logical groups, and use frames to organize the logical groups. You can make what you have work, but it's much easier to use frames to organize your widgets.

I see perhaps four logical groups:

  • a set of two buttons stacked vertically
  • a dozen or so buttons aligned vertically
  • a block of statistics with a "histogram" button
  • a histogram

So, start by creating four frames, one for each of those sections. Stacking vertically is best done with pack.

Once you've done that, put the various widgets inside one of those frames. Each frame is independent from a layout perspective, so you can use grid or pack in each. Though, since each group seems to be a vertical or horizontal grouping, pack will probably work best in all cases since it excels at left-to-right and top-to-bottom layouts with the fewest lines of code.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Interesting! I'll look into seeing how it goes implementing four frames then. Thanks a lot for the suggestion. – Illari Oct 28 '20 at 21:10
  • This ended up working very beautifully. Thanks a lot for bringing `tk.Frame()` to my attention. I ended up using 3 frames in the end. – Illari Oct 29 '20 at 01:43