Automatic Gradient Highlighting for a data frame value

Hello Dash community, hope you’re fine :slight_smile:

I’m facing problems when trying to display a data frame with hilighted value.

I found that I can use the Styling data frame in Python :
data

But doesn’t work when trying to apply it on Dash.

Can anyone give me a handle on this?

Thanks a lot.

Hi lahyouness

Did you see this example?

Highlighting with a colorscale on a single column

1 Like

Hi Samuel, thanks for your reactivity and your answer.

I have currently seen solutions of this kind, and I tell myself that to apply them I will lose the notion of gradient since I could only use the positive negative condition to display colors.

but apparently if I have no solution to apply the gradient, I will opt for this solution with two colors, one for the positive and another for the negative :).

Thanks a lot.

1 Like

Hi @lahyouness

If you scroll down on the page @SamuelVT posted or click on the link he provide you will find the example Highlighting with a colorscal on a single column.

btw Welcome to the forum @SamuelVT and thanks for posting such a helpful link. :slight_smile:

Here is the example modified to use the Spectral colorscale:

image

Here is more information on build-it color scales

from dash import Dash, dash_table, html
import pandas as pd
from collections import OrderedDict
import plotly.express as px

wide_data = [
    {'Firm': 'Acme', '2017': 13, '2018': 5, '2019': 10, '2020': 4},
    {'Firm': 'Olive', '2017': 3, '2018': 3, '2019': 13, '2020': 3},
    {'Firm': 'Barnwood', '2017': 6, '2018': 7, '2019': 3, '2020': 6},
    {'Firm': 'Henrietta', '2017': -3, '2018': -10, '2019': -5, '2020': -6},
]
df = pd.DataFrame(wide_data)

app = Dash(__name__)

def discrete_background_color_bins(df, n_bins=10, 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]

        # using color scales from colorlover
        backgroundColor1 = colorlover.scales[str(n_bins)]['div']['Spectral'][i - 1]

        # or using plotly express color scales
        backgroundColor = px.colors.diverging.Spectral[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, 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
    )
])

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

1 Like

Hi lahyouness

Here is a code with a little modification made by me , I hope can help you.

https://dash.plotly.com/datatable/conditional-formatting#highlighting-with-a-colorscale-on-a-single-column

import dash

import dash_html_components as html

import dash_table

import pandas as pd

from collections import OrderedDict

wide_data = [

    {'Firm': 'Acme', '2017': 13, '2018': 5, '2019': 10, '2020': 4},

    {'Firm': 'Olive', '2017': 3, '2018': 3, '2019': 13, '2020': 3},

    {'Firm': 'Barnwood', '2017': 6, '2018': 7, '2019': 3, '2020': 6},

    {'Firm': 'Olive', '2017': 3, '2018': 3, '2019': 13, '2020': 3},

    {'Firm': 'Barnwood', '2017': 6, '2018': 7, '2019': 3, '2020': 6},

    {'Firm': 'Olive', '2017': 3, '2018': 4, '2019': 13, '2020': 3},

    {'Firm': 'Barnwood', '2017': 6, '2018': 3, '2019': 3, '2020': 6},

    {'Firm': 'Olive', '2017': 3, '2018': 2, '2019': 13, '2020': 3},

    {'Firm': 'Barnwood', '2017': 6, '2018': 1, '2019': 3, '2020': 6},

    {'Firm': 'Henrietta', '2017': -3, '2018': -10, '2019': -5, '2020': -6},

]

df = pd.DataFrame(wide_data)

app = dash.Dash(__name__)

def discrete_background_color_bins(df, n_bins=8, 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']['Reds'][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, 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

    )

])

if __name__ == '__main__':

    app.run_server(debug=True)

3 Likes

Oh thanks for both of you ( Samuel and AnnMarie ) I appreciate your help. I can say that my problem was finally solved :pray: :pray:.

2 Likes