在 QML 中显示 Pandas 数据框 [英] Displaying pandas dataframe in QML

查看:56
本文介绍了在 QML 中显示 Pandas 数据框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有 2 个熊猫 dataframes,一个有 6 行7 列,另一个有 21 行12 列,我想使用 QML 显示它们,同时谷歌搜索我了解了 TableView

我用过:

  • Python 3.7.2
  • PyQt5 5.12.1
  • Qt 5.12.2
  • 熊猫 0.24.1

注意:如果你想在 PySide2 中使用这个例子,你只需要将 pyqtProperty 更改为 PropertypyqtSlotSlotPyQt5PySide2.

I have 2 pandas dataframes, one with 6 rows and 7 columns and another one with 21 rows and 12 columns, i would like to display them using QML, while googling i got to know about TableView TableView QML Type. In that example, the data has been entered already in ListElement and it is being shown. But in my case the data is from python pandas dataframe, how can i fetch the columns and rows from pandas straight into QML, should i create those columns well before under listelement? Any help would be appreciated

Note: I have used QtWidgets to display dataframe, it was just a drag and drop tableview and use the model created and set them using tableView.setModel(model). But i am kind of clueless here in QML

解决方案

You can create a class that inherits from QAbstractTableModel as implemented in this old answer and use the QTableView of QtQuick 2.12 that was released in Qt 5.12 since it supports the QAbstractTableModel type model, so you will have to use the latest versions of PyQt5.

main.py

from PyQt5 import QtCore, QtGui, QtQml
import numpy as np
import pandas as pd

class DataFrameModel(QtCore.QAbstractTableModel):
    DtypeRole = QtCore.Qt.UserRole + 1000
    ValueRole = QtCore.Qt.UserRole + 1001

    def __init__(self, df=pd.DataFrame(), parent=None):
        super(DataFrameModel, self).__init__(parent)
        self._dataframe = df

    def setDataFrame(self, dataframe):
        self.beginResetModel()
        self._dataframe = dataframe.copy()
        self.endResetModel()

    def dataFrame(self):
        return self._dataframe

    dataFrame = QtCore.pyqtProperty(pd.DataFrame, fget=dataFrame, fset=setDataFrame)

    @QtCore.pyqtSlot(int, QtCore.Qt.Orientation, result=str)
    def headerData(self, section: int, orientation: QtCore.Qt.Orientation, role: int = QtCore.Qt.DisplayRole):
        if role == QtCore.Qt.DisplayRole:
            if orientation == QtCore.Qt.Horizontal:
                return self._dataframe.columns[section]
            else:
                return str(self._dataframe.index[section])
        return QtCore.QVariant()

    def rowCount(self, parent=QtCore.QModelIndex()):
        if parent.isValid():
            return 0
        return len(self._dataframe.index)

    def columnCount(self, parent=QtCore.QModelIndex()):
        if parent.isValid():
            return 0
        return self._dataframe.columns.size

    def data(self, index, role=QtCore.Qt.DisplayRole):
        if not index.isValid() or not (0 <= index.row() < self.rowCount() \
            and 0 <= index.column() < self.columnCount()):
            return QtCore.QVariant()
        row = self._dataframe.index[index.row()]
        col = self._dataframe.columns[index.column()]
        dt = self._dataframe[col].dtype

        val = self._dataframe.iloc[row][col]
        if role == QtCore.Qt.DisplayRole:
            return str(val)
        elif role == DataFrameModel.ValueRole:
            return val
        if role == DataFrameModel.DtypeRole:
            return dt
        return QtCore.QVariant()

    def roleNames(self):
        roles = {
            QtCore.Qt.DisplayRole: b'display',
            DataFrameModel.DtypeRole: b'dtype',
            DataFrameModel.ValueRole: b'value'
        }
        return roles

if __name__ == "__main__":
    import os
    import sys

    app = QtGui.QGuiApplication(sys.argv)
    df = pd.DataFrame(np.random.randint(0, 100, size=(6, 7)), columns=list('ABCDEFG'))
    print(df)
    model = DataFrameModel(df)
    engine = QtQml.QQmlApplicationEngine()
    engine.rootContext().setContextProperty("table_model", model)
    qml_path = os.path.join(os.path.dirname(__file__), "main.qml")
    engine.load(QtCore.QUrl.fromLocalFile(qml_path))
    if not engine.rootObjects():
        sys.exit(-1)
    engine.quit.connect(app.quit)
    sys.exit(app.exec_())

main.qml

import QtQuick 2.12
import QtQuick.Controls 2.4
import QtQuick.Window 2.11

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")
    color: '#222222'

    TableView {
        id: tableView

        columnWidthProvider: function (column) { return 100; }
        rowHeightProvider: function (column) { return 60; }
        anchors.fill: parent
        leftMargin: rowsHeader.implicitWidth
        topMargin: columnsHeader.implicitHeight
        model: table_model
        delegate: Rectangle {
            color: parseFloat(display) > 50 ? 'green' : 'red'
            Text {
                text: display
                anchors.fill: parent
                anchors.margins: 10
                color: 'white'
                font.pixelSize: 15
                verticalAlignment: Text.AlignVCenter
            }
        }
        Rectangle { // mask the headers
            z: 3
            color: "#222222"
            y: tableView.contentY
            x: tableView.contentX
            width: tableView.leftMargin
            height: tableView.topMargin
        }

        Row {
            id: columnsHeader
            y: tableView.contentY
            z: 2
            Repeater {
                model: tableView.columns > 0 ? tableView.columns : 1
                Label {
                    width: tableView.columnWidthProvider(modelData)
                    height: 35
                    text: table_model.headerData(modelData, Qt.Horizontal)
                    color: '#aaaaaa'
                    font.pixelSize: 15
                    padding: 10
                    verticalAlignment: Text.AlignVCenter

                    background: Rectangle { color: "#333333" }
                }
            }
        }
        Column {
            id: rowsHeader
            x: tableView.contentX
            z: 2
            Repeater {
                model: tableView.rows > 0 ? tableView.rows : 1
                Label {
                    width: 40
                    height: tableView.rowHeightProvider(modelData)
                    text: table_model.headerData(modelData, Qt.Vertical)
                    color: '#aaaaaa'
                    font.pixelSize: 15
                    padding: 10
                    verticalAlignment: Text.AlignVCenter

                    background: Rectangle { color: "#333333" }
                }
            }
        }

        ScrollIndicator.horizontal: ScrollIndicator { }
        ScrollIndicator.vertical: ScrollIndicator { }
    }
}

I have used:

  • Python 3.7.2
  • PyQt5 5.12.1
  • Qt 5.12.2
  • pandas 0.24.1

Note: If you want to use the example with PySide2 you only have to change pyqtProperty with Property, pyqtSlot with Slot and PyQt5 to PySide2.

这篇关于在 QML 中显示 Pandas 数据框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆