Bring Drag & Drop to Dash with Dashboard Engine. 💫 Learn how at our next webinar!

Updating a variable used in DataTable's style_data_conditional

Hi everyone,

I’m facing a problem where I can’t update a variable I use for filter_query in style_data_conditional in a data table. In my example code I display 6 rows with IDs and dates. What I want is for dates that:

  • equal today’s date to be colored blue,
  • dates greater than today to be green ,
  • dates less than today to be red.

I managed to do that just fine, but when I leave my server overnight and check the next day it doesn’t update properly. The variable “dateToday” changes like it should when I print it, but the change is not reflected in the table (the colors stay the same).

Here’s my example code:

queryData = “SELECT [ID],convert(varchar,[Date inserted],23) AS Date_inserted FROM myTable ORDER BY Date_inserted ASC”
df_data = pd.read_sql(queryData, sql_conn)

query_dateToday = “SELECT convert(varchar, getdate(), 23) AS Date_today FROM myTable”
df_dateToday = pd.read_sql(query_dateToday, sql_conn)
dateToday = str(df_dateToday[‘Date_today’][0])

app.layout = html.Div(id=‘outer’,
children=[
html.Div(id=‘dateToday’, children=dateToday, style={‘display’: ‘none’}),

    dash_table.DataTable(
        id='table',
        columns = [{'name': i, 'id': i} for i in df_data.columns],
        data = df_data.to_dict('records'),
        style_data_conditional = [
            {
                'if' {
                    'filter_query': '{Date_inserted} eq '+dateToday+''
                },
                'color': 'blue'
            },
            {
                'if' {
                    'filter_query': '{Date_inserted} <  '+dateToday+''
                },
                'color': 'red'
            },
            {
                'if' {
                    'filter_query': '{Date_inserted} >  '+dateToday+''
                },
                'color': 'green'
            }
        ],
        style_table={'width': '15%', 'fontWeight': 'bold'},
    ),

    dcc.Interval(
        id='interval-time',
        interval=1000,
        n_intervals=0
    ),
],

)

@app.callback(Output(‘table’,‘data’),
[Input(‘interval-time’,‘n_intervals’)])
def update_table(n)
df_dateToday = pd.read_sql(query_dateToday, sql_conn)
dateToday = str(df_dateToday[‘Date_today’][0])
df_data = pd.read_sql(queryData, sql_conn)
data = df_data.to_dict(‘records’)

return data

This is how it looks if today is 20 Dec: today

This is how I want it to look the next day (21 Dec starting at 00:01): tomorrow

A workaround I found is to just return the whole DataTable in the callback again but that’s not going to make sense when I have 30 tables like that and I create them with a function outside the callback. I’ve also heard something about “derived_filter_query_structure” when looking for a solution but couldn’t figure out how to use it and if it is indeed related to my problem. How do I make my table to use the updated “dateToday” variable instead of the initial one when the server was started?

Any kind of help would be appreciated!

Why not return style_data_conditional in your dcc.Interval callback?

@app.callback(Output(‘table’, ‘style_data_conditional’),
[Input(‘interval-time’,‘n_intervals’)])
def update_table(n)
df_dateToday = pd.read_sql(query_dateToday, sql_conn)
dateToday = str(df_dateToday[‘Date_today’][0])
return [
            {
                'if' {
                    'filter_query': '{Date_inserted} eq '+dateToday+''
                },
                'color': 'blue'
            },
            {
                'if' {
                    'filter_query': '{Date_inserted} <  '+dateToday+''
                },
                'color': 'red'
            },
            {
                'if' {
                    'filter_query': '{Date_inserted} >  '+dateToday+''
                },
                'color': 'green'
            }
        ]

Did this end up working?

For some reason when I update 'style_data_conditional' via a callback it doesn’t seem to work correctly as described here. I’m doing something similar, but the result is that my table ends up going totally white in the background and loosing all background formatting.

My use-case is I am trying to select rows and have those selected rows have a different color to stand out from the rest of the datatable.

Here is a code-snippet

@app.callback(
    Output('icdTable', 'style_data_conditional'),
    Input('icdTable', 'selected_rows'),
    prevent_initial_call=True
)
def style_selected_rows(selRows):
    if selRows is None:
        return defaultCondStyle
    else:
        return defaultCondStyle.append({'if': {'row_index': selRows}, 'backgroundColor': '#333333'})

And defaultCondStyle is pre-defined and initialized as 'style_data_conditional' in my app initialization:

defaultCondStyle = [
    {'if': {'state': 'active'},
    'backgroundColor': '#00aaff'},
    {'if': {'state': 'selected'},
    'backgroundColor': '#00aaff'},
    {'if': {'row_index': 'odd'},
    'backgroundColor': '#80d4ff'},
    {'if': {'row_index': 'even'},
    'backgroundColor': '#a1a5ad'}
]

Seems like a similar output to this with updating 'style_data_conditional' but it isn’t working for me, so just wondering if this ended up working out.

I’ll also note that I know using append() isn’t the best solution in the long term since it will infinitely add dictionaries to that list, but I’m just trying to get this highlighting issue working before addressing that :).

Hi @kr-hansen and welcome to the Dash community :slight_smile:

Try:

     return defaultCondStyle + [{'if': {'row_index': selRows}, 'backgroundColor': '#333333', 'color': 'white'}]

This should fix the append() issue too. Plus adding the 'color': 'white' will make it so the text is visible in the dark background

@AnnMarieW thanks, that worked great!

Quick question, why is it that .append() doesn’t work when returning but adding the additional list does work? I understand from how it fixes the problem of making the list eternally long, but I don’t understand why it doesn’t like that appended list in the first place?

Thanks for the suggestion on 'color': 'white' too, but I just threw some random hex values in there for this example. I’m actually importing my styles from CSS using something similar to my suggestion here (https://github.com/plotly/dash-table/issues/843), but that wouldn’t make sense for this forum :).

Haha - now you are asking the hard questions!

OK, so when you use the “+” you are doing a concat and that operation returns a new list. When you use append, it mutates the list in place but doesn’t return anything. Or more precisely, it returns None

So when using the append in the callback, it was returning None (even though it was updating defaultCondStyle) . Returning None to the style_data_conditional property will remove all of the formatting. That is why the background colors went back to the default white.

1 Like

Ahh thanks for explaining. Python 101 stuff that I seem to have forgotten. Thanks!

Based on this github post, you have forgotten more than I know :laughing:

And btw, that looks like a pretty good idea!

1 Like