P.Hinz
P.Hinz

Reputation: 55

Extracting rows within Python Tkinter-Treeview into a Pandas data frame

I have a GUI where results from a dataframe are populated into a treeview within python based on filters previously input. The user can then click on treeview and update the values to the desired number. The number of rows within the view can vary from 1 - 20+. Once the user has updated the view as desired, I have a button below "Check Allocation".

It is at this point I want to "export" the treeview into a dataframe for me to run against another table. I cant seem to simply export this as a dataframe. Is there any work around this? I only need the first and last columns (of the 8) to check the newly updated file.

Here is what I have so far.

   def PrintAllocation(self):
        treeview = tkk.Treeview(root)
        treeview.grid(column = 1, row = 8, columnspan = 4, padx = 1, pady = 1)
        cols = list(matches.columns)
        treeview["columns"] = cols

        for i in cols:
            treeview.column(i, width = 100, anchor = "w")
            treeview.heading(i,text=i,anchor='w',)
        for index, row in matches.iterrows():
            treeview.insert("",0,text=index,values=list(row))

        def set_cell_value(event): # Double click to enter the edit state
            for item in treeview.selection():
                #item = I001
                item_text = treeview.item(item, "values")
                         #print(item_text[0:2]) # Output the value of the selected row
                column= treeview.identify_column(event.x)# column
                print(column)
                row = treeview.identify_row(event.y) #row
            cn = int(str(column).replace('#',''))
            rn = int(str(row).replace('I',''))
            if column == '#8':
                entryedit = Text(root,width=50,height = 1)
                entryedit.grid(column = 2, row = 9, padx = 1, pady = 1)
            else:
                entryedit = Text(root,width=10,height = 1)
                entryedit.grid(column = 2, row = 9, padx = 1, pady = 1)
            def saveedit():
                treeview.set(item, column=column, value=entryedit.get(0.0, "end"))
                entryedit.destroy()
                okb.destroy()
            okb = ttk.Button(root, text='OK', width=4, command=saveedit)
            okb.grid(column = 3, row = 9,padx = 1, pady=1)


        def CheckAllocation():
            children = treeview.getchildren()
            for child in children:
                print(treeview.set(child))

        treeview.bind('<Double-1>', set_cell_value) # Double-click the left button to enter the edit
        button_check = Button(root,text="Check Allocation", command = CheckAllocation)
        button_check.grid(column = 2, row = 10, padx = 10, pady=10)

'''



Upvotes: 0

Views: 3872

Answers (3)

Howscarrot
Howscarrot

Reputation: 39

You can also do this:

row_list = []
columns = ('name', 'school', 'c3', 'c4')
for row in treeview.get_children():
    row_list.append(treeview.item(row)["values"])
treeview_df = pd.DataFrame(row_list, columns = columns)

Upvotes: 1

Matias Andina
Matias Andina

Reputation: 4220

The current answer is good, I just wanted to add my two cents here:

self.treeview_columns = [] # list of names here
# initialize empty df
# if too big you can preallocate but probably not needed
treeview_df = pd.DataFrame(None, columns=self.treeview_columns)
for row in self.treeview.get_children():
    # each row will come as a list under name "values" 
    values = pd.DataFrame([self.treeview.item(row)["values"]], 
                columns=self.treeview_columns)
    # print(values)
    treeview_df = treeview_df.append(values)

This way you grow your df row by row using append and you reduce the number of subsets that you need to do.

Upvotes: 0

Zishe Schnitzler
Zishe Schnitzler

Reputation: 311

I don't really understand your code but when I need to get a treeview to pandas I do it as follows:

First I create an empty list for each column in the treeview.

column_a_list = []
column_b_list = []
column_c_list = []
column_d_list = []

Then running through the lines of the treeview in a "for" function, I append to each column list the value of the column in each line.

for child in self.treeview.get_children():
    column_a_list.append(self.treeview.item(child)["values"][0])            
    column_b_list.append(self.treeview.item(child)["values"][1])  
    column_c_list.append(self.treeview.item(child)["values"][2])  
    column_d_list.append(self.treeview.item(child)["values"][3])

Then I create a dictionary from all the lists, using the header as the key and lists are the values as a list.

 full_treeview_data_dict = {'HEADER A': column_a_list, 'HEADER B': column_b_list, 'HEADER C': column_c_list, 'HEADER D': column_d_list,}

Then I create a dataframe from the dictionary.

treeview_df = pd.DataFrame.from_dict(full_treeview_data_dict)

Here is the full sample code in one chunk:

column_a_list = []
column_b_list = []
column_c_list = []
column_d_list = []

for child in self.treeview.get_children():
    column_a_list.append(self.treeview.item(child)["values"][0])            
    column_b_list.append(self.treeview.item(child)["values"][1])  
    column_c_list.append(self.treeview.item(child)["values"][2])  
    column_d_list.append(self.treeview.item(child)["values"][3])  

full_treeview_data_dict = {'HEADER A': column_a_list, 'HEADER B': column_b_list, 'HEADER C': column_c_list, 'HEADER D': column_d_list,}

treeview_df = pd.DataFrame.from_dict(full_treeview_data_dict)

I hope it helps.

Upvotes: 1

Related Questions