Conditional Formatting

Conditional formatting is provided through the style_data_conditional
property. The if keyword provides a set of conditional formatting
statements and the rest of the keywords are camelCased CSS properties.

The if syntax supports several operators, row_index, column_id,
filter_query, column_type, column_editable, and state.

filter_query is the most flexible option when dealing with data.

Here is an example of all operators:

df['id'] = df.index
app.layout = dash_table.DataTable(
    data=df.to_dict('records'),
    sort_action='native',
    columns=[
        {'name': 'Date', 'id': 'Date', 'type': 'datetime', 'editable': False},
        {'name': 'Delivery', 'id': 'Delivery', 'type': 'datetime'},
        {'name': 'Region', 'id': 'Region', 'type': 'text'},
        {'name': 'Temperature', 'id': 'Temperature', 'type': 'numeric'},
        {'name': 'Humidity', 'id': 'Humidity', 'type': 'numeric'},
        {'name': 'Pressure', 'id': 'Pressure', 'type': 'any'},
    ],
    editable=True,
    style_data_conditional=[
        {
            'if': {
                'column_id': 'Region',
            },
            'backgroundColor': 'dodgerblue',
            'color': 'white'
        },
        {
            'if': {
                'filter_query': '{Humidity} > 19 && {Humidity} < 41',
                'column_id': 'Humidity'
            },
            'backgroundColor': 'tomato',
            'color': 'white'
        },

        {
            'if': {
                'column_id': 'Pressure',

                # since using .format, escape { with {{
                'filter_query': '{{Pressure}} = {}'.format(df['Pressure'].max())
            },
            'backgroundColor': '#85144b',
            'color': 'white'
        },

        {
            'if': {
                'row_index': 5,  # number | 'odd' | 'even'
                'column_id': 'Region'
            },
            'backgroundColor': 'hotpink',
            'color': 'white'
        },

        {
            'if': {
                'filter_query': '{id} = 4',  # matching rows of a hidden column with the id, `id`
                'column_id': 'Region'
            },
            'backgroundColor': 'RebeccaPurple'
        },

        {
            'if': {
                'filter_query': '{Delivery} > {Date}', # comparing columns to each other
                'column_id': 'Delivery'
            },
            'backgroundColor': '#3D9970'
        },

        {
            'if': {
                'column_editable': False  # True | False
            },
            'backgroundColor': 'rgb(240, 240, 240)',
            'cursor': 'not-allowed'
        },

        {
            'if': {
                'column_type': 'text'  # 'text' | 'any' | 'datetime' | 'numeric'
            },
            'textAlign': 'left'
        },

        {
            'if': {
                'state': 'active'  # 'active' | 'selected'
            },
           'backgroundColor': 'rgba(0, 116, 217, 0.3)',
           'border': '1px solid rgb(0, 116, 217)'
        }

    ]
)

Notes:
- filter_query supports different operators depending on the data type
of the column:

  • =, >, >=, <, <=, and contains are supported by
    all data types (numeric, text, datetime, and any)
  • With contains, the right-hand-side needs to be a string,
    so {Date} contains "01" will work but {Date} contains 1 will not.
  • datestartswith is supported by datetime
  • is nil is supported by all data types
  • is blank is supported by all data types

  • A column’s default data type is any

  • column_type refers to the data type of the column (numeric, text, datetime, and any)
  • column_editable can be equal to True or False (new in Dash 1.12.0)
  • state can be equal to 'active' or 'selected' (new in Dash 1.12.0). Use this to change
    the default pink background and border colors for selected and active cells.
  • row_index is absolute - if you filter or sort your table,
    the 5th row will remain highlighted. Try sorting the columns and
    notice how “San Francisco” remains highlighted but “London” does not.
  • column_id, row_index, and header_index can be equal to a scalar
    (as above) or a list of values. For example, 'column_id': ['Region', 'Pressure']
    is valid (new in Dash 1.12.0). DataTable filtering & conditional formatting
    performs faster when specified a list of values vs a list of separate if blocks.
  • Note 'filter_query': '{Delivery} > {Date}': Filter queries can compare columns
    to each other!
  • id is a special hidden column that can be used as an alternative
    to row_index for highlighting data by index. Since each row has a
    unique id, the conditional formatting associated with this id
    will remain associated with that data after sorting and filtering.
  • RebeccaPurple, hotpink, DodgerBlue… These are
    named CSS colors.
    We recommend avoiding the common color names like
    red, blue, green as they look very outdated. For other color
    suggestions, see http://clrs.cc/.
  • Since we’re using .format, we escape { with {{ and } with }}.
  • To highlight a row, omit column_id. To highlight a particular cell, include column_id.
  • style_cell_conditional (all cells, including headers),
    style_header_conditional (header cells),
    style_filter_conditional (filter input boxes)
    are alternative keywords that can be used for filtering other parts of the table.
  • Limitation - If the table is editable, then the maximum value could change
    if the user edits the table. Since this example hard codes the
    maximum value in the filter expression, the highlighting value
    would no longer be highlighted. As a workaround, you could update
    style_data_conditional via a callback whenever derived_virtual_data changes.
    This limitation applies for any conditional formatting with hardcoded
    numbers computed from an expression in Python
    (including many of the examples below!).
    See plotly/dash-table#755 for updates.

Alternative Highlighting Styles

Instead of highlighting the background cell, you can change the color
of the text, bold the text, add underlines, or style it using any
other css property.

from dash_table.Format import Format, Sign


app.layout = dash_table.DataTable(
    data=df.to_dict('records'),
    sort_action='native',
    columns=[
        {"name": i, "id": i} for i in df.columns
    ],
    style_data_conditional=[
        {
            'if': {
                'filter_query': '{Humidity} > 19 && {Humidity} < 41',
                'column_id': 'Humidity'
            },
            'color': 'tomato',
            'fontWeight': 'bold'
        },
        {
            'if': {
                'filter_query': '{Pressure} > 19',
                'column_id': 'Pressure'
            },
            'textDecoration': 'underline'
        }
    ]
)

Special characters like emoji, stars, checkmarks, circles

You can copy and paste emoji unicode characters directly into your code.
We recommend copying values from emojipedia, e.g.
https://emojipedia.org/star/.

New unicode emoji characters are released every year and may not be
available in the character sets of your audience’s machines.
The appearance of these icons differs on most operating systems.

You may need to place # -*- coding: utf-8 -*- at the top of your code.

# -*- coding: utf-8 -*-

df['Rating'] = df['Humidity'].apply(lambda x:
    '⭐⭐⭐' if x > 30 else (
    '⭐⭐' if x > 20 else (
    '⭐' if x > 10 else ''
)))
df['Growth'] = df['Temperature'].apply(lambda x: '↗️' if x > 0 else '↘️')
df['Status'] = df['Temperature'].apply(lambda x: '🔥' if x > 0 else '🚒')
app.layout = dash_table.DataTable(
    data=df.to_dict('records'),
    columns=[
        {"name": i, "id": i} for i in df.columns
    ],
)

Filtering & Conditional Formatting Recipes

Highlighting the max value in a column

app.layout = dash_table.DataTable(
    data=df.to_dict('records'),
    columns=[
        {"name": i, "id": i} for i in df.columns
    ],
    style_data_conditional=[
        {
            'if': {
                'filter_query': '{{Pressure}} = {}'.format(df['Pressure'].max()),
                'column_id': 'Pressure'
            },
            'backgroundColor': '#FF4136',
            'color': 'white'
        },
    ]
)

Highlighting a row with the min value

app.layout = dash_table.DataTable(
    data=df.to_dict('records'),
    columns=[
        {"name": i, "id": i} for i in df.columns
    ],
    style_data_conditional=[
        {
            'if': {
                'filter_query': '{{Temperature}} = {}'.format(df['Temperature'].min()),
            },
            'backgroundColor': '#FF4136',
            'color': 'white'
        },
    ]
)

Highlighting the top three or bottom three values in a column

app.layout = dash_table.DataTable(
    data=df.to_dict('records'),
    columns=[
        {"name": i, "id": i} for i in df.columns
    ],
    style_data_conditional=(
        [
            {
                'if': {
                    'filter_query': '{{Temperature}} = {}'.format(i),
                    'column_id': 'Temperature',
                },
                'backgroundColor': '#0074D9',
                'color': 'white'
            }
            for i in df['Temperature'].nlargest(3)
        ] +
        [
            {
                'if': {
                    'filter_query': '{{Pressure}} = {}'.format(i),
                    'column_id': 'Pressure',
                },
                'backgroundColor': '#7FDBFF',
                'color': 'white'
            }
            for i in df['Pressure'].nsmallest(3)
        ]
    )
)

Highlighting the max value in every row

def highlight_max_row(df):
    df_numeric_columns = df.select_dtypes('number').drop(['id'], axis=1)
    return [
        {
            'if': {
                'filter_query': '{{id}} = {}'.format(i),
                'column_id': col
            },
            'backgroundColor': '#3D9970',
            'color': 'white'
        }
        # idxmax(axis=1) finds the max indices of each row
        for (i, col) in enumerate(
            df_numeric_columns.idxmax(axis=1)
        )
    ]

df['id'] = df.index
app.layout = dash_table.DataTable(
    data=df.to_dict('records'),
    sort_action='native',
    columns=[{'name': i, 'id': i} for i in df.columns if i != 'id'],
    style_data_conditional=highlight_max_row(df)
)

Highlighting the top two values in a row

def style_row_by_top_values(df, nlargest=2):
    numeric_columns = df.select_dtypes('number').drop(['id'], axis=1).columns
    styles = []
    for i in range(len(df)):
        row = df.loc[i, numeric_columns].sort_values(ascending=False)
        for j in range(nlargest):
            styles.append({
                'if': {
                    'filter_query': '{{id}} = {}'.format(i),
                    'column_id': row.keys()[j]
                },
                'backgroundColor': '#39CCCC',
                'color': 'white'
            })
    return styles

df['id'] = df.index
app.layout = dash_table.DataTable(
    data=df.to_dict('records'),
    sort_action='native',
    columns=[{'name': i, 'id': i} for i in df.columns if i != 'id'],
    style_data_conditional=style_row_by_top_values(df)
)

Highlighting the maximum value in the table

def style_table_by_max_value(df):
    if 'id' in df:
        numeric_columns = df.select_dtypes('number').drop(['id'], axis=1)
    else:
        numeric_columns = df.select_dtypes('number')
    max_across_numeric_columns = numeric_columns.max()
    max_across_table = max_across_numeric_columns.max()
    styles = []
    for col in max_across_numeric_columns.keys():
        if max_across_numeric_columns[col] == max_across_table:
            styles.append({
                'if': {
                    'filter_query': '{{{col}}} = {value}'.format(
                        col=col, value=max_across_table
                    ),
                    'column_id': col
                },
                'backgroundColor': '#39CCCC',
                'color': 'white'
            })
    return styles


df['id'] = df.index
app.layout = dash_table.DataTable(
    data=df.to_dict('records'),
    sort_action='native',
    columns=[{'name': i, 'id': i} for i in df.columns if i != 'id'],
    style_data_conditional=style_table_by_max_value(df)
)

Highlighting a range of values

app.layout = dash_table.DataTable(
    data=df.to_dict('records'),
    sort_action='native',
    columns=[{'name': i, 'id': i} for i in df.columns],
    style_data_conditional=[
        {
            'if': {
                'filter_query': '{2018} >= 5 && {2018} < 10',
                'column_id': '2018'
            },
            'backgroundColor': '#B10DC9',
            'color': 'white'
        }
    ]
)
app.layout = dash_table.DataTable(
    data=df.to_dict('records'),
    sort_action='native',
    columns=[{'name': i, 'id': i} for i in df.columns],
    style_data_conditional=[
        {
            'if': {
                'filter_query': '{{{col}}} >= 5 && {{{col}}} < 10'.format(col=col),
                'column_id': col
            },
            'backgroundColor': '#B10DC9',
            'color': 'white'
        } for col in df.columns
    ]
)

Let’s break down {{{col}}}. We want the final expression to look something like
{2017} > 5 & {2017} < 10 where 2017 is the name of the column.
Since we’re using .format(), we need to escape the brackets,
so {2017} would be {{2017}}. Then, we need to replace 2017 with {col}
for the find-and-replace, so {{2017}} becomes {{{col}}}.format(col=col)

Highlighting top 10% or bottom 10% of values by column

app.layout = dash_table.DataTable(
    data=df.to_dict('records'),
    sort_action='native',
    columns=[{'name': i, 'id': i} for i in df.columns],
    style_data_conditional=[
        {
            'if': {
                'filter_query': '{{{}}} >= {}'.format(col, value),
                'column_id': col
            },
            'backgroundColor': '#B10DC9',
            'color': 'white'
        } for (col, value) in df.quantile(0.9).iteritems()
    ]
)
app.layout = dash_table.DataTable(
    data=df.to_dict('records'),
    sort_action='native',
    columns=[{'name': i, 'id': i} for i in df.columns if i != 'id'],
    style_data_conditional=[
        {
            'if': {
                'filter_query': '{{{}}} <= {}'.format(col, value),
                'column_id': col
            },
            'backgroundColor': '#B10DC9',
            'color': 'white'
        } for (col, value) in df.quantile(0.1).iteritems()
    ]
)

Highlighting values above average and below average

Here, the highlighting is done per column

app.layout = dash_table.DataTable(
    data=df.to_dict('records'),
    sort_action='native',
    columns=[{'name': i, 'id': i} for i in df.columns],
    style_data_conditional=(
        [
            {
                'if': {
                    'filter_query': '{{{}}} > {}'.format(col, value),
                    'column_id': col
                },
                'backgroundColor': '#3D9970',
                'color': 'white'
            } for (col, value) in df.quantile(0.1).iteritems()
        ] +
        [
            {
                'if': {
                    'filter_query': '{{{}}} <= {}'.format(col, value),
                    'column_id': col
                },
                'backgroundColor': '#FF4136',
                'color': 'white'
            } for (col, value) in df.quantile(0.5).iteritems()
        ]
    )
)

Here, the highlighting is done per table

def highlight_above_and_below_max(df):
    df_numeric_columns = df.select_dtypes('number').drop(['id'], axis=1)
    mean = df_numeric_columns.mean().mean()
    return (
        [
            {
                'if': {
                    'filter_query': '{{{}}} > {}'.format(col, mean),
                    'column_id': col
                },
                'backgroundColor': '#3D9970',
                'color': 'white'
            } for col in df_numeric_columns.columns
        ] +
        [
            {
                'if': {
                    'filter_query': '{{{}}} <= {}'.format(col, mean),
                    'column_id': col
                },
                'backgroundColor': '#FF4136',
                'color': 'white'
            } for col in df_numeric_columns.columns
        ]
    )

df['id'] = df.index
app.layout = dash_table.DataTable(
    data=df.to_dict('records'),
    sort_action='native',
    columns=[{'name': i, 'id': i} for i in df.columns if 'id' not in df],
    style_data_conditional=highlight_above_and_below_max(df)
)

Highlighting None, NaN, or empty string values

Three filter queries help with empty or blank values:
- {my_column} is nil will match None values
- {my_column} is blank will match None values and empty strings
- {my_column} = "" will match empty strings

df = df_with_none
app.layout = html.Div([
    html.Pre(repr(df)),
    dash_table.DataTable(
        data=df.to_dict('records'),
        columns=[{'name': i, 'id': i} for i in df.columns],
        style_data_conditional=(
            [
                {
                    'if': {
                        'filter_query': '{{{}}} is blank'.format(col),
                        'column_id': col
                    },
                    'backgroundColor': 'tomato',
                    'color': 'white'
                } for col in df.columns
            ]
        )
    )
])
        Firm  2017  2018  2019  2020
0       Acme           5    10     4
1      Olive  None     3    13     3
2   Barnwood   NaN     7     3     6
3  Henrietta    14     1    13     1

Displaying special values for NaN or None values

from dash_table.Format import Format

df = df_with_none
app.layout = html.Div([
    html.Pre(repr(df)),
    dash_table.DataTable(
        data=df.to_dict('records'),
        columns=[
            {
                'name': i,
                'id': i,
                'type': 'numeric',
                'format': Format(
                    nully='N/A'
                )
            } for i in df.columns
        ],
        editable=True
    )
])
        Firm  2017  2018  2019  2020
0       Acme           5    10     4
1      Olive  None     3    13     3
2   Barnwood   NaN     7     3     6
3  Henrietta    14     1    13     1

Limitations:
- Format(nully=) does not yet match for empty strings, only
None values. See plotly/dash-table#763
for updates.
- 'type': 'numeric' needs to be set, see plotly/dash-table#762
for updates.

An alternative method would be to fill in e.g. ‘N/A’ in the data before rendering:

from dash_table.Format import Format
df = df_with_none
df = df.fillna('N/A').replace('', 'N/A')
app.layout = html.Div([
    html.Pre(repr(df)),
    dash_table.DataTable(
        data=df.to_dict('records'),
        columns=[{'name': i, 'id': i} for i in df.columns],
        editable=True,
        style_data_conditional=[
            {
                'if': {
                    'filter_query': '{{{col}}} = "N/A"'.format(col=col),
                    'column_id': col
                },
                'backgroundColor': 'tomato',
                'color': 'white'
            } for col in df.columns
        ]
    )
])
        Firm 2017  2018  2019  2020
0       Acme  N/A     5    10     4
1      Olive  N/A     3    13     3
2   Barnwood  N/A     7     3     6
3  Henrietta   14     1    13     1

Limitation: If your table is editable, then if a user deletes the
contents of a cell, ‘N/A’ will no longer be displayed.
This is unlike the example with Format where the DataTable will
automatically display N/A for any empty cells, even after editing.

Highlighting text that contains a value

app.layout = dash_table.DataTable(
    data=df.to_dict('records'),
    columns=[
        {'name': i, 'id': i} for i in df.columns
    ],
    style_data_conditional=[
        {
            'if': {
                'filter_query': '{Region} contains "New"'
            },
            'backgroundColor': '#0074D9',
            'color': 'white'
        }
    ]
)

Highlighting text that equals a value

app.layout = dash_table.DataTable(
    data=df.to_dict('records'),
    columns=[
        {'name': i, 'id': i} for i in df.columns
    ],
    style_data_conditional=[
        {
            'if': {
                'filter_query': '{Region} = "San Francisco"'
            },
            'backgroundColor': '#0074D9',
            'color': 'white'
        }
    ]
)

Highlighting cells by value with a colorscale like a heatmap

This recipe shades cells with style_data_conditional and creates a
legend with HTML components. You’ll need to pip install colorlover
to get the colorscales.

import dash_html_components as html

def discrete_background_color_bins(df, n_bins=5, columns='all'):
    import colorlover
    bounds = [i * (1.0 / n_bins) for i in range(n_bins + 1)]
    if columns == 'all':
        if 'id' in df:
            df_numeric_columns = df.select_dtypes('number').drop(['id'], axis=1)
        else:
            df_numeric_columns = df.select_dtypes('number')
    else:
        df_numeric_columns = df[columns]
    df_max = df_numeric_columns.max().max()
    df_min = df_numeric_columns.min().min()
    ranges = [
        ((df_max - df_min) * i) + df_min
        for i in bounds
    ]
    styles = []
    legend = []
    for i in range(1, len(bounds)):
        min_bound = ranges[i - 1]
        max_bound = ranges[i]
        backgroundColor = colorlover.scales[str(n_bins)]['seq']['Blues'][i - 1]
        color = 'white' if i > len(bounds) / 2. else 'inherit'

        for column in df_numeric_columns:
            styles.append({
                'if': {
                    'filter_query': (
                        '{{{column}}} >= {min_bound}' +
                        (' && {{{column}}} < {max_bound}' if (i < len(bounds) - 1) else '')
                    ).format(column=column, min_bound=min_bound, max_bound=max_bound),
                    'column_id': column
                },
                'backgroundColor': backgroundColor,
                'color': color
            })
        legend.append(
            html.Div(style={'display': 'inline-block', 'width': '60px'}, children=[
                html.Div(
                    style={
                        'backgroundColor': backgroundColor,
                        'borderLeft': '1px rgb(50, 50, 50) solid',
                        'height': '10px'
                    }
                ),
                html.Small(round(min_bound, 2), style={'paddingLeft': '2px'})
            ])
        )

    return (styles, html.Div(legend, style={'padding': '5px 0 5px 0'}))
(styles, legend) = discrete_background_color_bins(df)

app.layout = html.Div([
    html.Div(legend, style={'float': 'right'}),
    dash_table.DataTable(
        data=df.to_dict('records'),
        sort_action='native',
        columns=[{'name': i, 'id': i} for i in df.columns],
        style_data_conditional=styles
    ),
])
-10.0
-5.4
-0.8
3.8
8.4

Highlighting with a colorscale on a single column

(styles, legend) = discrete_background_color_bins(df_wide, columns=['2018'])

app.layout = html.Div([
    legend,
    dash_table.DataTable(
        data=df.to_dict('records'),
        sort_action='native',
        columns=[{'name': i, 'id': i} for i in df.columns],
        style_data_conditional=styles
    )
])
-10.0
-6.6
-3.2
0.2
3.6

Displaying data bars

These recipes display a creative use of background linear-gradient
colors to display horizontal bar charts within the table.
Your mileage may vary! Feel free to modify these recipes for your own
use.

def data_bars(df, column):
    n_bins = 100
    bounds = [i * (1.0 / n_bins) for i in range(n_bins + 1)]
    ranges = [
        ((df[column].max() - df[column].min()) * i) + df[column].min()
        for i in bounds
    ]
    styles = []
    for i in range(1, len(bounds)):
        min_bound = ranges[i - 1]
        max_bound = ranges[i]
        max_bound_percentage = bounds[i] * 100
        styles.append({
            'if': {
                'filter_query': (
                    '{{{column}}} >= {min_bound}' +
                    (' && {{{column}}} < {max_bound}' if (i < len(bounds) - 1) else '')
                ).format(column=column, min_bound=min_bound, max_bound=max_bound),
                'column_id': column
            },
            'background': (
                """
                    linear-gradient(90deg,
                    #0074D9 0%,
                    #0074D9 {max_bound_percentage}%,
                    white {max_bound_percentage}%,
                    white 100%)
                """.format(max_bound_percentage=max_bound_percentage)
            ),
            'paddingBottom': 2,
            'paddingTop': 2
        })

    return styles


def data_bars_diverging(df, column, color_above='#3D9970', color_below='#FF4136'):
    n_bins = 100
    bounds = [i * (1.0 / n_bins) for i in range(n_bins + 1)]
    col_max = df[column].max()
    col_min = df[column].min()
    ranges = [
        ((col_max - col_min) * i) + col_min
        for i in bounds
    ]
    midpoint = (col_max + col_min) / 2.

    styles = []
    for i in range(1, len(bounds)):
        min_bound = ranges[i - 1]
        max_bound = ranges[i]
        min_bound_percentage = bounds[i - 1] * 100
        max_bound_percentage = bounds[i] * 100

        style = {
            'if': {
                'filter_query': (
                    '{{{column}}} >= {min_bound}' +
                    (' && {{{column}}} < {max_bound}' if (i < len(bounds) - 1) else '')
                ).format(column=column, min_bound=min_bound, max_bound=max_bound),
                'column_id': column
            },
            'paddingBottom': 2,
            'paddingTop': 2
        }
        if max_bound > midpoint:
            background = (
                """
                    linear-gradient(90deg,
                    white 0%,
                    white 50%,
                    {color_above} 50%,
                    {color_above} {max_bound_percentage}%,
                    white {max_bound_percentage}%,
                    white 100%)
                """.format(
                    max_bound_percentage=max_bound_percentage,
                    color_above=color_above
                )
            )
        else:
            background = (
                """
                    linear-gradient(90deg,
                    white 0%,
                    white {min_bound_percentage}%,
                    {color_below} {min_bound_percentage}%,
                    {color_below} 50%,
                    white 50%,
                    white 100%)
                """.format(
                    min_bound_percentage=min_bound_percentage,
                    color_below=color_below
                )
            )
        style['background'] = background
        styles.append(style)

    return styles
app.layout = dash_table.DataTable(
    data=df.to_dict('records'),
    sort_action='native',
    columns=[{'name': i, 'id': i} for i in df.columns],
    style_data_conditional=(
        data_bars(df, 'lifeExp') +
        data_bars(df, 'gdpPercap')
    ),
    style_cell={
        'width': '100px',
        'minWidth': '100px',
        'maxWidth': '100px',
        'overflow': 'hidden',
        'textOverflow': 'ellipsis',
    },
    page_size=20
)

Data bars without text

Display the data bars without text by creating a new column and making
the text transparent.

df_gapminder['gdpPercap relative values'] = df_gapminder['gdpPercap']
app.layout = dash_table.DataTable(
    data=df.to_dict('records'),
    sort_action='native',
    columns=[{'name': i, 'id': i} for i in df.columns],
    style_data_conditional=(
        data_bars(df, 'gdpPercap relative values') + [{
            'if': {'column_id': 'gdpPercap relative values'},
            'color': 'transparent'
        }]
    ),
    style_cell={
        'width': '100px',
        'minWidth': '100px',
        'maxWidth': '100px',
        'overflow': 'hidden',
        'textOverflow': 'ellipsis',
    },
    page_size=20
)

Diverging data bars

The data_bars_diverging function splits up the data into two quadrants
by the midpoint.
Alternative representations of data bars may split up the data by
positive and negative numbers or by the average values.
Your mileage may vary! Feel free to modify the data_bars_diverging
function to your own visualization needs. If you create something new,
please share your work on the Dash Community Forum.

app.layout = dash_table.DataTable(
    data=df.to_dict('records'),
    sort_action='native',
    columns=[{'name': i, 'id': i} for i in df.columns],
    style_data_conditional=(
        data_bars_diverging(df, 'lifeExp') +
        data_bars_diverging(df, 'gdpPercap')
    ),
    style_cell={
        'width': '100px',
        'minWidth': '100px',
        'maxWidth': '100px',
        'overflow': 'hidden',
        'textOverflow': 'ellipsis',
    },
    page_size=20
)

Highlighting dates

app.layout = dash_table.DataTable(
    data=df.to_dict('records'),
    columns=[
        {'name': i, 'id': i}
        if i != 'Date' else
        {'name': 'Date', 'id': 'Date', 'type': 'datetime'}
        for i in df.columns
    ],
    style_data_conditional=[{
        'if': {'filter_query': '{Date} datestartswith "2015-10"'},
        'backgroundColor': '#85144b',
        'color': 'white'
    }]
)