SANAA
SANAA

Reputation: 15

how to open a frame that plot graph once click on a button in the menu bar in tkinter

I tried to plot a graph once click on 'home' in the menu bar and display it on the right side of the menu bar in a new frame but in same root. the frame is displayed but the graph doesn't appear. here's my code:

from matplotlib.backends.backend_tkagg import (
FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.figure import Figure
import pandas as pd
from tkinter import *
from PIL import Image, ImageTk
import matplotlib.pyplot as plt
import matplotlib
matplotlib.use('TkAgg')

root = Tk()
width = root.winfo_screenwidth()
height = root.winfo_screenheight()
# setting tkinter window size
root.geometry("%dx%d" % (width, height))

min_w = 50  # Minimum width of the frame
max_w = 200  # Maximum width of the frame
cur_width = min_w  # Increasing width of the frame
expanded = False  # Check if it is completely exanded


def Graph():
    df = pd.read_csv('nbrePieces.csv', encoding='Utf-8')
    # display x: session of the employ, y: number of "OK" pieces producted
    x = df['SESSION']
    y = df['OK']

    fig = Figure(figsize=(12, 10))
    ax = fig.add_subplot(111)

    ax.bar(x, y, color='g')
    ax.set_xlabel('SESSION')
    ax.set_ylabel('DATA')

    ax.legend()
    ax.grid()

    canvas = FigureCanvasTkAgg(fig, master=frameG)

    canvas.get_tk_widget().grid(rows=0, column=0)
    canvas.draw()


def expand():
    global cur_width, expanded
    cur_width += 10  # Increase the width by 10
    rep = root.after(5, expand)  # Repeat this func every 5 ms
    frame.config(width=cur_width)  # Change the width to new increase width
    if cur_width >= max_w:  # If width is greater than maximum width
        expanded = True  # Frame is expended
        root.after_cancel(rep)  # Stop repeating the func
        fill()


def fill():
    if expanded:  # If the frame is exanded
        # Show a text, and remove the image
        home_b.config(text='Home', image='', font=(0, 15))
        liste_b.config(text='liste employés', image='', font=(0, 15))
        ajout_b.config(text='ajouter employés', image='', font=(0, 15))
        settings_b.config(text='settings', image='', font=(0, 15))
    else:
        # Bring the image back
        home_b.config(image=home, font=(0, 15))
        liste_b.config(image=liste, font=(0, 15))
        ajout_b.config(image=ajouter, font=(0, 15))
        settings_b.config(image=settings, font=(0, 15))


 def contract():
    global cur_width, expanded
    cur_width -= 10  # Reduce the width by 10
    rep = root.after(5, contract)  # Call this func every 5 ms
    frame.config(width=cur_width)  # Change the width to new reduced width
    if cur_width <= min_w:  # If it is back to normal width
        expanded = False  # Frame is not expanded
        root.after_cancel(rep)  # Stop repeating the func
        fill()


# Define the icons to be shown and resize it
home = ImageTk.PhotoImage(Image.open(
    'home.png').resize((40, 40), Image.ANTIALIAS))
liste = ImageTk.PhotoImage(Image.open(
    'liste.png').resize((40, 40), Image.ANTIALIAS))
ajouter = ImageTk.PhotoImage(Image.open(
    'ajouter.png').resize((40, 40), Image.ANTIALIAS))
settings = ImageTk.PhotoImage(Image.open(
    'settings.png').resize((40, 40), Image.ANTIALIAS))

root.update()  # For the width to get updated
frame = Frame(root, bg='#C1FFC1', width=50, height=root.winfo_height())
frame.grid(row=0, column=0)
# create the frame where the graph will appear
frameG = Frame(root, bg='gray2', width=1000,
               height=root.winfo_height(), padx=3, pady=3)
frameG.grid(row=0, column=1, sticky="nsew")

# Make the buttons with the icons to be shown
home_b = Button(frame, image=home, bg='#C1FFC1',
                command=lambda: Graph, relief='flat')
liste_b = Button(frame, image=liste, bg='#C1FFC1', relief='flat')
ajout_b = Button(frame, image=ajouter, bg='#C1FFC1', relief='flat')
settings_b = Button(frame, image=settings, bg='#C1FFC1', relief='flat')

# Put them on the frame
home_b.grid(row=0, column=0, pady=10)
liste_b.grid(row=1, column=0, pady=10)
ajout_b.grid(row=2, column=0, pady=10)
settings_b.grid(row=3, column=0, pady=10)

# Bind to the frame, if entered or left
frame.bind('<Enter>', lambda e: expand())
frame.bind('<Leave>', lambda e: contract())


# So that it does not depend on the widgets inside the frame
frame.grid_propagate(False)


root.mainloop()

i want once i click on the button 'home'in my menu bar a graph will appear in the full right side of my menu bar. thanks in advance

Upvotes: 1

Views: 424

Answers (1)

furas
furas

Reputation: 143216

I found two problems

  1. It has to be command=lambda:Graph() with () or command=Graph without () and without lambda

  2. typo in line

     canvas.get_tk_widget().grid(row=0, column=0)
    

    it has to be row instead of rows

After that it works.


Minimal working code.

I use empty images Image.new() to display it without files.

I put example data directly in code.

This way everyone can simply copy and run it.

from matplotlib.backends.backend_tkagg import (
FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.figure import Figure
import pandas as pd
from tkinter import *
from PIL import Image, ImageTk
import matplotlib.pyplot as plt
import matplotlib
matplotlib.use('TkAgg')

root = Tk()
width = root.winfo_screenwidth()
height = root.winfo_screenheight()
# setting tkinter window size
root.geometry("%dx%d" % (width, height))

min_w = 50  # Minimum width of the frame
max_w = 200  # Maximum width of the frame
cur_width = min_w  # Increasing width of the frame
expanded = False  # Check if it is completely exanded


def Graph():
    #df = pd.read_csv('nbrePieces.csv', encoding='Utf-8')
    df = pd.DataFrame({'SESSION':[1,2,3], 'OK':[10,12,14]})
    
    # display x: session of the employ, y: number of "OK" pieces producted
    x = df['SESSION']
    y = df['OK']

    fig = Figure(figsize=(12, 10))
    ax = fig.add_subplot(111)

    ax.bar(x, y, color='g')
    ax.set_xlabel('SESSION')
    ax.set_ylabel('DATA')

    ax.legend()
    ax.grid()

    canvas = FigureCanvasTkAgg(fig, master=frameG)

    canvas.get_tk_widget().grid(row=0, column=0)  # typo: `row`
    canvas.draw()


def expand():
    global cur_width, expanded
    cur_width += 10  # Increase the width by 10
    rep = root.after(5, expand)  # Repeat this func every 5 ms
    frame.config(width=cur_width)  # Change the width to new increase width
    if cur_width >= max_w:  # If width is greater than maximum width
        expanded = True  # Frame is expended
        root.after_cancel(rep)  # Stop repeating the func
        fill()


def fill():
    if expanded:  # If the frame is exanded
        # Show a text, and remove the image
        home_b.config(text='Home', image='', font=(0, 15))
        liste_b.config(text='liste employés', image='', font=(0, 15))
        ajout_b.config(text='ajouter employés', image='', font=(0, 15))
        settings_b.config(text='settings', image='', font=(0, 15))
    else:
        # Bring the image back
        home_b.config(image=home, font=(0, 15))
        liste_b.config(image=liste, font=(0, 15))
        ajout_b.config(image=ajouter, font=(0, 15))
        settings_b.config(image=settings, font=(0, 15))


def contract():
    global cur_width, expanded
    cur_width -= 10  # Reduce the width by 10
    rep = root.after(5, contract)  # Call this func every 5 ms
    frame.config(width=cur_width)  # Change the width to new reduced width
    if cur_width <= min_w:  # If it is back to normal width
        expanded = False  # Frame is not expanded
        root.after_cancel(rep)  # Stop repeating the func
        fill()


# Define the icons to be shown and resize it
#home = ImageTk.PhotoImage(Image.open('home.png').resize((40, 40), Image.ANTIALIAS))
#liste = ImageTk.PhotoImage(Image.open('liste.png').resize((40, 40), Image.ANTIALIAS))
#ajouter = ImageTk.PhotoImage(Image.open('ajouter.png').resize((40, 40), Image.ANTIALIAS))
#settings = ImageTk.PhotoImage(Image.open('settings.png').resize((40, 40), Image.ANTIALIAS))

home = ImageTk.PhotoImage(Image.new('RGB', (40,40), 'red'))
liste = ImageTk.PhotoImage(Image.new('RGB', (40,40), 'green'))
ajouter = ImageTk.PhotoImage(Image.new('RGB', (40,40), 'blue'))
settings = ImageTk.PhotoImage(Image.new('RGB', (40,40), 'yellow'))

root.update()  # For the width to get updated
frame = Frame(root, bg='#C1FFC1', width=50, height=root.winfo_height())
frame.grid(row=0, column=0)

# create the frame where the graph will appear
frameG = Frame(root, bg='gray2', width=1000,
               height=root.winfo_height(), padx=3, pady=3)
frameG.grid(row=0, column=1, sticky="nsew")

# Make the buttons with the icons to be shown
home_b = Button(frame, image=home, bg='#C1FFC1',
                command=lambda: Graph(), relief='flat')
liste_b = Button(frame, image=liste, bg='#C1FFC1', relief='flat')
ajout_b = Button(frame, image=ajouter, bg='#C1FFC1', relief='flat')
settings_b = Button(frame, image=settings, bg='#C1FFC1', relief='flat')

# Put them on the frame
home_b.grid(row=0, column=0, pady=10)
liste_b.grid(row=1, column=0, pady=10)
ajout_b.grid(row=2, column=0, pady=10)
settings_b.grid(row=3, column=0, pady=10)

# Bind to the frame, if entered or left
frame.bind('<Enter>', lambda e: expand())
frame.bind('<Leave>', lambda e: contract())


# So that it does not depend on the widgets inside the frame
frame.grid_propagate(False)


root.mainloop()

enter image description here

Upvotes: 1

Related Questions