Black Lives Matter. Please consider donating to Black Girls Code today.

Can Plotly support 2 x-axis and 2 y-axis in one graph?

Hi,

I would like to create a graph sharing with multiple x-axis and y-axis, but I checked it can support by using chart studio, does it has some examples to achieve this goal by using plotly.graph_objs?

Thanks
Jason

Hi @Jason.Tam ,

Yes, you can define two xaxes, and two yaxes. Here I’m posting an example of bar chart referenced to
(xaxis, yaxis), i.e. the bottom respectively the left axis, and a scatter trace referenced to (xaxis2, yaxis2) (top axis resp. right axis).
We are using make_subplots() with 'secondary_y'=True, that automatically sets the right yaxis. Then we are displaying fig.layout to inspect its settings and make an update to set xaxis2 as the top axis:


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

fig=make_subplots(
        specs=[[{"secondary_y": True}]])
print(fig.layout)    

fig.update_layout(xaxis2= {'anchor': 'y', 'overlaying': 'x', 'side': 'top'},
                  yaxis_domain=[0, 0.94]);

fig.add_trace(
    go.Bar(x=[1, 2, 3, 4],
           y=[7, 4, 5, 6],
           name="bar",
          ), secondary_y=False)
fig.add_trace(
    go.Scatter(x=[-2, -1, 0, 1],
               y=[4, 2, 5, 6],
               name="scatt1",
               line_color="#ee0000"), secondary_y=True)
fig.data[1].update(xaxis='x2')
fig.update_layout(width=700, height=475)

Hi @empet,

Thanks so much for your advice.

BR,
Jason

Hi @empet ,

If I would like to plot a graph by sharing the same y-axis, once I et the fig.data[0] as top axis, the bar chart color will cover the line color. Do you have a method to show the line color over the bar color?

Below is the sample code for your kind reference:

fig=make_subplots(
specs=[[{“secondary_y”: True}]])
print(fig.layout)

fig.update_layout(xaxis2= {‘anchor’: ‘y’, ‘overlaying’: ‘x’, ‘side’: ‘top’},
yaxis_domain=[0, 0.94]);

fig.add_trace(
go.Bar(x=[1, 2, 3, 4],
y=[7, 4, 5, 6],
name=“bar”, orientation = ‘h’
), secondary_y=True)

fig.add_trace(
go.Scatter(x=[‘A’, ‘B’, ‘C’, ‘D’],
y=[4, 2, 5, 6],
name=“scatt1”,
line_color=“black”), secondary_y=True)

fig.data[0].update(xaxis=‘x2’)

fig.update_layout(width=700, height=475)

Thanks for your support.

BR,
Jason Tam

@Jason.Tam

Please interchange the definition of the two traces to get the right order, i.e.:

fig.add_trace(
        go.Scatter(x=['A', 'B', 'C', 'D'],
                    y=[4, 2, 5, 6],
                    name="scatt1",
                    line_color="black"),
                   secondary_y=True)
fig.add_trace(go.Bar(x=[1, 2, 3, 4],
                     y=[7, 4, 5, 6],
                     name="bar", 
                     orientation = 'h'), secondary_y=True)

I can’t explain this behaviour, but I suppose that plotly.js renders above the trace referenced to the main xaxis, and below the trace ref to (x2 y2).

hi @empet,

Thanks for your advice.

I tired to interchange the order, the result is the same:

image

fig=make_subplots(
specs=[[{“secondary_y”: True}]])
print(fig.layout)

fig.update_layout(xaxis2= {‘anchor’: ‘y’, ‘overlaying’: ‘x’, ‘side’: ‘top’},
yaxis_domain=[0, 0.94]);

fig.add_trace(
go.Scatter(x=[‘A’, ‘B’, ‘C’, ‘D’],
y=[4, 2, 5, 6],
name=“scatt1”,
line_color=“black”), secondary_y=True)

fig.add_trace(
go.Bar(x=[1, 2, 3, 4],
y=[7, 4, 5, 6],
name=“bar”, orientation = ‘h’
), secondary_y=True)

fig.data[1].update(xaxis=‘x2’)

fig.update_layout(width=700, height=475)

BR,
Jason

@Jason.Tam
I running Plotly version 4.6.0

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

fig=make_subplots(
specs=[[{"secondary_y": True}]])

fig.update_layout(xaxis2= {'anchor': 'y', 'overlaying': 'x', 'side': 'top'},
                  yaxis_domain=[0, 0.94]);

fig.add_trace(
        go.Scatter(x=['A', 'B', 'C', 'D'],
                    y=[4, 2, 5, 6],
                    name="scatt1",
                    line_color="black"),
                   secondary_y=True)
fig.add_trace(go.Bar(x=[1, 2, 3, 4],
                     y=[7, 4, 5, 6],
                     name="bar", 
                     orientation = 'h'), secondary_y=True)

fig.data[0].update(xaxis='x2')

fig.update_layout(width=700, height=450)

hi @empet,

Thanks for your reply.

I think you can repeat the issue if you set fig.data[1].update(xaxis=‘x2’) instead of fig.data[0].
My goal is to set [‘A’, ‘B’, ‘C’, ‘D’] as main x-axis.

BR,
Jason Tam

@Jason.Tam

My feeling is that since it’s unusual to not use the yaxis for at least one trace, plotly.js cannot select the right order of traces to render your expected plot.

hi @empet,

Thanks for your reply.

If it cannot hardcode which graph is at the top layer, then I try to set the opacity = 0.5 for the bar chart as my last resort.

BR,
Jason

hi @empet,

Further to the question, I would like to plot this graph format by 2x2 metrix, but I encountered 2 issues during the plotting process:

(1) If I set secondary_y=True, I don’t know why the bottom left graph is overlapped with the top left graph:

(2) If I set the secondary x-axis by writing “fig.data[0].update(xaxis=‘x2’)”, I don’t know why some graphs are deleted.

Below is my sample code for your kind reference: Again, thanks so much for your technical advice.

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

fig=make_subplots(specs=[[{“secondary_y”: True}]*2]*2, rows=2, cols=2)

#/ fig.update_layout(xaxis2= {‘anchor’: ‘y’, ‘overlaying’: ‘x’, ‘side’: ‘top’}, yaxis_domain=[0, 0.94])

Graph1

fig.add_trace(
go.Scatter(x=[‘A’, ‘B’, ‘C’, ‘D’],
y=[4, 2, 5, 6],
name=“scatt1”,
line_color=“black”), secondary_y=True, row=1, col=1)
fig.add_trace(go.Bar(x=[1, 2, 3, 4],
y=[7, 4, 5, 6],
name=“bar”,
orientation = ‘h’), secondary_y=True, row=1, col=1)

Graph2

fig.add_trace(
go.Scatter(x=[‘D’, ‘E’, ‘F’, ‘G’],
y=[7, 8, 5, 6],
name=“scatt1”,
line_color=“black”), secondary_y=True, row=1, col=2)
fig.add_trace(go.Bar(x=[1, 2, 3, 4],
y=[7, 4, 5, 6],
name=“bar”,
orientation = ‘h’), secondary_y=True, row=1, col=2)

Graph3

fig.add_trace(
go.Scatter(x=[‘W’, ‘X’, ‘Y’, ‘Z’],
y=[10, 11, 5, 12],
name=“scatt1”,
line_color=“black”), secondary_y=True, row=2, col=1)
fig.add_trace(go.Bar(x=[1, 2, 3, 4],
y=[12, 11, 7, 6],
name=“bar”,
orientation = ‘h’), secondary_y=True, row=2, col=1)

#/ fig.data[0].update(xaxis=‘x2’)

fig.update_layout(width=1600, height=500)

BR,
Jason

Hi @Jason.Tam,

I checked your code step by step, and all settings seem to be the right ones.
As I said for the case with a single subplot, I think that plotly.js “gets confused” because you defined an axis at the right side of an inexistent left side axis. May I ask you, why do you insist to work with such unusual axes?
I’m using plotly.py for more than 6 years, but it’s the first time when someone doesn’t reference any trace to the default yaxis.
Here are the tests I made:
https://plotly.com/~empet/15640t

Please download this notebook and inspect the result of each cell.

hi @empet,

Thanks for your reply.
I cannot go to your provided link - “404 not found”.

Actually below is my graph format, it is more convenient for me to look at the most updated data at the secondary Y axis and I would like to plot multiple graphs instead of plotting it one by one.

For the second question, do you have some examples how to update the xaxis2 in subplot matrix?
I think my bottleneck now is at these 2 codes:
fig.update_layout(xaxis2= {‘anchor’: ‘y’, ‘overlaying’: ‘x’, ‘side’: ‘top’}, yaxis_domain=[0, 0.94])
fig.data[0].update(xaxis=‘x2’)

Thanks for your advice.

BR,
Jason

Sorry, t at the url end must be removed: https://plotly.com/~empet/15640.

Displaying the subplot information like in this notebook, and taking into account that the fig.data[k] is the trace added by the k^th fig.add_trace(), you can perform the required updates.

hi @empet,

Thanks so much.

Finally I can do it~

BR,
Jason

1 Like

hi @empet,

Sorry for bothering you again. :sweat_smile:

If I would like to plot a graph with multiple Y-axes in subplot, do you the sequence index of the y-axis? I tired many methods but the subplot can only show yaxis1 title. :weary:

Sample Code:
import plotly.graph_objects as go

fig = go.Figure()
fig = make_subplots(
rows=1, cols=2,
specs=[[{“rowspan”: 1, “colspan”: 1}, {“rowspan”: 1, “colspan”: 1}]],
horizontal_spacing =0.1, vertical_spacing =0.09)

fig.add_trace(go.Scatter(x=[1, 2, 3], y=[2, 52, 62]), row=1, col=1)

fig.add_trace(go.Bar(x=[[‘A’, ‘A’, ‘A’], [1, 2, 3]], y=[4, 5, 6000], name=“yaxis1 data”, yaxis=“y2”), row=1, col=2)
fig.add_trace(go.Bar(x=[[‘B’, ‘B’, ‘B’], [2, 3, 4]], y=[40, 50, 60], name=“yaxis2 data”, yaxis=“y3”), row=1, col=2)
fig.add_trace(go.Bar(x=[[‘C’, ‘C’, ‘C’], [4, 5, 6]], y=[40000, 50000, 60000], name=“yaxis3 data”, yaxis=“y4”), row=1, col=2)
fig.add_trace(go.Bar(x=[[‘D’, ‘D’, ‘D’], [5, 6, 7]], y=[400000, 500000, 600000], name=“yaxis4 data”, yaxis=“y5”), row=1, col=2)

Create axis objects
fig.update_layout(xaxis2=dict(domain=[0.6, 0.9]),
yaxis2=dict(title=“yaxis1 title”,titlefont=dict(color=“red”), tickfont=dict(color=“red”)),
yaxis3=dict(title=“yaxis2 title”,titlefont=dict(color=“orange”),tickfont=dict(color=“orange”), anchor=“free”, overlaying=“y2”, side=“left”, position=0.5),
yaxis4=dict(title=“yaxis3 title”,titlefont=dict(color=“pink”),tickfont=dict(color=“pink”), anchor=“x2”,overlaying=“y2”, side=“right”),
yaxis5=dict(title=“yaxis4 title”,titlefont=dict(color=“cyan”),tickfont=dict(color=“cyan”), anchor=“free”,overlaying=“y2”, side=“right”,position=1))

fig.update_layout(width=1600, height=400)
fig.update_xaxes(rangeslider_visible=False)
fig.show()

However, if I plot the graph individually, it can show y-axis1 to y-axis4 like this:

Thanks for your advice.

BR,
Jason