pythonplotplotly

Double bar stacked bar plot in plotly dash


I'm trying to create a double bar stacked bar chart using plotly.

I found this code:

from plotly import graph_objects as go

data = {
    "original":[15, 23, 32, 10, 23],
    "model_1": [4,   8, 18,  6,  0],
    "model_2": [11, 18, 18,  0,  20],
    "labels": [
        "feature",
        "question",
        "bug",
        "documentation",
        "maintenance"
    ]
}

fig = go.Figure(
    data=[
        go.Bar(
            name="Original",
            x=data["labels"],
            y=data["original"],
            offsetgroup=0,
        ),
        go.Bar(
            name="Model 1",
            x=data["labels"],
            y=data["model_1"],
            offsetgroup=1,
        ),
        go.Bar(
            name="Model 2",
            x=data["labels"],
            y=data["model_2"],
            offsetgroup=1,
            base=data["model_1"],
        )
    ],
    layout=go.Layout(
        title="Issue Types - Original and Models",
        yaxis_title="Number of Issues"
    )
)

enter image description here Source: https://dev.to/fronkan/stacked-and-grouped-bar-charts-using-plotly-python-a4p

This works, but I need to take it one step further if possible. I need the various models to able to appear on either side of each set of bars as I'm adding another parameter (yes on the left and no on the right). In the example, blue is always on the left bar and orange and/or green are always on the right. I'm looking for a way so that any of those colors could appear on both the left and right of a set of bars, but with different values. i.e. in the example feature has a blue bar count of 15, but maybe on the right side of feature blue has a value of 5.


Solution

  • you can use dynamic stacking with calculated base values and consistent color coding, maintaining exactly 10 bars -5 categories × 2 sides- while supporting variable component combinations per bar. also chekc this out stacked + grouped bar chart

    from plotly import graph_objects as go
    
    data = {
        "left": [
            {"original": 15, "model_1": 4, "model_2": 11},
            {"original": 23, "model_1": 8, "model_2": 18},
            {"original": 32, "model_1": 18, "model_2": 18},
            {"original": 10, "model_1": 6, "model_2": 0},
            {"original": 23, "model_1": 0, "model_2": 20}
        ],
        "right": [
            {"original": 7, "model_1": 3, "model_2": 5},
            {"original": 12, "model_1": 6, "model_2": 8},
            {"original": 15, "model_1": 8, "model_2": 10},
            {"original": 5, "model_1": 4, "model_2": 0},
            {"original": 10, "model_1": 2, "model_2": 12}
        ],
        "labels": [
            "feature",
            "question",
            "bug",
            "documentation",
            "maintenance"
        ]
    }
    
    fig = go.Figure()
    
    colors = {
        "original": "#636EFA",
        "model_1": "#EF553B",
        "model_2": "#00CC96"
    }
    
    def add_stacked_bar(side, offset_group):
        side_data = data[side]
        for i, category in enumerate(data["labels"]):
            current_base = 0
            for model_type in ["original", "model_1", "model_2"]:
                value = side_data[i].get(model_type, 0)
                if value > 0:
                    fig.add_trace(go.Bar(
                        name=f"{model_type.replace('_', ' ').title()} ({side.title()})",
                        x=[category],
                        y=[value],
                        offsetgroup=offset_group,
                        base=current_base,
                        marker_color=colors[model_type],
                        legendgroup=model_type,
                        showlegend=(i == 0)
                    ))
                    current_base += value
    
    add_stacked_bar("left", 0)
    add_stacked_bar("right", 1)
    
    fig.update_layout(
        title="Issue Types - Original and Models",
        yaxis_title="Number of Issues",
        barmode='group',
        legend_title="Model Types",
        legend=dict(
            orientation="h",
            yanchor="bottom",
            y=1.02,
            xanchor="right",
            x=1
        )
    )
    
    fig.show()
    

    enter image description here