On , I learned ...

To create stacked and grouped bar charts

I want to create stacked bar charts (duh, this is the best kind), but I also want them grouped. This proved more difficult than I first expected. Example code as follows:


import pandas as pd
import plotly.graph_objects as go

# Sample data
data = {
    "period": ["2024-01-01", "2024-01-01", "2024-01-01", "2024-01-01",
               "2024-02-01", "2024-02-01", "2024-02-01", "2024-02-01"],
    "user_group": ["new", "new", "super-user", "super-user",
                   "new", "new", "super-user", "super-user"],
    "type": ["really new", "kind of new", "employee", "experienced",
             "really new", "kind of new", "employee", "experienced"],
    "count": [100, 40, 50, 70, 90, 30, 70, 120]
}

df = pd.DataFrame(data)

# Create the figure with layout
fig = go.Figure(
    layout=go.Layout(
        barmode="relative",  # Bars stacked within user groups
        xaxis=dict(type="category", title="Date"),
        yaxis=dict(title="Count", range=[0, 200]),
        yaxis2=go.layout.YAxis(visible=False, matches="y", overlaying="y", anchor="x"),  # Invisible secondary y-axis
        legend=dict(x=1.1, y=1, orientation="v")  # Legend placed to the right
    )
)

bar_width = 0.3

# Define y-axis and offset for each user group
y_axis_dict = {
    "new": {"yaxis": 'y1', "offset": 0},
    "super-user": {"yaxis": 'y2', "offset": -bar_width}
}

# Add bars for each user group and type
for user_group in df['user_group'].unique():
    group_data = df[df['user_group'] == user_group]

    for type_value in group_data['type'].unique():
        type_data = group_data[group_data['type'] == type_value]

        fig.add_bar(
            x=type_data['period'],
            y=type_data['count'],
            yaxis=y_axis_dict[user_group]["yaxis"],
            offset=y_axis_dict[user_group]["offset"],
            offsetgroup=user_group,
            width=bar_width,
            name=str(type_value),
            legendgroup=user_group,
            legendgrouptitle_text=user_group
        )

# Display the figure
fig.show()