Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Plotly: How to show more than 2 x-axes titles/ranges on the same subplot?

I'm using Plotly and making scatter plot subplots with a shared y-axis and different x-axes. I have attempted to use the figure object (fig['layout'][data index]) syntax to show multiple stacked x-axes and their respective ranges. I have only been successful in showing two xaxes and ranges per subplot by assigning 'top' and 'bottom' to the side attribute of the figure layout. The 2nd column from the right in figure below should show titles/ranges for series T5, T6, and T7 but only the title and range for T5 and T7 appear.

Is it possible to show more than 2 x-axes title/ranges on the same subplot in Plotly? For an implemented example, Matplotlib supports showing multiple stacked axes

enter image description here

Thank you to Vestland, the key was using the position attribute of the figure's layout and scaling the y-axis to fit the adjustment properly. See the [monstrosity] below for a full implementation of multiple axes based on Vestland's sample code.

enter image description here

like image 616
straydog Avatar asked Oct 15 '25 17:10

straydog


1 Answers

You'll need a precise combination of make_subplots(rows=1, cols=2), add_traces() and fig.update_layout(xaxis=dict(domain=...):

  1. Set up a "regular" subplot using fig=make_subplots(rows=1, cols=2) and include two traces as described here.

  2. Add a third trace with its own xaxis using fig.add_trace(go.Scatter([...[, xaxis="x3"))

  3. Then, adjust subplot 1 to make room for xaxis3 using: fig.update_layout(xaxis3=dict(anchor="free", overlaying="x1", position=0.0))

  4. Make some final adjustments using fig.update_layout([...], yaxis2=dict(domain=[0.1, 1]))

The reason why you'll have to take domain into account is because the position attribute in point 3 can't be negative, and you'll have to make room for the double x-axes somehow. Here's the result:

Plot

enter image description here

Complete code:

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

# initial subplot with two traces
fig = make_subplots(rows=1, cols=2)

fig.add_trace(
    go.Scatter(x=[1, 2, 3], y=[4, 5, 6]),
    row=1, col=1
)

fig.add_trace(
    go.Scatter(x=[20, 30, 40], y=[50, 60, 70]),
    row=1, col=2
)

fig.update_layout(height=600, width=800,
                  title_text="Subplots with shared x-axes")

# extra data where xaxis3 is shared with subplot 1
fig.add_trace(go.Scatter(
    x=[11, 12, 13],
    y=[6, 5, 4],
    name="xaxis3 data",
    xaxis="x3"
))

# some adjustmentns for xaxis3
fig.update_layout(xaxis3=dict(
        title="xaxis3 title",
        titlefont=dict(
            color="#9467bd"
        ),
        tickfont=dict(
            color="#9467bd"
        ),
        anchor="free",
        overlaying="x1",
        side="right",
        position=0.0
    ))

# extra data where xaxis4 is shared with subplot 2
fig.add_trace(go.Scatter(
    x=[50, 60, 70],
    y=[60, 60, 60],
    name="xaxis4 data",
    xaxis="x4",
    yaxis = 'y2'
))

# some adjustments for xaxis4
fig.update_layout(xaxis4=dict(
        title="xaxis4 title",
        titlefont=dict(
            color="#9467bd"
        ),
        tickfont=dict(
            color="#9467bd"
        ),
        anchor="free",
        overlaying="x2",
        side="right",
        position=0.0
    ))

# make room to display double x-axes
fig.update_layout(yaxis1=dict(domain=[0.1, 1]),
                  yaxis2=dict(domain=[0.1, 1]),
                 )

# not critical, but just to put a little air in there
fig.update_layout(xaxis1=dict(domain=[0.0, 0.4]),
                  xaxis2=dict(domain=[0.6, 1]),
                 )

fig.show()

Edit: Tighten the space between title and range.

One approach is to change the position of the title itself using fig.update_layout(title=dict()):

fig.update_layout(
    title={
        'text': "Plot Title",
        'y':0.88,
        'x':0.42,
        'xanchor': 'left',
        'yanchor': 'top'})

Plot 2

enter image description here

Complete code for Plot 2

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

# initial subplot with two traces
fig = make_subplots(rows=1, cols=2)

fig.add_trace(
    go.Scatter(x=[1, 2, 3], y=[4, 5, 6]),
    row=1, col=1
)

fig.add_trace(
    go.Scatter(x=[20, 30, 40], y=[50, 60, 70]),
    row=1, col=2
)

fig.update_layout(height=600, width=800,
                  title_text="Subplots with shared x-axes")

# extra data where xaxis3 is shared with subplot 1
fig.add_trace(go.Scatter(
    x=[11, 12, 13],
    y=[6, 5, 4],
    name="xaxis3 data",
    xaxis="x3"
))

# some adjustmentns for xaxis3
fig.update_layout(xaxis3=dict(
        title="xaxis3 title",
        titlefont=dict(
            color="#9467bd"
        ),
        tickfont=dict(
            color="#9467bd"
        ),
        anchor="free",
        overlaying="x1",
        side="right",
        position=0.0
    ))

# extra data where xaxis4 is shared with subplot 2
fig.add_trace(go.Scatter(
    x=[50, 60, 70],
    y=[60, 60, 60],
    name="xaxis4 data",
    xaxis="x4",
    yaxis = 'y2'
))

# some adjustments for xaxis4
fig.update_layout(xaxis4=dict(
        title="xaxis4 title",
        titlefont=dict(
            color="#9467bd"
        ),
        tickfont=dict(
            color="#9467bd"
        ),
        anchor="free",
        overlaying="x2",
        side="right",
        position=0.0
    ))

# make room to display double x-axes
fig.update_layout(yaxis1=dict(domain=[0.1, 1]),
                  yaxis2=dict(domain=[0.1, 1]),
                 )

# not critical, but just to put a little air in there
fig.update_layout(xaxis1=dict(domain=[0.0, 0.4]),
                  xaxis2=dict(domain=[0.6, 1]),
                 )

fig.update_layout(
    title={
        'text': "Plot Title",
        'y':0.88,
        'x':0.42,
        'xanchor': 'left',
        'yanchor': 'top'})

fig.show()
like image 165
vestland Avatar answered Oct 19 '25 04:10

vestland