【问题标题】:Filter pandas dataframe, display in tkinter/pandastable过滤 pandas 数据框,在 tkinter/pandastable 中显示
【发布时间】:2018-12-16 17:45:38
【问题描述】:

我正在尝试创建一个涉及显示中型熊猫数据框的应用程序。我正在为我的用户界面使用 pandastable 和 tkinter。我希望用户能够做的部分事情是从组合框中选择一个过滤器,然后只显示匹配的行。

下面是我尝试使用的代码的简化但完整的版本。我创建了一个包含核心 UI 代码的类。最初一切看起来都很棒。我在我的类(change_df)中创建了一个测试按钮函数,它创建了一个虚拟列,效果很好。我在类(change_df_combo)中有另一个函数可以成功过滤数据框,但它不会显示在屏幕上。即,我可以打印 df 或导出它并且它已过滤。但是,这不会显示在屏幕上。

我假设我的班级或 tkinter 本身的循环不正确,但对于我的生活,我无法弄清楚!有什么想法吗?

from win32com.shell import shell, shellcon
import pandas as pd
import openpyxl
from openpyxl import load_workbook
import numpy as np
import time
from tkinter import *
from tkinter import ttk
from pandastable import Table, TableModel

class UserInterface(Frame):
    # Launch the df in a pandastable frame
    def __init__(self, parent=None):
        global ui_df
        global pt
        ui_df = pos_df
        self.parent = parent
        Frame.__init__(self)
        self.main = self.master
        #self.main.geometry('800x600+0+0')
        f = Frame(self.main)
        f.grid(column=0, row=1, sticky=(E, W))
        screen_width = f.winfo_screenwidth() * 0.8
        screen_height = f.winfo_screenheight() * 0.7
        self.table = pt = Table(f, dataframe=ui_df, height = screen_height, width = screen_width)
        pt.show()
        return

    def change_df(self, col_val_input):
        #Responds to button
        ui_df['Test col'] = col_val_input
        pt.show()

    def change_df_combo(self, event):
        #Responds to combobox, supposed to filter by 'Sec_type'
        combo_selection = str(combo_box.get())
        ui_df = pos_df[pos_df['Sec_type'] == combo_selection]
        pt.show()

#Create dataframe
pos_data = {'Location' : ['Denver', 'Boulder', 'Phoenix', 'Reno', 'Portland',
'Eugene', 'San Francisco'], 'Sec_type' : ['mbus', 'mbus', 'vmus', 'caus',
'vmus', 'mbus', 'mbus']}
pos_df = pd.DataFrame(data = pos_data)

#Launch Tkinter basics
root = Tk()
root.title("S test...")

mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)

ui_display = UserInterface(mainframe)

#'Test' button, this works fine
col_val_input = 'It worked!'
test_button = ttk.Button(mainframe, text = 'Test', command= lambda: ui_display.change_df(col_val_input))
test_button.grid(column=0, row=0, sticky=(W))

#Combobox, works to just show choice, but not to filter
combo_choices = ['mbus', 'vmus', 'caus']
choice = StringVar()
combo_box = ttk.Combobox(mainframe, textvariable=choice)
combo_box['values'] = combo_choices
combo_box.grid(column=1, row=0, sticky=(W))
combo_box.bind('<<ComboboxSelected>>', ui_display.change_df_combo)

root.mainloop()

编辑添加: 将导入的 df 更改为玩具 df 以进行测试

【问题讨论】:

  • 您可能希望包含 Excel 文件的示例。否则,我们将无法运行您的代码,这使得调试变得更加困难。屏幕截图应该可以。
  • @slightly_toasted:将数据框嵌入到文件中,使测试更容易
  • Tkinter 按预期循环,但是您的 change_df_combo 方法只是将过滤后的 df 存储在变量中。您需要在清除原始数据并显示过滤数据的方法末尾添加代码。
  • 您能详细说明一下吗?如果我 print(ui_df) 它看起来像我期望的那样。

标签: python pandas tkinter


【解决方案1】:

好的,我想出了一些可行的方法。不确定它是否是有史以来写的最 Pythonic 的代码,但它是这样的:(只发布类段)

class UserInterface(Frame):
    # Launch the df in a pandastable frame
    def __init__(self, parent=None):
        global ui_df
        ui_df = pos_df
        self.parent = parent
        self.refresh_df(df = ui_df)

    def refresh_df(self, df):
        Frame.__init__(self)
        self.main = self.master
        f = Frame(self.main)
        f.grid(column=0, row=1, sticky=(E, W))
        screen_width = f.winfo_screenwidth() * 0.8
        screen_height = f.winfo_screenheight() * 0.7
        self.table = pt = Table(f, dataframe=df, height = screen_height, width = screen_width)
        pt.show()
        return

    def change_df(self, col_val_input):
        #Responds to button
        ui_df['Test col'] = col_val_input
        self.refresh_df(df=ui_df)

    def change_df_combo(self, event):
        #Responds to combobox, supposed to filter by 'Sec_type'
        combo_selection = str(combo_box.get())
        ui_df = pos_df[pos_df['Sec_type'] == combo_selection]
        ui_df['Test col combo'] = combo_selection
        self.refresh_df(df=ui_df)

【讨论】:

  • 嗨,汤姆,我非常喜欢这个解决方案,但我似乎无法使其在具有 matplotlib 依赖项的 py3.7 上运行。它对你有什么作用?
  • 无法导入 matplotlib.pyplot。我看到这是 py3.7 的一个已知问题
猜你喜欢
  • 2019-06-14
  • 2015-09-12
  • 1970-01-01
  • 2018-06-07
  • 2021-10-24
  • 2019-03-29
  • 2017-12-01
  • 1970-01-01
  • 2019-08-14
相关资源
最近更新 更多