Make scatter trace extend beyond the plot area

Hi,

I would like to allow a trace of a scatter plot to extend in y beyond the plot area, i.e. the recatangle limited by the max range values. The intention is to draw attention to an event in a time series which has much higher y-values than the mean. The traces are plotted in several rows of subplots and they should be allowed to extend as far as the whole multiplot area. Is that possible somehow?

Regards, Christian

@ckkart good question. We can draw across subplots by plotting the data on a custom hidden axis seperate from the one defining the chart ticks. Just make sure scaleanchor and constrainttoward are set to keep the visible and invisible axis in sync. Here’s an example:

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

x  = list(range(11))
top    = [1, 0.6, 0.9, 0.3, 0.7, 0.2, 0.5, -0.2, 0.1, -0.6, -1]
bottom = [-1, -0.4, 0.2, -0.3, 0.5, 3.5, 0.4, -0.2, 0.3, 0.6, 1]   # <- spike at x=5

# Define two subplots as rows
fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.2,
                    subplot_titles=("Channel A", "Channel B"))

# Add a trace to the top one as normal
fig.add_trace(go.Scatter(x=x, y=top, name="Channel A"), row=1, col=1)

# Row 2 now technically holds no real trace; just an axis
fig.add_trace(go.Scatter(x=[None], y=[None], showlegend=False, hoverinfo="skip"), row=2, col=1)
# Set the bounds of the visible lower y-axis since it can't infer from data.
fig.update_yaxes(range=[-1, 1], row=2, col=1)

# The second trace lives on a custom axis number 3 instead of row 2
fig.add_trace(go.Scatter(x=x, y=bottom, name="Channel B", line_color="#EF553B", xaxis="x3", yaxis="y3"))
# Set up the hidden axis we're actually plotting on
fig.update_layout(
    xaxis3=dict(matches="x", visible=False),
    yaxis3=dict(scaleanchor="y2", constraintoward="bottom", visible=False, range=[-1, 1]),
    plot_bgcolor="rgba(0,0,0,0)",
)

fig.show()

Hi, it looks nice for the case you show, but I could not make it work with 3 rows. The contraintoward parameter does not sound like the correct way to do it. I changed xaxis=‘x3’ to ‘x4’, and maintened scaleanchor=‘y2’ but still, the trace is pushed to the bottom. Any ideas?

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

x  = list(range(11))
top    = [1, 0.6, 0.9, 0.3, 0.7, 0.2, 0.5, -0.2, 0.1, -0.6, -1]
bottom = [-1, -0.4, 0.2, -0.3, 0.5, 3.5, 0.4, -0.2, 0.3, 0.6, 1]   # <- spike at x=5

# Define two subplots as rows
fig = make_subplots(rows=3, cols=1, shared_xaxes=True, vertical_spacing=0.2,
                    subplot_titles=("Channel A", "Channel B"))

# Add a trace to the top one as normal
fig.add_trace(go.Scatter(x=x, y=top, name="Channel A"), row=1, col=1)

# Row 2 now technically holds no real trace; just an axis
fig.add_trace(go.Scatter(x=[None], y=[None], showlegend=False, hoverinfo="skip"), row=2, col=1)
# Set the bounds of the visible lower y-axis since it can't infer from data.
fig.update_yaxes(range=[-1, 1], row=2, col=1)

# The second trace lives on a custom axis number 3 instead of row 2
fig.add_trace(go.Scatter(x=x, y=bottom, name="Channel B", line_color="#EF553B", xaxis="x4", yaxis="y4"))
# Set up the hidden axis we're actually plotting on
fig.update_layout(
    xaxis4=dict(matches="x", visible=False),
    yaxis4=dict(scaleanchor="y2", constraintoward="bottom", visible=False, range=[-1, 1]),
    plot_bgcolor="rgba(0,0,0,0)",
)
print(fig)
fig.show()

I think you’re right. I added constrainttoward alongside scaleanchor and didn’t test without it. I don’t think it’s necessary after all since the “middle” default seems to work best anyways. scaleanchor might be all you need. When I tried your example with just constraintoward removed it seemed to work.

That’s better, right. But I whenever I try to add axes on two distinct subplots the result is weird.

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

x  = list(range(11))
top    = [1, 0.6, 0.9, 0.3, 0.7, 0.2, 0.5, -0.2, 0.1, -0.6, -1]
bottom = [-1, -0.4, 0.2, -0.3, 0.5, 3.5, 0.4, -0.2, 0.3, 0.6, 1]   # <- spike at x=5

# Define two subplots as rows
fig = make_subplots(rows=3, cols=1, shared_xaxes=True, vertical_spacing=0.2,
                    subplot_titles=("Channel A", "Channel B"))

fig.add_trace(go.Scatter(x=[None], y=[None], showlegend=False, hoverinfo="skip"), row=1, col=1)
fig.update_yaxes(range=[-1, 1], row=1, col=1)
# Add a trace to the top one as normal
fig.add_trace(go.Scatter(x=x, y=top, name="Channel A", xaxis='x4', yaxis='y4'))

# Row 2 now technically holds no real trace; just an axis
fig.add_trace(go.Scatter(x=[None], y=[None], showlegend=False, hoverinfo="skip"), row=2, col=1)
# Set the bounds of the visible lower y-axis since it can't infer from data.
fig.update_yaxes(range=[-1, 1], row=2, col=1)

# The second trace lives on a custom axis number 3 instead of row 2
fig.add_trace(go.Scatter(x=x, y=bottom, name="Channel B", line_color="#EF553B", xaxis="x5", yaxis="y5"))
# Set up the hidden axis we're actually plotting on
fig.update_layout(
    xaxis4=dict(matches="x", visible=False),
    yaxis4=dict(scaleanchor="y", visible=False, range=[-1, 1]),
    xaxis5=dict(matches="x", visible=False),
    yaxis5=dict(scaleanchor="y2", visible=False, range=[-1, 1]),
    plot_bgcolor="rgba(0,0,0,0)",
)
print(fig)
fig.show()