Conditional Formatting - Highlighting Cells

Hi all,

I’m trying to conditionally format individual cells based on the ‘Conditional Formatting - Highlighting Cells’ part of the “Styling the DataTable” guide (https://dash.plot.ly/datatable/style).
It is not working for me as it is not highlighting individual cells but whole columns.

e.g.: if I have the below code the whole ‘Attribute6’ column is colored lightblue even though there are cells in Attribute6 which equals 2 and therefore supposed to be shown with pink background color.

#The code:

import dash
import dash_table
import pandas as pd

app = dash.Dash(name)

df = pd.read_csv(‘C:/Users/AZT/Documents/csvfile20190903.csv’, encoding=‘cp1250’)

def serve_layout():
return dash_table.DataTable(
data=df.to_dict(‘records’),
columns=[
{‘name’: i, ‘id’: i} for i in df.columns
],
style_data_conditional=[
{
‘if’: {
‘column_id’: ‘Attribute6’,
‘filter_query’: ‘“Attribute6” = 2’,
},
‘backgroundColor’: ‘pink’
},
{
‘if’: {
‘column_id’: ‘Attribute6’,
‘filter_query’: ‘“Attribute6” < 2’,
},
‘backgroundColor’: ‘lightblue’
},
]
)

app.layout = serve_layout

if name == ‘main’:
app.run_server(debug=True)

#Code ended

I’ve also found out that no matter what condition (=, <, >) do I put, the whole column is highlighted anyway. It’s like not having the filter_query’: ‘“Attribute6” < 2’, row at all.
I’ve also checked in other columns, it works similarly.

Thank you in advance!

Put {} around the column name.

I think you might also have to wrap the 2 in num(), so ‘filter_query’: ‘{Attribute6}’ = num(2), etc.

As mentioned by @klamike, the columns need to be surrounded by { }.

In the previous versions of the table it was necessary to explicitly cast string values with num(...) but that hasn’t been necessary since dash>=1.0.0 (https://dash.plot.ly/dash-1-0-migration)

The example below shows the relational operators comparing a number to a string (column a) and a number to a number (column b).

Hope this helps!

import dash

from dash_table import DataTable

app = dash.Dash(__name__)

app.layout = DataTable(
    id='table',
    columns=[{
        'name': x,
        'id': x,
        'selectable': True
    } for x in ['a', 'b', 'c']],
    data=[{
        'a': str(x),
        'b': x,
        'c': str(x*x)
    } for x in range(0,100)],
    style_data_conditional=[{
        'if': {
            'column_id': 'a',
            'filter_query': '{a} < 2'
        },
        'backgroundColor': 'pink'
    }, {
        'if': {
            'column_id': 'b',
            'filter_query': '{b} >= 3 && {b} < 10'
        },
        'backgroundColor': 'pink'
    }]
)

if __name__ == '__main__':
    app.run_server(debug=True)

Thank you for your quick replies @klamike and @Marc-Andre!

One should put {} around the column name as you’ve suggested, otherwise it’s not working, so it was part of the solution. The problem still remained for me after that though. Based on @Marc-Andre’s post I realized I possibly have to pip upgrade (I had dash==0.39.0). After putting {} around the column name and the upgrade to dash==1.2.0 it works to highlight individual cells.

AZT, I had similar problems. I battled through and attach some code to highlight cells in a datatable, collect the values in a dataframe for subsequent processing. The idea is you can toggle the highlighted cell or clear them with a button. I am a novice so I am sure the code could be more efficient and would welcome comments.

import os
import numpy as np
import dash
from dash.dependencies import Input, Output, State
import dash_table
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import time
from datetime import datetime

results_table_headings = [ ‘ASX Code’, ‘Amount or Weighting Percent’,‘Calculated Weighting Percent’ ,‘Dividend Yield Percent’, ‘Franking Percent’,
‘Effective Franked Dividend’, ‘Capital Gain’,‘Total Return’,
‘Return Contribution’, ‘Standard Deviation’]
initialdata = [[‘AFI’, ‘$3000’,’’, ‘’, ‘’, ‘’,’’,’’,’’,’’],[‘CBAPF’, ‘$3600’,’’, ‘’, ‘’,’’,’’,’’,’’,’’],
[‘MFF’, ‘$4000’,’’, ‘’, ‘’,’’,’’,’’,’’,’’],[‘CASH’, ‘$1500’,’’ , ‘’, ‘’,’’,’’,’’,’’,’’]]

initialised_table = pd.DataFrame(initialdata, columns = results_table_headings)

app = dash.Dash(name)

app.layout = html.Div([
dash_table.DataTable(
id=‘table-editing-simple’,
columns=( [{‘id’: p, ‘name’: p, “hideable”: True} for p in results_table_headings] ),
data = initialised_table.to_dict(‘records’),
editable=True,
filter_action=“native”,
sort_action=“native”,
sort_mode=“multi”,
column_selectable=“single”,
row_selectable=“multi”,
row_deletable=True,
selected_columns=[],
selected_rows=[],
page_action=“native”,
page_current= 0,
page_size= 10,
),
html.Button( id=‘clear_selection_btn’, children=‘Clear Selection’,
n_clicks_timestamp=0, style={ ‘display’: ‘inline’, ‘backgroundColor’: ‘White’ , ‘color’ :‘black’ }),
dcc.Store(id=‘stylememory’,storage_type=‘session’),
dcc.Store(id=‘cellmemory’,storage_type=‘session’),
html.Div(id =‘Output Message’),

])

@app.callback([Output(‘stylememory’, ‘data’), Output(‘cellmemory’, ‘data’)],
[Input(‘table-editing-simple’, ‘active_cell’),Input(‘table-editing-simple’, ‘data’),Input(‘clear_selection_btn’, ‘n_clicks_timestamp’)],
[State(‘stylememory’, ‘data’),State(‘cellmemory’, ‘data’),State(‘clear_selection_btn’, ‘n_clicks’)])
def store_styles(active_cell, data, n_clicks_t, currstyle, currstylecells, n_clicks ):
if not active_cell: return (),’’

if currstylecells == '' : currstylecells = pd.DataFrame()
else: currstylecells = pd.DataFrame.from_dict(currstylecells, orient='columns')

if n_clicks != None:   # Clear selection button
    if len(currstylecells) != 0:
        if n_clicks_t > currstylecells.iloc[:1].timestamp[0]:
            return [{ 'background_color': 'transparent' }], ''
                                                                    # highlighting style
style = [{ 'if': { 'row_index': active_cell['row'] ,  'column_id': active_cell['column_id'] } , 'background_color': '#ffffe0' }]

# collect the active cell information
activecellrow = int(active_cell['row'])
activecellcol = str(active_cell['column_id'])
activecellval = str(data[active_cell['row']][active_cell['column_id']])
timestamp = int(time.time()*1000)
activecellinfo = {'activecellrow': activecellrow, 'activecellcol': activecellcol, 'activecellval': activecellval, 'timestamp': timestamp }

if len(currstylecells) == 0 : # first cell clicked
    finalstyle = style
    currstylecells = currstylecells.append([activecellinfo],ignore_index=True) 
else:                         # subsequnt cells
    if ((currstylecells.activecellrow  == activecellrow).any() and (currstylecells.activecellcol  == activecellcol).any()): 
        i = 0                                                   # look for duplicates signifying a toggle
        for i in range(len(currstyle)-1):
            if activecellrow == currstyle[i]['if']['row_index'] and activecellcol == currstyle[i]['if']['column_id']:  
                droppedstyle = currstyle.pop(i)                       # remove style entry
                currstylecells = currstylecells.drop(currstylecells.activecellrow[currstylecells.activecellrow == activecellrow].index.tolist()[0])    
            finalstyle = currstyle
    else:                                                            # no duplicates so add to both files
        currstylecells = currstylecells.append([activecellinfo],ignore_index=True)
        finalstyle = currstyle
        finalstyle.extend(style)

currstylecells =  currstylecells.to_dict('list')         

return finalstyle, currstylecells

@app.callback(Output(‘table-editing-simple’, ‘style_data_conditional’),
[Input(‘stylememory’, ‘data’)],
[State(‘table-editing-simple’, ‘data’),State(‘table-editing-simple’, ‘columns’)])
def update_styles(style, rows, columns):
if not style: return style
else:
results_table = pd.DataFrame(rows, columns=[c[‘name’] for c in columns])
return style

if name == ‘main’:
app.run_server(port=8077, host=‘127.0.0.1’)