I want to display dataframe in Pyqt5. However, I get an error like 'Process finished with exit code -1073740791 (0xC0000409)'
Open csv file with pandas
csv_path = os.path.expanduser("~/Desktop/dataset/traffic-crashes-vehicles-1.csv")
datac = pd.read_csv(csv_path)
class pandasModel(QAbstractTableModel):
def __init__(self,data):
QAbstractTableModel.__init__(self)
self._data = data
def rowCount(self,parent=None):
return self._data.shape[0]
def columnCount(self,parent=None):
return self._data.shape[1]
def data(self, index, role=Qt.DisplayRole):
if index.isValid():
if role == Qt.DisplayRole:
return str(self._data.iloc[index.row(),index.column()])
return None
the function causing the problem header Data function. Parameters
after self show in yellow. PyCharm. Something seems missing or
unidentifiable.
def headerData(self,orientation, role,col):
if orientation == Qt.Horizantal and role == Qt.DisplayRole:
return self._data.columns[col]
return None
if __name__ == '__main__':
app = QApplication(sys.argv)
model = pandasModel(datac)
view = QTableView()
view.setModel(model)
view.resize(800,600)
view.show()
sys.exit(app.exec())
I replaced col with seciton. I printed this section and it worked as much as my column count and printed a numerical value. I understood that section is counting columns. To get the columns from dataframe, I wrote a for loop and added the section. And now my column names appear.
def headerData(self, section, orientation, role=Qt.DisplayRole):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return datac.columns[section]
return QAbstractTableModel.headerData(self, section, orientation, role)
Related
i am using PandasModel(QAbstractTableModel) to show data in a qtableView. it's working fine with less data. but whenever i tried with large datas it became slow. for 5000 rows data it almost took 20-25 seconds .it just take a seconds in mssql mgmt studio to run the query. i am not getting where i did wrong with my codes.
class PandasModel(QtCore.QAbstractTableModel):
def __init__(self, df = pd.DataFrame(), parent=None):
QtCore.QAbstractTableModel.__init__(self, parent=parent)
self._df = df
def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
if role != QtCore.Qt.DisplayRole:
return QtCore.QVariant()
if orientation == QtCore.Qt.Horizontal:
try:
return self._df.columns.tolist()[section]
except (IndexError, ):
return QtCore.QVariant()
elif orientation == QtCore.Qt.Vertical:
try:
return self._df.index.tolist()[section]+1
except (IndexError, ):
return QtCore.QVariant()
def data(self, index, role=QtCore.Qt.DisplayRole):
if role != QtCore.Qt.DisplayRole:
return QtCore.QVariant()
if not index.isValid():
return QtCore.QVariant()
return QtCore.QVariant(str(self._df.iloc[index.row(), index.column()]))
def setData(self, index, value, role):
if not index.isValid():
return False
if role != QtCore.Qt.EditRole:
return False
row = index.row()
if row < 0 or row >= len(self._data.values):
return False
column = index.column()
if column < 0 or column >= self._data.columns.size:
return False
self._data.values[row][column] = value
self.dataChanged.emit(index, index)
return True
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self._df.index)
def columnCount(self, parent=QtCore.QModelIndex()):
return len(self._df.columns)
def sort(self, column, order):
colname = self._df.columns.tolist()[column]
self.layoutAboutToBeChanged.emit()
self._df.sort_values(colname, ascending= order == QtCore.Qt.AscendingOrder, inplace=True)
self._df.reset_index(inplace=True, drop=True)
self.layoutChanged.emit()
i tried many approaches like st the chunksize , but not working. please help me out
sql_conn = pyodbc.connect('DRIVER={ODBC Driver 17 for SQL Server};SERVER=' +
server+';DATABASE='+database+';UID='+username+';PWD=' + password)
cursor = sql_conn.cursor()
def loadTranForACC(AccountID):
query_string="Select * from user.dbo.Transaction(nolock) where accID =" + AccountID
data=pd.read_sql_query(query_string, sql_conn)
return data
Since you are working with the data from Database, I'd like to point out that PyQt has
QSqlTableModel and QSqlQueryModel to work with the data from database.
Looking at your model, to me, the model looks fine, try to see exactly what part of your program is eating up time.
You can look at these threads for more information and details regarding these:
qtablewidget becomes slow for large tables
pyqt qtablewidget extremely slow
The ultimate solution though would be to use pagination, show only 500,1000 rows at a time, it will run within a fraction of seconds.
You can visit these threads to implement pagination: QT Forum | Pagination in QTableWidget or Paginated Display of Table Data in PyQt
Is it possible to conditionally change the background color of items in a QTableView, using PySide2?
I've read a lot on the model view framework . I cannot figure out if it is necessary to use a Delegate or not. Recently I was able to get a column of checkboxes without a Delegate. I believe that the virtual methods setItemData(index, roles) and itemData(index) could be what I need. However, there is no QMap in PySide2. My model must need somewhere to store the extra information to be used by QtCore.Qt.BackgroundRole (that enum, btw, says "the background brush used for items rendered with the default delegate") If I don't specify a delegate, is the "default delegate" used?. Should I be using QStandardItemModel instead?
In the example code below, how would I get a particular column's background color to be red based on some thresholds (the min and max column are the thresholds?
from PySide2.QtWidgets import (QWidget, QApplication, QTableView,QVBoxLayout)
import sys
from PandasModel2 import PandasModel2
import numpy as np
import pandas as pd
class Example(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(300, 300, 700, 300)
self.setWindowTitle("QTableView")
self.initData()
self.initUI()
def initData(self):
data = pd.DataFrame(np.random.randint(1,10,size=(6,4)), columns=['Test#','MIN', 'MAX','MEASURED'])
data['Test#'] = [1,2,3,4,5,6]
#add the checkable column to the DataFrame
data['Check'] = True
self.model = PandasModel2(data)
def initUI(self):
self.tv = QTableView(self)
self.tv.setModel(self.model)
vbox = QVBoxLayout()
vbox.addWidget(self.tv)
self.setLayout(vbox)
app = QApplication([])
ex = Example()
ex.show()
sys.exit(app.exec_())
And I have a custom model using a pandas dataFrame:
import PySide2.QtCore as QtCore
class PandasModel2(QtCore.QAbstractTableModel):
"""
Class to populate a table view with a pandas dataframe.
This model is non-hierachical.
"""
def __init__(self, data, parent=None):
QtCore.QAbstractTableModel.__init__(self, parent)
self._data = data
def rowCount(self, parent=None):
return self._data.shape[0]
def columnCount(self, parent=None):
return self._data.shape[1]
def data(self, index, role=QtCore.Qt.DisplayRole):
if role==QtCore.Qt.DisplayRole:
if index.column() != 4:
#don't want what determines check state to be shown as a string
if index.isValid():
if index.column() in [1,2,3]:
return '{:.3f}'.format(self._data.iloc[index.row(), index.column()])
if index.column() == 0:
return '{:.2f}'.format(self._data.iloc[index.row(), index.column()])
return str(self._data.iloc[index.row(), index.column()])
if role==QtCore.Qt.CheckStateRole:
if index.column()==4:#had to add this check to get the check boxes only in column 10
if self._data.iloc[index.row(), index.column()] == True:
return QtCore.Qt.Checked
else:
return QtCore.Qt.Unchecked
def getMinimum(self, row):
return self._data.iloc[row, self.getColumnNumber('MIN')]
def getMaximum(self, row):
return self._data.iloc[row, self.getColumnNumber('MAX')]
def getColumnNumber(self, string):
'''
Given a string that identifies a label/column,
return the location of that label/column.
This enables the config file columns to be moved around.
'''
return self._data.columns.get_loc(string)
def headerData(self, col, orientation, role):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
return self._data.columns[col]
return None
def flags(self, index):
'''
The returned enums indicate which columns are editable, selectable,
checkable, etc.
The index is a QModelIndex.
'''
if index.column() == self.getColumnNumber('Check'):
#print(index.column())
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsUserCheckable
else:
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable
return QtCore.Qt.ItemIsEnabled
def setData(self, index, value, role=QtCore.Qt.DisplayRole):
"""Set the value to the index position depending on Qt::ItemDataRole and data type of the column
Args:
index (QtCore.QModelIndex): Index to define column and row.
value (object): new value.
role (Qt::ItemDataRole): Use this role to specify what you want to do.
Raises:
TypeError: If the value could not be converted to a known datatype.
Returns:
True if value is changed. Calls layoutChanged after update.
False if value is not different from original value.
"""
if not index.isValid():
return False
if role == QtCore.Qt.DisplayRole: #why not edit role?
self._data.iat[index.row(),index.column()]= value
self.layoutChanged.emit()
return True
elif role == (QtCore.Qt.CheckStateRole | QtCore.Qt.DisplayRole):
#this block does get executed when toggling the check boxes,
#verified with debugger. Although the action is the same
#as the block above!
self._data.iat[index.row(),index.column()]= value
self.layoutChanged.emit()
return True
else:
return False
The delegate by default uses the BackgroundRole information if it is available so the solution is just to return a QColor, QBrush or similar.
from PySide2 import QtCore, QtGui
class PandasModel2(QtCore.QAbstractTableModel):
# ...
def data(self, index, role=QtCore.Qt.DisplayRole):
if not index.isValid():
return
if not (0 <= index.row() < self.rowCount() and 0 <= index.column() <= self.columnCount()):
return
value = self._data.iloc[index.row(), index.column()]
if role == QtCore.Qt.DisplayRole:
if index.column() != 4:
if index.column() in [1,2,3]:
return '{:.3f}'.format(value)
if index.column() == 0:
return '{:.2f}'.format(value)
return str(value)
elif role == QtCore.Qt.CheckStateRole:
if index.column() == 4:
return QtCore.Qt.Checked if value else QtCore.Qt.Unchecked
elif index.column() == self.getColumnNumber('MEASURED'):
if role == QtCore.Qt.BackgroundRole:
if self.getMinimum(index.row()) <= value <= self.getMaximum(index.row()):
return QtGui.QColor("red")
So, Im currently taking just limited data from a ZeroMQ Messaging system appending it all to a Dataframe and then turning the Dataframe into a pandas model with code I acquired from someone on stack. Then running that model through a PyQt5 Tableview.
Every time I run the tableview code, after converting my Dataframe to a model for Tableview the kernal just dies. I tried to at least handle a exception but it wont even raise a runtimeerror that is super general. It just dies every time....
For the purpose of the test im using a CSV with data to try to get this into a workable model. You can use any csv or data you have on your end to test this as theres no hard coded formatting.
from PyQt5 import QtCore, QtGui, QtWidgets
import pandas as pd
class PandasModel(QtCore.QAbstractTableModel):
def __init__(self, df = pd.DataFrame(), parent=None):
QtCore.QAbstractTableModel.__init__(self, parent=parent)
self._df = df
def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
if role != QtCore.Qt.DisplayRole:
return QtCore.QVariant()
if orientation == QtCore.Qt.Horizontal:
try:
return self._df.columns.tolist()[section]
except (IndexError, ):
return QtCore.QVariant()
elif orientation == QtCore.Qt.Vertical:
try:
# return self.df.index.tolist()
return self._df.index.tolist()[section]
except (IndexError, ):
return QtCore.QVariant()
def data(self, index, role=QtCore.Qt.DisplayRole):
if role != QtCore.Qt.DisplayRole:
return QtCore.QVariant()
if not index.isValid():
return QtCore.QVariant()
return QtCore.QVariant(str(self._df.ix[index.row(), index.column()]))
def setData(self, index, value, role):
row = self._df.index[index.row()]
col = self._df.columns[index.column()]
if hasattr(value, 'toPyObject'):
# PyQt4 gets a QVariant
value = value.toPyObject()
else:
# PySide gets an unicode
dtype = self._df[col].dtype
if dtype != object:
value = None if value == '' else dtype.type(value)
self._df.set_value(row, col, value)
return True
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self._df.index)
def columnCount(self, parent=QtCore.QModelIndex()):
return len(self._df.columns)
def sort(self, column, order):
colname = self._df.columns.tolist()[column]
self.layoutAboutToBeChanged.emit()
self._df.sort_values(colname, ascending= order == QtCore.Qt.AscendingOrder, inplace=True)
self._df.reset_index(inplace=True, drop=True)
self.layoutChanged.emit()
def createview(title, model):
try:
view = QtWidgets.QTableView()
view.setWindowview
except:
raise RuntimeError("I know python!")
if __name__=="__main__":
df=pd.read_csv("C:\Excel Sheets\Test_CSV_6-18-18.csv")
model = PandasModel(df)
createview("Model", model)
----How The Problem Looks Like----
after I clicked on the Record button, it becomes this
As you can see, the table just shifted to the left, hiding the vertical headers.
----Related Codes----
My tableivew is called tableViewTransaction, it uses a model to link to data in pandas' dataframe format. Here is how I connected them together inside the __init__ function of a QMainWindow.
self.data = pd.read_csv('transactions.txt', sep='\t', header=None)
self.data.columns = ["Name", "Price", "Action"]
self.model = PandasModel(self.data)
self.tableViewTransaction.setModel(self.model)
Here is my Model for the TableView
class PandasModel(QtCore.QAbstractTableModel):
def __init__(self, df = pd.DataFrame(), parent=None):
QtCore.QAbstractTableModel.__init__(self, parent=parent)
self._df = df
def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
if role != QtCore.Qt.DisplayRole:
return QtCore.QVariant()
if orientation == QtCore.Qt.Horizontal:
try:
return self._df.columns.tolist()[section]
except (IndexError, ):
return QtCore.QVariant()
elif orientation == QtCore.Qt.Vertical:
try:
# return self.df.index.tolist()
return self._df.index.tolist()[section]
except (IndexError, ):
return QtCore.QVariant()
def data(self, index, role=QtCore.Qt.DisplayRole):
if role != QtCore.Qt.DisplayRole:
return QtCore.QVariant()
if not index.isValid():
return QtCore.QVariant()
return QtCore.QVariant(str(self._df.ix[index.row(), index.column()]))
def setData(self, index, value, role):
row = self._df.index[index.row()]
col = self._df.columns[index.column()]
if hasattr(value, 'toPyObject'):
# PyQt4 gets a QVariant
value = value.toPyObject()
else:
# PySide gets an unicode
dtype = self._df[col].dtype
if dtype != object:
value = None if value == '' else dtype.type(value)
self._df.set_value(row, col, value)
return True
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self._df.index)
def columnCount(self, parent=QtCore.QModelIndex()):
return len(self._df.columns)
def sort(self, column, order):
colname = self._df.columns.tolist()[column]
self.layoutChanged.emit()
self._df.sort_values(colname, ascending= order == QtCore.Qt.AscendingOrder, inplace=True)
self._df.reset_index(inplace=True, drop=True)
self.layoutChanged.emit()
When the Record button is pressed, the following function is called:
def recordTransaction(self):
name = self.comboBoxStock.currentText()
price = self.lineEditMoney.text()
action = self.comboBoxAction.currentText()
self.data.loc[len(self.data.index)] = [name, price, action]
self.tableViewTransaction.model().layoutChanged.emit()
I know that name, price, action here is storing the correct information i.e. "stock1", "2", "Buy" in my above example.
----Full Code----
https://drive.google.com/file/d/1rU66yLqlQu0bTdINkSWxJe2E_OdMtS0i/view?usp=sharing
How to use:
first unzip it, then use python3 to run StockSim.py.
On a mac, just run python3 StockSim.py when you have went to the Stock Sim directory using terminal. Make sure you have python3 and pyqt5 installed first.
----------------------
All I want is that the TableView not shift to the left, any of your help would be very much appreciated!
The purpose of this code is to show a list of string with a model herited from QtCore.QAbstractListModel
import sys
from PyQt4 import QtGui, QtCore
class StringListModel(QtCore.QAbstractListModel):
def __init__(self, strings):
QtCore.QAbstractListModel.__init__(self)
self._string_list = strings
def rowCount(self):
return len(self._string_list)
def data(self, index, role):
if not index.isValid() : return QtCore.QVariant()
if role != QtCore.Qt.DisplayRole : return QtCore.QVariant()
if index.row() <= self.rowCount() : return QtCore.QVariant()
return QtCore.QVariant(self._string_list[index.row()])
def headerData(self, section, orientation, role = QtCore.Qt.DisplayRole):
if role != QtCore.Qt.DisplayRole : return QtCore.QVariant()
if orientation == QtCore.Qt.Horizontal : return QtCore.QVariant("Column %s"%section)
else:
return QtCore.QVariant("Row %s"%section)
if __name__ == '__main__':
a = QtGui.QApplication(sys.argv)
lines = ["item 1", "item 2", "item 3"]
model = StringListModel(lines)
view = QtGui.QListView()
view.setModel(model)
view.setWindowTitle("String list model")
view.show()
a.exec_()
The error I've got is
TypeError: rowCount() takes exactly 1 positional argument (2 given)
The problem is that QAbstractItemModel.rowCount takes a 'parent' parameter. The following tweak suppresses the error (though I don't know if it actually implements the correct logic)
def rowCount(self, parent=None):
return len(self._string_list)
Also, are you sure that QListWidget doesn't provide the functionality you need?