0

In my tkinter GUI the user can generate a pandas dataframe (in the example I take a fixed one). In the GUI the user can enter a name and click the save button. The idea is that the dataframe is than stored as a global variable, so that it is available with that name, when the user leaves my application. I would also like to keep track of the variables he created in a combobox. Anyone who can help me with this results in n error message, such as global df ^ SyntaxError: invalid syntax

Here is my code:

#%% Import libraries
import tkinter as tk
import tkinter.ttk as ttk
import tkinter.messagebox as messagebox
import pandas as pd

#%% Main class
class PyDataTest(ttk.Frame):
    def __init__(self, master = None):
        # Construct the Frame object.
        ttk.Frame.__init__(self, master)
        self.grid(sticky=tk.N+tk.S+tk.E+tk.W)
        self.createWidgets()

    def save(self):
        global df 
        df = pd.DataFrame({'AAA' : [1., 2., 3., 4.], 'BBB' : [4., 3., 2., 1.]})
        messagebox.showinfo("Info","pandas dataframe saved as df")
#        eval("global " + self.pythonVar.get())
#        eval(self.pythonVar.get() + " = self.pyTable.data")
#        messagebox.showinfo("Info","pandas dataframe saved as " + self.pythonVar.get())

    #%% Create widgets
    def createWidgets(self):
        # Get top window 
        self.top = self.winfo_toplevel()

        # Make it stretchable         
        self.top.rowconfigure(0, weight=1)
        self.top.columnconfigure(0, weight=1)

        # Allow to enter a name and save the data in the base workspace
        ttk.Label(self, text = "Variable").grid(row = 0, column = 0, sticky = tk.W, padx =5, pady=5)
        self.pythonVar = tk.StringVar()
        self.pythonVar.set('d')
        ttk.Entry(self, textvariable=self.pythonVar).grid(row = 0, column = 1, sticky = tk.W, padx =5, pady=5)
        # Save button
        ttk.Button(self, text = "Save", command=self.save).grid(row = 0, column = 2, sticky = tk.W, padx =5, pady=5)

        # Combobox showing dataframes stored
        ttk.Label(self, text = "Dataframes").grid(row = 1, column = 0, sticky = tk.W, padx =5, pady=5)
        comboboxDataframes = ttk.Combobox(self)
#        variables= [var for var in dir() if isinstance(eval(var), pd.core.frame.DataFrame)]
#        comboboxDataframes['values'] = variables
        comboboxDataframes.grid(row = 1, column = 1, sticky = tk.W, padx =5, pady=5)    

#%% Allow the class to run stand-alone.
if __name__ == "__main__":
    PyDataTest().mainloop()
lvdp
  • 5
  • 5
  • 4
    When they "leave your application," how would they access this global variable? – Scott Hunter Dec 27 '17 at 22:56
  • 2
    Why do you need a unique variable name? Why not just store the data in a dictionary? – Bryan Oakley Dec 27 '17 at 22:58
  • 1
    "stored as a global variable, so that it is available with that name, when the user leaves my application" - you seem to be expecting globals to be so global that they're shared between separate executions of your program. They're not. Globals go away when your program ends. – user2357112 Dec 27 '17 at 22:59
  • To clarify the reason and how they can access the global variable after leaving my application: They work e.g. Spyder. To get access to data in an easy way, the user there runs my application, select what they need, give it the name they want, and then exit my program. Then they can go on in Spyder with that dataframe. – lvdp Dec 28 '17 at 14:03

1 Answers1

2

Standard way of doing this is to store it in a dictionary that has the user's desired key as in:

def save(self):
    global df 
    df = pd.DataFrame({'AAA' : [1., 2., 3., 4.], 'BBB' : [4., 3., 2., 1.]})

should simply be replaced with:

def save(self):
    global df
    user_spec = self.pythonVar.get()
    df[user_spec] = pd.DataFrame({'AAA' : [1., 2., 3., 4.], 'BBB' : [4., 3., 2., 1.]})

while also declaring df as a dictionary in the global scope, for example in 'main':

if __name__ == "__main__":
    df = dict()
    PyDataTest().mainloop()

A dangerous, and error-prone way would be to use exec or eval built-in method, like in here.

Nae
  • 14,209
  • 7
  • 52
  • 79
  • Thanks to your info I found a workable solution: var = self.pythonVar.get() glb = globals() glb[var] = pd.DataFrame({'AAA' : [1., 2., 3., 4.], 'BBB' : [43., 32., 21., 10.]}) – lvdp Dec 28 '17 at 16:46