Legendgroup with showlegend=False for shapes

Hi all,

I’m trying to plot multiple shapes that will be grouped based on some criteria and have them appear on the legend. Since there can be a lot of shapes, I wanted to have a single legend entry for each shape group. The docs explain how to do this (https://plotly.com/python/legend/#grouped-legend-items), however, it doesn’t seem to work for shapes. If I add showlegend=False to one of the shapes in my group, it will not toggle that shape when clicking the legend item. Here’s some code to illustrate:

from dash import Dash, dcc, html
import plotly.graph_objects as go

if __name__ == "__main__":
    fig = go.Figure()

    fig.add_trace(go.Scatter(
        x=[1, 2, 3],
        y=[2, 1, 3],
        legendgroup="group",
        name="First trace",
        mode="markers",
        marker=dict(color="Crimson", size=10)
    ))

    fig.add_trace(go.Scatter(
        x=[1, 2, 3],
        y=[2, 2, 2],
        legendgroup="group",
        name="Second trace",
        mode="lines",
        line=dict(color="Crimson"),
        showlegend=False,
    ))

    fig.add_shape(
        type="line",
        x0=0,
        y0=1,
        x1=4,
        y1=1,
        line_width=3,
        line_dash="dot",
        showlegend=True,
        legendgroup="shapes",
        name="First shape",
    )

    fig.add_shape(
        type="line",
        x0=0,
        y0=3,
        x1=4,
        y1=3,
        line_width=3,
        line_dash="dot",
        showlegend=False,
        legendgroup="shapes",
        name="Second shape",
    )

    fig.update_layout(title="Try Clicking on the Legend Items!")
    app = Dash()
    app.layout = html.Div([dcc.Graph(figure=fig)])
    app.run_server(debug=True, use_reloader=True)

This will result in a plot like the one below. Toggling the first trace in the legend will hide both traces because they are in the same legendgroup (expected). Toggling the first shape in the legend will hide only the first shape, leaving the other one visible.

Is it possible to get this to work? Making the shapes traces instead is not an option in my case. I’m using Dash version 2.12.0 and plotly version 5.16.0.

I just ran into this exact same problem. I think it’s a bug in plotly.js – the feature of putting shapes in the legend was added only recently.

I got most of the way to a hack to deal with this. You can put all of the shapes into the legend and then hide all but the first with css.

For example, if the shapes are in the second legend group, you can use

g.groups:nth-child(2) > g:not(:first-child) {display: none;}

to leave one shape in the legend and hide the rest.

The missing piece to the hack is that the hidden legend entries still take up space, so if there are a lot of them, an extraneous scrollbar gets added. I couldn’t get the normal fix, like overflow: clip, to work. I don’t think the legend is actually intended to be styled using css.

However, if you are stuck with using shapes, maybe this hack can work for you.

The bigger problem in my case was that I was using ~5000 shapes, and it was extremely slow. So I switched to traces – you can make all the shapes into one trace by separating the data points of the different shapes by nans, so it can end up being much faster.

1 Like

Hey Simon, thank you for your answer! We ended up deciding it was not necessary to show the legends for these shapes in particular so I guess you could say I was lucky.

Anyways, I think your solution is valuable and can be useful in some instances, but I still hope the issue gets fixed at some point. Thanks again!