考えられるのは、PyQt5 MVプログラミングイディオムでデータフレームを表示し、提示されたデータフレームに対して基本的なソートとフィルタリング操作を実行することです。pyqt5テーブルビューでソートした後にテーブルビューが更新されない
表示部分はすべて問題なくなりましたが、今はツールのソート部分に固執しています。 Printステートメントは自分自身がソートされたデータフレームを表示しました。これは更新されていないビューです。これでコードに戻りました:
import sys
import operator
tmp = [('23-02-1978', '19:03:13', 'eh', None, 'even more some data'),
('23-02-1978', '19:01:45', 'ss', 'some data ', 'even more some data'),
('23-02-1978', '19:02:55', 'he', 'some data ', 'even more some data')]
tmp1 = [('23-02-1978', '19:02:33', 'eh', 'some data ', '666', 'even more some data'),
('23-02-1978', '19:03:22', 'ss', 'some data ', '777', 'even more some data'),
('23-02-1978', '19:01:45', 'he', 'some data ', '888', 'even more some data')]
from PyQt5.QtWidgets import (QMainWindow, QApplication, QWidget, QAction,
QGroupBox, QCheckBox, QTableView, QTableWidgetItem,
QTabWidget, QGridLayout,QLineEdit, QFormLayout,
QVBoxLayout, QHBoxLayout, QLabel, QDialog, QHeaderView)
from PyQt5.QtGui import QIcon, QFont
from PyQt5.QtCore import Qt, pyqtSlot, pyqtSignal, QAbstractTableModel, QVariant, QModelIndex, QSortFilterProxyModel
from pandas import DataFrame
class DataFrameModel(QAbstractTableModel):
def __init__(self):
""" datain: a list of lists
headerdata: a list of strings
"""
super(DataFrameModel, self).__init__()
self._df = DataFrame()
def setDataFrame(self, df):
self._df = df;
def signalUpdate(self):
''' tell viewers to update their data (this is full update, not
efficient)'''
self.layoutChanged.emit()
#------------- table display functions -----------------
def headerData(self, section, orientation, role=Qt.DisplayRole):
if role != Qt.DisplayRole:
return QVariant()
if orientation == Qt.Horizontal:
try:
return self._df.columns.tolist()[section]
except (IndexError,):
return QVariant()
elif orientation == Qt.Vertical:
try:
# return self.df.index.tolist()
return self._df.index.tolist()[section]
except (IndexError,):
return QVariant()
def data(self, index, role=Qt.DisplayRole):
if role != Qt.DisplayRole:
return QVariant()
if not index.isValid():
return QVariant()
return QVariant(str(self._df.ix[index.row(), index.column()]))
def flags(self, index):
flags = super(DataFrameModel, self).flags(index)
return flags
def setData(self, index, value, role):
row = self._df.index[index.row()]
col = self._df.columns[index.column()]
if hasattr(value, 'toPyObject'):
# PyQt4 gets a QVariant
value = value.toPyObject()
else:
# PySide gets an unicode
dtype = self._df[col].dtype
if dtype != object:
value = None if value == '' else dtype.type(value)
self._df.set_value(row, col, value)
return True
def rowCount(self, parent=QModelIndex()):
return len(self._df.index)
def columnCount(self, parent=QModelIndex()):
return len(self._df.columns)
def sort(self, column, order=Qt.AscendingOrder):
"""Sort table by given column number.
"""
print('sort clicked col {} order {}'.format(column, order))
self.layoutAboutToBeChanged.emit()
print(self._df.columns[column])
self._df.sort_values('time', ascending=order == Qt.AscendingOrder, inplace=True)
print(self._df)
self.layoutChanged.emit()
class DataFrameWidget(QWidget):
''' a simple widget for using DataFrames in a gui '''
def __init__(self, dataFrame, parent=None):
super(DataFrameWidget, self).__init__(parent)
self.dataModel = DataFrameModel()
# Set DataFrame
self.dataTable = QTableView()
# self.proxy = QSortFilterProxyModel()
# self.proxy.setSourceModel(self.dataModel)
self.dataTable.setModel(self.dataModel)
self.dataTable.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
self.setDataFrame(dataFrame)
self.dataTable.setSortingEnabled(True)
self.dataTable.sortByColumn(0,0)
layout = QVBoxLayout()
layout.addWidget(self.dataTable)
self.setLayout(layout)
def setDataFrame(self, dataFrame):
self.dataModel.setDataFrame(dataFrame)
self.dataModel.signalUpdate()
def testDf():
''' creates test dataframe '''
# data = {'int': [1, 2, 3], 'float': [1.5, 2.5, 3.5],
# 'string': ['a', 'b', 'c'], 'nan': [np.nan, np.nan, np.nan]}
# data = [(1, 1.5, 'a', np.nan),
# (2, 2.5, 'b', np.nan),
# (3, 3.5, 'c', np.nan)]
return DataFrame(tmp, columns=['date', 'time', 'string', 'nan', 'bla'])
class Form(QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
df = testDf() # make up some data
widget = DataFrameWidget(df)
layout = QVBoxLayout()
layout.addWidget(widget)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
form = Form()
form.show()
exit(app.exec_())
この例ではSortFilterProxyを使用しましたが、データフレームが大きくなると非常に遅くなりました。
上記のコード例は、データフレーム以外のデータに対してソートされています。タプルのリストだけでモデル/ビューを作成するとうまくいきました。
私が見つけたアドバイスは、主に2つの方向にありました。表示を知らせるか、sortfilterproxyを使用してください。私は思い出して試しましたが、これまで成功していませんでした。データフレームの使用に関連しているようです。すべてのアドバイスは大歓迎です。前もって感謝します。
インデックスをリセットすると、間違った方向に見えていました。迅速な返信をありがとう、私が家に帰るとすぐにこれを変更します。 –
私の答えが正しいと印を付けるのに役立ちます。 :P – eyllanesc