2017-05-23 18 views
1

考えられるのは、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を使用してください。私は思い出して試しましたが、これまで成功していませんでした。データフレームの使用に関連しているようです。すべてのアドバイスは大歓迎です。前もって感謝します。

答えて

0

次の部分では、印象の結果を示しています。並べ替えられていることがわかりますが、インデックスも並べ替えられています。これにより、変更が更新されていないときに発生します。

sort clicked col 0 order 1 
date 
     date  time string   nan     bla 
0 23-02-1978 19:03:13  eh  None even more some data 
2 23-02-1978 19:02:55  he some data even more some data 
1 23-02-1978 19:01:45  ss some data even more some data 
sort clicked col 0 order 0 
date 
     date  time string   nan     bla 
1 23-02-1978 19:01:45  ss some data even more some data 
2 23-02-1978 19:02:55  he some data even more some data 
0 23-02-1978 19:03:13  eh  None even more some data 

データを更新するには、インデックスをreset_index()でリセットする必要があります。

def sort(self, column, order): 
    """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) 
    self._df.reset_index(inplace=True, drop=True) # <-- this is the change 
    print(self._df) 
    self.layoutChanged.emit() 
+0

インデックスをリセットすると、間違った方向に見えていました。迅速な返信をありがとう、私が家に帰るとすぐにこれを変更します。 –

+0

私の答えが正しいと印を付けるのに役立ちます。 :P – eyllanesc

関連する問題