2015-07-17 9 views
8

Ich bin sehr neu zu PyQt und ich habe Schwierigkeiten, ein QTableView-Steuerelement zu bevölkern.Schnellste Möglichkeit, QTableView von Pandas Datenrahmen zu bevölkern

Mein Code ist folgende:

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) 

Eigentlich in dem Code, den ich erfolgreich eine QListView zu füllen, aber die Werte, die ich auf die QTableView gesetzt werden nicht angezeigt, können Sie sehen auch, dass ich die Zeilen abgeschnitten 10 weil es ewig dauert, die Hunderte von Zeilen des Datenrahmens anzuzeigen.

Also, was ist der schnellste Weg, um das Tabellenmodell aus einem Pandas Datenrahmen zu füllen?

Vielen Dank im Voraus.

+0

Haben Sie die von Wolph gegebene Lösung getestet, um zu sehen, ob sie bessere Leistung bringt? – ekhumoro

+0

Noch nicht, auch ich verstehe es nicht ganz, also brauche ich etwas Zeit. –

+0

Ich habe ein wenig getestet. Bei einer Tabelle mit 25 Spalten und 10000 Zeilen ist das benutzerdefinierte Modell ungefähr 40-mal schneller (und die Leistungsdifferenz wächst geometrisch, wenn die Anzahl der Zeilen/Spalten erhöht wird). Dies war eine einfache Liste von Listen für die Daten, so scheint es, dass die Schaffung aller Instanzen von "QStandardItem" der größte Engpass ist. – ekhumoro

Antwort

12

Persönlich würde ich nur meine eigene Modellklasse erstellen, um die Handhabung etwas einfacher zu machen.

Zum Beispiel:

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_()) 
+1

Hallo, ich bekomme den folgenden Fehler: 'return QtCore.QVariant() TypeError: PyQt4.QtCore.QVariant stellt einen zugeordneten Typ und kann nicht instanziiert werden ' –

11

Dies funktioniert:

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 

es wie folgt aus:

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

ich here lesen zu vermeiden QVariant() von PyQT 4.6 auf.

+2

Alte Antwort, aber immer noch eine gute. Wenn der Index Ihres Datenframes in der Zeile erscheinen soll, können Sie die Methode headerData wie folgt ändern: 'def headerData (self, rowcol, Ausrichtung, Rolle): wenn orientation == QtCore.Qt.Horizontal und role = = QtCore.Qt.DisplayRole: return self._data.columns [ROWCOL] wenn Ausrichtung == QtCore.Qt.Vertical und Rolle == QtCore.Qt.DisplayRole: return self._data.index [ROWCOL] return None ' – Wli

+0

Das funktioniert, aber wie kann ich das Modell editierbar machen und es dann wieder auf einen Datenrahmen verschieben? Derzeit kann es nicht einmal bearbeitet werden. – Nickpick

+0

https://github.com/SanPen/GridCal/blob/master/UnderDevelopment/GridCal/gui/GuiFunctions.py. Dies ist ein Open-Source-Projekt, in dem ich dieses Modell entwickelt habe. –

3

Es gibt tatsächlich einen Code in pandas Unterstützung der Integration mit Qt.

Zum Zeitpunkt der Antwort des Schreibens, die neueste Pandas Version ist 0.18.1 und Sie tun können:

from pandas.sandbox.qtpandas import DataFrameModel, DataFrameWidget 

Dieser Code scheint pyside gekoppelt zu sein, es sollte jedoch relativ trivial sein, um es mit funktioniert PyQt. Außerdem ist dieser Code veraltet, und die Warnung besagt, dass das Modul in Zukunft entfernt wird.

Glücklicherweise extrahiert sie, dass in einem separaten Projekt in GitHub pandas-qt genannt:

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

Ich würde versuchen, das zu verwenden, bevor Sie versuchen, mein eigenes Modell und Ansicht Implementierung, Roll-out.

+0

Hallo ich möchte nur hinzufügen, pandas-qt unterstützt nicht python3 und es scheint so wahrscheinlich Gewohnheit. In der Zwischenzeit können Sie [qtpandas] (https://github.com/draperjames/qtpandas) 'pip install qtpandas' verwenden –

1

Ich habe alle vorgeschlagenen Antworten schmerzhaft langsam für DataFrames mit 1000+ Zeilen gefunden. Was für mich blitzschnell funktioniert:

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 
Verwandte Themen