Reaching an Object Outside of the Class in Python

Hello everyone,

I have started to learn Python recently and I am trying to make a basic GUI. I stucked at some point as you imagine. I found that code from the internet (possibly in stackoverflow) and am trying to modify it for the GUI which I want to make.

All code;

# imported necessary packages etc. 

class tkinterApp(tk.Tk):  
    # __init__ function for class tkinterApp 
    def __init__(self, *args, **kwargs): 
        # __init__ function for class Tk 
        tk.Tk.__init__(self, *args, **kwargs)
    
        container = tk.Frame(self) 
        container.pack()
        container.pack_propagate(0)
        
        # initializing frames to an empty array 
        self.frames = {} 
        
        # iterating through a tuple consisting 
        # of the different page layouts 
        for F in (LoadPage, StartPage): 
            frame = F(container, self) 
            
            # initializing frame of that object from 
            # startpage, page1, page2 respectively with 
            # for loop 
            self.frames[F] = frame 

            frame.grid(row = 0, column = 0, sticky ="nsew")  
            
        self.show_frame(LoadPage)
        
    # to display the current frame passed as 
    # parameter 
    def show_frame(self, cont): 
        frame = self.frames[cont] 
        frame.tkraise()
        
def load():
    try:
        import data 
    except:
        print("Error...")
        
# first window frame loadpage 
class LoadPage(tk.Frame): 
    def __init__(self, parent, controller): 
        tk.Frame.__init__(self, parent) 

        top_container = tk.Frame(self) 
        top_container.pack()
        top_container.pack_propagate(0)
        
        lbl_title = tk.Label(top_container, text = "TITLE")
        lbl_title.pack(side="bottom")
        lbl_title.pack_propagate(0)
        
        center_container = tk.Frame(self) 
        center_container.pack()
        center_container.pack_propagate(0)
        
        a_image = ImageTk.PhotoImage(Image.open(r"images/image.png"))
        image_area = tk.Label(center_container, image = a_image)
        image_area.image = a_image
        image_area.pack(side = "top", pady=50)
        image_area.pack_propagate(0)
        
        b_image = ImageTk.PhotoImage(Image.open(r"images/image.png"))
        btn_load = tk.Button(center_container, image = b_image, command=lambda:[load(), controller.show_frame(StartPage)])
        btn_load.image = b_image
        btn_load.pack(pady=10)
        btn_load.pack_propagate(0)
        
        lbl_load_inf = tk.Label(center_container, text = "INFO...")
        lbl_load_inf.pack(pady=5)
        lbl_load_inf.pack_propagate(0)
        
        bottom_container = tk.Frame(self) 
        bottom_container.pack()
        bottom_container.pack_propagate(0)
        
# second window frame startpage 
class StartPage(tk.Frame): 
    def __init__(self, parent, controller): 
        tk.Frame.__init__(self, parent) 
        
        top_container = tk.Frame(self) 
        top_container.pack()
        top_container.pack_propagate(0)
        
        lbl_title = tk.Label(top_container, text = "TITLE")
        lbl_title.pack(side="top")
        lbl_title.pack_propagate(0)
        
        toolbar = tk.Frame(top_container) 
        toolbar.pack(side="bottom")
        toolbar.pack_propagate(0)
        
        btn_1 = tk.Button(toolbar, text ="BUTTON_1", \
                           command = lambda : controller.show_frame(StartPage))
        btn_1.place(relheight=1, width=220, relx=0)
        
        btn_2 = tk.Button(toolbar, text ="BUTTON_2", \
                           command = lambda : controller.show_frame(StartPage))
        btn_2.place(relheight=1, width=200, relx=0.18)
        
        
        center_container = tk.Frame(self) 
        center_container.pack()
        center_container.pack_propagate(0)
        
        figure = plt.Figure()
        ax = figure.add_subplot(111)
        chart_type = FigureCanvasTkAgg(figure, center_container)
        chart_type.get_tk_widget().place(relx = 0.10, rely = 0.3, relwidth = 0.6, relheight = 0.4)
        df["Column"].value_counts().sort_values().plot(kind='barh', legend=True, ax=ax)
        ax.set_title('Title')
        
        bottom_container = tk.Frame(self) 
        bottom_container.pack()
        bottom_container.pack_propagate(0) 
        
# Driver Code 
app = tkinterApp() 
app.mainloop() 

If you look at the StartPage class, there is a code block in init function;

figure = plt.Figure()
ax = figure.add_subplot(111)
chart_type = FigureCanvasTkAgg(figure, center_container)
chart_type.get_tk_widget().place(relx = 0.10, rely = 0.3, relwidth = 0.6, relheight = 0.4)
df["Column"].value_counts().sort_values().plot(kind='barh', legend=True, ax=ax)
ax.set_title('Title')

at this code block there is a DataFrame (df). It comes from data.py (imported via load function which triggered by a button in LoadPage). I said it comes from but I should have said it should come from. Unfortunately I could not get the data. DataFrame imported perfectly but somehow I cannot reach that df. How can I reach it? Possibly it is about class system, I tried a lot of things but I cannot figure it out.

I got the error;

NameError: name ‘df’ is not defined

Note: Code is a bit mess right now, I know. I will modify more in future. I am trying to learn how Tkinter, GUI, Python works just right now. Please pardon me for that messy code :slight_smile:

Generally after importing

import data

If df is in there, it would be accessible with data.df
To use just df import would need to look like:

from data import df

However, because this is called within function, this makes it harder, as the scope of that import, as it is, is actually just the load function. In such case there will be needed additional operations to access contents of the data module outside of load function.

@sanity thanks for the answer.

I tried to code as data.df too with a lot of different trying. Unfortunately, I could not solve the problem for a while. Finally, I changed the code a bit and it works now.

I think the problem was init function. If you look at the code, firstly tkinterApp instance is created. This object creates other instances (StartPage, LoadPage) via init function. So, script should know what data.df is at the beginning. However it cannot be known before the user’s execution via pressing load button. Therefore, the pages which use df should be created outside of init function, after the execution of load button.

Anyway, I changed the code. The code creates only LoadPage with tkinterApp class init function. I write another method in tkinterApp and it creates other pages when load button pressed. I create an empty DataFrame object at the beginning of the script and I defined this object as global at load() function. Then, I assign this object to data.df. So, I can use this object as data.df wherever I want.

Possibly there is a more elegant way to do it. I will try to simplify my code at the end. I am trying to run it without problem right now.