Stacked and grouped bars in same chart

Hi,

Iโ€™m new to plotly. And Iโ€™m impressed by itโ€™s elegance and efficiency especially of plotly express.

Now I cannot find a solution to use this efficiency to create a chart of grouped and stacked bars. I have a dataset with one value and 4 dimensions. So the value is Y. Dim 1 is the timeline. Dim 2 and 3 are actually cumulative. So they are stacked. Dim 2 is identified by color and dim 3 by pattern. Dim 4 are the classes which I wand to compare with each other. So it should define the groups.

I implemented it with low level API. But this is quite complicated, and instable to variations of the scenarios. I tried to manipulate the figures created with px (offsetgroups, xaxis and domains) but without success.

Any suggestions?

Thx, m

Here some code to demonstrate what I already tried.

This works, but with facets instead of groups:

import pandas as pd
import numpy as np
import plotly.express as px
df = pd.DataFrame(index=pd.MultiIndex.from_product([
            pd.date_range(start="2022-01", end="2022-12", freq="MS"),
            ["A", "B", "C", "D", "E", "F"],
            ["a", "b", "c"],
            ["plan", "actual"],
        ], names=["dim1", "dim2", "dim3", "dim4"])).reset_index()
df["value"]=np.random.random(len(df))

barsp = []
fig = px.bar(data_frame=df,
    x=df.dim1, 
    y=df.value,
    color=df.dim2,
    pattern_shape=df.dim3,
    facet_row=df.dim4,
    )
fig.show()

This does produces errors:

import pandas as pd
import numpy as np
import plotly.express as px
df = pd.DataFrame(index=pd.MultiIndex.from_product([
            pd.date_range(start="2022-01", end="2022-12", freq="MS"),
            ["A", "B", "C", "D", "E", "F"],
            ["a", "b", "c"],
            ["plan", "actual"],
        ], names=["dim1", "dim2", "dim3", "dim4"])).reset_index()
df["value"]=np.random.random(len(df))

fig = px.bar(data_frame=df, x=np.stack([df.loc[df.dim4==v, "dim1"] for v in df["dim4"].unique()]), 
    y=np.stack([df.loc[df.dim4==v, "value"] for v in df["dim4"].unique()]),#.flatten(),
    # color=np.stack([df.loc[df.dim4==v, "dim2"] for v in df["dim4"].unique()]),#.flatten(),
    # pattern_shape=np.stack([df.loc[df.dim4==v, "dim3"] for v in df["dim4"].unique()]),#.flatten(),
    )
fig.show()

ValueError : Cannot accept list of column references or list of columns for both x and y.

If I flatten y then
ValueError : All arguments should have the same length. The length of argument wide_variable_0 is 216, whereas the length of previously-processed arguments [โ€˜yโ€™] is 432

The following code tries to patch and assemble traces created with px:

import pandas as pd
import numpy as np
import plotly.express as px
df = pd.DataFrame(index=pd.MultiIndex.from_product([
            pd.date_range(start="2022-01", end="2022-12", freq="MS"),
            ["A", "B", "C", "D", "E", "F"],
            ["a", "b", "c"],
            ["plan", "actual"],
        ], names=["dim1", "dim2", "dim3", "dim4"])).reset_index()
df["value"]=np.random.random(len(df))

barsp = []
for gi, gv in enumerate(df.dim4.unique()):
    barsp.append(dict(data_frame=df[df.dim4==gv], x="dim1", 
        y="value",
        color="dim2",
        pattern_shape="dim3",
        ))
fig = px.bar(**barsp[0])
fig.update_traces(xaxis="x1")
# print(fig["layout"])#.select_traces()))
step = 1./len(barsp)
for i, bp in enumerate(barsp[1:]):
    b = px.bar(**bp)
    fig.update_traces(xaxis=f"x{i+2}")
    for t in b.select_traces():
        fig.add_trace(t)
# for i in range(len(barsp)):
#     fig.update_layout(**{f"xaxis{i+1}":dict(***Is there something to patch here? anchor? ***)})
fig.show()

All traces are included in the legend. But the bars of one dim4 group is visible. They groups of dim4 are not even drawn over each other. Maybe the whole plotting area covers the other groups.

How can I make them all visible and give each group an x-offset?