Search code examples
pythonpython-3.xpandastkintertkinter-entry

Tkinter - passing 3 user input variables to functions to search a csv file via a pandas query


What I am trying to do: The user enters the file path to a csv, a field name, and then a keyword/phrase and clicks submit....what is returned are the results of a pandas query structured using their input which reads from the csv they want to use.

My code so far:

# Relevant Python libraries:
import pandas as pd
import csv
import tkinter as tk
    
fieldname = tk.StringVar()
keyword = tk.StringVar()
csv_file_path = tk.StringVar() 

def import_csv_data(self):
    ?????
    ?????
    df = pd.dataframe(pd.read_csv(csv_file_path)) # not sure this is possible, need to define pandas dataframe somewhere? 

def search(self):
    print(df[df[fieldname.get()].str.contains(keyword.get()), na=False)] 

window = tk.Tk()
window.title("Search CSV")
frm_form = tk.Frame(relief=tk.SUNKEN, borderwidth=3)
frm_form.pack()
        
   labels = [
       "CSV File Path:",
       "Field Name:",
       "Keyword/Phrase:",
   ]
    
 # Loop over the list of field labels
 for idx, text in enumerate(labels):
       # Create a Label widget with the text from the labels list
       label = tk.Label(master=frm_form, text=text)
        
       # Create an Entry widget
       entry = tk.Entry(master=frm_form, width=50)
       # Use the grid geometry manager to place the Label and
       # Entry widgets in the row whose index is idx
       label.grid(row=idx, column=0, sticky="ew")
       entry.grid(row=idx, column=1, sticky="ew")
    
 frm_buttons = tk.Frame()
 frm_buttons.pack(fill=tk.X, ipadx=5, ipady=5)
    
 btn_submit = tk.Button(master=frm_buttons, 
                        text="Submit", variable = csv_file_path, fieldname, keyword ) # HELP?
                       #command=lambda:[import_csv_data(self), search(self)]) #define a function and 
                       # insert at top to pull from from CSV and call with "command", bind for simplicity

 btn_submit.pack(side=tk.RIGHT, padx=10, ipadx=10)
                           
 btn_clear = tk.Button(master=frm_buttons, text="Clear")
 btn_clear.pack(side=tk.RIGHT, ipadx=10)
    
 window.mainloop()

Where I am stuck: defining the functions that will do the work. I have no idea how to lay them out. So, the first function would be to get the csv file and pass into a pandas dataframe...

The second function would get the field name (column) and the keyword and put it into something that looks like this:

print(df[df["fieldnamehere"].str.contains("thisphraseorkeyword", na=False)]

What I have found online so far doesn't have an example of how to get the input information into the function. I have labored searching for this situation and haven't had any luck. I don't have the skill to find related examples for one part and make it my own, I'm not there yet. I've also watched the first few parts of this YouTube tutorial by sentdex to help get me this far: https://www.youtube.com/watch?v=oV68QJJUXTU as did this RealPython tutorial: https://realpython.com/python-gui-tkinter/

This answer seemed helpful, but not sure to apply it here: https://stackoverflow.com/a/40894757

Ask: Any assistance with the functions and how to get the user input into the pandas string would be greatly appreciated. What I have written for the functions is kind of a guess. I am not sure how to use the get() within the functions to make sure it does what is intended. I hope this question is good enough, I've been editing it for an hour, ha.


Solution

  • I believe you are looking for something like this

    def import_csv_data():
        df = pd.DataFrame(pd.read_csv(csv_file_path.get()))
        search(df)
    
    def search(df):
        print(df[df[fieldname.get()].astype(str).str.contains(keyword.get())])
    

    You would need to define the StringVars after defining tk.Tk so that root is defined.

    window = tk.Tk()
    window.title("Search CSV")
    frm_form = tk.Frame(relief=tk.SUNKEN, borderwidth=3)
    frm_form.pack()
    
    csv_file_path = tk.StringVar() 
    fieldname = tk.StringVar()
    keyword = tk.StringVar()
    

    Since you are creating the Entry fields in a loop, you can use a dictionary and assign the textvariable

    labels = {
       "CSV File Path:":csv_file_path,
       "Field Name:":fieldname,
       "Keyword/Phrase:":keyword,
    }
        
    for idx, text in enumerate(labels.keys()):
        label = tk.Label(master=frm_form, text=text)
        entry = tk.Entry(master=frm_form, width=50, textvariable=labels[text])
        label.grid(row=idx, column=0, sticky="ew")
        entry.grid(row=idx, column=1, sticky="ew")
    

    For the button, you can simply use the import_csv_data function as the command

    btn_submit = tk.Button(master=frm_buttons, 
                        text="Submit",command=import_csv_data)