Change the way PandasModel operates

This commit is contained in:
Andreas Tsouchlos 2024-01-04 18:36:13 +01:00
parent 29aaa9066f
commit 393f654a57
2 changed files with 30 additions and 9 deletions

View File

@ -52,15 +52,17 @@ class MainWindow(QMainWindow):
self._list_widget.itemSelectionChanged.connect( self._list_widget.itemSelectionChanged.connect(
self._handle_list_selection_changed) self._handle_list_selection_changed)
self._pandas_model = PandasModel(self)
self._proxyModel = QSortFilterProxyModel(self) self._proxyModel = QSortFilterProxyModel(self)
self._proxyModel.setSourceModel(self._pandas_model)
self._table_view.setModel(self._proxyModel) self._table_view.setModel(self._proxyModel)
self._proxyModel.setDynamicSortFilter(False)
def set_statement_data(self, df: pd.DataFrame): def set_statement_data(self, df: pd.DataFrame):
if 'category' not in df.columns: if 'category' not in df.columns:
df['category'] = [' '] * len(df.index) df['category'] = [' '] * len(df.index)
model = PandasModel(df) self._pandas_model.set_dataframe(df)
self._proxyModel.setSourceModel(model)
if len(df.columns) < 10: # Experimentally determined threshold if len(df.columns) < 10: # Experimentally determined threshold
# Properly resize columns (takes longer) # Properly resize columns (takes longer)

View File

@ -3,20 +3,31 @@ from PyQt6 import QtCore
from PyQt6.QtCore import Qt from PyQt6.QtCore import Qt
def _get_str_dataframe(df: pd.DataFrame) -> pd.DataFrame:
"""Return a given dataframe with all values turned into strings.
When the data given to the PandasModel class contains non-strings,
an attached QTableView seems to respond rather slowly. This function
turns all data in the DataFrame into strings, yielding a better experience.
"""
return df.astype(str)
class PandasModel(QtCore.QAbstractTableModel): class PandasModel(QtCore.QAbstractTableModel):
def __init__(self, df: pd.DataFrame, parent=None): def __init__(self, parent=None):
QtCore.QAbstractTableModel.__init__(self, parent) QtCore.QAbstractTableModel.__init__(self, parent)
self._data = df self._data = pd.DataFrame()
self._horizontalHeaders = list(df.columns) self._data_str = pd.DataFrame()
self._horizontalHeaders = None
# Overloaded functions # Overloaded functions
def rowCount(self, parent=None): def rowCount(self, parent=None):
return len(self._data.values) return len(self._data_str.values)
def columnCount(self, parent=None): def columnCount(self, parent=None):
return self._data.columns.size return self._data_str.columns.size
def data(self, index, role=Qt.ItemDataRole.DisplayRole): def data(self, index, role=Qt.ItemDataRole.DisplayRole):
if not index.isValid(): if not index.isValid():
@ -24,7 +35,7 @@ class PandasModel(QtCore.QAbstractTableModel):
if role != Qt.ItemDataRole.DisplayRole: if role != Qt.ItemDataRole.DisplayRole:
return QtCore.QVariant() return QtCore.QVariant()
item = self._data.iloc[index.row(), index.column()] item = self._data_str.iloc[index.row(), index.column()]
return QtCore.QVariant(str(item)) return QtCore.QVariant(str(item))
def headerData(self, section, orientation, def headerData(self, section, orientation,
@ -38,5 +49,13 @@ class PandasModel(QtCore.QAbstractTableModel):
# Other functions # Other functions
def get_dataframe(self): def set_dataframe(self, df):
self._data = df
self._data_str = _get_str_dataframe(df)
self._horizontalHeaders = list(df.columns)
self.layoutAboutToBeChanged.emit()
self.layoutChanged.emit()
def get_dataframe(self) -> pd.DataFrame:
return self._data return self._data