如何在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
相关产品推荐
相关产品推荐

