Plotly subplots with individual legends

I have the same problem. Any update on this issue?

1 Like

I used two side by side Div elements to emulate Plotly subplot . Doing this way, we have independent legends. However, if we want to share an axis, we should do it manually:

app.layout = html.Div(children=[
        html.Div(['YOUR FIRST GRAPH OBJECT'],
                 style = {'float':'left', 'width':'49%'}) ,
        html.Div(['YOUR SECOND GRAPH OBJECT'],
                 style = {'float':'right', 'width':'49%'})   
                ])
1 Like

Is this possible now?

2 Likes

So how do you zoom-in synchronously then?

Hello :slight_smile:
I have the same problem, and the same question then :sweat_smile: : “How can you manually set shared axis?”
Thanks

The otherwise good support for common zooming and panning of subplots is severely marred by the inability to display legends per subplot. I would be grateful if users here could comment on how they are getting around this.

Has anyone managed to get separate legends to show on each subplot?
Has anyone implemented common zooming and spanning across separate plots which are not subplots of a common figure?

Any suggestions of a better python interactive plotting library that can achieve this?

2 Likes

Same issue as others in the group: The inability to display a legend for each subplot is unfortunate from a business perspective. For example, when displaying subplots with same colors the legend devolves and is difficult or impossible to interpret. One might simply alter the colors, but there are easily imagined cases where matching colors across subplots would be ideal to illustrate similar cohorts. Hope that this issue is addressed in a future release.

2 Likes

Did you find a workaround? I am also stuck due to this missing feature :frowning:

I have 6 subplots, their legends/colorbar looks aweful by default.
The documentation shows little info on how to use the api.

Can anyone help?

Here is a workaround. It allows you to disable a legend for a subplot or to make plots share the same legend entry by using a combination of legendgroup and showlegend = False.

Thank NeStack, but as far as I can tell this workaround only disables certain traces from the legend.
There is still no way, as far as I can tell, to use legendgroups and retain the ability to toggle traces on and off independently (the entire legend group is toggled instead). Then there is the fact that legendgroup spacing needs to be handcoded to match subplot positioning.

So users are left to choose between being able to toggle traces (very useful) or being able to display readable legends (essential). You cannot do both.

A thorough solution would include separate legends per subplot.

Admittedly I’d settle for an option to toggle individually rather than by grouplegend. Perhaps that can be an initial fix.

I believe I have the same issue already reported in this thread, if so, this is just a +1.

  1. I have a subplot with 2 rows and 1 column
  2. Both plots share x axes, so I can zoom in and out both at the same time
  3. Some legends are grouped, other are single legends
  4. There are no shared legends between subplots, all legends belong either to row 1 or 2
  5. I need the ability to toggle visibility of each data + legend individually

Is there a way to display the legend next to each row?

In the example below, orange marked legends belong to the bottom plot.

The way it is presented is counterintuitive :frowning:

1 Like

This post has a lot of views, so for readers interested in subplots legends: we have an open issue in plotly.js for this feature https://github.com/plotly/plotly.js/issues/1668, to which you can subscribe for updates. However, it represents a substantial amount of work. If anyone here works for an organization that has a software budget, we do accept sponsorship for features, which would enable us to build this feature faster. See https://plot.ly/products/consulting-and-oem/ for more details!

Hi all!

I do not have the perfect solution but if you are facing this issue in Python you can utilize the fields legendgroup and legend_tracegroupgap to fake having individual legends per subplot. See my explaination here: [Plotly] How to make individual legends in subplot | Kaggle

You can try the code below to create the figure above

import pandas as pd
import plotly.express as px

df = px.data.gapminder().query("continent=='Americas'")

from plotly.subplots import make_subplots
import plotly.graph_objects as go

fig = make_subplots(rows=3, cols=1)

fig.append_trace(go.Scatter(
    x=df.query("country == 'Canada'")['year'],
    y=df.query("country == 'Canada'")['lifeExp'],
    name = 'Canada',
    legendgroup = '1'
), row=1, col=1)
fig.append_trace(go.Scatter(
    x=df.query("country == 'United States'")['year'],
    y=df.query("country == 'United States'")['lifeExp'],
    name = 'United States',
    legendgroup = '1'
), row=1, col=1)

fig.append_trace(go.Scatter(
    x=df.query("country == 'Mexico'")['year'],
    y=df.query("country == 'Mexico'")['lifeExp'],
    name = 'Mexico',
    legendgroup = '2'
), row=2, col=1)
fig.append_trace(go.Scatter(
    x=df.query("country == 'Colombia'")['year'],
    y=df.query("country == 'Colombia'")['lifeExp'],
    name = 'Colombia',
    legendgroup = '2'
), row=2, col=1)
fig.append_trace(go.Scatter(
    x=df.query("country == 'Brazil'")['year'],
    y=df.query("country == 'Brazil'")['lifeExp'],
    name = 'Brazil',
    legendgroup = '2'
), row=2, col=1)

fig.append_trace(go.Scatter(
    x=df.query("country == 'Argentina'")['year'],
    y=df.query("country == 'Argentina'")['lifeExp'],
    name = 'Argentina',
    legendgroup = '3'
), row=3, col=1)
fig.append_trace(go.Scatter(
    x=df.query("country == 'Chile'")['year'],
    y=df.query("country == 'Chile'")['lifeExp'],
    name = 'Chile',
    legendgroup = '3'
), row=3, col=1)

fig.update_layout(
    height=800, 
    width=800, 
    title_text="Life Expectancy in the Americas", 
    xaxis3_title = 'Year',
    yaxis1_title = 'Age',
    yaxis2_title = 'Age',
    yaxis3_title = 'Age',
    legend_tracegroupgap = 180,
    yaxis1_range=[50, 90],
    yaxis2_range=[50, 90],
    yaxis3_range=[50, 90]
)
fig.show()
7 Likes

I understand this hasn’t been officialy addressed yet?
I’ve been studying Plotly for less than a month and I already hit this roadblock, which is a feature I use constantly (subplots comparing electrical variables, etc). I see that it has been 5 years since the first comment, so at this point it seems that it won’t happen… I’m not very confident.

1 Like

Totally agree. In my field we basically need this feature 95% of the time. Having other libraries that do this out of the box is quite unfortunate in this case from a business perspective. Anyways, Plotly is free to use so I thankfully take what is given :slight_smile:

1 Like

Another way to fix this problem is to use a dashboard:

Show & Tell: Plotly subplots with individual legends, all interactions clientside.

(thank’s @Emmanuelle for the deep_merge javascript function)

I was able to use the python example from @jrmistry above and modify this for R, using “legend = list(tracegroupgap = 240)” inside layout():

p = plot_ly(shared_data, x = ~Index)%>%
  add_trace(y = ~Rainfall, type = 'scatter', mode = 'lines',
            line = list(color = colour[1]), name = "Rainfall", legendgroup = "1st") %>%
  add_trace(y = ~`Forecast Rainfall`, type = 'scatter', mode = 'lines',
            line = list(color = colour[2]), name = "Forecast Rainfall", legendgroup = "1st") %>%
  add_trace(y = ~`Cummulative Rainfall`, type = 'scatter', mode = 'lines',
            line = list(color = colour[3]), name = "Cummulative Rainfall", legendgroup = "1st") %>%
    add_segments(x = Sys.time(), 
                 xend = Sys.time(), 
                 y = yBreaks[1], 
                 yend = yBreaks[length(yBreaks)], 
                 line = list(color = "black", dash="dash", width = 1.5),
                 showlegend = FALSE) %>%
    add_annotations(x = Sys.time()-hours(3), y = MedianRain*0.075, 
                    text = "Tnow",
                    textangle = -90,
                    showlegend = FALSE, 
                    showarrow = F) %>%
  layout(xaxis = list(title = ""),
         yaxis = list (title = "Rainfall (mm)") )

pARI = plot_ly()%>%
  add_trace(data = shared_data, x = ~Index, y = ~Meas_ARI_years, type = 'scatter', mode = 'lines',
            line = list(color = colour[1]), name = "1 hour (measured)", legendgroup = "2nd" 
            ) %>%
  add_trace(data = shared_data, x = ~Index, y = ~Pred_ARI_years, type = 'scatter', mode = 'lines',
            line = list(color = colour[2]), name = "1 hour (predicted)", legendgroup = "2nd" 
            ) %>%
  layout(xaxis = list(title = ""),
         yaxis = list(title = "ARI (years)",
                      range = list(0, 100)), 
         legend = list(title = "Rainfall duration"#, x = 0.1, y = 0.9
                       ))

annotations = list( 
  list( 
    x = 0.5, y = 0.9,  
    text = "<b>SiteName</b>",  
    xref = "paper", yref = "paper",  
    xanchor = "center", yanchor = "bottom",  
    showarrow = FALSE 
  ))

Rainplots = subplot(p, pARI, nrows = 2, heights = c(0.35,0.35), margin = 0.05,
                    titleY = TRUE) %>%
  layout(annotations = annotations, 
         # add space between legends for diff plots:
         legend = list(tracegroupgap = 240))

Rainplots

Here’s what it looks like:

There’s an example off multiple legends on the page: Legends in Python

I haven’t figured out how to make it work for subplots yet though. Just thought I’d post this incase it inspires anyone else… I’ll keep plugging away and let you al know if I figure something out.