如何为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()
关键说明
- 合并数据:将两年数据合并后,通过
animation_frame='year'让Plotly自动为每个年份生成独立trace,trace名称会包含年份标识(如full_pallet=2023)。 - 下拉菜单逻辑:每个下拉按钮通过
args控制对应年份trace的visible属性,实现显示/隐藏切换。 - 默认显示:初始化时仅显示2023年的trace,保持与原代码初始行为一致。
内容的提问来源于stack exchange,提问作者Péter Hrubos
相关产品推荐
相关产品推荐

