Black Lives Matter. Please consider donating to Black Girls Code today.
Learn about the upcoming Dash Enterprise 4.0 release in the August 5th webinar with Chris Parmer, the Inventor of Dash.

[Legend] Size or title padding

Hi,
I’m encoutering an issue with a legend: when created using plotly.express, it’s fine
image

When I do it by hand, the first trace overlaps with the legend title
image

Has anyone any idea how to replicate the plotly.express behavior ?

Can you provide the code you’re using when you’re not using Plotly Express?

Hi @nicolaskruchten,
Thanks for your reply. I’m using:

fig = go.Figure()
for possible_color in dataframe[color].unique():
    tmp_df = dataframe[dataframe[color] == possible_color]
    name = possible_color
    bar_trace = go.Bar(
        x=np.transpose(tmp_df[x].values),
        y=tmp_df[y].values,
        name=name)
    fig.add_trace(bar_trace)

The aim is to create a grouped stacked barchart, unavailable with plotly.express, as far as I known.
Everything works fine, except for the slight legend issue.

Interesting. I’m not seeing where you’re setting the legend title here at all?

I’m indeed no setting the legend title at all. It’s just there, I don’t really know why…
I do set the figure title, but remove the corresponding code, as it’s unrelevant here.

EDIT: Though it does seem far-fetched to me, maybe the legend title is kept by Dash (the plot is displayed by Dash) when the figure is changed. I feel like this could be an unexpected/unwanted behavior, but I’m going to investigate that.

The issue comes indeed from not setting the legend title. When updating a figure in Dash, the previous legend title is kept, but the current legend considers there is not title, thus overlaps it.

OK, that seems like it might be a bug then, but can you please share a bit more of your code so we can reproduce it? Is this a Dash app where you first create a figure with px and then update it with a figure created with graph_objects ? There might indeed be some “leftovers” but I’d need more information to confirm and fix it :slight_smile:

utils/create_grouped_stacked_barchart.py (fixed version):

import numpy as np
import plotly.graph_objects as go

def create_grouped_stacked_barchart(
        dataframe, x, y, color, customdata=None, hovertemplate=None,
        color_mapping=lambda x: x, fig=None, verbose=False, title=None,
        labels=None):
    """Create grouped stacked bar chart"""
    if fig is None:
        fig = go.Figure()
    if labels is None:
        labels = {}
    for possible_color in dataframe[color].unique():
        if verbose:
            print(possible_color)
        tmp_df = dataframe[dataframe[color] == possible_color]
        name = str(color_mapping(possible_color))
        bar_trace = go.Bar(
            x=np.transpose(tmp_df[x].values),
            y=tmp_df[y].values,
            name=name,
            hovertemplate=hovertemplate,
            customdata=[
                (name, *i)
                for i in tmp_df[customdata].values]
            )
        fig.add_trace(bar_trace)

    layout = {
        'barmode': 'stack', 'height': 600,
        'legend_title': labels.get(color, color),
        'yaxis_title': labels.get(y, y),
        'xaxis_title': (
            f"{labels.get(x[1], x[1])} par {labels.get(x[0], x[0]).lower()}"),
        }
    if title is not None:
        layout['title'] = title
    fig.update_layout(**layout)
    return fig

page.py (relevant parts only):

layout = html.Div([
    dcc.Checklist(id='checkbox'),
    dcc.Graph(id='blah')])

@app.callback(
    Output('blah', 'figure'),
    [Input('checkbox', 'value')])
def create_graph(split_on_handling):
    grouping_columns = ['A']
    if split_on_handling:
        grouping_columns.append('B')
    # data needs as columns: 'A', 'B', 'C', and 'D'
    detailed_df = retrieve_data()
    detailed_df = detailed_df.dropna()

    if split_on_handling:
        fig = create_grouped_stacked_barchart(
            detailed_df, x=grouping_columns, y='D', color='C')
    else:
        fig = px.bar(
            detailed_df, x='A', y='D', color='C')

    fig.update_layout(barmode='relative')
    return fig

The checkbox is unchecked by default. Checking it will change the figure of the graph.