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

如何在Plotly Express堆叠条形图中按counts列调整条形透明度?

问题:为堆叠条形图中counts < 20的条形设置低透明度/灰色

原始数据与初始绘图代码

初始DataFrame

import pandas as pd
data = {
    'user_type': ['L', 'L', 'L', 'L', 'L', 'L', 'L', 'L'],
    'cluster_phase1': ['A', 'A', 'A', 'A', 'A', 'A', 'A', 'A'],
    'group': ['Control', 'Control', 'Control', 'Control', 'Test', 'Test', 'Test', 'Test'],
    'phase': ['phase1', 'phase1', 'phase2', 'phase2', 'phase1', 'phase1', 'phase2', 'phase2'],
    'col': [0, 1, 0, 1, 0, 1, 0, 1],
    'value': [38.0, 62.0, 54.0, 46.0, 37.0, 63.0, 41.0, 59.0],
    'counts': [18, 18, 13, 13, 94, 94, 89, 89]
}

df = pd.DataFrame(data)

初始绘图代码

import plotly.express as px
fig = px.bar(df, x='cluster_phase1', y='value', color='col',
             facet_row='group', facet_col='phase',
             text='value', title='L')
fig.for_each_annotation(lambda a: a.update(text=a.text.split("=")[-1]))
fig.show()

生成的堆叠条形图:
堆叠条形图

需求

需要将counts < 20的条形(示例中Control组的4个条形)设置为低透明度(如0.2)或灰色,尝试的以下代码无效:

for i, count in enumerate(df['counts']):
    opacity = 0.2 if count < 20 else 1.0
    fig.update_traces(opacity=opacity, selector=f"x[{i + 1}]")

解决方案

方法1:设置低透明度

通过遍历每个trace,匹配对应的facet分组和col值,为每个条形单独设置透明度:

import plotly.express as px
import pandas as pd

# 初始化数据(可替换为测试用更新数据)
data = {
    'user_type': ['L', 'L', 'L', 'L', 'L', 'L', 'L', 'L'],
    'cluster_phase1': ['A', 'A', 'A', 'A', 'A', 'A', 'A', 'A'],
    'group': ['Control', 'Control', 'Control', 'Control', 'Test', 'Test', 'Test', 'Test'],
    'phase': ['phase1', 'phase1', 'phase2', 'phase2', 'phase1', 'phase1', 'phase2', 'phase2'],
    'col': [0, 1, 0, 1, 0, 1, 0, 1],
    'value': [38.0, 62.0, 54.0, 46.0, 37.0, 63.0, 41.0, 59.0],
    'counts': [18, 18, 13, 13, 94, 94, 89, 89]
}
df = pd.DataFrame(data)

# 绘制基础堆叠条形图
fig = px.bar(df, x='cluster_phase1', y='value', color='col',
             facet_row='group', facet_col='phase',
             text='value', title='L')
fig.for_each_annotation(lambda a: a.update(text=a.text.split("=")[-1]))

# 遍历每个trace,设置对应条形的透明度
for trace in fig.data:
    # 提取当前trace对应的col值
    col_val = int(trace.name)
    # 从trace的坐标轴信息匹配facet的group和phase
    xaxis = trace.xaxis.split('-')[0] if '-' in trace.xaxis else trace.xaxis
    yaxis = trace.yaxis.split('-')[0] if '-' in trace.yaxis else trace.yaxis
    phase = 'phase1' if xaxis == 'x' else 'phase2'
    group = 'Control' if yaxis == 'y' else 'Test'
    
    # 筛选对应的数据行
    mask = (df['col'] == col_val) & (df['group'] == group) & (df['phase'] == phase)
    counts = df.loc[mask, 'counts'].values
    
    # 为每个点设置透明度
    trace.marker.opacity = [0.2 if c < 20 else 1.0 for c in counts]

fig.show()

方法2:设置为灰色

通过在DataFrame中添加自定义颜色列,直接指定counts <20的条形为灰色:

import plotly.express as px
import pandas as pd

# 初始化数据(可替换为测试用更新数据)
data = {
    'user_type': ['L', 'L', 'L', 'L', 'L', 'L', 'L', 'L'],
    'cluster_phase1': ['A', 'A', 'A', 'A', 'A', 'A', 'A', 'A'],
    'group': ['Control', 'Control', 'Control', 'Control', 'Test', 'Test', 'Test', 'Test'],
    'phase': ['phase1', 'phase1', 'phase2', 'phase2', 'phase1', 'phase1', 'phase2', 'phase2'],
    'col': [0, 1, 0, 1, 0, 1, 0, 1],
    'value': [38.0, 62.0, 54.0, 46.0, 37.0, 63.0, 41.0, 59.0],
    'counts': [18, 18, 13, 13, 94, 94, 89, 89]
}
df = pd.DataFrame(data)

# 添加自定义颜色列:counts<20设为灰色,否则用默认的Plotly定性色
df['custom_color'] = df.apply(
    lambda row: 'gray' if row['counts'] < 20 else px.colors.qualitative.Plotly[row['col']],
    axis=1
)

# 绘图时指定自定义颜色
fig = px.bar(df, x='cluster_phase1', y='value', color='custom_color',
             facet_row='group', facet_col='phase',
             text='value', title='L', color_discrete_map='identity')
fig.for_each_annotation(lambda a: a.update(text=a.text.split("=")[-1]))

fig.show()

原代码无效原因

原代码使用的selector=f"x[{i + 1}]"不符合Plotly的trace选择器语法,且facet布局下每个trace对应特定col值在某个facet中的所有条形,无法通过简单的索引定位到单个条形。上述方法通过匹配trace对应的分组信息,精准定位到每个数据行并设置样式。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 20:22:03