plotly / plotly.py

The interactive graphing library for Python :sparkles: This project now includes Plotly Express!
https://plotly.com/python/
MIT License
16.23k stars 2.55k forks source link

Order of marginal wrong when using facet_col and setting traces to invisible by default #4438

Open beathvn opened 11 months ago

beathvn commented 11 months ago

I am creating a histogram plot using plotly express.histogram, like the following:

df = pd.DataFrame({
    'month': [5] * 30 + [6] * 30 + [7] * 30,
    'value': np.random.randint(0, 100, size=90),
    'Module': ['M', 'P']*45,
})

fig = px.histogram(
    df,
    x='value',
    opacity=0.8,
    color='month',
    category_orders={'month': df['month'].sort_values(ascending=True)},
    marginal='box',
    barmode='overlay',
    facet_col='Module',
)

for trace in fig.data:
    if int(trace.name) not in (7,6):
        trace.visible = "legendonly"

fig.show()

When I then want to show month 5 as well, the box in marginal is placed at the top of the others, giving the wrong order of month: 5, 7, 6 (red from top to bottom).

The problem does not appear when I don't use the facet_col argument, or when i show all month from the beginning (simply comment the part where i set trace.visible to legendonly).

plotly version: 5.18.0

Screenshot 2023-11-22 153608

beathvn commented 11 months ago

I tried to recreate the plot using plotly.graph_objects like this:

fig = make_subplots(rows=2, cols=2, row_heights=[1,2], shared_xaxes=True, shared_yaxes=False)

color_dict = {
    5: '#330C73',
    6: '#EB89B5',
    7: '#4F89B5',
}

for index_module, curr_module in enumerate(df.Module.unique()):
    for index_month, curr_month in enumerate(df.month.unique()):
        showlegend = True if index_module == 0 else False
        curr_col = index_module + 1
        fig.add_trace(
            go.Histogram(
                x=df[(df['month'] == curr_month) & (df.Module == curr_module)]['value'],
                name=str(curr_month),
                legendgroup=str(curr_month),
                showlegend=showlegend,
                marker_color=color_dict[curr_month],
            ),
            row=2,
            col=curr_col,
        )

        fig.add_trace(
            go.Box(
                x=df[(df['month'] == curr_month) & (df.Module == curr_module)]['value'],
                name=str(curr_month),
                legendgroup=str(curr_month),
                showlegend=False,
                marker_color=color_dict[curr_month],
            ),
            row=1,
            col=curr_col,
        )

for trace in fig.data:
    if int(trace.name) not in (7,6):
        trace.visible = "legendonly"

fig.update_layout(barmode='stack')

and the problem seems to be related to the together zooming: when i set shared_yaxes to True, the same issue described above occures. When it's set to False, everything works as expected