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
Fastest way to populate QTableView from Pandas data frame
提问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 pandas
supporting integration with Qt.
实际上有一些代码pandas
支持与 Qt 的集成。
At the time of writing this answer, the latest pandas version is 0.18.1
and 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])))