【问题标题】:Displaying pandas dataframe in QML在 QML 中显示 pandas 数据框
【发布时间】:2019-08-14 01:21:08
【问题描述】:

我有 2 个熊猫 dataframes,一个带有 6 rows7 columns,另一个带有 21 rows12 columns,我想使用 QML 显示它们,同时谷歌搜索我了解了 TableView @ 987654321@。在该示例中,数据已经输入到ListElement,并且正在显示。但在我的情况下,数据来自 python pandas 数据框,我如何将 pandas 中的列和行直接提取到 QML 中,我应该在listelement 下创建这些列吗?任何帮助将不胜感激

注意:我使用QtWidgets 来显示数据框,它只是一个拖放表格视图,并使用创建的模型并使用tableView.setModel(model) 设置它们。但我在 QML 中有点无能为力

【问题讨论】:

  • 我正在使用 pyqt5

标签: python pandas pyqt qml pyqt5


【解决方案1】:

您可以创建一个继承自QAbstractTableModel 的类,如在this old answer 中实现的那样,并使用Qt 5.12 中发布的QtQuick 2.12 的QTableView,因为它支持QAbstractTableModel 类型模型,因此您必须使用最新版本的 PyQt5。

ma​​in.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_())

ma​​in.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 { }
    }
}

我用过:

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

注意:如果您想在 PySide2 中使用该示例,您只需将 pyqtProperty 更改为 Property,将 pyqtSlot 更改为 SlotPyQt5 更改为 PySide2

【讨论】:

  • @Techiesoft 在 Qt Quick 2.12 的 TableView 中,它们没有带有标题,但使用 Column、Row 和 Repeaters 很容易实现它们,就像我在回答中所做的那样
  • 左边的索引是什么......它来自熊猫数据框吗?
  • 如果我想根据数字改变单元格颜色,我应该写任何js函数吗?
  • 排序后的数据框未按预期显示,在问题中添加了图像,请检查
  • 事实并非如此,我想要的是将我得到的 pandas 数据框原样显示为输出。我希望你能理解
猜你喜欢
  • 2015-09-12
  • 1970-01-01
  • 1970-01-01
  • 2019-07-08
  • 1970-01-01
  • 2016-04-29
  • 2016-12-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多