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

Plotly分组堆叠条形图过滤后浮动条问题的修复咨询

分组堆叠条形图过滤后浮动条问题解决方法

问题背景

使用以下Plotly代码生成分组堆叠条形图:

from plotly import graph_objects as go

data = {
    "left": [
        {"original": 15, "model_1": 4, "model_2": 11},
        {"original": 23, "model_1": 8, "model_2": 18},
        {"original": 32, "model_1": 18, "model_2": 18},
        {"original": 10, "model_1": 6, "model_2": 0},
        {"original": 23, "model_1": 0, "model_2": 20}
    ],
    "right": [
        {"original": 7, "model_1": 3, "model_2": 5},
        {"original": 12, "model_1": 6, "model_2": 8},
        {"original": 15, "model_1": 8, "model_2": 10},
        {"original": 5, "model_1": 4, "model_2": 0},
        {"original": 10, "model_1": 2, "model_2": 12}
    ],
    "labels": [
        "feature",
        "question",
        "bug",
        "documentation",
        "maintenance"
    ]
}

fig = go.Figure()

colors = {
    "original": "#636EFA",
    "model_1": "#EF553B",
    "model_2": "#00CC96"
}

def add_stacked_bar(side, offset_group):
    side_data = data[side]
    for i, category in enumerate(data["labels"]):
        current_base = 0
        for model_type in ["original", "model_1", "model_2"]:
            value = side_data[i].get(model_type, 0)
            if value > 0:
                fig.add_trace(go.Bar(
                    name=f"{model_type.replace('_', ' ').title()} ({side.title()})",
                    x=[category],
                    y=[value],
                    offsetgroup=offset_group,
                    base=current_base,
                    marker_color=colors[model_type],
                    legendgroup=model_type,
                    showlegend=(i == 0)
                ))
                current_base += value

add_stacked_bar("left", 0)
add_stacked_bar("right", 1)

fig.update_layout(
    title="Issue Types - Original and Models",
    yaxis_title="Number of Issues",
    barmode='group',
    legend_title="Model Types",
    legend=dict(
        orientation="h",
        yanchor="bottom",
        y=1.02,
        xanchor="right",
        x=1
    )
)

对图表进行过滤操作后,出现浮动条现象。尝试将barmode改为stack未解决问题;改为stack并注释base = current_base语句虽解决浮动条,但丢失了分组堆叠的原有样式。需要找到方法在过滤后重新计算base参数,兼顾问题修复与原有图表样式。

解决方案核心

过滤后浮动条的根源是:原有base值基于所有trace都显示的情况计算,当部分trace被隐藏后,剩余trace的base未更新,导致堆叠位置错误。解决思路是:针对每个offsetgroup(分组)和每个类别,根据当前显示状态的trace重新累加计算base值。

具体实现代码

以下是添加过滤逻辑和重新计算base的完整代码示例:

from plotly import graph_objects as go

# 原始数据
data = {
    "left": [
        {"original": 15, "model_1": 4, "model_2": 11},
        {"original": 23, "model_1": 8, "model_2": 18},
        {"original": 32, "model_1": 18, "model_2": 18},
        {"original": 10, "model_1": 6, "model_2": 0},
        {"original": 23, "model_1": 0, "model_2": 20}
    ],
    "right": [
        {"original": 7, "model_1": 3, "model_2": 5},
        {"original": 12, "model_1": 6, "model_2": 8},
        {"original": 15, "model_1": 8, "model_2": 10},
        {"original": 5, "model_1": 4, "model_2": 0},
        {"original": 10, "model_1": 2, "model_2": 12}
    ],
    "labels": [
        "feature",
        "question",
        "bug",
        "documentation",
        "maintenance"
    ]
}

colors = {
    "original": "#636EFA",
    "model_1": "#EF553B",
    "model_2": "#00CC96"
}

fig = go.Figure()

def add_stacked_bar(side, offset_group):
    side_data = data[side]
    for i, category in enumerate(data["labels"]):
        current_base = 0
        for model_type in ["original", "model_1", "model_2"]:
            value = side_data[i].get(model_type, 0)
            if value > 0:
                fig.add_trace(go.Bar(
                    name=f"{model_type.replace('_', ' ').title()} ({side.title()})",
                    x=[category],
                    y=[value],
                    offsetgroup=offset_group,
                    base=current_base,
                    marker_color=colors[model_type],
                    legendgroup=model_type,
                    showlegend=(i == 0)
                ))
                current_base += value

add_stacked_bar("left", 0)
add_stacked_bar("right", 1)

fig.update_layout(
    title="Issue Types - Original and Models",
    yaxis_title="Number of Issues",
    barmode='group',
    legend_title="Model Types",
    legend=dict(
        orientation="h",
        yanchor="bottom",
        y=1.02,
        xanchor="right",
        x=1
    )
)

# 定义过滤后重新计算base的函数
def update_base_after_filter():
    # 按offsetgroup和x类别分组整理trace
    grouped_traces = {}
    for trace in fig.data:
        key = (trace.offsetgroup, trace.x[0])
        if key not in grouped_traces:
            grouped_traces[key] = []
        # 只保留显示的trace
        if trace.visible:
            grouped_traces[key].append(trace)
    
    # 对每组trace按堆叠顺序(original -> model_1 -> model_2)排序
    stack_order = ["original", "model_1", "model_2"]
    for key in grouped_traces:
        # 根据trace名称中的模型类型排序
        grouped_traces[key].sort(
            key=lambda t: stack_order.index(t.name.split(" ")[0].lower().replace(" ", "_"))
        )
        # 重新计算base
        current_base = 0
        for trace in grouped_traces[key]:
            trace.base = current_base
            current_base += trace.y[0]

# 示例:过滤掉model_1的所有trace
for trace in fig.data:
    if "Model 1" in trace.name:
        trace.visible = False

# 过滤后更新base
update_base_after_filter()

fig.show()

关键说明

  1. 分组整理trace:将trace按offsetgroup(左右分组)和x类别(issue类型)分组,确保每个分组内的trace属于同一类别和同一侧。
  2. 排序trace:按照原始堆叠顺序(original -> model_1 -> model_2)对分组内的trace排序,保证堆叠层级正确。
  3. 重新计算base:遍历排序后的trace,累加y值更新base,确保每个堆叠条的底部位置是前一个显示条的顶部。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 07:07:02