0

This is a follow up question to: PyQt: How to sort QTableView columns(strings and numericals)

Now I am planning to do the same sorting for the excel files

Here is my Code:

self.Upload = QtGui.QPushButton()
self.Upload.clicked.connect(self.showOpenDialog)
self.Table = QtGui.QPushButton()
self.table.clicked.connect(self.LoadTable)


def showOpenDialog(self):
    fileName = QtGui.QFileDialog.getOpenFileName(self, 'Open file', '/home')
    if (".xls" or ".xml" or ".xlsx" or ".xlsm") in fileName:
        with open(fileName, 'rb') as drate:
            self.Datas = pd.read_excel(drate, index_col=0)
        self.Loaded_File.clear()
        self.Loaded_File.append(fileName)
        colll = self.Datas.dtypes.index
        col_names = np.array(colll)


def LoadTable(self):
    tab_table_view = QtGui.QWidget()
    self.Tab.insertTab(0, tab_table_view, self.File_Name)
    self.tableView = QtGui.QTableView(tab_table_view)
    self.tableView.setGeometry(QtCore.QRect(0, 0, 721, 571))
    self.model = QtGui.QStandardItemModel(self)
    file_name_temp = self.File_Name
    self.tableView.setModel(self.model)
    colll = self.Datas.dtypes.index
    col_names = np.array(colll)
    col_names = np.insert(col_names, 0, self.Datas.index.name)
    self.model.setHorizontalHeaderLabels(col_names)
    self.tableView.hideRow(0)
    self.tableView.setSortingEnabled(True)

            if (".xls" or ".xml" or ".xlsx" or ".xlsm") in self.File_Name:
        from itertools import chain
        ii = 1
        book = xlrd.open_workbook(self.File_Name)
        sheet = book.sheet_by_index(0)
        num_col = len(self.Datas.columns)
        num_row = len(self.Datas)
        print(num_col,num_row)
        self.Matrix = [[0 for x in range(num_col+1)] for y in range(num_row)]
        for i in range(num_row):
            self.Matrix[i][0]=self.Datas.index.values[i]
            for j in range(num_col):
                self.Matrix[i][j+1] = self.Datas.iat[i,j]
        print(self.Matrix)
        for i in range(num_row):
            items = []
            for j in range(num_col):
                field = self.Matrix[i][j]
                item = QtGui.QStandardItem(field)
                for numtype in (int, float):
                    try:
                        data = numtype(field)
                        break
                    except (ValueError, OverflowError):
                        pass
                else:
                    print('Not a number: %r' % field)
                    data = field
                item.setData(data, QtCore.Qt.UserRole)
            items.append(item)
            self.model.appendRow(items)

The output will be:

Not a number: 'Government'
Not a number: 'Canada'
Not a number: 'Carretera'
Not a number: 'None'
Traceback (most recent call last):
  File "Main_File.py", line 1535, in loadTable
    item = QtGui.QStandardItem(field)
TypeError: arguments did not match any overloaded call:
  QStandardItem(): too many arguments
  QStandardItem(str): argument 1 has unexpected type 'Timestamp'
  QStandardItem(QIcon, str): argument 1 has unexpected type 'Timestamp'
  QStandardItem(int, int columns=1): argument 1 has unexpected type 'Timestamp'
  QStandardItem(QStandardItem): argument 1 has unexpected type 'Timestamp'

It is fine if the datatype is str in the file(upto "None") and when the first int or float comes it generates some overloaded call.

Please someone help me.

learncode
  • 1,105
  • 4
  • 18
  • 36
  • 1
    Please explain more clearly what you're trying to achieve with this code, and what the specific problems are. – ekhumoro Nov 02 '16 at 17:15
  • 1
    @ekhumoro I have now explained the question as well as I can do. – learncode Nov 02 '16 at 17:41
  • 1
    I'm sorry, but I cannot make any sense of that code. It's impossible for me to test it, because I have no idea what `self.Datas` is, or how it relates to the excel worksheet (which doesn't seem to get used at all). Why are you using an `np.array` to set the headers, and why do you then seem to add those same headers as the first row in the table? And how did you arrive at the method of constructing the other rows? – ekhumoro Nov 02 '16 at 18:07
  • @ekhumoro can you now check the updated code? I am having the some sort of error that I cannot understand. – learncode Nov 02 '16 at 20:49
  • I have posted an answer with a new version of my previous demo script. Hopefully you will be able to adapt it to your needs. – ekhumoro Nov 02 '16 at 20:53

2 Answers2

3

Below is a demo script which reads both csv and excel files, and should sort dates, ints, floats, and strings correctly.

import sys
import pandas as pd, numpy as np
from PyQt4 import QtCore, QtGui

class Window(QtGui.QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.model = QtGui.QStandardItemModel(self)
        self.model.setSortRole(QtCore.Qt.UserRole)
        self.tableView = QtGui.QTableView()
        self.tableView.setSortingEnabled(True)
        self.tableView.setModel(self.model)
        self.button = QtGui.QPushButton('Open CSV', self)
        self.button.clicked.connect(self.handleButton)
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.tableView)
        layout.addWidget(self.button)

    def handleButton(self):
        filters = (
            'CSV files (*.csv *.txt)',
            'Excel Files (*.xls *.xml *.xlsx *.xlsm)',
            )
        path, filter = QtGui.QFileDialog.getOpenFileNameAndFilter(
            self, 'Open File', '', ';;'.join(filters))
        if path:
            csv = filter.startswith('CSV')
            if csv:
                dataframe = pd.read_csv(path)
            else:
                dataframe = pd.read_excel(path)
            self.model.setRowCount(0)
            dateformat = '%m/%d/%Y'
            rows, columns = dataframe.shape
            for row in range(rows):
                items = []
                for column in range(columns):
                    field = dataframe.iat[row, column]
                    if csv and isinstance(field, str):
                        try:
                            field = pd.to_datetime(field, format=dateformat)
                        except ValueError:
                            pass
                    if isinstance(field, pd.tslib.Timestamp):
                        text = field.strftime(dateformat)
                        data = field.timestamp()
                    else:
                        text = str(field)
                        if isinstance(field, np.number):
                            data = field.item()
                        else:
                            data = text
                    item = QtGui.QStandardItem(text)
                    item.setData(data, QtCore.Qt.UserRole)
                    items.append(item)
                self.model.appendRow(items)

if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.setGeometry(500, 150, 600, 400)
    window.show()
    sys.exit(app.exec_())
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
0

As Ekhumoro suggests, sorting of Excel data is easiest done with Pandas. I have tried similar operations with openpyxl, but it's too limited. Pandas can save you many lines of code.

A small example:

from PyQt4 import QtGui , QtCore
import pandas as pd
import numpy as np
import time
import sys

# open excel file
sales = pd.read_excel ("Sales.xlsx" , parse_dates=['Data'] )
# select columns
purchase_patterns = sales [['Total','Date']]
# choose date index
purchase_patterns = purchase_patterns.set_index("Date")
# regroup / resample by week and get subtotals by sum 
resample = purchase_patterns.resample ('W' , how = sum)

Here are some nice links:

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
rainer
  • 3,295
  • 5
  • 34
  • 50