Add background gradient colouring in a table using matplotlib

Viewed 55

I have a dataframe that I want to export as an image, but I also want to colour the cells based on the values I achieved it using dataframe_image: dataframe_image result

but now I need to get the same result using matplotlib. so far I managed to render a table using the following code:

df = pd.DataFrame({'Name': ['One','Two','Three','Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine', 'Ten','Eleven'],
                         '1Param': [255,191,1200,130,474,22,1203,1618,959,45,6097],
                         '2Param': [21,27,173,16,43,0,181,151,107,7,726],
                         '3Param': [2022,1794,9045,1054,3642,152,8431,12411,6630,325,45506],
                         '4Param': [470,486,2230,252,1092,18,2008,2748,1364,86,10754],
                             })
    

def render_mpl_table(data, col_width=3.0, row_height=0.625, font_size=14,
                     header_color='#40466e', row_colors=['#f1f1f2', 'w'], edge_color='w',
                     bbox=[0, 0, 1, 1], header_columns=0,
                     ax=None, **kwargs):
    if ax is None:
        size = (np.array(data.shape[::-1]) + np.array([0, 1])) * np.array([col_width, row_height])
        fig, ax = plt.subplots(figsize=size)
        ax.axis('off')

    mpl_table = ax.table(cellText=data.values, bbox=bbox, colLabels=data.columns, **kwargs)
    
    mpl_table.auto_set_font_size(False)
    mpl_table.set_fontsize(font_size)
    mpl_table.auto_set_column_width(col=list(range(len(data.columns))))  
    
    for k, cell in  six.iteritems(mpl_table._cells):
        cell.set_edgecolor(edge_color)
        if k[0] == 0 or k[1] < header_columns:
            cell.set_text_props(weight='bold', color='w')
            cell.set_facecolor(header_color)
        # else:
        #     cell.set_facecolor(row_colors[k[0]%len(row_colors)])      

    return ax

render_mpl_table(df, header_columns=0)

the result I get: matplotlib result does anyone know how do I add background gradient colouring similar to dataframe_image module?

1 Answers

Use a color map that is close to the expected output and standardize on the maximum and minimum values of the data. Looping to get the cell's string, and if the string is not an error when converted to float, it is numeric, so the value is used to set the color in the cell.

def render_mpl_table(data, col_width=3.0, row_height=0.625, font_size=14,
                     header_color='#40466e', row_colors=['#f1f1f2', 'w'], edge_color='w',
                     bbox=[0, 0, 1, 1], header_columns=0,
                     ax=None, **kwargs):
    if ax is None:
        size = (np.array(data.shape[::-1]) + np.array([0, 1])) * np.array([col_width, row_height])
        fig, ax = plt.subplots(figsize=size)
        ax.axis('off')

    # min, max
    min_val = df[['1Param', '2Param', '3Param', '4Param']].min().min()
    max_val = df[['1Param', '2Param', '3Param', '4Param']].max().max()
    # normalize and cmap
    norm = plt.Normalize(vmin=min_val, vmax=max_val)
    cmap = plt.get_cmap('Blues')
    
    mpl_table = ax.table(cellText=data.values, bbox=bbox, colLabels=data.columns, **kwargs)

    mpl_table.auto_set_font_size(False)
    mpl_table.set_fontsize(font_size)
    mpl_table.auto_set_column_width(col=list(range(len(data.columns))))  

    for k, cell in  six.iteritems(mpl_table._cells):
        cell.set_edgecolor(edge_color)
        if k[0] == 0 or k[1] < header_columns:
            cell.set_text_props(weight='bold', color='w')
            cell.set_facecolor(header_color)
        else:
            v = cell._text.get_text()
            #print(type(v))
            try:
                float(v)
            except ValueError:
                pass
            else:
                #print(v)
                cell.set_facecolor(cmap(norm(int(v))))      

    return ax

render_mpl_table(df, header_columns=0)

enter image description here

Related