Search code examples
pythonpandasdatatableplotly-dashconditional-formatting

Dash DataTable with individual formatting of certain cells


I am visualizing a Pandas DataFrame in a Dash DataTable and would like to manually highlight certain cells with a specific color (e.g., red or green).

The coloring depends on some conditions which are not simply dependent on the value of the cell itself but on neighboring values (e.g., the difference between the previous and the next row).

I have gone through the docs and reference. From my understanding conditional formatting does not allow to introduce conditions which do depend on values of neighboring cells.

Is there a way to define the conditions in Python using the Pandas DataFrame and then format certain specific cells of my Dash DataTable accordingly? I have looked into the [style_cell property]](https://dash.plotly.com/datatable/style) but this seems to be applied to the entire table and cannot be applied on a cell-by-cell basis.

Edit: To be more precise, what I am looking for is to color the values of each cell depending on the cell value of the next row see example in image:

  • when the value of a cell is greater than the value of the cell in the next row (e.g., row1 @ col1 > row2 @ col1) then the text color should be green (e.g., row1 @ col1)
  • when the value of a cell is lower than the value of the cell in the next row (e.g., row2 @ col1 < row3 @ col1) then the text color should be red (e.g., row2 @ col1)
  • when the value of a cell is equal to the value of the cell in the next row (e.g., row1 @ col2 = row2 @ col2) then the text color should not change / remain black (e.g., row1 @ col2)

Solution

  • I think you can find different between rows in pandas first then use this to style your dash datatable. Below is my code:

    from dash import Dash, dash_table
    import pandas as pd
    from collections import OrderedDict
    import numpy as np
    import dash_bootstrap_components as dbc
    from dash import Dash, dash_table
    import numpy as np
    data = OrderedDict(
        [("col1", [3, 1,2]),
         ("col2", [3, 3, 1]),
         ("col3", [1, 3, 3]),
        ])
    
    df = pd.DataFrame(data)
    df['col_1_shift'] = df['col1'] - df['col1'].shift(-1)
    df['col_2_shift'] = df['col2'] - df['col2'].shift(-1) 
    df['col_3_shift'] = df['col3'] - df['col3'].shift(-1) 
    df.fillna(0,inplace=True)
    

    And here is the df Ouput:

        col1    col2    col3    col_1_shift col_2_shift col_3_shift
    0   3   3   1   2.0 0.0 -2.0
    1   1   3   3   -1.0    2.0 0.0
    2   2   1   3   0.0 0.0 0.0
    

    After that we will style based on col_shift columns:

    app = Dash(__name__, external_stylesheets=[dbc.themes.LUX])
    
    
    #print(df)
    app.layout = dash_table.DataTable(
        data=df.to_dict('records'),
        
        #sort_action='native',
        columns=[{'name': i, 'id': i} for i in df.columns[0:3]],
        style_data_conditional=[
            {'if': {'filter_query': '{col_1_shift} > 0',
                    'column_id': 'col1'
                },
                'color': 'green'
            },
                    {'if': {'filter_query': '{col_1_shift} < 0',
                    'column_id': 'col1'
                },
                'color': 'red'
            },
                    {'if': {'filter_query': '{col_2_shift} > 0',
                    'column_id': 'col2'
                },
                'color': 'green'
            },
                    {'if': {'filter_query': '{col_2_shift} < 0',
                    'column_id': 'col2'
                },
                'color': 'red'
            },
                    {'if': {'filter_query': '{col_3_shift} > 0',
                    'column_id': 'col3'
                },
                'color': 'green'
            },
                    {'if': {'filter_query': '{col_3_shift} < 0',
                    'column_id': 'col3'
                },
                'color': 'red'
            },
            
        ] 
    )
    
    if __name__ == '__main__':
        app.run_server(debug=False)
    

    And here is the result:

    enter image description here