'What is the correct way to update data/rows in a QAbstractTableModel backed by a DataFrame?

I have the following class derived from QAbstractTableModel

import pandas as pd
from typing import List, Any
from PyQt5 import QtCore, QtWidgets

class DataModel(QtCore.QAbstractTableModel):
  data_updated = QtCore.pyqtSignal()

  def __init__(self, data: pd.DataFrame = pd.DataFrame()):
    super(DataModel, self).__init__()
    self._data = data

  def update_data(self, data: pd.DataFrame):
    self.beginInsertRows(QtCore.QModelIndex(), 0, self.rowCount())
    self._data = data
    self.endInsertRows()
    self.data_updated.emit()

  def data(self, index, role):
    if role == QtCore.Qt.DisplayRole:
      return str(self._data.iloc[index.row()][index.column()])

  def rowCount(self, index = None) -> int:
    return self._data.shape[0]
  
  def columnCount(self, index = None) -> int:
    return self._data.shape[1]

  def headerData(self, section: int, orientation: QtCore.Qt.Orientation, role: int ) -> Any:
    # section is the index of the column/row.
    if role == QtCore.Qt.DisplayRole:
      if orientation == QtCore.Qt.Horizontal:
        return str(self._data.columns[section])
      if orientation == QtCore.Qt.Vertical:
        return str(self._data.index[section])

The issue I have is that when I update the data in the DataModel using update_data, I'm passing in a full dataframe and replacing the existing dataframe. This is probably not the right way to do it since I see examples online of modifying rows one by one. The current method seems to cause a segfault over time e.g. after multiple data updates. I also occasionally get these types of errors:

QAbstractItemModel::endInsertRows:  Invalid index ( 36 , 0 ) in model QSortFilterProxyModel(0x55b4e0d007f0)

This model is used in the following way:

class DataView(QtWidgets.QWidget):
  def __init__(self):
    super(DataView, self).__init__()

    self.model = DataModel()

    self.view = QtWidgets.QTableView(self)
    self.view.setAlternatingRowColors(True)
    self.view.setStyleSheet('alternate-background-color: grey;background-color: white;')

    self.proxy = QtCore.QSortFilterProxyModel(self)
    self.proxy.setSourceModel(self.model)

    self.view.setModel(self.proxy)

Is the right way to do this to diff the old dataframe and the new dataframe and individually update those rows in DataModel? Is there a better way of doing this? I would prefer to keep the dataframe as the backing datastructure if possible.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source