You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python Plotly的px.imshow热力图中实现散点抖动

如何在Plotly风险矩阵的同一单元格中为散点添加抖动效果避免重叠

我用Plotly制作了风险矩阵热力图,叠加散点表示单个项目,但同一单元格(比如影响中等、可能性低的单元格)有多个项目时,散点会重叠。怎么给散点加抖动效果让它们在单元格内不重叠?示例代码如下:

import plotly.express as px
import plotly.graph_objects as go

fig = px.imshow([[3, 5, 5],
                 [1, 3, 5],
                 [1, 1, 3]],
                color_continuous_scale='Reds',
                labels=dict(x="Likelihood", y="Impact"),
                x=['Low', 'Medium', 'High'],
                y=['High', 'Medium', 'Low']
                )
fig.add_trace(go.Scatter(x=["Low"], y=["Medium"],
                         name="project1",
                         marker=dict(color='black', size=16)))
fig.show()

要实现这个效果,核心思路是给同一单元格内的散点坐标添加微小的随机偏移量(抖动)。Plotly的类别轴底层是用连续数值(0、1、2...)映射类别的,基于这些数值生成偏移,既能保证点在单元格内,又能避免重叠。

具体实现代码

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

# 定义风险矩阵基础数据
heatmap_data = [[3, 5, 5],
                [1, 3, 5],
                [1, 1, 3]]
x_labels = ['Low', 'Medium', 'High']
y_labels = ['High', 'Medium', 'Low']

# 生成热力图
fig = px.imshow(heatmap_data,
                color_continuous_scale='Reds',
                labels=dict(x="Likelihood", y="Impact"),
                x=x_labels,
                y=y_labels)

# 模拟多项目数据,包含同一单元格的项目
projects = [
    {"name": "project1", "likelihood": "Low", "impact": "Medium"},
    {"name": "project2", "likelihood": "Low", "impact": "Medium"},
    {"name": "project3", "likelihood": "Medium", "impact": "High"},
    {"name": "project4", "likelihood": "Medium", "impact": "High"}
]

# 映射类别标签到数值索引
x_indices = {label: idx for idx, label in enumerate(x_labels)}
y_indices = {label: idx for idx, label in enumerate(y_labels)}

jitter_amount = 0.2  # 抖动幅度,建议不超过0.5(避免跨单元格)
x_jittered = []
y_jittered = []
proj_names = []

# 为每个项目生成带抖动的坐标
for proj in projects:
    x_idx = x_indices[proj["likelihood"]]
    y_idx = y_indices[proj["impact"]]
    # 添加随机偏移
    x_jittered.append(x_idx + np.random.uniform(-jitter_amount, jitter_amount))
    y_jittered.append(y_idx + np.random.uniform(-jitter_amount, jitter_amount))
    proj_names.append(proj["name"])

# 添加带抖动的散点,可选显示项目名称
fig.add_trace(go.Scatter(
    x=x_jittered,
    y=y_jittered,
    mode='markers+text',
    text=proj_names,
    textposition='top center',
    name="Projects",
    marker=dict(color='black', size=16)
))

# 保持轴的类别标签显示,不切换为数值
fig.update_layout(
    xaxis=dict(tickmode='array', tickvals=list(x_indices.values()), ticktext=list(x_indices.keys())),
    yaxis=dict(tickmode='array', tickvals=list(y_indices.values()), ticktext=list(y_indices.keys()))
)

fig.show()

关键说明

  • jitter_amount:控制抖动幅度,值越大点分散越开,但不要超过0.5,否则点会跑到相邻单元格
  • 如果需要规整排列而非随机抖动,可以预先设置固定偏移量(比如同一单元格内的点按(±0.1, ±0.1)排列),适合项目数量固定的场景
  • 启用mode='markers+text'可以同时显示项目名称,方便快速识别每个散点对应的项目

内容的提问来源于stack exchange,提问作者Subaru Spirit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 08:24:57