为空值格式化文本单元格,为所有负值格式化颜色单元格

format text cell for empty values and color cell for all negative values

我正在生成一个 plotly 热图,如下所示:

@app.callback(
    Output('graph', 'figure'),
    [
        Input('submit', 'n_clicks')
    ],
    prevent_initial_call=True
)
def update_plot(n_clicks):
    if n_clicks:
        my_row = ['T-3', 'T-2', 'T-1']
        col = ['T-2', 'T-1', 'T0']
        df_stat = pd.DataFrame([[12, -3.5, 7.8], [np.nan, 0.5, -19], [np.nan, np.nan, 56]], columns=col)
        df_stat.index = my_row

        fig = go.Figure()
        fig.add_trace(go.Heatmap(
            x=df_stat.columns,
            y=df_stat.index,
            z=df_stat.values.tolist(),
            # zauto=True,
            zmax=0.67,
            zmin=0,
            hoverongaps=False,
            showscale=True,
            colorscale='OrRd',
            text=df_stat.to_numpy(), 
            texttemplate="%{text}",
            hovertemplate='My number: %{z:.2f}<extra></extra>',
            textfont={"color": "black"},
            # autocolorscale=True
        ))
        fig.update_yaxes(autorange="reversed", type='category', categoryorder='array', categoryarray=my_row)
        fig.update_xaxes(automargin=True, side='top', type='category', categoryorder='array', categoryarray=col)
        fig.update_layout(height=600, width=1200)

        return fig

用作输入的数据框是三角形的(由 np.nan 和浮点数组成)。我要实现的目标如下:

这是目前的样子:

我正在看与此类似的内容:

没有任何方法可以使用 plotly 中的默认参数来实现您想要的,但我们可以通过一些变通方法获得您想要的结果。

要处理df_stat中的NaNs显示为null,可以使用空字符串的.fillna("")方法。这些单元格的背景已经是透明的,但绘图的背景颜色是透明的。由于您想要的图似乎具有带灰色线条的白色背景,我们可以走捷径并将 template 设置为 'plotly_white'

我认为不存在具有多种条件的色标(例如 x>=0 的一种色标和 x<0 的一种颜色),因此我们需要屏蔽您的 df_stat DataFrame 并将它们绘制为单独的轨迹。

为此,我们将制作两个单独的掩码 df_stat:

  • df_stat_non_negative 将包含 df_stat 的正值,所有其他值设置为 NaN。我也不确定 'OrRd' 色阶实际上是你想要的,因为它看起来像你想要小的正值是灰色的。您可以在 0 和 1 之间的标准化值处指定多种颜色。例如:如果您设置 colorscale=[[0, 'lightgrey'],[0.10, 'LightSalmon'],[1.0,'DarkRed']],对于热图中相对较小的值,您将浅灰色混合到 lightsalmon 中,但热图中的大部分将类似于 'OrRd'

  • df_stat_negative 将包含 df_stat 的负值,所有其他值设置为 NaN,对于热图,我们将创建一个自定义 colorscale,其中从 0 到 1 的标准化值都设置为 grey(这将确保对应于 df_stat_negative 的热图无论值如何,每个单元格都显示为灰色)。我们还将隐藏负值热图的色标。

综合起来:

from turtle import bgcolor
import numpy as np
import pandas as pd
import plotly.graph_objects as go

my_row = ['T-3', 'T-2', 'T-1']
col = ['T-2', 'T-1', 'T0']
df_stat = pd.DataFrame([[12, -3.5, 7.8], [np.nan, 0.5, -19], [np.nan, np.nan, 56]], columns=col)
df_stat.index = my_row

## only plot positive df_stat values 
df_stat_non_negative = df_stat.copy()
df_stat_non_negative[df_stat_non_negative < 0] = np.nan
df_stat_non_negative.fillna("", inplace=True)

fig = go.Figure()
fig.add_trace(go.Heatmap(
    x=df_stat_non_negative.columns,
    y=df_stat_non_negative.index,
    z=df_stat_non_negative.values.tolist(),
    # zauto=True,
    zmin=0,
    hoverongaps=False,
    showscale=True,
    colorscale=[[0, 'lightgrey'],[0.10, 'LightSalmon'],[1.0,'DarkRed']],
    text=df_stat_non_negative.to_numpy(), 
    texttemplate="%{text}",
    hovertemplate='My number: %{z:.2f}<extra></extra>',
    textfont={"color": "black"},
    # autocolorscale=True
))

df_stat_negative = df_stat.copy()
df_stat_negative[df_stat_negative >= 0] = np.nan
df_stat_negative.fillna("", inplace=True)

fig.add_trace(go.Heatmap(
    x=df_stat_negative.columns,
    y=df_stat_negative.index,
    z=df_stat_negative.values.tolist(),
    # zauto=True,
    zmax=0,
    zmin=0,
    hoverongaps=False,
    showscale=False,
    colorscale=[[0, 'lightgrey'],[1.0, 'lightgrey']],
    text=df_stat_negative.to_numpy(), 
    texttemplate="%{text}",
    hovertemplate='My number: %{z:.2f}<extra></extra>',
    textfont={"color": "black"},
    # autocolorscale=True
))

fig.update_yaxes(autorange="reversed", type='category', categoryorder='array', categoryarray=my_row)
fig.update_xaxes(automargin=True, side='top', type='category', categoryorder='array', categoryarray=col)
fig.update_layout(height=600, width=1200, template='plotly_white')
fig.show()