1

I designed a UI in Qt designer which consists of 1 button and 1 QTableView. The button is used to browse for excel, manipulate it as per my code and display the result in the TableView. This is my code:

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QIcon
import numpy as np
import pandas as pd
import glob
import os
import csv
from itertools import combinations
from PyQt5.QtWidgets import QDialog, QApplication


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


class Ui_Rulepriority(object):
    def setupUi(self, Rulepriority):
        Rulepriority.setObjectName("Rulepriority")
        Rulepriority.resize(820, 480)
        self.verticalLayout = QtWidgets.QVBoxLayout(Rulepriority)
        self.verticalLayout.setObjectName("verticalLayout")
        self.OpenCsv = QtWidgets.QPushButton(Rulepriority)
        self.OpenCsv.setObjectName("OpenCsv")
        self.verticalLayout.addWidget(self.OpenCsv)
        self.OpenCsv.clicked.connect(self.file_open)
        self.tableView = QtWidgets.QTableView(Rulepriority)
        self.tableView.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
        self.tableView.setObjectName("tableView")
        self.verticalLayout.addWidget(self.tableView)

        self.retranslateUi(Rulepriority)
        self.OpenCsv.clicked.connect(self.tableView.show)
        QtCore.QMetaObject.connectSlotsByName(Rulepriority)

    def retranslateUi(self, Rulepriority):
        _translate = QtCore.QCoreApplication.translate
        Rulepriority.setWindowTitle(_translate("Rulepriority", "Violation Solving Prioritization tool"))
        self.OpenCsv.setText(_translate("Rulepriority", "Browse excel and get solving probability"))
        Rulepriority.setWindowIcon(QtGui.QIcon('favicon.ico'))

    def file_open(self):
        path, _ = QtWidgets.QFileDialog.getOpenFileName(Rulepriority, 'Open csv', QtCore.QDir.rootPath(),
                                                        'Data_*.xlsx')

        df1 = pd.read_excel(path)
        df2 = df1.set_index(['Priority', 'RID to solve', 'Probability', 'RID per probability', 'Remarks']).sort_values(by=['Priority'],
                                                                                                       ascending=True)
        model = DataFrameModel(df2)
        self.tableView.setModel(model)

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Rulepriority = QtWidgets.QDialog()
    ui = Ui_Rulepriority()
    ui.setupUi(Rulepriority)
    Rulepriority.show()
    sys.exit(app.exec_())

Here def file_open(self) is used to browse the excel sheet. For displaying the pandas DataFrame in the QTableView, I am using the class DataFrameModel(QtCore.QAbstractTableModel) which I have borrowed from this answer How to display a Pandas data frame with PyQt5/PySide2

This is how my browsed data looks like:

enter image description here I want the above data to look like this:

enter image description here

and for that I am using this code:

df2 = df1.set_index(['Priority', 'RID to solve', 'Probability', 'RID per probability', 'Remarks']).sort_values(by=['Priority'],
                                                                                                       ascending=True)

but when I try to display the same result in Front-end, I get the comma seperated result like this:

enter image description here

If you guys could help me get the above displayed format, I'd greatly appreciate it.

vesuvius
  • 435
  • 4
  • 20

1 Answers1

1

Solved the issue. I figured out that the unusual indexing was causing the problem, so,

Instead of:

df2 = df1.set_index(['Priority', 'RID to solve', 'Probability', 'RID per probability', 'Remarks']).sort_values(by=['Priority'],
                                                                                                   ascending=True)

I used this:

cols = ['Priority','RID to solve']
dm = df1[cols].apply(lambda x: x.duplicated())    
df1[cols]= df1[cols].mask(m, '')

What this code did is, first replace duplicate values with missing values and then masked them on the dataframe columns to get the result like this:

enter image description here

This is the full code with above moderations:

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QIcon
import numpy as np
import pandas as pd
import glob
import os
import csv
from itertools import combinations
from PyQt5.QtWidgets import QDialog, QApplication


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


class Ui_Rulepriority(object):
    def setupUi(self, Rulepriority):
        Rulepriority.setObjectName("Rulepriority")
        Rulepriority.resize(820, 480)
        self.verticalLayout = QtWidgets.QVBoxLayout(Rulepriority)
        self.verticalLayout.setObjectName("verticalLayout")
        self.OpenCsv = QtWidgets.QPushButton(Rulepriority)
        self.OpenCsv.setObjectName("OpenCsv")
        self.verticalLayout.addWidget(self.OpenCsv)
        self.OpenCsv.clicked.connect(self.file_open)
        self.tableView = QtWidgets.QTableView(Rulepriority)
        self.tableView.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
        self.tableView.setObjectName("tableView")
        self.verticalLayout.addWidget(self.tableView)
        QtCore.QFileSystemWatcher()
        self.retranslateUi(Rulepriority)
        self.OpenCsv.clicked.connect(self.tableView.show)
        QtCore.QMetaObject.connectSlotsByName(Rulepriority)

    def retranslateUi(self, Rulepriority):
        _translate = QtCore.QCoreApplication.translate
        Rulepriority.setWindowTitle(_translate("Rulepriority", "Violation Solving Prioritization tool"))
        self.OpenCsv.setText(_translate("Rulepriority", "Browse excel and get solving probability"))
        Rulepriority.setWindowIcon(QtGui.QIcon('favicon.ico'))

    def file_open(self):
        path, _ = QtWidgets.QFileDialog.getOpenFileName(Rulepriority, 'Open csv', QtCore.QDir.rootPath(),
                                                        'Data_*.xlsx')

        df1 = pd.read_excel(path)

        cols = ['Priority', 'RID to solve']
        dm = df1[cols].apply(lambda x: x.duplicated())
        df1[cols] = df1[cols].mask(dm, '')
        model = DataFrameModel(df1)
        self.tableView.setModel(model)

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Rulepriority = QtWidgets.QDialog()
    ui = Ui_Rulepriority()
    ui.setupUi(Rulepriority)
    Rulepriority.show()
    sys.exit(app.exec_())

Cheers :)

vesuvius
  • 435
  • 4
  • 20