Create custom legend by hand

It depends on what is your intention with the subplots. You can for example use facets, which creates and handles the subplots internally. In your case it is actually very simple to adapt to use values in listOfAxis as facet_row and isNoise as color. All you need to do is to redefine the columns X, Y and Z => (value, axis), so each row of the data will have a single “coordinate” (x, y or z), and similar to isNoise. Like:

From: 

X | Y | Z | isNoiseX | isNoiseY | isNoiseZ
--- | --- | --- | --- | --- | --- 
0.5 | 1 | 2 | 1 | 0 | 1 

To: 

value | axis | isNoise
0.5  | X   | 1
1  | Y   | 0
2  | Z  | 1

No, never said that. :slight_smile: You can in principle create a fake trace just to create a legend item, but this is IMO inefficient in your case. Here is a recent post where I elaborate a bit on how to do it, just if you are curious…

My suggestion remains the same: use two traces instead of one, one for each color. Here is a quick example from a different (but very relatable) context:

import plotly.express as px
import plotly.graph_objects as go

df = px.data.stocks()

tickers = ["GOOG", "AAPL"]

fig = go.Figure().set_subplots(len(tickers), 1, shared_xaxes=True, subplot_titles=tickers)

df = df[["date"] + tickers]

for tick in tickers:
    df[f"{tick}_diff"] = df[tick].diff()


for idx, tick in enumerate(tickers):
    _red_df = df[df[f"{tick}_diff"] < 0]
    _green_df = df[df[f"{tick}_diff"] >= 0]
    fig.add_trace(
        go.Scatter(
            x=_red_df["date"],
            y=_red_df[tick],
            mode="markers",
            marker=dict(
                color="red"
            ),
            name=f"{tick} - Down"
        ),
        row=idx+1,
        col=1
    )
    fig.add_trace(
        go.Scatter(
            x=_green_df["date"],
            y=_green_df[tick],
            mode="markers",
            marker=dict(
                color="green"
            ),
            name=f"{tick} - Up"
        ),
        row=idx+1,
        col=1
    )

Output:

If you want a single legend item per color, then you just need to assign a legendgroup for the traces and hide duplicates. Like this:

for idx, tick in enumerate(tickers):
   # This is "equivalent" to your isNoise column 
    _red_df = df[df[f"{tick}_diff"] < 0]
    _green_df = df[df[f"{tick}_diff"] >= 0]
    fig.add_trace(
        go.Scatter(
            x=_red_df["date"],
            y=_red_df[tick],
            mode="markers",
            marker=dict(
                color="red"
            ),
            name=f"Down (all traces)",
            legendgroup="down",
            showlegend = idx == 0
        ),
        row=idx+1,
        col=1
    )
    fig.add_trace(
        go.Scatter(
            x=_green_df["date"],
            y=_green_df[tick],
            mode="markers",
            marker=dict(
                color="green"
            ),
            name=f"Up (all traces)",
            legendgroup="up",
            showlegend = idx == 0
        ),
        row=idx+1,
        col=1
    )

Would that be what you are looking for?

2 Likes