Python 从 Pandas 数据框填充 QTableView 的最快方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31475965/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 10:04:09  来源:igfitidea点击:

Fastest way to populate QTableView from Pandas data frame

pythonpandaspyqt4

提问by Santi Pe?ate-Vera

I'm very new to PyQt and I am struggling to populate a QTableView control.

我对 PyQt 很陌生,我正在努力填充 QTableView 控件。

My code is the following:

我的代码如下:

def data_frame_to_ui(self, data_frame):
        """
        Displays a pandas data frame into the GUI
        """
        list_model = QtGui.QStandardItemModel()
        i = 0
        for val in data_frame.columns:
            # for the list model
            if i > 0:
                item = QtGui.QStandardItem(val)
                #item.setCheckable(True)
                item.setEditable(False)
                list_model.appendRow(item)
            i += 1
        self.ui.profilesListView.setModel(list_model)

        # for the table model
        table_model = QtGui.QStandardItemModel()

        # set table headers
        table_model.setColumnCount(data_frame.columns.size)
        table_model.setHorizontalHeaderLabels(data_frame.columns.tolist())
        self.ui.profileTableView.horizontalHeader().setStretchLastSection(True)

        # fill table model data
        for row_idx in range(10): #len(data_frame.values)
            row = list()
            for col_idx in range(data_frame.columns.size):
                val = QtGui.QStandardItem(str(data_frame.values[row_idx][col_idx]))
                row.append(val)
            table_model.appendRow(row)

        # set table model to table object
        self.ui.profileTableView.setModel(table_model)

Actually in the code I succeed to populate a QListView, but the values I set to the QTableView are not displayed, also you can see that I truncated the rows to 10 because it takes forever to display the hundreds of rows of the data frame.

实际上在代码中我成功地填充了一个 QListView,但是我设置给 QTableView 的值没有显示,你也可以看到我将行截断为 10,因为它需要永远显示数据框的数百行。

So, What is the fastest way to populate the table model from a pandas data frame?

那么,从 Pandas 数据框填充表模型的最快方法是什么?

Thanks in advance.

提前致谢。

采纳答案by Wolph

Personally I would just create my own model class to make handling it somewhat easier.

就我个人而言,我只会创建自己的模型类,以便更轻松地处理它。

For example:

例如:

import sys
from PyQt4 import QtCore, QtGui
Qt = QtCore.Qt

class PandasModel(QtCore.QAbstractTableModel):
    def __init__(self, data, parent=None):
        QtCore.QAbstractTableModel.__init__(self, parent)
        self._data = data

    def rowCount(self, parent=None):
        return len(self._data.values)

    def columnCount(self, parent=None):
        return self._data.columns.size

    def data(self, index, role=Qt.DisplayRole):
        if index.isValid():
            if role == Qt.DisplayRole:
                return QtCore.QVariant(str(
                    self._data.values[index.row()][index.column()]))
        return QtCore.QVariant()


if __name__ == '__main__':
    application = QtGui.QApplication(sys.argv)
    view = QtGui.QTableView()
    model = PandasModel(your_pandas_data)
    view.setModel(model)

    view.show()
    sys.exit(application.exec_())

回答by Santi Pe?ate-Vera

This works:

这有效:

class PandasModel(QtCore.QAbstractTableModel):
    """
    Class to populate a table view with a pandas dataframe
    """
    def __init__(self, data, parent=None):
        QtCore.QAbstractTableModel.__init__(self, parent)
        self._data = data

    def rowCount(self, parent=None):
        return len(self._data.values)

    def columnCount(self, parent=None):
        return self._data.columns.size

    def data(self, index, role=QtCore.Qt.DisplayRole):
        if index.isValid():
            if role == QtCore.Qt.DisplayRole:
                return str(self._data.values[index.row()][index.column()])
        return None

    def headerData(self, col, orientation, role):
        if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
            return self._data.columns[col]
        return None

Using it like this:

像这样使用它:

model = PandasModel(your_pandas_data_frame)
your_tableview.setModel(model)

I read hereto avoid QVariant()from PyQT 4.6 on.

在这里阅读是为了避免QVariant()从 PyQT 4.6 开始。

回答by Gabriel Reis

There is actually some code in pandassupporting integration with Qt.

实际上有一些代码pandas支持与 Qt 的集成。

At the time of writing this answer, the latest pandas version is 0.18.1and you could do:

在撰写此答案时,最新的 Pandas 版本是0.18.1,您可以执行以下操作:

from pandas.sandbox.qtpandas import DataFrameModel, DataFrameWidget

That code seems to be coupled to PySide, however it should be relatively trivial to make it work with PyQt. Also, that code has been deprecated and the warning says that the module will be removed in the future.

该代码似乎与 PySide 耦合,但是使其与 PyQt 一起工作应该相对简单。此外,该代码已被弃用,警告说该模块将在未来被删除。

Luckily they extracted that into a separated project in GitHub called pandas-qt:

幸运的是,他们将其提取到 GitHub 中一个名为 的独立项目中pandas-qt

https://github.com/datalyze-solutions/pandas-qt

https://github.com/datalyze-solutions/pandas-qt

I would try to use that before trying to roll out my own model and view implementation.

在尝试推出我自己的模型和视图实现之前,我会尝试使用它。

回答by m0nhawk

I've found all of the proposed answers painfully slow for DataFrames with 1000+ rows. What works for me blazingly fast:

我发现所有建议的答案对于 1000 多行的 DataFrame 来说都非常缓慢。什么对我有用:

class PandasModel(QtCore.QAbstractTableModel):
    """
    Class to populate a table view with a pandas dataframe
    """
    def __init__(self, data, parent=None):
        QtCore.QAbstractTableModel.__init__(self, parent)
        self._data = data

    def rowCount(self, parent=None):
        return self._data.shape[0]

    def columnCount(self, parent=None):
        return self._data.shape[1]

    def data(self, index, role=QtCore.Qt.DisplayRole):
        if index.isValid():
            if role == QtCore.Qt.DisplayRole:
                return str(self._data.iloc[index.row(), index.column()])
        return None

    def headerData(self, col, orientation, role):
        if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
            return self._data.columns[col]
        return None

回答by Frederick Li

Apart from using QtCore.QAbstractTableModel, one may also inherit from QtGui.QStandardItemModel. I find this way is easier to support handleChanged event emiited from QTableView.

除了使用 QtCore.QAbstractTableModel,还可以继承 QtGui.QStandardItemModel。我发现这种方式更容易支持从 QTableView 发出的 handleChanged 事件。

from PyQt5 import QtCore, QtGui

class PandasModel(QtGui.QStandardItemModel):
    def __init__(self, data, parent=None):
        QtGui.QStandardItemModel.__init__(self, parent)
        self._data = data
        for row in data.values.tolist():
            data_row = [ QtGui.QStandardItem("{0:.6f}".format(x)) for x in row ]
            self.appendRow(data_row)
        return

    def rowCount(self, parent=None):
        return len(self._data.values)

    def columnCount(self, parent=None):
        return self._data.columns.size

    def headerData(self, x, orientation, role):
        if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
            return self._data.columns[x]
        if orientation == QtCore.Qt.Vertical and role == QtCore.Qt.DisplayRole:
            return self._data.index[x]
        return None

回答by Frederick Li

Simple and faster way to write a dataframe to QtableWidget

将数据帧写入 QtableWidget 的简单快捷的方法

# Takes a df and writes it to a qtable provided. df headers become qtable headers
@staticmethod
def write_df_to_qtable(df,table):
    headers = list(df)
    table.setRowCount(df.shape[0])
    table.setColumnCount(df.shape[1])
    table.setHorizontalHeaderLabels(headers)        

    # getting data from df is computationally costly so convert it to array first
    df_array = df.values
    for row in range(df.shape[0]):
        for col in range(df.shape[1]):
            table.setItem(row, col, QtGui.QTableWidgetItem(str(df_array[row,col])))