Filled area plots for lines not working if two of them are on different Y-axis

My intention is to color the spread between two line charts that have different Y-axis (one is log scale, one is nominal scale)

The filled area feature works s intended if both lines are in the same Y-axis.

import plotly.graph_objects as go

fig = go.Figure()
fig.add_trace(go.Scatter(x=[1, 2, 3, 4], y=[3, 4, 8, 3],
    fill=None,
    mode='lines',
    line_color='indigo',
    ))
fig.add_trace(go.Scatter(
    x=[1, 2, 3, 4],
    y=[1, 6, 2, 6],
    fill='tonexty', # fill area between trace0 and trace1
    mode='lines', line_color='indigo'))

fig.show()

Capture

However, it fails if both lines belonged to a different Y-axis

import plotly.graph_objects as go

fig = go.Figure()
fig.add_trace(go.Scatter(x=[1, 2, 3, 4], y=[3, 4, 8, 3],
    fill=None,
    mode='lines',
    line_color='indigo',
    yaxis= 'y1',         
    ))

fig.add_trace(go.Scatter(
    x=[1, 2, 3, 4],
    y=[1, 6, 2, 6],
    fill='tonexty', # fill area between trace0 and trace1
    mode='lines', line_color='indigo',
    yaxis= 'y2'
))

fig.update_layout(
    xaxis=dict(
       domain=[0.15, 0.9]
    ),
    yaxis=dict(
        title="Y1",
        titlefont=dict(
            color="#1f77b4"
        ),
        tickfont=dict(
            color="#1f77b4"
        )
    ),
    yaxis2=dict(
        title="Y2",
        titlefont=dict(
            color="red"
        ),
        tickfont=dict(
            color="red"
        ),
        anchor="x",
        overlaying="y",
        side="right",
   ),
)

fig.show()

Capture1

Is there a way I can fix this? (Or is there a feature that allows area filling for lines belonging to different Y-axis?)

@divadlen
The second plot does not reproduce the first one, because only graphs referenced to the same xaxis and yaxis can be compared.
But with a trick you can get it as follows:

Reference both graphs to yaxis, and a third one to the yaxis2. Set mode “markers” for the third trace, and set invisible markers (i.e. of small size). Also showlegend=False for the this one:

import plotly.graph_objects as go
from plotly.subplots import make_subplots
fig = make_subplots(specs=[[{"secondary_y": True}]])
y1 =  [3, 4, 8, 3]
y2= [1, 6, 2, 6]
fig.add_trace(go.Scatter(x=[1, 2, 3, 4], y=y1,
    fill=None,
    mode='lines',
    line_color='indigo' ), secondary_y=False)
fig.add_trace(go.Scatter(
    x=[1, 2, 3, 4],
    y=[1, 6, 2, 6],
    fill='tonexty', # fill area between trace0 and trace1
    mode='lines', line_color='indigo'), secondary_y=False)

fig.add_trace(go.Scatter(
    x=[1, 2, 3, 4],
    y=[1, 6, 2, 6],
    showlegend=False,
    mode='markers', marker_size=0.1, line_color='indigo'), secondary_y=True)

fig.update_layout(
    xaxis_domain=[0.15, 0.9],
    yaxis=dict(
        title="Y1",
        titlefont_color="#1f77b4",
        tickfont_color="#1f77b4"
        ),
    yaxis2=dict(
        title="Y2",
        titlefont_color="red",
        tickfont_color="red"
        ))

fig.show()

Someone looking at this graph can wonder why are you comparing values of different ranges. You can get the right information setting the same range for both yaxis and yaxis2:

fig = make_subplots(specs=[[{"secondary_y": True}]])
y1 =   [3, 4, 8, 3]
y2 =  [1, 6, 2, 6]

ymin=min(y1+y2)
ymax=max(y1+y2)
fig.add_trace(go.Scatter(x=[1, 2, 3, 4], y=y1,
    fill=None,
    mode='lines',
    line_color='indigo',
            
    ), secondary_y=False)
fig.add_trace(go.Scatter(
    x=[1, 2, 3, 4],
    y=[1, 6, 2, 6],
    fill='tonexty', # fill area between trace0 and trace1
    mode='lines', line_color='indigo',
    
), secondary_y=False)


fig.add_trace(go.Scatter(
    x=[1, 2, 3, 4],
    y=[1, 6, 2, 6],
    showlegend=False,
    mode='markers', marker_size=0.1, line_color='indigo',
    
), secondary_y=True)

fig.update_layout(
    xaxis_domain=[0.15, 0.9],
    yaxis=dict(
        title="Y1",
        range=[ymin-0.5, ymax+0.5],
        titlefont_color="#1f77b4",
        tickfont_color="#1f77b4"
        ),
    yaxis2=dict(
        title="Y2",
        range=[ymin-0.5, ymax+0.5],
        titlefont_color="red",
        tickfont_color="red"
        ))

Someone looking at this graph can wonder why are you comparing values of different ranges. You can get the right information setting the same range for both yaxis and yaxis2:

My intention is to do cointegration analysis between time series, many of them often don’t come in the same scale (EG: labor hours, value-added, log-scaled, nominal scaled). So having a way to highlight the spread seems useful.

Unfortunately, your suggestion doesn’t seem to help the problem. As soon as I scale the numbers for a certain Ydata, all y-axis ends up scaling accordingly.

import plotly.graph_objects as go
from plotly.subplots import make_subplots
fig = make_subplots(specs=[[{"secondary_y": True}]])
y1 =  [3, 4, 8, 3]
y2= [1, 6, 2, 6]
fig.add_trace(go.Scatter(
    x=[1, 2, 3, 4],
    y=y1,
    fill=None,
    name= 'Y1 line',   
    mode='lines',
    line_color='blue' ), secondary_y=False)
fig.add_trace(go.Scatter(
    x=[1, 2, 3, 4],
    y=[1, 6, 2, 6],
    name= 'Y2 line',
    fill='tonexty', # fill area between trace0 and trace1
    mode='lines', 
    line_color='red'), secondary_y=False)

fig.add_trace(go.Scatter(
    x=[1, 2, 3, 4],
    y=[1, 6, 2, 6],
    showlegend=False,
    mode='markers', marker_size=0.1, 
    line_color='red'), secondary_y=True)

fig.update_layout(
    xaxis_domain=[0.15, 0.9],
    yaxis=dict(
        title="Y1",
        titlefont_color="#1f77b4",
        tickfont_color="#1f77b4"
        ),
    yaxis2=dict(
        title="Y2",
        titlefont_color="red",
        tickfont_color="red",
        ))

fig.show()

import plotly.graph_objects as go
from plotly.subplots import make_subplots
fig = make_subplots(specs=[[{"secondary_y": True}]])
y1 =  [3, 4, 8, 3]
y2= [1, 6, 2, 6]
fig.add_trace(go.Scatter(
    x=[1, 2, 3, 4],
    y=y1,
    fill=None,
    name= 'Y1 line',   
    mode='lines',
    line_color='blue' ), secondary_y=False)
fig.add_trace(go.Scatter(
    x=[1, 2, 3, 4],
    y=[10, 60, 20, 60],
    name= 'Y2 line',
    fill='tonexty', # fill area between trace0 and trace1
    mode='lines', 
    line_color='red'), secondary_y=False)

fig.add_trace(go.Scatter(
    x=[1, 2, 3, 4],
    y=[10, 60, 20, 60],
    showlegend=False,
    mode='markers', marker_size=0.1, 
    line_color='red'), secondary_y=True)

fig.update_layout(
    xaxis_domain=[0.15, 0.9],
    yaxis=dict(
        title="Y1",
        titlefont_color="#1f77b4",
        tickfont_color="#1f77b4"
        ),
    yaxis2=dict(
        title="Y2",
        titlefont_color="red",
        tickfont_color="red",
        ))

fig.show()

So Y1 in this case is plotted against the Y2-axis, bringing me back to my original problem. Ideally, Y1 axis should be 1-8, while Y2 axis should be 10-60. Changing the parameters of secondary_y= from False to True brings me back to my original problem.

The solution I’m trying to get is for Y1 and Y2 to be plot in independent-axis (which plotly already has a solution for), and to have the tonexty function to work for Y-lines that occur in different Y-axis scales.

Alternatively, I can just try to scale all different Ydata values to fit in the same Y-axis. Not sure if it would cause problems for research interpretation.

Original

import plotly.graph_objects as go

fig = go.Figure()

fig.add_trace(go.Scatter(
    x= df.Year,
    y= df['Value added'],
    name = 'Value added',
    yaxis= 'y1',
    mode= 'lines',
    fill= None,
))

fig.add_trace(go.Scatter(
    x= df.Year[1:],
    y= df['Wages paid'],
    name = 'Wages paid',
    yaxis= 'y2',
    mode= 'lines',
    fill= None,
))

fig.add_trace(go.Scatter(
    x= df.Year,
    y= df['Total workers by year end'],
    name = 'Total workers by year end',
    yaxis= 'y3',
    mode= 'lines',
    fill='tonexty', 
))



###############
fig.update_layout(
    xaxis=dict(
       domain=[0.15, 0.9]
    ),
    yaxis=dict(
        title="Value added ($)",
        titlefont=dict(
            color="#1f77b4"
        ),
        tickfont=dict(
            color="#1f77b4"
        )
    ),
    yaxis2=dict(
        title="Wages paid ($)",
        titlefont=dict(
            color="red"
        ),
        tickfont=dict(
            color="red"
        ),
        anchor="free",
        overlaying="y",
        side="left",
        position = 0.0
   ),
    yaxis3=dict(
        title="Total workers by year end",
        titlefont=dict(
            color="green"
        ),
        tickfont=dict(
            color="green"
        ),
        anchor="x",
        overlaying="y",
        side="right",
   ),    
    
    
    height= 600,
    width= 900,
    title= "Value Spread (1963-2019)"
)

fig.show()

Work around (using a rescaled data set, also the chart I wanted)

import plotly.graph_objects as go

fig = go.Figure()

fig.add_trace(go.Scatter(
    x= a.Year,
    y= a['Value added'],
    name = 'Value added',
    yaxis= 'y1',
    mode= 'lines',
    fill= None,
))

fig.add_trace(go.Scatter(
    x= a.Year,
    y= a['Wages paid'],
    name = 'Wages paid',
    yaxis= 'y1',
    mode= 'lines',
    fill= 'tonexty',
))

fig.add_trace(go.Scatter(
    x= a.Year,
    y= a['Total workers by year end'],
    name = 'Total workers by year end',
    yaxis= 'y1',
    mode= 'lines',
    fill='tonexty', 
))

###############
fig.update_layout(
    xaxis=dict(
       domain=[0.15, 0.9]
    ),
    yaxis=dict(
        title="Scaled values",
        titlefont=dict(
            color="#1f77b4"
        ),
        tickfont=dict(
            color="#1f77b4"
        )
    ),   
    
    height= 600,
    width= 900,
    title= "Value Spread, (1963-2019)"
)

fig.show()

However, this method loses the clarity at communicating the true scale for each variable. But thanks for the help and ideas anyway.