Search code examples
pythondatatablebokeh

Bokeh DataTable compare cells between rows & highlight if different


I have a Bokeh DataTable and would like to to compare each cell from row 1 with the cells from all other rows and highlight cells with differing values. This is what I came up with so far:

import pandas as pd

from bokeh.models import HTMLTemplateFormatter, DataTable, TableColumn
from bokeh.plotting import show, output_notebook
output_notebook()

df = pd.DataFrame({'x':[1,2,3,1], 'y':[2,2,2,3]})

def get_html_formatter(my_col, reference_vals):
    template = """        
        <div style="background:<%=
            (function colorfromint() {
                if(!vals.includes(my_column)) {
                    console.log('Success!');
                    console.log(my_column);
                    return('red');                    
                }                    
                else {
                    console.log('Fail');
                }
            }()) %>; 
            color: black"> 
        <%= value %>        
        </div>
    """.replace('my_column', my_col).replace('vals', str(reference_vals))

    return HTMLTemplateFormatter(template=template)

reference_values = df.iloc[0].to_list()
table = DataTable()
table.source.data = df
table.columns = [TableColumn(field=c, title=c, formatter=get_html_formatter(c, reference_values)) for c in df.columns]

show(table)

It works, but the results aren't correct because I just created a list with the values from the first row and compare every cell value against it without taking the specific columns into account.


Solution

  • I hope I did understand you and you want to format each column by the first value of the column.

    In that case you are very close to a working solution. You only have to pass one value instead a list to the formatter, which is created by column.

    import pandas as pd
    
    from bokeh.models import HTMLTemplateFormatter, DataTable, TableColumn
    from bokeh.plotting import show, output_notebook
    output_notebook()
    
    df = pd.DataFrame({'x':[1,2,3,1], 'y':[2,2,2,3]})
    
    def get_html_formatter(my_col, reference_val):
        template = """
            <div style="background:<%=
                (function (){return (vals != my_column ? 'red': '')}()) 
                %>;
                color: black">
            <%= value %>
            </div>
        """.replace('my_column', my_col).replace('vals', str(reference_val))
    
        return HTMLTemplateFormatter(template=template)
    
    reference_values = df.iloc[0].to_list()
    table = DataTable()
    table.source.data = df
    table.columns = [
        TableColumn(field=c, title=c, formatter=get_html_formatter(c, reference_value))
        for c, reference_value in zip(df.columns, reference_values) # main change here
    ]
    
    show(table)
    

    This gives the table below:

    table with red background for values which are different from the first value in the column