When using DataFrame, there are situations where I wish I could search and display it. It is especially useful when creating GUI apps. I would like to search Pandas DataFrame below and create a search form to display using Tkinter.
import pandas as pd
import tkinter as tk
import tkinter.ttk as ttk
class SearchWindow(tk.Frame):
def __init__(self, master=None, parent=None):
super().__init__(master)
self.master = master
self.master.geometry("300x300")
self.master.title("Search window")
self.pack()
self.set_data()
self.create_widgets()
def set_data(self):
self.data = pd.read_csv("data.csv", encoding="utf-8")
self.colname_list = ["Food code", "Food name"] #Column name to be displayed in the search results
self.width_list = [100, 200]
self.search_col = "Search keyword" # Search keywordの入力されている列名
def create_widgets(self):
self.pw_main = ttk.PanedWindow(self.master, orient="vertical")
self.pw_main.pack(expand=True, fill=tk.BOTH, side="left")
self.pw_top = ttk.PanedWindow(self.pw_main, orient="horizontal", height=25)
self.pw_main.add(self.pw_top)
self.pw_bottom = ttk.PanedWindow(self.pw_main, orient="vertical")
self.pw_main.add(self.pw_bottom)
self.creat_input_frame(self.pw_top)
self.create_tree(self.pw_bottom)
def creat_input_frame(self, parent):
fm_input = ttk.Frame(parent, )
parent.add(fm_input)
lbl_keyword = ttk.Label(fm_input, text="keyword", width=7)
lbl_keyword.grid(row=1, column=1, padx=2, pady=2)
self.keyword = tk.StringVar()
ent_keyword = ttk.Entry(fm_input, justify="left", textvariable=self.keyword)
ent_keyword.grid(row=1, column=2, padx=2, pady=2)
ent_keyword.bind("<Return>", self.search)
def create_tree(self, parent):
self.result_text = tk.StringVar()
lbl_result = ttk.Label(parent, textvariable=self.result_text)
parent.add(lbl_result)
self.tree = ttk.Treeview(parent)
self.tree["column"] = self.colname_list
self.tree["show"] = "headings"
self.tree.bind("<Double-1>", self.onDuble)
for i, (colname, width) in enumerate(zip(self.colname_list, self.width_list)):
self.tree.heading(i, text=colname)
self.tree.column(i, width=width)
parent.add(self.tree)
def search(self, event=None):
keyword = self.keyword.get()
result = self.data[self.data[self.search_col].str.contains(keyword, na=False)]
self.update_tree_by_search_result(result)
def update_tree_by_search_result(self, result):
self.tree.delete(*self.tree.get_children())
self.result_text.set(f"search results:{len(result)}")
for _, row in result.iterrows():
self.tree.insert("", "end", values=row[self.colname_list].to_list())
def onDuble(self, event):
for item in self.tree.selection():
print(self.tree.item(item)["values"])
def main():
root = tk.Tk()
app = SearchWindow(master=root)
app.mainloop()
if __name__ == "__main__":
main()
The contents of the CSV being read are as follows. :
Food code Food name Search keyword
0 1001 Amaranth / Genuine Amaranth / Genuine Amaranthus
1 1002 Millet / millet grain millet / millet grain millet
2 1003 Awa Mochi Awa Mochi Awa Mochi Awa Mochi
3 1004 Oat / Oatmeal Oat / Oatmeal Oat Meal Oat Oat
4 1005 Barley / Oshimugi with seven minutes Barley / Oshimugi with seven minutes Omugi Nanabutsuki Oshimugi
Enter text → Enter to display the search results in the tree.
The methods are linked so that you can search with the Enter key. The following part:
ent_keyword.bind("<Return>", self.search)
TTK's Treeview is used as the widget that displays the search results. I like it because it can be displayed simply in tabular format. When search
is executed, ʻupdate_tree_by_search_result` receives the result. All are deleted before inserting into Treeview, and then added. This part is the following process:
def search(self, event=None):
keyword = self.keyword.get()
result = self.data[self.data[self.search_col].str.contains(keyword, na=False)]
self.update_tree_by_search_result(result)
def update_tree_by_search_result(self, result):
self.tree.delete(*self.tree.get_children())
self.result_text.set(f"search results:{len(result)}")
for _, row in result.iterrows():
self.tree.insert("", "end", values=row[self.colname_list].to_list())
Although not mentioned in the GIF, you can also use this search result. In the code below, ʻon Double` is linked as the process when the tree item is double-clicked.
self.tree.bind("<Double-1>", self.onDuble)
onDouble is as follows. You can now get the value of the selected item.
def onDuble(self, event):
for item in self.tree.selection():
print(self.tree.item(item)["values"])
Recommended Posts