Search code examples
pythonplotlydata-visualizationstacked-bar-chart

How to plot Stacked Bar Chart with Text Overlay with Plotly in Python?


I'm trying to plot a Stacked Bar Chart with Text Overlay with Plotly in Python. Like the below one

enter image description here

Sample Data

Fail_Word Fail_Count Pass_Word Pass_Count
properly 48 michigan 9
fraudulent 64 bodily 39
train 41 unauthorized 28
eos 42 insufficient 28
inaccurate 42 decision 8
strategy 41 program 18
escalate 14 inability 96
report 124 actuarial 128
register 14 account 86
applicable 42 annual 88

I have tried the below code

import plotly.graph_objects as go

fig = go.Figure()
fig.add_trace(go.Bar(
    y=["Fail"],
    x=word_tr["Fail_Count"].to_list(),
    name="Fail",
    orientation='h',
    
))
fig.add_trace(go.Bar(
    y=["Pass"],
    x=word_tr["Pass_Count"].to_list(),
    name="Pass",
    orientation='h',
    
))

fig.update_layout(barmode='stack')
fig.show()

enter image description here

For Fail bar, I want to add Fail_Word and Fail_Count as stacked bar, similarly for Pass ---> Pass_Word and Pass_Count.

But could not be able to generate the required Stacked Bar Chart with Text Overlay plot. Can someone shed some light on how to plot a Stacked Bar Chart with Text Overlay in plotly?


Solution

    • primarily this is restructuring dataframe so that it is well structured for Plotly Express
    index level_1 Count Word Percent
    7 Fail 124 report 0.262712
    1 Fail 64 fraudulent 0.135593
    0 Fail 48 properly 0.101695
    3 Fail 42 eos 0.0889831
    4 Fail 42 inaccurate 0.0889831
    • then define x, y, color and text
    • finally update texttemplate
    • have excluded small contributors as there is insufficient space in figure to show text
    import io
    import pandas as pd
    import plotly.express as px
    
    df = pd.read_csv(
        io.StringIO(
            """Fail_Word,Fail_Count,Pass_Word,Pass_Count
    properly,48,michigan,9
    fraudulent,64,bodily,39
    train,41,unauthorized,28
    eos,42,insufficient,28
    inaccurate,42,decision,8
    strategy,41,program,18
    escalate,14,inability,96
    report,124,actuarial,128
    register,14,account,86
    applicable,42,annual,88"""
        )
    )
    
    # restructure dataframe for plotting
    df2 = (
        pd.wide_to_long(
            df.reset_index(),
            stubnames=["Fail", "Pass"],
            i="index",
            j="data",
            sep="_",
            suffix="\\w+",
        )
        .stack()
        .unstack(1)
        .reset_index()
        .sort_values(["level_1", "Count"], ascending=[1, 0])
        .groupby("level_1", as_index=False)
        .apply(lambda d: d.assign(Percent=d["Count"] / d["Count"].sum()))
    )
    
    fig = px.bar(
        df2.loc[df2["Percent"].gt(0.05)],
        y="level_1",
        x="Percent",
        color="level_1",
        orientation="h",
        text="Word",
    )
    fig.update_traces(texttemplate="%{text}<br>%{x:.1%}")
    fig.update_layout(yaxis_title="", legend_title="", xaxis_tickformat=".0%")
    

    enter image description here