Bars won't align on x axis

Here’s a full example code you can run.
The goal is to make the “makeStacked” plot align on the x-axis.

import pandas as pd
import plotly.express as px
import plotly.graph_objects as go


# Create plotly figure from params
def make_figure(df2=None, makeStacked=False, debug=True) -> go.Figure:

    if debug:
        data = {
            'Dummy': [0, 0],
            'Field': ['Category', 'Category'],
            'Group': ['Misc', 'Food'],
            'Amount': [-778.69, -589.71],
            'Budget': [-500, -500],
            'Percent': [155.738, 117.942],
            'Margin': [278.69, 89.71],
            'Color': ['#D62728', '#D62728'],
        }
        df_test = pd.DataFrame(data)
        print('df_test=\n', df_test)
        df2 = df_test.copy()

    # figure
    fig = go.Figure()

    # Whether plot is stacked or grouped
    if makeStacked:
        x = df2['Dummy']
        opacity = 0.5
        title = 'Budget (Stacked)'
        x_title = ''
        barmode_budget = 'relative'  # 'group', 'overlay' or 'relative' (default 'relative')
        barmode_data = 'relative'  # 'group', 'overlay' or 'relative' (default 'relative')
        barmode_fig = 'overlay'  # 'stack', 'relative', 'group', 'overlay' (default 'relative'?)

        # budget
        fig1 = px.bar(
            data_frame=df2,
            x=x,
            y=df2['Budget'],
            custom_data=['Group', 'Budget', 'Percent', 'Margin'],
            opacity=opacity,
            barmode=barmode_budget,  # 'group', 'overlay' or 'relative' (default 'relative')
        ).update_traces(
            width=0.8,
            hovertemplate="<br>".join([
                "Group: %{customdata[0]}",
                "Budget: $%{customdata[1]:.0f}",
            ]),
            # hovertemplate=None,
            # hoverinfo='skip'
        )
        fig1.data[0]['showlegend'] = True
        fig1.data[0]['name'] = 'Budget'
        fig1.data[0]['hoverlabel'].namelength = 0

        # data
        fig2 = px.bar(
            data_frame=df2,
            x=x,
            y=df2['Amount'],
            custom_data=['Group', 'Budget', 'Percent', 'Margin'],
            # barmode=barmode_data,  # 'group', 'overlay' or 'relative' (default 'relative')
        ).update_traces(
            width=0.7,
            marker_color=df2['Color'],
            hovertemplate="<br>".join([
                "Group: %{customdata[0]}",
                "Amount: $%{y:.0f}",
                "Budget: $%{customdata[1]:.0f}",
                "Percent: %{customdata[2]:.1f}%",
                "Margin: $%{customdata[3]:.0f}",
            ]),
        )
        # fig2.update_layout(barmode=barmode_data)
        fig2.data[0]['showlegend'] = True
        fig2.data[0]['name'] = 'Data'
        fig2.data[0]['hoverlabel'].namelength = 0

        # add figs to chart
        fig.add_traces([fig1.data[0], fig2.data[0]])

        # layout
        fig.update_layout(
            title=title,
            title_x=0.5,
            xaxis_title=x_title,
            yaxis_title='Amount',
            showlegend=True,
            # barmode=barmode_fig,  # 'stack', 'relative', 'group', 'overlay' (default 'relative'?)
        )

        return fig

        # below is good
    else:
        x = df2['Group']
        opacity = 0.5
        title = 'Budget (Grouped)'
        x_title = 'Group'
        barmode_budget = 'relative'  # 'group', 'overlay' or 'relative' (default 'relative')
        barmode_data = 'relative'  # 'group', 'overlay' or 'relative' (default 'relative')
        barmode_fig = 'overlay'  # 'stack', 'relative', 'group', 'overlay' (default 'relative'?)

        # budget
        fig1 = px.bar(
            data_frame=df2,
            x=x,
            y=df2['Budget'],
            custom_data=['Group', 'Budget', 'Percent', 'Margin'],
            opacity=opacity,
            barmode=barmode_budget,  # 'group', 'overlay' or 'relative' (default 'relative')
        ).update_traces(
            width=0.8,
            hovertemplate="<br>".join([
                "Group: %{customdata[0]}",
                "Budget: $%{customdata[1]:.0f}",
            ]),
            # hovertemplate=None,
            # hoverinfo='skip'
        )
        fig1.data[0]['showlegend'] = True
        fig1.data[0]['name'] = 'Budget'
        fig1.data[0]['hoverlabel'].namelength = 0

        # data
        fig2 = px.bar(
            data_frame=df2,
            x=x,
            y=df2['Amount'],
            custom_data=['Group', 'Budget', 'Percent', 'Margin'],
            barmode=barmode_data,  # 'group', 'overlay' or 'relative' (default 'relative')
        ).update_traces(
            width=0.7,
            marker_color=df2['Color'],
            hovertemplate="<br>".join([
                "Group: %{customdata[0]}",
                "Amount: $%{y:.0f}",
                "Budget: $%{customdata[1]:.0f}",
                "Percent: %{customdata[2]:.1f}%",
                "Margin: $%{customdata[3]:.0f}",
            ]),
        )
        # fig2.update_layout(barmode=barmode_data)
        fig2.data[0]['showlegend'] = True
        fig2.data[0]['name'] = 'Data'
        fig2.data[0]['hoverlabel'].namelength = 0

        # add figs to chart
        fig.add_traces([fig1.data[0], fig2.data[0]])

        # layout
        fig.update_layout(
            title=title,
            title_x=0.5,
            xaxis_title=x_title,
            yaxis_title='Amount',
            showlegend=True,
            barmode=barmode_fig,  # 'stack', 'relative', 'group', 'overlay' (default 'relative'?)
        )

        return fig


# test
# fig = make_figure(makeStacked=False)
# fig.show()

fig = make_figure(makeStacked=True)
fig.show()

I found these settings worked for the “Grouped” (makeStacked=False) plot in all cases, so I think that part is resolved:

barmode_budget = ‘relative’
barmode_data = ‘relative’
barmode_fig = ‘overlay’

However the same settings cause the “Budget” trace to overlap on itself, when it should be stacked (relative.) Example below:

Good: both blue and red bars are stacked on each other.
Bad: Red bars should be overlaid on top of blue, not staggered.

Good: Traces are overlaid
Bad: Blue ‘Budget’ bars are not stacked correctly–they appear to be overlaid on themselves.