How to color each column in a heatmap individually?

Hello everyone

I used plotly.figure_factory to plot the following heatmap:

But what I want is to colorscale each column individually. Something like this:

image
(done in Excel)

Notice how for example in column A, the highest value 52 [A4] is darkest among column A, and value 30 [A2] is lightest, while in column D the highest value 34 [D5] is darkest among column D, and the value 8 D[3] is the lightest.

Can this be achievable in plotly?

Thank for you very much in advance!

I actually managed to do it with the help of this answer. I.e. by scaling each column by its max value, and providing the raw values in the โ€˜textโ€™ and annotation_text arguments:

def _scale(column, new_range):
    old_range = (column.min(), column.max())
    return (((column - old_range[0]) * (new_range[1] - new_range[0])) / (old_range[1] - old_range[0])) + new_range[0]

ff.create_annotated_heatmap(z=(hm.apply(lambda col: _scale(col, (0, 1)))).values,
                            annotation_text=hm.values,
                            text=hm.values,
                            x=hm.columns.to_list(),
                            y=hm.index.to_list(),
                            hoverinfo='x+y+text',
                            colorscale='Blues')

I changed the code from the documentation a bit, and it worked:

from dash import Dash, dash_table, html
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': '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=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]

    styles = []
    for column in df_numeric_columns:
        df_max = df_numeric_columns[[column]].max().max()
        df_min = df_numeric_columns[[column]].min().min()
        ranges = [
            ((df_max - df_min) * i) + df_min
            for i in bounds
        ]

        for i in range(1, len(bounds)):
            min_bound = ranges[i - 1]
            max_bound = ranges[i]
            backgroundColor = colorlover.scales[str(n_bins)]['seq']['YlOrRd'][i - 1]
            color = 'white' if i > len(bounds) / 2. else 'inherit'

            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
            })

    return styles


styles = discrete_background_color_bins(df, columns=['2017', '2018', '2019', '2020'])

app.layout = html.Div([
    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(debug=True)