3

I have a QTableWidget in editable mode in which user puts in integer input , how can I generate a list of data entered in this table so as to perform operations on it , here is my manual code for that:

def dataframe_generation_from_table(self,table):
    number_of_rows = table.rowCount()
    number_of_columns = table.columnCount()

    tmp_df = pd.DataFrame({ 'Date' : [] , str(self.final_lvl_of_analysis) :[],  'Value': []}) 

    for i in range(0,number_of_rows):
        for j in range(0,number_of_columns):
            tmp_item = table.item(i,j)
            tmp_df2 = pd.DataFrame( { 'Date' : [pd.to_datetime(table.horizontalHeaderItem(j).data())] , str(self.final_lvl_of_analysis) :[ str(table.verticalHeaderItem(i).data())], 'Value': [float(tmp_item.data(0))]})
            print tmp_df2
            tmp_df.update(tmp_df2, join = 'left', overwrite = False)

    return tmp_df

Also , I am using the following code for QTableWidget generation:

    self.pd_table = QtGui.QTableWidget(self.groupBox_19)
    self.pd_table.setObjectName(_fromUtf8("pd_table"))
    self.pd_table.setColumnCount(0)
    self.pd_table.setRowCount(0)

My specs are : pandas 0.18.1 , PyQt 4 and Python 2.7

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Rishabh Gupta
  • 73
  • 4
  • 13
  • Retrieve data always from the model of the view you are interested in. – NoDataDumpNoContribution Jun 11 '16 at 11:24
  • @Trilarion kindly consider that I am not using QTableView , instead I am using QTableWidget , so please if you know a way to get data from a QTableWidget , do reply with an appropriate answer . – Rishabh Gupta Jun 13 '16 at 04:44
  • QTableWidget inherits from QTableView which inherits from QAbstractItemView which contains a QAbstractItemModel and there you have the model. I recommend interacting with the model or provide your own via QAbstractItemView.setModel. – NoDataDumpNoContribution Jun 13 '16 at 07:14
  • @Trilarion Thanks for explaining the whole parentage , I had created my abstraction model for pasting in the QTableView for another table , here it is https://ideone.com/do1Ho6 but I don't know how do I modify my model to take input , if possible do help . I do have one query though , what is the use of QTableWidget if it isnot made specifically for user interaction and if I at-all need to use it ? Also when this appears to be a more common function , why hasn't there been included a method inside it already ? – Rishabh Gupta Jun 13 '16 at 07:35

3 Answers3

5

I think you're overcomplicating it a little with the updates/joins. The simplest approach is to create the full-size DataFrame first (filled with NaN) and then assign the data to this:

def dataframe_generation_from_table(self,table):
    number_of_rows = table.rowCount()
    number_of_columns = table.columnCount()

    tmp_df = pd.DataFrame( 
                columns=['Date', str(self.final_lvl_of_analysis), 'Value'], # Fill columnets
                index=range(number_of_rows) # Fill rows
                ) 

    for i in range(number_of_rows):
        for j in range(number_of_columns):
            tmp_df.ix[i, j] = table.item(i, j).data()

    return tmp_df

The above code assigns data to it's location by the numerical index, so position 1,1 in the QtTableWidget will end up at 1,1 in the DataFrame. This way you don't need to worry about the column headers when moving data. If you want to change the column names you can do that when creating the DataFrame, changing the values passed into the columns= parameter.

If you want to change a column to DateTime format, you should be able to do this in a single operation after the loop with:

tmp_df['Date'] = pd.to_datetime( tmp_df['Date'] )
mfitzp
  • 15,275
  • 7
  • 50
  • 70
  • what dataframe do you mean by df , here and also how can I ensure that the data is stored in correct cell ,i.e with its corresponding header labels ? thanks a lot for replying . – Rishabh Gupta Jun 10 '16 at 05:35
  • Typo sorry that should be `tmp_df`. See the edit for more description. – mfitzp Jun 10 '16 at 07:44
  • there seems to be an issue with your method apparently it generates an error "ValueError: cannot set by positional indexing with enlargement " which can be resolved by using loc instead of ix , but that still does not solve my issue of referencing the horizontal and vertical labels for each QTableWidgetItem . – Rishabh Gupta Jun 16 '16 at 10:47
1

The change from .data() to .text() eliminated the ValueError.

def saveFile(self):
    df = pd.DataFrame()
    savePath = QtGui.QFileDialog.getSaveFileName(None, "Blood Hound", 
        "Testing.csv", "CSV files (*.csv)")        
    rows = self.tableWidget.rowCount()
    columns = self.tableWidget.columnCount()        

    for i in range(rows):            
        for j in range(columns):                
            df.loc[i, j] = str(self.tableWidget.item(i, j).text())              
    df.to_csv((savePath), header = None, index = 0)
Pika Supports Ukraine
  • 3,612
  • 10
  • 26
  • 42
Jeff
  • 57
  • 1
  • 2
  • 7
1
# creates a new df from qtables dimensions,
# copies qtable (data & headers) to the df and returns the df
@staticmethod
def write_qtable_to_df(table):
    col_count = table.columnCount()
    row_count = table.rowCount()
    headers = [str(table.horizontalHeaderItem(i).text()) for i in range(col_count)]

    # df indexing is slow, so use lists
    df_list = []
    for row in range(row_count):
        df_list2 = []
        for col in range(col_count):
            table_item = table.item(row,col)
            df_list2.append('' if table_item is None else str(table_item.text()))
        df_list.append(df_list2)

    df = pandas.DataFrame(df_list, columns=headers)

    return df