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

如何在Plotly Express气泡图中为不同健康状态分组设置独立的连续色阶

如何在Plotly Express气泡图中为不同健康状态分组设置独立的连续色阶

嗨,我完全懂你想要的效果——给健康组和患病组分别用基于-log10(pvalue)的连续渐变(健康组从浅红到深红,患病组从浅蓝到深蓝),而不是单一的固定颜色对吧?确实Plotly Express本身没法直接设置多个连续色阶,但我们有两种简单可行的方法来实现这个需求,我结合你的数据和代码一步步给你说明:

方法一:自定义颜色列(Plotly Express友好版)

这个思路是先给每组的-log10(pvalue)做组内归一化,再分别映射到红、蓝色阶上,生成每个点的自定义颜色,最后用Plotly Express绘制:

import plotly.express as px
import pandas as pd
from plotly.colors import sample_colorscale

# 加载你的数据(这里用你提供的片段示例)
data = [
    ["innate immune response in mucosa", "Group A healthy", "healthy", 0.001312593, 2.881869847],
    ["low-density lipoprotein particle remodeling", "Group A healthy", "healthy", 0.004084727, 2.388836964],
    ["nucleosome assembly", "Group A healthy", "healthy", 0.005324106, 2.273753336],
    ["antimicrobial humoral immune response mediated by antimicrobial peptide", "Group B healthy", "healthy", 0.005932275, 2.226778741],
    ["intermediate filament organization", "Group B healthy", "healthy", 0.005932275, 2.226778741],
    ["defense response to bacterium", "Group B healthy", "healthy", 0.005932275, 2.226778741],
    ["leukocyte migration involved in inflammatory response", "Group B healthy", "healthy", 0.015600119, 1.806872092],
    ["defense response to Gram-negative bacterium", "Group B healthy", "healthy", 0.015600119, 1.806872092],
    ["keratinization", "Group C healthy", "healthy", 0.018984856, 1.721592692],
    ["Golgi apparatus mannose trimming", "Group C healthy", "healthy", 0.018984856, 1.721592692],
    ["sequestering of zinc ion", "Group C healthy", "healthy", 0.018984856, 1.721592692],
    ["chylomicron remnant clearance", "Group A sick", "sick", 0.018984856, 1.721592692],
    ["neutrophil aggregation", "Group A sick", "sick", 0.018984856, 1.721592692],
    ["protein localization to CENP-A containing chromatin", "Group A sick", "sick", 0.018984856, 1.721592692],
    ["negative regulation of lipid biosynthetic process", "Group B sick", "sick", 0.018984856, 1.721592692],
    ["antibacterial humoral response", "Group B sick", "sick", 0.022844656, 1.641215378],
    ["positive regulation of cell growth", "Group B sick", "sick", 0.023998364, 1.619818356]
]
df = pd.DataFrame(data, columns=["terms", "group", "health_status", "pvalue", "-LOG10(pvalue)"])

# 1. 选择要使用的连续色阶
red_scale = px.colors.sequential.Reds
blue_scale = px.colors.sequential.Blues

# 2. 对每组的-log10(pvalue)做归一化(映射到0-1区间)
df['norm_log_p'] = df.groupby('health_status')['-LOG10(pvalue)'].transform(lambda x: (x - x.min())/(x.max() - x.min()))

# 3. 根据健康状态和归一化值生成每个点的颜色
def get_custom_color(row):
    if row['health_status'] == 'healthy':
        return sample_colorscale(red_scale, row['norm_log_p'])[0]
    else:
        return sample_colorscale(blue_scale, row['norm_log_p'])[0]

df['custom_color'] = df.apply(get_custom_color, axis=1)

# 4. 绘制气泡图,使用自定义颜色列
height = (df['terms'].nunique()*20)+100
fig = px.scatter(df, x='group', y='terms', size='-LOG10(pvalue)',
                 color='custom_color', height=height, width=1500,
                 color_discrete_map=None)  # 关闭默认颜色映射逻辑

fig.show()

方法说明:

  • 归一化是为了让每组的颜色渐变都能覆盖从组内最小值到最大值的范围,避免某组因为数值范围小导致颜色区分度低
  • 如果需要添加对应两组的颜色条,可以结合Plotly Graph Objects手动添加,不过如果只是要视觉区分,这个方法已经足够

方法二:分层绘制(Graph Objects版,支持独立颜色条)

如果需要给两组分别显示独立的颜色条,用Plotly Graph Objects分层绘制会更直观——分别绘制健康组和患病组的散点,各自设置连续色阶:

import plotly.graph_objects as go
import pandas as pd

# 同样加载你的df数据(代码同上,这里省略)

height = (df['terms'].nunique()*20)+100
fig = go.Figure()

# 添加健康组散点:使用Reds连续色阶
fig.add_trace(go.Scatter(
    x=df[df['health_status'] == 'healthy']['group'],
    y=df[df['health_status'] == 'healthy']['terms'],
    mode='markers',
    marker=dict(
        size=df[df['health_status'] == 'healthy']['-LOG10(pvalue)'] * 10,  # 调整size缩放系数,让点大小合适
        color=df[df['health_status'] == 'healthy']['-LOG10(pvalue)'],
        colorscale='Reds',
        colorbar=dict(
            title='Healthy<br>-log10(pvalue)',
            x=0.05  # 调整颜色条位置,避免重叠
        )
    ),
    name='Healthy'
))

# 添加患病组散点:使用Blues连续色阶
fig.add_trace(go.Scatter(
    x=df[df['health_status'] == 'sick']['group'],
    y=df[df['health_status'] == 'sick']['terms'],
    mode='markers',
    marker=dict(
        size=df[df['health_status'] == 'sick']['-LOG10(pvalue)'] * 10,
        color=df[df['health_status'] == 'sick']['-LOG10(pvalue)'],
        colorscale='Blues',
        colorbar=dict(
            title='Sick<br>-log10(pvalue)',
            x=0.95  # 调整颜色条到右侧
        )
    ),
    name='Sick'
))

# 调整整体布局
fig.update_layout(
    height=height,
    width=1500,
    xaxis_title='group',
    yaxis_title='terms'
)

fig.show()

方法说明:

  • 这个方法的优势是能直接生成两个独立的颜色条,让观众清晰看到每组的数值对应颜色的关系
  • 你可以根据需求调整size的缩放系数,或者给颜色条设置更多样式(比如位置、宽度等)

额外小提示:

  • 如果两组的-log10(pvalue)全局范围差异很大,你可以选择是否对全局数值做归一化,还是保持组内归一化,完全取决于你想要展示的重点
  • 色阶也可以换成你喜欢的其他连续色阶,比如Reds_r是反向的红渐变,Blues_r是反向的蓝渐变

备注:内容来源于stack exchange,提问作者Bob McBobson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.23 14:32:48