ValueError with pandastable row coloring

Viewed 148

I'm using pandastable to visualize a Dataframe and I want to highlight certain rows. In the pandastable documentation I found the function setRowColors. It says there to use color in hex. But when I'm applying the code I get the following error:

ValueError: could not convert string to float: '#ff3300'

With this code I'm reproducing the error:

import tkinter as tk
from pandastable import Table 
import pandas as pd

root = tk.Tk()
frame = tk.Frame(root) 
frame.pack(fill="both", expand=True)

df = pd.DataFrame() 
df["column1"] = [1,2,3] 
df["column2"] = ["a","b","c"]


pt = Table(frame, dataframe=df) 
pt.setRowColors(rows=1, clr="#ff3300", cols="all") 
pt.redraw() 
pt.show()

root.mainloop()
1 Answers

Due to the current implementation in version 0.12.2 of the setRowColors function, the rows parameter must be passed a list of values:

import tkinter as tk

import pandas as pd
from pandastable import Table

root = tk.Tk()
frame = tk.Frame(root)
frame.pack(fill="both", expand=True)

df = pd.DataFrame()
df["column1"] = [1, 2, 3]
df["column2"] = ["a", "b", "c"]

pt = Table(frame, dataframe=df)
# rows=list of values
pt.setRowColors(rows=[1], clr='#ff3300', cols="all")
# No need to redraw it is done within the setRowColors function
pt.show()

root.mainloop()

tkinter window with coloured rows

There is an open issue for this on github Setting colour of cell in dataframe


The reason this happens is because of the way that the index is subset, and the way that Series.at modifies column dtypes depending on if it is accessing a cell or a group of cells.

This pandas code reproduces the error:

import numpy as np
import pandas as pd

df = pd.DataFrame({"column1": [1, 2, 3], "column2": ["a", "b", "c"]})
rc = pd.DataFrame()
rc['column1'] = pd.Series(np.nan, index=df.index)
idx = df.index[1]  # <- uses int
print(idx)  # 1  # (python int)
rc.at[idx, 'column1'] = '#ff3300'
print(rc)

Producing:

ValueError: could not convert string to float: '#ff3300'

However the following works as expected:

import numpy as np
import pandas as pd

df = pd.DataFrame({"column1": [1, 2, 3], "column2": ["a", "b", "c"]})
rc = pd.DataFrame()
rc['column1'] = pd.Series(np.nan, index=df.index)
idx = df.index[[1]]  # <- uses list
print(idx)  # Int64Index([1], dtype='int64')  # (pandas Index object)
rc.at[idx, 'column1'] = '#ff3300'
print(rc)
   column1
0      NaN
1  #ff3300
2      NaN

This occurs in the setRowColors function in version 0.12.2 source code:

def setRowColors(self, rows=None, clr=None, cols=None):
    """Set rows color from menu.
    Args:
        rows: row numbers to be colored
        clr: color in hex
        cols: column numbers, can also use 'all'
    """

    if clr is None:
        clr = pickColor(self, '#dcf1fc')
    if clr == None:
        return
    if rows == None:
        rows = self.multiplerowlist
    df = self.model.df
    idx = df.index[rows]  # <- The issue is here (idx becomes an int if not a list)
    rc = self.rowcolors
    if cols is None:
        cols = self.multiplecollist
    elif cols is 'all':
        cols = range(len(df.columns))
    colnames = df.columns[cols]
    for c in colnames:
        if c not in rc.columns:
            rc[c] = pd.Series(np.nan, index=df.index)
        # rc[c][idx] = clr
        rc.at[idx, c] = clr
    self.redraw()
    return

*Comment marking the line at issue is added for clarity

Related