Fastest way to populate QTableView from Pandas data frame

后端 未结 7 1207
面向向阳花
面向向阳花 2020-11-27 16:54

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

My code is the following:

def data_frame_to_ui(self, data_frame):
                


        
相关标签:
7条回答
  • 2020-11-27 17:11

    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.

    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
    
    0 讨论(0)
  • 2020-11-27 17:14

    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 here to avoid QVariant() from PyQT 4.6 on.

    0 讨论(0)
  • 2020-11-27 17:18

    Simple and faster way to write a dataframe to 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])))
    
    0 讨论(0)
  • 2020-11-27 17:20

    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_())
    
    0 讨论(0)
  • 2020-11-27 17:20

    There is actually some code in pandas supporting integration with Qt.

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

    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.

    Luckily they extracted that into a separated project in GitHub called 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.

    0 讨论(0)
  • 2020-11-27 17:31

    Here is fully working copy-paste example for PyQT5 based on @Frederick Li answer with minor modifications.

    from PyQt5 import QtGui, QtWidgets
    from PyQt5.QtCore import Qt
    import sys
    import pandas as pd
    
    class MainWindow(QtWidgets.QMainWindow):
        def __init__(self, *args, obj=None, **kwargs):
            super(MainWindow, self).__init__(*args, **kwargs)
    
            self.centralwidget = QtWidgets.QWidget(self)
            sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed)
            self.centralwidget.setSizePolicy(sizePolicy)
    
            self.pdtable = QtWidgets.QTableView(self.centralwidget)
            sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed)
            self.pdtable.setSizePolicy(sizePolicy)
    
            dataPD = [['tom', 10.0, 180.3], ['nick', 15.0, 175.7], ['juli', 14.0, 160.6]]
            df = pd.DataFrame(dataPD, columns=['Name', 'Age', 'Height'])
            print(df.dtypes)
            self.model = PandasTableModel(df)
            self.pdtable.setModel(self.model)
    
            self.setCentralWidget(self.centralwidget)
    
    
    class PandasTableModel(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("{}".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 == Qt.Horizontal and role == Qt.DisplayRole:
                return self._data.columns[x]
            if orientation == Qt.Vertical and role == Qt.DisplayRole:
                return self._data.index[x]
            return None
    
    
    if __name__ == "__main__":
        app  = QtWidgets.QApplication(sys.argv)
        app.setStyle("Fusion")
        main = MainWindow()
        main.show()
        main.resize(600, 400)
        sys.exit(app.exec_())
    
    0 讨论(0)
提交回复
热议问题