Plotly Express柱状图叠加问题:Dash应用多轨迹图表重叠修复求助
Dash柱状图叠加重叠问题解决方案
问题背景
开发Dash应用时,通过过滤数据绘制柱状图,添加额外轨迹后图表出现叠加重叠情况,循环内直接生成图表会报错。
原代码
def filter_dataframe(selected_racetracks, selected_bops): filtered_df = df_bop.copy() # Initialize with original DataFrame # Perform data filtering based on left-hand side filter filtered_df = filtered_df.loc[(filtered_df['racetrack'] == selected_racetracks[0])] # Check if selected_bops is None or empty list if not selected_bops[0] is None: filtered_df = filtered_df[filtered_df['bop'] == selected_bops[0]] # Get the first racetrack from the list racetrack_str = selected_racetracks[0] if selected_racetracks else None # Check if the filtered DataFrame is empty if filtered_df.empty: # Return an empty figure if the filtered DataFrame is empty return {'data': [], 'layout': {}} # ==================== Figure 1 ================================ fig_weight = px.bar( filtered_df, x='make_model', y='total_weight_wo_driver', barmode='group', color='bop_date', template="plotly_dark", text="total_weight_wo_driver", ) # Additional traces for the second and third rows of filters for racetrack, bop in zip(selected_racetracks[1:], selected_bops[1:]): if racetrack and bop: filtered_df_additional = df_bop[(df_bop['racetrack'] == racetrack) & (df_bop['bop'] == bop)] date_string = datetime.strptime(filtered_df_additional['bop_date'].unique()[0], '%Y.%m.%d').strftime('%Y.%m.%d') bar_text = filtered_df_additional['total_weight_wo_driver'] if not filtered_df_additional.empty: fig_weight.add_bar( x=filtered_df_additional['make_model'], y=filtered_df_additional['total_weight_wo_driver'], name=date_string, # set trace name text=bar_text ) fig_weight.update_xaxes( tickangle=-70) fig_weight.update_layout( title_text=racetrack_str + " BOP total weight evolution", title_xanchor="left", barmode='group', yaxis_range=[1200, 1400], height=600, title_font=dict(size=24) ) return fig_weight
问题原因
- 初始
px.bar生成的图表x轴仅包含第一个筛选结果中的make_model,后续add_bar添加的轨迹如果x轴类别不全或顺序不一致,Plotly的group模式无法正确对齐,导致柱状图叠加。 - 手动添加轨迹时,没有保证每个trace的x轴维度完全匹配,引发布局错位。
解决方案
方案一:合并数据后一次性生成图表(推荐)
将所有符合筛选条件的数据合并到一个DataFrame,用px.bar一次性生成,让Plotly自动处理分组对齐,代码更简洁且不易出错。
修改后代码:
import pandas as pd import plotly.express as px def filter_dataframe(selected_racetracks, selected_bops): combined_df = pd.DataFrame() # 遍历所有筛选条件,收集有效数据 for racetrack, bop in zip(selected_racetracks, selected_bops): if not racetrack or bop is None: continue filtered = df_bop[(df_bop['racetrack'] == racetrack) & (df_bop['bop'] == bop)] if not filtered.empty: # 添加批次标识,用于区分不同筛选条件的数据 batch_name = f"{racetrack} - {pd.to_datetime(filtered['bop_date'].unique()[0]).strftime('%Y.%m.%d')}" filtered['batch'] = batch_name combined_df = pd.concat([combined_df, filtered], ignore_index=True) if combined_df.empty: return {'data': [], 'layout': {}} # 一次性生成分组柱状图 fig_weight = px.bar( combined_df, x='make_model', y='total_weight_wo_driver', color='batch', barmode='group', template="plotly_dark", text="total_weight_wo_driver", title=f"{selected_racetracks[0]} BOP total weight evolution" ) fig_weight.update_xaxes(tickangle=-70) fig_weight.update_layout( title_xanchor="left", yaxis_range=[1200, 1400], height=600, title_font=dict(size=24) ) return fig_weight
方案二:对齐所有轨迹的x轴类别
如果需要保留add_bar的方式,需确保每个trace的x轴包含所有make_model类别,缺失值补0或NaN,且顺序一致。
修改后代码片段:
import pandas as pd import plotly.express as px from datetime import datetime def filter_dataframe(selected_racetracks, selected_bops): filtered_df = df_bop.copy() filtered_df = filtered_df.loc[(filtered_df['racetrack'] == selected_racetracks[0])] if not selected_bops[0] is None: filtered_df = filtered_df[filtered_df['bop'] == selected_bops[0]] racetrack_str = selected_racetracks[0] if selected_racetracks else None if filtered_df.empty: return {'data': [], 'layout': {}} # 获取全量make_model列表,确保顺序一致 all_models = df_bop['make_model'].unique().tolist() # 对齐初始数据的x轴 filtered_df_full = filtered_df.set_index('make_model').reindex(all_models).fillna(0).reset_index() fig_weight = px.bar( filtered_df_full, x='make_model', y='total_weight_wo_driver', barmode='group', color='bop_date', template="plotly_dark", text="total_weight_wo_driver", ) # 循环添加轨迹时对齐x轴 for racetrack, bop in zip(selected_racetracks[1:], selected_bops[1:]): if racetrack and bop: filtered_df_additional = df_bop[(df_bop['racetrack'] == racetrack) & (df_bop['bop'] == bop)] if not filtered_df_additional.empty: # 对齐x轴类别,缺失值补0 filtered_additional_full = filtered_df_additional.set_index('make_model').reindex(all_models).fillna(0).reset_index() date_string = datetime.strptime(filtered_df_additional['bop_date'].unique()[0], '%Y.%m.%d').strftime('%Y.%m.%d') fig_weight.add_bar( x=filtered_additional_full['make_model'], y=filtered_additional_full['total_weight_wo_driver'], name=date_string, text=filtered_additional_full['total_weight_wo_driver'] ) fig_weight.update_xaxes(tickangle=-70) fig_weight.update_layout( title_text=racetrack_str + " BOP total weight evolution", title_xanchor="left", barmode='group', yaxis_range=[1200, 1400], height=600, title_font=dict(size=24) ) return fig_weight
内容的提问来源于stack exchange,提问作者Andrei Filep
相关产品推荐
相关产品推荐

