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

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

问题原因

  1. 初始px.bar生成的图表x轴仅包含第一个筛选结果中的make_model,后续add_bar添加的轨迹如果x轴类别不全或顺序不一致,Plotly的group模式无法正确对齐,导致柱状图叠加。
  2. 手动添加轨迹时,没有保证每个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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 17:51:09