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

如何为Plotly Express堆叠柱状图添加年份选择下拉菜单?

实现带年份下拉菜单的Plotly堆叠柱状图

第一步:修正数据并合并

先修正原始代码中data_2024创建的错误(原代码误用未定义的data变量),再将两个年份的DataFrame合并,统一处理数据:

import pandas as pd
import plotly.express as px

# 2023年数据
data_2023 = {
    'country': ['CE', 'CE', 'CE', 'CE', 'CE', 'CZ', 'CZ', 'CZ', 'CZ', 'CZ', 'HU', 'HU', 'HU', 'HU', 'HU', 'SK', 'SK', 'SK', 'SK', 'SK'],
    'category': ['BABY']*20,
    'repl_types': ['full_pallet', 'mu', 'nsrp', 'split_pallet', 'srp']*4,
    'period': ['p11']*20,
    'value': [137.0, 0.0, 79686.0, 76.0, 86973.0,
              137.0, 0.0, 23453.0, 76.0, 34163.0,
              0.0, 0.0, 34060.0, 0.0, 23228.0,
              0.0, 0.0, 22173.0, 0.0, 29582.0],
    'value_%': [0.000821, 0.0, 0.477528, 0.000455, 0.521196,
                0.002369, 0.0, 0.405558, 0.001314, 0.590759,
                0.0, 0.0, 0.594540, 0.0, 0.405460,
                0.0, 0.0, 0.428422, 0.0, 0.571578],
    'year': [2023]*20,
}
df_2023 = pd.DataFrame(data_2023)

# 2024年数据(修正创建错误)
data_2024_dict = {
    'country': ['CE', 'CE', 'CE', 'CE', 'CE', 'CZ', 'CZ', 'CZ', 'CZ', 'CZ', 'HU', 'HU', 'HU', 'HU', 'HU', 'SK', 'SK', 'SK', 'SK', 'SK'],
    'category': ['BABY']*20,
    'repl_types': ['full_pallet', 'mu', 'nsrp', 'split_pallet', 'srp']*4,
    'period': ['p11']*20,
    'value': [100000, 0, 50000, 0, 140000,
              50000, 0, 70000, 0, 100000,
              0, 0, 80000, 0, 50000,
              0, 0, 90000, 0, 60000],
}
df_2024 = pd.DataFrame(data_2024_dict)
df_2024['value_%'] = df_2024.groupby('country')['value'].apply(lambda x: x / x.sum())
df_2024['year'] = 2024

# 合并两年数据
df = pd.concat([df_2023, df_2024], ignore_index=True)

第二步:绘制带下拉菜单的堆叠柱状图

利用Plotly的updatemenus配置下拉菜单,通过控制不同年份trace的显示/隐藏实现数据切换:

# 遍历每个分类(此处仅BABY分类)
for category in df['category'].unique():
    # 绘制包含所有年份的堆叠柱状图
    fig = px.bar(
        df[df['category'] == category],
        x="period",
        y="value_%",
        color='repl_types',
        barmode='stack',
        facet_col='country',
        text_auto='.0%',
        color_discrete_sequence=["#5497c7", "green", "#c74848", "goldenrod", "#5f48c7"],
        opacity=0.8,
        facet_row_spacing=0.08,
        height=400,
        width=1800,
        category_orders={"country": ["CZ", "HU", "SK", "CE"]},
        title=f"<b>{category}</b>",
        facet_col_wrap=5,
        orientation='v',
        # 按年份区分trace,便于后续控制显示
        animation_frame='year'
    )

    # 保留原代码的样式设置
    fig.update_traces(textfont_size=12, textangle=0, textposition="auto", cliponaxis=False)
    fig.update_yaxes(matches=None)
    fig.for_each_annotation(lambda a: a.update(text=a.text.split("=")[-1], font_size=18))
    fig.update_yaxes(title_font_color='white')
    for annotation in fig['layout']['annotations']:
        annotation['textangle'] = 0
    fig.update_layout(
        legend=dict(
            orientation="h",
            yanchor="bottom",
            y=1.1,
            xanchor="right",
            x=1.1
        )
    )

    # 替换默认动画控件为下拉菜单
    fig.update_layout(
        updatemenus=[
            dict(
                type="dropdown",
                direction="down",
                x=0.05,
                y=1.2,
                buttons=[
                    dict(
                        label="2023",
                        method="update",
                        args=[
                            {"visible": [trace.name.endswith("2023") for trace in fig.data]},
                            {"title": f"<b>{category} - 2023</b>"}
                        ]
                    ),
                    dict(
                        label="2024",
                        method="update",
                        args=[
                            {"visible": [trace.name.endswith("2024") for trace in fig.data]},
                            {"title": f"<b>{category} - 2024</b>"}
                        ]
                    ),
                    dict(
                        label="全部年份",
                        method="update",
                        args=[
                            {"visible": [True]*len(fig.data)},
                            {"title": f"<b>{category} - 全部年份</b>"}
                        ]
                    )
                ]
            )
        ]
    )

    # 默认显示2023年数据,与原代码初始行为一致
    fig.update_layout(title_text=f"<b>{category} - 2023</b>")
    for i, trace in enumerate(fig.data):
        fig.data[i].visible = trace.name.endswith("2023")

    fig.show()

关键说明

  1. 合并数据:将两年数据合并后,通过animation_frame='year'让Plotly自动为每个年份生成独立trace,trace名称会包含年份标识(如full_pallet=2023)。
  2. 下拉菜单逻辑:每个下拉按钮通过args控制对应年份trace的visible属性,实现显示/隐藏切换。
  3. 默认显示:初始化时仅显示2023年的trace,保持与原代码初始行为一致。

内容的提问来源于stack exchange,提问作者Péter Hrubos

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 01:12:03