Can anyone explain the following: I have 2 scripts for loading a pandas dataframe in a tableview which has a filter field. The one with the standard model loads the data in the "init" section. With this one everyting is blazing fast , also the filtering. The second script works much slower but with this one i can set the background color of the cells which i need. These are the scripts:
import timeit
import pandas as pd
from PyQt5 import QtGui
from PyQt5 import QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtCore import QAbstractTableModel
from PyQt5.QtCore import Qt, QSortFilterProxyModel
from PyQt5.QtGui import *
from PyQt5.uic import loadUi
class PandasTableModel(QtGui.QStandardItemModel):
def __init__(self, data, parent=None):
QtGui.QStandardItemModel.__init__(self, parent)
self._data = data
for col in data.columns:
data_col = [QtGui.QStandardItem("{}".format(x)) for x in data[col].values]
self.appendColumn(data_col)
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]
def flags(self, index):
if not index.isValid():
return Qt.ItemIsEnabled
return super().flags(index) | Qt.ItemIsEditable # add editable flag.
def setData(self, index, value, role):
if role == Qt.EditRole:
# Set the value into the frame.
self._data.iloc[index.row(), index.column()] = value
return True
return False
class TableViewer(QtWidgets.QMainWindow):
def __init__(self):
super(TableViewer, self).__init__()
self.ui = loadUi("QTableViewForm.ui", self)
self.ui.cmdRun1.clicked.connect(self.RunFunction1)
self.ui.cmdRun2.clicked.connect(self.RunFunction2)
self.ui.inputFilter.textChanged.connect(self.SetFilteredView)
self.showdata()
def showdata(self):
start = timeit.default_timer()
print("Start LoadData")
data = pd.read_pickle("productdata.pkl")
self.model = PandasTableModel(data)
self.ui.tableData.setModel(self.model)
self.proxy_model = QSortFilterProxyModel()
self.proxy_model.setFilterKeyColumn(-1) # Search all columns.
self.proxy_model.setSourceModel(self.model)
self.proxy_model.sort(0, Qt.AscendingOrder)
self.proxy_model.setFilterCaseSensitivity(False)
self.ui.tableData.setModel(self.proxy_model)
print("Stop LoadData")
end = timeit.default_timer()
print("Process Time: ", (end - start))
def set_cell_color(self, row, column):
self.model.change_color(row, column, QBrush(Qt.red))
def RunFunction1(self):
start = timeit.default_timer()
print("Start RunFunction1")
#Gans de rij in 't rood
colums = self.proxy_model.columnCount()
for c in range(colums):
self.set_cell_color(3, c)
print("Stop RunFunction1")
end = timeit.default_timer()
print("Process Time: ", (end - start))
def RunFunction2(self):
start = timeit.default_timer()
print("Start RunFunction1")
#Gans de rij in 't rood
colums = self.proxy_model.columnCount()
for c in range(colums):
self.set_cell_color(3, c)
print("Stop RunFunction1")
end = timeit.default_timer()
print("Process Time: ", (end - start))
def SetFilteredView(self):
# print("Start set_filter")
filter_text = self.ui.inputFilter.text()
self.proxy_model.setFilterFixedString(filter_text)
filter_result = self.proxy_model.rowCount()
self.ui.lblResult.setText("(" str(filter_result) " records)")
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
win = TableViewer()
win.show()
sys.exit(app.exec_())enter code here
And the slow one:
import timeit
import pandas as pd
from PyQt5 import QtGui
from PyQt5 import QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtCore import QAbstractTableModel
from PyQt5.QtCore import Qt, QSortFilterProxyModel
from PyQt5.QtGui import *
from PyQt5.uic import loadUi
class PandasTableModel(QAbstractTableModel):
def __init__(self, data, parent=None):
QAbstractItemModel.__init__(self, parent)
self._data = data
self.colors = dict()
def rowCount(self, parent=None):
return self._data.index.size
def columnCount(self, parent=None):
return self._data.columns.size
def setData(self, index, value, role):
if role == Qt.EditRole:
# Set the value into the frame.
self._data.iloc[index.row(), index.column()] = value
return True
def data(self, index, role=Qt.DisplayRole):
if index.isValid():
if role == Qt.DisplayRole:
return str(self._data.iloc[index.row(), index.column()])
if role == Qt.EditRole:
return str(self._data.iloc[index.row(), index.column()])
if role == Qt.BackgroundRole:
color = self.colors.get((index.row(), index.column()))
if color is not None:
return color
return None
def headerData(self, rowcol, orientation, role):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self._data.columns[rowcol]
if orientation == Qt.Vertical and role == Qt.DisplayRole:
return self._data.index[rowcol]
return None
def change_color(self, row, column, color):
ix = self.index(row, column)
self.colors[(row, column)] = color
self.dataChanged.emit(ix, ix, (Qt.BackgroundRole,))
class TableViewer(QtWidgets.QMainWindow):
def __init__(self):
super(TableViewer, self).__init__()
self.ui = loadUi("QTableViewForm.ui", self)
self.ui.cmdRun1.clicked.connect(self.RunFunction1)
self.ui.cmdRun2.clicked.connect(self.RunFunction2)
self.ui.inputFilter.textChanged.connect(self.SetFilteredView)
self.showdata()
def showdata(self):
start = timeit.default_timer()
print("Start LoadData")
data = pd.read_pickle("productdata.pkl")
self.model = PandasTableModel(data)
self.ui.tableData.setModel(self.model)
self.proxy_model = QSortFilterProxyModel()
self.proxy_model.setFilterKeyColumn(-1) # Search all columns.
self.proxy_model.setSourceModel(self.model)
self.proxy_model.sort(0, Qt.AscendingOrder)
self.proxy_model.setFilterCaseSensitivity(False)
self.ui.tableData.setModel(self.proxy_model)
print("Stop LoadData")
end = timeit.default_timer()
print("Process Time: ", (end - start))
def set_cell_color(self, row, column):
self.model.change_color(row, column, QBrush(Qt.red))
def RunFunction1(self):
start = timeit.default_timer()
print("Start RunFunction1")
#Gans de rij in 't rood
colums = self.proxy_model.columnCount()
for c in range(colums):
self.set_cell_color(3, c)
print("Stop RunFunction1")
end = timeit.default_timer()
print("Process Time: ", (end - start))
def RunFunction2(self):
start = timeit.default_timer()
print("Start RunFunction1")
#Gans de rij in 't rood
colums = self.proxy_model.columnCount()
for c in range(colums):
self.set_cell_color(3, c)
print("Stop RunFunction1")
end = timeit.default_timer()
print("Process Time: ", (end - start))
def SetFilteredView(self):
# print("Start set_filter")
filter_text = self.ui.inputFilter.text()
self.proxy_model.setFilterFixedString(filter_text)
filter_result = self.proxy_model.rowCount()
self.ui.lblResult.setText("(" str(filter_result) " records)")
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
win = TableViewer()
win.show()
sys.exit(app.exec_())
(i'm loading 2000 rows and 35 columns)
Can i have a fast one with the background color function in it ?
Cheers , Johnson
CodePudding user response:
Instead of
def set_cell_color(self, row, column):
self.model.change_color(row, column, QBrush(Qt.red))
use this
def set_cell_color(self, row, column):
self.model.item(row, column).setBackground(QBrush(Qt.red))
Depending on your requirements, you may need to replace model
for proxy_model
, but it depends on whether row and column should refer to coordinates of the filtered or the underlying model. So it is up to you.