Dash Heatmap colors based on Hover values

Hello!
I have a dash app that creates a heatmap with colors based on a color scale. So far so good.
Is it possible to change some of the cells background based on one of the hover values of that cell?

Example:

Monday the 13th should have a red bg color since “Last Minute” (hover value) is -10.

OPT:
I see the running code of heatmaps creates 3 SVGs, one for cartesian layes for structure, one for main layers (with values in annotation tags) and one for hover layers, which is populated with hover info only on mouse hover (by some JS function I presume).
Example of void “hoverlayer”:
<svg class="main-svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="991.602" height="450"><g class="hoverlayer"></g></svg>
Is it possible to have the “hoverlayer” to always contain all the values and manipulate them using JS and CSS?

Hi @andrew_from_ita and welcome to the forum :tada:

If I understand it correctly, what you want is that the color of the cell changes only when you are hovering over it? Is that right?

If that’s what you want, you can try using ‘hoverData’ as input: Input(component_id, 'hoverData')
and the figure as both state and output.

Maybe this thread is helpful as well if you don’t want to update the whole figure: Is it possible to update just `layout`, not whole `figure` of Graph in callback? - #14 by sjtrny

If you need more help, could you share a MRE?

Thanks!

1 Like

Hi Celia, and thank you for the welcome and the link!

It’s not that though, I need the color of the cell to be “red” even when not hovering.

Let me clarify with an example: the heatmap uses price values to set the colors maps.
The higher the price value, the darker the blue.
100 = light blue, 120 = blue, 150 = darker blue.
I’d like some of the cells to be red based not on price, but on another value. A value that I already display in the hover box.
When the user hovers, many info are displayed in the hover box, among these info, a parameter called “last minute” is shown in the hover box. Let’s say last minute can be -10, -20 or -30.
I’d like to paint the cell always red (not only when the user is not hovering) if this value is “-10”, darker red if the value is -20.
If the “last minute” value is not -10 nor -20 nor -30, the cell should stays “blue” as it is right now.

    data = [
        dict(
            x=x_axis,
            y=y_axis,
            z=df.values,
            type="heatmap",
            name="",
            hoverinfo='text',
            hovertext=text,
            showscale=False,
            colorscale=[[0, "#caf3ff"], [1, "#2c82ff"]],
        )
    ]

I think in that case the best solution is to create a heatmap and the add another go.Heatmap trace with the price values. For that, it is important that the price data for the second heatmap has nan for the values that you don’t want to cover. This MRE could give you a good starting point:

import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go

df = pd.DataFrame(dict(
    x = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']*3,
    y = ['Morning', 'Afternoon', 'Evening']*5,
    z1 = [100, 120, 150, 120, 150, 150, 120, 100, 100, 100, 120, 150, 100, 120, 120],
    z2 = [-20, -10, 0, 0, 0, 0, 0, -10, -20, -10, 0, -10, -20, -10, 0]
))

df['z1'] = np.where(
    df['z2'] < 0,
    np.NaN,
    df['z1']
)

df['z2'] = np.where(
    df['z2'] < 0,
    df['z2'],
    np.NaN
)

df_hmap_1 = pd.pivot_table(
    df.drop(columns = ['z2']),
    values = 'z1',
    index = 'y',
    columns = 'x'
)

df_hmap_2 = pd.pivot_table(
    df.drop(columns = ['z1']),
    values = 'z2',
    index = 'y',
    columns = 'x'
)

df_hmap_2_array = [df_hmap_2.iloc[r,].to_list() for r in range(len(df_hmap_2))]

fig = px.imshow(df_hmap_1, 
                color_continuous_scale=[(0, 'lightblue'), (1, "darkblue")])

fig.add_trace(go.Heatmap(
    x = df_hmap_2.columns.tolist(),
    y = df_hmap_2.index.tolist(),
    z = df_hmap_2_array,
    colorscale=[(0, 'darkred'), (1, "salmon")],
    colorbar_x=1.15
))
fig.show()