在 QML 中显示 Pandas 数据框 [英] Displaying pandas dataframe in QML
问题描述
我有 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
更改为 Property
、pyqtSlot
与 Slot
和 PyQt5
到 PySide2
.
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屋!