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

