Can you create overlaying barcharts with the same x value as index

Hi all,

I wanted to created this chart:


and I got stuck with the overlay part.

In the end I used the Previous Year chart as a background-image for the Current chart (AC).
PY is generated when the image does not already exist, it took some experimenting.

I tried a lot to avoid this route, and still wonder, how can you accomplish an effect like this without using a background image and by creating two barcharts. Previous Year does not need tooltips. I tried stuff like a little shift for the previous year, to keep the current year exactly at the right spot on the x-axis.

code for this graph

def create_bar_ac_py(df_revenue_mom):  
    
    colors = {'AC': 'rgba(64,64,64,1)','PY':'rgba(166,166,166,1)' }
    # Define a small shift using Timedelta
    #shift = pd.Timedelta(days=3)  # Adjust as needed
    
    max_y = df_revenue_mom['revenue'].max()
    current_year = df_revenue_mom['Last_dayofmonth_Date'].dt.year.max()
    src_background = f"/assets/{current_year}_figPY.svg"

    
    
    figPY = go.Figure()
    
    
    
    # First bar trace (shift left)
    figPY.add_trace(go.Bar(
               x=df_revenue_mom['Last_dayofmonth_Date'],
               y=df_revenue_mom['revenue_py'], 
               #width=0.5,
               marker_color=colors.get('PY'),
               name='PY'
    ))
    
    #background needs to be transparent
    figPY.update_layout({
        'plot_bgcolor': 'rgba(0, 0, 0, 0)',
        'paper_bgcolor': 'rgba(0, 0, 0, 0)',
    })
    
    
    
    # Change the bar mode
    figPY.update_layout(bargap=0.2)
    figPY.update_layout(yaxis_title=None)
    figPY.update_yaxes(showticklabels=False)
    figPY.update_layout(xaxis_title=None)
    figPY.update_xaxes(showticklabels=False)
    figPY.update_layout(yaxis_range=[0,max_y])
    figPY.update_layout(
        margin=dict(l=0, r=0, t=0, b=0),
        width=800,
        height=300,
    )
    
    #solution stuck kaleido 2 on win11 : https://github.com/plotly/Kaleido/issues/126
    #writing an image dynamically triggers the callback function for a second time
    #pio.write_image(figPY, "assets/figPY.svg") 
    
    figAC = go.Figure()
    
    # Second bar trace (shift right)
    figAC.add_trace(go.Bar(
               x=df_revenue_mom['Last_dayofmonth_Date'], 
               y=df_revenue_mom['revenue'],  
               #width=0.5,
               marker_color=colors.get('AC'),
               name='AC',
               text=df_revenue_mom['revenue'],
               texttemplate = "%{y:,.3s}"
    ))
    
    
    
    
    # Change the bar mode
    #figAC.update_layout(bargap=0.2)
    
    #background needs to be transparent fo a see through to PY
    figAC.update_layout({
         'plot_bgcolor': 'rgba(0, 0, 0, 0)',
         'paper_bgcolor': 'rgba(0, 0, 0, 0)',
     })
    
    figAC.update_xaxes(showgrid=False, zeroline=False)
    figAC.update_yaxes(showgrid=False, zeroline=False)
    
    # Add images
    figAC.add_layout_image(
            dict(
                source=src_background,
                xref="paper", yref="paper",
                #x=1, y=1,
                x=-0.01, y=0, 
                sizex=1,
                sizey=1,
                xanchor="left",
                yanchor="bottom",
                opacity=1,
                layer="below",
                sizing="stretch")
    )
    
    figAC.update_layout(yaxis_title=None)
    figAC.update_yaxes(showticklabels=False)
    figAC.update_xaxes(
        dtick="M1",
        tickformat="%b")
        #ticklabelmode="period")
        
    figAC.update_layout(
        margin=dict(l=0, r=0, t=0, b=0),
        autosize=False,
        width=800,
        height=300,
        hovermode=False
    )
    figAC.update_traces(textfont_size=12, textangle=0, textposition="outside", cliponaxis=False)
    


    return dcc.Graph(figure = figAC)

Hey Iโ€™m not sure how to do this in plotly but Iโ€™ve been procrastinating making some vega gant charts and stumbled across the attached links that might be helpful.

Bar chart variance

Iโ€™ve managed to recreate some of the gant charts using dash-vega-components and they work! So Iโ€™m guessing the same could be true for the charts you want!

1 Like

In this case, two new x-axis arrays are prepared and placed on each. We can then give them the x-axis ticks they need as strings. I customized the Gapminder sample data appropriately.

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

data_canada = px.data.gapminder().query("country == 'Canada'")
data_argentina = px.data.gapminder().query("country == 'Argentina'")

colors = {'AC': 'rgba(64,64,64,1)','PY':'rgba(166,166,166,1)' }
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
offset = 0.1

fig = go.Figure()

fig.add_trace(go.Bar(
    x=[x for x in range(0,12,1)],
    y=data_canada['pop'],
    width=0.5,
    marker=dict(color=colors.get('PY')),
    name='PY'
))

fig.add_trace(go.Bar(
    x=[x+offset for x in range(0,12,1)],
    y=data_argentina['pop'],
    width=0.5,
    text=data_argentina['pop'],
    texttemplate='%{y:,.3s}',
    textposition='outside',
    marker=dict(color=colors.get('AC')),
    name='AC'
))
fig.update_xaxes(tickmode='array', tickvals=[x+offset for x in range(0,12,1)], ticktext=months)

fig.show()

1 Like

@Javadabbadoo , thank you for your answer and your solution does what I want, at least the example shows that it can. Two buts :slight_smile: , @r-beginners has a more native solution which Iโ€™m now going to try (and will work I suppose), and I did some experimenting with vega & vega lite in Powerbi (Deneb extension) , you can do everything but you have to define all your visuals as json instead of the more native approach and if possible I go for native. Maybe thatโ€™s different with dash-vega but it still occurs to me as making things more difficult than they need to be. Maybe Iโ€™m wrong.

Thank you @r-beginners , this is exactly what I was looking for!

1 Like

Hey! You are not wrong! Hence my procrastination :joy:.

I only explored it as I liked some of the gantt charts. Everything else was a bit of a pain to do / get working and much prefer staying in plotly etc!

1 Like